1 /*
2  *  Copyright (c) 2018 Michael Zhou <simeirxh@gmail.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include <QHash>
20 #include <QString>
21 #include <QScopedPointer>
22 #include <QPointer>
23 #include <QFormLayout>
24 #include <QCheckBox>
25 #include <QLineEdit>
26 #include <QPushButton>
27 #include <QLabel>
28 #include <QSpinBox>
29 #include <QComboBox>
30 #include <QMessageBox>
31 
32 #include <KoDialog.h>
33 #include <KoFileDialog.h>
34 #include <KoColorSet.h>
35 #include <KisSwatchGroup.h>
36 #include <kis_signal_compressor.h>
37 #include <KisViewManager.h>
38 #include <KisDocument.h>
39 #include <KoResourceServer.h>
40 #include <KoResourceServerProvider.h>
41 #include <KisPaletteModel.h>
42 #include <kis_color_button.h>
43 
44 #include "KisPaletteEditor.h"
45 
46 struct KisPaletteEditor::PaletteInfo {
47     QString name;
48     QString filename;
49     int columnCount;
50     bool isGlobal;
51     bool isReadOnly;
52     QHash<QString, KisSwatchGroup> groups;
53 };
54 
55 struct KisPaletteEditor::Private
56 {
57     bool isGlobalModified {false};
58     bool isNameModified {false};
59     bool isFilenameModified {false};
60     bool isColumnCountModified {false};
61     QSet<QString> modifiedGroupNames; // key is original group name
62     QSet<QString> newGroupNames;
63     QSet<QString> keepColorGroups;
64     QSet<QString> pathsToRemove;
65     QString groupBeingRenamed;
66     QPointer<KisPaletteModel> model;
67     QPointer<KisViewManager> view;
68     PaletteInfo modified;
69     QPointer<KoDialog> query;
70     KoResourceServer<KoColorSet> *rServer {0};
71 
72     QPalette normalPalette;
73     QPalette warnPalette;
74 };
75 
KisPaletteEditor(QObject * parent)76 KisPaletteEditor::KisPaletteEditor(QObject *parent)
77     : QObject(parent)
78     , m_d(new Private)
79 {
80     m_d->rServer = KoResourceServerProvider::instance()->paletteServer();
81     m_d->warnPalette.setColor(QPalette::Text, Qt::red);
82 }
83 
~KisPaletteEditor()84 KisPaletteEditor::~KisPaletteEditor()
85 { }
86 
setPaletteModel(KisPaletteModel * model)87 void KisPaletteEditor::setPaletteModel(KisPaletteModel *model)
88 {
89     if (!model) { return; }
90     m_d->model = model;
91     slotPaletteChanged();
92     connect(model, SIGNAL(sigPaletteChanged()), SLOT(slotPaletteChanged()));
93     connect(model, SIGNAL(sigPaletteModified()), SLOT(slotSetDocumentModified()));
94 }
95 
setView(KisViewManager * view)96 void KisPaletteEditor::setView(KisViewManager *view)
97 {
98     m_d->view = view;
99 }
100 
addPalette()101 void KisPaletteEditor::addPalette()
102 {
103     if (!m_d->view) { return; }
104     if (!m_d->view->document()) { return; }
105 
106     KoDialog dlg;
107     QFormLayout layout;
108     dlg.mainWidget()->setLayout(&layout);
109     QLabel lbl(i18nc("Label for line edit to set a palette name.","Name"));
110     QLineEdit le(i18nc("Default name for a new palette","New Palette"));
111     layout.addRow(&lbl, &le);
112 
113     QLabel lbl2(i18nc("Label for line edit to set a palette filename.","File Name"));
114     QLineEdit le2(i18nc("Default file name for a new palette", "New Palette"));
115     layout.addRow(&lbl2, &le2);
116 
117 
118     QCheckBox chkSaveInDocument(i18n("Save Palette in the Current Document"));
119     chkSaveInDocument.setChecked(false);
120     layout.addRow(&chkSaveInDocument);
121 
122     if (dlg.exec() != QDialog::Accepted) { return; }
123 
124     KoColorSet *newColorSet = new KoColorSet(newPaletteFileName(!chkSaveInDocument.isChecked(), le2.text()));
125     newColorSet->setPaletteType(KoColorSet::KPL);
126     newColorSet->setIsGlobal(!chkSaveInDocument.isChecked());
127     newColorSet->setIsEditable(true);
128     newColorSet->setValid(true);
129     newColorSet->setName(le.text());
130 
131     m_d->rServer->addResource(newColorSet, !chkSaveInDocument.isChecked());
132     m_d->rServer->removeFromBlacklist(newColorSet);
133 
134     uploadPaletteList();
135 }
136 
importPalette()137 void KisPaletteEditor::importPalette()
138 {
139     KoFileDialog dialog(0, KoFileDialog::OpenFile, "Open Palette");
140 
141     dialog.setDefaultDir(QDir::homePath());
142     dialog.setMimeTypeFilters(QStringList() << "krita/x-colorset" << "application/x-gimp-color-palette");
143 
144     QString filename = dialog.filename();
145     if (filename.isEmpty()) { return; }
146     if (duplicateExistsFilename(filename, false)) {
147         QMessageBox message;
148         message.setWindowTitle(i18n("Can't Import Palette"));
149         message.setText(i18n("Can't import palette: there's already imported with the same filename"));
150         message.exec();
151         return;
152     }
153 
154     KoColorSet *colorSet = new KoColorSet(filename);
155     colorSet->load();
156     QString name = filenameFromPath(colorSet->filename());
157 
158     if (duplicateExistsFilename(name, false)) {
159         colorSet->setFilename(newPaletteFileName(true));
160     } else {
161         colorSet->setFilename(name);
162     }
163 
164     colorSet->setIsGlobal(true);
165     m_d->rServer->addResource(colorSet, true);
166     m_d->rServer->removeFromBlacklist(colorSet);
167 
168     uploadPaletteList();
169 }
170 
removePalette(KoColorSet * cs)171 void KisPaletteEditor::removePalette(KoColorSet *cs)
172 {
173     if (!m_d->view) { return; }
174     if (!m_d->view->document()) { return; }
175     if (!cs || !cs->isEditable()) {
176         return;
177     }
178 
179     if (cs->isGlobal()) {
180         QFile::remove(cs->filename());
181         m_d->rServer->removeResourceAndBlacklist(cs);
182         return;
183     }
184     m_d->rServer->removeResourceFromServer(cs);
185     uploadPaletteList();
186 }
187 
rowNumberOfGroup(const QString & oriName) const188 int KisPaletteEditor::rowNumberOfGroup(const QString &oriName) const
189 {
190     if (!m_d->modified.groups.contains(oriName)) { return 0; }
191     return m_d->modified.groups[oriName].rowCount();
192 }
193 
duplicateExistsGroupName(const QString & name) const194 bool KisPaletteEditor::duplicateExistsGroupName(const QString &name) const
195 {
196     if (name == m_d->groupBeingRenamed) { return false; }
197     Q_FOREACH (const KisSwatchGroup &g, m_d->modified.groups.values()) {
198         if (name == g.name()) { return true; }
199     }
200     return false;
201 }
202 
duplicateExistsOriginalGroupName(const QString & name) const203 bool KisPaletteEditor::duplicateExistsOriginalGroupName(const QString &name) const
204 {
205     return m_d->modified.groups.contains(name);
206 }
207 
oldNameFromNewName(const QString & newName) const208 QString KisPaletteEditor::oldNameFromNewName(const QString &newName) const
209 {
210     Q_FOREACH (const QString &oldGroupName, m_d->modified.groups.keys()) {
211         if (m_d->modified.groups[oldGroupName].name() == newName) {
212             return oldGroupName;
213         }
214     }
215     return QString();
216 }
217 
rename(const QString & newName)218 void KisPaletteEditor::rename(const QString &newName)
219 {
220     if (newName.isEmpty()) { return; }
221     m_d->isNameModified = true;
222     m_d->modified.name = newName;
223 }
224 
changeFilename(const QString & newName)225 void KisPaletteEditor::changeFilename(const QString &newName)
226 {
227     if (newName.isEmpty()) { return; }
228     m_d->isFilenameModified = true;
229     m_d->pathsToRemove.insert(m_d->modified.filename);
230     if (m_d->modified.isGlobal) {
231         m_d->modified.filename = m_d->rServer->saveLocation() + newName;
232     } else {
233         m_d->modified.filename = newName;
234     }
235 }
236 
changeColCount(int newCount)237 void KisPaletteEditor::changeColCount(int newCount)
238 {
239     m_d->isColumnCountModified = true;
240     m_d->modified.columnCount = newCount;
241 }
242 
addGroup()243 QString KisPaletteEditor::addGroup()
244 {
245     KoDialog dlg;
246     m_d->query = &dlg;
247 
248     QVBoxLayout layout(&dlg);
249     dlg.mainWidget()->setLayout(&layout);
250 
251     QLabel lblName(i18n("Name"), &dlg);
252     layout.addWidget(&lblName);
253     QLineEdit leName(&dlg);
254     leName.setText(newGroupName());
255     connect(&leName, SIGNAL(textChanged(QString)), SLOT(slotGroupNameChanged(QString)));
256     layout.addWidget(&leName);
257     QLabel lblRowCount(i18n("Row count"), &dlg);
258     layout.addWidget(&lblRowCount);
259     QSpinBox spxRow(&dlg);
260     spxRow.setValue(20);
261     layout.addWidget(&spxRow);
262 
263     if (dlg.exec() != QDialog::Accepted) { return QString(); }
264     if (duplicateExistsGroupName(leName.text())) { return QString(); }
265 
266     QString realName = leName.text();
267     QString name = realName;
268     if (duplicateExistsOriginalGroupName(name)) {
269         name = newGroupName();
270     }
271     m_d->modified.groups[name] = KisSwatchGroup();
272     KisSwatchGroup &newGroup = m_d->modified.groups[name];
273     newGroup.setName(realName);
274     m_d->newGroupNames.insert(name);
275     newGroup.setRowCount(spxRow.value());
276     return realName;
277 }
278 
removeGroup(const QString & name)279 bool KisPaletteEditor::removeGroup(const QString &name)
280 {
281     KoDialog window;
282     window.setWindowTitle(i18nc("@title:window", "Removing Group"));
283     QFormLayout editableItems(&window);
284     QCheckBox chkKeep(&window);
285     window.mainWidget()->setLayout(&editableItems);
286     editableItems.addRow(i18nc("Shows up when deleting a swatch group", "Keep the Colors"), &chkKeep);
287     if (window.exec() != KoDialog::Accepted) { return false; }
288 
289     m_d->modified.groups.remove(name);
290     m_d->newGroupNames.remove(name);
291     if (chkKeep.isChecked()) {
292         m_d->keepColorGroups.insert(name);
293     }
294     return true;
295 }
296 
renameGroup(const QString & oldName)297 QString KisPaletteEditor::renameGroup(const QString &oldName)
298 {
299     if (oldName.isEmpty() || oldName == KoColorSet::GLOBAL_GROUP_NAME) { return QString(); }
300 
301     KoDialog dlg;
302     m_d->query = &dlg;
303     m_d->groupBeingRenamed = m_d->modified.groups[oldName].name();
304 
305     QFormLayout form(&dlg);
306     dlg.mainWidget()->setLayout(&form);
307 
308     QLineEdit leNewName;
309     connect(&leNewName, SIGNAL(textChanged(QString)), SLOT(slotGroupNameChanged(QString)));
310     leNewName.setText(m_d->modified.groups[oldName].name());
311 
312     form.addRow(i18nc("Renaming swatch group", "New name"), &leNewName);
313 
314     if (dlg.exec() != KoDialog::Accepted) { return QString(); }
315     if (leNewName.text().isEmpty()) { return QString(); }
316     if (duplicateExistsGroupName(leNewName.text())) { return QString(); }
317 
318     m_d->modified.groups[oldName].setName(leNewName.text());
319     m_d->modifiedGroupNames.insert(oldName);
320 
321     return leNewName.text();
322 }
323 
slotGroupNameChanged(const QString & newName)324 void KisPaletteEditor::slotGroupNameChanged(const QString &newName)
325 {
326     QLineEdit *leGroupName = qobject_cast<QLineEdit*>(sender());
327     if (duplicateExistsGroupName(newName) || newName == QString()) {
328         leGroupName->setPalette(m_d->warnPalette);
329         if (m_d->query->button(KoDialog::Ok)) {
330             m_d->query->button(KoDialog::Ok)->setEnabled(false);
331         }
332         return;
333     }
334     leGroupName->setPalette(m_d->normalPalette);
335     if (m_d->query->button(KoDialog::Ok)) {
336         m_d->query->button(KoDialog::Ok)->setEnabled(true);
337     }
338 }
339 
changeGroupRowCount(const QString & name,int newRowCount)340 void KisPaletteEditor::changeGroupRowCount(const QString &name, int newRowCount)
341 {
342     if (!m_d->modified.groups.contains(name)) { return; }
343     m_d->modified.groups[name].setRowCount(newRowCount);
344     m_d->modifiedGroupNames.insert(name);
345 }
346 
setGlobal(bool isGlobal)347 void KisPaletteEditor::setGlobal(bool isGlobal)
348 {
349     m_d->isGlobalModified = true;
350     m_d->modified.isGlobal = isGlobal;
351 }
352 
setEntry(const KoColor & color,const QModelIndex & index)353 void KisPaletteEditor::setEntry(const KoColor &color, const QModelIndex &index)
354 {
355     Q_ASSERT(m_d->model);
356     if (!m_d->model->colorSet()->isEditable()) { return; }
357     if (!m_d->view) { return; }
358     if (!m_d->view->document()) { return; }
359     KisSwatch c = KisSwatch(color);
360     c.setId(QString::number(m_d->model->colorSet()->colorCount() + 1));
361     c.setName(i18nc("Default name for a color swatch","Color %1", QString::number(m_d->model->colorSet()->colorCount()+1)));
362     m_d->model->setEntry(c, index);
363 }
364 
slotSetDocumentModified()365 void KisPaletteEditor::slotSetDocumentModified()
366 {
367     m_d->view->document()->setModified(true);
368 }
369 
removeEntry(const QModelIndex & index)370 void KisPaletteEditor::removeEntry(const QModelIndex &index)
371 {
372     Q_ASSERT(m_d->model);
373     if (!m_d->model->colorSet()->isEditable()) { return; }
374     if (!m_d->view) { return; }
375     if (!m_d->view->document()) { return; }
376     if (qvariant_cast<bool>(index.data(KisPaletteModel::IsGroupNameRole))) {
377         removeGroup(qvariant_cast<QString>(index.data(KisPaletteModel::GroupNameRole)));
378         updatePalette();
379     } else {
380         m_d->model->removeEntry(index, false);
381     }
382     if (m_d->model->colorSet()->isGlobal()) {
383         m_d->model->colorSet()->save();
384         return;
385     }
386 }
387 
modifyEntry(const QModelIndex & index)388 void KisPaletteEditor::modifyEntry(const QModelIndex &index)
389 {
390     if (!m_d->model->colorSet()->isEditable()) { return; }
391     if (!m_d->view) { return; }
392     if (!m_d->view->document()) { return; }
393 
394     KoDialog dlg;
395     dlg.setCaption(i18nc("@title:window", "Add a Color"));
396     QFormLayout *editableItems = new QFormLayout(&dlg);
397     dlg.mainWidget()->setLayout(editableItems);
398 
399     QString groupName = qvariant_cast<QString>(index.data(Qt::DisplayRole));
400     if (qvariant_cast<bool>(index.data(KisPaletteModel::IsGroupNameRole))) {
401         renameGroup(groupName);
402         updatePalette();
403     }
404     else {
405 
406         QLineEdit *lnIDName = new QLineEdit(&dlg);
407         QLineEdit *lnGroupName = new QLineEdit(&dlg);
408         KisColorButton *bnColor = new KisColorButton(&dlg);
409         QCheckBox *chkSpot = new QCheckBox(&dlg);
410         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."));
411 
412         KisSwatch entry = m_d->model->getEntry(index);
413 
414         editableItems->addRow(i18n("ID"), lnIDName);
415         editableItems->addRow(i18nc("Name of the color swatch", "Color swatch name"), lnGroupName);
416         editableItems->addRow(i18n("Color"), bnColor);
417         editableItems->addRow(i18n("Spot color"), chkSpot);
418 
419         lnGroupName->setText(entry.name());
420         lnIDName->setText(entry.id());
421         bnColor->setColor(entry.color());
422         chkSpot->setChecked(entry.spotColor());
423 
424         if (dlg.exec() == KoDialog::Accepted) {
425             entry.setName(lnGroupName->text());
426             entry.setId(lnIDName->text());
427             entry.setColor(bnColor->color());
428             entry.setSpotColor(chkSpot->isChecked());
429             m_d->model->setEntry(entry, index);
430         }
431     }
432 }
433 
addEntry(const KoColor & color)434 void KisPaletteEditor::addEntry(const KoColor &color)
435 {
436     Q_ASSERT(m_d->model);
437     if (!m_d->view) { return; }
438     if (!m_d->view->document()) { return; }
439     if (!m_d->model->colorSet()->isEditable()) { return; }
440     KoDialog window;
441     window.setWindowTitle(i18nc("@title:window", "Add a new Colorset Entry"));
442     QFormLayout editableItems(&window);
443     window.mainWidget()->setLayout(&editableItems);
444     QComboBox cmbGroups(&window);
445     cmbGroups.addItems(m_d->model->colorSet()->getGroupNames());
446     QLineEdit lnIDName(&window);
447     QLineEdit lnName(&window);
448     KisColorButton bnColor(&window);
449     QCheckBox chkSpot(&window);
450     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."));
451     editableItems.addRow(i18n("Group"), &cmbGroups);
452     editableItems.addRow(i18n("ID"), &lnIDName);
453     editableItems.addRow(i18n("Name"), &lnName);
454     editableItems.addRow(i18n("Color"), &bnColor);
455     editableItems.addRow(i18nc("Spot color", "Spot"), &chkSpot);
456     cmbGroups.setCurrentIndex(0);
457     lnName.setText(i18nc("Default name for a color swatch","Color %1", QString::number(m_d->model->colorSet()->colorCount()+1)));
458     lnIDName.setText(QString::number(m_d->model->colorSet()->colorCount() + 1));
459     bnColor.setColor(color);
460     chkSpot.setChecked(false);
461 
462     if (window.exec() != KoDialog::Accepted) { return; }
463 
464     QString groupName = cmbGroups.currentText();
465 
466     KisSwatch newEntry;
467     newEntry.setColor(bnColor.color());
468     newEntry.setName(lnName.text());
469     newEntry.setId(lnIDName.text());
470     newEntry.setSpotColor(chkSpot.isChecked());
471     m_d->model->addEntry(newEntry, groupName);
472 
473     if (m_d->model->colorSet()->isGlobal()) {
474         m_d->model->colorSet()->save();
475         return;
476     }
477     m_d->modifiedGroupNames.insert(groupName);
478     m_d->modified.groups[groupName].addEntry(newEntry);
479 }
480 
updatePalette()481 void KisPaletteEditor::updatePalette()
482 {
483     Q_ASSERT(m_d->model);
484     Q_ASSERT(m_d->model->colorSet());
485     if (!m_d->model->colorSet()->isEditable()) { return; }
486     if (!m_d->view) { return; }
487     if (!m_d->view->document()) { return; }
488     KoColorSet *palette = m_d->model->colorSet();
489     PaletteInfo &modified = m_d->modified;
490 
491     if (m_d->isColumnCountModified) {
492         palette->setColumnCount(modified.columnCount);
493     }
494     if (m_d->isNameModified) {
495         palette->setName(modified.name);
496     }
497     if (m_d->isFilenameModified) {
498         QString originalPath = palette->filename();
499         palette->setFilename(modified.filename);
500         if (palette->isGlobal()) {
501             if (!palette->save()) {
502                 palette->setFilename(newPaletteFileName(true));
503                 palette->save();
504             }
505             QFile::remove(originalPath);
506         }
507     }
508     if (m_d->isGlobalModified) {
509         palette->setIsGlobal(modified.isGlobal);
510         if (modified.isGlobal) {
511             setGlobal();
512         } else {
513             setNonGlobal();
514         }
515     }
516     Q_FOREACH (const QString &groupName, palette->getGroupNames()) {
517         if (!modified.groups.contains(groupName)) {
518             m_d->model->removeGroup(groupName, m_d->keepColorGroups.contains(groupName));
519         }
520     }
521     m_d->keepColorGroups.clear();
522     Q_FOREACH (const QString &groupName, palette->getGroupNames()) {
523         if (m_d->modifiedGroupNames.contains(groupName)) {
524             m_d->model->setRowNumber(groupName, modified.groups[groupName].rowCount());
525             if (groupName != modified.groups[groupName].name()) {
526                 m_d->model->renameGroup(groupName, modified.groups[groupName].name());
527                 modified.groups[modified.groups[groupName].name()] = modified.groups[groupName];
528                 modified.groups.remove(groupName);
529             }
530         }
531     }
532     m_d->modifiedGroupNames.clear();
533     Q_FOREACH (const QString &newGroupName, m_d->newGroupNames) {
534         m_d->model->addGroup(modified.groups[newGroupName]);
535     }
536     m_d->newGroupNames.clear();
537 
538     if (m_d->model->colorSet()->isGlobal()) {
539         m_d->model->colorSet()->save();
540     }
541 }
542 
slotPaletteChanged()543 void KisPaletteEditor::slotPaletteChanged()
544 {
545     Q_ASSERT(m_d->model);
546     if (!m_d->model->colorSet()) { return; }
547     KoColorSet *palette = m_d->model->colorSet();
548     m_d->modified.groups.clear();
549     m_d->keepColorGroups.clear();
550     m_d->newGroupNames.clear();
551     m_d->modifiedGroupNames.clear();
552 
553     m_d->modified.name = palette->name();
554     m_d->modified.filename = palette->filename();
555     m_d->modified.columnCount = palette->columnCount();
556     m_d->modified.isGlobal = palette->isGlobal();
557     m_d->modified.isReadOnly = !palette->isEditable();
558 
559     Q_FOREACH (const QString &groupName, palette->getGroupNames()) {
560         KisSwatchGroup *cs = palette->getGroup(groupName);
561         m_d->modified.groups[groupName] = KisSwatchGroup(*cs);
562     }
563 }
564 
setGlobal()565 void KisPaletteEditor::setGlobal()
566 {
567     Q_ASSERT(m_d->model);
568     if (!m_d->view) { return; }
569     if (!m_d->view->document()) { return; }
570     if (!m_d->model->colorSet()) { return; }
571 
572     KoColorSet *colorSet = m_d->model->colorSet();
573     QString saveLocation = m_d->rServer->saveLocation();
574     QString name = filenameFromPath(colorSet->filename());
575 
576     QFileInfo fileInfo(saveLocation + name);
577 
578     colorSet->setFilename(fileInfo.filePath());
579     colorSet->setIsGlobal(true);
580     m_d->rServer->removeFromBlacklist(colorSet);
581     if (!colorSet->save()) {
582         QMessageBox message;
583         message.setWindowTitle(i18n("Saving palette failed"));
584         message.setText(i18n("Failed to save global palette file. Please set it to non-global, or you will lose the file when you close Krita"));
585         message.exec();
586     }
587 
588     uploadPaletteList();
589 }
590 
duplicateExistsFilename(const QString & filename,bool global) const591 bool KisPaletteEditor::duplicateExistsFilename(const QString &filename, bool global) const
592 {
593     QString prefix;
594     if (global) {
595         prefix = m_d->rServer->saveLocation();
596     }
597 
598     Q_FOREACH (const KoResource *r, KoResourceServerProvider::instance()->paletteServer()->resources()) {
599         if (r->filename() == prefix + filename && r != m_d->model->colorSet()) {
600             return true;
601         }
602     }
603 
604     return false;
605 }
606 
relativePathFromSaveLocation() const607 QString KisPaletteEditor::relativePathFromSaveLocation() const
608 {
609     return filenameFromPath(m_d->modified.filename);
610 }
611 
setNonGlobal()612 void KisPaletteEditor::setNonGlobal()
613 {
614     Q_ASSERT(m_d->model);
615     if (!m_d->view) { return; }
616     if (!m_d->view->document()) { return; }
617     if (!m_d->model->colorSet()) { return; }
618 
619     KoColorSet *colorSet = m_d->model->colorSet();
620     QString name = filenameFromPath(colorSet->filename());
621     QFile::remove(colorSet->filename());
622 
623     if (duplicateExistsFilename(name, false)) {
624         colorSet->setFilename(newPaletteFileName(false));
625     } else {
626         colorSet->setFilename(name);
627     }
628 
629     colorSet->setIsGlobal(false);
630 
631     uploadPaletteList();
632 }
633 
newPaletteFileName(bool isGlobal,const QString & filename)634 QString KisPaletteEditor::newPaletteFileName(bool isGlobal, const QString &filename)
635 {
636     QSet<QString> nameSet;
637 
638     Q_FOREACH (const KoResource *r, m_d->rServer->resources()) {
639         nameSet.insert(r->filename());
640     }
641 
642     KoColorSet tmpColorSet;
643     QString result = (filename.isEmpty() ? "new_palette" : filename);
644 
645     if (isGlobal) {
646         result = m_d->rServer->saveLocation() + result;
647     }
648 
649     int i = 0;
650     while (nameSet.contains(result + QString::number(i) + tmpColorSet.defaultFileExtension())) {
651         i++;
652     }
653     result = result + (i > 0 ? QString::number(i) : "") + tmpColorSet.defaultFileExtension();
654     return result;
655 }
656 
newGroupName() const657 QString KisPaletteEditor::newGroupName() const
658 {
659     int i = 1;
660     QString groupname = i18nc("Default new group name", "New Group %1", QString::number(i));
661     while (m_d->modified.groups.contains(groupname)) {
662         i++;
663         groupname = i18nc("Default new group name", "New Group %1", QString::number(i));
664     }
665     return groupname;
666 }
667 
uploadPaletteList() const668 void KisPaletteEditor::uploadPaletteList() const
669 {
670     QList<KoColorSet *> list;
671     Q_FOREACH (KoResource * paletteResource, m_d->rServer->resources()) {
672         KoColorSet *palette = static_cast<KoColorSet*>(paletteResource);
673         Q_ASSERT(palette);
674         if (!palette->isGlobal()) {
675             list.append(palette);
676         }
677     }
678     m_d->view->document()->setPaletteList(list);
679 }
680 
filenameFromPath(const QString & path) const681 QString KisPaletteEditor::filenameFromPath(const QString &path) const
682 {
683     return QDir::fromNativeSeparators(path).section('/', -1, -1);
684 }
685