File indexing completed on 2024-06-02 04:32:28

0001 /*
0002  * SPDX-FileCopyrightText: 2021 Mathias Wein <lynx.mw+kde@gmail.com>
0003  *  SPDX-FileCopyrightText: 2023 Srirupa Datta <srirupa.sps@gmail.com>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 
0008 #include "DlgResourceManager.h"
0009 
0010 #include "ui_WdgDlgResourceManager.h"
0011 
0012 #include <QItemSelection>
0013 #include <QPainter>
0014 
0015 #include <kis_action.h>
0016 #include <kis_action_manager.h>
0017 #include <KisResourceTypeModel.h>
0018 #include <KisStorageModel.h>
0019 #include <KisTagModel.h>
0020 #include <KisResourceModel.h>
0021 #include <KisTagFilterResourceProxyModel.h>
0022 #include <kis_assert.h>
0023 #include <KisResourceItemDelegate.h>
0024 #include <wdgtagselection.h>
0025 #include <kis_paintop_factory.h>
0026 #include <kis_paintop_registry.h>
0027 #include <dlg_create_bundle.h>
0028 #include <ResourceImporter.h>
0029 #include <KisResourceLocator.h>
0030 
0031 DlgResourceManager::DlgResourceManager(KisActionManager *actionMgr, QWidget *parent)
0032     : KoDialog(parent)
0033     , m_ui(new Ui::WdgDlgResourceManager)
0034     , m_actionManager(actionMgr)
0035     , m_tagsController(0)
0036 {
0037     setCaption(i18n("Manage Resources"));
0038     m_page = new QWidget(this);
0039     m_ui->setupUi(m_page);
0040     resize(m_page->size());
0041     setMainWidget(m_page);
0042     setButtons(Close);
0043     setDefaultButton(Close);
0044 
0045     m_wdgResourcePreview = new WdgResourcePreview(WidgetType::ResourceManager, this);
0046     m_ui->formLayout->addWidget(m_wdgResourcePreview);
0047 
0048     connect(m_wdgResourcePreview, SIGNAL(signalResourcesSelectionChanged(QModelIndex)), this, SLOT(slotResourcesSelectionChanged(QModelIndex)));
0049 
0050     connect(m_ui->btnDeleteResource, SIGNAL(clicked(bool)), SLOT(slotDeleteResources()));
0051     connect(m_ui->btnCreateBundle, SIGNAL(clicked(bool)), SLOT(slotCreateBundle()));
0052     connect(m_ui->btnOpenResourceFolder, SIGNAL(clicked(bool)), SLOT(slotOpenResourceFolder()));
0053     connect(m_ui->btnImportResources, SIGNAL(clicked(bool)), SLOT(slotImportResources()));
0054     connect(m_ui->btnExtractTagsToResourceFolder, SIGNAL(clicked(bool)), SLOT(slotSaveTags()));
0055 
0056 
0057     m_tagsController.reset(new KisWdgTagSelectionControllerOneResource(m_ui->wdgResourcesTags, true));
0058 
0059 #ifdef Q_OS_ANDROID
0060     // TODO(sh_zam): Opening a directory can cause a crash. A ContentProvider is needed for this.
0061     m_ui->btnOpenResourceFolder->setEnabled(false);
0062     m_ui->btnOpenResourceFolder->setVisible(false);
0063 #endif
0064 
0065     // make sure the panel is properly cleared. -Amy
0066     slotResourcesSelectionChanged({});
0067 }
0068 
0069 DlgResourceManager::~DlgResourceManager()
0070 {
0071 }
0072 
0073 void DlgResourceManager::slotResourcesSelectionChanged(QModelIndex index)
0074 {
0075     Q_UNUSED(index);
0076     QModelIndexList list = m_wdgResourcePreview->geResourceItemsSelected();
0077     KisTagFilterResourceProxyModel* model = m_wdgResourcePreview->getResourceProxyModelsForResourceType()[m_wdgResourcePreview->getCurrentResourceType()];
0078     if (list.size() == 1) {
0079         const QModelIndex idx = list[0];
0080         m_ui->lblFilename->setText(model->data(idx, Qt::UserRole + KisAllResourcesModel::Filename).toString());
0081         m_ui->lneName->setText(model->data(idx, Qt::UserRole + KisAllResourcesModel::Name).toString());
0082         m_ui->lblLocation->setText(model->data(idx, Qt::UserRole + KisAllResourcesModel::Location).toString());
0083         m_ui->lblId->setText(model->data(idx, Qt::UserRole + KisAllResourcesModel::Id).toString());
0084 
0085         const QSize thumbSize = m_ui->lblThumbnail->size();
0086 
0087         QImage thumbLabel = m_thumbnailPainter.getReadyThumbnail(idx, thumbSize*devicePixelRatioF(), palette());
0088         thumbLabel.setDevicePixelRatio(devicePixelRatioF());
0089 
0090         const QPixmap pix = QPixmap::fromImage(thumbLabel);
0091         m_ui->lblThumbnail->setScaledContents(true);
0092         m_ui->lblThumbnail->setPixmap(pix);
0093 
0094         const QMap<QString, QVariant> metadata =
0095             model->data(idx, Qt::UserRole + KisAllResourcesModel::MetaData).toMap();
0096 
0097         m_ui->lblMetadata->setDisabled(false);
0098         m_ui->lblFilename->setDisabled(false);
0099         m_ui->lblLocation->setDisabled(false);
0100         m_ui->lblThumbnail->setDisabled(false);
0101         m_ui->lneName->setDisabled(false);
0102         m_ui->lblId->setDisabled(false);
0103         m_ui->lblMetadata->setText(constructMetadata(metadata, m_wdgResourcePreview->getCurrentResourceType()));
0104     } else if (list.size() > 1) {
0105 
0106         QString commonLocation = model->data(list.first(), Qt::UserRole + KisAllResourcesModel::Location).toString();
0107         bool commonLocationFound = true;
0108         Q_FOREACH(QModelIndex idx, list) {
0109             QString location = model->data(idx, Qt::UserRole + KisAllResourcesModel::Location).toString();
0110             if (location != commonLocation) {
0111                 commonLocationFound = false;
0112             }
0113         }
0114 
0115         QString multipleSelectedText = i18nc("In Resource manager, this is text shown instead of filename, name or location, "
0116                                              "when multiple resources are shown so there is no one specific filename", "(Multiple selected)");
0117 
0118         m_ui->lblId->setText(multipleSelectedText);
0119         m_ui->lblMetadata->setText("");
0120         m_ui->lblFilename->setText(multipleSelectedText);
0121         m_ui->lblLocation->setText(commonLocationFound ? commonLocation : multipleSelectedText);
0122         m_ui->lneName->setText(multipleSelectedText);
0123         m_ui->lblThumbnail->setText(multipleSelectedText);
0124         QPixmap pix;
0125         m_ui->lblThumbnail->setPixmap(pix);
0126 
0127         m_ui->lblMetadata->setDisabled(true);
0128         m_ui->lblFilename->setDisabled(true);
0129         m_ui->lblLocation->setDisabled(!commonLocationFound);
0130         m_ui->lblThumbnail->setDisabled(true);
0131         m_ui->lneName->setDisabled(true);
0132         m_ui->lblId->setDisabled(true);
0133     } else {
0134         QString noneSelectedText = i18nc("In Resource manager, this is text shown instead of filename, name or location, "
0135                                              "when no resource is shown so there is no specific filename", "(None selected)");
0136 
0137         m_ui->lblId->setText(noneSelectedText);
0138         m_ui->lblMetadata->setText(noneSelectedText);
0139         m_ui->lblFilename->setText(noneSelectedText);
0140         m_ui->lblLocation->setText(noneSelectedText);
0141         m_ui->lneName->setText(noneSelectedText);
0142         m_ui->lblThumbnail->setText(noneSelectedText);
0143         m_ui->lblThumbnail->setPixmap({});
0144 
0145         m_ui->lblMetadata->setDisabled(true);
0146         m_ui->lblFilename->setDisabled(true);
0147         m_ui->lblLocation->setDisabled(true);
0148         m_ui->lblThumbnail->setDisabled(true);
0149         m_ui->lneName->setDisabled(true);
0150         m_ui->lblId->setDisabled(true);
0151     }
0152 
0153     QList<int> resourceIds;
0154     Q_FOREACH(QModelIndex idx, list) {
0155         int resourceId = model->data(idx, Qt::UserRole + KisAllResourcesModel::Id).toInt();
0156         resourceIds << resourceId;
0157     }
0158     updateDeleteButtonState(list);
0159     m_tagsController->setResourceIds(m_wdgResourcePreview->getCurrentResourceType(), resourceIds);
0160 }
0161 
0162 void DlgResourceManager::slotDeleteResources()
0163 {
0164     QModelIndexList list = m_wdgResourcePreview->geResourceItemsSelected();
0165     QMap<QString, KisTagFilterResourceProxyModel*> resourceProxyModelsForResourceType = m_wdgResourcePreview->getResourceProxyModelsForResourceType();
0166 
0167     if (!resourceProxyModelsForResourceType.contains(m_wdgResourcePreview->getCurrentResourceType()) || list.empty()) {
0168         return;
0169     }
0170     KisTagFilterResourceProxyModel *model = resourceProxyModelsForResourceType[m_wdgResourcePreview->getCurrentResourceType()];
0171     KisAllResourcesModel *allModel = KisResourceModelProvider::resourceModel(m_wdgResourcePreview->getCurrentResourceType());
0172 
0173     if (static_cast<QAbstractItemModel*>(model) != m_wdgResourcePreview->getModel()) {
0174         qCritical() << "wrong item model!";
0175         return;
0176     }
0177 
0178     // deleting a resource with "Show deleted resources" disabled will update the proxy model
0179     // and next index in selection now points at wrong item.
0180     QList<int> resourceIds;
0181     Q_FOREACH (QModelIndex index, list) {
0182         int resourceId = model->data(index, Qt::UserRole + KisResourceModel::Id).toInt();
0183         resourceIds.append(resourceId);
0184     }
0185 
0186     Q_FOREACH (int resourceId, resourceIds) {
0187 
0188         QModelIndex index = allModel->indexForResourceId(resourceId);
0189         allModel->setResourceActive(index, m_undeleteMode);
0190     }
0191 
0192     updateDeleteButtonState(list);
0193 }
0194 
0195 void DlgResourceManager::slotImportResources()
0196 {
0197     ResourceImporter importer(this);
0198     importer.importResources();
0199 
0200 }
0201 
0202 void DlgResourceManager::slotOpenResourceFolder()
0203 {
0204     if (m_actionManager) {
0205         KisAction *action = m_actionManager->actionByName("open_resources_directory");
0206         action->trigger();
0207     }
0208 }
0209 
0210 void DlgResourceManager::slotCreateBundle()
0211 {
0212     DlgCreateBundle* dlg = new DlgCreateBundle(0, this);
0213     dlg->exec();
0214 }
0215 
0216 
0217 void DlgResourceManager::slotSaveTags()
0218 {
0219     KisResourceLocator::instance()->saveTags();
0220 }
0221 
0222 void DlgResourceManager::updateDeleteButtonState(const QModelIndexList &list)
0223 {
0224     bool allActive = true;
0225     bool allInactive = true;
0226 
0227     for(QModelIndex index: list) {
0228         bool active = index.data(Qt::UserRole + KisAllResourcesModel::ResourceActive).toBool();
0229         allActive = allActive && active;
0230         allInactive = allInactive && !active;
0231     }
0232 
0233     // if nothing selected or selected are mixed active/inactive state
0234     if (allActive == allInactive) {
0235         m_ui->btnDeleteResource->setEnabled(false);
0236     }
0237     // either all are active or all are inactive
0238     else {
0239         m_undeleteMode = allInactive;
0240         m_ui->btnDeleteResource->setEnabled(true);
0241         if (m_undeleteMode) {
0242             m_ui->btnDeleteResource->setText(i18n("Undelete Resources"));
0243         } else {
0244             m_ui->btnDeleteResource->setText(i18n("Delete Resources"));
0245         }
0246     }
0247 }
0248 
0249 QString DlgResourceManager::constructMetadata(const QMap<QString, QVariant> &metadata, const QString &resourceType)
0250 {
0251     QString response;
0252     if (resourceType == ResourceType::PaintOpPresets) {
0253         QString paintopKey = "paintopid";
0254         QString paintopId = metadata.contains(paintopKey) ? metadata[paintopKey].toString() : "";
0255         if (!paintopId.isEmpty()) {
0256 
0257             KisPaintOpFactory* factory = KisPaintOpRegistry::instance()->get(paintopId);
0258             if (factory) {
0259                 QString name = factory->name();
0260                 response.append(name);
0261             } else {
0262                 response.append(i18nc("Brush engine type, in resource manager", "Engine: "));
0263                 response.append(paintopId);
0264             }
0265         }
0266 
0267 
0268     } else if (resourceType == ResourceType::GamutMasks) {
0269         QString descriptionKey = "description";
0270         QString description = metadata.contains(descriptionKey) ? metadata[descriptionKey].toString() : "";
0271         response.append(description);
0272     } else {
0273         Q_FOREACH(QString key, metadata.keys()) {
0274             response.append(key).append(": ").append(metadata[key].toString()).append("\n");
0275         }
0276     }
0277     return response;
0278 
0279 }