File indexing completed on 2025-01-05 03:58:31
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2010-03-22 0007 * Description : A view to display a list of items with GPS info. 0008 * 0009 * SPDX-FileCopyrightText: 2010-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * SPDX-FileCopyrightText: 2010 by Michael G. Hansen <mike at mghansen dot de> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "gpsitemlist.h" 0017 0018 // Qt includes 0019 0020 #include <QDrag> 0021 #include <QHeaderView> 0022 #include <QWheelEvent> 0023 #include <QMenu> 0024 #include <QAction> 0025 0026 // KDE includes 0027 0028 #include <kconfiggroup.h> 0029 0030 // Local includes 0031 0032 #include "digikam_debug.h" 0033 #include "gpsitemdelegate.h" 0034 #include "gpsitemlistdragdrophandler.h" 0035 0036 namespace Digikam 0037 { 0038 0039 class Q_DECL_HIDDEN GPSItemList::Private 0040 { 0041 public: 0042 0043 explicit Private() 0044 : editEnabled (true), 0045 dragEnabled (false), 0046 model (nullptr), 0047 selectionModel (nullptr), 0048 itemDelegate (nullptr), 0049 imageSortProxyModel (nullptr), 0050 dragDropHandler (nullptr) 0051 { 0052 } 0053 0054 bool editEnabled; 0055 bool dragEnabled; 0056 GPSItemModel* model; 0057 QItemSelectionModel* selectionModel; 0058 GPSItemDelegate* itemDelegate; 0059 GPSItemSortProxyModel* imageSortProxyModel; 0060 ItemListDragDropHandler* dragDropHandler; 0061 }; 0062 0063 GPSItemList::GPSItemList(QWidget* const parent) 0064 : QTreeView(parent), 0065 d(new Private()) 0066 { 0067 header()->setSectionsMovable(true); 0068 setAlternatingRowColors(true); 0069 setUniformRowHeights(true); 0070 setRootIsDecorated(false); 0071 0072 d->itemDelegate = new GPSItemDelegate(this, this); 0073 setItemDelegate(d->itemDelegate); 0074 setThumbnailSize(60); 0075 slotUpdateActionsEnabled(); 0076 0077 header()->installEventFilter(this); 0078 } 0079 0080 GPSItemList::~GPSItemList() 0081 { 0082 delete d; 0083 } 0084 0085 void GPSItemList::startDrag(Qt::DropActions supportedActions) 0086 { 0087 if (!d->dragDropHandler) 0088 { 0089 QTreeView::startDrag(supportedActions); 0090 return; 0091 } 0092 0093 // NOTE: read the selected indices from the source selection model, not our selection model, 0094 // which is for the sorted model! 0095 0096 const QList<QModelIndex> selectedIndicesFromModel = d->selectionModel->selectedIndexes(); 0097 QList<QPersistentModelIndex> selectedIndices; 0098 0099 for (int i = 0 ; i < selectedIndicesFromModel.count() ; ++i) 0100 { 0101 selectedIndices << selectedIndicesFromModel.at(i); 0102 } 0103 0104 QMimeData* const dragMimeData = d->dragDropHandler->createMimeData(selectedIndices); 0105 0106 if (!dragMimeData) 0107 { 0108 return; 0109 } 0110 0111 QDrag* const drag = new QDrag(this); 0112 drag->setMimeData(dragMimeData); 0113 drag->exec(Qt::CopyAction); 0114 } 0115 0116 void GPSItemList::setModelAndSelectionModel(GPSItemModel* const model, QItemSelectionModel* const selectionModel) 0117 { 0118 d->model = model; 0119 d->selectionModel = selectionModel; 0120 d->imageSortProxyModel = new GPSItemSortProxyModel(d->model, d->selectionModel); 0121 setModel(d->imageSortProxyModel); 0122 0123 connect(d->model, SIGNAL(signalThumbnailForIndexAvailable(QPersistentModelIndex,QPixmap)), 0124 this, SLOT(slotThumbnailFromModel(QPersistentModelIndex,QPixmap))); 0125 0126 connect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), 0127 this, SLOT(slotInternalTreeViewImageActivated(QModelIndex,QModelIndex))); 0128 0129 if (d->imageSortProxyModel->mappedSelectionModel()) 0130 { 0131 setSelectionModel(d->imageSortProxyModel->mappedSelectionModel()); 0132 } 0133 } 0134 0135 void GPSItemList::setDragDropHandler(ItemListDragDropHandler* const dragDropHandler) 0136 { 0137 d->dragDropHandler = dragDropHandler; 0138 } 0139 0140 GPSItemModel* GPSItemList::getModel() const 0141 { 0142 return d->model; 0143 } 0144 0145 void GPSItemList::setThumbnailSize(const int size) 0146 { 0147 d->itemDelegate->setThumbnailSize(size); 0148 setColumnWidth(GPSItemContainer::ColumnThumbnail, size); 0149 } 0150 0151 void GPSItemList::slotIncreaseThumbnailSize() 0152 { 0153 // TODO: pick reasonable limits and make sure we stay on multiples of 5 0154 0155 const int currentThumbnailSize = d->itemDelegate->getThumbnailSize(); 0156 0157 if (currentThumbnailSize < 200) 0158 { 0159 setThumbnailSize(currentThumbnailSize + 5); 0160 } 0161 } 0162 0163 void GPSItemList::slotDecreaseThumbnailSize() 0164 { 0165 const int currentThumbnailSize = d->itemDelegate->getThumbnailSize(); 0166 0167 if (currentThumbnailSize > 30) 0168 { 0169 setThumbnailSize(currentThumbnailSize - 5); 0170 } 0171 } 0172 0173 void GPSItemList::wheelEvent(QWheelEvent* we) 0174 { 0175 if ((we->modifiers() & Qt::ControlModifier) == 0) 0176 { 0177 QTreeView::wheelEvent(we); 0178 return; 0179 } 0180 0181 we->accept(); 0182 0183 if (we->angleDelta().y() > 0) 0184 { 0185 slotIncreaseThumbnailSize(); 0186 } 0187 else if (we->angleDelta().y() < 0) 0188 { 0189 slotDecreaseThumbnailSize(); 0190 } 0191 } 0192 0193 void GPSItemList::slotThumbnailFromModel(const QPersistentModelIndex& index, const QPixmap& /*pixmap*/) 0194 { 0195 // TODO: verify that the size corresponds to the size of our thumbnails! 0196 0197 update(d->imageSortProxyModel->mapFromSource(index)); 0198 } 0199 0200 void GPSItemList::saveSettingsToGroup(KConfigGroup* const group) 0201 { 0202 group->writeEntry("Image List Thumbnail Size", d->itemDelegate->getThumbnailSize()); 0203 group->writeEntry("Header State", header()->saveState()); 0204 } 0205 0206 void GPSItemList::readSettingsFromGroup(const KConfigGroup* const group) 0207 { 0208 setThumbnailSize(group->readEntry("Image List Thumbnail Size", 60)); 0209 0210 const QByteArray headerState = group->readEntry("Header State", QByteArray()); 0211 0212 if (!headerState.isEmpty()) 0213 { 0214 header()->restoreState(headerState); 0215 } 0216 else 0217 { 0218 // by default, hide the advanced columns: 0219 0220 header()->setSectionHidden(GPSItemContainer::ColumnDOP, true); 0221 header()->setSectionHidden(GPSItemContainer::ColumnFixType, true); 0222 header()->setSectionHidden(GPSItemContainer::ColumnNSatellites, true); 0223 } 0224 } 0225 0226 QItemSelectionModel* GPSItemList::getSelectionModel() const 0227 { 0228 return d->selectionModel; 0229 } 0230 0231 void GPSItemList::slotInternalTreeViewImageActivated(const QModelIndex& current, 0232 const QModelIndex& /*previous*/) 0233 { 0234 // qCDebug(DIGIKAM_GENERAL_LOG) << current; 0235 0236 Q_EMIT signalImageActivated(current); 0237 } 0238 0239 GPSItemSortProxyModel* GPSItemList::getSortProxyModel() const 0240 { 0241 return d->imageSortProxyModel; 0242 } 0243 0244 void GPSItemList::setEditEnabled(const bool state) 0245 { 0246 d->editEnabled = state; 0247 slotUpdateActionsEnabled(); 0248 } 0249 0250 void GPSItemList::setDragEnabled(const bool state) 0251 { 0252 d->dragEnabled = state; 0253 slotUpdateActionsEnabled(); 0254 } 0255 0256 void GPSItemList::slotUpdateActionsEnabled() 0257 { 0258 QTreeView::setDragEnabled(d->dragEnabled && d->editEnabled); 0259 0260 if (d->dragEnabled && d->editEnabled) 0261 { 0262 QTreeView::setDragDropMode(QAbstractItemView::DragOnly); 0263 } 0264 } 0265 0266 bool GPSItemList::eventFilter(QObject* watched, QEvent* event) 0267 { 0268 QHeaderView* const headerView = header(); 0269 0270 if (!d->model || (watched != headerView) || (event->type() != QEvent::ContextMenu)) 0271 { 0272 return QWidget::eventFilter(watched, event); 0273 } 0274 0275 QMenu* const menu = new QMenu(this); 0276 0277 // add action for all the columns 0278 0279 for (int i = 0 ; i < d->model->columnCount() ; ++i) 0280 { 0281 const QString columnName = d->model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString(); 0282 const bool isVisible = !headerView->isSectionHidden(i); 0283 0284 QAction* const columnAction = new QAction(columnName, menu); 0285 columnAction->setCheckable(true); 0286 columnAction->setChecked(isVisible); 0287 columnAction->setData(i); 0288 0289 menu->addAction(columnAction); 0290 } 0291 0292 connect(menu, SIGNAL(triggered(QAction*)), 0293 this, SLOT(slotColumnVisibilityActionTriggered(QAction*))); 0294 0295 QContextMenuEvent* const e = static_cast<QContextMenuEvent*>(event); 0296 menu->exec(e->globalPos()); 0297 0298 return true; 0299 } 0300 0301 void GPSItemList::slotColumnVisibilityActionTriggered(QAction* action) 0302 { 0303 const int columnNumber = action->data().toInt(); 0304 const bool columnIsVisible = action->isChecked(); 0305 0306 header()->setSectionHidden(columnNumber, !columnIsVisible); 0307 } 0308 0309 } // namespace Digikam 0310 0311 #include "moc_gpsitemlist.cpp"