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 }