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

0001 /* This file is part of the KDE project
0002    SPDX-FileCopyrightText: 2002 Patrick Julien <freak@codepimps.org>
0003    SPDX-FileCopyrightText: 2007 Jan Hambrecht <jaham@gmx.net>
0004    SPDX-FileCopyrightText: 2007 Sven Langkamp <sven.langkamp@gmail.com>
0005    SPDX-FileCopyrightText: 2011 Srikanth Tiyyagura <srikanth.tulasiram@gmail.com>
0006    SPDX-FileCopyrightText: 2011 José Luis Vergara <pentalis@gmail.com>
0007    SPDX-FileCopyrightText: 2013 Sascha Suelzer <s.suelzer@gmail.com>
0008 
0009    SPDX-License-Identifier: LGPL-2.0-or-later
0010 */
0011 #include "KisResourceItemChooser.h"
0012 
0013 #include <math.h>
0014 
0015 #include <QGridLayout>
0016 #include <QButtonGroup>
0017 #include <QHeaderView>
0018 #include <QAbstractProxyModel>
0019 #include <QLabel>
0020 #include <QScrollArea>
0021 #include <QScrollBar>
0022 #include <QImage>
0023 #include <QPixmap>
0024 #include <QPainter>
0025 #include <QSplitter>
0026 #include <QToolButton>
0027 #include <QWheelEvent>
0028 #include <QLineEdit>
0029 #include <QComboBox>
0030 #include <QStandardPaths>
0031 
0032 #include "ksharedconfig.h"
0033 #include "kconfiggroup.h"
0034 #include <klocalizedstring.h>
0035 
0036 #include <KoIcon.h>
0037 #include <KoFileDialog.h>
0038 #include <KisKineticScroller.h>
0039 #include <KisMimeDatabase.h>
0040 #include "KisPopupButton.h"
0041 
0042 #include <KisResourceModel.h>
0043 #include <KisTagFilterResourceProxyModel.h>
0044 #include <KisResourceLoaderRegistry.h>
0045 
0046 #include "KisResourceItemListView.h"
0047 #include "KisResourceItemDelegate.h"
0048 #include "KisTagFilterWidget.h"
0049 #include "KisTagChooserWidget.h"
0050 #include "KisResourceItemChooserSync.h"
0051 #include "KisResourceTaggingManager.h"
0052 #include <KisResourceUserOperations.h>
0053 
0054 #include "KisStorageChooserWidget.h"
0055 
0056 
0057 class Q_DECL_HIDDEN KisResourceItemChooser::Private
0058 {
0059 public:
0060     Private(QString _resourceType)
0061         : resourceType(_resourceType)
0062     {}
0063 
0064     QString resourceType;
0065 
0066     // Top/Bottom bar
0067     KisTagFilterResourceProxyModel *tagFilterProxyModel {0};
0068     KisResourceTaggingManager *tagManager {0};
0069     KisPopupButton *viewModeButton {0};
0070     KisStorageChooserWidget *storagePopupButton {0};
0071 
0072     // Resources view
0073     KisResourceItemListView *view {0};
0074     QSplitter *resourcesSplitter {0};
0075 
0076     QScrollArea *previewScroller {0};
0077     QLabel *previewLabel {0};
0078 
0079     // Import and Export buttons
0080     QFrame* importExportBtns {0};
0081     QToolButton *importButton {0};
0082     QToolButton *deleteButton {0};
0083     QButtonGroup *buttonGroup {0};  // does not seem to do much, maybe replace with std::array
0084 
0085     // Custom Buttons
0086     QList<QAbstractButton*> customButtons;
0087 
0088     bool usePreview {false};
0089     bool tiledPreview {false};
0090     bool grayscalePreview {false};
0091     bool synced {false};
0092     bool updatesBlocked {false};
0093 
0094     KoResourceSP currentResource;
0095     Layout layout = Layout::NotSet;
0096     ListViewMode requestedViewMode = ListViewMode::IconGrid;
0097     bool isResponsive = false;
0098     bool showViewModeBtn = true;
0099     bool showStoragePopupBtn = true;
0100 
0101     // Horizontal Layout Widgets
0102     QSplitter* horzSplitter {0};
0103     QFrame* left {0};
0104     QFrame* right {0};
0105 
0106     QFrame* right2Rows {0};
0107     QHBoxLayout* top {0};
0108     QHBoxLayout* bot {0};
0109 
0110     QToolButton* scroll_left {0};
0111     QToolButton* scroll_right {0};
0112 
0113     bool restoreSplitterState(Layout layout);
0114 };
0115 
0116 KisResourceItemChooser::KisResourceItemChooser(const QString &resourceType, bool usePreview, QWidget *parent)
0117     : QWidget(parent)
0118     , d(new Private(resourceType))
0119 {
0120     // Tag manager
0121     d->tagFilterProxyModel = new KisTagFilterResourceProxyModel(resourceType, this);
0122     d->tagFilterProxyModel->sort(Qt::DisplayRole);
0123     d->tagManager = new KisResourceTaggingManager(resourceType, d->tagFilterProxyModel, this);
0124 
0125     // Viewmode button
0126     d->viewModeButton = new KisPopupButton(this);
0127     d->viewModeButton->setToolTip(i18n("Display settings"));
0128     d->viewModeButton->setVisible(false);
0129     d->viewModeButton->setArrowVisible(false);
0130     d->viewModeButton->setAutoRaise(true);
0131 
0132     // Storage button
0133     d->storagePopupButton = new KisStorageChooserWidget(resourceType, this);
0134     d->storagePopupButton->setToolTip(i18n("Storage Resources"));
0135     d->storagePopupButton->setAutoRaise(true);
0136     d->storagePopupButton->setArrowVisible(false);
0137 
0138     // Resource List View
0139     d->view = new KisResourceItemListView(this);
0140     d->view->setObjectName("ResourceItemview");
0141     d->view->setStrictSelectionMode(true);
0142 
0143     if (d->resourceType == ResourceType::Gradients) {
0144         d->view->setFixedToolTipThumbnailSize(QSize(256, 64));
0145         d->view->setToolTipShouldRenderCheckers(true);
0146     }
0147     else if (d->resourceType == ResourceType::PaintOpPresets) {
0148         d->view->setFixedToolTipThumbnailSize(QSize(128, 128));
0149     }
0150     else if (d->resourceType == ResourceType::Patterns || d->resourceType == ResourceType::Palettes) {
0151         d->view->setToolTipShouldRenderCheckers(false);
0152         d->view->setFixedToolTipThumbnailSize(QSize(256, 256));
0153     }
0154 
0155     d->view->setItemDelegate(new KisResourceItemDelegate(this));
0156     d->view->setSelectionMode(QAbstractItemView::SingleSelection);
0157     d->view->viewport()->installEventFilter(this);
0158     d->view->setModel(d->tagFilterProxyModel);
0159 
0160     connect(d->tagFilterProxyModel, SIGNAL(afterFilterChanged()), this, SLOT(afterFilterChanged()));
0161 
0162     connect(d->view, SIGNAL(currentResourceChanged(QModelIndex)), this, SLOT(activate(QModelIndex)));
0163     connect(d->view, SIGNAL(currentResourceClicked(QModelIndex)), this, SLOT(clicked(QModelIndex)));
0164     connect(d->view, SIGNAL(contextMenuRequested(QPoint)), this, SLOT(contextMenuRequested(QPoint)));
0165     connect(d->view, SIGNAL(sigSizeChanged()), this, SLOT(updateView()));
0166 
0167     // Splitter with resource views and preview scroller
0168     d->resourcesSplitter = new QSplitter(this);
0169     d->resourcesSplitter->addWidget(d->view);
0170     d->resourcesSplitter->setStretchFactor(0, 1);
0171 
0172     d->usePreview = usePreview;
0173     if (d->usePreview) {
0174         d->previewScroller = new QScrollArea(this);
0175         d->previewScroller->setWidgetResizable(true);
0176         d->previewScroller->setBackgroundRole(QPalette::Dark);
0177         d->previewScroller->setVisible(true);
0178         d->previewScroller->setAlignment(Qt::AlignCenter);
0179         d->previewLabel = new QLabel(this);
0180         d->previewScroller->setWidget(d->previewLabel);
0181         d->resourcesSplitter->addWidget(d->previewScroller);
0182 
0183         if (d->resourcesSplitter->count() == 2) {
0184             d->resourcesSplitter->setSizes(QList<int>() << 280 << 160);
0185         }
0186 
0187         QScroller* scroller = KisKineticScroller::createPreconfiguredScroller(d->previewScroller);
0188         if (scroller) {
0189             connect(scroller, SIGNAL(stateChanged(QScroller::State)), this, SLOT(slotScrollerStateChanged(QScroller::State)));
0190         }
0191     }
0192 
0193     // Import and Export buttons
0194     d->importButton = new QToolButton(this);
0195     d->importButton->setToolTip(i18nc("@info:tooltip", "Import resource"));
0196     d->importButton->setAutoRaise(true);
0197     d->importButton->setEnabled(true);
0198 
0199     d->deleteButton = new QToolButton(this);
0200     d->deleteButton->setToolTip(i18nc("@info:tooltip", "Delete resource"));
0201     d->deleteButton->setEnabled(false);
0202     d->deleteButton->setAutoRaise(true);
0203 
0204     d->buttonGroup = new QButtonGroup(this);
0205     d->buttonGroup->setExclusive(false);
0206     d->buttonGroup->addButton(d->importButton, Button_Import);
0207     d->buttonGroup->addButton(d->deleteButton, Button_Remove);
0208     connect(d->buttonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotButtonClicked(int)));
0209 
0210     d->importExportBtns = new QFrame(this);  
0211     QHBoxLayout* importExportLayout = new QHBoxLayout(d->importExportBtns);
0212     importExportLayout->setAlignment(Qt::AlignmentFlag::AlignLeft);
0213     importExportLayout->setMargin(0);
0214     importExportLayout->addWidget(d->importButton);
0215     importExportLayout->addWidget(d->deleteButton);
0216 
0217     auto removePadding = [](QLayout* layout) {
0218         layout->setMargin(0);
0219         layout->setSpacing(0);
0220     };
0221 
0222     // Layout
0223     QGridLayout* thisLayout = new QGridLayout(this);
0224     thisLayout->setObjectName("ResourceChooser this");
0225     removePadding(thisLayout);
0226 
0227     // Horizontal Layout
0228     {
0229         // Splitter
0230         d->horzSplitter = new QSplitter(this);
0231         d->horzSplitter->setOrientation(Qt::Orientation::Horizontal);
0232         connect(d->horzSplitter, SIGNAL(splitterMoved(int, int)), this, SLOT(slotSaveSplitterState()));
0233 
0234         // Horizontal 1 row
0235         d->left = new QFrame(this);
0236         QSizePolicy newPolicy = d->left->sizePolicy();
0237         newPolicy.setHorizontalStretch(2);
0238         d->left->setSizePolicy(newPolicy);
0239         QHBoxLayout* leftLayout = new QHBoxLayout(d->left);
0240         leftLayout->setObjectName("ResourceChooser left");
0241 
0242         d->right = new QFrame(this);
0243         newPolicy = d->right->sizePolicy();
0244         newPolicy.setHorizontalStretch(0);
0245         d->right->setSizePolicy(newPolicy);
0246         QHBoxLayout* rightLayout = new QHBoxLayout(d->right);
0247         rightLayout->setObjectName("ResourceChooser right");
0248 
0249         // Horizontal 2 rows
0250         d->right2Rows = new QFrame(this);
0251         newPolicy = d->right2Rows->sizePolicy();
0252         newPolicy.setHorizontalStretch(0);
0253         d->right2Rows->setSizePolicy(newPolicy);
0254         QVBoxLayout* rightLayout2 = new QVBoxLayout(d->right2Rows);
0255         rightLayout2->setObjectName("ResourceChooser right 2 rows");
0256 
0257         d->top = new QHBoxLayout();
0258         d->bot = new QHBoxLayout();
0259         rightLayout2->addLayout(d->top);
0260         rightLayout2->addLayout(d->bot);
0261 
0262         // Common style
0263         removePadding(leftLayout);
0264         removePadding(rightLayout);
0265         removePadding(rightLayout2);
0266         removePadding(d->top);
0267         removePadding(d->bot);
0268 
0269         // Scroll buttons
0270         d->scroll_left = new QToolButton(this);
0271         d->scroll_left->setIcon(KisIconUtils::loadIcon("draw-arrow-back"));
0272         connect(d->scroll_left, &QToolButton::clicked, this, &KisResourceItemChooser::scrollBackwards);
0273         d->scroll_right = new QToolButton(this);
0274         d->scroll_right->setIcon(KisIconUtils::loadIcon("draw-arrow-forward"));
0275         connect(d->scroll_right, &QToolButton::clicked, this, &KisResourceItemChooser::scrollForwards);
0276 
0277         // Hide
0278         d->scroll_left->hide();
0279         d->scroll_right->hide();
0280         d->left->hide();
0281         d->right->hide();
0282         d->right2Rows->hide();
0283         d->horzSplitter->hide();
0284     }
0285 
0286     // Other
0287     updateView();
0288 
0289     // Default Configuration
0290     updateButtonState();
0291     showViewModeBtn(false);
0292     showTaggingBar(false);
0293     showImportExportBtns(true);
0294     applyVerticalLayout();
0295 }
0296 
0297 KisResourceItemChooser::~KisResourceItemChooser()
0298 {
0299     disconnect();
0300     delete d;
0301 }
0302 
0303 void KisResourceItemChooser::setResponsiveness(bool isResponsive)
0304 {
0305     if (isResponsive) {
0306 
0307         if (d->isResponsive == false) {
0308             d->isResponsive = true;
0309             changeLayoutBasedOnSize();
0310         }
0311         else {
0312             d->isResponsive = true;
0313         }
0314     }
0315     else {
0316         d->isResponsive = false;
0317     }
0318 }
0319 
0320 void KisResourceItemChooser::setListViewMode(ListViewMode newViewMode)
0321 {
0322     d->requestedViewMode = newViewMode;
0323     if (d->layout == Layout::NotSet || d->layout == Layout::Vertical) {
0324         d->view->setListViewMode(newViewMode);
0325     }
0326 }
0327 
0328 KisTagFilterResourceProxyModel *KisResourceItemChooser::tagFilterModel() const
0329 {
0330     return d->tagFilterProxyModel;
0331 }
0332 
0333 void KisResourceItemChooser::slotButtonClicked(int button)
0334 {
0335     if (button == Button_Import) {
0336         QStringList mimeTypes = KisResourceLoaderRegistry::instance()->mimeTypes(d->resourceType);
0337         KoFileDialog dialog(0, KoFileDialog::OpenFiles, "OpenDocument");
0338         dialog.setMimeTypeFilters(mimeTypes);
0339         dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
0340         dialog.setCaption(i18nc("@title:window", "Choose File to Add"));
0341         Q_FOREACH(const QString &filename, dialog.filenames()) {
0342             if (QFileInfo(filename).exists() && QFileInfo(filename).isReadable()) {
0343 
0344                 KoResourceSP previousResource = this->currentResource();
0345                 KoResourceSP newResource = KisResourceUserOperations::importResourceFileWithUserInput(this, "", d->resourceType, filename);
0346 
0347                 if (previousResource && newResource && !currentResource()) {
0348                     /// We have overridden the currently selected resource and
0349                     /// nothing is selected now
0350                     setCurrentResource(newResource);
0351                 } else if (currentResource() == newResource) {
0352                     /// We have overridden the currently selected resource and
0353                     /// the model has managed to track the selection under it
0354                     /// (that is not possible right now, but can theoretically
0355                     /// happen under some circumstances)
0356                     const QModelIndex index = d->tagFilterProxyModel->indexForResource(newResource);
0357                     updatePreview(index);
0358                 }
0359             }
0360         }
0361         tagFilterModel()->sort(Qt::DisplayRole);
0362     }
0363     else if (button == Button_Remove) {
0364         QModelIndex index = d->view->currentIndex();
0365         if (index.isValid()) {
0366             d->tagFilterProxyModel->setResourceInactive(index);
0367         }
0368         int row = index.row();
0369         int rowMin = --row;
0370         row = qBound(0, rowMin, row);
0371         setCurrentItem(row);
0372         activate(d->tagFilterProxyModel->index(row, index.column()));
0373     }
0374     updateButtonState();
0375 }
0376 
0377 void KisResourceItemChooser::showImportExportBtns(bool show)
0378 {
0379     // assert(show == false);
0380     if (show) {
0381         d->importExportBtns->show();
0382     }
0383     else {
0384         d->importExportBtns->hide();
0385     }
0386 }
0387 
0388 void KisResourceItemChooser::showTaggingBar(bool show)
0389 {
0390     d->tagManager->showTaggingBar(show);
0391 }
0392 
0393 void KisResourceItemChooser::setRowHeight(int rowHeight)
0394 {
0395     d->view->setItemSize(QSize(d->view->gridSize().width(), rowHeight));
0396 }
0397 
0398 void KisResourceItemChooser::setColumnWidth(int columnWidth)
0399 {
0400     d->view->setItemSize(QSize(columnWidth, d->view->gridSize().height()));
0401 }
0402 
0403 void KisResourceItemChooser::setItemDelegate(QAbstractItemDelegate *delegate)
0404 {
0405     d->view->setItemDelegate(delegate);
0406 }
0407 
0408 KoResourceSP KisResourceItemChooser::currentResource(bool includeHidden) const
0409 {
0410     if (includeHidden || d->view->selectionModel()->isSelected(d->view->currentIndex())) {
0411         return d->currentResource;
0412     }
0413 
0414     return nullptr;
0415 }
0416 
0417 void KisResourceItemChooser::setCurrentResource(KoResourceSP resource)
0418 {
0419     // don't update if the change came from the same chooser
0420     if (d->updatesBlocked) {
0421         return;
0422     }
0423     QModelIndex index = d->tagFilterProxyModel->indexForResource(resource);
0424     d->view->setCurrentIndex(index);
0425 
0426     // The resource may currently be filtered out, but we want to be able
0427     // to select it if the filter changes and includes the resource.
0428     // Otherwise, activate() already took care of setting the current resource.
0429     if (!index.isValid()) {
0430         d->currentResource = resource;
0431     }
0432     updatePreview(index);
0433 }
0434 
0435 void KisResourceItemChooser::setCurrentResource(QString resourceName)
0436 {
0437     // don't update if the change came from the same chooser
0438     if (d->updatesBlocked) {
0439         return;
0440     }
0441 
0442     for (int row = 0; row < d->tagFilterProxyModel->rowCount(); row++) {
0443         for (int col = 0; col < d->tagFilterProxyModel->columnCount(); col++) {
0444             QModelIndex index = d->tagFilterProxyModel->index(row, col);
0445             KoResourceSP resource = d->tagFilterProxyModel->resourceForIndex(index);
0446 
0447             if (resource->name() == resourceName) {
0448                 d->view->setCurrentIndex(index);
0449 
0450                 // The resource may currently be filtered out, but we want to be able
0451                 // to select it if the filter changes and includes the resource.
0452                 // Otherwise, activate() already took care of setting the current resource.
0453                 if (!index.isValid()) {
0454                     d->currentResource = resource;
0455                 }
0456                 updatePreview(index);
0457             }
0458         }
0459     }
0460 }
0461 
0462 void KisResourceItemChooser::setPreviewOrientation(Qt::Orientation orientation)
0463 {
0464     d->resourcesSplitter->setOrientation(orientation);
0465 }
0466 
0467 void KisResourceItemChooser::setPreviewTiled(bool tiled)
0468 {
0469     d->tiledPreview = tiled;
0470 }
0471 
0472 void KisResourceItemChooser::setGrayscalePreview(bool grayscale)
0473 {
0474     d->grayscalePreview = grayscale;
0475 }
0476 
0477 void KisResourceItemChooser::setCurrentItem(int row)
0478 {
0479     QModelIndex index = d->view->model()->index(row, 0);
0480     if (!index.isValid())
0481         return;
0482 
0483     d->view->setCurrentIndex(index);
0484     if (index.isValid()) {
0485         updatePreview(index);
0486     }
0487 }
0488 
0489 void KisResourceItemChooser::scrollBackwards()
0490 {
0491     QScrollBar* bar = d->view->horizontalScrollBar();
0492     bar->setValue(bar->value() - d->view->gridSize().width());
0493 }
0494 
0495 void KisResourceItemChooser::scrollForwards()
0496 {
0497     QScrollBar* bar = d->view->horizontalScrollBar();
0498     bar->setValue(bar->value() + d->view->gridSize().width());
0499 }
0500 
0501 void KisResourceItemChooser::activate(const QModelIndex &index)
0502 {
0503     if (!index.isValid())
0504     {
0505         updateButtonState();
0506         return;
0507     }
0508 
0509     KoResourceSP resource = resourceFromModelIndex(index);
0510 
0511     if (resource && resource->valid()) {
0512         if (resource != d->currentResource) {
0513             d->currentResource = resource;
0514             d->updatesBlocked = true;
0515             emit resourceSelected(resource);
0516             d->updatesBlocked = false;
0517         }
0518         updatePreview(index);
0519         updateButtonState();
0520     }
0521 }
0522 
0523 void KisResourceItemChooser::clicked(const QModelIndex &index)
0524 {
0525     Q_UNUSED(index);
0526 
0527     KoResourceSP resource = currentResource();
0528     if (resource) {
0529         emit resourceClicked(resource);
0530     }
0531 }
0532 
0533 void KisResourceItemChooser::updateButtonState()
0534 {
0535     QAbstractButton *removeButton = d->buttonGroup->button(Button_Remove);
0536     if (! removeButton)
0537         return;
0538 
0539     KoResourceSP resource = currentResource();
0540     if (resource) {
0541         removeButton->setEnabled(!resource->permanent());
0542         return;
0543     }
0544     removeButton->setEnabled(false);
0545 }
0546 
0547 void KisResourceItemChooser::updatePreview(const QModelIndex &idx)
0548 {
0549     if (!d->usePreview) return;
0550 
0551     if (!idx.isValid()) {
0552         d->previewLabel->setPixmap(QPixmap());
0553         return;
0554     }
0555 
0556     QImage image = idx.data(Qt::UserRole + KisAbstractResourceModel::Thumbnail).value<QImage>();
0557 
0558     if (image.format() != QImage::Format_RGB32 &&
0559         image.format() != QImage::Format_ARGB32 &&
0560         image.format() != QImage::Format_ARGB32_Premultiplied) {
0561 
0562         image.convertTo(QImage::Format_ARGB32_Premultiplied);
0563     }
0564 
0565     if (d->tiledPreview) {
0566         int width = d->previewScroller->width() * 4;
0567         int height = d->previewScroller->height() * 4;
0568         QImage img(width, height, image.format());
0569         QPainter gc(&img);
0570         gc.fillRect(img.rect(), Qt::white);
0571         gc.setPen(Qt::NoPen);
0572         gc.setBrush(QBrush(image));
0573         gc.drawRect(img.rect());
0574         image = img;
0575     }
0576 
0577     // Only convert to grayscale if it is rgb. Otherwise, it's gray already.
0578     if (d->grayscalePreview && !image.isGrayscale()) {
0579         QRgb *pixel = reinterpret_cast<QRgb *>(image.bits());
0580         for (int row = 0; row < image.height(); ++row) {
0581             for (int col = 0; col < image.width(); ++col) {
0582                 const QRgb currentPixel = pixel[row * image.width() + col];
0583                 const int red = qRed(currentPixel);
0584                 const int green = qGreen(currentPixel);
0585                 const int blue = qBlue(currentPixel);
0586                 const int grayValue = (red * 11 + green * 16 + blue * 5) / 32;
0587                 pixel[row * image.width() + col] = qRgb(grayValue, grayValue, grayValue);
0588             }
0589         }
0590     }
0591     d->previewLabel->setPixmap(QPixmap::fromImage(image));
0592 }
0593 
0594 KoResourceSP KisResourceItemChooser::resourceFromModelIndex(const QModelIndex &index) const
0595 {
0596     if (!index.isValid()) {
0597         return 0;
0598     }
0599     KoResourceSP r = d->tagFilterProxyModel->resourceForIndex(index);
0600     return r;
0601 }
0602 
0603 QSize KisResourceItemChooser::viewSize() const
0604 {
0605     return d->view->size();
0606 }
0607 
0608 KisResourceItemListView *KisResourceItemChooser::itemView() const
0609 {
0610     return d->view;
0611 }
0612 
0613 void KisResourceItemChooser::contextMenuRequested(const QPoint &pos)
0614 {
0615     d->tagManager->contextMenuRequested(currentResource(), pos);
0616 }
0617 
0618 void KisResourceItemChooser::showStorageBtn(bool visible)
0619 {
0620     d->storagePopupButton->setVisible(visible);
0621     d->showStoragePopupBtn = visible;
0622 }
0623 
0624 void KisResourceItemChooser::showViewModeBtn(bool visible)
0625 {
0626     d->viewModeButton->setVisible(visible);
0627     d->showViewModeBtn = visible;
0628 }
0629 
0630 KisPopupButton *KisResourceItemChooser::viewModeButton() const
0631 {
0632     return d->viewModeButton;
0633 }
0634 
0635 void KisResourceItemChooser::setSynced(bool sync)
0636 {
0637     if (d->synced == sync)
0638         return;
0639 
0640     d->synced = sync;
0641     KisResourceItemChooserSync *chooserSync = KisResourceItemChooserSync::instance();
0642     if (sync) {
0643         connect(chooserSync, SIGNAL(baseLengthChanged(int)), SLOT(baseLengthChanged(int)));
0644         baseLengthChanged(chooserSync->baseLength());
0645     } else {
0646         chooserSync->disconnect(this);
0647     }
0648 }
0649 
0650 void KisResourceItemChooser::baseLengthChanged(int length)
0651 {
0652     if (d->synced) {
0653         d->view->setItemSize(QSize(length, length));
0654     }
0655 }
0656 
0657 void KisResourceItemChooser::afterFilterChanged()
0658 {
0659     // Note: Item model reset events silently reset the view's selection model too.
0660     // This currently only covers models resets as part of filter changes.
0661     QModelIndex idx = d->tagFilterProxyModel->indexForResource(d->currentResource);
0662 
0663     if (idx.isValid()) {
0664         d->view->setCurrentIndex(idx);
0665     }
0666 
0667     updateButtonState();
0668 }
0669 
0670 bool KisResourceItemChooser::eventFilter(QObject *object, QEvent *event)
0671 {
0672     if (d->synced && event->type() == QEvent::Wheel) {
0673         KisResourceItemChooserSync *chooserSync = KisResourceItemChooserSync::instance();
0674         QWheelEvent *qwheel = static_cast<QWheelEvent *>(event);
0675         if (qwheel->modifiers() & Qt::ControlModifier) {
0676 
0677             int degrees = qwheel->delta() / 8;
0678             int newBaseLength = chooserSync->baseLength() + degrees / 15 * 10;
0679             chooserSync->setBaseLength(newBaseLength);
0680             return true;
0681         }
0682     }
0683     return QObject::eventFilter(object, event);
0684 }
0685 
0686 
0687 void KisResourceItemChooser::resizeEvent(QResizeEvent *event)
0688 {
0689     QWidget::resizeEvent(event);
0690     changeLayoutBasedOnSize();
0691     updateView();
0692 }
0693 
0694 void KisResourceItemChooser::showEvent(QShowEvent *event)
0695 {
0696     QWidget::showEvent(event);
0697     updateView();
0698 }
0699 
0700 void KisResourceItemChooser::hideEverything()
0701 {
0702     d->horzSplitter->hide();
0703     d->left->hide();
0704     d->right->hide();
0705     d->right2Rows->hide();
0706     d->scroll_left->hide();
0707     d->scroll_right->hide();
0708 
0709     d->viewModeButton->hide();
0710 }
0711 
0712 void KisResourceItemChooser::applyVerticalLayout()
0713 {
0714     if (d->layout == Layout::Vertical) {
0715         return;
0716     }
0717 
0718     hideEverything();
0719 
0720     d->view->setListViewMode(d->requestedViewMode);
0721     emit listViewModeChanged(d->requestedViewMode);
0722 
0723     // The horizontal layouts size the items based widget height not user configured base length
0724     // so it needs to be restored when switching back to vertical layout
0725     KisResourceItemChooserSync *chooserSync = KisResourceItemChooserSync::instance();
0726     d->view->setItemSize(QSize(chooserSync->baseLength(), chooserSync->baseLength()));
0727 
0728     QGridLayout* thisLayout = dynamic_cast<QGridLayout*>(layout());
0729     thisLayout->addWidget(d->tagManager->tagChooserWidget(), 0, 0);
0730     thisLayout->addWidget(d->viewModeButton, 0, 1);
0731     thisLayout->addWidget(d->storagePopupButton, 0, 2);
0732     thisLayout->addWidget(d->resourcesSplitter, 1, 0, 1, 3);
0733     thisLayout->setRowStretch(1, 1);
0734     thisLayout->addWidget(d->tagManager->tagFilterWidget(), 2, 0, 1, 3);
0735     thisLayout->addWidget(d->importExportBtns, 3, 0, 1, 3);
0736 
0737     d->viewModeButton->setVisible(d->showViewModeBtn);
0738     d->storagePopupButton->setVisible(d->showStoragePopupBtn);
0739 
0740     d->viewModeButton->setVisible(d->showViewModeBtn);
0741     d->layout = Layout::Vertical;
0742 }
0743 
0744 void KisResourceItemChooser::changeLayoutBasedOnSize()
0745 {
0746     if (d->isResponsive == false) {
0747         return;
0748     }
0749     // Responsive Layout
0750     else {
0751         // Vertical
0752         if (height() > 100) {
0753             applyVerticalLayout();
0754         }
0755         // Horizontal 2 rows
0756         else if (height() > 60) {
0757 
0758             if (d->layout == Layout::Horizontal2Rows) {
0759                 return;
0760             }
0761 
0762             hideEverything();
0763 
0764             d->view->setListViewMode(ListViewMode::IconStripHorizontal);
0765             emit listViewModeChanged(ListViewMode::IconStripHorizontal);
0766 
0767             // Left
0768             QLayout* leftLayout = d->left->layout();
0769             leftLayout->addWidget(d->resourcesSplitter);
0770 
0771             // Right Top
0772             d->top->addWidget(d->scroll_left);
0773             d->top->addWidget(d->scroll_right);
0774             d->top->addWidget(d->tagManager->tagChooserWidget());
0775             d->top->addWidget(d->importExportBtns);
0776 
0777             // Right Bot
0778             d->bot->addWidget(d->viewModeButton);
0779             d->bot->addWidget(d->storagePopupButton);
0780             d->bot->addWidget(d->tagManager->tagFilterWidget());
0781 
0782             d->horzSplitter->addWidget(d->left);
0783             d->horzSplitter->addWidget(d->right2Rows);
0784 
0785             QGridLayout* thisLayout = dynamic_cast<QGridLayout*>(layout());
0786             thisLayout->addWidget(d->horzSplitter, 0, 0);
0787             thisLayout->setRowStretch(0, 2);
0788             thisLayout->setColumnStretch(0, 2);
0789             thisLayout->setRowStretch(1, 0);
0790 
0791             d->viewModeButton->setVisible(false);
0792             d->storagePopupButton->setVisible(d->showStoragePopupBtn);
0793 
0794             const bool splitterRestored = d->restoreSplitterState(Layout::Horizontal2Rows);
0795 
0796             d->horzSplitter->show();
0797             d->left->show();
0798             d->scroll_left->show();
0799             d->scroll_right->show();
0800             d->right2Rows->show();
0801 
0802             d->layout = Layout::Horizontal2Rows;
0803 
0804             if (!splitterRestored) {
0805                 slotSaveSplitterState();
0806             }
0807         }
0808         // Horizontal 1 row
0809         else {
0810             if (d->layout == Layout::Horizontal1Row) {
0811                 return;
0812             }
0813 
0814             hideEverything();
0815 
0816             d->view->setListViewMode(ListViewMode::IconStripHorizontal);
0817             emit listViewModeChanged(ListViewMode::IconStripHorizontal);
0818 
0819             QLayout* leftLayout = d->left->layout();
0820             leftLayout->addWidget(d->resourcesSplitter);
0821             leftLayout->addWidget(d->scroll_left);
0822             leftLayout->addWidget(d->scroll_right);
0823 
0824             QLayout* rightLayout = d->right->layout();
0825             rightLayout->addWidget(d->tagManager->tagChooserWidget());
0826             rightLayout->addWidget(d->viewModeButton);
0827             rightLayout->addWidget(d->storagePopupButton);
0828             rightLayout->addWidget(d->tagManager->tagFilterWidget());
0829             rightLayout->addWidget(d->importExportBtns);
0830 
0831             d->horzSplitter->addWidget(d->left);
0832             d->horzSplitter->addWidget(d->right);
0833 
0834             QGridLayout* thisLayout = dynamic_cast<QGridLayout*>(layout());
0835             thisLayout->addWidget(d->horzSplitter, 0, 0);
0836             thisLayout->setRowStretch(0, 2);
0837             thisLayout->setColumnStretch(0, 2);
0838             thisLayout->setRowStretch(1, 0);
0839 
0840             d->viewModeButton->setVisible(false);
0841             d->storagePopupButton->setVisible(d->showStoragePopupBtn);
0842 
0843             const bool splitterRestored = d->restoreSplitterState(Layout::Horizontal1Row);
0844 
0845             d->horzSplitter->show();
0846             d->left->show();
0847             d->scroll_left->show();
0848             d->scroll_right->show();
0849             d->right->show();
0850 
0851             d->layout = Layout::Horizontal1Row;
0852 
0853             if (!splitterRestored) {
0854                 slotSaveSplitterState();
0855             }
0856         }
0857     }
0858 }
0859 
0860 bool KisResourceItemChooser::Private::restoreSplitterState(Layout layout)
0861 {
0862     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(layout > Layout::Vertical, false);
0863 
0864     KConfigGroup group = KSharedConfig::openConfig()->group(QString("KisResourceItemChooser_%1").arg(resourceType));
0865 
0866     const QLatin1String key(
0867         layout == Layout::Horizontal1Row ? "splitterState_1row" : "splitterState_2row");
0868 
0869     bool splitterRestored = false;
0870     QByteArray state = group.readEntry(key, QByteArray());
0871     if (!state.isEmpty()) {
0872         splitterRestored = horzSplitter->restoreState(state);
0873         KIS_SAFE_ASSERT_RECOVER_NOOP(splitterRestored);
0874     }
0875 
0876     return splitterRestored;
0877 }
0878 
0879 void KisResourceItemChooser::slotSaveSplitterState()
0880 {
0881     if (d->layout > Layout::Vertical) {
0882         KConfigGroup group = KSharedConfig::openConfig()->group(QString("KisResourceItemChooser_%1").arg(d->resourceType));
0883         const QByteArray state = d->horzSplitter->saveState();
0884 
0885         const QLatin1String key(
0886             d->layout == Layout::Horizontal1Row ? "splitterState_1row" : "splitterState_2row");
0887 
0888         group.writeEntry(key, state);
0889     }
0890 }
0891 
0892 void KisResourceItemChooser::updateView()
0893 {
0894     /// helps to set icons here in case the theme is changed
0895     d->viewModeButton->setIcon(KisIconUtils::loadIcon("view-choose"));
0896     d->importButton->setIcon(koIcon("document-import-16"));
0897     d->deleteButton->setIcon(koIcon("edit-delete"));
0898     d->storagePopupButton->setIcon(koIcon("bundle_archive"));
0899     d->tagManager->tagChooserWidget()->updateIcons();
0900 }