File indexing completed on 2025-01-19 03:53:23
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-05-09 0007 * Description : A combo box for selecting albums 0008 * 0009 * SPDX-FileCopyrightText: 2008-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0010 * SPDX-FileCopyrightText: 2010-2011 by Andi Clemens <andi dot clemens at gmail dot com> 0011 * SPDX-FileCopyrightText: 2012-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0012 * 0013 * SPDX-License-Identifier: GPL-2.0-or-later 0014 * 0015 * ============================================================ */ 0016 0017 #include "albumselectcombobox.h" 0018 0019 // Qt includes 0020 0021 #include <QSortFilterProxyModel> 0022 #include <QTreeView> 0023 0024 // KDE includes 0025 0026 #include <klocalizedstring.h> 0027 0028 // Local includes 0029 0030 #include "albummodel.h" 0031 #include "albumfiltermodel.h" 0032 #include "albumtreeview.h" 0033 #include "tagtreeview.h" 0034 #include "contextmenuhelper.h" 0035 0036 namespace Digikam 0037 { 0038 0039 class Q_DECL_HIDDEN AlbumSelectComboBox::Private 0040 { 0041 public: 0042 0043 explicit Private(AlbumSelectComboBox* const q) 0044 : model (nullptr), 0045 filterModel (nullptr), 0046 recursive (false), 0047 isCheckable (true), 0048 closeOnActivate (false), 0049 allSelectedText (false), 0050 showCheckStateSummary (true), 0051 q (q) 0052 { 0053 } 0054 0055 void updateCheckable(); 0056 void updateCloseOnActivate(); 0057 0058 public: 0059 0060 AbstractCheckableAlbumModel* model; 0061 AlbumFilterModel* filterModel; 0062 QString noSelectionText; 0063 bool recursive; 0064 bool isCheckable; 0065 bool closeOnActivate; 0066 bool allSelectedText; 0067 bool showCheckStateSummary; 0068 0069 AlbumSelectComboBox* const q; 0070 }; 0071 0072 AlbumSelectComboBox::AlbumSelectComboBox(QWidget* const parent) 0073 : TreeViewLineEditComboBox(parent), 0074 d (new Private(this)) 0075 { 0076 d->noSelectionText = i18n("No Album Selected"); 0077 0078 // Workaround for QLineEdit text when QComboBox loses focus 0079 0080 // --- NOTE: use dynamic binding as updateText() is a virtual slot which can be re-implemented in derived classes. 0081 connect(this, &AlbumSelectComboBox::editTextChanged, 0082 this, &AlbumSelectComboBox::updateText); 0083 } 0084 0085 AlbumSelectComboBox::~AlbumSelectComboBox() 0086 { 0087 delete d; 0088 } 0089 0090 void AlbumSelectComboBox::setDefaultAlbumModel() 0091 { 0092 d->noSelectionText = i18n("No Album Selected"); 0093 setAlbumModels(new AlbumModel(AlbumModel::IgnoreRootAlbum, this)); 0094 view()->expandToDepth(0); 0095 } 0096 0097 void AlbumSelectComboBox::setDefaultTagModel() 0098 { 0099 d->noSelectionText = i18n("No Tag Selected"); 0100 setAlbumModels(new TagModel(AlbumModel::IgnoreRootAlbum, this)); 0101 } 0102 0103 void AlbumSelectComboBox::setAlbumModels(AbstractCheckableAlbumModel* model, AlbumFilterModel* filterModel) 0104 { 0105 d->model = model; 0106 d->model->setRecursive(d->recursive); 0107 0108 if (filterModel) 0109 { 0110 d->filterModel = filterModel; 0111 } 0112 else 0113 { 0114 d->filterModel = new AlbumFilterModel(this); 0115 /* 0116 d->filterModel->setDynamicSortFilter(true); 0117 */ 0118 d->filterModel->setSourceAlbumModel(d->model); 0119 } 0120 0121 d->updateCheckable(); 0122 0123 QComboBox::setModel(d->filterModel); 0124 installView(); 0125 0126 d->updateCloseOnActivate(); 0127 updateText(); 0128 } 0129 0130 void AlbumSelectComboBox::installView(QAbstractItemView* v) 0131 { 0132 if (view()) 0133 { 0134 return; 0135 } 0136 0137 TreeViewLineEditComboBox::installView(v); 0138 0139 // cppcheck-suppress nullPointerRedundantCheck 0140 view()->sortByColumn(0, Qt::AscendingOrder); 0141 // cppcheck-suppress nullPointerRedundantCheck 0142 view()->setSortingEnabled(true); 0143 // cppcheck-suppress nullPointerRedundantCheck 0144 view()->collapseAll(); 0145 } 0146 0147 void AlbumSelectComboBox::setCheckable(bool checkable) 0148 { 0149 if (checkable == d->isCheckable) 0150 { 0151 return; 0152 } 0153 0154 d->isCheckable = checkable; 0155 d->updateCheckable(); 0156 } 0157 0158 bool AlbumSelectComboBox::isCheckable() const 0159 { 0160 return d->isCheckable; 0161 } 0162 0163 void AlbumSelectComboBox::Private::updateCheckable() 0164 { 0165 if (!model) 0166 { 0167 return; 0168 } 0169 0170 model->setCheckable(isCheckable); 0171 0172 if (isCheckable) 0173 { 0174 connect(model, SIGNAL(checkStateChanged(Album*,Qt::CheckState)), 0175 q, SLOT(updateText())); 0176 } 0177 else 0178 { 0179 disconnect(model, SIGNAL(checkStateChanged(Album*,Qt::CheckState)), 0180 q, SLOT(updateText())); 0181 } 0182 } 0183 0184 void AlbumSelectComboBox::setCloseOnActivate(bool close) 0185 { 0186 if (d->closeOnActivate == close) 0187 { 0188 return; 0189 } 0190 0191 d->closeOnActivate = close; 0192 d->updateCloseOnActivate(); 0193 } 0194 0195 void AlbumSelectComboBox::Private::updateCloseOnActivate() 0196 { 0197 if (!q->view()) 0198 { 0199 return; 0200 } 0201 0202 if (closeOnActivate) 0203 { 0204 connect(q->view(), SIGNAL(activated(QModelIndex)), 0205 q, SLOT(hidePopup())); 0206 } 0207 else 0208 { 0209 disconnect(q->view(), SIGNAL(activated(QModelIndex)), 0210 q, SLOT(hidePopup())); 0211 } 0212 } 0213 0214 void AlbumSelectComboBox::setRecursive(bool recursive) 0215 { 0216 d->recursive = recursive; // used if a new model will be set 0217 0218 if (d->model) 0219 { 0220 d->model->setRecursive(recursive); 0221 } 0222 } 0223 0224 void AlbumSelectComboBox::setNoSelectionText(const QString& text) 0225 { 0226 d->noSelectionText = text; 0227 updateText(); 0228 } 0229 0230 void AlbumSelectComboBox::setAllSelectedText(bool all) 0231 { 0232 d->allSelectedText = all; 0233 updateText(); 0234 } 0235 0236 void AlbumSelectComboBox::setShowCheckStateSummary(bool show) 0237 { 0238 d->showCheckStateSummary = show; 0239 updateText(); 0240 } 0241 0242 AbstractCheckableAlbumModel* AlbumSelectComboBox::model() const 0243 { 0244 return d->model; 0245 } 0246 0247 QSortFilterProxyModel* AlbumSelectComboBox::filterModel() const 0248 { 0249 return d->filterModel; 0250 } 0251 0252 void AlbumSelectComboBox::hidePopup() 0253 { 0254 // just make this a slot 0255 0256 TreeViewLineEditComboBox::hidePopup(); 0257 updateText(); 0258 } 0259 0260 void AlbumSelectComboBox::updateText() 0261 { 0262 if (!d->isCheckable || !d->showCheckStateSummary) 0263 { 0264 return; 0265 } 0266 0267 QList<Album*> checkedAlbums; 0268 0269 if (!d->allSelectedText) 0270 { 0271 checkedAlbums = d->model->checkedAlbums(); 0272 } 0273 else 0274 { 0275 if (d->model->albumType() == Album::TAG) 0276 { 0277 checkedAlbums = AlbumManager::instance()->allTAlbums(); 0278 } 0279 else 0280 { 0281 checkedAlbums = AlbumManager::instance()->allPAlbums(); 0282 } 0283 } 0284 0285 QList<Album*> partiallyCheckedAlbums = d->model->partiallyCheckedAlbums(); 0286 QString newIncludeText; 0287 QString newExcludeText; 0288 0289 if (!checkedAlbums.isEmpty()) 0290 { 0291 if (checkedAlbums.count() == 1) 0292 { 0293 newIncludeText = checkedAlbums.first()->title(); 0294 } 0295 else 0296 { 0297 if (d->model->albumType() == Album::TAG) 0298 { 0299 newIncludeText = i18np("1 Tag selected", "%1 Tags selected", 0300 checkedAlbums.count()); 0301 } 0302 else 0303 { 0304 newIncludeText = i18np("1 Album selected", "%1 Albums selected", 0305 checkedAlbums.count()); 0306 } 0307 } 0308 } 0309 0310 if (!partiallyCheckedAlbums.isEmpty() && !d->allSelectedText) 0311 { 0312 if (d->model->albumType() == Album::TAG) 0313 { 0314 newExcludeText = i18np("1 Tag excluded", "%1 Tags excluded", 0315 partiallyCheckedAlbums.count()); 0316 } 0317 else 0318 { 0319 newExcludeText = i18np("1 Album excluded", "%1 Albums excluded", 0320 partiallyCheckedAlbums.count()); 0321 } 0322 } 0323 0324 blockSignals(true); 0325 0326 if (newIncludeText.isEmpty() && newExcludeText.isEmpty()) 0327 { 0328 setLineEditText(d->noSelectionText); 0329 } 0330 else if (newIncludeText.isEmpty() || newExcludeText.isEmpty()) 0331 { 0332 setLineEditText(newIncludeText + newExcludeText); 0333 } 0334 else 0335 { 0336 setLineEditText(newIncludeText + QLatin1String(", ") + newExcludeText); 0337 } 0338 0339 blockSignals(false); 0340 } 0341 0342 // --------------------------------------------------------------------------------------------------- 0343 0344 AbstractAlbumTreeViewSelectComboBox::AbstractAlbumTreeViewSelectComboBox(QWidget* const parent) 0345 : AlbumSelectComboBox(parent), 0346 m_treeView (nullptr) 0347 { 0348 } 0349 0350 void AbstractAlbumTreeViewSelectComboBox::installView(QAbstractItemView* view) 0351 { 0352 if (!view) 0353 { 0354 view = m_treeView; 0355 } 0356 0357 AlbumSelectComboBox::installView(view); 0358 } 0359 0360 void AbstractAlbumTreeViewSelectComboBox::sendViewportEventToView(QEvent* e) 0361 { 0362 // needed for StayPoppedUpComboBox 0363 0364 m_treeView->viewportEvent(e); 0365 } 0366 0367 void AbstractAlbumTreeViewSelectComboBox::setTreeView(AbstractAlbumTreeView* const treeView) 0368 { 0369 // this is independent from the installView mechanism, just to override 0370 // the tree view created below without the need to subclass 0371 0372 if (!m_treeView) 0373 { 0374 m_treeView = treeView; 0375 } 0376 } 0377 0378 // ------------------------------------------------------------------------------------------------------------------- 0379 0380 class Q_DECL_HIDDEN CheckUncheckContextMenuElement : public QObject, 0381 public AbstractAlbumTreeView::ContextMenuElement 0382 { 0383 Q_OBJECT 0384 0385 public: 0386 0387 explicit CheckUncheckContextMenuElement(QObject* const parent) 0388 : QObject(parent) 0389 { 0390 } 0391 0392 void addActions(AbstractAlbumTreeView* view, ContextMenuHelper& cmh, Album* album) override 0393 { 0394 AbstractCheckableAlbumModel* const checkable = qobject_cast<AbstractCheckableAlbumModel*>(view->albumModel()); 0395 0396 if (checkable) 0397 { 0398 cmh.setAlbumModel(checkable); 0399 cmh.addAlbumCheckUncheckActions(album); 0400 } 0401 } 0402 }; 0403 0404 void AbstractAlbumTreeViewSelectComboBox::addCheckUncheckContextMenuActions() 0405 { 0406 if (m_treeView) 0407 { 0408 m_treeView->setEnableContextMenu(true); 0409 m_treeView->addContextMenuElement(new CheckUncheckContextMenuElement(this)); 0410 } 0411 } 0412 0413 // --------------------------------------------------------------------------------- 0414 0415 AlbumTreeViewSelectComboBox::AlbumTreeViewSelectComboBox(QWidget* const parent) 0416 : AbstractAlbumTreeViewSelectComboBox(parent) 0417 { 0418 } 0419 0420 AlbumTreeView* AlbumTreeViewSelectComboBox::view() const 0421 { 0422 return static_cast<AlbumTreeView*>(m_treeView); 0423 } 0424 0425 void AlbumTreeViewSelectComboBox::setDefaultModel() 0426 { 0427 setAlbumModels(nullptr, nullptr); 0428 } 0429 0430 void AlbumTreeViewSelectComboBox::setAlbumModels(AlbumModel* model, CheckableAlbumFilterModel* filterModel) 0431 { 0432 if (!m_treeView) 0433 { 0434 AlbumTreeView::Flags flags; 0435 m_treeView = new AlbumTreeView(this, flags); 0436 } 0437 0438 if (!model) 0439 { 0440 model = new AlbumModel(AlbumModel::IgnoreRootAlbum, this); 0441 } 0442 0443 if (!filterModel) 0444 { 0445 filterModel = new CheckableAlbumFilterModel(this); 0446 } 0447 0448 view()->setAlbumModel(model); 0449 view()->setAlbumFilterModel(filterModel); 0450 0451 AlbumSelectComboBox::setAlbumModels(view()->albumModel(), view()->albumFilterModel()); 0452 0453 view()->expandToDepth(0); 0454 } 0455 0456 // --------------------------------------------------------------------------------------------------- 0457 0458 TagTreeViewSelectComboBox::TagTreeViewSelectComboBox(QWidget* const parent) 0459 : AbstractAlbumTreeViewSelectComboBox(parent) 0460 { 0461 } 0462 0463 TagTreeView* TagTreeViewSelectComboBox::view() const 0464 { 0465 return static_cast<TagTreeView*>(m_treeView); 0466 } 0467 0468 void TagTreeViewSelectComboBox::setDefaultModel() 0469 { 0470 setAlbumModels(nullptr, nullptr); 0471 } 0472 0473 void TagTreeViewSelectComboBox::setAlbumModels(TagModel* model, 0474 TagPropertiesFilterModel* filteredModel, 0475 CheckableAlbumFilterModel* filterModel) 0476 { 0477 if (!m_treeView) 0478 { 0479 TagTreeView::Flags flags; 0480 m_treeView = new TagTreeView(this, flags); 0481 } 0482 0483 if (!model) 0484 { 0485 model = new TagModel(AlbumModel::IgnoreRootAlbum, this); 0486 } 0487 0488 if (!filteredModel) 0489 { 0490 filteredModel = new TagPropertiesFilterModel(this); 0491 } 0492 0493 if (!filterModel) 0494 { 0495 filterModel = new CheckableAlbumFilterModel(this); 0496 } 0497 0498 view()->setAlbumModel(model); 0499 view()->setAlbumFilterModel(filteredModel, filterModel); 0500 0501 AlbumSelectComboBox::setAlbumModels(view()->albumModel(), view()->albumFilterModel()); 0502 } 0503 0504 } // namespace Digikam 0505 0506 #include "albumselectcombobox.moc" 0507 0508 #include "moc_albumselectcombobox.cpp"