1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 #include "colorlistbox.h"
8
9 #include <cstdlib>
10 #include <QBitmap>
11 #include <QCursor>
12 #include <QEvent>
13 #include <QHelpEvent>
14 #include <QMenu>
15 #include <QPainter>
16 #include <QPersistentModelIndex>
17 #include <QPixmap>
18 #include <QSignalBlocker>
19 #include <QToolTip>
20
21 #include "colorlistmodel.h"
22 #include "commonstrings.h"
23 #include "iconmanager.h"
24 #include "sccolorengine.h"
25 #include "scconfig.h"
26 #include "scribusapp.h"
27 #include "scribusdoc.h"
28 #include "util_color.h"
29
30 class SCRIBUS_API ColorSmallItemDelegate : public ScListBoxPixmap<15, 15>
31 {
32 public:
ColorSmallItemDelegate()33 ColorSmallItemDelegate(): ScListBoxPixmap<15, 15>() {};
~ColorSmallItemDelegate()34 ~ColorSmallItemDelegate() {};
35
36 void redraw(const QVariant&) const override;
37 QString text(const QVariant&) const override;
38 };
39
40 class SCRIBUS_API ColorWideItemDelegate : public ScListBoxPixmap<30, 15>
41 {
42 public:
ColorWideItemDelegate()43 ColorWideItemDelegate(): ScListBoxPixmap<30, 15>() {};
~ColorWideItemDelegate()44 ~ColorWideItemDelegate() {};
45
46 void redraw(const QVariant&) const override;
47 QString text(const QVariant&) const override;
48 };
49
50 class SCRIBUS_API ColorFancyItemDelegate : public ScListBoxPixmap<60, 15>
51 {
52 public:
53 ColorFancyItemDelegate();
~ColorFancyItemDelegate()54 ~ColorFancyItemDelegate() {};
55
56 void iconSetChange();
57 void redraw(const QVariant&) const override;
58 QString text(const QVariant&) const override;
59
60 private:
61 QPixmap alertIcon;
62 QPixmap cmykIcon;
63 QPixmap rgbIcon;
64 QPixmap labIcon;
65 QPixmap spotIcon;
66 QPixmap regIcon;
67 };
68
ColorFancyItemDelegate()69 ColorFancyItemDelegate::ColorFancyItemDelegate() : ScListBoxPixmap<60, 15>()
70 {
71 iconSetChange();
72 }
73
redraw(const QVariant & data) const74 void ColorSmallItemDelegate::redraw(const QVariant& data) const
75 {
76 QPixmap* pPixmap = ScListBoxPixmap<15, 15>::pmap.data();
77 pPixmap->fill(Qt::transparent);
78 if (data.canConvert<ColorPixmapValue>())
79 {
80 ColorPixmapValue item(data.value<ColorPixmapValue>());
81 QColor rgb = ScColorEngine::getDisplayColor(item.m_color, item.m_doc);
82 pPixmap->fill(rgb);
83 QPainter painter(pPixmap);
84 painter.setBrush(Qt::NoBrush);
85 QPen b(Qt::black, 1);
86 painter.setPen(b);
87 painter.drawRect(0, 0, 15, 15);
88 painter.end();
89 }
90 }
91
redraw(const QVariant & data) const92 void ColorWideItemDelegate::redraw(const QVariant& data) const
93 {
94 QPixmap* pPixmap = ScListBoxPixmap<30, 15>::pmap.data();
95 pPixmap->fill(Qt::transparent);
96 if (data.canConvert<ColorPixmapValue>())
97 {
98 ColorPixmapValue item(data.value<ColorPixmapValue>());
99 QColor rgb = ScColorEngine::getDisplayColor(item.m_color, item.m_doc);
100 pPixmap->fill(rgb);
101 }
102 }
103
redraw(const QVariant & data) const104 void ColorFancyItemDelegate::redraw(const QVariant& data) const
105 {
106 static QPixmap smallPix(15, 15);
107
108 QPixmap* pPixmap = ScListBoxPixmap<60, 15>::pmap.data();
109 pPixmap->fill(Qt::transparent);
110
111 if (data.canConvert<ColorPixmapValue>())
112 {
113 ColorPixmapValue item(data.value<ColorPixmapValue>());
114
115 QColor rgb = ScColorEngine::getDisplayColor(item.m_color, item.m_doc);
116 smallPix.fill(rgb);
117 QPainter painter(&smallPix);
118 painter.setBrush(Qt::NoBrush);
119 QPen b(Qt::black, 1);
120 painter.setPen(b);
121 painter.drawRect(0, 0, 15, 15);
122 painter.end();
123
124 paintAlert(smallPix, *pPixmap, 0, 0);
125 bool isOutOfGamut = ScColorEngine::isOutOfGamut(item.m_color, item.m_doc);
126 if (isOutOfGamut)
127 paintAlert(alertIcon, *pPixmap, 15, 0);
128 if (item.m_color.getColorModel() == colorModelCMYK)
129 paintAlert(cmykIcon, *pPixmap, 30, 0);
130 else if (item.m_color.getColorModel() == colorModelRGB)
131 paintAlert(rgbIcon, *pPixmap, 30, 0);
132 else if (item.m_color.getColorModel() == colorModelLab)
133 paintAlert(labIcon, *pPixmap, 30, 0);
134 if (item.m_color.isSpotColor())
135 paintAlert(spotIcon, *pPixmap, 45, 0);
136 if (item.m_color.isRegistrationColor())
137 paintAlert(regIcon, *pPixmap, 46, 0);
138 }
139 }
140
141
text(const QVariant & data) const142 QString ColorSmallItemDelegate::text(const QVariant& data) const
143 {
144 if (data.canConvert<ColorPixmapValue>())
145 return data.value<ColorPixmapValue>().m_name;
146 return data.toString();
147 }
148
text(const QVariant & data) const149 QString ColorWideItemDelegate::text(const QVariant& data) const
150 {
151 if (data.canConvert<ColorPixmapValue>())
152 return data.value<ColorPixmapValue>().m_name;
153 return data.toString();
154 }
155
text(const QVariant & data) const156 QString ColorFancyItemDelegate::text(const QVariant& data) const
157 {
158 if (data.canConvert<ColorPixmapValue>())
159 return data.value<ColorPixmapValue>().m_name;
160 return data.toString();
161 }
162
iconSetChange()163 void ColorFancyItemDelegate::iconSetChange()
164 {
165 IconManager& iconManager = IconManager::instance();
166
167 alertIcon = iconManager.loadPixmap("alert.png", true);
168 cmykIcon = iconManager.loadPixmap("cmyk.png", true);
169 rgbIcon = iconManager.loadPixmap("rgb.png", true);
170 labIcon = iconManager.loadPixmap("lab.png", true);
171 spotIcon = iconManager.loadPixmap("spot.png", true);
172 regIcon = iconManager.loadPixmap("register.png", true);
173 }
174
175 int ColorListBox::initialized;
176 int ColorListBox::sortRule;
177
ColorListBox(QWidget * parent)178 ColorListBox::ColorListBox(QWidget * parent)
179 : QListView(parent)
180 {
181 cList = nullptr;
182 if (initialized != 12345)
183 sortRule = 0;
184 initialized = 12345;
185 QListView::setModel(new ColorListModel(this));
186 setPixmapType(ColorListBox::widePixmap);
187
188 connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(emitItemClicked(QModelIndex)));
189 connect(this, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(emitItemDoubleClicked(QModelIndex)));
190 connect(this->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
191 this, SLOT(emitCurrentChanged(QModelIndex, QModelIndex)));
192 connect(this->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
193 this, SIGNAL(itemSelectionChanged()));
194 connect(this, SIGNAL(contextMenuRequested()), this, SLOT(slotRightClick()));
195 }
196
ColorListBox(ColorListBox::PixmapType type,QWidget * parent)197 ColorListBox::ColorListBox(ColorListBox::PixmapType type, QWidget * parent)
198 : QListView(parent)
199 {
200 cList = nullptr;
201 if (initialized != 12345)
202 sortRule = 0;
203 initialized = 12345;
204 QListView::setModel(new ColorListModel(this));
205 setPixmapType(type);
206
207 connect(ScQApp, SIGNAL(iconSetChanged()), this, SLOT(iconSetChange()));
208
209 connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(emitItemClicked(QModelIndex)));
210 connect(this, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(emitItemDoubleClicked(QModelIndex)));
211 connect(this->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
212 this, SLOT(emitCurrentChanged(QModelIndex, QModelIndex)));
213 connect(this->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
214 this, SIGNAL(itemSelectionChanged()));
215 connect(this, SIGNAL(contextMenuRequested()), this, SLOT(slotRightClick()));
216 }
217
~ColorListBox()218 ColorListBox::~ColorListBox()
219 {
220 if (itemDelegate())
221 delete itemDelegate();
222 clear();
223 }
224
clear()225 void ColorListBox::clear()
226 {
227 QAbstractItemModel* itemModel = model();
228 itemModel->removeRows(0, itemModel->rowCount());
229 }
230
count() const231 int ColorListBox::count() const
232 {
233 return this->model()->rowCount();
234 }
235
changeEvent(QEvent * e)236 void ColorListBox::changeEvent(QEvent *e)
237 {
238 if (e->type() == QEvent::LanguageChange)
239 {
240 languageChange();
241 return;
242 }
243 QListView::changeEvent(e);
244 }
245
emitCurrentChanged(const QModelIndex & current,const QModelIndex & previous)246 void ColorListBox::emitCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous)
247 {
248 QPersistentModelIndex persistentCurrent = current;
249
250 QString text = model()->data(current, Qt::DisplayRole).toString();
251 emit currentTextChanged(text);
252 emit currentRowChanged(persistentCurrent.row());
253 }
254
emitItemClicked(const QModelIndex & current)255 void ColorListBox::emitItemClicked(const QModelIndex ¤t)
256 {
257 QPersistentModelIndex persistentCurrent = current;
258 emit itemClicked(persistentCurrent.row());
259 }
260
emitItemDoubleClicked(const QModelIndex & current)261 void ColorListBox::emitItemDoubleClicked(const QModelIndex ¤t)
262 {
263 QPersistentModelIndex persistentCurrent = current;
264 emit itemDoubleClicked(persistentCurrent.row());
265 }
266
iconSetChange()267 void ColorListBox::iconSetChange()
268 {
269 if (m_type == ColorListBox::fancyPixmap)
270 {
271 QAbstractItemDelegate* curDelegate = itemDelegate();
272 ColorFancyItemDelegate* colorDelegate = dynamic_cast<ColorFancyItemDelegate*>(curDelegate);
273 if (colorDelegate)
274 {
275 colorDelegate->iconSetChange();
276 this->update();
277 }
278 }
279 }
280
languageChange()281 void ColorListBox::languageChange()
282 {
283 // Not needed anymore normally: on language change a paintEvent is sent to widget
284 // and model will return the new translated string for None color
285 /*if (this->count() > 0)
286 {
287 QModelIndexList result;
288 QModelIndex start = model()->index(0, 0, this->rootIndex());
289 result = model()->match(start, Qt::UserRole, CommonStrings::None, 1, Qt::MatchExactly | Qt::MatchCaseSensitive);
290 if (result.isEmpty())
291 return;
292 int index = result.first().row();
293 QListWidgetItem* item = this->item(index);
294 item->setText(CommonStrings::tr_NoneColor);
295 }*/
296 }
297
currentColor() const298 QString ColorListBox::currentColor() const
299 {
300 if (currentRow() >= 0)
301 {
302 QAbstractItemModel* itemModel = model();
303 return itemModel->data(currentIndex(), Qt::DisplayRole).toString();
304 }
305 return CommonStrings::tr_NoneColor;
306 }
307
currentRow() const308 int ColorListBox::currentRow() const
309 {
310 return currentIndex().row();
311 }
312
data(int row,int role) const313 QVariant ColorListBox::data(int row, int role) const
314 {
315 QModelIndex index = model()->index(row, 0);
316 return model()->data(index, role);
317 }
318
findColors(const QString & name,Qt::MatchFlags flags) const319 QStringList ColorListBox::findColors(const QString &name, Qt::MatchFlags flags) const
320 {
321 QStringList foundColors;
322 QAbstractItemModel* currentModel = model();
323
324 QModelIndex firstIndex = currentModel->index(0, 0, QModelIndex());
325 QModelIndexList indexes = currentModel->match(firstIndex, Qt::DisplayRole, name, -1, flags);
326 for (int i = 0; i < indexes.count(); ++i)
327 {
328 QModelIndex modelIndex = indexes.at(i);
329 QVariant modelData = currentModel->data(modelIndex, Qt::DisplayRole);
330 foundColors.append(modelData.toString());
331 }
332
333 return foundColors;
334 }
335
hasSelection() const336 bool ColorListBox::hasSelection() const
337 {
338 return this->selectionModel()->hasSelection();
339 }
340
insertItem(int row,const ScColor & color,const QString & colorName)341 void ColorListBox::insertItem(int row, const ScColor& color, const QString& colorName)
342 {
343 ColorListModel* colorListModel = qobject_cast<ColorListModel*>(model());
344 if (!colorListModel)
345 return;
346
347 ScribusDoc* doc = nullptr;
348 if (cList)
349 doc = cList->document();
350
351 ColorPixmapValue value(color, doc, colorName);
352 colorListModel->insert(row, value);
353 }
354
isNoneColorShown() const355 bool ColorListBox::isNoneColorShown() const
356 {
357 ColorListModel* colorListModel = qobject_cast<ColorListModel*>(model());
358 if (colorListModel)
359 return colorListModel->isNoneColorShown();
360 return false;
361 }
362
removeItem(int i)363 void ColorListBox::removeItem(int i)
364 {
365 // None color item cannot be removed
366 if (isNoneColorShown() && (i == 0))
367 return;
368
369 model()->removeRow(i);
370 }
371
row(const QString & colorName)372 int ColorListBox::row(const QString& colorName)
373 {
374 QAbstractItemModel* currentModel = model();
375
376 QModelIndex firstIndex = currentModel->index(0, 0, QModelIndex());
377 QModelIndexList indexes = currentModel->match(firstIndex, Qt::DisplayRole, colorName, -1, Qt::MatchExactly);
378 if (indexes.count() > 0)
379 {
380 const QModelIndex& first = indexes.at(0);
381 return first.row();
382 }
383 return -1;
384 }
385
setCurrentColor(QString colorName)386 void ColorListBox::setCurrentColor(QString colorName)
387 {
388 if (colorName == CommonStrings::None)
389 colorName = CommonStrings::tr_NoneColor;
390
391 QModelIndex firstIndex = model()->index(0, 0, QModelIndex());
392 QModelIndexList indexes = this->model()->match(firstIndex, Qt::DisplayRole, colorName, -1, Qt::MatchExactly);
393 if (indexes.count() > 0)
394 this->selectionModel()->setCurrentIndex(indexes[0], QItemSelectionModel::ClearAndSelect);
395 }
396
setColors(ColorList & list,bool insertNone)397 void ColorListBox::setColors(ColorList& list, bool insertNone)
398 {
399 ColorList::Iterator it;
400
401 ColorListModel* colorModel = qobject_cast<ColorListModel*>(this->model());
402 if (!colorModel)
403 return;
404
405 cList = &list;
406
407 colorModel->setColorList(list, insertNone);
408 }
409
setCurrentRow(int row)410 void ColorListBox::setCurrentRow(int row)
411 {
412 QModelIndex index = this->model()->index(row, 0);
413 selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
414 }
415
setPixmapType(ColorListBox::PixmapType type)416 void ColorListBox::setPixmapType(ColorListBox::PixmapType type)
417 {
418 if (type == ColorListBox::fancyPixmap)
419 {
420 QAbstractItemDelegate* oldDelegate = itemDelegate();
421 ColorFancyItemDelegate* colorDelegate = dynamic_cast<ColorFancyItemDelegate*>(oldDelegate);
422 if (!colorDelegate)
423 {
424 setItemDelegate(new ColorFancyItemDelegate());
425 delete oldDelegate;
426 m_type = type;
427 }
428 }
429 else if (type == ColorListBox::widePixmap)
430 {
431 QAbstractItemDelegate* oldDelegate = itemDelegate();
432 ColorWideItemDelegate* colorDelegate = dynamic_cast<ColorWideItemDelegate*>(oldDelegate);
433 if (!colorDelegate)
434 {
435 setItemDelegate(new ColorWideItemDelegate());
436 delete oldDelegate;
437 m_type = type;
438 }
439 }
440 else if (type == ColorListBox::smallPixmap)
441 {
442 QAbstractItemDelegate* oldDelegate = itemDelegate();
443 ColorSmallItemDelegate* colorDelegate = dynamic_cast<ColorSmallItemDelegate*>(oldDelegate);
444 if (!colorDelegate)
445 {
446 setItemDelegate(new ColorSmallItemDelegate());
447 delete oldDelegate;
448 m_type = type;
449 }
450 }
451 }
452
setShowNoneColor(bool showNone)453 void ColorListBox::setShowNoneColor(bool showNone)
454 {
455 ColorListModel* colorListModel = qobject_cast<ColorListModel*>(model());
456 if (colorListModel)
457 colorListModel->setShowNoneColor(showNone);
458 }
459
slotRightClick()460 void ColorListBox::slotRightClick()
461 {
462 QSignalBlocker sigBlocker(this);
463 QString currentSel = currentColor();
464 if (currentSel.isEmpty())
465 return;
466
467 QMenu *pmen = new QMenu();
468 pmen->addAction( tr("Sort by Name"));
469 pmen->addAction( tr("Sort by Color"));
470 pmen->addAction( tr("Sort by Type"));
471 sortRule = pmen->actions().indexOf(pmen->exec(QCursor::pos()));
472 delete pmen;
473
474 ColorListModel* colorListModel = qobject_cast<ColorListModel*>(model());
475 if (!colorListModel)
476 return;
477
478 if (sortRule == 0)
479 colorListModel->setSortRule(ColorListModel::SortByName);
480 else if (sortRule == 1)
481 colorListModel->setSortRule(ColorListModel::SortByValues);
482 else if (sortRule == 2)
483 colorListModel->setSortRule(ColorListModel::SortByType);
484
485 if (!currentSel.isEmpty())
486 setCurrentColor(currentSel);
487 }
488
text(int row)489 QString ColorListBox::text(int row)
490 {
491 QVariant varText = data(row, Qt::DisplayRole);
492 return varText.toString();
493 }
494
updateBox(ColorList & list)495 void ColorListBox::updateBox(ColorList& list)
496 {
497 bool showNoneColor = false;
498
499 clear();
500 reset();
501
502 ColorListModel* colorModel = qobject_cast<ColorListModel*>(this->model());
503 if (colorModel)
504 showNoneColor = colorModel->isNoneColorShown();
505 setColors(list, showNoneColor);
506 }
507
viewportEvent(QEvent * event)508 bool ColorListBox::viewportEvent(QEvent *event)
509 {
510 if (event != nullptr)
511 {
512 if (event->type() == QEvent::MouseButtonPress)
513 {
514 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
515 if (mouseEvent->button() == Qt::RightButton)
516 return true;
517 }
518 else if (event->type() == QEvent::MouseButtonRelease)
519 {
520 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
521 if (mouseEvent->button() == Qt::RightButton)
522 {
523 emit contextMenuRequested();
524 return true;
525 }
526 }
527 }
528 return QListView::viewportEvent(event);
529 }
530