oopapidocs  2.0
metadatatable.cpp
00001 
00002 #include "abstractmetadataloader.h"
00003 #include "dbutils.h"
00004 #include "dbconnectionsettings.h"
00005 #include "metadatatable.h"
00006 #include "audiometadata.h"
00007 #include <QFileInfo>
00008 #include <QDirIterator>
00009 #include <QModelIndex>
00010 #include <QTime>
00011 #include <QSqlDatabase>
00012 #include <QSqlResult>
00013 #include <QSqlRecord>
00014 #include <QSqlField>
00015 #include <QSqlIndex>
00016 #include <QSqlError>
00017 #include <QDebug>
00018 #include <QApplication>
00019 #include <QSqlQuery>
00020 
00021 
00022 MetaDataTable* MetaDataTable::instance() {
00023     static MetaDataTable* retval = 0;
00024     QSqlDatabase db = DbConnectionSettings::lastSaved();
00025     if (!db.isValid()) {
00026         qDebug() << "Unable to create db connection.";
00027         abort();
00028     }
00029     if (retval == 0) {
00030         retval = new MetaDataTable(qApp);
00031     }
00032     return retval;
00033 }
00034 //start id=prepare
00035 MetaDataTable::MetaDataTable(QObject* parent)
00036     : QObject(parent), m_tableName("MetaData") {
00037     setObjectName(m_tableName);
00038     m_mdl = Abstract::MetaDataLoader::instance();
00039     m_driver = DbConnectionSettings::lastSaved().driverName();
00040     Q_ASSERT(createMetadataTable());
00041     QString preparedQuery = "INSERT into MetaData" /* Tested with MySQL5. */
00042          "(Artist, TrackTitle, AlbumTitle, TrackNumber, TrackTime, Genre,"
00043          "Preference, FileName, Comment) VALUES (:artist, :title, :album,"
00044          ":track, :time, :genre, :preference, :filename, :comment) "
00045          "ON DUPLICATE KEY UPDATE Preference=VALUES(Preference),"
00046          "Genre=VALUES(Genre), AlbumTitle=VALUES(AlbumTitle),"
00047          "TrackTitle=VALUES(TrackTitle), TrackNumber=VALUES(TrackNumber),"
00048          "Artist=VALUES(Artist), COMMENT=VALUES(Comment)"; 
00049     if (m_driver == "QSQLITE") {
00050         preparedQuery = "INSERT or REPLACE into MetaData"
00051             "(Artist, TrackTitle, AlbumTitle, TrackNumber, TrackTime, "
00052             "Genre, Preference, FileName, Comment)"
00053             "VALUES (:artist, :title, :album, :track, :time, :genre, "
00054             ":preference, :filename, :comment)";
00055     }
00056     bool prepSuccess = m_insertQuery.prepare(preparedQuery);
00057     if (!prepSuccess) {
00058         qDebug() << "Prepare fail: " << m_insertQuery.lastError().text() 
00059                  << m_insertQuery.lastQuery();
00060         abort();
00061     }
00062 //end
00063     m_deleteQuery = 
00064        QString("delete from MetaData where FileName = \"%1\"");
00065     connect (m_mdl, SIGNAL(fetched(MetaDataValue)),
00066              this, SLOT(insert(MetaDataValue)), Qt::QueuedConnection);
00067 }
00068 
00069 
00070 MetaDataTable::~MetaDataTable()
00071 {
00072     DbConnectionSettings::lastSaved().close();
00073 }
00074 
00075 //start id=create
00076 bool MetaDataTable::createMetadataTable() {
00077     QSqlDatabase db = DbConnectionSettings::lastSaved();
00078     if (m_driver == "QMYSQL")
00079        m_createTableQStr = QString("CREATE TABLE if not exists %1 ("
00080          "TrackTitle  text, Artist text, "
00081          "AlbumTitle  text, TrackTime integer, TrackNumber integer, "
00082          "Genre varchar(30),  Preference integer, Comment  text, "
00083          "FileName  varchar(255) PRIMARY KEY, INDEX(Genre) ) "
00084          "DEFAULT CHARSET utf8").arg(m_tableName);
00085     else m_createTableQStr = QString("CREATE TABLE IF NOT EXISTS %1 ("    /* 
00086             Tested with SQLite3. */
00087          "TrackTitle  text, Artist text, AlbumTitle  text, "
00088          "TrackTime integer, TrackNumber integer, Genre varchar(30), "
00089          "Preference integer, Comment  text, FileName  varchar(255) "
00090          "PRIMARY KEY)").arg(m_tableName);
00091     QSqlQuery q(m_createTableQStr);
00092     if (!q.isActive()) {
00093        qDebug() << "Create Table Fail: " << q.lastError().text() 
00094                 << q.lastQuery();
00095        return false;
00096     }
00097     db.commit();
00098     return true;
00099 }
00100 //end
00101 
00102 bool MetaDataTable::clearTable() {
00103     QSqlDatabase db = DbConnectionSettings::lastSaved();
00104     QSqlQuery q("delete from MetaData");
00105     return q.isActive();
00106 }
00107 //start id=select
00108 QStringList MetaDataTable::genres() const {
00109     QStringList sl;
00110     QSqlDatabase db = DbConnectionSettings::lastSaved();
00111     QSqlQuery q("SELECT DISTINCT Genre from MetaData");
00112     if (!q.isActive()) {
00113         qDebug() << "Query Failed: " << q.lastQuery() 
00114                  << q.lastError().text();
00115     } else while (q.next()) {
00116         sl << q.value(0).toString();
00117     }
00118     return sl;
00119 }
00120 //end
00121 
00122 //start id="insert"
00123 bool MetaDataTable::insert(const MetaDataValue &ft) {
00124     using namespace DbUtils;
00125 
00126     QSqlDatabase db = DbConnectionSettings::lastSaved();
00127     QSqlRecord record = db.record(m_tableName);
00128     if (record.isEmpty() && !createMetadataTable()) {
00129         qDebug() << "unable to create metadata: " 
00130                  << db.lastError().text();
00131         return false;
00132     }
00133 
00134     m_insertQuery.bindValue(":artist", ft.artist());
00135     m_insertQuery.bindValue(":title", ft.trackTitle());
00136     m_insertQuery.bindValue(":album", ft.albumTitle());
00137     m_insertQuery.bindValue(":track", ft.trackNumber());
00138     QTime t = ft.trackTime();
00139     int secs = QTime().secsTo(t);
00140     m_insertQuery.bindValue(":time", secs);
00141     m_insertQuery.bindValue(":genre", ft.genre());
00142     m_insertQuery.bindValue(":filename", ft.fileName());
00143     int pref = ft.preference().intValue();
00144     m_insertQuery.bindValue(":preference", pref);
00145     m_insertQuery.bindValue(":comment", ft.comment());
00146 
00147     bool retval = m_insertQuery.exec();
00148 
00149     if (!retval) {
00150         qDebug() << m_insertQuery.lastError().text() 
00151                  << m_insertQuery.lastQuery();
00152         abort();
00153     }
00154     emit inserted(ft);
00155     return retval;
00156 }
00157 //end
00158 
00159 bool MetaDataTable::
00160 hasMetaData(QString fileName, bool fetch, bool refresh) {
00161     MetaDataValue mdv = findRecord(fileName);
00162     if (refresh || (fetch && mdv.isNull())) {
00163         m_mdl->get(fileName);
00164     }
00165     return !mdv.isNull(); 
00166 }
00167 //start id="findrecord"
00168 MetaDataValue MetaDataTable::findRecord(QString fileName) {
00169     using namespace DbUtils;
00170     QFileInfo fi(fileName);
00171     MetaDataObject f;
00172     if (!fi.exists()) return f;                  /* Return a QObject by value? Don't forget, MetaDataValue is the base class of this particular QObject. */
00173     QString abs = fi.absoluteFilePath();
00174 
00175     QSqlDatabase db = DbConnectionSettings::lastSaved();
00176     QString qs = QString("select * from %1 where FileName = \"%2\"")
00177                   .arg(m_tableName).arg(escape(abs));
00178     QSqlQuery findQuery(qs);
00179     if (!findQuery.isActive()) {
00180         qDebug() << "Query Failed: " << findQuery.lastQuery() 
00181                  << findQuery.lastError().text();
00182         return f;
00183     }
00184     if (!findQuery.first()) return f;
00185     QSqlRecord rec = findQuery.record();
00186     for (int i=rec.count() -1; i >= 0; --i) {    /* Properties in QObject map to column names / field values in the table! */
00187         QSqlField field = rec.field(i);
00188         QString key = field.name();
00189         QVariant value = field.value();
00190         if (key == "Preference") {
00191             int v = value.toInt();
00192             Preference p(v);
00193             f.setPreference(p);
00194         }
00195         else if (key == "TrackTime") {           /* SQLite has no time type, so we must store as int. */
00196             QTime trackTime;
00197             trackTime = trackTime.addSecs(value.toInt());
00198             f.setTrackTime(trackTime);
00199         }
00200         else {
00201             f.setProperty(key, value);           /* Using QObject setProperty for other columns. */
00202         }
00203 
00204     }
00205     return f;                                    /* Create a value type from this local stack QObject about to be destroyed. */
00206 }
00207 //end
00208 QSet<QString> MetaDataTable::allSongs() {
00209     QSet<QString> retval;
00210     QSqlDatabase db = DbConnectionSettings::lastSaved();
00211     QSqlQuery q = db.exec("select FileName from MetaData");
00212     while (q.next()) {
00213         retval << q.value(0).toString();
00214     }
00215     return retval;
00216 }
00217 
00218 int MetaDataTable::visit(QString directory) {
00219 //    QSet<QString> loaded = allSongs();
00220     int i=0;
00221     QDirIterator itr(directory, m_mdl->supportedExtensions(),
00222                      QDir::Files, QDirIterator::Subdirectories);
00223     while (itr.hasNext()) {
00224         QString fn = itr.next();
00225         if (!hasMetaData(fn, true)) {
00226             ++i;
00227             qApp->processEvents();
00228         }
00229     }
00230     return i;
00231 }
00232 
00233 
00234 bool MetaDataTable::dropMetaData(QString fileName) {
00235     QString q = m_deleteQuery.arg(DbUtils::escape(fileName));
00236     QSqlQuery query(q);
00237 
00238 //    qDebug() << "drop: " << fileName;
00239     bool retval = query.isActive();
00240     qDebug() << query.lastQuery();
00241     return retval;
00242 }
00243 
 All Classes Namespaces Functions Enumerations