File indexing completed on 2024-05-19 04:29:17
0001 /* 0002 * SPDX-FileCopyrightText: 2018 Michael Zhou <simeirxh@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include <QHash> 0008 #include <QString> 0009 #include <QScopedPointer> 0010 #include <QPointer> 0011 #include <QFormLayout> 0012 #include <QCheckBox> 0013 #include <QLineEdit> 0014 #include <QLabel> 0015 #include <QSpinBox> 0016 #include <QComboBox> 0017 #include <QMessageBox> 0018 0019 #include <KoDialog.h> 0020 #include <KoFileDialog.h> 0021 #include <KoColorSet.h> 0022 #include <KisSwatchGroup.h> 0023 #include <kis_signal_compressor.h> 0024 #include <KisViewManager.h> 0025 #include <KisDocument.h> 0026 #include <KoResourceServer.h> 0027 #include <KisStorageModel.h> 0028 #include <KoResourceServerProvider.h> 0029 #include <KisPaletteModel.h> 0030 #include <kis_color_button.h> 0031 0032 #include "KisPaletteEditor.h" 0033 #include <KisGlobalResourcesInterface.h> 0034 #include <KisResourceUserOperations.h> 0035 0036 struct KisPaletteEditor::PaletteInfo { 0037 QString name; 0038 QString filename; 0039 int columnCount; 0040 QString storageLocation; 0041 QHash<QString, KisSwatchGroupSP> groups; 0042 }; 0043 0044 struct KisPaletteEditor::Private 0045 { 0046 bool isNameModified {false}; 0047 bool isColumnCountModified {false}; 0048 QSet<QString> modifiedGroupNames; // key is original group name 0049 QSet<QString> newGroupNames; 0050 QSet<QString> keepColorGroups; 0051 QSet<QString> pathsToRemove; 0052 QString groupBeingRenamed; 0053 QPointer<KisPaletteModel> model; 0054 QPointer<KisViewManager> view; 0055 KisPaletteEditor::PaletteInfo modifiedPaletteInfo; 0056 QPointer<KoDialog> query; 0057 KoResourceServer<KoColorSet> *rServer {0}; 0058 0059 QPalette normalPalette; 0060 QPalette warnPalette; 0061 0062 }; 0063 0064 KisPaletteEditor::KisPaletteEditor(QObject *parent) 0065 : QObject(parent) 0066 , m_d(new Private) 0067 { 0068 m_d->rServer = KoResourceServerProvider::instance()->paletteServer(); 0069 m_d->warnPalette.setColor(QPalette::Text, Qt::red); 0070 } 0071 0072 KisPaletteEditor::~KisPaletteEditor() 0073 { } 0074 0075 void KisPaletteEditor::setPaletteModel(KisPaletteModel *model) 0076 { 0077 if (!model) { return; } 0078 m_d->model = model; 0079 slotPaletteChanged(); 0080 connect(model, SIGNAL(sigPaletteChanged()), SLOT(slotPaletteChanged())); 0081 connect(model, SIGNAL(sigPaletteModified()), SLOT(slotSetDocumentModified())); 0082 } 0083 0084 void KisPaletteEditor::setView(KisViewManager *view) 0085 { 0086 m_d->view = view; 0087 } 0088 0089 KoColorSetSP KisPaletteEditor::addPalette() 0090 { 0091 if (!m_d->view) { return 0; } 0092 if (!m_d->view->document()) { return 0; } 0093 0094 KoColorSetSP colorSet(new KoColorSet()); 0095 0096 KoDialog dialog; 0097 QFormLayout *layout = new QFormLayout(dialog.mainWidget()); 0098 QLineEdit *le = new QLineEdit(i18nc("Default name for a new palette","New Palette")); 0099 layout->addRow(i18n("New palette name:"), le); 0100 0101 QComboBox *cmbPaletteType = new QComboBox(); 0102 cmbPaletteType->addItem(i18nc("Palette File Type", "Krita Palette (KPL)")); 0103 cmbPaletteType->addItem(i18nc("Palette File Type", "GIMP Palette (GPL)")); 0104 layout->addRow(cmbPaletteType); 0105 0106 QCheckBox *chkSaveInDocument = new QCheckBox(i18n("Save Palette in the Current Document")); 0107 chkSaveInDocument->setChecked(false); 0108 layout->addRow(chkSaveInDocument); 0109 0110 0111 if (dialog.exec() != QDialog::Accepted) { return 0; } 0112 0113 QString name = le->text(); 0114 if (cmbPaletteType->currentIndex() == 0) { 0115 colorSet->setPaletteType(KoColorSet::KPL); 0116 } 0117 else { 0118 colorSet->setPaletteType(KoColorSet::GPL); 0119 } 0120 colorSet->setValid(true); 0121 colorSet->setName(name); 0122 colorSet->setFilename(name.split(" ").join("_")+colorSet->defaultFileExtension()); 0123 0124 QString resourceLocation = ""; 0125 if (chkSaveInDocument->isChecked()) { 0126 resourceLocation = m_d->view->document()->linkedResourcesStorageId(); 0127 } 0128 0129 if (KisResourceUserOperations::addResourceWithUserInput(m_d->view->mainWindowAsQWidget(), colorSet, resourceLocation)) { 0130 return colorSet; 0131 0132 } 0133 0134 return 0; 0135 } 0136 0137 KoColorSetSP KisPaletteEditor::importPalette() 0138 { 0139 KoFileDialog dialog(nullptr, KoFileDialog::OpenFile, "Open Palette"); 0140 dialog.setCaption(i18n("Import Palette")); 0141 0142 dialog.setDefaultDir(QDir::homePath()); 0143 dialog.setMimeTypeFilters(QStringList() << "application/x-krita-palette" << "application/x-gimp-color-palette"); 0144 0145 QString filename = dialog.filename(); 0146 if (filename.isEmpty()) { 0147 return nullptr; 0148 } 0149 0150 QMessageBox messageBox; 0151 messageBox.setText(i18n("Do you want to store this palette in your current image?")); 0152 messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); 0153 QString storageLocation = ""; 0154 if (messageBox.exec() == QMessageBox::Yes) { 0155 storageLocation = m_d->view->document()->linkedResourcesStorageId(); 0156 } 0157 KoResourceSP resource = KisResourceUserOperations::importResourceFileWithUserInput(m_d->view->mainWindowAsQWidget(), storageLocation, ResourceType::Palettes, filename); 0158 0159 KoColorSetSP palette; 0160 if (resource) { 0161 palette = resource.dynamicCast<KoColorSet>(); 0162 } 0163 0164 return palette; 0165 } 0166 0167 void KisPaletteEditor::removePalette(KoColorSetSP cs) 0168 { 0169 if (!m_d->view) { return; } 0170 if (!m_d->view->document()) { return; } 0171 if (!cs) { return; } 0172 m_d->rServer->removeResourceFromServer(cs); 0173 } 0174 0175 int KisPaletteEditor::rowNumberOfGroup(const QString &originalName) const 0176 { 0177 if (!m_d->modifiedPaletteInfo.groups.contains(originalName)) { return 0; } 0178 return m_d->modifiedPaletteInfo.groups[originalName]->rowCount(); 0179 } 0180 0181 bool KisPaletteEditor::duplicateExistsGroupName(const QString &name) const 0182 { 0183 if (name == m_d->groupBeingRenamed) { return false; } 0184 Q_FOREACH (const KisSwatchGroupSP group, m_d->modifiedPaletteInfo.groups.values()) { 0185 if (name == group->name()) { return true; } 0186 } 0187 return false; 0188 } 0189 0190 bool KisPaletteEditor::duplicateExistsOriginalGroupName(const QString &name) const 0191 { 0192 return m_d->modifiedPaletteInfo.groups.contains(name); 0193 } 0194 0195 QString KisPaletteEditor::oldNameFromNewName(const QString &newName) const 0196 { 0197 Q_FOREACH (const QString &oldGroupName, m_d->modifiedPaletteInfo.groups.keys()) { 0198 if (m_d->modifiedPaletteInfo.groups[oldGroupName]->name() == newName) { 0199 return oldGroupName; 0200 } 0201 } 0202 return QString(); 0203 } 0204 0205 void KisPaletteEditor::rename(const QString &newName) 0206 { 0207 if (newName.isEmpty()) { return; } 0208 m_d->isNameModified = true; 0209 m_d->modifiedPaletteInfo.name = newName; 0210 } 0211 0212 void KisPaletteEditor::changeColumnCount(int newCount) 0213 { 0214 m_d->isColumnCountModified = true; 0215 m_d->modifiedPaletteInfo.columnCount = newCount; 0216 } 0217 0218 QString KisPaletteEditor::addGroup() 0219 { 0220 KoDialog dialog; 0221 m_d->query = &dialog; 0222 0223 QVBoxLayout *layout = new QVBoxLayout(dialog.mainWidget()); 0224 0225 layout->addWidget(new QLabel(i18n("New swatch group name:"))); 0226 QLineEdit *leName = new QLineEdit(newGroupName()); 0227 connect(leName, SIGNAL(textChanged(QString)), SLOT(slotGroupNameChanged(QString))); 0228 layout->addWidget(leName); 0229 layout->addWidget(new QLabel(i18n("Rows of swatches in group:"))); 0230 QSpinBox *spxRow = new QSpinBox(); 0231 spxRow->setValue(20); 0232 layout->addWidget(spxRow); 0233 0234 if (dialog.exec() != QDialog::Accepted) { return QString(); } 0235 if (duplicateExistsGroupName(leName->text())) { return QString(); } 0236 0237 QString realName = leName->text(); 0238 QString name = realName; 0239 if (duplicateExistsOriginalGroupName(name)) { 0240 name = newGroupName(); 0241 } 0242 m_d->modifiedPaletteInfo.groups[name].reset(new KisSwatchGroup); 0243 KisSwatchGroupSP newGroup = m_d->modifiedPaletteInfo.groups[name]; 0244 newGroup->setName(realName); 0245 m_d->newGroupNames.insert(name); 0246 newGroup->setRowCount(spxRow->value()); 0247 return realName; 0248 } 0249 0250 bool KisPaletteEditor::removeGroup(const QString &name) 0251 { 0252 KoDialog dialog; 0253 dialog.setWindowTitle(i18nc("@title:dialog", "Removing Swatch Group")); 0254 QFormLayout *editableItems = new QFormLayout(dialog.mainWidget()); 0255 QCheckBox *chkKeep = new QCheckBox(); 0256 0257 editableItems->addRow(i18nc("Shows up when deleting a swatch group", "Keep the Colors"), chkKeep); 0258 if (dialog.exec() != KoDialog::Accepted) { return false; } 0259 0260 m_d->modifiedPaletteInfo.groups.remove(name); 0261 m_d->newGroupNames.remove(name); 0262 if (chkKeep->isChecked()) { 0263 m_d->keepColorGroups.insert(name); 0264 } 0265 return true; 0266 } 0267 0268 QString KisPaletteEditor::renameGroup(const QString &oldName) 0269 { 0270 if (oldName.isEmpty() || oldName == KoColorSet::GLOBAL_GROUP_NAME) { return QString(); } 0271 0272 KoDialog dialog; 0273 m_d->query = &dialog; 0274 m_d->groupBeingRenamed = m_d->modifiedPaletteInfo.groups[oldName]->name(); 0275 0276 QFormLayout *form = new QFormLayout(dialog.mainWidget()); 0277 0278 QLineEdit *leNewName = new QLineEdit(); 0279 connect(leNewName, SIGNAL(textChanged(QString)), SLOT(slotGroupNameChanged(QString))); 0280 leNewName->setText(m_d->modifiedPaletteInfo.groups[oldName]->name()); 0281 0282 form->addRow(i18n("New swatch group name:"), leNewName); 0283 0284 if (dialog.exec() != KoDialog::Accepted) { return QString(); } 0285 if (leNewName->text().isEmpty()) { return QString(); } 0286 if (duplicateExistsGroupName(leNewName->text())) { return QString(); } 0287 0288 m_d->modifiedPaletteInfo.groups[oldName]->setName(leNewName->text()); 0289 m_d->modifiedGroupNames.insert(oldName); 0290 0291 return leNewName->text(); 0292 } 0293 0294 void KisPaletteEditor::slotGroupNameChanged(const QString &newName) 0295 { 0296 QLineEdit *leGroupName = qobject_cast<QLineEdit*>(sender()); 0297 if (duplicateExistsGroupName(newName) || newName == QString()) { 0298 leGroupName->setPalette(m_d->warnPalette); 0299 if (m_d->query->button(KoDialog::Ok)) { 0300 m_d->query->button(KoDialog::Ok)->setEnabled(false); 0301 } 0302 return; 0303 } 0304 leGroupName->setPalette(m_d->normalPalette); 0305 if (m_d->query->button(KoDialog::Ok)) { 0306 m_d->query->button(KoDialog::Ok)->setEnabled(true); 0307 } 0308 } 0309 0310 void KisPaletteEditor::changeGroupRowCount(const QString &name, int newRowCount) 0311 { 0312 if (!m_d->modifiedPaletteInfo.groups.contains(name)) { return; } 0313 m_d->modifiedPaletteInfo.groups[name]->setRowCount(newRowCount); 0314 m_d->modifiedGroupNames.insert(name); 0315 } 0316 0317 void KisPaletteEditor::setStorageLocation(QString location) 0318 { 0319 m_d->modifiedPaletteInfo.storageLocation = location; 0320 } 0321 0322 void KisPaletteEditor::setEntry(const KoColor &color, const QModelIndex &index) 0323 { 0324 Q_ASSERT(m_d->model); 0325 if (!m_d->view) { return; } 0326 if (!m_d->view->document()) { return; } 0327 KisSwatch c = KisSwatch(color); 0328 c.setId(QString::number(m_d->model->colorSet()->colorCount() + 1)); 0329 c.setName(i18nc("Default name for a color swatch","Color %1", QString::number(m_d->model->colorSet()->colorCount()+1))); 0330 m_d->model->setSwatch(c, index); 0331 } 0332 0333 void KisPaletteEditor::slotSetDocumentModified() 0334 { 0335 if (m_d->modifiedPaletteInfo.storageLocation == m_d->view->document()->linkedResourcesStorageId()) { 0336 updatePalette(); 0337 KisResourceUserOperations::updateResourceWithUserInput(m_d->view->mainWindowAsQWidget(), m_d->model->colorSet()); 0338 m_d->view->document()->setModified(true); 0339 } 0340 m_d->model->colorSet()->setDirty(true); 0341 } 0342 0343 void KisPaletteEditor::removeEntry(const QModelIndex &index) 0344 { 0345 Q_ASSERT(m_d->model); 0346 if (!m_d->view) { return; } 0347 if (!m_d->view->document()) { return; } 0348 if (qvariant_cast<bool>(index.data(KisPaletteModel::IsGroupNameRole))) { 0349 removeGroup(qvariant_cast<QString>(index.data(KisPaletteModel::GroupNameRole))); 0350 } else { 0351 m_d->model->removeSwatch(index, false); 0352 } 0353 updatePalette(); 0354 } 0355 0356 void KisPaletteEditor::modifyEntry(const QModelIndex &index) 0357 { 0358 if (!m_d->view) { return; } 0359 if (!m_d->view->document()) { return; } 0360 0361 KoDialog dialog; 0362 dialog.setCaption(i18nc("@title:dialog", "Add a new Color Swatch")); 0363 QFormLayout *editableItems = new QFormLayout(dialog.mainWidget()); 0364 0365 QString groupName = qvariant_cast<QString>(index.data(Qt::DisplayRole)); 0366 if (qvariant_cast<bool>(index.data(KisPaletteModel::IsGroupNameRole))) { 0367 renameGroup(groupName); 0368 updatePalette(); 0369 } 0370 else { 0371 0372 QLineEdit *lnIDName = new QLineEdit(); 0373 QLineEdit *lnGroupName = new QLineEdit(); 0374 KisColorButton *bnColor = new KisColorButton(); 0375 QCheckBox *chkSpot = new QCheckBox(); 0376 chkSpot->setToolTip(i18nc("@info:tooltip", "A spot color is a color that the printer is able to print without mixing the paints it has available to it. The opposite is called a process color.")); 0377 0378 KisSwatch entry = m_d->model->getSwatch(index); 0379 0380 editableItems->addRow(i18n("Swatch ID:"), lnIDName); 0381 editableItems->addRow(i18n("Color swatch name:"), lnGroupName); 0382 editableItems->addRow(i18nc("Color as the Color of a Swatch in a Palette", "Color:"), bnColor); 0383 editableItems->addRow(i18n("Spot color:"), chkSpot); 0384 0385 lnGroupName->setText(entry.name()); 0386 lnIDName->setText(entry.id()); 0387 bnColor->setColor(entry.color()); 0388 chkSpot->setChecked(entry.spotColor()); 0389 0390 if (dialog.exec() == KoDialog::Accepted) { 0391 entry.setName(lnGroupName->text()); 0392 entry.setId(lnIDName->text()); 0393 entry.setColor(bnColor->color()); 0394 entry.setSpotColor(chkSpot->isChecked()); 0395 m_d->model->setSwatch(entry, index); 0396 } 0397 } 0398 } 0399 0400 void KisPaletteEditor::addEntry(const KoColor &color) 0401 { 0402 Q_ASSERT(m_d->model); 0403 if (!m_d->view) { return; } 0404 if (!m_d->view->document()) { return; } 0405 0406 KoDialog dialog; 0407 dialog.setWindowTitle(i18nc("@title:dialog", "Add a new Color Swatch")); 0408 0409 QFormLayout *editableItems = new QFormLayout(dialog.mainWidget()); 0410 0411 QComboBox *cmbGroups = new QComboBox(); 0412 cmbGroups->addItems(m_d->model->colorSet()->swatchGroupNames()); 0413 cmbGroups->setCurrentIndex(0); 0414 0415 QLineEdit *lnIDName = new QLineEdit(); 0416 lnIDName->setText(QString::number(m_d->model->colorSet()->colorCount() + 1)); 0417 0418 QLineEdit *lnName = new QLineEdit(); 0419 lnName->setText(i18nc("Default name for a color swatch","Color %1", QString::number(m_d->model->colorSet()->colorCount()+1))); 0420 0421 KisColorButton *bnColor = new KisColorButton(); 0422 bnColor->setColor(color); 0423 0424 QCheckBox *chkSpot = new QCheckBox(); 0425 chkSpot->setChecked(false); 0426 chkSpot->setToolTip(i18nc("@info:tooltip", "A spot color is a color that the printer is able to print without mixing the paints it has available to it. The opposite is called a process color.")); 0427 0428 editableItems->addRow(i18n("Swatch Group:"), cmbGroups); 0429 editableItems->addRow(i18n("Swatch ID:"), lnIDName); 0430 editableItems->addRow(i18n("Color swatch name:"), lnName); 0431 editableItems->addRow(i18nc("Color as the Color of a Swatch in a Palette", "Color:"), bnColor); 0432 editableItems->addRow(i18n("Spot color:"), chkSpot); 0433 0434 if (dialog.exec() != KoDialog::Accepted) { return; } 0435 0436 QString groupName = cmbGroups->currentText(); 0437 0438 KisSwatch newSwatch; 0439 newSwatch.setColor(bnColor->color()); 0440 newSwatch.setName(lnName->text()); 0441 newSwatch.setId(lnIDName->text()); 0442 newSwatch.setSpotColor(chkSpot->isChecked()); 0443 m_d->model->addSwatch(newSwatch, groupName); 0444 m_d->modifiedGroupNames.insert(groupName); 0445 m_d->modifiedPaletteInfo.groups[groupName]->addSwatch(newSwatch); 0446 } 0447 0448 bool KisPaletteEditor::isModified() const 0449 { 0450 if (m_d->model->colorSet()) { 0451 return m_d->model->colorSet()->isDirty(); 0452 } else { 0453 return false; 0454 } 0455 } 0456 0457 void KisPaletteEditor::updatePalette() 0458 { 0459 if (!m_d->model) return; 0460 if (!m_d->model->colorSet()) return; 0461 if (!m_d->view) return; 0462 if (!m_d->view->document()) return; 0463 0464 KoColorSetSP palette = m_d->model->colorSet(); 0465 PaletteInfo &modified = m_d->modifiedPaletteInfo; 0466 0467 if (m_d->isColumnCountModified) { 0468 m_d->model->setColumnCount(modified.columnCount); 0469 } 0470 if (m_d->isNameModified) { 0471 KisResourceUserOperations::renameResourceWithUserInput(m_d->view->mainWindowAsQWidget(), palette, m_d->modifiedPaletteInfo.name); 0472 } 0473 QString resourceLocation = m_d->model->colorSet()->storageLocation(); 0474 if (resourceLocation != m_d->modifiedPaletteInfo.storageLocation) { 0475 // We need functionality for moving the resource to the new resource storage... 0476 } 0477 0478 Q_FOREACH (const QString &groupName, palette->swatchGroupNames()) { 0479 if (!modified.groups.contains(groupName)) { 0480 m_d->model->removeGroup(groupName, m_d->keepColorGroups.contains(groupName)); 0481 } 0482 } 0483 m_d->keepColorGroups.clear(); 0484 Q_FOREACH (const QString &groupName, palette->swatchGroupNames()) { 0485 if (m_d->modifiedGroupNames.contains(groupName)) { 0486 m_d->model->setRowCountForGroup(groupName, modified.groups[groupName]->rowCount()); 0487 if (groupName != modified.groups[groupName]->name()) { 0488 m_d->model->changeGroupName(groupName, modified.groups[groupName]->name()); 0489 modified.groups[modified.groups[groupName]->name()] = modified.groups[groupName]; 0490 modified.groups.remove(groupName); 0491 } 0492 } 0493 } 0494 m_d->modifiedGroupNames.clear(); 0495 Q_FOREACH (const QString &newGroupName, m_d->newGroupNames) { 0496 m_d->model->addGroup(newGroupName); 0497 } 0498 m_d->newGroupNames.clear(); 0499 } 0500 0501 void KisPaletteEditor::saveNewPaletteVersion() 0502 { 0503 if (!m_d->model || !m_d->model->colorSet()) { return; } 0504 0505 QModelIndex index = m_d->rServer->resourceModel()->indexForResource(m_d->model->colorSet()); 0506 bool isGlobal = false; 0507 if (index.isValid()) { 0508 bool ok = false; 0509 int storageId = m_d->rServer->resourceModel()->data(index, Qt::UserRole + KisAllResourcesModel::StorageId).toInt(&ok); 0510 if (ok) { 0511 KisStorageModel storageModel; 0512 KisResourceStorageSP storage = storageModel.storageForId(storageId); 0513 isGlobal = storage->type() != KisResourceStorage::StorageType::Memory; 0514 } 0515 } 0516 bool res = false; 0517 if (isGlobal) { 0518 if (m_d->view) { 0519 res = KisResourceUserOperations::updateResourceWithUserInput(m_d->view->mainWindowAsQWidget(), m_d->model->colorSet()); 0520 } else if (m_d->model->colorSet()->version() >= 0) { 0521 //if the version is -1, then the resource should not be updated, because it was never saved to begin with... 0522 res = m_d->rServer->resourceModel()->updateResource(m_d->model->colorSet()); 0523 dbgResources << Q_FUNC_INFO << "-- Updating resource without user input: " << m_d->model->colorSet()->name() << "Result:" << res; 0524 } 0525 } 0526 } 0527 0528 void KisPaletteEditor::slotPaletteChanged() 0529 { 0530 Q_ASSERT(m_d->model); 0531 if (!m_d->model->colorSet()) { return; } 0532 KoColorSetSP palette = m_d->model->colorSet(); 0533 m_d->modifiedPaletteInfo.groups.clear(); 0534 m_d->keepColorGroups.clear(); 0535 m_d->newGroupNames.clear(); 0536 m_d->modifiedGroupNames.clear(); 0537 0538 m_d->modifiedPaletteInfo.name = palette->name(); 0539 m_d->modifiedPaletteInfo.storageLocation = palette->storageLocation(); 0540 m_d->modifiedPaletteInfo.columnCount = palette->columnCount(); 0541 0542 Q_FOREACH (const QString &groupName, palette->swatchGroupNames()) { 0543 KisSwatchGroupSP cs = palette->getGroup(groupName); 0544 m_d->modifiedPaletteInfo.groups[groupName].reset(new KisSwatchGroup(*cs.data())); 0545 } 0546 } 0547 0548 QString KisPaletteEditor::newGroupName() const 0549 { 0550 int i = 1; 0551 QString groupname = i18nc("Default new group name", "New Group %1", QString::number(i)); 0552 while (m_d->modifiedPaletteInfo.groups.contains(groupname)) { 0553 i++; 0554 groupname = i18nc("Default new group name", "New Group %1", QString::number(i)); 0555 } 0556 return groupname; 0557 } 0558 0559 QString KisPaletteEditor::filenameFromPath(const QString &path) const 0560 { 0561 return QDir::fromNativeSeparators(path).section('/', -1, -1); 0562 }