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 }