![]() |
Mixxx
|
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 }