16.3.  The Façade Pattern

[ fromfile: facade.xml id: facade ]

Figure 16.4.  MetaDataLoader and MetaDataValue

MetaDataLoader and MetaDataValue

Example 16.16. src/libs/metadata/metadatavalue.h

[ . . . . ]
class METADATAEXPORT MetaDataValue {
public:

    friend METADATAEXPORT QTextStream& operator<< (QTextStream& os, 
                                         const MetaDataValue& mdv);
    friend METADATAEXPORT QTextStream& operator>> (QTextStream& is,
                                         MetaDataValue& mdv);
    friend METADATAEXPORT QDataStream& operator<< (QDataStream& os,
                                         const MetaDataValue& mdv);
    friend METADATAEXPORT QDataStream& operator>> (QDataStream& is,
                                         MetaDataValue& mdv);
    friend METADATAEXPORT bool operator==(const MetaDataValue&,
                                          const MetaDataValue&);
[ . . . . ]
    virtual QString fileName() const ;
    virtual Preference preference() const ;
    virtual QString genre() const;
    virtual QString artist() const;
    virtual QString albumTitle() const;
    virtual QString trackTitle() const;
    virtual QString trackNumber() const;
    virtual const QImage &image() const;
    virtual QTime trackTime() const;
    virtual QString trackTimeString() const;
    virtual QString comment() const;
[ . . . . ]
protected:
    bool m_isNull;
    QUrl m_Url;
    QString m_TrackNumber;
    QString m_TrackTitle;
    QString m_Comment;
    Preference m_Preference;
    QString m_Genre;
    QString m_Artist;
    QTime m_TrackTime;
    QString m_AlbumTitle;
    QImage m_Image;
};
Q_DECLARE_METATYPE(MetaDataValue);  1
[ . . . . ]

1

Add to QVariant type system.


Example 16.17. src/libs/metadata/abstractmetadataloader.h

[ . . . . ]
namespace Abstract {
class METADATAEXPORT MetaDataLoader : public QObject {
    Q_OBJECT
public:
    
    explicit MetaDataLoader(QObject *parent = 0) 
    	: QObject(parent) {}
    static MetaDataLoader* instance();
    virtual MetaDataLoader* clone(QObject* parent=0) = 0;
    virtual ~MetaDataLoader();
    virtual const QStringList& supportedExtensions() = 0;
    virtual void get(QString path) = 0;
    virtual void get(QStringList path) = 0;
    virtual bool isRunning() const = 0;
public slots:
    virtual void cancel() = 0;
    
signals:
    void fetched(const MetaDataValue& mdv);
    void progressValueChanged(int);
    void progressRangeChanged(int, int);
    void finished();

};
}

#endif // AMETADATALOADER_H

Example 16.18. src/libs/filetagger/tmetadataloader.h

[ . . . . ]
class FILETAGGER_EXPORT MetaDataLoader 
                          : public Abstract::MetaDataLoader {
    Q_OBJECT
public:
    typedef Abstract::MetaDataLoader SUPER;
    explicit MetaDataLoader(QObject *parent = 0);
    static MetaDataLoader* instance();
    virtual ~MetaDataLoader() {}
    const QStringList &supportedExtensions() ;
    MetaDataLoader* clone(QObject *parent) ;
    void get(QString path);
    void get(QStringList path);
    bool isRunning() const {return m_running;}
public slots:
    void cancel();
private slots:
    void checkForWork();

private:
    bool m_running;
    bool m_canceled;
    int m_processingMax;
    QStringList m_queue;
    QTimer m_timer;
};
}

[ . . . . ]

Example 16.19. src/libs/filetagger/tmetadataloader.cpp

[ . . . . ]

TagLib::MetaDataLoader::MetaDataLoader(QObject *parent) :
    SUPER(parent) {
    m_processingMax = 0;
    m_running = false;
    qDebug() << "TagLib::MetaDataLoader created.";
    connect (this, SIGNAL(finished()), this, SLOT(checkForWork()),
             Qt::QueuedConnection);
}

void TagLib::MetaDataLoader::get(QString path) {
    m_queue << path;
    m_timer.singleShot(2000, this, SLOT(checkForWork()));
}

void TagLib::MetaDataLoader::checkForWork() {
    MetaDataFunctor functor;
    if (m_queue.isEmpty() && !m_running) {
        m_processingMax = 0;
        return;
    }
    if (m_running ) return;
    m_running = true;
    m_canceled = false;
    while (!m_queue.isEmpty()) {
        QStringList sl = m_queue;
        m_queue = QStringList();
        m_processingMax = sl.length();
        emit progressRangeChanged(0, m_processingMax);
        for (int i=0; i<m_processingMax;++i) {
            if (m_canceled) break;
            emit fetched(functor(sl[i]));
            emit progressValueChanged(i);
            qApp->processEvents();          1
        }
        m_running = false;
    }
    emit finished();
}

1

Allow the GUI to process events (and our signals to be delivered).


Example 16.20. src/libs/filetagger/tmetadataloader.cpp

[ . . . . ]

MetaDataValue MetaDataFunctor::operator ()(QString path) {
    using namespace TagLib;
    MetaDataValue retval;
    FileRef f(path.toLocal8Bit().constData());
    const Tag* t = f.tag();
    Q_ASSERT( t != NULL ) ;
    retval.setFileName(path);
    retval.setTrackTitle(toQString(t->title()));
    retval.setArtist(toQString(t->artist()));
    retval.setAlbumTitle(toQString(t->album()));
[ . . . . ]

    QTime time(0,0,0,0);
    const AudioProperties* ap = f.audioProperties();
    time = time.addSecs(ap->length());
    retval.setTrackTime(time);
    return retval;
}

[Note] qRegisterMetaType() and Queued Connections

You must call qRegisterMetaType<MetaDataValue>("MetaDataValue") before emitting signals over queued connections with MetaDataValue parameters. This is because under the covers, another instance is being created dynamically by QMetaType::construct().