File indexing completed on 2024-12-22 04:14:54
0001 /* 0002 * SPDX-FileCopyrightText: 2013 Sven Langkamp <sven.langkamp@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 0008 #include "palettedocker_dock.h" 0009 0010 #include <QPainter> 0011 #include <QGridLayout> 0012 #include <QTableView> 0013 #include <QHeaderView> 0014 #include <QWheelEvent> 0015 #include <QCompleter> 0016 #include <QComboBox> 0017 #include <QAction> 0018 #include <QMenu> 0019 #include <QCheckBox> 0020 #include <QFormLayout> 0021 #include <QLineEdit> 0022 #include <QString> 0023 0024 #include <kundo2stack.h> 0025 #include <KisSqueezedComboBox.h> 0026 #include <klocalizedstring.h> 0027 #include <KoResourceServerProvider.h> 0028 #include <KisResourceLocator.h> 0029 #include <KoColorSpaceRegistry.h> 0030 #include <KoFileDialog.h> 0031 #include <kis_floating_message.h> 0032 #include <kis_icon.h> 0033 #include <kis_config.h> 0034 #include <kis_node_manager.h> 0035 #include <kis_canvas_resource_provider.h> 0036 #include <KisMainWindow.h> 0037 #include <KisViewManager.h> 0038 #include <kis_display_color_converter.h> 0039 #include <kis_canvas2.h> 0040 #include <KoDialog.h> 0041 #include <kis_color_button.h> 0042 #include <KisDocument.h> 0043 #include <KisPart.h> 0044 #include <KisPaletteEditor.h> 0045 0046 #include <KisStorageModel.h> 0047 0048 #include <KisPaletteModel.h> 0049 #include <KisPaletteDelegate.h> 0050 #include <kis_palette_view.h> 0051 #include <KisPaletteChooser.h> 0052 0053 #include <KisPaletteEditor.h> 0054 #include <dialogs/KisDlgPaletteEditor.h> 0055 0056 #include "ui_wdgpalettedock.h" 0057 0058 PaletteDockerDock::PaletteDockerDock( ) 0059 : QDockWidget(i18n("Palette")) 0060 , m_ui(new Ui_WdgPaletteDock()) 0061 , m_model(new KisPaletteModel(this)) 0062 , m_paletteChooser(new KisPaletteChooser(this)) 0063 , m_view(0) 0064 , m_resourceProvider(0) 0065 , m_rServer(KoResourceServerProvider::instance()->paletteServer()) 0066 , m_activeDocument(0) 0067 , m_paletteEditor(new KisPaletteEditor) 0068 , m_actAdd(new QAction(KisIconUtils::loadIcon("list-add"), i18n("Add a new color swatch"))) 0069 , m_actRemove(new QAction(KisIconUtils::loadIcon("edit-delete"), i18n("Remove swatch or group"))) 0070 , m_actModify(new QAction(KisIconUtils::loadIcon("document-edit"), i18n("Edit swatch or group"))) 0071 , m_actEditPalette(new QAction(KisIconUtils::loadIcon("palette-edit"), i18n("Edit current palette"))) 0072 , m_actSavePalette(new QAction(KisIconUtils::loadIcon("document-save-16"), i18n("Save current palette"))) 0073 , m_colorSelfUpdate(false) 0074 { 0075 QWidget *mainWidget = new QWidget(this); 0076 setWidget(mainWidget); 0077 m_ui->setupUi(mainWidget); 0078 0079 connect(KisResourceLocator::instance(), SIGNAL(storageRemoved(QString)), this, SLOT(slotStoragesChanged(QString))); 0080 0081 m_ui->bnAdd->setDefaultAction(m_actAdd.data()); 0082 m_ui->bnRemove->setDefaultAction(m_actRemove.data()); 0083 m_ui->bnRename->setDefaultAction(m_actModify.data()); 0084 m_ui->bnEditPalette->setDefaultAction(m_actEditPalette.data()); 0085 m_ui->bnSavePalette->setDefaultAction(m_actSavePalette.data()); 0086 0087 // to make sure their icons have the same size 0088 m_ui->bnRemove->setIconSize(QSize(16, 16)); 0089 m_ui->bnRename->setIconSize(QSize(16, 16)); 0090 m_ui->bnAdd->setIconSize(QSize(16, 16)); 0091 m_ui->bnEditPalette->setIconSize(QSize(16, 16)); 0092 m_ui->bnSavePalette->setIconSize(QSize(16, 16)); 0093 0094 0095 m_ui->paletteView->setPaletteModel(m_model); 0096 m_ui->paletteView->setAllowModification(true); 0097 m_ui->cmbNameList->setCompanionView(m_ui->paletteView); 0098 0099 m_paletteEditor->setPaletteModel(m_model); 0100 0101 connect(m_actAdd.data(), SIGNAL(triggered()), SLOT(slotAddColor())); 0102 connect(m_actRemove.data(), SIGNAL(triggered()), SLOT(slotRemoveColor())); 0103 connect(m_actModify.data(), SIGNAL(triggered()), SLOT(slotEditEntry())); 0104 connect(m_actEditPalette.data(), SIGNAL(triggered()), SLOT(slotEditPalette())); 0105 connect(m_actSavePalette.data(), SIGNAL(triggered()), SLOT(slotSavePalette())); 0106 connect(m_ui->paletteView, SIGNAL(sigIndexSelected(QModelIndex)), SLOT(slotPaletteIndexSelected(QModelIndex))); 0107 connect(m_ui->paletteView, SIGNAL(clicked(QModelIndex)), SLOT(slotPaletteIndexClicked(QModelIndex))); 0108 connect(m_ui->paletteView, SIGNAL(doubleClicked(QModelIndex)), 0109 SLOT(slotPaletteIndexDoubleClicked(QModelIndex))); 0110 connect(m_ui->paletteView, SIGNAL(sigPaletteUpdatedFromModel()), SLOT(slotUpdateLblPaletteName())); 0111 connect(m_ui->cmbNameList, SIGNAL(sigColorSelected(const KoColor&)), SLOT(slotNameListSelection(const KoColor&))); 0112 connect(m_ui->bnLock, SIGNAL(toggled(bool)), SLOT(slotLockPalette(bool))); 0113 0114 m_viewContextMenu.addAction(m_actModify.data()); 0115 m_viewContextMenu.addAction(m_actRemove.data()); 0116 connect(m_ui->paletteView, SIGNAL(pressed(QModelIndex)), SLOT(slotContextMenu(QModelIndex))); 0117 0118 connect(m_paletteChooser, SIGNAL(sigPaletteSelected(KoColorSetSP)), SLOT(slotSetColorSet(KoColorSetSP))); 0119 connect(m_paletteChooser, SIGNAL(sigAddPalette()), SLOT(slotAddPalette())); 0120 connect(m_paletteChooser, SIGNAL(sigImportPalette()), SLOT(slotImportPalette())); 0121 connect(m_paletteChooser, SIGNAL(sigRemovePalette(KoColorSetSP)), SLOT(slotRemovePalette(KoColorSetSP))); 0122 connect(m_paletteChooser, SIGNAL(sigExportPalette(KoColorSetSP)), SLOT(slotExportPalette(KoColorSetSP))); 0123 0124 m_ui->bnColorSets->setIcon(KisIconUtils::loadIcon("palette-library")); 0125 m_ui->bnColorSets->setToolTip(i18n("Load a palette")); 0126 m_ui->bnColorSets->setPopupWidget(m_paletteChooser); 0127 0128 KisConfig cfg(true); 0129 QString defaultPaletteName = cfg.defaultPalette(); 0130 KoColorSetSP defaultPalette = m_rServer->resource("", "", defaultPaletteName); 0131 if (defaultPalette) { 0132 slotSetColorSet(defaultPalette); 0133 m_paletteChooser->setCurrentItem(defaultPalette); 0134 } else { 0135 m_ui->bnAdd->setEnabled(false); 0136 m_ui->bnUndo->setEnabled(false); 0137 m_ui->bnRedo->setEnabled(false); 0138 m_ui->bnRename->setEnabled(false); 0139 m_ui->bnRemove->setEnabled(false); 0140 m_ui->bnEditPalette->setEnabled(false); 0141 m_ui->bnSavePalette->setEnabled(false); 0142 m_ui->bnLock->setEnabled(false); 0143 0144 m_ui->paletteView->setAllowModification(false); 0145 } 0146 0147 m_ui->bnUndo->setVisible(false); 0148 m_ui->bnRedo->setVisible(false); 0149 0150 0151 KoResourceServer<KoColorSet> *srv = KoResourceServerProvider::instance()->paletteServer(); 0152 srv->addObserver(this); 0153 } 0154 0155 PaletteDockerDock::~PaletteDockerDock() 0156 { 0157 if (m_paletteEditor->isModified()) { 0158 m_paletteEditor->saveNewPaletteVersion(); 0159 } 0160 KoResourceServer<KoColorSet> *srv = KoResourceServerProvider::instance()->paletteServer(); 0161 srv->removeObserver(this); 0162 } 0163 0164 void PaletteDockerDock::setViewManager(KisViewManager* kisview) 0165 { 0166 m_view = kisview; 0167 m_resourceProvider = kisview->canvasResourceProvider(); 0168 connect(m_resourceProvider, SIGNAL(sigFGColorChanged(KoColor)), 0169 this, SLOT(slotFGColorResourceChanged(KoColor))); 0170 kisview->nodeManager()->disconnect(m_model); 0171 } 0172 0173 void PaletteDockerDock::unsetResourceServer() 0174 { 0175 KoResourceServer<KoColorSet> *srv = KoResourceServerProvider::instance()->paletteServer(); 0176 srv->removeObserver(this); 0177 } 0178 0179 void PaletteDockerDock::resourceAdded(QSharedPointer<KoColorSet> resource) 0180 { 0181 Q_UNUSED(resource); 0182 } 0183 0184 void PaletteDockerDock::removingResource(QSharedPointer<KoColorSet> resource) 0185 { 0186 Q_UNUSED(resource); 0187 } 0188 0189 void PaletteDockerDock::resourceChanged(QSharedPointer<KoColorSet> resource) 0190 { 0191 m_model->slotExternalPaletteModified(resource); 0192 } 0193 0194 void PaletteDockerDock::slotContextMenu(const QModelIndex &) 0195 { 0196 if (QApplication::mouseButtons() == Qt::RightButton) { 0197 m_viewContextMenu.exec(QCursor::pos()); 0198 } 0199 } 0200 0201 void PaletteDockerDock::slotAddPalette() 0202 { 0203 KoColorSetSP palette = m_paletteEditor->addPalette(); 0204 0205 if (palette) { 0206 m_paletteChooser->setCurrentItem(palette); 0207 } 0208 } 0209 0210 void PaletteDockerDock::slotRemovePalette(KoColorSetSP cs) 0211 { 0212 m_paletteEditor->removePalette(cs); 0213 } 0214 0215 void PaletteDockerDock::slotImportPalette() 0216 { 0217 KoColorSetSP palette = m_paletteEditor->importPalette(); 0218 if (palette) { 0219 m_paletteChooser->setCurrentItem(palette); 0220 } 0221 } 0222 0223 void PaletteDockerDock::slotExportPalette(KoColorSetSP palette) 0224 { 0225 KoFileDialog dialog(this, KoFileDialog::SaveFile, "Save Palette"); 0226 dialog.setCaption(i18n("Export Palette")); 0227 dialog.setDefaultDir(palette->filename()); 0228 dialog.setMimeTypeFilters(QStringList() << "application/x-krita-palette"); 0229 QString newPath; 0230 if ((newPath = dialog.filename()).isEmpty()) { return; } 0231 0232 QFile file(newPath); 0233 if (!file.open(QIODevice::WriteOnly)) { 0234 warnKrita << "Could not open the file for writing:" << newPath; 0235 return; 0236 } 0237 if (palette->saveToDevice(&file)) { 0238 m_view->showFloatingMessage( 0239 i18nc("Floating message about exporting successful", "Palette exported successfully"), QIcon(), 0240 500, KisFloatingMessage::Low); 0241 } else { 0242 warnKrita << "Could export to the file:" << newPath; 0243 } 0244 } 0245 0246 void PaletteDockerDock::setCanvas(KoCanvasBase *canvas) 0247 { 0248 setEnabled(canvas != 0); 0249 if (canvas) { 0250 KisCanvas2 *cv = qobject_cast<KisCanvas2*>(canvas); 0251 m_ui->paletteView->setDisplayRenderer(cv->displayColorConverter()->displayRendererInterface()); 0252 } 0253 0254 if (m_view && m_view->document()) { 0255 m_activeDocument = m_view->document(); 0256 m_paletteEditor->setView(m_view); 0257 } 0258 0259 if (!m_currentColorSet) { 0260 slotSetColorSet(0); 0261 } 0262 } 0263 0264 void PaletteDockerDock::unsetCanvas() 0265 { 0266 setEnabled(false); 0267 m_ui->paletteView->setDisplayRenderer(0); 0268 m_paletteEditor->setView(0); 0269 0270 if (!m_currentColorSet) { 0271 slotSetColorSet(0); 0272 } 0273 } 0274 0275 void PaletteDockerDock::slotSetColorSet(KoColorSetSP colorSet) 0276 { 0277 if (m_currentColorSet == colorSet) { 0278 slotUpdateLblPaletteName(); 0279 m_paletteEditor->updatePalette(); 0280 return; 0281 } 0282 0283 if (m_currentColorSet) { 0284 disconnect(m_currentColorSet->undoStack()); 0285 } 0286 0287 // needs to save the palette before switching to another one 0288 if (m_paletteEditor->isModified() && m_currentColorSet != colorSet) { 0289 m_paletteEditor->saveNewPaletteVersion(); 0290 } 0291 else if (colorSet) { 0292 0293 m_model->setColorSet(colorSet); 0294 0295 m_ui->bnUndo->setEnabled(colorSet->undoStack()->canUndo() && !colorSet->isLocked()); 0296 connect(colorSet->undoStack(), SIGNAL(canUndoChanged(bool)), m_ui->bnUndo, SLOT(setEnabled(bool))); 0297 connect(colorSet->undoStack(), SIGNAL(undoTextChanged(QString)), this, SLOT(setUndoToolTip(QString))); 0298 0299 m_ui->bnRedo->setEnabled(colorSet->undoStack()->canRedo() && colorSet->isLocked()); 0300 connect(colorSet->undoStack(), SIGNAL(canRedoChanged(bool)), m_ui->bnRedo, SLOT(setEnabled(bool))); 0301 connect(colorSet->undoStack(), SIGNAL(redoTextChanged(QString)), this, SLOT(setRedoToolTip(QString))); 0302 0303 connect(m_ui->bnUndo, SIGNAL(clicked()), this, SLOT(undo())); 0304 connect(m_ui->bnRedo, SIGNAL(clicked()), this, SLOT(redo())); 0305 0306 m_ui->bnLock->setChecked(colorSet->isLocked()); 0307 } 0308 bool state = (bool)colorSet; 0309 if (state != (bool)m_currentColorSet) { 0310 m_ui->bnAdd->setEnabled(state); 0311 m_ui->bnRename->setEnabled(state); 0312 m_ui->bnRemove->setEnabled(state); 0313 m_ui->bnEditPalette->setEnabled(state); 0314 m_ui->bnSavePalette->setEnabled(state); 0315 m_ui->paletteView->setAllowModification(state); 0316 m_ui->bnLock->setEnabled(state); 0317 } 0318 0319 m_currentColorSet = colorSet; 0320 0321 if (colorSet) { 0322 KisConfig cfg(true); 0323 cfg.setDefaultPalette(colorSet->name()); 0324 m_ui->lblPaletteName->setTextElideMode(Qt::ElideMiddle); 0325 m_ui->lblPaletteName->setText(colorSet->name()); 0326 } 0327 else { 0328 m_ui->lblPaletteName->setText(""); 0329 } 0330 slotUpdateLblPaletteName(); 0331 } 0332 0333 void PaletteDockerDock::slotEditPalette() 0334 { 0335 KisDlgPaletteEditor dlg; 0336 if (!m_currentColorSet) { return; } 0337 dlg.setPaletteModel(m_model); 0338 dlg.setView(m_view); 0339 if (dlg.exec() != QDialog::Accepted){ return; } 0340 0341 slotSetColorSet(m_currentColorSet); // update GUI 0342 } 0343 0344 void PaletteDockerDock::slotSavePalette() 0345 { 0346 if (m_paletteEditor->isModified()) { 0347 m_paletteEditor->saveNewPaletteVersion(); 0348 slotUpdateLblPaletteName(); 0349 } 0350 } 0351 0352 0353 void PaletteDockerDock::slotAddColor() 0354 { 0355 if (m_resourceProvider) { 0356 m_paletteEditor->addEntry(m_resourceProvider->fgColor()); 0357 } 0358 slotUpdateLblPaletteName(); 0359 } 0360 0361 void PaletteDockerDock::slotRemoveColor() 0362 { 0363 QModelIndex index = m_ui->paletteView->currentIndex(); 0364 if (!index.isValid()) { 0365 return; 0366 } 0367 m_paletteEditor->removeEntry(index); 0368 m_ui->bnRemove->setEnabled(false); 0369 slotUpdateLblPaletteName(); 0370 } 0371 0372 void PaletteDockerDock::setFGColorByPalette(const KisSwatch &entry) 0373 { 0374 if (m_resourceProvider) { 0375 m_colorSelfUpdate = true; 0376 m_resourceProvider->setFGColor(entry.color()); 0377 m_colorSelfUpdate = false; 0378 } 0379 } 0380 0381 void PaletteDockerDock::slotUpdateLblPaletteName() 0382 { 0383 if (m_currentColorSet) { 0384 m_ui->lblPaletteName->setTextElideMode(Qt::ElideLeft); 0385 QString name = m_currentColorSet->name(); 0386 0387 bool isGlobal = true; 0388 KisResourceModel model(ResourceType::Palettes); 0389 QModelIndex index = model.indexForResource(m_currentColorSet); 0390 if (index.isValid()) { 0391 bool ok; 0392 int storageId = model.data(index, Qt::UserRole + KisAllResourcesModel::StorageId).toInt(&ok); 0393 if (ok) { 0394 KisStorageModel storageModel; 0395 KisResourceStorageSP storage = storageModel.storageForId(storageId); 0396 isGlobal = storage->type() != KisResourceStorage::StorageType::Memory; 0397 } 0398 } 0399 m_actSavePalette.data()->setEnabled(isGlobal); 0400 if (isGlobal) { 0401 m_actSavePalette.data()->setToolTip(i18nc("@tooltip", "Save palette explicitly, will also happen automatically on exiting Krita.")); 0402 } 0403 else { 0404 m_actSavePalette.data()->setToolTip(i18nc("@tooltip", "Saving for document palettes is done by saving the document.")); 0405 } 0406 // if the palette is not global, then let's not indicate that the changes has been made 0407 // (it's easier than tracking whether the document has been saved or maybe exported etc.) 0408 if (m_paletteEditor->isModified() && isGlobal) { 0409 name = "* " + name; 0410 QFont font = m_ui->lblPaletteName->font(); 0411 font.setItalic(true); 0412 m_ui->lblPaletteName->setFont(font); 0413 } 0414 else { 0415 QFont font = m_ui->lblPaletteName->font(); 0416 font.setItalic(false); 0417 m_ui->lblPaletteName->setFont(font); 0418 } 0419 0420 m_ui->lblPaletteName->setText(name); 0421 } 0422 else { 0423 m_ui->lblPaletteName->setText(""); 0424 } 0425 } 0426 0427 void PaletteDockerDock::slotLockPalette(bool locked) 0428 { 0429 m_currentColorSet->setLocked(locked); 0430 QIcon icon = locked ? KisIconUtils::loadIcon(koIconName("object-locked")) 0431 : KisIconUtils::loadIcon(koIconName("object-unlocked")); 0432 m_ui->bnLock->setIcon(icon); 0433 m_ui->bnAdd->setEnabled(!locked); 0434 m_ui->bnRename->setEnabled(!locked); 0435 m_ui->bnRemove->setEnabled(!locked); 0436 m_ui->bnEditPalette->setEnabled(!locked); 0437 m_ui->bnSavePalette->setEnabled(!locked); 0438 m_ui->paletteView->setAllowModification(!locked); 0439 } 0440 0441 void PaletteDockerDock::setUndoToolTip(const QString &text) 0442 { 0443 m_ui->bnUndo->setToolTip(text); 0444 } 0445 0446 void PaletteDockerDock::setRedoToolTip(const QString &text) 0447 { 0448 m_ui->bnRedo->setToolTip(text); 0449 } 0450 0451 void PaletteDockerDock::undo() 0452 { 0453 m_currentColorSet->undoStack()->undo(); 0454 m_model->slotExternalPaletteModified(m_currentColorSet); 0455 m_paletteEditor->updatePalette(); 0456 slotUpdateLblPaletteName(); 0457 } 0458 0459 void PaletteDockerDock::redo() 0460 { 0461 m_currentColorSet->undoStack()->redo(); 0462 m_model->slotExternalPaletteModified(m_currentColorSet); 0463 m_paletteEditor->updatePalette(); 0464 slotUpdateLblPaletteName(); 0465 0466 } 0467 0468 0469 void PaletteDockerDock::slotFGColorResourceChanged(const KoColor &color) 0470 { 0471 if (!m_colorSelfUpdate) { 0472 m_ui->paletteView->slotFGColorChanged(color); 0473 } 0474 } 0475 0476 void PaletteDockerDock::slotStoragesChanged(const QString &/*location*/) 0477 { 0478 if (m_activeDocument.isNull()) { 0479 slotSetColorSet(0); 0480 } 0481 if (m_currentColorSet) { 0482 if (!m_rServer->resource(m_currentColorSet->md5Sum(), "", "")) { 0483 slotSetColorSet(0); 0484 } 0485 } 0486 } 0487 0488 void PaletteDockerDock::slotPaletteIndexSelected(const QModelIndex &index) 0489 { 0490 bool occupied = qvariant_cast<bool>(index.data(KisPaletteModel::CheckSlotRole)); 0491 if (occupied) { 0492 if (!qvariant_cast<bool>(index.data(KisPaletteModel::IsGroupNameRole))) { 0493 m_ui->bnRemove->setEnabled(true); 0494 KisSwatch entry = m_model->getSwatch(index); 0495 setFGColorByPalette(entry); 0496 } 0497 } 0498 m_ui->bnRemove->setEnabled(occupied); 0499 slotUpdateLblPaletteName(); 0500 } 0501 0502 void PaletteDockerDock::slotPaletteIndexClicked(const QModelIndex &index) 0503 { 0504 if (!(qvariant_cast<bool>(index.data(KisPaletteModel::CheckSlotRole)))) { 0505 setEntryByForeground(index); 0506 } 0507 slotUpdateLblPaletteName(); 0508 } 0509 0510 void PaletteDockerDock::slotPaletteIndexDoubleClicked(const QModelIndex &index) 0511 { 0512 m_paletteEditor->modifyEntry(index); 0513 slotUpdateLblPaletteName(); 0514 } 0515 0516 void PaletteDockerDock::setEntryByForeground(const QModelIndex &index) 0517 { 0518 m_paletteEditor->setEntry(m_resourceProvider->fgColor(), index); 0519 m_ui->bnRemove->setEnabled(true); 0520 slotUpdateLblPaletteName(); 0521 } 0522 0523 void PaletteDockerDock::slotEditEntry() 0524 { 0525 QModelIndex index = m_ui->paletteView->currentIndex(); 0526 if (!index.isValid()) { 0527 return; 0528 } 0529 m_paletteEditor->modifyEntry(index); 0530 slotUpdateLblPaletteName(); 0531 } 0532 0533 void PaletteDockerDock::slotNameListSelection(const KoColor &color) 0534 { 0535 m_colorSelfUpdate = true; 0536 m_ui->paletteView->selectClosestColor(color); 0537 m_resourceProvider->setFGColor(color); 0538 m_colorSelfUpdate = false; 0539 }