File indexing completed on 2024-05-12 16:02:04

0001 /*
0002  *  SPDX-FileCopyrightText: 2013 Sven Langkamp <sven.langkamp@gmail.com>
0003  *  SPDX-FileCopyrightText: 2018 Michael Zhou <simeirxh@gmail.com>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #include "KisPaletteModel.h"
0009 
0010 #include <QBrush>
0011 #include <QDomDocument>
0012 #include <QDomElement>
0013 #include <QMimeData>
0014 
0015 #include <KoColor.h>
0016 
0017 #include <KoColorSpace.h>
0018 #include <KoColorModelStandardIds.h>
0019 #include <resources/KoColorSet.h>
0020 #include <KoColorDisplayRendererInterface.h>
0021 #include <KisResourceModel.h>
0022 #include <QFileInfo>
0023 
0024 
0025 KisPaletteModel::KisPaletteModel(QObject* parent)
0026     : QAbstractTableModel(parent)
0027     , m_colorSet(0)
0028     , m_displayRenderer(KoDumbColorDisplayRenderer::instance())
0029 {
0030     connect(this, SIGNAL(sigPaletteModified()), SLOT(slotPaletteModified()));
0031 }
0032 
0033 KisPaletteModel::~KisPaletteModel()
0034 {
0035 }
0036 
0037 QVariant KisPaletteModel::data(const QModelIndex& index, int role) const
0038 {
0039     if (!index.isValid()) { return QVariant(); }
0040     bool groupNameRow = m_rowGroupNameMap.contains(index.row());
0041     if (role == IsGroupNameRole) {
0042         return groupNameRow;
0043     }
0044     if (groupNameRow) {
0045         return dataForGroupNameRow(index, role);
0046     } else {
0047         return dataForSwatch(index, role);
0048     }
0049 }
0050 
0051 int KisPaletteModel::rowCount(const QModelIndex& /*parent*/) const
0052 {
0053     if (!m_colorSet)
0054         return 0;
0055     return m_colorSet->rowCount() // count of color rows
0056             + m_rowGroupNameMap.size()  // rows for names
0057             - 1; // global doesn't have a name
0058 }
0059 
0060 int KisPaletteModel::columnCount(const QModelIndex& /*parent*/) const
0061 {
0062     if (m_colorSet && m_colorSet->columnCount() > 0) {
0063         return m_colorSet->columnCount();
0064     }
0065     if (!m_colorSet) {
0066         return 0;
0067     }
0068     return 16;
0069 }
0070 
0071 Qt::ItemFlags KisPaletteModel::flags(const QModelIndex& index) const
0072 {
0073     if (index.isValid()) {
0074         return  Qt::ItemIsSelectable |
0075                 Qt::ItemIsEnabled |
0076                 Qt::ItemIsUserCheckable |
0077                 Qt::ItemIsDragEnabled |
0078                 Qt::ItemIsDropEnabled;
0079     }
0080     return Qt::ItemIsDropEnabled;
0081 }
0082 
0083 QModelIndex KisPaletteModel::index(int row, int column, const QModelIndex& parent) const
0084 {
0085     Q_UNUSED(parent);
0086     Q_ASSERT(m_colorSet);
0087     if (m_rowGroupNameMap.isEmpty()) {
0088         return {};
0089     }
0090     int groupNameRow = groupNameRowForRow(row);
0091     KisSwatchGroup *group = m_colorSet->getGroup(m_rowGroupNameMap[groupNameRow]);
0092     KIS_ASSERT_RECOVER_RETURN_VALUE(group,QModelIndex());
0093     return createIndex(row, column, group);
0094 }
0095 
0096 void KisPaletteModel::resetGroupNameRows()
0097 {
0098     m_rowGroupNameMap.clear();
0099     int row = -1;
0100     for (const QString &groupName : m_colorSet->getGroupNames()) {
0101         m_rowGroupNameMap[row] = groupName;
0102         row += m_colorSet->getGroup(groupName)->rowCount();
0103         row += 1; // row for group name
0104     }
0105 }
0106 
0107 void KisPaletteModel::setPalette(KoColorSetSP palette)
0108 {
0109     beginResetModel();
0110     m_colorSet = palette;
0111     if (palette) {
0112         resetGroupNameRows();
0113     }
0114     endResetModel();
0115     emit sigPaletteChanged();
0116 }
0117 
0118 KoColorSetSP KisPaletteModel::colorSet() const
0119 {
0120     return m_colorSet;
0121 }
0122 
0123 int KisPaletteModel::rowNumberInGroup(int rowInModel) const
0124 {
0125     if (m_rowGroupNameMap.contains(rowInModel)) {
0126         return -1;
0127     }
0128     QList<int> rowNumberList = m_rowGroupNameMap.keys();
0129     for (auto it = rowNumberList.rbegin(); it != rowNumberList.rend(); it++) {
0130         if (*it < rowInModel) {
0131             return rowInModel - *it - 1;
0132         }
0133     }
0134     return rowInModel;
0135 }
0136 
0137 int KisPaletteModel::groupNameRowForName(const QString &groupName)
0138 {
0139     for (auto it = m_rowGroupNameMap.begin(); it != m_rowGroupNameMap.end(); it++) {
0140         if (it.value() == groupName) {
0141             return it.key();
0142         }
0143     }
0144     return -1;
0145 }
0146 
0147 bool KisPaletteModel::addEntry(const KisSwatch &entry, const QString &groupName)
0148 {
0149     beginInsertRows(QModelIndex(), rowCount(), rowCount() + 1);
0150     m_colorSet->add(entry, groupName);
0151     endInsertRows();
0152     emit sigPaletteModified();
0153     return true;
0154 }
0155 
0156 bool KisPaletteModel::removeEntry(const QModelIndex &index, bool keepColors)
0157 {
0158     if (!qvariant_cast<bool>(data(index, IsGroupNameRole))) {
0159         static_cast<KisSwatchGroup*>(index.internalPointer())->removeEntry(index.column(),
0160                                                                            rowNumberInGroup(index.row()));
0161         emit dataChanged(index, index);
0162     } else {
0163         int groupNameRow = groupNameRowForRow(index.row());
0164         QString groupName = m_rowGroupNameMap[groupNameRow];
0165         removeGroup(groupName, keepColors);
0166     }
0167     emit sigPaletteModified();
0168     return true;
0169 }
0170 
0171 void KisPaletteModel::removeGroup(const QString &groupName, bool keepColors)
0172 {
0173     int removeStart = groupNameRowForName(groupName);
0174     int removedRowCount = m_colorSet->getGroup(groupName)->rowCount();
0175     int insertStart = m_colorSet->getGlobalGroup()->rowCount();
0176     beginRemoveRows(QModelIndex(),
0177                     removeStart,
0178                     removeStart + removedRowCount);
0179     m_colorSet->removeGroup(groupName, keepColors);
0180     resetGroupNameRows();
0181     endRemoveRows();
0182     beginInsertRows(QModelIndex(),
0183     insertStart, m_colorSet->getGlobalGroup()->rowCount());
0184     endInsertRows();
0185     emit sigPaletteModified();
0186 }
0187 
0188 bool KisPaletteModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
0189                                    int row, int column, const QModelIndex &parent)
0190 {
0191     Q_UNUSED(row);
0192     Q_UNUSED(column);
0193     if (!data->hasFormat("krita/x-colorsetentry") && !data->hasFormat("krita/x-colorsetgroup")) {
0194         return false;
0195     }
0196     if (action == Qt::IgnoreAction) {
0197         return false;
0198     }
0199 
0200     QModelIndex finalIndex = parent;
0201     if (!finalIndex.isValid()) { return false; }
0202 
0203     if (data->hasFormat("krita/x-colorsetgroup")) {
0204         // dragging group not supported for now
0205         QByteArray encodedData = data->data("krita/x-colorsetgroup");
0206         QDataStream stream(&encodedData, QIODevice::ReadOnly);
0207 
0208         while (!stream.atEnd()) {
0209             QString groupNameDroppedOn = qvariant_cast<QString>(finalIndex.data(GroupNameRole));
0210             if (groupNameDroppedOn == KoColorSet::GLOBAL_GROUP_NAME) {
0211                 return false;
0212             }
0213             QString groupNameDragged;
0214             stream >> groupNameDragged;
0215             KisSwatchGroup *groupDragged = m_colorSet->getGroup(groupNameDragged);
0216             int start = groupNameRowForName(groupNameDragged);
0217             int end = start + groupDragged->rowCount();
0218             if (!beginMoveRows(QModelIndex(), start, end, QModelIndex(), groupNameRowForName(groupNameDroppedOn))) {
0219                 return false;
0220             }
0221             m_colorSet->moveGroup(groupNameDragged, groupNameDroppedOn);
0222             resetGroupNameRows();
0223             endMoveRows();
0224             emit sigPaletteModified();
0225         }
0226         return true;
0227     }
0228 
0229     if (qvariant_cast<bool>(finalIndex.data(KisPaletteModel::IsGroupNameRole))) {
0230         return true;
0231     }
0232 
0233 
0234     if (data->hasFormat("krita/x-colorsetentry")) {
0235         QByteArray encodedData = data->data("krita/x-colorsetentry");
0236         QString oldGroupName;
0237         int oriRow;
0238         int oriColumn;
0239         KisSwatch entry = KisSwatch::fromByteArray(encodedData, oldGroupName, oriRow, oriColumn);
0240 
0241         if (action == Qt::MoveAction){
0242             KisSwatchGroup *g = m_colorSet->getGroup(oldGroupName);
0243             if (g) {
0244                 if (qvariant_cast<bool>(finalIndex.data(KisPaletteModel::CheckSlotRole))) {
0245                     g->setEntry(getEntry(finalIndex), oriColumn, oriRow);
0246                 } else {
0247                     g->removeEntry(oriColumn, oriRow);
0248                 }
0249             }
0250             setEntry(entry, finalIndex);
0251             emit sigPaletteModified();
0252         }
0253 
0254         return true;
0255     }
0256 
0257     return false;
0258 }
0259 
0260 QMimeData *KisPaletteModel::mimeData(const QModelIndexList &indexes) const
0261 {
0262     QMimeData *mimeData = new QMimeData();
0263     QByteArray encodedData;
0264 
0265     QDataStream stream(&encodedData, QIODevice::WriteOnly);
0266     QModelIndex index = indexes.last();
0267     if (index.isValid() && qvariant_cast<bool>(index.data(CheckSlotRole))) {
0268         QString mimeTypeName = "krita/x-colorsetentry";
0269         if (qvariant_cast<bool>(index.data(IsGroupNameRole))==false) {
0270             KisSwatch entry = getEntry(index);
0271             QString groupName = qvariant_cast<QString>(index.data(KisPaletteModel::GroupNameRole));
0272             entry.writeToStream(stream,
0273                                 groupName,
0274                                 rowNumberInGroup(index.row()),
0275                                 index.column());
0276         } else {
0277             mimeTypeName = "krita/x-colorsetgroup";
0278             QString groupName = qvariant_cast<QString>(index.data(GroupNameRole));
0279             stream << groupName;
0280         }
0281         mimeData->setData(mimeTypeName, encodedData);
0282     }
0283 
0284     return mimeData;
0285 }
0286 
0287 QStringList KisPaletteModel::mimeTypes() const
0288 {
0289     return QStringList() << "krita/x-colorsetentry" << "krita/x-colorsetgroup";
0290 }
0291 
0292 Qt::DropActions KisPaletteModel::supportedDropActions() const
0293 {
0294     return Qt::MoveAction;
0295 }
0296 
0297 void KisPaletteModel::setEntry(const KisSwatch &entry,
0298                                const QModelIndex &index)
0299 {
0300     KisSwatchGroup *group = static_cast<KisSwatchGroup*>(index.internalPointer());
0301     Q_ASSERT(group);
0302     group->setEntry(entry, index.column(), rowNumberInGroup(index.row()));
0303     emit sigPaletteModified();
0304     emit dataChanged(index, index);
0305 }
0306 
0307 bool KisPaletteModel::renameGroup(const QString &groupName, const QString &newName)
0308 {
0309     beginResetModel();
0310     bool success = m_colorSet->changeGroupName(groupName, newName);
0311     for (auto it = m_rowGroupNameMap.begin(); it != m_rowGroupNameMap.end(); it++) {
0312         if (it.value() == groupName) {
0313             m_rowGroupNameMap[it.key()] = newName;
0314             break;
0315         }
0316     }
0317     endResetModel();
0318     emit sigPaletteModified();
0319     return success;
0320 }
0321 
0322 void KisPaletteModel::addGroup(const KisSwatchGroup &group)
0323 {
0324     beginInsertRows(QModelIndex(), rowCount(), rowCount() + group.rowCount());
0325     m_colorSet->addGroup(group.name());
0326     *m_colorSet->getGroup(group.name()) = group;
0327     endInsertColumns();
0328 
0329     emit sigPaletteModified();
0330 }
0331 
0332 void KisPaletteModel::setRowNumber(const QString &groupName, int rowCount)
0333 {
0334     beginResetModel();
0335     KisSwatchGroup *g = m_colorSet->getGroup(groupName);
0336     if (g) {
0337         g->setRowCount(rowCount);
0338     }
0339     endResetModel();
0340 }
0341 
0342 void KisPaletteModel::clear()
0343 {
0344     beginResetModel();
0345     m_colorSet->clear();
0346     endResetModel();
0347 }
0348 
0349 void KisPaletteModel::clear(int defaultColumnsCount)
0350 {
0351     beginResetModel();
0352     m_colorSet->clear();
0353     m_colorSet->setColumnCount(defaultColumnsCount);
0354     endResetModel();
0355 }
0356 
0357 QVariant KisPaletteModel::dataForGroupNameRow(const QModelIndex &idx, int role) const
0358 {
0359     KisSwatchGroup *group = static_cast<KisSwatchGroup*>(idx.internalPointer());
0360     Q_ASSERT(group);
0361     QString groupName = group->name();
0362     switch (role) {
0363     case Qt::ToolTipRole:
0364     case Qt::DisplayRole: {
0365         return groupName;
0366     }
0367     case GroupNameRole: {
0368         return groupName;
0369     }
0370     case CheckSlotRole: {
0371         return true;
0372     }
0373     case RowInGroupRole: {
0374         return -1;
0375     }
0376     default: {
0377         return QVariant();
0378     }
0379     }
0380 }
0381 
0382 QVariant KisPaletteModel::dataForSwatch(const QModelIndex &idx, int role) const
0383 {
0384     KisSwatchGroup *group = static_cast<KisSwatchGroup*>(idx.internalPointer());
0385     Q_ASSERT(group);
0386     int rowInGroup = rowNumberInGroup(idx.row());
0387     bool entryPresent = group->checkEntry(idx.column(), rowInGroup);
0388     KisSwatch entry;
0389     if (entryPresent) {
0390         entry = group->getEntry(idx.column(), rowInGroup);
0391     }
0392     switch (role) {
0393     case Qt::ToolTipRole:
0394     case Qt::DisplayRole: {
0395         return entryPresent ? entry.name() + "\n(" + KoColor::toQString(entry.color()) + ")" : i18n("Empty slot");
0396     }
0397     case Qt::BackgroundRole: {
0398         QColor color(0, 0, 0, 0);
0399         if (entryPresent) {
0400             color = m_displayRenderer->toQColor(entry.color());
0401         }
0402         return QBrush(color);
0403     }
0404     case GroupNameRole: {
0405         return group->name();
0406     }
0407     case CheckSlotRole: {
0408         return entryPresent;
0409     }
0410     case RowInGroupRole: {
0411         return rowInGroup;
0412     }
0413     default: {
0414         return QVariant();
0415     }
0416     }
0417 }
0418 
0419 void KisPaletteModel::setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer)
0420 {
0421     if (displayRenderer) {
0422         if (m_displayRenderer) {
0423             disconnect(m_displayRenderer, 0, this, 0);
0424         }
0425         m_displayRenderer = displayRenderer;
0426         connect(m_displayRenderer, SIGNAL(displayConfigurationChanged()),
0427                 SLOT(slotDisplayConfigurationChanged()), Qt::UniqueConnection);
0428     } else {
0429         m_displayRenderer = KoDumbColorDisplayRenderer::instance();
0430     }
0431 }
0432 
0433 void KisPaletteModel::slotDisplayConfigurationChanged()
0434 {
0435     beginResetModel();
0436     endResetModel();
0437 }
0438 
0439 void KisPaletteModel::slotPaletteModified() {
0440     /**
0441      * Until we implemement resource->convertToSerializable() we should
0442      * explictly convert all the palettes into Krita internal format
0443      */
0444     if (m_colorSet->paletteType() != KoColorSet::KPL) {
0445         m_colorSet->setPaletteType(KoColorSet::KPL);
0446         m_colorSet->setFilename(QFileInfo(m_colorSet->filename()).completeBaseName() + ".kpl");
0447         m_colorSet->setDirty(true);
0448     }
0449 }
0450 
0451 void KisPaletteModel::slotExternalPaletteModified(QSharedPointer<KoColorSet> resource)
0452 {
0453     if (resource && resource == m_colorSet) {
0454         slotPaletteModified();
0455         slotDisplayConfigurationChanged();
0456     }
0457 }
0458 
0459 QModelIndex KisPaletteModel::indexForClosest(const KoColor &compare)
0460 {
0461     KisSwatchGroup::SwatchInfo info = colorSet()->getClosestColorInfo(compare);
0462     return createIndex(indexRowForInfo(info), info.column, colorSet()->getGroup(info.group));
0463 }
0464 
0465 int KisPaletteModel::indexRowForInfo(const KisSwatchGroup::SwatchInfo &info)
0466 {
0467     for (auto it = m_rowGroupNameMap.begin(); it != m_rowGroupNameMap.end(); it++) {
0468         if (it.value() == info.group) {
0469             return it.key() + info.row + 1;
0470         }
0471     }
0472     return info.row;
0473 }
0474 
0475 KisSwatch KisPaletteModel::getEntry(const QModelIndex &index) const
0476 {
0477     KisSwatchGroup *group = static_cast<KisSwatchGroup*>(index.internalPointer());
0478     if (!group || !group->checkEntry(index.column(), rowNumberInGroup(index.row()))) {
0479         return KisSwatch();
0480     }
0481     return group->getEntry(index.column(), rowNumberInGroup(index.row()));
0482 }
0483 
0484 int KisPaletteModel::groupNameRowForRow(int rowInModel) const
0485 {
0486     return rowInModel - rowNumberInGroup(rowInModel) - 1;
0487 }