1 /***************************************************************************
2 * Copyright (C) 2004-2018 by Thomas Fischer <fischer@unix-ag.uni-kl.de> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
16 ***************************************************************************/
17
18 #include "colorlabelwidget.h"
19
20 #include <QAbstractItemModel>
21 #include <QFontMetrics>
22 #include <QPainter>
23 #include <QColorDialog>
24
25 #include <KLocalizedString>
26 #include <KSharedConfig>
27 #include <KConfigGroup>
28
29 #include "notificationhub.h"
30 #include "preferences.h"
31
32 class ColorLabelComboBoxModel : public QAbstractItemModel, private NotificationListener
33 {
34 Q_OBJECT
35
36 public:
37 enum ColorLabelComboBoxModelRole {
38 /// Color of a color-label pair
39 ColorRole = Qt::UserRole + 1721
40 };
41
42 struct ColorLabelPair {
43 QColor color;
44 QString label;
45 };
46
47 QList<ColorLabelPair> colorLabelPairs;
48 QColor userColor;
49
50 KSharedConfigPtr config;
51
ColorLabelComboBoxModel(QObject * p=nullptr)52 ColorLabelComboBoxModel(QObject *p = nullptr)
53 : QAbstractItemModel(p), userColor(Qt::black), config(KSharedConfig::openConfig(QStringLiteral("kbibtexrc"))) {
54 readConfiguration();
55 NotificationHub::registerNotificationListener(this, NotificationHub::EventConfigurationChanged);
56 }
57
notificationEvent(int eventId)58 void notificationEvent(int eventId) override {
59 if (eventId == NotificationHub::EventConfigurationChanged)
60 readConfiguration();
61 }
62
readConfiguration()63 void readConfiguration() {
64 KConfigGroup configGroup(config, Preferences::groupColor);
65 QStringList colorCodes = configGroup.readEntry(Preferences::keyColorCodes, Preferences::defaultColorCodes);
66 QStringList colorLabels = configGroup.readEntry(Preferences::keyColorLabels, Preferences::defaultColorLabels);
67
68 colorLabelPairs.clear();
69 for (QStringList::ConstIterator itc = colorCodes.constBegin(), itl = colorLabels.constBegin(); itc != colorCodes.constEnd() && itl != colorLabels.constEnd(); ++itc, ++itl) {
70 ColorLabelPair clp;
71 clp.color = QColor(*itc);
72 clp.label = i18n((*itl).toUtf8().constData());
73 colorLabelPairs << clp;
74 }
75 }
76
index(int row,int column,const QModelIndex &) const77 QModelIndex index(int row, int column, const QModelIndex &) const override {
78 return createIndex(row, column);
79 }
80
parent(const QModelIndex &=QModelIndex ()) const81 QModelIndex parent(const QModelIndex & = QModelIndex()) const override {
82 return QModelIndex();
83 }
84
rowCount(const QModelIndex & parent=QModelIndex ()) const85 int rowCount(const QModelIndex &parent = QModelIndex()) const override {
86 return parent == QModelIndex() ? 2 + colorLabelPairs.count() : 0;
87 }
88
columnCount(const QModelIndex &=QModelIndex ()) const89 int columnCount(const QModelIndex & = QModelIndex()) const override {
90 return 1;
91 }
92
data(const QModelIndex & index,int role=Qt::DisplayRole) const93 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
94 if (role == ColorRole) {
95 if (index.row() == 0)
96 return QColor(Qt::black);
97 else if (index.row() == rowCount() - 1)
98 return userColor;
99 else
100 return colorLabelPairs[index.row() - 1].color;
101 } else if (role == Qt::FontRole && (index.row() == 0 || index.row() == rowCount() - 1)) {
102 QFont font;
103 font.setItalic(true);
104 return font;
105 } else if (role == Qt::DecorationRole && index.row() > 0 && (index.row() < rowCount() - 1 || userColor != Qt::black)) {
106 QColor color = data(index, ColorRole).value<QColor>();
107 return ColorLabelWidget::createSolidIcon(color);
108 } else if (role == Qt::DisplayRole)
109 if (index.row() == 0)
110 return i18n("No color");
111 else if (index.row() == rowCount() - 1)
112 return i18n("User-defined color");
113 else
114 return colorLabelPairs[index.row() - 1].label;
115 else
116 return QVariant();
117 }
118
headerData(int section,Qt::Orientation orientation,int role=Qt::DisplayRole) const119 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override {
120 if (section != 0 || orientation != Qt::Horizontal || role != Qt::DisplayRole)
121 return QVariant();
122
123 return i18n("Color & Label");
124 }
125
setColor(const QColor & newColor)126 void setColor(const QColor &newColor) {
127 userColor = newColor;
128 const QModelIndex idx = index(rowCount() - 1, 0, QModelIndex());
129 emit dataChanged(idx, idx);
130 }
131 };
132
133 class ColorLabelWidget::ColorLabelWidgetPrivate
134 {
135 public:
136 ColorLabelComboBoxModel *model;
137
ColorLabelWidgetPrivate(ColorLabelWidget * parent,ColorLabelComboBoxModel * m)138 ColorLabelWidgetPrivate(ColorLabelWidget *parent, ColorLabelComboBoxModel *m)
139 : model(m)
140 {
141 Q_UNUSED(parent)
142 }
143 };
144
ColorLabelWidget(QWidget * parent)145 ColorLabelWidget::ColorLabelWidget(QWidget *parent)
146 : KComboBox(false, parent), d(new ColorLabelWidgetPrivate(this, new ColorLabelComboBoxModel(this)))
147 {
148 setModel(d->model);
149 connect(this, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ColorLabelWidget::slotCurrentIndexChanged);
150 }
151
~ColorLabelWidget()152 ColorLabelWidget::~ColorLabelWidget()
153 {
154 delete d;
155 }
156
clear()157 void ColorLabelWidget::clear()
158 {
159 setCurrentIndex(0);
160 }
161
reset(const Value & value)162 bool ColorLabelWidget::reset(const Value &value)
163 {
164 /// Avoid triggering signal when current index is set by the program
165 disconnect(this, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ColorLabelWidget::slotCurrentIndexChanged);
166
167 QSharedPointer<VerbatimText> verbatimText;
168 if (value.count() == 1 && !(verbatimText = value.first().dynamicCast<VerbatimText>()).isNull()) {
169 int i = 0;
170 const QColor color = QColor(verbatimText->text());
171 for (; i < d->model->rowCount(); ++i)
172 if (d->model->data(d->model->index(i, 0, QModelIndex()), ColorLabelComboBoxModel::ColorRole).value<QColor>() == color)
173 break;
174
175 if (i >= d->model->rowCount()) {
176 d->model->userColor = color;
177 i = d->model->rowCount() - 1;
178 }
179 setCurrentIndex(i);
180 } else
181 setCurrentIndex(0);
182
183 /// Re-enable triggering signal after setting current index
184 connect(this, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ColorLabelWidget::slotCurrentIndexChanged);
185
186 return true;
187 }
188
apply(Value & value) const189 bool ColorLabelWidget::apply(Value &value) const
190 {
191 QColor color = d->model->data(d->model->index(currentIndex(), 0, QModelIndex()), ColorLabelComboBoxModel::ColorRole).value<QColor>();
192 value.clear();
193 if (color != Qt::black)
194 value.append(QSharedPointer<VerbatimText>(new VerbatimText(color.name())));
195 return true;
196 }
197
validate(QWidget **,QString &) const198 bool ColorLabelWidget::validate(QWidget **, QString &) const
199 {
200 return true;
201 }
202
setReadOnly(bool isReadOnly)203 void ColorLabelWidget::setReadOnly(bool isReadOnly)
204 {
205 setEnabled(!isReadOnly);
206 }
207
slotCurrentIndexChanged(int index)208 void ColorLabelWidget::slotCurrentIndexChanged(int index)
209 {
210 if (index == count() - 1) {
211 QColor dialogColor = d->model->userColor;
212 if (QColorDialog::getColor(dialogColor, this) == QColorDialog::Accepted)
213 d->model->setColor(dialogColor);
214 }
215
216 emit modified();
217 }
218
createSolidIcon(const QColor & color)219 QPixmap ColorLabelWidget::createSolidIcon(const QColor &color)
220 {
221 QFontMetrics fm = QFontMetrics(QFont());
222 int h = fm.height() - 4;
223 QPixmap pm(h, h);
224 QPainter painter(&pm);
225 painter.setPen(color);
226 painter.setBrush(QBrush(color));
227 painter.drawRect(0, 0, h, h);
228 return pm;
229 }
230
231 #include "colorlabelwidget.moc"
232