File indexing completed on 2024-05-19 04:27:45

0001 /* This file is part of the KDE project
0002  * SPDX-FileCopyrightText: 2019 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #include "KisResourceItemListView.h"
0008 
0009 #include <QEvent>
0010 #include <QScroller>
0011 #include <QScrollBar>
0012 #include <QHelpEvent>
0013 
0014 #include "KisIconToolTip.h"
0015 
0016 
0017 struct  Q_DECL_HIDDEN KisResourceItemListView::Private
0018 {
0019     ListViewMode viewMode = ListViewMode::IconGrid;
0020     bool strictSelectionMode {false};
0021     KisIconToolTip tip;
0022 
0023     QScroller* scroller {0};
0024     QString prev_scrollbar_style;
0025 
0026     QSize requestedItemSize = QSize(56, 56);
0027 };
0028 
0029 KisResourceItemListView::KisResourceItemListView(QWidget *parent)
0030     : QListView(parent)
0031     , m_d(new Private)
0032 {
0033     setSelectionMode(QAbstractItemView::SingleSelection);
0034     setContextMenuPolicy(Qt::DefaultContextMenu);   
0035     setResizeMode(QListView::Adjust);
0036     setUniformItemSizes(true);
0037 
0038     // Default configuration
0039     setViewMode(QListView::IconMode);
0040     setGridSize(QSize(56, 56));
0041     setIconSize(QSize(56, 56));
0042     setResizeMode(QListView::Adjust);
0043     setUniformItemSizes(true);
0044 
0045     m_d->scroller = KisKineticScroller::createPreconfiguredScroller(this);
0046     if (m_d->scroller) {
0047         connect(m_d->scroller, SIGNAL(stateChanged(QScroller::State)), this, SLOT(slotScrollerStateChange(QScroller::State)));
0048     }
0049 
0050     connect(this, SIGNAL(clicked(QModelIndex)), SIGNAL(currentResourceClicked(const QModelIndex &)));
0051 
0052     m_d->prev_scrollbar_style = horizontalScrollBar()->styleSheet();
0053 }
0054 
0055 KisResourceItemListView::~KisResourceItemListView()
0056 {
0057 }
0058 
0059 void KisResourceItemListView::setListViewMode(ListViewMode viewMode)
0060 {
0061     m_d->viewMode = viewMode;
0062 
0063     auto restoreScrollbar = [&, this] () {
0064         horizontalScrollBar()->setStyleSheet(m_d->prev_scrollbar_style);
0065         setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded);
0066     };
0067 
0068     switch (viewMode) {
0069     case ListViewMode::IconGrid: {
0070         setViewMode(ViewMode::IconMode);
0071         setFlow(Flow::LeftToRight);
0072         setWrapping(true);
0073         restoreScrollbar();
0074 
0075         setItemSize(m_d->requestedItemSize);
0076         break;
0077     }
0078     case ListViewMode::IconStripHorizontal: {
0079         setViewMode(ViewMode::IconMode);
0080         setFlow(Flow::LeftToRight);
0081         setWrapping(false);
0082 
0083         // this is the only way to hide it and not have it ocupy space
0084         horizontalScrollBar()->setStyleSheet("QScrollBar::horizontal {height: 0px;}");
0085         setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
0086 
0087         setItemSize(m_d->requestedItemSize);
0088         break;
0089     }
0090     case ListViewMode::Detail: {
0091         setViewMode(ViewMode::ListMode);
0092         setFlow(Flow::TopToBottom);
0093         setWrapping(false);
0094         restoreScrollbar();
0095         setItemSize(m_d->requestedItemSize);
0096         // horizontalScrollBar()->setStyleSheet(m_d->prev_scrollbar_style);
0097         setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded);
0098         setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded);
0099         break;
0100     }
0101     }
0102 }
0103 
0104 void KisResourceItemListView::setItemSize(QSize size)
0105 {
0106     m_d->requestedItemSize = size;
0107 
0108     switch (m_d->viewMode) {
0109     case ListViewMode::IconGrid: {
0110         setGridSize(size);
0111         setIconSize(size);
0112         break;
0113     }
0114     case ListViewMode::IconStripHorizontal: {
0115         // you can not set the item size in strip mode
0116         // it is configured automatically based on size
0117         break;
0118     }
0119     case ListViewMode::Detail: {
0120         const int w = width() - horizontalScrollBar()->width();
0121         setGridSize(QSize(w, size.height()));
0122         setIconSize(QSize(size));
0123         break;
0124     }
0125     }
0126 }
0127 
0128 void KisResourceItemListView::setStrictSelectionMode(bool enable)
0129 {
0130     m_d->strictSelectionMode = enable;
0131 }
0132 
0133 void KisResourceItemListView::setFixedToolTipThumbnailSize(const QSize &size)
0134 {
0135     m_d->tip.setFixedToolTipThumbnailSize(size);
0136 }
0137 
0138 void KisResourceItemListView::setToolTipShouldRenderCheckers(bool value)
0139 {
0140     m_d->tip.setToolTipShouldRenderCheckers(value);
0141 }
0142 
0143 void KisResourceItemListView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
0144 {
0145     // QAbstractItemView moves the current index if the row it points to is removed,
0146     // which we don't want for strict selections
0147     QModelIndex current = currentIndex();
0148     if (selectionMode() == SingleSelection
0149             && m_d->strictSelectionMode
0150             && current.isValid()
0151             && current.row() >= start
0152             && current.row() <= end) {
0153 
0154         selectionModel()->clear();
0155     }
0156     QListView::rowsAboutToBeRemoved(parent, start, end);
0157 }
0158 
0159 void KisResourceItemListView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
0160 {
0161     // base class takes care of viewport updates
0162     QListView::selectionChanged(selected, deselected);
0163 
0164     if (selected.isEmpty()) {
0165         emit currentResourceChanged(QModelIndex());
0166     }
0167     else {
0168         emit currentResourceChanged(selected.indexes().first());
0169     }
0170 }
0171 
0172 QItemSelectionModel::SelectionFlags KisResourceItemListView::selectionCommand(const QModelIndex &index, const QEvent *event) const
0173 {
0174     QItemSelectionModel::SelectionFlags cmd = QListView::selectionCommand(index, event);
0175 
0176     // avoid deselecting the current item by Ctrl-clicking in single selection mode
0177     if (selectionMode() == SingleSelection
0178             && m_d->strictSelectionMode
0179             && cmd.testFlag(QItemSelectionModel::Deselect)) {
0180 
0181         cmd = QItemSelectionModel::NoUpdate;
0182     }
0183     return cmd;
0184 }
0185 
0186 void KisResourceItemListView::contextMenuEvent(QContextMenuEvent *event)
0187 {
0188     QListView::contextMenuEvent(event);
0189     emit contextMenuRequested(event->globalPos());
0190 }
0191 
0192 bool KisResourceItemListView::viewportEvent(QEvent *event)
0193 {
0194     if (!model()) return true;
0195 
0196     if (event->type() == QEvent::ToolTip) {
0197         QHelpEvent *he = static_cast<QHelpEvent *>(event);
0198         QStyleOptionViewItem option = viewOptions();
0199         QModelIndex index = model()->buddy(indexAt(he->pos()));
0200         if (index.isValid()) {
0201             option.rect = visualRect(index);
0202             m_d->tip.showTip(this, he->pos(), option, index);
0203             return true;
0204         }
0205         m_d->tip.hide();
0206     }
0207 
0208     return QListView::viewportEvent(event);
0209 }
0210 
0211 void KisResourceItemListView::resizeEvent(QResizeEvent *event)
0212 {
0213     QListView::resizeEvent(event);
0214 
0215     switch (m_d->viewMode) {
0216     case ListViewMode::IconStripHorizontal: {
0217         const int height = event->size().height();
0218         setGridSize(QSize(height, height));
0219         setIconSize(QSize(height, height));
0220         break;
0221     }
0222     case ListViewMode::Detail: {
0223         setItemSize(m_d->requestedItemSize);
0224     }
0225     }
0226     scrollTo(currentIndex(), QAbstractItemView::PositionAtCenter);
0227 }