File indexing completed on 2024-05-19 04:29:28

0001 /*
0002  *  SPDX-FileCopyrightText: 2013 Sven Langkamp <sven.langkamp@gmail.com>
0003  *  SPDX-FileCopyrightText: 2018 Michael Zhou <simeirxh@gmail.com>
0004  *  SPDX-FileCopyrightText: 2022 Halla Rempt <halla@valdyas.org>
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_colorSet->isGroupTitleRow(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) return 0;
0054     return m_colorSet->rowCountWithTitles();
0055 }
0056 
0057 int KisPaletteModel::columnCount(const QModelIndex& /*parent*/) const
0058 {
0059     if (m_colorSet && m_colorSet->columnCount() > 0) {
0060         return m_colorSet->columnCount();
0061     }
0062     if (!m_colorSet) {
0063         return 0;
0064     }
0065     return 16;
0066 }
0067 
0068 Qt::ItemFlags KisPaletteModel::flags(const QModelIndex& index) const
0069 {
0070     if (index.isValid()) {
0071         return  Qt::ItemIsSelectable |
0072                 Qt::ItemIsEnabled |
0073                 Qt::ItemIsUserCheckable |
0074                 Qt::ItemIsDragEnabled |
0075                 Qt::ItemIsDropEnabled;
0076     }
0077     return Qt::ItemIsDropEnabled;
0078 }
0079 
0080 QModelIndex KisPaletteModel::index(int row, int column, const QModelIndex& parent) const
0081 {
0082     Q_UNUSED(parent);
0083 
0084     KisSwatchGroupSP group = 0;
0085     if (m_colorSet) {
0086         group = m_colorSet->getGroup(row);
0087     }
0088     else {
0089         return {};
0090     }
0091 
0092     if (!group) {
0093         qDebug() << "no group for row" << row << "col" << column << "total rows in model" << rowCount() << "rows in colorset" << m_colorSet->rowCountWithTitles();
0094         return QModelIndex();
0095     }
0096     //KIS_ASSERT_RECOVER_RETURN_VALUE(group, QModelIndex());
0097     QModelIndex idx = createIndex(row, column);
0098     Q_ASSERT(idx.column() < columnCount());
0099     Q_ASSERT(idx.row() < rowCount());
0100     return idx;
0101 }
0102 
0103 void KisPaletteModel::setColorSet(KoColorSetSP colorSet)
0104 {
0105     beginResetModel();
0106     m_colorSet = colorSet;
0107     if (colorSet) {
0108         connect(colorSet.data(), SIGNAL(modified()), this, SIGNAL(sigPaletteModified()));
0109     }
0110     endResetModel();
0111     emit sigPaletteChanged();
0112 }
0113 
0114 KoColorSetSP KisPaletteModel::colorSet() const
0115 {
0116     return m_colorSet;
0117 }
0118 
0119 int KisPaletteModel::rowNumberInGroup(int rowInModel) const
0120 {
0121     return m_colorSet->rowNumberInGroup(rowInModel);
0122 }
0123 
0124 
0125 void KisPaletteModel::addSwatch(const KisSwatch &entry, const QString &groupName)
0126 {
0127     beginInsertRows(QModelIndex(), rowCount(), rowCount() + 1);
0128     m_colorSet->addSwatch(entry, groupName);
0129     endInsertRows();
0130 }
0131 
0132 void KisPaletteModel::removeSwatch(const QModelIndex &index, bool keepColors)
0133 {
0134     KisSwatchGroupSP group = m_colorSet->getGroup(index.row());
0135     if (!qvariant_cast<bool>(data(index, IsGroupNameRole))) {
0136         m_colorSet->removeSwatch(index.column(),
0137                                  rowNumberInGroup(index.row()),
0138                                  group);
0139         emit dataChanged(index, index);
0140     } else {
0141         int groupNameRow = m_colorSet->startRowForGroup(group->name());
0142         QString groupName = m_colorSet->getGroup(groupNameRow)->name();
0143         removeGroup(groupName, keepColors);
0144     }
0145 }
0146 
0147 void KisPaletteModel::removeGroup(const QString &groupName, bool keepColors)
0148 {
0149     int removeStart = m_colorSet->startRowForGroup(groupName);
0150     int removedRowCount = m_colorSet->getGroup(groupName)->rowCount();
0151 
0152     beginRemoveRows(QModelIndex(), removeStart, removeStart + removedRowCount);
0153     m_colorSet->removeGroup(groupName, keepColors);
0154     endRemoveRows();
0155 }
0156 
0157 bool KisPaletteModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
0158                                    int row, int column, const QModelIndex &parent)
0159 {
0160     Q_UNUSED(row);
0161     Q_UNUSED(column);
0162     if (!data->hasFormat("krita/x-colorsetentry") && !data->hasFormat("krita/x-colorsetgroup")) {
0163         return false;
0164     }
0165     if (action == Qt::IgnoreAction) {
0166         return false;
0167     }
0168 
0169     QModelIndex finalIndex = parent;
0170     if (!finalIndex.isValid()) { return false; }
0171 
0172     if (data->hasFormat("krita/x-colorsetgroup")) {
0173         // dragging group not supported for now
0174         QByteArray encodedData = data->data("krita/x-colorsetgroup");
0175         QDataStream stream(&encodedData, QIODevice::ReadOnly);
0176 
0177         while (!stream.atEnd()) {
0178             QString groupNameDroppedOn = qvariant_cast<QString>(finalIndex.data(GroupNameRole));
0179             if (groupNameDroppedOn == KoColorSet::GLOBAL_GROUP_NAME) {
0180                 return false;
0181             }
0182             QString groupNameDragged;
0183             stream >> groupNameDragged;
0184             KisSwatchGroupSP groupDragged = m_colorSet->getGroup(groupNameDragged);
0185             int start = m_colorSet->startRowForGroup(groupNameDragged);
0186             int end = start + groupDragged->rowCount();
0187             if (!beginMoveRows(QModelIndex(), start, end, QModelIndex(), m_colorSet->startRowForGroup(groupNameDroppedOn))) {
0188                 return false;
0189             }
0190             m_colorSet->moveGroup(groupNameDragged, groupNameDroppedOn);
0191             endMoveRows();
0192             emit sigPaletteModified();
0193         }
0194         return true;
0195     }
0196 
0197     if (qvariant_cast<bool>(finalIndex.data(KisPaletteModel::IsGroupNameRole))) {
0198         return true;
0199     }
0200 
0201 
0202     if (data->hasFormat("krita/x-colorsetentry")) {
0203         QByteArray encodedData = data->data("krita/x-colorsetentry");
0204         QString oldGroupName;
0205         int oriRow;
0206         int oriColumn;
0207         KisSwatch entry = KisSwatch::fromByteArray(encodedData, oldGroupName, oriRow, oriColumn);
0208 
0209         if (action == Qt::MoveAction){
0210             KisSwatchGroupSP g = m_colorSet->getGroup(oldGroupName);
0211             if (g) {
0212                 if (qvariant_cast<bool>(finalIndex.data(KisPaletteModel::CheckSlotRole))) {
0213                     m_colorSet->addSwatch(getSwatch(finalIndex), g->name(), oriColumn, oriRow);
0214                 } else {
0215                     m_colorSet->removeSwatch(oriColumn, oriRow, g);
0216                 }
0217             }
0218             setSwatch(entry, finalIndex);
0219             emit sigPaletteModified();
0220         }
0221 
0222         return true;
0223     }
0224 
0225     return false;
0226 }
0227 
0228 QMimeData *KisPaletteModel::mimeData(const QModelIndexList &indexes) const
0229 {
0230     QMimeData *mimeData = new QMimeData();
0231     QByteArray encodedData;
0232 
0233     QDataStream stream(&encodedData, QIODevice::WriteOnly);
0234     QModelIndex index = indexes.last();
0235     if (index.isValid() && qvariant_cast<bool>(index.data(CheckSlotRole))) {
0236         QString mimeTypeName = "krita/x-colorsetentry";
0237         if (qvariant_cast<bool>(index.data(IsGroupNameRole))==false) {
0238             KisSwatch entry = getSwatch(index);
0239             QString groupName = qvariant_cast<QString>(index.data(KisPaletteModel::GroupNameRole));
0240             entry.writeToStream(stream,
0241                                 groupName,
0242                                 rowNumberInGroup(index.row()),
0243                                 index.column());
0244         } else {
0245             mimeTypeName = "krita/x-colorsetgroup";
0246             QString groupName = qvariant_cast<QString>(index.data(GroupNameRole));
0247             stream << groupName;
0248         }
0249         mimeData->setData(mimeTypeName, encodedData);
0250     }
0251 
0252     return mimeData;
0253 }
0254 
0255 QStringList KisPaletteModel::mimeTypes() const
0256 {
0257     return QStringList() << "krita/x-colorsetentry" << "krita/x-colorsetgroup";
0258 }
0259 
0260 Qt::DropActions KisPaletteModel::supportedDropActions() const
0261 {
0262     return Qt::MoveAction;
0263 }
0264 
0265 void KisPaletteModel::setSwatch(const KisSwatch &entry, const QModelIndex &index)
0266 {
0267     if (m_colorSet->isGroupTitleRow(index.row())) return;
0268 
0269     Q_ASSERT(index.column() < m_colorSet->columnCount());
0270     Q_ASSERT(index.column() < columnCount());
0271 
0272     KisSwatchGroupSP group = m_colorSet->getGroup(index.row());
0273     Q_ASSERT(group);
0274 
0275     m_colorSet->addSwatch(entry, group->name(), index.column(), rowNumberInGroup(index.row()));
0276 
0277     emit dataChanged(index, index);
0278 }
0279 
0280 void KisPaletteModel::changeGroupName(const QString &groupName, const QString &newName)
0281 {
0282     beginResetModel();
0283     m_colorSet->changeGroupName(groupName, newName);
0284     endResetModel();
0285 }
0286 
0287 KisSwatchGroupSP KisPaletteModel::addGroup(const QString &groupName, int _columnCount, int _rowCount)
0288 {
0289     beginInsertRows(QModelIndex(), rowCount(), rowCount() + _rowCount);
0290     m_colorSet->addGroup(groupName, _columnCount, _rowCount);
0291     endInsertRows();
0292     return m_colorSet->getGroup(groupName);
0293 }
0294 
0295 void KisPaletteModel::setRowCountForGroup(const QString &groupName, int rowCount)
0296 {
0297     beginResetModel();
0298     KisSwatchGroupSP g = m_colorSet->getGroup(groupName);
0299     if (g) {
0300         g->setRowCount(rowCount);
0301     }
0302     endResetModel();
0303 }
0304 
0305 void KisPaletteModel::setColumnCount(int colCount)
0306 {
0307     beginResetModel();
0308     m_colorSet->setColumnCount(colCount);
0309     endResetModel();
0310 }
0311 
0312 void KisPaletteModel::clear()
0313 {
0314     beginResetModel();
0315     m_colorSet->clear();
0316     endResetModel();
0317 }
0318 
0319 void KisPaletteModel::clear(int defaultColumnsCount)
0320 {
0321     beginResetModel();
0322     m_colorSet->clear();
0323     m_colorSet->setColumnCount(defaultColumnsCount);
0324     endResetModel();
0325 }
0326 
0327 QVariant KisPaletteModel::dataForGroupNameRow(const QModelIndex &idx, int role) const
0328 {
0329     KisSwatchGroupSP group = m_colorSet->getGroup(idx.row());
0330     Q_ASSERT(group);
0331     QString groupName = group->name();
0332     switch (role) {
0333     case Qt::ToolTipRole:
0334     case Qt::DisplayRole: {
0335         return groupName;
0336     }
0337     case GroupNameRole: {
0338         return groupName;
0339     }
0340     case CheckSlotRole: {
0341         return true;
0342     }
0343     case RowInGroupRole: {
0344         return -1;
0345     }
0346     default: {
0347         return QVariant();
0348     }
0349     }
0350 }
0351 
0352 QVariant KisPaletteModel::dataForSwatch(const QModelIndex &idx, int role) const
0353 {
0354     KisSwatchGroupSP group = m_colorSet->getGroup(idx.row());
0355     Q_ASSERT(group);
0356     int rowInGroup = rowNumberInGroup(idx.row());
0357     bool entryPresent = group->checkSwatchExists(idx.column(), rowInGroup);
0358     KisSwatch entry;
0359     if (entryPresent) {
0360         entry = group->getSwatch(idx.column(), rowInGroup);
0361     }
0362     switch (role) {
0363     case Qt::ToolTipRole:
0364     case Qt::DisplayRole: {
0365         return entryPresent ? entry.name() + "\n(" + KoColor::toQString(entry.color()) + ")" : i18n("Empty slot");
0366     }
0367     case Qt::BackgroundRole: {
0368         QColor color(0, 0, 0, 0);
0369         if (entryPresent) {
0370             color = m_displayRenderer->toQColor(entry.color());
0371         }
0372         return QBrush(color);
0373     }
0374     case GroupNameRole: {
0375         return group->name();
0376     }
0377     case CheckSlotRole: {
0378         return entryPresent;
0379     }
0380     case RowInGroupRole: {
0381         return rowInGroup;
0382     }
0383     default: {
0384         return QVariant();
0385     }
0386     }
0387 }
0388 
0389 void KisPaletteModel::setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer)
0390 {
0391     if (displayRenderer) {
0392         if (m_displayRenderer) {
0393             disconnect(m_displayRenderer, 0, this, 0);
0394         }
0395         m_displayRenderer = displayRenderer;
0396         connect(m_displayRenderer, SIGNAL(displayConfigurationChanged()),
0397                 SLOT(slotDisplayConfigurationChanged()), Qt::UniqueConnection);
0398     } else {
0399         m_displayRenderer = KoDumbColorDisplayRenderer::instance();
0400     }
0401 }
0402 
0403 void KisPaletteModel::slotDisplayConfigurationChanged()
0404 {
0405     beginResetModel();
0406     endResetModel();
0407 }
0408 
0409 void KisPaletteModel::slotPaletteModified()
0410 {
0411     /**
0412      * Until we implement resource->convertToSerializable() we should
0413      * explicitly convert all the palettes into Krita internal format
0414      */
0415     if (m_colorSet->paletteType() != KoColorSet::KPL || m_colorSet->paletteType() != KoColorSet::GPL) {
0416         m_colorSet->setPaletteType(KoColorSet::KPL);
0417     }
0418 
0419     if (m_colorSet->paletteType() == KoColorSet::KPL) {
0420         m_colorSet->setFilename(QFileInfo(m_colorSet->filename()).completeBaseName() + ".kpl");
0421     }
0422     else if (m_colorSet->paletteType() == KoColorSet::GPL) {
0423         m_colorSet->setFilename(QFileInfo(m_colorSet->filename()).completeBaseName() + ".gpl");
0424     }
0425 }
0426 
0427 void KisPaletteModel::slotExternalPaletteModified(QSharedPointer<KoColorSet> resource)
0428 {
0429     if (resource && resource == m_colorSet) {
0430         slotPaletteModified();
0431         slotDisplayConfigurationChanged();
0432     }
0433 }
0434 
0435 QModelIndex KisPaletteModel::indexForClosest(const KoColor &compare)
0436 {
0437     KisSwatchGroup::SwatchInfo info = colorSet()->getClosestSwatchInfo(compare);
0438     return createIndex(indexRowForInfo(info), info.column, colorSet()->getGroup(info.group).data());
0439 }
0440 
0441 int KisPaletteModel::indexRowForInfo(const KisSwatchGroup::SwatchInfo &info)
0442 {
0443     int groupRow = m_colorSet->startRowForGroup(info.group);
0444     if (info.group.isEmpty()) {
0445         return groupRow + info.row;
0446     }
0447     return groupRow + info.row + 1;
0448 }
0449 
0450 KisSwatch KisPaletteModel::getSwatch(const QModelIndex &index) const
0451 {
0452     if (index.row() >= rowCount()) return KisSwatch();
0453     if (index.row() < 0) return KisSwatch();
0454 
0455     return m_colorSet->getColorGlobal(index.column(), index.row());
0456 }