File indexing completed on 2025-01-05 04:00:10
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2008-11-15 0007 * Description : collections setup tab model/view 0008 * 0009 * SPDX-FileCopyrightText: 2008-2012 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0010 * SPDX-FileCopyrightText: 2005-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * SPDX-FileCopyrightText: 2012 by Andi Clemens <andi dot clemens at gmail dot com> 0012 * 0013 * SPDX-License-Identifier: GPL-2.0-or-later 0014 * 0015 * ============================================================ */ 0016 0017 #define INTERNALID 65535 0018 0019 #include "setupcollectionview.h" 0020 0021 // Qt includes 0022 0023 #include <QGroupBox> 0024 #include <QLabel> 0025 #include <QDir> 0026 #include <QGridLayout> 0027 #include <QHeaderView> 0028 #include <QHBoxLayout> 0029 #include <QMessageBox> 0030 #include <QStandardPaths> 0031 #include <QComboBox> 0032 #include <QUrlQuery> 0033 #include <QUrl> 0034 #include <QIcon> 0035 #include <QDialog> 0036 #include <QDialogButtonBox> 0037 #include <QVBoxLayout> 0038 #include <QApplication> 0039 0040 // KDE includes 0041 0042 #include <klocalizedstring.h> 0043 0044 // Local includes 0045 0046 #include "dmessagebox.h" 0047 #include "dfiledialog.h" 0048 #include "applicationsettings.h" 0049 #include "collectionmanager.h" 0050 #include "newitemsfinder.h" 0051 #include "dtextedit.h" 0052 #include "digikam_globals.h" 0053 0054 namespace Digikam 0055 { 0056 0057 SetupCollectionDelegate::SetupCollectionDelegate(QAbstractItemView* const view, QObject* const parent) 0058 : DWItemDelegate(view, parent), 0059 m_categoryMaxStyledWidth(0) 0060 { 0061 // We keep a standard delegate that does all the normal drawing work for us 0062 // DWItemDelegate handles the widgets, for the rest of the work we act as a proxy to m_styledDelegate 0063 0064 m_styledDelegate = new QStyledItemDelegate(parent); 0065 0066 // forward all signals 0067 0068 connect(m_styledDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)), 0069 this, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint))); 0070 0071 connect(m_styledDelegate, SIGNAL(commitData(QWidget*)), 0072 this, SIGNAL(commitData(QWidget*))); 0073 0074 connect(m_styledDelegate, SIGNAL(sizeHintChanged(QModelIndex)), 0075 this, SIGNAL(sizeHintChanged(QModelIndex))); 0076 0077 // For size hint. To get a valid size hint, the widgets seem to need a parent widget 0078 0079 m_samplePushButton = new QPushButton(view); 0080 m_samplePushButton->hide(); 0081 m_sampleAppendButton = new QToolButton(view); 0082 m_sampleAppendButton->hide(); 0083 m_sampleUpdateButton = new QToolButton(view); 0084 m_sampleUpdateButton->hide(); 0085 m_sampleDeleteButton = new QToolButton(view); 0086 m_sampleDeleteButton->hide(); 0087 } 0088 0089 SetupCollectionDelegate::~SetupCollectionDelegate() 0090 { 0091 } 0092 0093 QList<QWidget*> SetupCollectionDelegate::createItemWidgets(const QModelIndex& /*index*/) const 0094 { 0095 // We only need a push button for certain indexes and two tool button for others, 0096 // but we have no index here, but need to provide the widgets for each index 0097 0098 QList<QWidget*> list; 0099 QPushButton* const pushButton = new QPushButton(); 0100 list << pushButton; 0101 0102 connect(pushButton, &QPushButton::clicked, 0103 this, [this, pushButton]() { Q_EMIT categoryButtonPressed(pushButton->property("id").toInt()); }); 0104 0105 QToolButton* const appendButton = new QToolButton(); 0106 appendButton->setToolTip(i18nc("@info:tooltip", "Append a path to the collection.")); 0107 appendButton->setAutoRaise(true); 0108 list << appendButton; 0109 0110 connect(appendButton, &QToolButton::clicked, 0111 this, [this, appendButton]() { Q_EMIT appendPressed(appendButton->property("id").toInt()); }); 0112 0113 QToolButton* const updateButton = new QToolButton(); 0114 updateButton->setToolTip(i18nc("@info:tooltip", "Updates the path of the collection.")); 0115 updateButton->setAutoRaise(true); 0116 list << updateButton; 0117 0118 connect(updateButton, &QToolButton::clicked, 0119 this, [this, updateButton]() { Q_EMIT updatePressed(updateButton->property("id").toInt()); }); 0120 0121 QToolButton* const deleteButton = new QToolButton(); 0122 deleteButton->setToolTip(i18nc("@info:tooltip", "Removes the collection from digiKam.")); 0123 deleteButton->setAutoRaise(true); 0124 list << deleteButton; 0125 0126 connect(deleteButton, &QToolButton::clicked, 0127 this, [this, deleteButton]() { Q_EMIT deletePressed(deleteButton->property("id").toInt()); }); 0128 0129 return list; 0130 } 0131 0132 QSize SetupCollectionDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const 0133 { 0134 // get default size hint 0135 0136 QSize hint = m_styledDelegate->sizeHint(option, index); 0137 0138 // We need to handle those two cases where we display widgets 0139 0140 if (index.data(SetupCollectionModel::IsCategoryRole).toBool()) 0141 { 0142 // get the largest size hint for the icon/text of all category entries 0143 0144 int maxStyledWidth = 0; 0145 0146 Q_FOREACH (const QModelIndex& catIndex, static_cast<const SetupCollectionModel*>(index.model())->categoryIndexes()) 0147 { 0148 maxStyledWidth = qMax(maxStyledWidth, m_styledDelegate->sizeHint(option, catIndex).width()); 0149 } 0150 0151 const_cast<SetupCollectionDelegate*>(this)->m_categoryMaxStyledWidth = maxStyledWidth; 0152 0153 // set real text on sample button to compute correct size hint 0154 0155 m_samplePushButton->setText(index.data(SetupCollectionModel::CategoryButtonDisplayRole).toString()); 0156 QSize widgetHint = m_samplePushButton->sizeHint(); 0157 0158 // add largest of the icon/text sizes (so that all buttons are aligned) and our button size hint 0159 0160 hint.setWidth(m_categoryMaxStyledWidth + widgetHint.width()); 0161 hint.setHeight(qMax(hint.height(), widgetHint.height())); 0162 } 0163 else if (index.data(SetupCollectionModel::IsAppendRole).toBool()) 0164 { 0165 // set real pixmap on sample button to compute correct size hint 0166 0167 QIcon pix = index.data(SetupCollectionModel::AppendDecorationRole).value<QIcon>(); 0168 m_sampleAppendButton->setIcon(index.data(SetupCollectionModel::AppendDecorationRole).value<QIcon>()); 0169 QSize widgetHint = m_sampleAppendButton->sizeHint(); 0170 0171 // combine hints 0172 0173 hint.setWidth(hint.width() + widgetHint.width()); 0174 hint.setHeight(qMax(hint.height(), widgetHint.height())); 0175 } 0176 else if (index.data(SetupCollectionModel::IsUpdateRole).toBool()) 0177 { 0178 // set real pixmap on sample button to compute correct size hint 0179 0180 QIcon pix = index.data(SetupCollectionModel::UpdateDecorationRole).value<QIcon>(); 0181 m_sampleUpdateButton->setIcon(index.data(SetupCollectionModel::UpdateDecorationRole).value<QIcon>()); 0182 QSize widgetHint = m_sampleUpdateButton->sizeHint(); 0183 0184 // combine hints 0185 0186 hint.setWidth(hint.width() + widgetHint.width()); 0187 hint.setHeight(qMax(hint.height(), widgetHint.height())); 0188 } 0189 else if (index.data(SetupCollectionModel::IsDeleteRole).toBool()) 0190 { 0191 // set real pixmap on sample button to compute correct size hint 0192 0193 QIcon pix = index.data(SetupCollectionModel::DeleteDecorationRole).value<QIcon>(); 0194 m_sampleDeleteButton->setIcon(index.data(SetupCollectionModel::DeleteDecorationRole).value<QIcon>()); 0195 QSize widgetHint = m_sampleDeleteButton->sizeHint(); 0196 0197 // combine hints 0198 0199 hint.setWidth(hint.width() + widgetHint.width()); 0200 hint.setHeight(qMax(hint.height(), widgetHint.height())); 0201 } 0202 0203 return hint; 0204 } 0205 0206 void SetupCollectionDelegate::updateItemWidgets(const QList<QWidget*>& widgets, 0207 const QStyleOptionViewItem& option, 0208 const QPersistentModelIndex& index) const 0209 { 0210 QPushButton* const pushButton = static_cast<QPushButton*>(widgets.at(0)); 0211 QToolButton* const appendButton = static_cast<QToolButton*>(widgets.at(1)); 0212 QToolButton* const updateButton = static_cast<QToolButton*>(widgets.at(2)); 0213 QToolButton* const deleteButton = static_cast<QToolButton*>(widgets.at(3)); 0214 0215 if (index.data(SetupCollectionModel::IsCategoryRole).toBool()) 0216 { 0217 // set text from model 0218 0219 pushButton->setText(index.data(SetupCollectionModel::CategoryButtonDisplayRole).toString()); 0220 0221 // resize according to size hint 0222 0223 pushButton->resize(pushButton->sizeHint()); 0224 0225 // move to position in line. We have cached the icon/text size hint from sizeHint() 0226 0227 pushButton->move(m_categoryMaxStyledWidth, (option.rect.height() - pushButton->height()) / 2); 0228 pushButton->show(); 0229 appendButton->hide(); 0230 updateButton->hide(); 0231 deleteButton->hide(); 0232 0233 pushButton->setEnabled(itemView()->isEnabled()); 0234 pushButton->setProperty("id", index.data(SetupCollectionModel::CategoryButtonMapId)); 0235 } 0236 else if (index.data(SetupCollectionModel::IsAppendRole).toBool()) 0237 { 0238 appendButton->setIcon(index.data(SetupCollectionModel::AppendDecorationRole).value<QIcon>()); 0239 appendButton->resize(appendButton->sizeHint()); 0240 appendButton->move(0, (option.rect.height() - appendButton->height()) / 2); 0241 appendButton->show(); 0242 pushButton->hide(); 0243 0244 appendButton->setEnabled(itemView()->isEnabled()); 0245 appendButton->setProperty("id", index.data(SetupCollectionModel::AppendMapId)); 0246 } 0247 else if (index.data(SetupCollectionModel::IsUpdateRole).toBool()) 0248 { 0249 updateButton->setIcon(index.data(SetupCollectionModel::UpdateDecorationRole).value<QIcon>()); 0250 updateButton->resize(updateButton->sizeHint()); 0251 updateButton->move(0, (option.rect.height() - updateButton->height()) / 2); 0252 updateButton->show(); 0253 pushButton->hide(); 0254 0255 updateButton->setEnabled(itemView()->isEnabled()); 0256 updateButton->setProperty("id", index.data(SetupCollectionModel::UpdateMapId)); 0257 } 0258 else if (index.data(SetupCollectionModel::IsDeleteRole).toBool()) 0259 { 0260 deleteButton->setIcon(index.data(SetupCollectionModel::DeleteDecorationRole).value<QIcon>()); 0261 deleteButton->resize(deleteButton->sizeHint()); 0262 deleteButton->move(0, (option.rect.height() - deleteButton->height()) / 2); 0263 deleteButton->show(); 0264 pushButton->hide(); 0265 0266 deleteButton->setEnabled(itemView()->isEnabled()); 0267 deleteButton->setProperty("id", index.data(SetupCollectionModel::DeleteMapId)); 0268 } 0269 else 0270 { 0271 pushButton->hide(); 0272 appendButton->hide(); 0273 updateButton->hide(); 0274 deleteButton->hide(); 0275 } 0276 } 0277 0278 QWidget* SetupCollectionDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const 0279 { 0280 return m_styledDelegate->createEditor(parent, option, index); 0281 } 0282 0283 bool SetupCollectionDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, 0284 const QStyleOptionViewItem& option, const QModelIndex& index) 0285 { 0286 return static_cast<QAbstractItemDelegate*>(m_styledDelegate)->editorEvent(event, model, option, index); 0287 } 0288 0289 void SetupCollectionDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const 0290 { 0291 m_styledDelegate->paint(painter, option, index); 0292 } 0293 0294 void SetupCollectionDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const 0295 { 0296 m_styledDelegate->setEditorData(editor, index); 0297 } 0298 0299 void SetupCollectionDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const 0300 { 0301 m_styledDelegate->setModelData(editor, model, index); 0302 } 0303 0304 void SetupCollectionDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const 0305 { 0306 m_styledDelegate->updateEditorGeometry(editor, option, index); 0307 } 0308 0309 // ------------- View ----------------- // 0310 0311 SetupCollectionTreeView::SetupCollectionTreeView(QWidget* const parent) 0312 : QTreeView(parent) 0313 { 0314 setHeaderHidden(true); 0315 setRootIsDecorated(false); 0316 setUniformRowHeights(true); 0317 setExpandsOnDoubleClick(false); 0318 0319 // Set custom delegate 0320 0321 setItemDelegate(new SetupCollectionDelegate(this, this)); 0322 } 0323 0324 void SetupCollectionTreeView::setModel(SetupCollectionModel* collectionModel) 0325 { 0326 if (model()) 0327 { 0328 disconnect(model(), nullptr, this, nullptr); 0329 } 0330 0331 // we need to do some things after the model has loaded its data 0332 0333 connect(collectionModel, SIGNAL(collectionsLoaded()), 0334 this, SLOT(modelLoadedCollections())); 0335 0336 // connect button click signals from the delegate to the model 0337 0338 connect(static_cast<SetupCollectionDelegate*>(itemDelegate()), SIGNAL(categoryButtonPressed(int)), 0339 collectionModel, SLOT(slotCategoryButtonPressed(int))); 0340 0341 connect(static_cast<SetupCollectionDelegate*>(itemDelegate()), SIGNAL(appendPressed(int)), 0342 collectionModel, SLOT(slotAppendPressed(int))); 0343 0344 connect(static_cast<SetupCollectionDelegate*>(itemDelegate()), SIGNAL(updatePressed(int)), 0345 collectionModel, SLOT(slotUpdatePressed(int))); 0346 0347 connect(static_cast<SetupCollectionDelegate*>(itemDelegate()), SIGNAL(deletePressed(int)), 0348 collectionModel, SLOT(slotDeletePressed(int))); 0349 0350 // give model a widget to use as parent for message boxes 0351 0352 collectionModel->setParentWidgetForDialogs(this); 0353 0354 QTreeView::setModel(collectionModel); 0355 } 0356 0357 void SetupCollectionTreeView::modelLoadedCollections() 0358 { 0359 // make category entries span the whole line 0360 0361 for (int i = 0 ; i < model()->rowCount(QModelIndex()) ; ++i) 0362 { 0363 setFirstColumnSpanned(i, QModelIndex(), true); 0364 } 0365 0366 // show all entries 0367 0368 expandAll(); 0369 0370 // Resize name and path column 0371 0372 header()->setSectionResizeMode(SetupCollectionModel::ColumnName, QHeaderView::Stretch); 0373 header()->setSectionResizeMode(SetupCollectionModel::ColumnPath, QHeaderView::Stretch); 0374 0375 // Resize last column, so that delete button is always rightbound 0376 0377 header()->setStretchLastSection(false); // defaults to true 0378 header()->setSectionResizeMode(SetupCollectionModel::ColumnAppendButton, QHeaderView::Fixed); 0379 resizeColumnToContents(SetupCollectionModel::ColumnAppendButton); 0380 header()->setSectionResizeMode(SetupCollectionModel::ColumnUpdateButton, QHeaderView::Fixed); 0381 resizeColumnToContents(SetupCollectionModel::ColumnUpdateButton); 0382 header()->setSectionResizeMode(SetupCollectionModel::ColumnDeleteButton, QHeaderView::Fixed); 0383 resizeColumnToContents(SetupCollectionModel::ColumnDeleteButton); 0384 0385 // Resize first column 0386 // This is more difficult because we need to ignore the width of the category entries, 0387 // which are formally location in the first column (although spanning the whole line). 0388 // resizeColumnToContents fails therefore. 0389 0390 SetupCollectionModel* const collectionModel = static_cast<SetupCollectionModel*>(model()); 0391 QModelIndex categoryIndex = collectionModel->indexForCategory(SetupCollectionModel::CategoryLocal); 0392 QModelIndex firstChildOfFirstCategory = collectionModel->index(0, SetupCollectionModel::ColumnStatus, categoryIndex); 0393 QSize hint = sizeHintForIndex(firstChildOfFirstCategory); 0394 setColumnWidth(SetupCollectionModel::ColumnStatus, hint.width() + indentation()); 0395 } 0396 0397 // ------------- Model ----------------- // 0398 0399 SetupCollectionModel::Item::Item() 0400 : parentId(INTERNALID), 0401 orgIndex(0), 0402 appended(false), 0403 updated (false), 0404 deleted (false) 0405 { 0406 } 0407 0408 SetupCollectionModel::Item::Item(const CollectionLocation& location) 0409 : location(location), 0410 orgIndex(0), 0411 appended(false), 0412 updated (false), 0413 deleted (false) 0414 { 0415 parentId = SetupCollectionModel::typeToCategory(location.type()); 0416 } 0417 0418 SetupCollectionModel::Item::Item(const QString& path, const QString& label, SetupCollectionModel::Category category) 0419 : label (label), 0420 path (path), 0421 parentId(category), 0422 orgIndex(0), 0423 appended(false), 0424 updated (false), 0425 deleted (false) 0426 { 0427 } 0428 0429 /** 0430 * Internal data structure: 0431 * 0432 * The category entries get a model index with INTERNALID and are identified by their row(). 0433 * The item entries get the index in m_collections as INTERNALID. 0434 * No item is ever removed from m_collections, deleted entries are only marked as such. 0435 * 0436 * Items have a location, a parentId, and a name and label field. 0437 * parentId always contains the category, needed to implement parent(). 0438 * The location is the location if it exists, or is null if the item was added. 0439 * Name and label are null if unchanged, then the values from location are used. 0440 * They are valid if edited (label) or the location was added (both valid, location null). 0441 */ 0442 0443 SetupCollectionModel::SetupCollectionModel(QObject* const parent) 0444 : QAbstractItemModel(parent), 0445 m_dialogParentWidget(nullptr) 0446 { 0447 } 0448 0449 SetupCollectionModel::~SetupCollectionModel() 0450 { 0451 } 0452 0453 void SetupCollectionModel::loadCollections() 0454 { 0455 beginResetModel(); 0456 0457 m_collections.clear(); 0458 QList<CollectionLocation> locations = CollectionManager::instance()->allLocations(); 0459 0460 Q_FOREACH (const CollectionLocation& location, locations) 0461 { 0462 m_collections << Item(location); 0463 int idx = m_collections.size() - 1; 0464 0465 if (location.type() == CollectionLocation::Network) 0466 { 0467 QUrl url(location.identifier); 0468 0469 if (url.scheme() == QLatin1String("networkshareid")) 0470 { 0471 QUrlQuery q(url); 0472 0473 Q_FOREACH (const QString& path, q.allQueryItemValues(QLatin1String("mountpath"))) 0474 { 0475 if (location.albumRootPath() != path) 0476 { 0477 Item item(location); 0478 item.orgIndex = idx; 0479 item.appended = true; 0480 item.path = path; 0481 m_collections << item; 0482 m_collections[idx].childs << path; 0483 } 0484 } 0485 } 0486 } 0487 } 0488 0489 endResetModel(); 0490 Q_EMIT collectionsLoaded(); 0491 } 0492 0493 void SetupCollectionModel::apply() 0494 { 0495 QList<int> newItems, deletedItems, updatedItems, renamedItems; 0496 0497 for (int i = 0 ; i < m_collections.count() ; ++i) 0498 { 0499 const Item& item = m_collections.at(i); 0500 0501 if (item.appended) 0502 { 0503 continue; 0504 } 0505 else if (item.deleted && !item.location.isNull()) 0506 { 0507 // if item was deleted and had a valid location, i.e. exists in DB 0508 0509 deletedItems << i; 0510 } 0511 else if (!item.deleted && item.location.isNull()) 0512 { 0513 // if item has no valid location, i.e. does not yet exist in db 0514 0515 newItems << i; 0516 } 0517 else if (!item.deleted && !item.location.isNull()) 0518 { 0519 // if item has a valid location, is updated or has changed its label 0520 0521 if (item.updated) 0522 { 0523 updatedItems << i; 0524 } 0525 else if (!item.label.isNull() && item.label != item.location.label()) 0526 { 0527 renamedItems << i; 0528 } 0529 } 0530 } 0531 0532 // Delete deleted items 0533 0534 Q_FOREACH (int i, deletedItems) 0535 { 0536 Item& item = m_collections[i]; 0537 CollectionManager::instance()->removeLocation(item.location); 0538 item.location = CollectionLocation(); 0539 } 0540 0541 // Add added items 0542 0543 QList<Item> failedItems; 0544 0545 Q_FOREACH (int i, newItems) 0546 { 0547 Item& item = m_collections[i]; 0548 CollectionLocation location; 0549 0550 if (item.parentId == CategoryRemote) 0551 { 0552 location = CollectionManager::instance()->addNetworkLocation(QUrl::fromLocalFile(item.path), item.label); 0553 } 0554 else 0555 { 0556 location = CollectionManager::instance()->addLocation(QUrl::fromLocalFile(item.path), item.label); 0557 } 0558 0559 if (location.isNull()) 0560 { 0561 failedItems << item; 0562 } 0563 else 0564 { 0565 item.location = location; 0566 item.path.clear(); 0567 item.label.clear(); 0568 } 0569 } 0570 0571 // Update collections 0572 0573 Q_FOREACH (int i, updatedItems) 0574 { 0575 Item& item = m_collections[i]; 0576 CollectionLocation location; 0577 0578 int newType = CollectionLocation::VolumeHardWired; 0579 0580 if (item.parentId == CategoryRemovable) 0581 { 0582 newType = CollectionLocation::VolumeRemovable; 0583 } 0584 else if (item.parentId == CategoryRemote) 0585 { 0586 newType = CollectionLocation::Network; 0587 } 0588 0589 QStringList pathList; 0590 pathList << item.path << item.childs; 0591 location = CollectionManager::instance()->refreshLocation(item.location, newType, 0592 pathList, item.label); 0593 0594 if (location.isNull()) 0595 { 0596 failedItems << item; 0597 } 0598 else 0599 { 0600 item.location = location; 0601 item.path.clear(); 0602 item.label.clear(); 0603 } 0604 } 0605 0606 // Rename collections 0607 0608 Q_FOREACH (int i, renamedItems) 0609 { 0610 Item& item = m_collections[i]; 0611 CollectionManager::instance()->setLabel(item.location, item.label); 0612 item.label.clear(); 0613 } 0614 0615 // Handle any errors 0616 0617 if (!failedItems.isEmpty()) 0618 { 0619 QStringList failedPaths; 0620 0621 Q_FOREACH (const Item& item, failedItems) 0622 { 0623 failedPaths << QDir::toNativeSeparators(item.path); 0624 } 0625 0626 DMessageBox::showInformationList(QMessageBox::Critical, 0627 m_dialogParentWidget, 0628 qApp->applicationName(), 0629 i18n("It was not possible to add a collection for the following paths:"), 0630 failedPaths); 0631 } 0632 0633 // Trigger collection scan 0634 0635 if (!newItems.isEmpty() || !updatedItems.isEmpty() || !deletedItems.isEmpty()) 0636 { 0637 NewItemsFinder* const tool = new NewItemsFinder(); 0638 tool->start(); 0639 } 0640 } 0641 0642 void SetupCollectionModel::setParentWidgetForDialogs(QWidget* widget) 0643 { 0644 m_dialogParentWidget = widget; 0645 } 0646 0647 void SetupCollectionModel::slotCategoryButtonPressed(int mappedId) 0648 { 0649 addCollection(mappedId); 0650 } 0651 0652 void SetupCollectionModel::slotAppendPressed(int mappedId) 0653 { 0654 QString picPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); 0655 0656 QUrl curl = DFileDialog::getExistingDirectoryUrl(m_dialogParentWidget, 0657 i18nc("@title:window", "Choose the Folder Containing your Collection"), 0658 QUrl::fromLocalFile(picPath)); 0659 0660 if (curl.isEmpty()) 0661 { 0662 return; 0663 } 0664 0665 bool foundPath = false; 0666 0667 Q_FOREACH (const Item& item, m_collections) 0668 { 0669 if (!item.deleted) 0670 { 0671 QStringList possiblePaths; 0672 0673 possiblePaths << item.childs; 0674 0675 if (!item.path.isEmpty()) 0676 { 0677 possiblePaths << item.path; 0678 } 0679 else if (!item.location.isNull()) 0680 { 0681 possiblePaths << item.location.albumRootPath(); 0682 } 0683 0684 if (possiblePaths.contains(curl.toLocalFile())) 0685 { 0686 foundPath = true; 0687 break; 0688 } 0689 } 0690 } 0691 0692 if (foundPath) 0693 { 0694 QMessageBox::warning(m_dialogParentWidget, i18nc("@title:window", "Problem Appending Collection"), 0695 i18n("A collection with the path \"%1\" already exists.", 0696 QDir::toNativeSeparators(curl.toLocalFile()))); 0697 0698 return; 0699 } 0700 0701 QModelIndex index = indexForId(mappedId, (int)ColumnStatus); 0702 0703 if (!index.isValid() || (mappedId >= m_collections.count())) 0704 { 0705 return; 0706 } 0707 0708 Item& orgItem = m_collections[index.internalId()]; 0709 0710 Item item(curl.toLocalFile(), orgItem.label, (Category)orgItem.parentId); 0711 orgItem.path = !orgItem.updated ? orgItem.location.albumRootPath() 0712 : orgItem.path; 0713 orgItem.label = orgItem.location.label(); 0714 orgItem.childs << curl.toLocalFile(); 0715 orgItem.updated = true; 0716 0717 item.orgIndex = index.internalId(); 0718 item.location = orgItem.location; 0719 item.appended = true; 0720 0721 int row = rowCount(index); 0722 0723 beginInsertRows(index, row, row); 0724 m_collections << item; 0725 endInsertRows(); 0726 0727 // only workaround for bug 182753 0728 0729 Q_EMIT layoutChanged(); 0730 } 0731 0732 void SetupCollectionModel::slotUpdatePressed(int mappedId) 0733 { 0734 updateCollection(mappedId); 0735 } 0736 0737 void SetupCollectionModel::slotDeletePressed(int mappedId) 0738 { 0739 deleteCollection(mappedId); 0740 } 0741 0742 void SetupCollectionModel::addCollection(int category) 0743 { 0744 if ((category < 0) || (category >= NumberOfCategories)) 0745 { 0746 return; 0747 } 0748 0749 QString label; 0750 QString path = lastAddedCollectionPath; 0751 0752 if (askForNewCollectionPath(true, category, &path, &label)) 0753 { 0754 // Add new item to model. Adding to CollectionManager is done in apply()! 0755 0756 QModelIndex parent = indexForCategory((Category)category); 0757 int row = rowCount(parent); 0758 0759 beginInsertRows(parent, row, row); 0760 m_collections << Item(path, label, (Category)category); 0761 endInsertRows(); 0762 0763 // only workaround for bug 182753 0764 0765 Q_EMIT layoutChanged(); 0766 } 0767 } 0768 0769 /* 0770 //This code works, but is currently not used. Was intended as a workaround for 219876. 0771 void SetupCollectionModel::emitDataChangedForChildren(const QModelIndex& parent) 0772 { 0773 int rows = rowCount(parent); 0774 int columns = columnCount(parent); 0775 Q_EMIT dataChanged(index(0, 0, parent), index(rows, columns, parent)); 0776 0777 for (int r = 0 ; r < rows ; ++r) 0778 { 0779 for (int c = 0 ; c < columns ; ++c) 0780 { 0781 QModelIndex i = index(r, c, parent); 0782 0783 if (i.isValid()) 0784 { 0785 emitDataChangedForChildren(i); 0786 } 0787 } 0788 } 0789 } 0790 */ 0791 0792 void SetupCollectionModel::updateCollection(int internalId) 0793 { 0794 QModelIndex index = indexForId(internalId, (int)ColumnStatus); 0795 0796 if (!index.isValid() || (internalId >= m_collections.count())) 0797 { 0798 return; 0799 } 0800 0801 Item& item = m_collections[index.internalId()]; 0802 int parentId = item.parentId; 0803 0804 if (askForNewCollectionCategory(&parentId)) 0805 { 0806 QString path = item.path; 0807 QString label; 0808 0809 if (!item.location.isNull()) 0810 { 0811 path = item.location.albumRootPath(); 0812 } 0813 0814 // Mark item as deleted so that 0815 // the path can be used again. 0816 0817 item.deleted = true; 0818 0819 if (askForNewCollectionPath(false, parentId, &path, &label)) 0820 { 0821 item.parentId = parentId; 0822 item.label = label; 0823 item.path = path; 0824 item.updated = true; 0825 0826 // only workaround for bug 182753 0827 0828 Q_EMIT layoutChanged(); 0829 } 0830 0831 item.deleted = false; 0832 } 0833 } 0834 0835 void SetupCollectionModel::deleteCollection(int internalId) 0836 { 0837 QModelIndex index = indexForId(internalId, (int)ColumnStatus); 0838 QModelIndex parentIndex = parent(index); 0839 0840 if (!index.isValid() || (internalId >= m_collections.count())) 0841 { 0842 return; 0843 } 0844 0845 int result = QMessageBox::No; 0846 Item& item = m_collections[index.internalId()]; 0847 QString label = data(indexForId(internalId, (int)ColumnName), Qt::DisplayRole).toString(); 0848 Q_UNUSED(result); 0849 0850 // Ask for confirmation 0851 0852 if (item.appended) 0853 { 0854 result = QMessageBox::warning(m_dialogParentWidget, 0855 i18nc("@title:window", "Remove Path from the Collection?"), 0856 i18n("Do you want to remove the appended path \"%1\" from the collection \"%2\"?", 0857 item.path, label), 0858 QMessageBox::Yes | QMessageBox::No); 0859 } 0860 else 0861 { 0862 result = QMessageBox::warning(m_dialogParentWidget, 0863 i18nc("@title:window", "Remove Collection?"), 0864 i18n("Do you want to remove the collection \"%1\" from your list of collections?", 0865 label), 0866 QMessageBox::Yes | QMessageBox::No); 0867 } 0868 0869 if (result == QMessageBox::Yes) 0870 { 0871 // Remove from model. Removing from CollectionManager is done in apply()! 0872 0873 beginRemoveRows(parentIndex, index.row(), index.row()); 0874 item.deleted = true; 0875 endRemoveRows(); 0876 0877 if (item.appended) 0878 { 0879 Item& orgItem = m_collections[item.orgIndex]; 0880 0881 orgItem.path = orgItem.location.albumRootPath(); 0882 orgItem.label = orgItem.location.label(); 0883 orgItem.childs.removeAll(item.path); 0884 orgItem.updated = true; 0885 } 0886 else if (!item.childs.isEmpty()) 0887 { 0888 for (int i = 0 ; i < m_collections.count() ; ++i) 0889 { 0890 Item& remItem = m_collections[i]; 0891 0892 if (remItem.orgIndex == (int)index.internalId()) 0893 { 0894 QModelIndex remIndex = indexForId(i, (int)ColumnStatus); 0895 QModelIndex remParentIndex = parent(remIndex); 0896 0897 beginRemoveRows(remParentIndex, remIndex.row(), remIndex.row()); 0898 remItem.deleted = true; 0899 endRemoveRows(); 0900 } 0901 } 0902 } 0903 0904 // only workaround for bug 182753 0905 0906 Q_EMIT layoutChanged(); 0907 } 0908 } 0909 0910 QVariant SetupCollectionModel::data(const QModelIndex& index, int role) const 0911 { 0912 if (!index.isValid()) 0913 { 0914 return QVariant(); 0915 } 0916 0917 if (index.internalId() == INTERNALID) 0918 { 0919 if (index.column() == 0) 0920 { 0921 switch (role) 0922 { 0923 case Qt::DisplayRole: 0924 { 0925 switch (index.row()) 0926 { 0927 case CategoryLocal: 0928 { 0929 return i18n("Local Collections"); 0930 } 0931 0932 case CategoryRemovable: 0933 { 0934 return i18n("Collections on Removable Media"); 0935 } 0936 0937 case CategoryRemote: 0938 { 0939 return i18n("Collections on Network Shares"); 0940 } 0941 } 0942 0943 break; 0944 } 0945 0946 case Qt::DecorationRole: 0947 { 0948 switch (index.row()) 0949 { 0950 case CategoryLocal: 0951 { 0952 return QIcon::fromTheme(QLatin1String("drive-harddisk")); 0953 } 0954 0955 case CategoryRemovable: 0956 { 0957 return QIcon::fromTheme(QLatin1String("drive-removable-media")); 0958 } 0959 0960 case CategoryRemote: 0961 { 0962 return QIcon::fromTheme(QLatin1String("network-wired-activated")); 0963 } 0964 } 0965 0966 break; 0967 } 0968 0969 case IsCategoryRole: 0970 { 0971 return true; 0972 } 0973 0974 case CategoryButtonDisplayRole: 0975 { 0976 return i18n("Add Collection"); 0977 } 0978 0979 case CategoryButtonMapId: 0980 { 0981 return categoryButtonMapId(index); 0982 } 0983 0984 default: 0985 { 0986 break; 0987 } 0988 } 0989 } 0990 } 0991 else 0992 { 0993 const Item& item = m_collections.at(index.internalId()); 0994 0995 if ((role == Qt::BackgroundRole) && item.appended) 0996 { 0997 return QPalette().alternateBase(); 0998 } 0999 1000 switch (index.column()) 1001 { 1002 case ColumnName: 1003 { 1004 if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) 1005 { 1006 if (item.appended) 1007 { 1008 const Item& orgItem = m_collections.at(item.orgIndex); 1009 1010 if (!orgItem.label.isNull()) 1011 { 1012 return orgItem.label; 1013 } 1014 } 1015 1016 if (!item.label.isNull()) 1017 { 1018 return item.label; 1019 } 1020 1021 if (!item.location.label().isNull()) 1022 { 1023 return item.location.label(); 1024 } 1025 1026 return i18n("Col. %1", index.row()); 1027 } 1028 1029 break; 1030 } 1031 1032 case ColumnPath: 1033 { 1034 if ((role == Qt::DisplayRole) || (role == Qt::ToolTipRole)) 1035 { 1036 if (!item.path.isNull()) 1037 { 1038 return QDir::toNativeSeparators(item.path); 1039 } 1040 1041 // TODO: Path can be empty for items not available, 1042 // query more info from CollectionManager 1043 1044 return QDir::toNativeSeparators(item.location.albumRootPath()); 1045 } 1046 1047 break; 1048 } 1049 1050 case ColumnStatus: 1051 { 1052 if (role == Qt::DecorationRole) 1053 { 1054 if (item.updated) 1055 { 1056 return QIcon::fromTheme(QLatin1String("view-refresh")); 1057 } 1058 1059 if (item.deleted) 1060 { 1061 return QIcon::fromTheme(QLatin1String("edit-delete")); 1062 } 1063 1064 if (item.location.isNull()) 1065 { 1066 return QIcon::fromTheme(QLatin1String("folder-new")); 1067 } 1068 1069 if (item.appended) 1070 { 1071 return QIcon::fromTheme(QLatin1String("mail-attachment")); 1072 } 1073 1074 switch (item.location.status()) 1075 { 1076 case CollectionLocation::LocationAvailable: 1077 { 1078 return QIcon::fromTheme(QLatin1String("dialog-ok-apply")); 1079 } 1080 1081 case CollectionLocation::LocationHidden: 1082 { 1083 return QIcon::fromTheme(QLatin1String("object-locked")); 1084 } 1085 1086 case CollectionLocation::LocationUnavailable: 1087 { 1088 switch (item.parentId) 1089 { 1090 case CategoryLocal: 1091 { 1092 return QIcon::fromTheme(QLatin1String("drive-harddisk")).pixmap(16, QIcon::Disabled); 1093 } 1094 1095 case CategoryRemovable: 1096 { 1097 return QIcon::fromTheme(QLatin1String("drive-removable-media-usb")).pixmap(16, QIcon::Disabled); 1098 } 1099 1100 case CategoryRemote: 1101 { 1102 return QIcon::fromTheme(QLatin1String("network-wired-activated")).pixmap(16, QIcon::Disabled); 1103 } 1104 } 1105 1106 break; 1107 } 1108 1109 case CollectionLocation::LocationNull: 1110 case CollectionLocation::LocationDeleted: 1111 { 1112 return QIcon::fromTheme(QLatin1String("edit-delete")); 1113 } 1114 } 1115 } 1116 else if (role == Qt::ToolTipRole) 1117 { 1118 switch (item.location.status()) 1119 { 1120 case CollectionLocation::LocationUnavailable: 1121 { 1122 return i18n("This collection is currently not available."); 1123 } 1124 1125 case CollectionLocation::LocationAvailable: 1126 { 1127 return i18n("No problems found, enjoy this collection."); 1128 } 1129 1130 case CollectionLocation::LocationHidden: 1131 { 1132 return i18n("This collection is hidden."); 1133 } 1134 1135 default: 1136 { 1137 break; 1138 } 1139 } 1140 } 1141 1142 break; 1143 } 1144 1145 case ColumnAppendButton: 1146 { 1147 switch (role) 1148 { 1149 case Qt::ToolTipRole: 1150 { 1151 return i18n("Append network path"); 1152 } 1153 1154 case IsAppendRole: 1155 { 1156 return ((item.location.type() == CollectionLocation::Network) && !item.appended); 1157 } 1158 1159 case AppendDecorationRole: 1160 { 1161 return QIcon::fromTheme(QLatin1String("list-add")); 1162 } 1163 1164 case AppendMapId: 1165 { 1166 return buttonMapId(index); 1167 } 1168 } 1169 1170 break; 1171 } 1172 1173 case ColumnUpdateButton: 1174 { 1175 switch (role) 1176 { 1177 case Qt::ToolTipRole: 1178 { 1179 return i18n("Update collection"); 1180 } 1181 1182 case IsUpdateRole: 1183 { 1184 return (!item.appended); 1185 } 1186 1187 case UpdateDecorationRole: 1188 { 1189 return QIcon::fromTheme(QLatin1String("view-refresh")); 1190 } 1191 1192 case UpdateMapId: 1193 { 1194 return buttonMapId(index); 1195 } 1196 } 1197 1198 break; 1199 } 1200 1201 case ColumnDeleteButton: 1202 { 1203 switch (role) 1204 { 1205 case Qt::ToolTipRole: 1206 { 1207 return i18n("Remove collection"); 1208 } 1209 1210 case IsDeleteRole: 1211 { 1212 return true; 1213 } 1214 1215 case DeleteDecorationRole: 1216 { 1217 return QIcon::fromTheme(QLatin1String("edit-delete")); 1218 } 1219 1220 case DeleteMapId: 1221 { 1222 return buttonMapId(index); 1223 } 1224 } 1225 1226 break; 1227 } 1228 } 1229 } 1230 1231 return QVariant(); 1232 } 1233 1234 QVariant SetupCollectionModel::headerData(int section, Qt::Orientation orientation, int role) const 1235 { 1236 if ((role == Qt::DisplayRole) && (orientation == Qt::Horizontal) && (section < NumberOfColumns)) 1237 { 1238 switch (section) 1239 { 1240 case ColumnName: 1241 { 1242 return i18nc("#title: collection name", "Name"); 1243 } 1244 1245 case ColumnPath: 1246 { 1247 return i18nc("#title: collection mount path", "Path"); 1248 } 1249 1250 case ColumnStatus: 1251 { 1252 return i18nc("#title: collection status", "Status"); 1253 } 1254 1255 case ColumnAppendButton: 1256 { 1257 break; 1258 } 1259 1260 case ColumnUpdateButton: 1261 { 1262 break; 1263 } 1264 1265 case ColumnDeleteButton: 1266 { 1267 break; 1268 } 1269 } 1270 } 1271 1272 return QVariant(); 1273 } 1274 1275 int SetupCollectionModel::rowCount(const QModelIndex& parent) const 1276 { 1277 if (!parent.isValid()) 1278 { 1279 return NumberOfCategories; // Level 0: the three top level items 1280 } 1281 1282 if (parent.column() != 0) 1283 { 1284 return 0; 1285 } 1286 1287 if (parent.internalId() != INTERNALID) 1288 { 1289 return 0; // Level 2: no children 1290 } 1291 1292 // Level 1: item children count 1293 1294 int parentId = parent.row(); 1295 int rowCount = 0; 1296 1297 Q_FOREACH (const Item& item, m_collections) 1298 { 1299 if (!item.deleted && (item.parentId == parentId)) 1300 { 1301 ++rowCount; // cppcheck-suppress useStlAlgorithm 1302 } 1303 } 1304 1305 return rowCount; 1306 } 1307 1308 int SetupCollectionModel::columnCount(const QModelIndex& /*parent*/) const 1309 { 1310 return NumberOfColumns; 1311 } 1312 1313 Qt::ItemFlags SetupCollectionModel::flags(const QModelIndex& index) const 1314 { 1315 if (!index.isValid()) 1316 { 1317 return Qt::NoItemFlags; 1318 } 1319 1320 if (index.internalId() == INTERNALID) 1321 { 1322 return Qt::ItemIsEnabled; 1323 } 1324 else 1325 { 1326 Qt::ItemFlags flags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); 1327 1328 switch (index.column()) 1329 { 1330 case ColumnName: 1331 { 1332 const Item& item = m_collections.at(index.internalId()); 1333 1334 if (item.appended) 1335 { 1336 return flags; 1337 } 1338 1339 return (flags | Qt::ItemIsEditable); 1340 } 1341 1342 default: 1343 { 1344 return flags; 1345 } 1346 } 1347 } 1348 } 1349 1350 bool SetupCollectionModel::setData(const QModelIndex& index, const QVariant& value, int role) 1351 { 1352 // only editable in one case 1353 1354 if (index.isValid() && (index.internalId() != INTERNALID) && (index.column() == ColumnName) && (role == Qt::EditRole)) 1355 { 1356 Item& item = m_collections[index.internalId()]; 1357 item.label = value.toString(); 1358 Q_EMIT dataChanged(index, index); 1359 } 1360 1361 return false; 1362 } 1363 1364 QModelIndex SetupCollectionModel::index(int row, int column, const QModelIndex& parent) const 1365 { 1366 if (!parent.isValid()) 1367 { 1368 if ((row < NumberOfCategories) && (row >= 0) && (column == 0)) 1369 { 1370 return createIndex(row, 0, INTERNALID); 1371 } 1372 } 1373 else if ((row >= 0) && (column < NumberOfColumns)) 1374 { 1375 // m_collections is a flat list with all entries, of all categories and also deleted entries. 1376 // The model indices contain as internal id the index to this list. 1377 int parentId = parent.row(); 1378 int rowCount = 0; 1379 1380 for (int i = 0 ; i < m_collections.count() ; ++i) 1381 { 1382 const Item& item = m_collections.at(i); 1383 1384 if (!item.deleted && (item.parentId == parentId)) 1385 { 1386 if (rowCount == row) 1387 { 1388 return createIndex(row, column, i); 1389 } 1390 1391 ++rowCount; 1392 } 1393 } 1394 } 1395 1396 return QModelIndex(); 1397 } 1398 1399 QModelIndex SetupCollectionModel::parent(const QModelIndex& index) const 1400 { 1401 if (!index.isValid()) 1402 { 1403 return QModelIndex(); 1404 } 1405 1406 if (index.internalId() == INTERNALID) 1407 { 1408 return QModelIndex(); // one of the three toplevel items 1409 } 1410 1411 const Item& item = m_collections.at(index.internalId()); 1412 1413 return createIndex(item.parentId, 0, INTERNALID); 1414 } 1415 1416 QModelIndex SetupCollectionModel::indexForCategory(Category category) const 1417 { 1418 return index(category, 0, QModelIndex()); 1419 } 1420 1421 QList<QModelIndex> SetupCollectionModel::categoryIndexes() const 1422 { 1423 QList<QModelIndex> list; 1424 1425 for (int cat = 0 ; cat < NumberOfCategories ; ++cat) 1426 { 1427 list << index(cat, 0, QModelIndex()); 1428 } 1429 1430 return list; 1431 } 1432 1433 QModelIndex SetupCollectionModel::indexForId(int id, int column) const 1434 { 1435 int row = 0; 1436 const Item& indexItem = m_collections.at(id); 1437 1438 for (int i = 0 ; i < m_collections.count() ; ++i) 1439 { 1440 const Item& item = m_collections.at(i); 1441 1442 if (!item.deleted && (item.parentId == indexItem.parentId)) 1443 { 1444 if (i == id) 1445 { 1446 return createIndex(row, column, i); 1447 } 1448 1449 ++row; 1450 } 1451 } 1452 1453 return QModelIndex(); 1454 } 1455 1456 SetupCollectionModel::Category SetupCollectionModel::typeToCategory(CollectionLocation::Type type) 1457 { 1458 switch (type) 1459 { 1460 default: 1461 case CollectionLocation::VolumeHardWired: 1462 { 1463 return CategoryLocal; 1464 } 1465 1466 case CollectionLocation::VolumeRemovable: 1467 { 1468 return CategoryRemovable; 1469 } 1470 1471 case CollectionLocation::Network: 1472 { 1473 return CategoryRemote; 1474 } 1475 } 1476 } 1477 1478 bool SetupCollectionModel::askForNewCollectionPath(bool adding, int category, QString* const newPath, QString* const newLabel) 1479 { 1480 QString picPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); 1481 1482 if (newPath && !(*newPath).isEmpty() && QFileInfo::exists(*newPath)) 1483 { 1484 picPath = *newPath; 1485 } 1486 1487 QUrl curl = DFileDialog::getExistingDirectoryUrl(m_dialogParentWidget, 1488 i18nc("@title:window", "Choose the Folder Containing your Collection"), 1489 QUrl::fromLocalFile(picPath)); 1490 1491 if (curl.isEmpty()) 1492 { 1493 return false; 1494 } 1495 1496 lastAddedCollectionPath = curl.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).toLocalFile(); 1497 1498 // Check path: First check with manager 1499 1500 QString messageFromManager, deviceIcon; 1501 QList<CollectionLocation> assumeDeleted; 1502 1503 Q_FOREACH (const Item& item, m_collections) 1504 { 1505 if (item.deleted && !item.location.isNull()) 1506 { 1507 assumeDeleted << item.location; 1508 } 1509 } 1510 1511 CollectionManager::LocationCheckResult result; 1512 1513 if (category == CategoryRemote) 1514 { 1515 result = CollectionManager::instance()->checkNetworkLocation(curl, assumeDeleted, 1516 &messageFromManager, &deviceIcon); 1517 } 1518 else 1519 { 1520 result = CollectionManager::instance()->checkLocation(curl, assumeDeleted, 1521 &messageFromManager, &deviceIcon); 1522 } 1523 1524 QString path = curl.toLocalFile(); 1525 1526 // If there are other added collections then CollectionManager does not know about them. Check here. 1527 1528 Q_FOREACH (const Item& item, m_collections) 1529 { 1530 if (!item.deleted && item.location.isNull()) 1531 { 1532 if (!item.path.isEmpty() && path.startsWith(item.path)) 1533 { 1534 if ((path == item.path) || path.startsWith(item.path + QLatin1Char('/'))) 1535 { 1536 messageFromManager = i18n("You have previously added a collection " 1537 "that contains the path \"%1\".", QDir::toNativeSeparators(path)); 1538 result = CollectionManager::LocationNotAllowed; 1539 break; 1540 } 1541 } 1542 } 1543 } 1544 1545 // If check failed, display sorry message 1546 1547 QString iconName; 1548 1549 switch (result) 1550 { 1551 case CollectionManager::LocationAllRight: 1552 { 1553 iconName = QLatin1String("dialog-ok-apply"); 1554 break; 1555 } 1556 1557 case CollectionManager::LocationHasProblems: 1558 { 1559 iconName = QLatin1String("dialog-information"); 1560 break; 1561 } 1562 1563 case CollectionManager::LocationNotAllowed: 1564 case CollectionManager::LocationInvalidCheck: 1565 { 1566 QString warning; 1567 1568 if (adding) 1569 { 1570 warning = i18nc("@title:window", 1571 "Problem Adding Collection"); 1572 } 1573 else 1574 { 1575 warning = i18nc("@title:window", 1576 "Problem updating Collection"); 1577 } 1578 1579 QMessageBox::warning(m_dialogParentWidget, warning, messageFromManager); 1580 1581 // fail 1582 1583 return false; 1584 } 1585 } 1586 1587 // Create a dialog that displays volume information and allows to change the name of the collection 1588 1589 QDialog* const dialog = new QDialog(m_dialogParentWidget); 1590 1591 if (adding) 1592 { 1593 dialog->setWindowTitle(i18nc("@title:window", "Adding Collection")); 1594 } 1595 else 1596 { 1597 dialog->setWindowTitle(i18nc("@title:window", "Update Collection")); 1598 } 1599 1600 QWidget* const mainWidget = new QWidget(dialog); 1601 QLabel* const nameLabel = new QLabel; 1602 1603 if (adding) 1604 { 1605 nameLabel->setText(i18n("Your new collection will be created with this name:")); 1606 } 1607 else 1608 { 1609 nameLabel->setText(i18n("Your collection will be updated to this name:")); 1610 } 1611 1612 nameLabel->setWordWrap(true); 1613 1614 // lineedit for collection name 1615 1616 DTextEdit* const nameEdit = new DTextEdit; 1617 nameEdit->setLinesVisible(1); 1618 nameLabel->setBuddy(nameEdit); 1619 1620 // label for the icon showing the type of storage (hard disk, CD, USB drive) 1621 1622 QLabel* const deviceIconLabel = new QLabel; 1623 deviceIconLabel->setPixmap(QIcon::fromTheme(deviceIcon).pixmap(64)); 1624 1625 QGroupBox* const infoBox = new QGroupBox; 1626 /* 1627 infoBox->setTitle(i18n("More Information")); 1628 */ 1629 // label either signalling everything is all right, or raising awareness to some problems 1630 // (like handling of CD identified by a label) 1631 1632 QLabel* const iconLabel = new QLabel; 1633 iconLabel->setPixmap(QIcon::fromTheme(iconName).pixmap(48)); 1634 QLabel* const infoLabel = new QLabel; 1635 infoLabel->setText(messageFromManager); 1636 infoLabel->setWordWrap(true); 1637 1638 QHBoxLayout* const hbox1 = new QHBoxLayout; 1639 hbox1->addWidget(iconLabel); 1640 hbox1->addWidget(infoLabel); 1641 infoBox->setLayout(hbox1); 1642 1643 QGridLayout* const grid1 = new QGridLayout; 1644 grid1->addWidget(deviceIconLabel, 0, 0, 3, 1); 1645 grid1->addWidget(nameLabel, 0, 1); 1646 grid1->addWidget(nameEdit, 1, 1); 1647 grid1->addWidget(infoBox, 2, 1); 1648 mainWidget->setLayout(grid1); 1649 1650 QVBoxLayout* const vbx = new QVBoxLayout(dialog); 1651 QDialogButtonBox* const buttons = new QDialogButtonBox(QDialogButtonBox::Ok | 1652 QDialogButtonBox::Help | 1653 QDialogButtonBox::Cancel, 1654 dialog); 1655 vbx->addWidget(mainWidget); 1656 vbx->addWidget(buttons); 1657 dialog->setLayout(vbx); 1658 1659 connect(buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), 1660 dialog, SLOT(accept())); 1661 1662 connect(buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), 1663 dialog, SLOT(reject())); 1664 1665 connect(buttons->button(QDialogButtonBox::Help), SIGNAL(clicked()), 1666 this, SLOT(slotHelp())); 1667 1668 // default to directory name as collection name 1669 1670 QDir dir(path); 1671 nameEdit->setText(dir.dirName()); 1672 1673 if (dialog->exec() == QDialog::Accepted) 1674 { 1675 if (newPath && newLabel) 1676 { 1677 *newLabel = nameEdit->text(); 1678 *newPath = path; 1679 1680 return true; 1681 } 1682 } 1683 1684 return false; 1685 } 1686 1687 bool SetupCollectionModel::askForNewCollectionCategory(int* const category) 1688 { 1689 // Create a dialog that displays the category and allows to change the category of the collection 1690 1691 QDialog* const dialog = new QDialog(m_dialogParentWidget); 1692 dialog->setWindowTitle(i18nc("@title:window", "Select Category")); 1693 1694 QWidget* const mainWidget = new QWidget(dialog); 1695 QLabel* const nameLabel = new QLabel; 1696 nameLabel->setText(i18n("Your collection will use this category:")); 1697 nameLabel->setWordWrap(true); 1698 1699 // combobox for collection category 1700 1701 QComboBox* const categoryBox = new QComboBox; 1702 categoryBox->addItem(i18n("Local Collections"), CategoryLocal); 1703 categoryBox->addItem(i18n("Collections on Removable Media"), CategoryRemovable); 1704 categoryBox->addItem(i18n("Collections on Network Shares"), CategoryRemote); 1705 1706 // label for the icon showing the refresh icon 1707 1708 QLabel* const questionIconLabel = new QLabel; 1709 questionIconLabel->setPixmap(QIcon::fromTheme(QLatin1String("view-sort")).pixmap(64)); 1710 1711 QGridLayout* const grid1 = new QGridLayout; 1712 grid1->addWidget(questionIconLabel, 0, 0, 3, 1); 1713 grid1->addWidget(nameLabel, 0, 1); 1714 grid1->addWidget(categoryBox, 1, 1); 1715 mainWidget->setLayout(grid1); 1716 1717 QVBoxLayout* const vbx = new QVBoxLayout(dialog); 1718 QDialogButtonBox* const buttons = new QDialogButtonBox(QDialogButtonBox::Ok | 1719 QDialogButtonBox::Help | 1720 QDialogButtonBox::Cancel, 1721 dialog); 1722 vbx->addWidget(mainWidget); 1723 vbx->addWidget(buttons); 1724 dialog->setLayout(vbx); 1725 1726 connect(buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), 1727 dialog, SLOT(accept())); 1728 1729 connect(buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), 1730 dialog, SLOT(reject())); 1731 1732 connect(buttons->button(QDialogButtonBox::Help), SIGNAL(clicked()), 1733 this, SLOT(slotHelp())); 1734 1735 // default to current category 1736 1737 if (category) 1738 { 1739 categoryBox->setCurrentIndex(categoryBox->findData(*category)); 1740 } 1741 1742 if (dialog->exec() == QDialog::Accepted) 1743 { 1744 if (category) 1745 { 1746 *category = categoryBox->currentData().toInt(); 1747 } 1748 1749 return true; 1750 } 1751 1752 return false; 1753 } 1754 1755 int SetupCollectionModel::categoryButtonMapId(const QModelIndex& index) const 1756 { 1757 if (!index.isValid() || index.parent().isValid()) 1758 { 1759 return INTERNALID; 1760 } 1761 1762 return index.row(); 1763 } 1764 1765 int SetupCollectionModel::buttonMapId(const QModelIndex& index) const 1766 { 1767 if (!index.isValid() || (index.internalId() == INTERNALID)) 1768 { 1769 return INTERNALID; 1770 } 1771 1772 return index.internalId(); 1773 } 1774 1775 void SetupCollectionModel::slotHelp() 1776 { 1777 openOnlineDocumentation(QLatin1String("setup_application"), QLatin1String("collections_settings")); 1778 } 1779 1780 } // namespace Digikam 1781 1782 #include "moc_setupcollectionview.cpp"