File indexing completed on 2024-12-01 04:37:50
0001 /*************************************************************************** 0002 * SPDX-License-Identifier: GPL-2.0-or-later 0003 * * 0004 * SPDX-FileCopyrightText: 2004-2022 Thomas Fischer <fischer@unix-ag.uni-kl.de> 0005 * * 0006 * This program is free software; you can redistribute it and/or modify * 0007 * it under the terms of the GNU General Public License as published by * 0008 * the Free Software Foundation; either version 2 of the License, or * 0009 * (at your option) any later version. * 0010 * * 0011 * This program is distributed in the hope that it will be useful, * 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0014 * GNU General Public License for more details. * 0015 * * 0016 * You should have received a copy of the GNU General Public License * 0017 * along with this program; if not, see <https://www.gnu.org/licenses/>. * 0018 ***************************************************************************/ 0019 0020 #include "colorlabelwidget.h" 0021 0022 #include <QAbstractItemModel> 0023 #include <QFontMetrics> 0024 #include <QPainter> 0025 #include <QColorDialog> 0026 #include <QSignalBlocker> 0027 0028 #include <KLocalizedString> 0029 0030 #include <NotificationHub> 0031 #include <Preferences> 0032 0033 class ColorLabelComboBoxModel : public QAbstractItemModel 0034 { 0035 Q_OBJECT 0036 0037 public: 0038 static const QColor NoColor; 0039 0040 enum ColorLabelComboBoxModelRole { 0041 /// Color of a color-label pair 0042 ColorRole = Qt::UserRole + 1721 0043 }; 0044 0045 struct ColorLabelPair { 0046 QColor color; 0047 QString label; 0048 }; 0049 0050 QColor userColor; 0051 0052 ColorLabelComboBoxModel(QObject *p = nullptr) 0053 : QAbstractItemModel(p), userColor(NoColor) { 0054 /// nothing 0055 } 0056 0057 QModelIndex index(int row, int column, const QModelIndex &parent) const override { 0058 return parent == QModelIndex() ? createIndex(row, column) : QModelIndex(); 0059 } 0060 0061 QModelIndex parent(const QModelIndex & = QModelIndex()) const override { 0062 return QModelIndex(); 0063 } 0064 0065 int rowCount(const QModelIndex &parent = QModelIndex()) const override { 0066 return parent == QModelIndex() ? 2 + Preferences::instance().colorCodes().count() : 0; 0067 } 0068 0069 int columnCount(const QModelIndex &parent = QModelIndex()) const override { 0070 return parent == QModelIndex() ? 1 : 0; 0071 } 0072 0073 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override { 0074 if (role == ColorRole) { 0075 const int cci = index.row() - 1; 0076 if (index.row() == 0 || cci < 0 || cci >= Preferences::instance().colorCodes().count()) 0077 return NoColor; 0078 else if (index.row() == rowCount() - 1) 0079 return userColor; 0080 else 0081 return QColor(Preferences::instance().colorCodes().at(cci).first); 0082 } else if (role == Qt::FontRole && (index.row() == 0 || index.row() == rowCount() - 1)) { 0083 /// Set first item's text ("No color") and last item's text ("User-defined color") in italics 0084 QFont font; 0085 font.setItalic(true); 0086 return font; 0087 } else if (role == Qt::DecorationRole && index.row() > 0 && (index.row() < rowCount() - 1 || userColor != NoColor)) { 0088 /// For items that have a color to choose, draw a little square in this chosen color 0089 QColor color = data(index, ColorRole).value<QColor>(); 0090 return ColorLabelWidget::createSolidIcon(color); 0091 } else if (role == Qt::DisplayRole) 0092 if (index.row() == 0) 0093 return i18n("No color"); 0094 else if (index.row() == rowCount() - 1) 0095 return i18n("User-defined color"); 0096 else 0097 return Preferences::instance().colorCodes().at(index.row() - 1).second; 0098 else 0099 return QVariant(); 0100 } 0101 0102 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override { 0103 if (section != 0 || orientation != Qt::Horizontal || role != Qt::DisplayRole) 0104 return QVariant(); 0105 0106 return i18n("Color & Label"); 0107 } 0108 0109 void setColor(const QColor &newColor) { 0110 userColor = newColor; 0111 const QModelIndex idx = index(rowCount() - 1, 0, QModelIndex()); 0112 Q_EMIT dataChanged(idx, idx); 0113 } 0114 0115 void reset() { 0116 beginResetModel(); 0117 endResetModel(); 0118 } 0119 }; 0120 0121 const QColor ColorLabelComboBoxModel::NoColor = Qt::black; 0122 0123 0124 class ColorLabelWidget::ColorLabelWidgetPrivate : private NotificationListener 0125 { 0126 private: 0127 ColorLabelWidget *parent; 0128 0129 public: 0130 ColorLabelComboBoxModel *model; 0131 0132 ColorLabelWidgetPrivate(ColorLabelWidget *_parent, ColorLabelComboBoxModel *m) 0133 : parent(_parent), model(m) 0134 { 0135 Q_UNUSED(parent) 0136 NotificationHub::registerNotificationListener(this, NotificationHub::EventConfigurationChanged); 0137 } 0138 0139 void notificationEvent(int eventId) override { 0140 if (eventId == NotificationHub::EventConfigurationChanged) { 0141 /// Avoid triggering signal when current index is set by the program 0142 const QSignalBlocker blocker(parent); 0143 0144 const QColor currentColor = parent->currentColor(); 0145 model->reset(); 0146 model->userColor = ColorLabelComboBoxModel::NoColor; 0147 selectColor(currentColor); 0148 } 0149 } 0150 0151 int selectColor(const QString &color) 0152 { 0153 return selectColor(QColor(color)); 0154 } 0155 0156 int selectColor(const QColor &color) 0157 { 0158 int rowIndex = 0; 0159 if (color != ColorLabelComboBoxModel::NoColor) { 0160 /// Find row that matches given color 0161 for (rowIndex = 0; rowIndex < model->rowCount(); ++rowIndex) 0162 if (model->data(model->index(rowIndex, 0, QModelIndex()), ColorLabelComboBoxModel::ColorRole).value<QColor>() == color) 0163 break; 0164 0165 if (rowIndex >= model->rowCount()) { 0166 /// Color was not in the list of known colors, so set user color to given color 0167 model->userColor = color; 0168 rowIndex = model->rowCount() - 1; 0169 } 0170 } 0171 return rowIndex; 0172 } 0173 }; 0174 0175 ColorLabelWidget::ColorLabelWidget(QWidget *parent) 0176 : QComboBox(parent), d(new ColorLabelWidgetPrivate(this, new ColorLabelComboBoxModel(this))) 0177 { 0178 setModel(d->model); 0179 connect(this, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ColorLabelWidget::slotCurrentIndexChanged); 0180 } 0181 0182 ColorLabelWidget::~ColorLabelWidget() 0183 { 0184 delete d; 0185 } 0186 0187 void ColorLabelWidget::clear() 0188 { 0189 /// Avoid triggering signal when current index is set by the program 0190 const QSignalBlocker blocker(this); 0191 0192 d->model->userColor = ColorLabelComboBoxModel::NoColor; 0193 setCurrentIndex(0); ///< index 0 should be "no color" 0194 } 0195 0196 QColor ColorLabelWidget::currentColor() const 0197 { 0198 return d->model->data(d->model->index(currentIndex(), 0, QModelIndex()), ColorLabelComboBoxModel::ColorRole).value<QColor>(); 0199 } 0200 0201 bool ColorLabelWidget::reset(const Value &value) 0202 { 0203 /// Avoid triggering signal when current index is set by the program 0204 const QSignalBlocker blocker(this); 0205 0206 QSharedPointer<VerbatimText> verbatimText; 0207 int rowIndex = 0; 0208 if (value.count() == 1 && !(verbatimText = value.first().dynamicCast<VerbatimText>()).isNull()) { 0209 /// Create QColor instance based on given textual representation 0210 rowIndex = d->selectColor(verbatimText->text()); 0211 } 0212 setCurrentIndex(rowIndex); 0213 0214 return true; 0215 } 0216 0217 bool ColorLabelWidget::apply(Value &value) const 0218 { 0219 const QColor color = currentColor(); 0220 value.clear(); 0221 if (color != ColorLabelComboBoxModel::NoColor) 0222 value.append(QSharedPointer<VerbatimText>(new VerbatimText(color.name()))); 0223 return true; 0224 } 0225 0226 bool ColorLabelWidget::validate(QWidget **, QString &) const 0227 { 0228 return true; 0229 } 0230 0231 void ColorLabelWidget::setReadOnly(bool isReadOnly) 0232 { 0233 setEnabled(!isReadOnly); 0234 } 0235 0236 void ColorLabelWidget::slotCurrentIndexChanged(int index) 0237 { 0238 if (index == count() - 1) { 0239 const QColor initialColor = d->model->userColor; 0240 const QColor newColor = QColorDialog::getColor(initialColor, this); 0241 if (newColor.isValid()) 0242 d->model->setColor(newColor); 0243 } 0244 0245 Q_EMIT modified(); 0246 } 0247 0248 QPixmap ColorLabelWidget::createSolidIcon(const QColor &color) 0249 { 0250 QFontMetrics fm = QFontMetrics(QFont()); 0251 int h = fm.height() - 4; 0252 QPixmap pm(h, h); 0253 QPainter painter(&pm); 0254 painter.setPen(color); 0255 painter.setBrush(QBrush(color)); 0256 painter.drawRect(0, 0, h, h); 0257 return pm; 0258 } 0259 0260 #include "colorlabelwidget.moc"