Krita Source Code Documentation
Loading...
Searching...
No Matches
KisPaletteModel.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2013 Sven Langkamp <sven.langkamp@gmail.com>
3 * SPDX-FileCopyrightText: 2018 Michael Zhou <simeirxh@gmail.com>
4 * SPDX-FileCopyrightText: 2022 Halla Rempt <halla@valdyas.org>
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8#include "KisPaletteModel.h"
9
10#include <QBrush>
11#include <QDomDocument>
12#include <QDomElement>
13#include <QMimeData>
14
15#include <KoColor.h>
16
17#include <KoColorSpace.h>
21#include <KisResourceModel.h>
22#include <QFileInfo>
23#include <QScopedValueRollback>
24
26 : QAbstractTableModel(parent)
27 , m_colorSet(0)
28 , m_displayRenderer(KoDumbColorDisplayRenderer::instance())
29{
30 connect(this, SIGNAL(sigPaletteModified()), SLOT(slotPaletteModified()));
31}
32
36
37QVariant KisPaletteModel::data(const QModelIndex& index, int role) const
38{
39 if (!index.isValid()) { return QVariant(); }
40 bool groupNameRow = m_colorSet->isGroupTitleRow(index.row());
41 if (role == IsGroupNameRole) {
42 return groupNameRow;
43 }
44 if (groupNameRow) {
45 return dataForGroupNameRow(index, role);
46 } else {
47 return dataForSwatch(index, role);
48 }
49}
50
51int KisPaletteModel::rowCount(const QModelIndex& /*parent*/) const
52{
53 if (!m_colorSet) return 0;
54 return m_colorSet->rowCountWithTitles();
55}
56
57int KisPaletteModel::columnCount(const QModelIndex& /*parent*/) const
58{
59 if (m_colorSet && m_colorSet->columnCount() > 0) {
60 return m_colorSet->columnCount();
61 }
62 if (!m_colorSet) {
63 return 0;
64 }
65 return 16;
66}
67
68Qt::ItemFlags KisPaletteModel::flags(const QModelIndex& index) const
69{
70 if (index.isValid()) {
71 return Qt::ItemIsSelectable |
72 Qt::ItemIsEnabled |
73 Qt::ItemIsUserCheckable |
74 Qt::ItemIsDragEnabled |
75 Qt::ItemIsDropEnabled;
76 }
77 return Qt::ItemIsDropEnabled;
78}
79
80QModelIndex KisPaletteModel::index(int row, int column, const QModelIndex& parent) const
81{
82 Q_UNUSED(parent);
83
84 KisSwatchGroupSP group = 0;
85 if (m_colorSet) {
86 group = m_colorSet->getGroup(row);
87 }
88 else {
89 return {};
90 }
91
92 if (!group) {
93 qDebug() << "no group for row" << row << "col" << column << "total rows in model" << rowCount() << "rows in colorset" << m_colorSet->rowCountWithTitles();
94 return QModelIndex();
95 }
96 //KIS_ASSERT_RECOVER_RETURN_VALUE(group, QModelIndex());
97 QModelIndex idx = createIndex(row, column);
98 Q_ASSERT(idx.column() < columnCount());
99 Q_ASSERT(idx.row() < rowCount());
100 return idx;
101}
102
104{
105 if (colorSet == m_colorSet) {
106 return;
107 }
108
109 beginResetModel();
110 m_colorSet = colorSet;
111 if (m_colorSet) {
112 m_colorSet->disconnect(this);
113 }
114 if (colorSet) {
115 connect(colorSet.data(), SIGNAL(modified()), this, SIGNAL(sigPaletteModified()));
116 connect(colorSet.data(), SIGNAL(layoutChanged()), this, SLOT(slotLayoutChanged()));
117 connect(colorSet.data(), SIGNAL(layoutAboutToChange()), this, SLOT(slotLayoutAboutToChange()));
118 connect(colorSet.data(), SIGNAL(entryChanged(int,int)), this, SLOT(slotEntryChanged(int,int)));
119 }
120 endResetModel();
121 Q_EMIT sigPaletteChanged();
122}
123
125{
126 return m_colorSet;
127}
128
129int KisPaletteModel::rowNumberInGroup(int rowInModel) const
130{
131 return m_colorSet->rowNumberInGroup(rowInModel);
132}
133
134
135void KisPaletteModel::addSwatch(const KisSwatch &entry, const QString &groupName)
136{
137 beginInsertRows(QModelIndex(), rowCount(), rowCount() + 1);
138 m_colorSet->addSwatch(entry, groupName);
139 endInsertRows();
140}
141
142void KisPaletteModel::removeSwatch(const QModelIndex &index, bool keepColors)
143{
144 if (!index.isValid()) { return; }
145
146 KisSwatchGroupSP group = m_colorSet->getGroup(index.row());
147 if (!qvariant_cast<bool>(data(index, IsGroupNameRole))) {
148 m_colorSet->removeSwatch(index.column(),
149 rowNumberInGroup(index.row()),
150 group);
151 Q_EMIT dataChanged(index, index);
152 } else {
153 int groupNameRow = m_colorSet->startRowForGroup(group->name());
154 QString groupName = m_colorSet->getGroup(groupNameRow)->name();
155 removeGroup(groupName, keepColors);
156 }
157}
158
159void KisPaletteModel::removeGroup(const QString &groupName, bool keepColors)
160{
161 QScopedValueRollback editMarker(m_editing, true);
162 int removeStart = m_colorSet->startRowForGroup(groupName);
163 int removedRowCount = m_colorSet->getGroup(groupName)->rowCount();
164
165 beginRemoveRows(QModelIndex(), removeStart, removeStart + removedRowCount);
166 m_colorSet->removeGroup(groupName, keepColors);
167 endRemoveRows();
168}
169
170bool KisPaletteModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
171 int row, int column, const QModelIndex &parent)
172{
173 Q_UNUSED(row);
174 Q_UNUSED(column);
175 if (!data->hasFormat("krita/x-colorsetentry") && !data->hasFormat("krita/x-colorsetgroup")) {
176 return false;
177 }
178 if (action == Qt::IgnoreAction) {
179 return false;
180 }
181
182 QModelIndex finalIndex = parent;
183 if (!finalIndex.isValid()) { return false; }
184
185 if (data->hasFormat("krita/x-colorsetgroup")) {
186 QScopedValueRollback editMarker(m_editing, true);
187 QByteArray encodedData = data->data("krita/x-colorsetgroup");
188 QDataStream stream(&encodedData, QIODevice::ReadOnly);
189
190 while (!stream.atEnd()) {
191 QString groupNameDroppedOn = qvariant_cast<QString>(finalIndex.data(GroupNameRole));
192 if (groupNameDroppedOn == KoColorSet::GLOBAL_GROUP_NAME) {
193 return false;
194 }
195 QString groupNameDragged;
196 stream >> groupNameDragged;
197 KisSwatchGroupSP groupDragged = m_colorSet->getGroup(groupNameDragged);
198 int start = m_colorSet->startRowForGroup(groupNameDragged);
199 int end = start + groupDragged->rowCount();
200 if (!beginMoveRows(QModelIndex(), start, end, QModelIndex(), m_colorSet->startRowForGroup(groupNameDroppedOn))) {
201 return false;
202 }
203 m_colorSet->moveGroup(groupNameDragged, groupNameDroppedOn);
204 endMoveRows();
205 }
206 return true;
207 }
208
209 if (qvariant_cast<bool>(finalIndex.data(KisPaletteModel::IsGroupNameRole))) {
210 return true;
211 }
212
213
214 if (data->hasFormat("krita/x-colorsetentry")) {
215 QByteArray encodedData = data->data("krita/x-colorsetentry");
216 QString oldGroupName;
217 int oriRow;
218 int oriColumn;
219 KisSwatch entry = KisSwatch::fromByteArray(encodedData, oldGroupName, oriRow, oriColumn);
220
221 if (action == Qt::MoveAction){
222 KisSwatchGroupSP g = m_colorSet->getGroup(oldGroupName);
223 if (g) {
224 if (qvariant_cast<bool>(finalIndex.data(KisPaletteModel::CheckSlotRole))) {
225 m_colorSet->addSwatch(getSwatch(finalIndex), g->name(), oriColumn, oriRow);
226 } else {
227 m_colorSet->removeSwatch(oriColumn, oriRow, g);
228 }
229 }
230 setSwatch(entry, finalIndex);
231 }
232
233 return true;
234 }
235
236 return false;
237}
238
239QMimeData *KisPaletteModel::mimeData(const QModelIndexList &indexes) const
240{
241 QMimeData *mimeData = new QMimeData();
242 QByteArray encodedData;
243
244 QDataStream stream(&encodedData, QIODevice::WriteOnly);
245 QModelIndex index = indexes.last();
246 if (index.isValid() && qvariant_cast<bool>(index.data(CheckSlotRole))) {
247 QString mimeTypeName = "krita/x-colorsetentry";
248 if (qvariant_cast<bool>(index.data(IsGroupNameRole))==false) {
249 KisSwatch entry = getSwatch(index);
250 QString groupName = qvariant_cast<QString>(index.data(KisPaletteModel::GroupNameRole));
251 entry.writeToStream(stream,
252 groupName,
253 rowNumberInGroup(index.row()),
254 index.column());
255 } else {
256 mimeTypeName = "krita/x-colorsetgroup";
257 QString groupName = qvariant_cast<QString>(index.data(GroupNameRole));
258 stream << groupName;
259 }
260 mimeData->setData(mimeTypeName, encodedData);
261 }
262
263 return mimeData;
264}
265
267{
268 return QStringList() << "krita/x-colorsetentry" << "krita/x-colorsetgroup";
269}
270
272{
273 return Qt::MoveAction;
274}
275
276void KisPaletteModel::setSwatch(const KisSwatch &entry, const QModelIndex &index)
277{
278 if (m_colorSet->isGroupTitleRow(index.row())) return;
279
280 Q_ASSERT(index.column() < m_colorSet->columnCount());
281 Q_ASSERT(index.column() < columnCount());
282
283 KisSwatchGroupSP group = m_colorSet->getGroup(index.row());
284 Q_ASSERT(group);
285
286 m_colorSet->addSwatch(entry, group->name(), index.column(), rowNumberInGroup(index.row()));
287
288 Q_EMIT dataChanged(index, index);
289}
290
291void KisPaletteModel::changeGroupName(const QString &groupName, const QString &newName)
292{
293 QScopedValueRollback editMarker(m_editing, true);
294 beginResetModel();
295 m_colorSet->changeGroupName(groupName, newName);
296 endResetModel();
297}
298
299KisSwatchGroupSP KisPaletteModel::addGroup(const QString &groupName, int _columnCount, int _rowCount)
300{
301 QScopedValueRollback editMarker(m_editing, true);
302 beginInsertRows(QModelIndex(), rowCount(), rowCount() + _rowCount);
303 m_colorSet->addGroup(groupName, _columnCount, _rowCount);
304 endInsertRows();
305 return m_colorSet->getGroup(groupName);
306}
307
308void KisPaletteModel::setRowCountForGroup(const QString &groupName, int rowCount)
309{
310 QScopedValueRollback editMarker(m_editing, true);
311 beginResetModel();
312 KisSwatchGroupSP g = m_colorSet->getGroup(groupName);
313 if (g) {
314 g->setRowCount(rowCount);
315 }
316 endResetModel();
317}
318
320{
321 m_colorSet->setColumnCount(colCount);
322}
323
325{
326 m_colorSet->clear();
327}
328
329void KisPaletteModel::clear(int defaultColumnsCount)
330{
331 QScopedValueRollback editMarker(m_editing, true);
332 beginResetModel();
333 m_colorSet->clear();
334 m_colorSet->setColumnCount(defaultColumnsCount);
335 endResetModel();
336}
337
338QVariant KisPaletteModel::dataForGroupNameRow(const QModelIndex &idx, int role) const
339{
340 KisSwatchGroupSP group = m_colorSet->getGroup(idx.row());
341 Q_ASSERT(group);
342 QString groupName = group->name();
343 switch (role) {
344 case Qt::ToolTipRole:
345 case Qt::DisplayRole: {
346 return groupName;
347 }
348 case GroupNameRole: {
349 return groupName;
350 }
351 case CheckSlotRole: {
352 return true;
353 }
354 case RowInGroupRole: {
355 return -1;
356 }
357 default: {
358 return QVariant();
359 }
360 }
361}
362
363QVariant KisPaletteModel::dataForSwatch(const QModelIndex &idx, int role) const
364{
365 KisSwatchGroupSP group = m_colorSet->getGroup(idx.row());
366 Q_ASSERT(group);
367 int rowInGroup = rowNumberInGroup(idx.row());
368 bool entryPresent = group->checkSwatchExists(idx.column(), rowInGroup);
369 KisSwatch entry;
370 if (entryPresent) {
371 entry = group->getSwatch(idx.column(), rowInGroup);
372 }
373 switch (role) {
374 case Qt::ToolTipRole:
375 case Qt::DisplayRole: {
376 return entryPresent ? entry.name() + "\n(" + KoColor::toQString(entry.color()) + ")" : i18n("Empty slot");
377 }
378 case Qt::BackgroundRole: {
379 QColor color(0, 0, 0, 0);
380 if (entryPresent) {
381 color = m_displayRenderer->toQColor(entry.color());
382 }
383 return QBrush(color);
384 }
385 case GroupNameRole: {
386 return group->name();
387 }
388 case CheckSlotRole: {
389 return entryPresent;
390 }
391 case RowInGroupRole: {
392 return rowInGroup;
393 }
394 default: {
395 return QVariant();
396 }
397 }
398}
399
401{
402 if (displayRenderer) {
403 if (m_displayRenderer) {
404 disconnect(m_displayRenderer, 0, this, 0);
405 }
406 m_displayRenderer = displayRenderer;
407 connect(m_displayRenderer, SIGNAL(displayConfigurationChanged()),
408 SLOT(slotDisplayConfigurationChanged()), Qt::UniqueConnection);
409 } else {
411 }
412}
413
415{
416 beginResetModel();
417 endResetModel();
418}
419
421{
426 if (m_colorSet->paletteType() != KoColorSet::KPL || m_colorSet->paletteType() != KoColorSet::GPL) {
427 m_colorSet->setPaletteType(KoColorSet::KPL);
428 }
429
430 if (m_colorSet->paletteType() == KoColorSet::KPL) {
431 m_colorSet->setFilename(QFileInfo(m_colorSet->filename()).completeBaseName() + ".kpl");
432 }
433 else if (m_colorSet->paletteType() == KoColorSet::GPL) {
434 m_colorSet->setFilename(QFileInfo(m_colorSet->filename()).completeBaseName() + ".gpl");
435 }
436}
437
439{
440 // when m_editing is true, we have the information about model changes and don't need to reset
441 if (!m_editing) {
442 beginResetModel();
443 }
444}
445
447{
448 if (!m_editing) {
449 endResetModel();
450 }
451}
452
453void KisPaletteModel::slotEntryChanged(int column, int row)
454{
455 QModelIndex index = createIndex(row, column);
456 Q_EMIT dataChanged(index, index);
457}
458
460{
461 if (resource && resource == m_colorSet) {
464 }
465}
466
467QModelIndex KisPaletteModel::indexForClosest(const KoColor &compare)
468{
469 KisSwatchGroup::SwatchInfo info = colorSet()->getClosestSwatchInfo(compare);
470 return createIndex(indexRowForInfo(info), info.column, colorSet()->getGroup(info.group).data());
471}
472
473int KisPaletteModel::indexRowForInfo(const KisSwatchGroup::SwatchInfo &info)
474{
475 int groupRow = m_colorSet->startRowForGroup(info.group);
476 if (info.group.isEmpty()) {
477 return groupRow + info.row;
478 }
479 return groupRow + info.row + 1;
480}
481
482KisSwatch KisPaletteModel::getSwatch(const QModelIndex &index) const
483{
484 if (index.row() >= rowCount()) return KisSwatch();
485 if (index.row() < 0) return KisSwatch();
486
487 return m_colorSet->getColorGlobal(index.column(), index.row());
488}
QList< QString > QStringList
PythonPluginManager * instance
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
void slotExternalPaletteModified(QSharedPointer< KoColorSet > resource)
QModelIndex indexForClosest(const KoColor &compare)
void sigPaletteModified()
sigPaletteModified emitted when palette associated with the model is modified
int columnCount(const QModelIndex &parent=QModelIndex()) const override
void changeGroupName(const QString &groupName, const QString &newName)
void setRowCountForGroup(const QString &groupName, int rowCount)
QPointer< const KoColorDisplayRendererInterface > m_displayRenderer
void removeSwatch(const QModelIndex &index, bool keepColors=true)
void setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer)
QVariant dataForSwatch(const QModelIndex &idx, int role) const
void removeGroup(const QString &groupName, bool keepColors)
void slotDisplayConfigurationChanged()
void addSwatch(const KisSwatch &entry, const QString &groupName=KoColorSet::GLOBAL_GROUP_NAME)
void setColorSet(KoColorSetSP colorSet)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
int indexRowForInfo(const KisSwatchGroup::SwatchInfo &info)
KisPaletteModel(QObject *parent=0)
~KisPaletteModel() override
KisSwatch getSwatch(const QModelIndex &index) const
void slotEntryChanged(int column, int row)
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
void setColumnCount(int colCount)
int rowNumberInGroup(int rowInModel) const
Qt::DropActions supportedDropActions() const override
Qt::ItemFlags flags(const QModelIndex &index) const override
QVariant dataForGroupNameRow(const QModelIndex &idx, int role) const
KoColorSetSP colorSet() const
KisSwatchGroupSP addGroup(const QString &groupName, int columnCount=KisSwatchGroup::DEFAULT_COLUMN_COUNT, int rowCount=KisSwatchGroup::DEFAULT_ROW_COUNT)
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void sigPaletteChanged()
sigPaletteChanged emitted when the palette associated with the model is changed for another palette
QStringList mimeTypes() const override
QMimeData * mimeData(const QModelIndexList &indexes) const override
void setSwatch(const KisSwatch &entry, const QModelIndex &index)
void writeToStream(QDataStream &stream, const QString &groupName, int originalRow, int originalColumn)
Definition KisSwatch.cpp:44
KoColor color() const
Definition KisSwatch.h:30
QString name() const
Definition KisSwatch.h:24
static KisSwatch fromByteArray(QByteArray &data, QString &groupName, int &originalRow, int &originalColumn)
Definition KisSwatch.cpp:57
static const QString GLOBAL_GROUP_NAME
Definition KoColorSet.h:33
static QString toQString(const KoColor &color)
toQString create a user-visible string of the channel names and the channel values
Definition KoColor.cpp:655
static KoColorDisplayRendererInterface * instance()