Mixxx

/home/maxime/Projets/Mixxx/1.10/mixxx/src/library/sidebarmodel.cpp

Go to the documentation of this file.
00001 #include <QtDebug>
00002 #include <QUrl>
00003 #include <QApplication>
00004 
00005 #include "library/libraryfeature.h"
00006 #include "library/sidebarmodel.h"
00007 #include "library/treeitem.h"
00008 
00009 SidebarModel::SidebarModel(QObject* parent)
00010         : QAbstractItemModel(parent),
00011           m_iDefaultSelectedIndex(0) {
00012 }
00013 
00014 SidebarModel::~SidebarModel() {
00015 
00016 }
00017 
00018 void SidebarModel::addLibraryFeature(LibraryFeature* feature) {
00019     m_sFeatures.push_back(feature);
00020     connect(feature, SIGNAL(featureUpdated()), this, SLOT(refreshData()));
00021     connect(feature, SIGNAL(featureIsLoading(LibraryFeature*)),
00022             this, SLOT(slotFeatureIsLoading(LibraryFeature*)));
00023     connect(feature, SIGNAL(featureLoadingFinished(LibraryFeature*)),
00024             this,SLOT(slotFeatureLoadingFinished(LibraryFeature*)));
00025 
00026     QAbstractItemModel* model = feature->getChildModel();
00027 
00028     connect(model, SIGNAL(modelReset()),
00029             this, SLOT(slotModelReset()));
00030     connect(model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)),
00031             this, SLOT(slotDataChanged(const QModelIndex&,const QModelIndex&)));
00032 
00033     connect(model, SIGNAL(rowsAboutToBeInserted(const QModelIndex&, int, int)),
00034             this, SLOT(slotRowsAboutToBeInserted(const QModelIndex&, int, int)));
00035     connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)),
00036             this, SLOT(slotRowsAboutToBeRemoved(const QModelIndex&, int, int)));
00037     connect(model, SIGNAL(rowsInserted(const QModelIndex&, int, int)),
00038             this, SLOT(slotRowsInserted(const QModelIndex&, int, int)));
00039     connect(model, SIGNAL(rowsRemoved(const QModelIndex&, int, int)),
00040             this, SLOT(slotRowsRemoved(const QModelIndex&, int, int)));
00041 
00042 }
00043 
00044 QModelIndex SidebarModel::getDefaultSelection() {
00045     if (m_sFeatures.size() == 0)
00046         return QModelIndex();
00047     return createIndex(m_iDefaultSelectedIndex, 0, (void*)this);
00048 }
00049 
00050 void SidebarModel::setDefaultSelection(unsigned int index)
00051 {
00052     m_iDefaultSelectedIndex = index;
00053 }
00054 
00055 void SidebarModel::activateDefaultSelection() {
00056     if (m_sFeatures.size() > 0) {
00057         m_sFeatures[m_iDefaultSelectedIndex]->activate();
00058     }
00059 }
00060 
00061 void SidebarModel::refreshData()
00062 {
00063     //Reset all the model indices and refresh all the data.
00064     //TODO: Could do something nicer when a feature's children change,
00065     //      but the features know nothing about their model indices,
00066     //      so they can't do stuff like beginInsertRow() to help the
00067     //      model manage the indices.
00068     //reset();
00069 }
00070 
00071 QModelIndex SidebarModel::index(int row, int column,
00072                                 const QModelIndex& parent) const {
00073     // qDebug() << "SidebarModel::index row=" << row
00074       //       << "column=" << column << "parent=" << parent.data();
00075     if (parent.isValid()) {
00076         /* If we have selected the root of a library feature at position 'row'
00077          * its internal pointer is the current sidebar object model
00078          * we return its associated childmodel
00079          */
00080         if (parent.internalPointer() == this) {
00081             const QAbstractItemModel* childModel = m_sFeatures[parent.row()]->getChildModel();
00082             QModelIndex childIndex = childModel->index(row, column);
00083             TreeItem* tree_item = (TreeItem*)childIndex.internalPointer();
00084             if (tree_item && childIndex.isValid()) {
00085                 return createIndex(childIndex.row(), childIndex.column(), (void*)tree_item);
00086             } else {
00087                 return QModelIndex();
00088             }
00089         } else {
00090             // We have selected an item within the childmodel
00091             // This item has always an internal pointer of (sub)type TreeItem
00092             TreeItem* tree_item = (TreeItem*)parent.internalPointer();
00093             return createIndex(row, column, (void*) tree_item->child(row));
00094         }
00095     }
00096     return createIndex(row, column, (void*)this);
00097 }
00098 
00099 QModelIndex SidebarModel::parent(const QModelIndex& index) const {
00100     //qDebug() << "SidebarModel::parent index=" << index.data();
00101     if (index.isValid()) {
00102         /* If we have selected the root of a library feature
00103          * its internal pointer is the current sidebar object model
00104          * A root library feature has no parent and thus we return
00105          * an invalid QModelIndex
00106          */
00107         if (index.internalPointer() == this) {
00108             return QModelIndex();
00109         } else {
00110             TreeItem* tree_item = (TreeItem*)index.internalPointer();
00111             // if we have selected an item at the first level of a childnode
00112             if (tree_item->parent()->data() == "$root"){
00113                 LibraryFeature* feature = tree_item->getFeature();
00114                 for (int i = 0; i < m_sFeatures.size(); ++i) {
00115                     if (feature == m_sFeatures[i]) {
00116                          // create a ModelIndex for parent 'this' having a
00117                          // library feature at position 'i'
00118                         return createIndex(i, 0, (void*)this);
00119                     }
00120                 }
00121             }
00122             // if we have selected an item at some deeper level of a childnode
00123             return createIndex(tree_item->parent()->row(), 0 , tree_item->parent());
00124         }
00125     }
00126     return QModelIndex();
00127 }
00128 
00129 int SidebarModel::rowCount(const QModelIndex& parent) const {
00130     //qDebug() << "SidebarModel::rowCount parent=" << parent.data();
00131     if (parent.isValid()) {
00132         if (parent.internalPointer() == this) {
00133             return m_sFeatures[parent.row()]->getChildModel()->rowCount();
00134         } else {
00135             // We support tree models deeper than 1 level
00136             TreeItem* tree_item = (TreeItem*)parent.internalPointer();
00137             if (tree_item) {
00138                 return tree_item->childCount();
00139             }
00140             return 0;
00141         }
00142     }
00143     return m_sFeatures.size();
00144 }
00145 
00146 int SidebarModel::columnCount(const QModelIndex& parent) const {
00147     //qDebug() << "SidebarModel::columnCount parent=" << parent;
00148     // TODO(rryan) will we ever have columns? I don't think so.
00149     return 1;
00150 }
00151 
00152 bool SidebarModel::hasChildren(const QModelIndex& parent) const {
00153     if (parent.isValid()) {
00154         if (parent.internalPointer() == this) {
00155             return QAbstractItemModel::hasChildren(parent);
00156         }
00157         else
00158         {
00159             TreeItem* tree_item = (TreeItem*)parent.internalPointer();
00160             if (tree_item) {
00161                 LibraryFeature* feature = tree_item->getFeature();
00162                 return feature->getChildModel()->hasChildren(parent);
00163             }
00164         }
00165     }
00166 
00167     return QAbstractItemModel::hasChildren(parent);
00168 }
00169 
00170 QVariant SidebarModel::data(const QModelIndex& index, int role) const {
00171     // qDebug("SidebarModel::data row=%d column=%d pointer=%8x, role=%d",
00172     //        index.row(), index.column(), index.internalPointer(), role);
00173     if (index.isValid()) {
00174         if (index.internalPointer() == this) {
00175             if (role == Qt::DisplayRole) {
00176                 return m_sFeatures[index.row()]->title();
00177             } else if (role == Qt::DecorationRole) {
00178                 return m_sFeatures[index.row()]->getIcon();
00179             }
00180         } else {
00181             TreeItem* tree_item = (TreeItem*)index.internalPointer();
00182 
00183             if (tree_item) {
00184                 if (role == Qt::DisplayRole) {
00185                     return tree_item->data();
00186                 } else if (role == Qt::DecorationRole) {
00187                     return tree_item->getIcon();
00188                 }
00189             }
00190         }
00191     }
00192     return QVariant();
00193 }
00194 
00195 void SidebarModel::clicked(const QModelIndex& index) {
00196     //qDebug() << "SidebarModel::clicked() index=" << index;
00197 
00198     // We use clicked() for keyboard and mouse control, and the
00199     // following code breaks that for us:
00200     /*if (QApplication::mouseButtons() != Qt::LeftButton) {
00201         return;
00202     }*/
00203 
00204     if (index.isValid()) {
00205         if (index.internalPointer() == this) {
00206             m_sFeatures[index.row()]->activate();
00207         } else {
00208             TreeItem* tree_item = (TreeItem*)index.internalPointer();
00209             if (tree_item) {
00210                 LibraryFeature* feature = tree_item->getFeature();
00211                 feature->activateChild(index);
00212             }
00213         }
00214     }
00215 }
00216 void SidebarModel::doubleClicked(const QModelIndex& index) {
00217     if (index.isValid()) {
00218         if (index.internalPointer() == this) {
00219            return;
00220         } else {
00221             TreeItem* tree_item = (TreeItem*)index.internalPointer();
00222             if (tree_item) {
00223                 LibraryFeature* feature = tree_item->getFeature();
00224                 feature->onLazyChildExpandation(index);
00225             }
00226         }
00227     }
00228 }
00229 
00230 void SidebarModel::rightClicked(const QPoint& globalPos, const QModelIndex& index) {
00231     //qDebug() << "SidebarModel::rightClicked() index=" << index;
00232     if (index.isValid()) {
00233         if (index.internalPointer() == this) {
00234             m_sFeatures[index.row()]->activate();
00235             m_sFeatures[index.row()]->onRightClick(globalPos);
00236         }
00237         else
00238         {
00239             TreeItem* tree_item = (TreeItem*)index.internalPointer();
00240             if (tree_item) {
00241                 LibraryFeature* feature = tree_item->getFeature();
00242                 feature->activateChild(index);
00243                 feature->onRightClickChild(globalPos, index);
00244             }
00245         }
00246     }
00247 }
00248 
00249 bool SidebarModel::dropAccept(const QModelIndex& index, QUrl url) {
00250     //qDebug() << "SidebarModel::dropAccept() index=" << index << url;
00251     if (index.isValid()) {
00252         if (index.internalPointer() == this) {
00253             return m_sFeatures[index.row()]->dropAccept(url);
00254         } else {
00255             TreeItem* tree_item = (TreeItem*)index.internalPointer();
00256             if (tree_item) {
00257                 LibraryFeature* feature = tree_item->getFeature();
00258                 return feature->dropAcceptChild(index, url);
00259             }
00260         }
00261     }
00262 
00263     return false;
00264 }
00265 
00266 bool SidebarModel::dragMoveAccept(const QModelIndex& index, QUrl url)
00267 {
00268     //qDebug() << "SidebarModel::dragMoveAccept() index=" << index << url;
00269     if (index.isValid()) {
00270         if (index.internalPointer() == this) {
00271             return m_sFeatures[index.row()]->dragMoveAccept(url);
00272         } else {
00273             TreeItem* tree_item = (TreeItem*)index.internalPointer();
00274             if (tree_item) {
00275                 LibraryFeature* feature = tree_item->getFeature();
00276                 return feature->dragMoveAcceptChild(index, url);
00277             }
00278         }
00279     }
00280     return false;
00281 }
00282 
00283 // Translates an index from the child models to an index of the sidebar models
00284 QModelIndex SidebarModel::translateSourceIndex(const QModelIndex& index) {
00285     QModelIndex translatedIndex;
00286 
00287     /* These method is called from the slot functions below.
00288      * QObject::sender() return the object which emitted the signal
00289      * handled by the slot functions.
00290 
00291      * For child models, this always the child models itself
00292      */
00293 
00294     const QAbstractItemModel* model = dynamic_cast<QAbstractItemModel*>(sender());
00295 
00296     Q_ASSERT(model);
00297     if (index.isValid()) {
00298        TreeItem* item = (TreeItem*)index.internalPointer();
00299        translatedIndex = createIndex(index.row(), index.column(), item);
00300     }
00301     else
00302     {
00303         //Comment from Tobias Rafreider --> Dead Code????
00304 
00305         for (int i = 0; i < m_sFeatures.size(); ++i) {
00306             if (m_sFeatures[i]->getChildModel() == model) {
00307                 translatedIndex = createIndex(i, 0, (void*)this);
00308             }
00309         }
00310     }
00311     return translatedIndex;
00312 }
00313 
00314 void SidebarModel::slotDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) {
00315     //qDebug() << "slotDataChanged topLeft:" << topLeft << "bottomRight:" << bottomRight;
00316 }
00317 
00318 void SidebarModel::slotRowsAboutToBeInserted(const QModelIndex& parent, int start, int end) {
00319     //qDebug() << "slotRowsABoutToBeInserted" << parent << start << end;
00320 
00321     QModelIndex newParent = translateSourceIndex(parent);
00322     beginInsertRows(newParent, start, end);
00323 }
00324 
00325 void SidebarModel::slotRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) {
00326     //qDebug() << "slotRowsABoutToBeRemoved" << parent << start << end;
00327 
00328     QModelIndex newParent = translateSourceIndex(parent);
00329     beginRemoveRows(newParent, start, end);
00330 }
00331 
00332 void SidebarModel::slotRowsInserted(const QModelIndex& parent, int start, int end) {
00333    // qDebug() << "slotRowsInserted" << parent << start << end;
00334     //QModelIndex newParent = translateSourceIndex(parent);
00335     endInsertRows();
00336 }
00337 
00338 void SidebarModel::slotRowsRemoved(const QModelIndex& parent, int start, int end) {
00339     //qDebug() << "slotRowsRemoved" << parent << start << end;
00340     //QModelIndex newParent = translateSourceIndex(parent);
00341     endRemoveRows();
00342 }
00343 
00344 void SidebarModel::slotModelReset() {
00345     // If a child model is reset, we can't really do anything but reset(). This
00346     // will close any open items.
00347     reset();
00348 }
00349 
00350 /*
00351  * Call this slot whenever the title of the feature has changed.
00352  * See RhythmboxFeature for an example.
00353  * While the rhythmbox music collection is parsed
00354  * the title becomes 'Rhythmbox (loading)'
00355  */
00356 void SidebarModel::slotFeatureIsLoading(LibraryFeature * feature)
00357 {
00358     featureRenamed(feature);
00359     selectFeature(feature);
00360 }
00361 
00362 /* Tobias: This slot is somewhat redundant but I decided
00363  * to leave it for code readability reasons
00364  */
00365 void SidebarModel::slotFeatureLoadingFinished(LibraryFeature * feature){
00366     featureRenamed(feature);
00367     selectFeature(feature);
00368 }
00369 
00370 void SidebarModel::featureRenamed(LibraryFeature* pFeature){
00371     for (int i=0; i < m_sFeatures.size(); ++i) {
00372         if (m_sFeatures[i] == pFeature) {
00373             QModelIndex ind = index(i, 0);
00374             emit(dataChanged(ind, ind));
00375         }
00376     }
00377 }
00378 
00379 void SidebarModel::selectFeature(LibraryFeature* pFeature) {
00380     for (int i=0; i < m_sFeatures.size(); ++i) {
00381         if (m_sFeatures[i] == pFeature) {
00382             QModelIndex ind = index(i, 0);
00383             emit(selectIndex(ind));
00384         }
00385     }
00386 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines