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 }