Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/library/browse/browsetablemodel.cpp

Go to the documentation of this file.
00001 
00002 #include <QtCore>
00003 #include <QtSql>
00004 #include <QStringList>
00005 #include <QtConcurrentRun>
00006 #include <QMetaType>
00007 #include <QMessageBox>
00008 
00009 #include "library/browse/browsetablemodel.h"
00010 #include "library/browse/browsethread.h"
00011 #include "soundsourceproxy.h"
00012 #include "mixxxutils.cpp"
00013 #include "playerinfo.h"
00014 #include "controlobject.h"
00015 #include "library/dao/trackdao.h"
00016 #include "audiotagger.h"
00017 
00018 
00019 BrowseTableModel::BrowseTableModel(QObject* parent, TrackCollection* pTrackCollection,
00020                                    RecordingManager* pRecordingManager)
00021         : TrackModel(pTrackCollection->getDatabase(), // TrackCollections m_db (defaultConnection)
00022                      "mixxx.db.model.browse"),
00023           QStandardItemModel(parent),
00024           m_pTrackCollection(pTrackCollection),
00025          m_pRecordingManager(pRecordingManager) {
00026     QStringList header_data;
00027     header_data.insert(COLUMN_FILENAME, tr("Filename"));
00028     header_data.insert(COLUMN_ARTIST, tr("Artist"));
00029     header_data.insert(COLUMN_TITLE, tr("Title"));
00030     header_data.insert(COLUMN_ALBUM, tr("Album"));
00031     header_data.insert(COLUMN_TRACK_NUMBER, tr("Track #"));
00032     header_data.insert(COLUMN_YEAR, tr("Year"));
00033     header_data.insert(COLUMN_GENRE, tr("Genre"));
00034     header_data.insert(COLUMN_COMMENT, tr("Comment"));
00035     header_data.insert(COLUMN_DURATION, tr("Duration"));
00036     header_data.insert(COLUMN_BPM, tr("BPM"));
00037     header_data.insert(COLUMN_KEY, tr("Key"));
00038     header_data.insert(COLUMN_TYPE, tr("Type"));
00039     header_data.insert(COLUMN_BITRATE, tr("Bitrate"));
00040     header_data.insert(COLUMN_LOCATION, tr("Location"));
00041 
00042     addSearchColumn(COLUMN_FILENAME);
00043     addSearchColumn(COLUMN_ARTIST);
00044     addSearchColumn(COLUMN_ALBUM);
00045     addSearchColumn(COLUMN_TITLE);
00046     addSearchColumn(COLUMN_GENRE);
00047     addSearchColumn(COLUMN_KEY);
00048     addSearchColumn(COLUMN_COMMENT);
00049 
00050     setHorizontalHeaderLabels(header_data);
00051     //register the QList<T> as a metatype since we use QueuedConnection below
00052     qRegisterMetaType< QList< QList<QStandardItem*> > >("QList< QList<QStandardItem*> >");
00053     qRegisterMetaType<BrowseTableModel*>("BrowseTableModel*");
00054 
00055     connect(BrowseThread::getInstance(), SIGNAL(clearModel(BrowseTableModel*)),
00056             this, SLOT(slotClear(BrowseTableModel*)),
00057             Qt::QueuedConnection);
00058 
00059     connect(BrowseThread::getInstance(), SIGNAL(rowsAppended(const QList< QList<QStandardItem*> >&, BrowseTableModel*)),
00060             this, SLOT(slotInsert(const QList< QList<QStandardItem*> >&, BrowseTableModel*)),
00061             Qt::QueuedConnection);
00062 
00063 }
00064 
00065 BrowseTableModel::~BrowseTableModel()
00066 {
00067 
00068 }
00069 
00070 const QList<int>& BrowseTableModel::searchColumns() const {
00071     return m_searchColumns;
00072 }
00073 
00074 void BrowseTableModel::addSearchColumn(int index) {
00075     m_searchColumns.push_back(index);
00076 }
00077 
00078 void BrowseTableModel::setPath(QString absPath)
00079 {
00080     m_current_path = absPath;
00081     BrowseThread::getInstance()->executePopulation(m_current_path, this);
00082 
00083 }
00084 
00085 TrackPointer BrowseTableModel::getTrack(const QModelIndex& index) const
00086 {
00087     QString track_location = getTrackLocation(index);
00088     if(m_pRecordingManager->getRecordingLocation() == track_location) {
00089         QMessageBox::critical(0, tr("Mixxx Library"),tr("Could not load the following file because"
00090                                                         " it is in use by Mixxx or another application.")
00091                               + "\n" +track_location);
00092         return TrackPointer();
00093     }
00094 
00095     TrackDAO& track_dao = m_pTrackCollection->getTrackDAO();
00096     int track_id = track_dao.getTrackId(track_location);
00097     if (track_id < 0) {
00098         // Add Track to library
00099         track_id = track_dao.addTrack(track_location, true);
00100     }
00101 
00102     return track_dao.getTrack(track_id);
00103 }
00104 
00105 QString BrowseTableModel::getTrackLocation(const QModelIndex& index) const
00106 {
00107     int row = index.row();
00108 
00109     QModelIndex index2 = this->index(row, COLUMN_LOCATION);
00110     return data(index2).toString();
00111 
00112 }
00113 
00114 int BrowseTableModel::getTrackId(const QModelIndex& index) const {
00115    Q_UNUSED(index);
00116    // We can't implement this as it stands.
00117     return -1;
00118 }
00119 
00120 const QLinkedList<int> BrowseTableModel::getTrackRows(int trackId) const {
00121    Q_UNUSED(trackId);
00122    // We can't implement this as it stands.
00123    return QLinkedList<int>();
00124 }
00125 
00126 void BrowseTableModel::search(const QString& searchText) {
00127    Q_UNUSED(searchText);
00128 }
00129 
00130 const QString BrowseTableModel::currentSearch() const {
00131     return QString();
00132 }
00133 
00134 bool BrowseTableModel::isColumnInternal(int) {
00135     return false;
00136 }
00137 
00138 bool BrowseTableModel::isColumnHiddenByDefault(int) {
00139     return false;
00140 }
00141 
00142 void BrowseTableModel::moveTrack(const QModelIndex&, const QModelIndex&) {
00143 
00144 }
00145 
00146 QItemDelegate* BrowseTableModel::delegateForColumn(const int) {
00147     return NULL;
00148 }
00149 
00150 void BrowseTableModel::removeTrack(const QModelIndex& index)
00151 {
00152     if(!index.isValid()) {
00153         return;
00154     }
00155     QStringList trackLocations;
00156     trackLocations.append(getTrackLocation(index));
00157     removeTracks(trackLocations);
00158 }
00159 
00160 void BrowseTableModel::removeTracks(const QModelIndexList& indices)
00161 {
00162     QStringList trackLocations;
00163     foreach (QModelIndex index, indices) {
00164         if (!index.isValid()) {
00165             continue;
00166         }
00167         trackLocations.append(getTrackLocation(index));
00168     }
00169     removeTracks(trackLocations);
00170 }
00171 
00172 void BrowseTableModel::removeTracks(QStringList trackLocations) {
00173     if (trackLocations.size() == 0)
00174         return;
00175 
00176     // Ask user if s/he is sure
00177     if (QMessageBox::question(NULL, tr("Mixxx Library"),
00178                              tr("Warning: This will permanently delete the following files:")
00179                              + "\n" + trackLocations.join("\n") + "\n" +
00180                              tr("Are you sure you want to delete these files from your computer?"),
00181                               QMessageBox::Yes, QMessageBox::Abort) == QMessageBox::Abort) {
00182         return;
00183     }
00184 
00185 
00186     bool any_deleted = false;
00187     TrackDAO& track_dao = m_pTrackCollection->getTrackDAO();
00188 
00189     foreach (QString track_location, trackLocations) {
00190         // If track is in use or deletion fails, show an error message.
00191         if (isTrackInUse(track_location) || !QFile::remove(track_location)) {
00192             QMessageBox::critical(0, tr("Mixxx Library"),tr("Could not delete the following file because"
00193                                                             " it is in use by Mixxx or another application:") + "\n" +track_location);
00194             continue;
00195         }
00196 
00197         qDebug() << "BrowseFeature: User deleted track " << track_location;
00198         any_deleted = true;
00199 
00200         // If the track was contained in the Mixxx library, delete it
00201         if (track_dao.trackExistsInDatabase(track_location)) {
00202             int id = track_dao.getTrackId(track_location);
00203             qDebug() << "BrowseFeature: Deletion affected database";
00204             track_dao.removeTrack(id);
00205         }
00206     }
00207 
00208     // Repopulate model if any tracks were actually deleted
00209     if (any_deleted) {
00210         BrowseThread::getInstance()->executePopulation(m_current_path, this);
00211     }
00212 }
00213 
00214 bool BrowseTableModel::addTrack(const QModelIndex& index, QString location)
00215 {
00216     Q_UNUSED(index);
00217     Q_UNUSED(location);
00218    return false;
00219 }
00220 
00221 QMimeData* BrowseTableModel::mimeData(const QModelIndexList &indexes) const {
00222     QMimeData *mimeData = new QMimeData();
00223     QList<QUrl> urls;
00224 
00225     //Ok, so the list of indexes we're given contains separates indexes for
00226     //each column, so even if only one row is selected, we'll have like 7 indexes.
00227     //We need to only count each row once:
00228     QList<int> rows;
00229 
00230     foreach (QModelIndex index, indexes) {
00231         if (index.isValid()) {
00232             if (!rows.contains(index.row())) {
00233                 rows.push_back(index.row());
00234                 QUrl url = QUrl::fromLocalFile(getTrackLocation(index));
00235                 if (!url.isValid())
00236                     qDebug() << "ERROR invalid url\n";
00237                 else {
00238                     urls.append(url);
00239                     qDebug() << "Appending URL:" << url;
00240                 }
00241             }
00242         }
00243     }
00244     mimeData->setUrls(urls);
00245     return mimeData;
00246 }
00247 
00248 void BrowseTableModel::slotClear(BrowseTableModel* caller_object)
00249 {
00250     if(caller_object == this)
00251         removeRows(0, rowCount());
00252 }
00253 
00254 void BrowseTableModel::slotInsert(const QList< QList<QStandardItem*> >& rows, BrowseTableModel* caller_object) {
00255     //There exists more than one BrowseTableModel in Mixxx
00256     //We only want to receive items here, this object has 'ordered' by the BrowserThread (singleton)
00257     if(caller_object == this) {
00258         //qDebug() << "BrowseTableModel::slotInsert";
00259         for(int i=0; i < rows.size(); ++i) {
00260             appendRow(rows.at(i));
00261         }
00262     }
00263 
00264 }
00265 
00266 TrackModel::CapabilitiesFlags BrowseTableModel::getCapabilities() const {
00267     // See src/library/trackmodel.h for the list of TRACKMODELCAPS
00268     return TRACKMODELCAPS_NONE
00269             | TRACKMODELCAPS_ADDTOPLAYLIST
00270             | TRACKMODELCAPS_ADDTOCRATE
00271             | TRACKMODELCAPS_ADDTOAUTODJ
00272             | TRACKMODELCAPS_LOADTODECK
00273             | TRACKMODELCAPS_LOADTOSAMPLER;
00274 }
00275 
00276 Qt::ItemFlags BrowseTableModel::flags(const QModelIndex &index) const{
00277 
00278     Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index);
00279 
00280     //Enable dragging songs from this data model to elsewhere (like the waveform
00281     //widget to load a track into a Player).
00282     defaultFlags |= Qt::ItemIsDragEnabled;
00283 
00284     QString track_location = getTrackLocation(index);
00285     int column = index.column();
00286 
00287     if(isTrackInUse(track_location) ||
00288        column == COLUMN_FILENAME ||
00289        column == COLUMN_BITRATE ||
00290        column == COLUMN_DURATION ||
00291        column == COLUMN_TYPE) {
00292         return defaultFlags;
00293     }
00294     else{
00295         return defaultFlags | Qt::ItemIsEditable;
00296     }
00297 }
00298 
00299 bool BrowseTableModel::isTrackInUse(QString &track_location) const
00300 {
00301     int decks = ControlObject::getControl(ConfigKey("[Master]","num_decks"))->get();
00302     //check if file is loaded to a deck
00303     for(int i=1; i <= decks; ++i) {
00304         TrackPointer loaded_track = PlayerInfo::Instance().getTrackInfo(QString("[Channel%1]").arg(i));
00305         if(loaded_track && (loaded_track->getLocation() == track_location)) {
00306             return true;
00307         }
00308     }
00309 
00310     if(m_pRecordingManager->getRecordingLocation() == track_location) {
00311         return true;
00312     }
00313 
00314     return false;
00315 }
00316 
00317 bool BrowseTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
00318 {
00319     Q_UNUSED(role);
00320 
00321    if(!index.isValid())
00322         return false;
00323     qDebug() << "BrowseTableModel::setData(" << index.data() << ")";
00324     int row = index.row();
00325     int col = index.column();
00326     QString track_location = getTrackLocation(index);
00327     AudioTagger tagger(track_location);
00328 
00329     //set tagger information
00330     tagger.setArtist(this->index(row,COLUMN_ARTIST).data().toString());
00331     tagger.setTitle(this->index(row,COLUMN_TITLE).data().toString());
00332     tagger.setAlbum(this->index(row,COLUMN_ALBUM).data().toString());
00333     tagger.setKey(this->index(row,COLUMN_KEY).data().toString());
00334     tagger.setBpm(this->index(row,COLUMN_BPM).data().toString());
00335     tagger.setComment(this->index(row,COLUMN_COMMENT).data().toString());
00336     tagger.setTracknumber(this->index(row,COLUMN_TRACK_NUMBER).data().toString());
00337     tagger.setYear(this->index(row,COLUMN_YEAR).data().toString());
00338     tagger.setGenre(this->index(row,COLUMN_GENRE).data().toString());
00339 
00340     //check if one the item were edited
00341     if(col == COLUMN_ARTIST) {
00342         tagger.setArtist(value.toString());
00343     } else if(col == COLUMN_TITLE) {
00344         tagger.setTitle(value.toString());
00345     } else if(col == COLUMN_ALBUM) {
00346         tagger.setAlbum(value.toString());
00347     } else if(col == COLUMN_BPM) {
00348         tagger.setBpm(value.toString());
00349     } else if(col == COLUMN_KEY) {
00350         tagger.setKey(value.toString());
00351     } else if(col == COLUMN_TRACK_NUMBER) {
00352         tagger.setTracknumber(value.toString());
00353     } else if(col == COLUMN_COMMENT) {
00354         tagger.setComment(value.toString());
00355     } else if(col == COLUMN_GENRE) {
00356         tagger.setGenre(value.toString());
00357     } else if(col == COLUMN_YEAR) {
00358         tagger.setYear(value.toString());
00359     }
00360 
00361 
00362     QStandardItem* item = itemFromIndex(index);
00363     if(tagger.save()) {
00364         //Modify underlying interalPointer object
00365         item->setText(value.toString());
00366         return true;
00367     }
00368     else {
00369         //reset to old value in error
00370         item->setText(index.data().toString());
00371         QMessageBox::critical(0, tr("Mixxx Library"),tr("Could not update file metadata.")
00372                               + "\n" +track_location);
00373         return false;
00374     }
00375 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines