[Marble-commits] KDE/kdeedu/marble/src

Bastian Holst bastianholst at gmx.de
Thu Aug 13 16:27:03 CEST 2009


SVN commit 1010843 by bholst:

Marble Weather Plugin speedup by sourcing complex tasks out into a thread. 


 M  +3 -0      lib/AbstractDataPluginItem.h  
 M  +1 -0      lib/AbstractDataPluginModel.cpp  
 M  +90 -1     plugins/render/weather/BBCParser.cpp  
 M  +28 -2     plugins/render/weather/BBCParser.h  
 M  +3 -23     plugins/render/weather/BBCWeatherItem.cpp  
 M  +33 -11    plugins/render/weather/BBCWeatherService.cpp  
 M  +11 -0     plugins/render/weather/BBCWeatherService.h  
 M  +28 -4     plugins/render/weather/StationListParser.cpp  
 M  +15 -2     plugins/render/weather/StationListParser.h  
 M  +3 -0      plugins/render/weather/WeatherItem.cpp  


--- trunk/KDE/kdeedu/marble/src/lib/AbstractDataPluginItem.h #1010842:1010843
@@ -81,6 +81,9 @@
     virtual bool isGeoProjected();
                          
     virtual bool operator<( const AbstractDataPluginItem *other ) const = 0;
+
+ Q_SIGNALS:
+    void updated();
     
  private:
     AbstractDataPluginItemPrivate * const d;
--- trunk/KDE/kdeedu/marble/src/lib/AbstractDataPluginModel.cpp #1010842:1010843
@@ -303,6 +303,7 @@
     d->m_itemSet.insert( i, item );
     
     connect( item, SIGNAL( destroyed( QObject* ) ), this, SLOT( removeItem( QObject* ) ) );
+    connect( item, SIGNAL( updated() ), this, SIGNAL( itemsUpdated() ) );
 
     if ( item->initialized() ) {
         emit itemsUpdated();
--- trunk/KDE/kdeedu/marble/src/plugins/render/weather/BBCParser.cpp #1010842:1010843
@@ -14,11 +14,14 @@
 // Marble
 #include "global.h"
 #include "WeatherData.h"
+#include "BBCWeatherItem.h"
 
 // Qt
 #include <QtCore/QByteArray>
 #include <QtCore/QDateTime>
 #include <QtCore/QDebug>
+#include <QtCore/QFile>
+#include <QtCore/QMutexLocker>
 #include <QtCore/QRegExp>
 
 using namespace Marble;
@@ -36,11 +39,93 @@
 QHash<QString, int> BBCParser::monthNames
         = QHash<QString, int>();
 
+const int WAIT_ATTEMPTS = 20;
+const int WAIT_TIME = 100;
+
 BBCParser::BBCParser()
+    : QThread(),
+      m_end( false )
 {
     BBCParser::setupHashes();
 }
 
+BBCParser::~BBCParser()
+{
+    m_schedule.clear();
+    if ( isRunning() ) {
+        m_end = true;
+        wait( 1000 );
+    }
+}
+
+BBCParser *BBCParser::instance()
+{
+    static BBCParser parser;
+    return &parser;
+}
+
+void BBCParser::scheduleRead( const QString& path,
+                              BBCWeatherItem *item,
+                              const QString& type )
+{
+    ScheduleEntry entry;
+    entry.path = path;
+    entry.item = item;
+    entry.type = type;
+
+    m_schedule.push( entry );
+
+    QMutexLocker locker( &m_runStateMutex );
+    if ( !isRunning() ) {
+        start( QThread::IdlePriority );
+    }
+}
+
+void BBCParser::run()
+{
+    int waitAttempts = WAIT_ATTEMPTS;
+    while( 1 ) {
+        m_runStateMutex.lock();
+        if ( m_schedule.isEmpty() ) {
+            waitAttempts--;
+            if ( !waitAttempts || m_end ) {
+                break;
+            }
+            else {
+                m_runStateMutex.unlock();
+                msleep( WAIT_TIME );
+            }
+        }
+        else {
+            m_runStateMutex.unlock();
+            ScheduleEntry entry = m_schedule.pop();
+
+            QFile file( entry.path );
+            if( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) {
+                return;
+            }
+
+            QList<WeatherData> data = read( &file );
+
+            if( !data.isEmpty() && !entry.item.isNull() ) {
+                if ( entry.type == "bbcobservation" ) {
+                    entry.item->setCurrentWeather( data.at( 0 ) );
+                }
+                else if ( entry.type == "bbcforecast" ) {
+                    entry.item->addForecastWeather( data );
+                }
+
+                emit parsedFile();
+            }
+
+            waitAttempts = WAIT_ATTEMPTS;
+        }
+    }
+
+    m_runStateMutex.unlock();
+}
+
+
 QList<WeatherData> BBCParser::read( QIODevice *device )
 {
     m_list.clear();
@@ -381,7 +466,7 @@
     {
         return;
     }
-    
+
     dayConditions["sunny"] = WeatherData::ClearDay;
     dayConditions["clear"] = WeatherData::ClearDay;
     dayConditions["clear sky"] = WeatherData::ClearDay;
@@ -396,6 +481,7 @@
     dayConditions["fog"] = WeatherData::Mist;
     dayConditions["foggy"] = WeatherData::Mist;
     dayConditions["dense fog"] = WeatherData::Mist;
+    dayConditions["Thick Fog"] = WeatherData::Mist;
     dayConditions["tropical storm"] = WeatherData::Thunderstorm;
     dayConditions["hazy"] = WeatherData::Mist;
     dayConditions["light shower"] = WeatherData::LightShowersDay;
@@ -443,6 +529,7 @@
     nightConditions["fog"] = WeatherData::Mist;
     nightConditions["foggy"] = WeatherData::Mist;
     nightConditions["dense fog"] = WeatherData::Mist;
+    nightConditions["Thick Fog"] = WeatherData::Mist;
     nightConditions["tropical storm"] = WeatherData::Thunderstorm;
     nightConditions["hazy"] = WeatherData::Mist;
     nightConditions["light shower"] = WeatherData::LightShowersNight;
@@ -522,3 +609,5 @@
     monthNames["Nov"] = 11;
     monthNames["Dec"] = 12;
 }
+
+#include "BBCParser.moc"
--- trunk/KDE/kdeedu/marble/src/plugins/render/weather/BBCParser.h #1010842:1010843
@@ -17,6 +17,10 @@
 // Qt
 #include <QtCore/QHash>
 #include <QtCore/QList>
+#include <QtCore/QMutex>
+#include <QtCore/QPointer>
+#include <QtCore/QStack>
+#include <QtCore/QThread>
 #include <QtCore/QXmlStreamReader>
 
 class QByteArray;
@@ -25,14 +29,33 @@
 namespace Marble
 {
 
-class BBCParser : public QXmlStreamReader
+class BBCWeatherItem;
+
+struct ScheduleEntry {
+    QString path;
+    QPointer<BBCWeatherItem> item;
+    QString type;
+};
+
+class BBCParser : public QThread, public QXmlStreamReader
 {
+    Q_OBJECT;
 public:
     BBCParser();
+    ~BBCParser();
 
+    static BBCParser *instance();
+    void scheduleRead( const QString& path, BBCWeatherItem *item, const QString& type );
+
+protected:
+    void run();
+
+Q_SIGNALS:
+    void parsedFile();
+
+private:
     QList<WeatherData> read( QIODevice *device );
 
-private:
     void readUnknownElement();
     void readBBC();
     void readChannel();
@@ -44,6 +67,9 @@
     void setupHashes();
 
     QList<WeatherData> m_list;
+    QStack<ScheduleEntry> m_schedule;
+    QMutex m_runStateMutex;
+    bool m_end;
     
     static QHash<QString, WeatherData::WeatherCondition> dayConditions;
     static QHash<QString, WeatherData::WeatherCondition> nightConditions;
--- trunk/KDE/kdeedu/marble/src/plugins/render/weather/BBCWeatherItem.cpp #1010842:1010843
@@ -18,6 +18,7 @@
 // Qt
 #include <QtCore/QDebug>
 #include <QtCore/QFile>
+#include <QtCore/QTime>
 #include <QtCore/QUrl>
 
 using namespace Marble;
@@ -57,30 +58,9 @@
 
 void BBCWeatherItem::addDownloadedFile( const QString& url, const QString& type )
 {
-    if( type == "bbcobservation" ) {
-        QFile file( url );
-        if( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) {
-            return;
-        }
-        
-        BBCParser parser;
-        QList<WeatherData> data = parser.read( &file );
-        if( !data.isEmpty() ) {
-            setCurrentWeather( data.at( 0 ) );
-        }
+    if( type == "bbcobservation" || type == "bbcforecast" ) {
+        BBCParser::instance()->scheduleRead( url, this, type );
     }
-    else if ( type == "bbcforecast" ) {
-        QFile file( url );
-
-        if( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) {
-            return;
-        }
-
-        BBCParser parser;
-        QList<WeatherData> data = parser.read( &file );
-
-        addForecastWeather( data );
-    }
 }
 
 quint32 BBCWeatherItem::bbcId() const
--- trunk/KDE/kdeedu/marble/src/plugins/render/weather/BBCWeatherService.cpp #1010842:1010843
@@ -31,7 +31,12 @@
 using namespace Marble;
 
 BBCWeatherService::BBCWeatherService( QObject *parent ) 
-    : AbstractWeatherService( parent )
+    : AbstractWeatherService( parent ),
+      m_parsingStarted( false ),
+      m_parser( 0 ),
+      m_scheduledBox(),
+      m_scheduledNumber( 0 ),
+      m_scheduledFacade( 0 )
 {
 }
 
@@ -45,10 +50,17 @@
 {
     Q_UNUSED( facade );
 
-    if ( m_items.isEmpty() ) {
+    if ( !m_parsingStarted ) {
         setupList();
     }
-    
+
+    if ( m_items.isEmpty() ) {
+        m_scheduledBox = box;
+        m_scheduledNumber = number;
+        m_scheduledFacade = facade;
+        return;
+    }
+
     qint32 fetched = 0;
     QList<BBCWeatherItem *>::iterator it = m_items.begin();
     
@@ -63,18 +75,28 @@
     }
 }
 
-void BBCWeatherService::setupList()
+void BBCWeatherService::fetchStationList()
 {
-    QTime time;
-    QFile file( MarbleDirs::path( "weather/bbc-stations.xml" ) );
+    m_items = m_parser->stationList();
+    delete m_parser;
+    m_parser = 0;
 
-    if( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) {
-        return;
+    if ( m_scheduledNumber
+         && !m_scheduledBox.isNull()
+         && m_scheduledFacade ) {
+        getAdditionalItems( m_scheduledBox, m_scheduledFacade, m_scheduledNumber );
     }
+}
 
-    StationListParser parser( this );
-    m_items = parser.read( &file );
-    qDebug() << "Parsed station list in " << time.elapsed() << " ms and found " << m_items.size() << "items";
+void BBCWeatherService::setupList()
+{
+    m_parsingStarted = true;
+
+    m_parser = new StationListParser( this );
+    m_parser->setPath( MarbleDirs::path( "weather/bbc-stations.xml" ) );
+    connect( m_parser, SIGNAL( parsedStationList() ),
+             this,     SLOT( fetchStationList() ) );
+    m_parser->start( QThread::IdlePriority );
 }
 
 #include "BBCWeatherService.moc"
--- trunk/KDE/kdeedu/marble/src/plugins/render/weather/BBCWeatherService.h #1010842:1010843
@@ -13,10 +13,13 @@
 
 #include "AbstractWeatherService.h"
 
+#include "GeoDataLatLonAltBox.h"
+
 namespace Marble
 {
     
 class BBCWeatherItem;
+class StationListParser;
 
 class BBCWeatherService : public AbstractWeatherService
 {
@@ -31,10 +34,18 @@
                              MarbleDataFacade *facade,
                              qint32 number = 10 );
  
+ private Q_SLOTS:
+    void fetchStationList();
+
  private:
     void setupList();
 
     QList<BBCWeatherItem*> m_items;
+    bool m_parsingStarted;
+    StationListParser *m_parser;
+    GeoDataLatLonAltBox m_scheduledBox;
+    qint32 m_scheduledNumber;
+    MarbleDataFacade *m_scheduledFacade;
 };
 
 } // namespace Marble
--- trunk/KDE/kdeedu/marble/src/plugins/render/weather/StationListParser.cpp #1010842:1010843
@@ -18,6 +18,7 @@
 
 // Qt
 #include <QtCore/QDebug>
+#include <QtCore/QFile>
 #include <QtCore/QString>
 
 using namespace Marble;
@@ -34,14 +35,14 @@
 }
 
 StationListParser::StationListParser( QObject *parent )
-    : m_parent( parent )
+    : QThread( parent ),
+      QXmlStreamReader()
 {
 }
 
-QList<BBCWeatherItem*> StationListParser::read( QIODevice *device )
+void StationListParser::read()
 {
     m_list.clear();
-    setDevice( device );
 
     while ( !atEnd() ) {
         readNext();
@@ -53,10 +54,31 @@
                 raiseError( "The file is not an valid file." );
         }
     }
+}
 
+QList<BBCWeatherItem *> StationListParser::stationList() const
+{
     return m_list;
 }
 
+void StationListParser::setPath( QString path )
+{
+    m_path = path;
+}
+
+void StationListParser::run()
+{
+    QFile file( m_path );
+
+    if( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) {
+        return;
+    }
+
+    setDevice( &file );
+    read();
+    emit parsedStationList();
+}
+
 void StationListParser::readUnknownElement()
 {
     Q_ASSERT( isStartElement() );
@@ -97,7 +119,7 @@
     Q_ASSERT( isStartElement()
               && name() == "Station" );
     
-    BBCWeatherItem *item = new BBCWeatherItem( m_parent );
+    BBCWeatherItem *item = new BBCWeatherItem();
     
     while ( !atEnd() ) {
         readNext();
@@ -179,3 +201,5 @@
         }
     }
 }
+
+#include "StationListParser.moc"
--- trunk/KDE/kdeedu/marble/src/plugins/render/weather/StationListParser.h #1010842:1010843
@@ -15,6 +15,7 @@
 #include <QtCore/QHash>
 #include <QtCore/QStringList>
 #include <QtCore/QList>
+#include <QtCore/QThread>
 #include <QtCore/QXmlStreamReader>
 
 class QString;
@@ -24,13 +25,24 @@
 
 class BBCWeatherItem;
     
-class StationListParser : public QXmlStreamReader
+class StationListParser : public QThread, public QXmlStreamReader
 {
+    Q_OBJECT
 public:
     StationListParser( QObject *parent );
 
-    QList<BBCWeatherItem *> read( QIODevice *device );
+    void read();
 
+    QList<BBCWeatherItem *> stationList() const;
+
+    void setPath( QString path );
+
+Q_SIGNALS:
+    void parsedStationList();
+
+protected:
+    void run();
+
 private:
     void readUnknownElement();
     void readStationList();
@@ -38,6 +50,7 @@
     QString readCharacters();
     void readPoint( BBCWeatherItem *item );
 
+    QString m_path;
     QList<BBCWeatherItem *> m_list;
     QObject *m_parent;
 };
--- trunk/KDE/kdeedu/marble/src/plugins/render/weather/WeatherItem.cpp #1010842:1010843
@@ -347,6 +347,7 @@
     d->m_currentWeather = weather;
     d->updateToolTip();
     d->updateLabels();
+    emit updated();
 }
 
 QMap<QDate, WeatherData> WeatherItem::forecastWeather() const
@@ -359,6 +360,7 @@
     d->m_forecastWeather = forecasts;
 
     d->updateToolTip();
+    emit updated();
 }
 
 void WeatherItem::addForecastWeather( const QList<WeatherData>& forecasts )
@@ -389,6 +391,7 @@
     }
 
     d->updateToolTip();
+    emit updated();
 }
 
 quint8 WeatherItem::priority() const


More information about the Marble-commits mailing list