File indexing completed on 2024-04-21 14:55:51

0001 /* This file is part of the KDE libraries
0002     Copyright (C) 1997 Martin Jones (mjones@kde.org)
0003     Copyright (C) 2007 Roberto Raggi (roberto@kdevelop.org)
0004 
0005     This library is free software; you can redistribute it and/or
0006     modify it under the terms of the GNU Library General Public
0007     License as published by the Free Software Foundation; either
0008     version 2 of the License, or (at your option) any later version.
0009 
0010     This library is distributed in the hope that it will be useful,
0011     but WITHOUT ANY WARRANTY; without even the implied warranty of
0012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013     Library General Public License for more details.
0014 
0015     You should have received a copy of the GNU Library General Public License
0016     along with this library; see the file COPYING.LIB.  If not, write to
0017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018     Boston, MA 02110-1301, USA.
0019 */
0020 //-----------------------------------------------------------------------------
0021 // KDE color selection dialog.
0022 //
0023 // 1999-09-27 Espen Sand <espensa@online.no>
0024 // KColorDialog is now subclassed from KDialog. I have also extended
0025 // KColorDialog::getColor() so that it contains a parent argument. This
0026 // improves centering capability.
0027 //
0028 // layout management added Oct 1997 by Mario Weilguni
0029 // <mweilguni@sime.com>
0030 //
0031 
0032 #include "kcolordialog.h"
0033 #include "kcolordialog_p.h"
0034 
0035 #include <config-kdelibs4support.h>
0036 
0037 #include <stdio.h>
0038 #include <stdlib.h>
0039 
0040 #include <QButtonGroup>
0041 #include <QCheckBox>
0042 #include <QDesktopWidget>
0043 #include <QRadioButton>
0044 #include <QFrame>
0045 #include <qdrawutil.h>
0046 #include <QActionEvent>
0047 #include <QFile>
0048 #include <QHeaderView>
0049 #include <QImage>
0050 #include <QHBoxLayout>
0051 #include <QDrag>
0052 #include <QStyledItemDelegate>
0053 #include <QLabel>
0054 #include <QLayout>
0055 #include <QPainter>
0056 #include <QPushButton>
0057 #include <QScrollBar>
0058 #include <QTimer>
0059 #include <QListWidget>
0060 #include <QApplication>
0061 #include <QSpinBox>
0062 
0063 #include <kcombobox.h>
0064 #include <kconfig.h>
0065 #include <klineedit.h>
0066 #include <klocalizedstring.h>
0067 #include <kmessagebox.h>
0068 #include <kseparator.h>
0069 #include <qstandardpaths.h>
0070 #include <kcolorcollection.h>
0071 #include <kcolorutils.h>
0072 
0073 #include "kcolormimedata.h"
0074 #include <kdebug.h>
0075 
0076 #include "kcolorchoosermode_p.h"
0077 #include "kcolorhelpers_p.h"
0078 #include "kselector.h"
0079 #include "kcolorvalueselector.h"
0080 #include "khuesaturationselect.h"
0081 #include "kxyselector.h"
0082 #include <kconfiggroup.h>
0083 #include <ksharedconfig.h>
0084 
0085 #if HAVE_X11
0086 #include <X11/Xlib.h>
0087 #include <X11/Xutil.h>
0088 #include <QX11Info>
0089 #include <fixx11h.h>
0090 #endif
0091 
0092 using namespace KDEPrivate;
0093 
0094 using KDEPrivate::KColorTable;
0095 
0096 struct ColorCollectionNameType {
0097     const char *const m_fileName;
0098     const char *const m_displayName;
0099 };
0100 
0101 static const ColorCollectionNameType colorCollectionName[] = {
0102     { "Recent_Colors", I18N_NOOP2("palette name", "* Recent Colors *") },
0103     { "Custom_Colors", I18N_NOOP2("palette name", "* Custom Colors *") },
0104     { "40.colors",     I18N_NOOP2("palette name", "Forty Colors") },
0105     { "Oxygen.colors", I18N_NOOP2("palette name", "Oxygen Colors") },
0106     { "Rainbow.colors", I18N_NOOP2("palette name", "Rainbow Colors") },
0107     { "Royal.colors",  I18N_NOOP2("palette name", "Royal Colors") },
0108     { "Web.colors",    I18N_NOOP2("palette name", "Web Colors") },
0109     { nullptr, nullptr } // end of data
0110 };
0111 
0112 enum ColorCollectionIndices {
0113     recentColorIndex,
0114     customColorIndex,
0115     fortyColorIndex
0116 };
0117 
0118 //-----------------------------------------------------------------------------
0119 
0120 class Q_DECL_HIDDEN KColorCells::KColorCellsPrivate
0121 {
0122 public:
0123     KColorCellsPrivate(KColorCells *q): q(q)
0124     {
0125         inMouse = false;
0126         selected = -1;
0127         shade = false;
0128     }
0129 
0130     KColorCells *q;
0131     QPoint mousePos;
0132     int selected;
0133     bool shade;
0134     bool inMouse;
0135 };
0136 
0137 class KColorCellsItemDelegate: public QStyledItemDelegate
0138 {
0139 public:
0140     KColorCellsItemDelegate(KColorCells *parent): QStyledItemDelegate(parent) {}
0141     void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
0142     {
0143         QStyleOptionViewItem opt(option);
0144         initStyleOption(&opt, index);
0145 
0146         //Get the current cell color
0147         QColor backgroundColor = index.data(Qt::BackgroundRole).value<QColor>();
0148         if (backgroundColor.isValid()) {
0149             //Paint the general background
0150             painter->fillRect(opt.rect, backgroundColor);
0151             //Paint the selection mark (circle)
0152             if (opt.state & QStyle::State_Selected) {
0153                 //Use black or white, depending on the contrast
0154                 QColor color = QColor(0, 0, 0, 220);
0155                 if (KColorUtils::contrastRatio(color, backgroundColor) < 5) {
0156                     color = QColor(255, 255, 255, 220);
0157                 }
0158                 //Draw the selection (radiobutton-like) circle
0159                 painter->save();
0160                 painter->setRenderHint(QPainter::Antialiasing, true);
0161                 painter->setRenderHint(QPainter::HighQualityAntialiasing, true);
0162                 painter->setPen(QPen(color, 1.2, Qt::SolidLine));
0163                 painter->setBrush(QBrush());
0164                 painter->drawEllipse(opt.rect.adjusted(2, 2, -2, -2));
0165                 painter->restore();
0166             }
0167         } else {
0168             //Paint the "X" (missing) cross on empty background color
0169             backgroundColor = opt.palette.color(QPalette::Window);
0170             painter->fillRect(opt.rect, backgroundColor);
0171             painter->save();
0172             QColor crossColor = qGray(backgroundColor.rgb()) > 192 ? backgroundColor.darker(106) :
0173                                 backgroundColor.lighter(106);
0174             painter->setPen(QPen(crossColor, 1.5));
0175             painter->drawLine(opt.rect.topLeft(), opt.rect.bottomRight());
0176             painter->drawLine(opt.rect.topRight(), opt.rect.bottomLeft());
0177             painter->restore();
0178         }
0179     }
0180 };
0181 
0182 KColorCells::KColorCells(QWidget *parent, int rows, int cols)
0183     : QTableWidget(parent), d(new KColorCellsPrivate(this))
0184 {
0185     setItemDelegate(new KColorCellsItemDelegate(this));
0186 
0187     setFrameShape(QFrame::NoFrame);
0188     d->shade = true;
0189     setRowCount(rows);
0190     setColumnCount(cols);
0191 
0192     verticalHeader()->hide();
0193     horizontalHeader()->hide();
0194 
0195     d->selected = 0;
0196     d->inMouse = false;
0197 
0198     // Drag'n'Drop
0199     setAcceptDrops(true);
0200 
0201     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
0202     setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
0203     viewport()->setBackgroundRole(QPalette::Window);
0204     setBackgroundRole(QPalette::Window);
0205 
0206     setSelectionMode(QAbstractItemView::SingleSelection);
0207     setDragEnabled(false);
0208 }
0209 
0210 KColorCells::~KColorCells()
0211 {
0212     delete d;
0213 }
0214 
0215 QColor KColorCells::color(int index) const
0216 {
0217     QTableWidgetItem *tmpItem = item(index / columnCount(), index % columnCount());
0218 
0219     if (tmpItem != nullptr) {
0220         return tmpItem->data(Qt::BackgroundRole).value<QColor>();
0221     }
0222 
0223     return QColor();
0224 }
0225 
0226 int KColorCells::count() const
0227 {
0228     return rowCount() * columnCount();
0229 }
0230 
0231 void KColorCells::setShading(bool _shade)
0232 {
0233     d->shade = _shade;
0234 }
0235 
0236 bool KColorCells::shading() const
0237 {
0238     return d->shade;
0239 }
0240 
0241 void KColorCells::setAcceptDrags(bool _acceptDrags)
0242 {
0243     this->setDragEnabled(_acceptDrags);
0244 }
0245 
0246 bool KColorCells::acceptDrags() const
0247 {
0248     return this->dragEnabled();
0249 }
0250 
0251 void KColorCells::setSelected(int index)
0252 {
0253     Q_ASSERT(index >= 0 && index < count());
0254 
0255     d->selected = index;
0256 }
0257 
0258 int KColorCells::selectedIndex() const
0259 {
0260     return d->selected;
0261 }
0262 
0263 void KColorCells::setColor(int column, const QColor &color)
0264 {
0265     const int tableRow = column / columnCount();
0266     const int tableColumn = column % columnCount();
0267 
0268     Q_ASSERT(tableRow >= 0 && tableRow < rowCount());
0269     Q_ASSERT(tableColumn >= 0 && tableColumn < columnCount());
0270 
0271     QTableWidgetItem *tableItem = item(tableRow, tableColumn);
0272 
0273     if (tableItem == nullptr) {
0274         tableItem = new QTableWidgetItem();
0275         setItem(tableRow, tableColumn, tableItem);
0276     }
0277 
0278     tableItem->setData(Qt::BackgroundRole, color);
0279 }
0280 
0281 /*void KColorCells::paintCell( QPainter *painter, int row, int col )
0282 {
0283     painter->setRenderHint( QPainter::Antialiasing , true );
0284 
0285  QBrush brush;
0286  int w = 1;
0287 
0288  if (shade)
0289  {
0290   qDrawShadePanel( painter, 1, 1, cellWidth()-2,
0291        cellHeight()-2, palette(), true, 1, &brush );
0292   w = 2;
0293  }
0294  QColor color = colors[ row * numCols() + col ];
0295  if (!color.isValid())
0296  {
0297   if (!shade) return;
0298   color = palette().color(backgroundRole());
0299  }
0300 
0301  const QRect colorRect( w, w, cellWidth()-w*2, cellHeight()-w*2 );
0302  painter->fillRect( colorRect, color );
0303 
0304  if ( row * numCols() + col == selected ) {
0305   painter->setPen( qGray(color.rgb())>=127 ? Qt::black : Qt::white );
0306   painter->drawLine( colorRect.topLeft(), colorRect.bottomRight() );
0307   painter->drawLine( colorRect.topRight(), colorRect.bottomLeft() );
0308  }
0309 }*/
0310 
0311 void KColorCells::resizeEvent(QResizeEvent *)
0312 {
0313     // According to the Qt doc:
0314     //   If you need to set the width of a given column to a fixed value, call
0315     //   QHeaderView::resizeSection() on the table's {horizontal,vertical}
0316     //   header.
0317     // Therefore we iterate over each row and column and set the header section
0318     // size, as the sizeHint does indeed appear to be ignored in favor of a
0319     // minimum size that is larger than what we want.
0320     for (int index = 0; index < columnCount(); index++) {
0321         horizontalHeader()->resizeSection(index, sizeHintForColumn(index));
0322     }
0323     for (int index = 0; index < rowCount(); index++) {
0324         verticalHeader()->resizeSection(index, sizeHintForRow(index));
0325     }
0326 }
0327 
0328 int KColorCells::sizeHintForColumn(int /*column*/) const
0329 {
0330     return width() / columnCount();
0331 }
0332 
0333 int KColorCells::sizeHintForRow(int /*row*/) const
0334 {
0335     return height() / rowCount();
0336 }
0337 
0338 void KColorCells::mousePressEvent(QMouseEvent *e)
0339 {
0340     d->inMouse = true;
0341     d->mousePos = e->pos();
0342 
0343     QTableWidget::mousePressEvent(e);
0344 }
0345 
0346 int KColorCells::positionToCell(const QPoint &pos, bool ignoreBorders) const
0347 {
0348     //TODO ignoreBorders not yet handled
0349     Q_UNUSED(ignoreBorders)
0350 
0351     QTableWidgetItem *tableItem = itemAt(pos);
0352 
0353     if (!tableItem) {
0354         return -1;
0355     }
0356 
0357     const int itemRow = row(tableItem);
0358     const int itemColumn = column(tableItem);
0359     int cell = itemRow * columnCount() + itemColumn;
0360 
0361     /*if (!ignoreBorders)
0362     {
0363        int border = 2;
0364        int x = pos.x() - col * cellWidth();
0365        int y = pos.y() - row * cellHeight();
0366        if ( (x < border) || (x > cellWidth()-border) ||
0367             (y < border) || (y > cellHeight()-border))
0368           return -1;
0369     }*/
0370 
0371     return cell;
0372 }
0373 
0374 void KColorCells::mouseMoveEvent(QMouseEvent *e)
0375 {
0376     if (this->dragEnabled() || this->acceptDrops()) {
0377         if (!(e->buttons() & Qt::LeftButton)) {
0378             return;
0379         }
0380 
0381         if (d->inMouse) {
0382             int delay = QApplication::startDragDistance();
0383             if (e->x() > d->mousePos.x() + delay || e->x() < d->mousePos.x() - delay ||
0384                     e->y() > d->mousePos.y() + delay || e->y() < d->mousePos.y() - delay) {
0385                 // Drag color object
0386                 QTableWidgetItem *tableItem = itemAt(d->mousePos);
0387 
0388                 if (tableItem) {
0389                     QVariant var = tableItem->data(Qt::BackgroundRole);
0390                     QColor tmpCol = var.value<QColor>();
0391                     if (tmpCol.isValid()) {
0392                         KColorMimeData::createDrag(tmpCol, this)->start();
0393                     }
0394                 }
0395             }
0396         }
0397     } else {
0398         QTableWidget::mouseMoveEvent(e);
0399     }
0400 }
0401 
0402 void KColorCells::dragEnterEvent(QDragEnterEvent *event)
0403 {
0404     kDebug() << "KColorCells::dragEnterEvent() acceptDrags="
0405              << this->dragEnabled()
0406              << " canDecode=" << KColorMimeData::canDecode(event->mimeData())
0407              << endl;
0408     event->setAccepted(this->dragEnabled() && KColorMimeData::canDecode(event->mimeData()));
0409 }
0410 
0411 // Reimplemented to override QTableWidget's override.  Else dropping doesn't work.
0412 void KColorCells::dragMoveEvent(QDragMoveEvent *event)
0413 {
0414     kDebug() << "KColorCells::dragMoveEvent() acceptDrags="
0415              << this->dragEnabled()
0416              << " canDecode=" << KColorMimeData::canDecode(event->mimeData())
0417              << endl;
0418     event->setAccepted(this->dragEnabled() && KColorMimeData::canDecode(event->mimeData()));
0419 }
0420 
0421 void KColorCells::dropEvent(QDropEvent *event)
0422 {
0423     QColor c = KColorMimeData::fromMimeData(event->mimeData());
0424 
0425     kDebug() << "KColorCells::dropEvent() color.isValid=" << c.isValid();
0426     if (c.isValid()) {
0427         QTableWidgetItem *tableItem = itemAt(event->pos());
0428 
0429         if (tableItem) {
0430             tableItem->setData(Qt::BackgroundRole, c);
0431         }
0432     }
0433 }
0434 
0435 void KColorCells::mouseReleaseEvent(QMouseEvent *e)
0436 {
0437     if (selectionMode() != QAbstractItemView::NoSelection) {
0438         int cell = positionToCell(d->mousePos);
0439         int currentCell = positionToCell(e->pos());
0440 
0441         // If we release the mouse in another cell and we don't have
0442         // a drag we should ignore this event.
0443         if (currentCell != cell) {
0444             cell = -1;
0445         }
0446 
0447         if ((cell != -1) && (d->selected != cell)) {
0448             d->selected = cell;
0449 
0450             const int newRow = cell / columnCount();
0451             const int newColumn = cell % columnCount();
0452 
0453             clearSelection(); // we do not want old violet selected cells
0454 
0455             item(newRow, newColumn)->setSelected(true);
0456         }
0457 
0458         d->inMouse = false;
0459         if (cell != -1) {
0460             emit colorSelected(cell, color(cell));
0461         }
0462     }
0463 
0464     QTableWidget::mouseReleaseEvent(e);
0465 }
0466 
0467 void KColorCells::mouseDoubleClickEvent(QMouseEvent * /*e*/)
0468 {
0469     int cell = positionToCell(d->mousePos);
0470 
0471     if (cell != -1) {
0472         emit colorDoubleClicked(cell, color(cell));
0473     }
0474 }
0475 
0476 //-----------------------------------------------------------------------------
0477 
0478 class Q_DECL_HIDDEN KColorPatch::KColorPatchPrivate
0479 {
0480 public:
0481     KColorPatchPrivate(KColorPatch *q): q(q) {}
0482 
0483     KColorPatch *q;
0484     QColor color;
0485 };
0486 
0487 KColorPatch::KColorPatch(QWidget *parent) : QFrame(parent), d(new KColorPatchPrivate(this))
0488 {
0489     setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
0490     setAcceptDrops(true);
0491     setMinimumSize(12, 12);
0492 }
0493 
0494 KColorPatch::~KColorPatch()
0495 {
0496     delete d;
0497 }
0498 
0499 QColor KColorPatch::color() const
0500 {
0501     return d->color;
0502 }
0503 
0504 void KColorPatch::setColor(const QColor &col)
0505 {
0506     d->color = col.toRgb();
0507 
0508     update();
0509 }
0510 
0511 void KColorPatch::paintEvent(QPaintEvent *pe)
0512 {
0513     QFrame::paintEvent(pe);
0514     QPainter painter(this);
0515 
0516     fillOpaqueRect(&painter, contentsRect(), d->color);
0517 }
0518 
0519 void KColorPatch::mouseMoveEvent(QMouseEvent *e)
0520 {
0521     // Drag color object
0522     if (!(e->buttons() & Qt::LeftButton)) {
0523         return;
0524     }
0525     KColorMimeData::createDrag(d->color, this)->start();
0526 }
0527 
0528 void KColorPatch::dragEnterEvent(QDragEnterEvent *event)
0529 {
0530     event->setAccepted(KColorMimeData::canDecode(event->mimeData()));
0531 }
0532 
0533 void KColorPatch::dropEvent(QDropEvent *event)
0534 {
0535     QColor c = KColorMimeData::fromMimeData(event->mimeData());
0536     if (c.isValid()) {
0537         setColor(c);
0538         emit colorChanged(c);
0539     }
0540 }
0541 
0542 class KColorTable::KColorTablePrivate
0543 {
0544 public:
0545     KColorTablePrivate(KColorTable *q): q(q) {}
0546 
0547     void slotColorCellSelected(int index, const QColor &);
0548     void slotColorCellDoubleClicked(int index, const QColor &);
0549     void slotColorTextSelected(const QString &colorText);
0550     void slotSetColors(const QString &_collectionName);
0551     void slotShowNamedColorReadError(void);
0552 
0553     KColorTable *q;
0554     QString i18n_namedColors;
0555     KComboBox *combo;
0556     KColorCells *cells;
0557     QScrollArea *sv;
0558     QListWidget *mNamedColorList;
0559     KColorCollection *mPalette;
0560     int mMinWidth;
0561     int mCols;
0562     QMap<QString, QColor> m_namedColorMap;
0563 };
0564 
0565 KColorTable::KColorTable(QWidget *parent, int minWidth, int cols)
0566     : QWidget(parent), d(new KColorTablePrivate(this))
0567 {
0568     d->cells = nullptr;
0569     d->mPalette = nullptr;
0570     d->mMinWidth = minWidth;
0571     d->mCols = cols;
0572     d->i18n_namedColors  = i18n("Named Colors");
0573 
0574     QStringList diskPaletteList = KColorCollection::installedCollections();
0575     QStringList paletteList;
0576 
0577     // We must replace the untranslated file names by translate names (of course only for KDE's standard palettes)
0578     for (int i = 0; colorCollectionName[i].m_fileName; ++i) {
0579         diskPaletteList.removeAll(colorCollectionName[i].m_fileName);
0580         paletteList.append(i18nc("palette name", colorCollectionName[i].m_displayName));
0581     }
0582     paletteList += diskPaletteList;
0583     paletteList.append(d->i18n_namedColors);
0584 
0585     QVBoxLayout *layout = new QVBoxLayout(this);
0586 
0587     d->combo = new KComboBox(this);
0588     d->combo->setEditable(false);
0589     d->combo->addItems(paletteList);
0590     layout->addWidget(d->combo);
0591 
0592     d->sv = new QScrollArea(this);
0593     QSize cellSize = QSize(d->mMinWidth, 120);
0594     d->sv->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
0595     d->sv->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
0596     QSize minSize = QSize(d->sv->verticalScrollBar()->sizeHint().width(), 0);
0597     minSize += QSize(d->sv->frameWidth() * 2, 0);
0598     minSize += QSize(cellSize);
0599     d->sv->setFixedSize(minSize);
0600     layout->addWidget(d->sv);
0601 
0602     d->mNamedColorList = new QListWidget(this);
0603     d->mNamedColorList->setObjectName("namedColorList");
0604     d->mNamedColorList->setFixedSize(minSize);
0605     d->mNamedColorList->hide();
0606     layout->addWidget(d->mNamedColorList);
0607     connect(d->mNamedColorList, SIGNAL(currentTextChanged(QString)),
0608             this, SLOT(slotColorTextSelected(QString)));
0609 
0610     setFixedSize(sizeHint());
0611     connect(d->combo, SIGNAL(activated(QString)),
0612             this, SLOT(slotSetColors(QString)));
0613 }
0614 
0615 KColorTable::~KColorTable()
0616 {
0617     delete d->mPalette;
0618     delete d;
0619 }
0620 
0621 QString
0622 KColorTable::name() const
0623 {
0624     return d->combo->currentText();
0625 }
0626 
0627 static const char *const *namedColorFilePath(void)
0628 {
0629     //
0630     // 2000-02-05 Espen Sand.
0631     // Add missing filepaths here. Make sure the last entry is 0, 0!
0632     //
0633     // 2009-06-16 Pino Toscano
0634     //
0635     // You can specify either absolute paths or relative locations.
0636     // Relative locations are relative to GenericDataLocation (XDG_DATA_DIRS).
0637     //
0638     static const char *const path[] = {
0639 #if HAVE_X11
0640 #ifdef X11_RGBFILE
0641         X11_RGBFILE,
0642 #endif
0643         "/usr/share/X11/rgb.txt",
0644         "/usr/X11R6/lib/X11/rgb.txt",
0645         "/usr/openwin/lib/X11/rgb.txt", // for Solaris.
0646 #else /* systems without X11 */
0647         "kf5/kdeui/rgb.txt",
0648 #endif
0649         nullptr
0650     };
0651     return path;
0652 }
0653 
0654 void
0655 KColorTable::readNamedColor(void)
0656 {
0657     if (d->mNamedColorList->count() != 0) {
0658         return; // Strings already present
0659     }
0660 
0661     //
0662     // Code somewhat inspired by KColorCollection.
0663     //
0664 
0665     const char *const *path = namedColorFilePath();
0666     for (int i = 0; path[i]; ++i) {
0667         QString file;
0668         if (path[i][0] != '/') { // relative path
0669             file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString::fromLatin1(path[i]));
0670             if (file.isEmpty()) {
0671                 continue;
0672             }
0673         } else { // absolute path
0674             file = QString::fromLatin1(path[i]);
0675         }
0676 
0677         QFile paletteFile(file);
0678         if (!paletteFile.open(QIODevice::ReadOnly)) {
0679             continue;
0680         }
0681 
0682         QByteArray line;
0683         QStringList list;
0684         while (!paletteFile.atEnd()) {
0685             line = paletteFile.readLine();
0686 
0687             int red, green, blue;
0688             int pos = 0;
0689 
0690             if (sscanf(line, "%d %d %d%n", &red, &green, &blue, &pos) == 3) {
0691                 //
0692                 // Remove duplicates. Every name with a space and every name
0693                 // that start with "gray".
0694                 //
0695                 QString name = line.mid(pos).trimmed();
0696                 QByteArray s1 = line.mid(pos);
0697                 if (name.isNull() || name.indexOf(' ') != -1 ||
0698                         name.indexOf("gray") != -1 ||  name.indexOf("grey") != -1) {
0699                     continue;
0700                 }
0701 
0702                 const QColor color(red, green, blue);
0703                 if (color.isValid()) {
0704                     const QString colorName(i18nc("color", name.toLatin1().data()));
0705                     list.append(colorName);
0706                     d->m_namedColorMap[ colorName ] = color;
0707                 }
0708             }
0709         }
0710 
0711         list.sort();
0712         d->mNamedColorList->addItems(list);
0713         break;
0714     }
0715 
0716     if (d->mNamedColorList->count() == 0) {
0717         //
0718         // Give the error dialog box a chance to center above the
0719         // widget (or dialog). If we had displayed it now we could get a
0720         // situation where the (modal) error dialog box pops up first
0721         // preventing the real dialog to become visible until the
0722         // error dialog box is removed (== bad UI).
0723         //
0724         QTimer::singleShot(10, this, SLOT(slotShowNamedColorReadError()));
0725     }
0726 }
0727 
0728 void
0729 KColorTable::KColorTablePrivate::slotShowNamedColorReadError(void)
0730 {
0731     if (mNamedColorList->count() == 0) {
0732         QString pathMsg;
0733         int pathCount = 0;
0734 
0735         const char *const *path = namedColorFilePath();
0736         for (int i = 0; path[i]; i += 2, ++pathCount) {
0737             if (path[i + 1]) {
0738                 pathMsg += QLatin1String(path[i + 1]) + ", " + QString::fromLatin1(path[i]);
0739             } else {
0740                 pathMsg += QLatin1String(path[i]);
0741             }
0742             pathMsg += '\n';
0743         }
0744 
0745         QString finalMsg  = i18ncp("%1 is the number of paths, %2 is the list of paths (with newlines between them)",
0746                                    "Unable to read X11 RGB color strings. The following "
0747                                    "file location was examined:\n%2",
0748                                    "Unable to read X11 RGB color strings. The following "
0749                                    "file locations were examined:\n%2",
0750                                    pathCount, pathMsg);
0751 
0752         KMessageBox::error(q, finalMsg);
0753     }
0754 }
0755 
0756 //
0757 // 2000-02-12 Espen Sand
0758 // Set the color in two steps. The setColors() slot will not emit a signal
0759 // with the current color setting. The reason is that setColors() is used
0760 // by the color selector dialog on startup. In the color selector dialog
0761 // we normally want to display a startup color which we specify
0762 // when the dialog is started. The slotSetColors() slot below will
0763 // set the palette and then use the information to emit a signal with the
0764 // new color setting. It is only used by the combobox widget.
0765 //
0766 void
0767 KColorTable::KColorTablePrivate::slotSetColors(const QString &_collectionName)
0768 {
0769     q->setColors(_collectionName);
0770     if (mNamedColorList->count() && mNamedColorList->isVisible()) {
0771         int item = mNamedColorList->currentRow();
0772         mNamedColorList->setCurrentRow(item < 0 ? 0 : item);
0773         slotColorTextSelected(mNamedColorList->currentItem()->text());
0774     } else {
0775         slotColorCellSelected(0, QColor()); // FIXME: We need to save the current value!!
0776     }
0777 }
0778 
0779 void
0780 KColorTable::setColors(const QString &_collectionName)
0781 {
0782     QString collectionName(_collectionName);
0783 
0784     if (d->combo->currentText() != collectionName) {
0785         bool found = false;
0786         for (int i = 0; i < d->combo->count(); i++) {
0787             if (d->combo->itemText(i) == collectionName) {
0788                 d->combo->setCurrentIndex(i);
0789                 found = true;
0790                 break;
0791             }
0792         }
0793         if (!found) {
0794             d->combo->addItem(collectionName);
0795             d->combo->setCurrentIndex(d->combo->count() - 1);
0796         }
0797     }
0798 
0799     // We must again find the file name of the palette from the eventual translation
0800     for (int i = 0; colorCollectionName[i].m_fileName; ++i) {
0801         if (collectionName == i18nc("palette name", colorCollectionName[i].m_displayName)) {
0802             collectionName = colorCollectionName[i].m_fileName;
0803             break;
0804         }
0805     }
0806 
0807     //
0808     // 2000-02-12 Espen Sand
0809     // The palette mode "i18n_namedColors" does not use the KColorCollection
0810     // class. In fact, 'mPalette' and 'cells' are 0 when in this mode. The reason
0811     // for this is maninly that KColorCollection reads from and writes to files
0812     // using "locate()". The colors used in "i18n_namedColors" mode comes from
0813     // the X11 diretory and is not writable. I don't think this fit in
0814     // KColorCollection.
0815     //
0816     if (!d->mPalette || d->mPalette->name() != collectionName) {
0817         if (collectionName == d->i18n_namedColors) {
0818             d->sv->hide();
0819             d->mNamedColorList->show();
0820             readNamedColor();
0821 
0822             delete d->cells; d->cells = nullptr;
0823             delete d->mPalette; d->mPalette = nullptr;
0824         } else {
0825             d->mNamedColorList->hide();
0826             d->sv->show();
0827 
0828             delete d->cells;
0829             delete d->mPalette;
0830             d->mPalette = new KColorCollection(collectionName);
0831             int rows = (d->mPalette->count() + d->mCols - 1) / d->mCols;
0832             if (rows < 1) {
0833                 rows = 1;
0834             }
0835             d->cells = new KColorCells(d->sv->viewport(), rows, d->mCols);
0836             d->cells->setShading(false);
0837             d->cells->setAcceptDrags(false);
0838             QSize cellSize = QSize(d->mMinWidth, d->mMinWidth * rows / d->mCols);
0839             d->cells->setFixedSize(cellSize);
0840             for (int i = 0; i < d->mPalette->count(); i++) {
0841                 d->cells->setColor(i, d->mPalette->color(i));
0842             }
0843             connect(d->cells, SIGNAL(colorSelected(int,QColor)),
0844                     SLOT(slotColorCellSelected(int,QColor)));
0845             connect(d->cells, SIGNAL(colorDoubleClicked(int,QColor)),
0846                     SLOT(slotColorCellDoubleClicked(int,QColor)));
0847             d->sv->setWidget(d->cells);
0848             d->cells->show();
0849 
0850             //d->sv->updateScrollBars();
0851         }
0852     }
0853 }
0854 
0855 void
0856 KColorTable::KColorTablePrivate::slotColorCellSelected(int index, const QColor & /*color*/)
0857 {
0858     if (!mPalette || (index >= mPalette->count())) {
0859         return;
0860     }
0861     emit q->colorSelected(mPalette->color(index), mPalette->name(index));
0862 }
0863 
0864 void
0865 KColorTable::KColorTablePrivate::slotColorCellDoubleClicked(int index, const QColor & /*color*/)
0866 {
0867     if (!mPalette || (index >= mPalette->count())) {
0868         return;
0869     }
0870     emit q->colorDoubleClicked(mPalette->color(index), mPalette->name(index));
0871 }
0872 
0873 void
0874 KColorTable::KColorTablePrivate::slotColorTextSelected(const QString &colorText)
0875 {
0876     emit q->colorSelected(m_namedColorMap[ colorText ], colorText);
0877 }
0878 
0879 void
0880 KColorTable::addToCustomColors(const QColor &color)
0881 {
0882     setColors(i18nc("palette name", colorCollectionName[customColorIndex].m_displayName));
0883     d->mPalette->addColor(color);
0884     d->mPalette->save();
0885     delete d->mPalette;
0886     d->mPalette = nullptr;
0887     setColors(i18nc("palette name", colorCollectionName[customColorIndex].m_displayName));
0888 }
0889 
0890 void
0891 KColorTable::addToRecentColors(const QColor &color)
0892 {
0893     //
0894     // 2000-02-12 Espen Sand.
0895     // The 'mPalette' is always 0 when current mode is i18n_namedColors
0896     //
0897     bool recentIsSelected = false;
0898     if (d->mPalette && d->mPalette->name() == colorCollectionName[ recentColorIndex ].m_fileName) {
0899         delete d->mPalette;
0900         d->mPalette = nullptr;
0901         recentIsSelected = true;
0902     }
0903     KColorCollection *recentPal = new KColorCollection(colorCollectionName[ recentColorIndex ].m_fileName);
0904     if (recentPal->findColor(color) == -1) {
0905         recentPal->addColor(color);
0906         recentPal->save();
0907     }
0908     delete recentPal;
0909     if (recentIsSelected) {
0910         setColors(i18nc("palette name", colorCollectionName[ recentColorIndex ].m_displayName));
0911     }
0912 }
0913 
0914 class KCDPickerFilter;
0915 
0916 class Q_DECL_HIDDEN KColorDialog::KColorDialogPrivate
0917 {
0918 public:
0919     KColorDialogPrivate(KColorDialog *q): q(q) {}
0920 
0921     void setRgbEdit(const QColor &col);
0922     void setHsvEdit(const QColor &col);
0923     void setHtmlEdit(const QColor &col);
0924     void _setColor(const QColor &col, const QString &name = QString());
0925     void showColor(const QColor &color, const QString &name);
0926 
0927     void slotRGBChanged(void);
0928     void slotAlphaChanged(void);
0929     void slotHSVChanged(void);
0930     void slotHtmlChanged(void);
0931     void slotHSChanged(int, int);
0932     void slotVChanged(int);
0933     void slotAChanged(int);
0934     void slotModeChanged(int);
0935 
0936     void slotColorSelected(const QColor &col);
0937     void slotColorSelected(const QColor &col, const QString &name);
0938     void slotColorDoubleClicked(const QColor &col, const QString &name);
0939     void slotColorPicker();
0940     void slotAddToCustomColors();
0941     void slotDefaultColorClicked();
0942     /**
0943       * Write the settings of the dialog to config file.
0944      **/
0945     void slotWriteSettings();
0946 
0947     /**
0948      * Returns the mode.
0949      */
0950     KColorChooserMode chooserMode();
0951 
0952     /**
0953      * Sets a mode. Updates the color picker and the color bar.
0954      */
0955     void setChooserMode(KColorChooserMode c);
0956 
0957     KColorDialog *q;
0958     KColorTable *table;
0959     QString originalPalette;
0960     bool bRecursion;
0961     bool bEditRgb;
0962     bool bEditHsv;
0963     bool bEditHtml;
0964     bool bColorPicking;
0965     bool bAlphaEnabled;
0966     QLabel *colorName;
0967     KLineEdit *htmlName;
0968     QSpinBox *hedit;
0969     QSpinBox *sedit;
0970     QSpinBox *vedit;
0971     QSpinBox *redit;
0972     QSpinBox *gedit;
0973     QSpinBox *bedit;
0974     QWidget *alphaLabel;
0975     QSpinBox *aedit;
0976 
0977     KColorPatch *patch;
0978     KColorPatch *comparePatch;
0979 
0980     KColorChooserMode _mode;
0981     QButtonGroup *modeGroup;
0982 
0983     KHueSaturationSelector *hsSelector;
0984     KColorCollection *palette;
0985     KColorValueSelector *valuePal;
0986     KGradientSelector *alphaSelector;
0987     QVBoxLayout *l_right;
0988     QGridLayout *tl_layout;
0989     QCheckBox *cbDefaultColor;
0990     QColor defaultColor;
0991     QColor selColor;
0992 };
0993 
0994 KColorDialog::KColorDialog(QWidget *parent, bool modal)
0995     : KDialog(parent), d(new KColorDialogPrivate(this))
0996 {
0997     setCaption(i18n("Select Color"));
0998     setButtons(modal ? Ok | Cancel : Close);
0999     setModal(modal);
1000     d->bRecursion = true;
1001     d->bColorPicking = false;
1002     d->bAlphaEnabled = false;
1003     d->cbDefaultColor = nullptr;
1004     d->_mode = ChooserClassic;
1005     connect(this, SIGNAL(okClicked()), this, SLOT(slotWriteSettings()));
1006     connect(this, SIGNAL(closeClicked()), this, SLOT(slotWriteSettings()));
1007 
1008     QLabel *label;
1009 
1010     //
1011     // Create the top level page and its layout
1012     //
1013     QWidget *page = new QWidget(this);
1014     setMainWidget(page);
1015 
1016     QGridLayout *tl_layout = new QGridLayout(page);
1017     tl_layout->setContentsMargins(0, 0, 0, 0);
1018     d->tl_layout = tl_layout;
1019     tl_layout->addItem(new QSpacerItem(spacingHint() * 2, 0), 0, 1);
1020 
1021     //
1022     // the more complicated part: the left side
1023     // add a V-box
1024     //
1025     QVBoxLayout *l_left = new QVBoxLayout();
1026     tl_layout->addLayout(l_left, 0, 0);
1027 
1028     //
1029     // add a H-Box for the XY-Selector and a grid for the
1030     // entry fields
1031     //
1032     QHBoxLayout *l_ltop = new QHBoxLayout();
1033     l_left->addLayout(l_ltop);
1034 
1035     //
1036     // the palette and value selector go into the H-box
1037     //
1038     d->hsSelector = new KHueSaturationSelector(page);
1039     d->hsSelector->setMinimumSize(256, 256);
1040     l_ltop->addWidget(d->hsSelector, 8);
1041     connect(d->hsSelector, SIGNAL(valueChanged(int,int)),
1042             SLOT(slotHSChanged(int,int)));
1043 
1044     d->valuePal = new KColorValueSelector(page);
1045     d->valuePal->setMinimumSize(26, 70);
1046     d->valuePal->setIndent(false);
1047     d->valuePal->setArrowDirection(Qt::RightArrow);
1048     l_ltop->addWidget(d->valuePal, 1);
1049     connect(d->valuePal, SIGNAL(valueChanged(int)),
1050             SLOT(slotVChanged(int)));
1051 
1052     d->alphaSelector = new KGradientSelector(Qt::Horizontal, page);
1053     d->alphaSelector->setFixedSize(256, 26);
1054     d->alphaSelector->setIndent(false);
1055     d->alphaSelector->setArrowDirection(Qt::DownArrow);
1056     d->alphaSelector->setRange(0, 255);
1057     l_left->addWidget(d->alphaSelector, 1);
1058     connect(d->alphaSelector, SIGNAL(valueChanged(int)),
1059             SLOT(slotAChanged(int)));
1060 
1061     // a little space between
1062     l_left->addSpacing(10); // FIXME: remove hardcoded values
1063 
1064     QGridLayout *l_lbot = new QGridLayout();
1065     l_left->addLayout(l_lbot);
1066 
1067     // button group that manages the radio buttons
1068     QRadioButton *modeButton;
1069     d->modeGroup = new QButtonGroup(page);
1070     connect(d->modeGroup, SIGNAL(buttonClicked(int)), SLOT(slotModeChanged(int)));
1071 
1072     //
1073     // add the HSV fields
1074     //
1075     l_lbot->setColumnStretch(2, 10);
1076 
1077     modeButton = new QRadioButton(i18n("Hue:"), page);
1078     l_lbot->addWidget(modeButton, 0, 0);
1079     d->modeGroup->addButton(modeButton, ChooserHue);
1080 
1081     d->hedit = new QSpinBox(page);
1082     d->hedit->setMaximum(359);
1083     d->hedit->setSuffix(i18nc("The angular degree unit (for hue)", "\302\260")); //  U+00B0 DEGREE SIGN
1084     l_lbot->addWidget(d->hedit, 0, 1);
1085     connect(d->hedit, SIGNAL(valueChanged(int)),
1086             SLOT(slotHSVChanged()));
1087 
1088     modeButton = new QRadioButton(i18n("Saturation:"), page);
1089     l_lbot->addWidget(modeButton, 1, 0);
1090     d->modeGroup->addButton(modeButton, ChooserSaturation);
1091 
1092     d->sedit = new QSpinBox(page);
1093     d->sedit->setMaximum(255);
1094     l_lbot->addWidget(d->sedit, 1, 1);
1095     connect(d->sedit, SIGNAL(valueChanged(int)),
1096             SLOT(slotHSVChanged()));
1097 
1098     modeButton = new QRadioButton(i18nc("This is the V of HSV", "Value:"), page);
1099     l_lbot->addWidget(modeButton, 2, 0);
1100     d->modeGroup->addButton(modeButton, ChooserValue);
1101 
1102     d->vedit = new QSpinBox(page);
1103     d->vedit->setMaximum(255);
1104     l_lbot->addWidget(d->vedit, 2, 1);
1105     connect(d->vedit, SIGNAL(valueChanged(int)),
1106             SLOT(slotHSVChanged()));
1107 
1108     //
1109     // add the RGB fields
1110     //
1111     modeButton = new QRadioButton(i18n("Red:"), page);
1112     l_lbot->addWidget(modeButton, 0, 3);
1113     d->modeGroup->addButton(modeButton, ChooserRed);
1114 
1115     d->redit = new QSpinBox(page);
1116     d->redit->setMaximum(255);
1117     l_lbot->addWidget(d->redit, 0, 4);
1118     connect(d->redit, SIGNAL(valueChanged(int)),
1119             SLOT(slotRGBChanged()));
1120 
1121     modeButton = new QRadioButton(i18n("Green:"), page);
1122     l_lbot->addWidget(modeButton, 1, 3);
1123     d->modeGroup->addButton(modeButton, ChooserGreen);
1124 
1125     d->gedit = new QSpinBox(page);
1126     d->gedit->setMaximum(255);
1127     l_lbot->addWidget(d->gedit, 1, 4);
1128     connect(d->gedit, SIGNAL(valueChanged(int)),
1129             SLOT(slotRGBChanged()));
1130 
1131     modeButton = new QRadioButton(i18n("Blue:"), page);
1132     l_lbot->addWidget(modeButton, 2, 3);
1133     d->modeGroup->addButton(modeButton, ChooserBlue);
1134 
1135     d->bedit = new QSpinBox(page);
1136     d->bedit->setMaximum(255);
1137     l_lbot->addWidget(d->bedit, 2, 4);
1138     connect(d->bedit, SIGNAL(valueChanged(int)),
1139             SLOT(slotRGBChanged()));
1140 
1141     //the layout
1142     QHBoxLayout *layout = new QHBoxLayout(this);
1143     layout->setSpacing(0);
1144     layout->setContentsMargins(0, 0, 0, 0);
1145 
1146     //the frame
1147     QFrame *frame = new QFrame(page);
1148     frame->setLayout(layout);
1149 
1150     d->alphaLabel = frame;
1151     QWidget *spacer = new QWidget(d->alphaLabel);
1152     label = new QLabel(i18n("Alpha:"), d->alphaLabel);
1153     QStyleOptionButton option;
1154     option.initFrom(modeButton);
1155     QRect labelRect = modeButton->style()->subElementRect(QStyle::SE_RadioButtonContents, &option, modeButton);
1156     int indent = layoutDirection() == Qt::LeftToRight ? labelRect.left() : modeButton->geometry().right() - labelRect.right();
1157     spacer->setFixedWidth(indent);
1158     l_lbot->addWidget(d->alphaLabel, 3, 3);
1159 
1160     d->aedit = new QSpinBox(page);
1161     d->aedit->setMaximum(255);
1162     label->setBuddy(d->aedit);
1163     l_lbot->addWidget(d->aedit, 3, 4);
1164     connect(d->aedit, SIGNAL(valueChanged(int)),
1165             SLOT(slotAlphaChanged()));
1166 
1167     d->aedit->setVisible(false);
1168     d->alphaLabel->setVisible(false);
1169     d->alphaSelector->setVisible(false);
1170 
1171     //
1172     // add a layout for the right side
1173     //
1174     d->l_right = new QVBoxLayout;
1175     tl_layout->addLayout(d->l_right, 0, 2);
1176 
1177     //
1178     // Add the palette table
1179     //
1180     d->table = new KColorTable(page);
1181     d->l_right->addWidget(d->table, 10);
1182 
1183     connect(d->table, SIGNAL(colorSelected(QColor,QString)),
1184             SLOT(slotColorSelected(QColor,QString)));
1185 
1186     connect(
1187         d->table,
1188         SIGNAL(colorDoubleClicked(QColor,QString)),
1189         SLOT(slotColorDoubleClicked(QColor,QString))
1190     );
1191     // Store the default value for saving time.
1192     d->originalPalette = d->table->name();
1193 
1194     //
1195     // a little space between
1196     //
1197     d->l_right->addSpacing(10);
1198 
1199     QHBoxLayout *l_hbox = new QHBoxLayout();
1200     d->l_right->addItem(l_hbox);
1201 
1202     //
1203     // The add to custom colors button
1204     //
1205     QPushButton *addButton = new QPushButton(page);
1206     addButton->setText(i18n("&Add to Custom Colors"));
1207     l_hbox->addWidget(addButton, 0, Qt::AlignLeft);
1208     connect(addButton, SIGNAL(clicked()), SLOT(slotAddToCustomColors()));
1209 
1210     //
1211     // The color picker button
1212     //
1213     QPushButton *button = new QPushButton(page);
1214     button->setIcon(QIcon::fromTheme("color-picker"));
1215     int commonHeight = addButton->sizeHint().height();
1216     button->setFixedSize(commonHeight, commonHeight);
1217     l_hbox->addWidget(button, 0, Qt::AlignHCenter);
1218     connect(button, SIGNAL(clicked()), SLOT(slotColorPicker()));
1219 
1220     //
1221     // a little space between
1222     //
1223     d->l_right->addSpacing(10);
1224 
1225     //
1226     // and now the entry fields and the patch (=colored box)
1227     //
1228     QGridLayout *l_grid = new QGridLayout();
1229     d->l_right->addLayout(l_grid);
1230 
1231     l_grid->setColumnStretch(2, 1);
1232 
1233     label = new QLabel(page);
1234     label->setText(i18n("Name:"));
1235     l_grid->addWidget(label, 0, 1, Qt::AlignLeft);
1236 
1237     d->colorName = new QLabel(page);
1238     l_grid->addWidget(d->colorName, 0, 2, Qt::AlignLeft);
1239 
1240     label = new QLabel(page);
1241     label->setText(i18n("HTML:"));
1242     l_grid->addWidget(label, 1, 1, Qt::AlignLeft);
1243 
1244     d->htmlName = new KLineEdit(page);
1245     d->htmlName->setMaxLength(13);   // Qt's QColor allows 12 hexa-digits
1246     d->htmlName->setText("#FFFFFF"); // But HTML uses only 6, so do not worry about the size
1247     int w = d->htmlName->fontMetrics().width(QLatin1String("#DDDDDDD"));
1248     d->htmlName->setFixedWidth(w);
1249     l_grid->addWidget(d->htmlName, 1, 2, Qt::AlignLeft);
1250 
1251     connect(d->htmlName, SIGNAL(textChanged(QString)),
1252             SLOT(slotHtmlChanged()));
1253 
1254     d->patch = new KColorPatch(page);
1255     d->patch->setFixedSize(48, 48);
1256     l_grid->addWidget(d->patch, 0, 0, 2, 1, Qt::AlignHCenter | Qt::AlignVCenter);
1257     connect(d->patch, SIGNAL(colorChanged(QColor)),
1258             SLOT(setColor(QColor)));
1259 
1260     //
1261     // chain fields together
1262     //
1263     setTabOrder(d->hedit, d->sedit);
1264     setTabOrder(d->sedit, d->vedit);
1265     setTabOrder(d->vedit, d->redit);
1266     setTabOrder(d->redit, d->gedit);
1267     setTabOrder(d->gedit, d->bedit);
1268     setTabOrder(d->bedit, d->aedit);
1269 
1270     tl_layout->activate();
1271     page->setMinimumSize(page->sizeHint());
1272 
1273     readSettings();
1274     d->bRecursion = false;
1275     d->bEditHsv = false;
1276     d->bEditRgb = false;
1277     d->bEditHtml = false;
1278 
1279     setFixedSize(sizeHint());
1280     QColor col;
1281     col.setHsv(0, 0, 255);
1282     d->_setColor(col);
1283 
1284 // FIXME: with enabled event filters, it crashes after ever enter of a drag.
1285 // better disable drag and drop than crashing it...
1286 //   d->htmlName->installEventFilter(this);
1287 //   d->hsSelector->installEventFilter(this);
1288     d->hsSelector->setAcceptDrops(true);
1289 
1290     d->setChooserMode(ChooserValue);
1291 }
1292 
1293 KColorDialog::~KColorDialog()
1294 {
1295     delete d;
1296 }
1297 
1298 bool
1299 KColorDialog::eventFilter(QObject *obj, QEvent *ev)
1300 {
1301     if ((obj == d->htmlName) || (obj == d->hsSelector))
1302         switch (ev->type()) {
1303         case QEvent::DragEnter:
1304         case QEvent::DragMove:
1305         case QEvent::DragLeave:
1306         case QEvent::Drop:
1307         case QEvent::DragResponse:
1308             qApp->sendEvent(d->patch, ev);
1309             return true;
1310         default:
1311             break;
1312         }
1313     return KDialog::eventFilter(obj, ev);
1314 }
1315 
1316 void
1317 KColorDialog::setDefaultColor(const QColor &col)
1318 {
1319     if (!d->cbDefaultColor) {
1320         //
1321         // a little space between
1322         //
1323         d->l_right->addSpacing(10);
1324 
1325         //
1326         // and the "default color" checkbox, under all items on the right side
1327         //
1328         d->cbDefaultColor = new QCheckBox(i18n("Default color"), mainWidget());
1329 
1330         d->l_right->addWidget(d->cbDefaultColor);
1331 
1332         mainWidget()->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);   // cancel setFixedSize()
1333         d->tl_layout->activate();
1334         mainWidget()->setMinimumSize(mainWidget()->sizeHint());
1335         setFixedSize(sizeHint());
1336 
1337         connect(d->cbDefaultColor, SIGNAL(clicked()), SLOT(slotDefaultColorClicked()));
1338     }
1339 
1340     d->defaultColor = col;
1341 
1342     d->slotDefaultColorClicked();
1343 }
1344 
1345 QColor KColorDialog::defaultColor() const
1346 {
1347     return d->defaultColor;
1348 }
1349 
1350 void KColorDialog::setAlphaChannelEnabled(bool alpha)
1351 {
1352     if (d->bAlphaEnabled != alpha) {
1353         d->bAlphaEnabled = alpha;
1354         d->aedit->setVisible(d->bAlphaEnabled);
1355         d->alphaLabel->setVisible(d->bAlphaEnabled);
1356         d->alphaSelector->setVisible(d->bAlphaEnabled);
1357 
1358         mainWidget()->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);   // cancel setFixedSize()
1359         d->tl_layout->activate();
1360         mainWidget()->setMinimumSize(mainWidget()->sizeHint());
1361         setFixedSize(sizeHint());
1362     }
1363 }
1364 
1365 bool KColorDialog::isAlphaChannelEnabled() const
1366 {
1367     return d->bAlphaEnabled;
1368 }
1369 
1370 void KColorDialog::KColorDialogPrivate::setChooserMode(KColorChooserMode c)
1371 {
1372     _mode = c;
1373     hsSelector->setChooserMode(c);
1374     valuePal->setChooserMode(c);
1375 
1376     modeGroup->button(valuePal->chooserMode())->setChecked(true);
1377     valuePal->updateContents();
1378     hsSelector->updateContents();
1379     valuePal->update();
1380     hsSelector->update();
1381     slotHSVChanged();
1382 }
1383 
1384 KColorChooserMode KColorDialog::KColorDialogPrivate::chooserMode()
1385 {
1386     return _mode;
1387 }
1388 
1389 void KColorDialog::KColorDialogPrivate::slotDefaultColorClicked()
1390 {
1391     if (cbDefaultColor->isChecked()) {
1392         selColor = defaultColor;
1393         showColor(selColor, i18n("-default-"));
1394     } else {
1395         showColor(selColor, QString());
1396     }
1397     emit q->colorSelected(selColor);
1398 }
1399 
1400 void
1401 KColorDialog::KColorDialogPrivate::slotModeChanged(int id)
1402 {
1403     setChooserMode(KColorChooserMode(id));
1404 }
1405 
1406 void
1407 KColorDialog::readSettings()
1408 {
1409     KConfigGroup group(KSharedConfig::openConfig(), "Colors");
1410 
1411     QString collectionName = group.readEntry("CurrentPalette");
1412     if (collectionName.isEmpty()) {
1413         collectionName = i18nc("palette name", colorCollectionName[fortyColorIndex].m_displayName);
1414     } else {
1415         for (int i = 0; colorCollectionName[i].m_fileName; ++i) {
1416             if (collectionName == colorCollectionName[i].m_displayName) {
1417                 collectionName = i18nc("palette name", colorCollectionName[i].m_displayName);
1418                 break;
1419             }
1420         }
1421     }
1422 
1423     d->table->setColors(collectionName);
1424 }
1425 
1426 void
1427 KColorDialog::KColorDialogPrivate::slotWriteSettings()
1428 {
1429     KConfigGroup group(KSharedConfig::openConfig(), "Colors");
1430 
1431     QString collectionName = table->name();
1432     if (!group.hasDefault("CurrentPalette") && table->name() == originalPalette) {
1433         group.revertToDefault("CurrentPalette");
1434     } else {
1435         QString collectionName(table->name());
1436         for (int i = 0; colorCollectionName[i].m_fileName; ++i) {
1437             if (collectionName == i18nc("palette name", colorCollectionName[i].m_displayName)) {
1438                 collectionName = colorCollectionName[i].m_displayName;
1439                 break;
1440             }
1441         }
1442         group.writeEntry("CurrentPalette", collectionName); //Make sure the untranslated name is saved, assuming there is one
1443     }
1444 }
1445 
1446 QColor
1447 KColorDialog::color() const
1448 {
1449     if (d->cbDefaultColor && d->cbDefaultColor->isChecked()) {
1450         return QColor();
1451     }
1452     if (d->selColor.isValid()) {
1453         d->table->addToRecentColors(d->selColor);
1454     }
1455     return d->selColor;
1456 }
1457 
1458 void KColorDialog::setColor(const QColor &col)
1459 {
1460     d->_setColor(col);
1461 }
1462 
1463 //
1464 // static function to display dialog and return color
1465 //
1466 int KColorDialog::getColor(QColor &theColor, QWidget *parent)
1467 {
1468     KColorDialog dlg(parent, true);
1469     dlg.setObjectName("Color Selector");
1470     if (theColor.isValid()) {
1471         dlg.setColor(theColor);
1472     }
1473     int result = dlg.exec();
1474 
1475     if (result == Accepted) {
1476         theColor = dlg.color();
1477     }
1478 
1479     return result;
1480 }
1481 
1482 //
1483 // static function to display dialog and return color
1484 //
1485 int KColorDialog::getColor(QColor &theColor, const QColor &defaultCol, QWidget *parent)
1486 {
1487     KColorDialog dlg(parent, true);
1488     dlg.setObjectName("Color Selector");
1489     dlg.setDefaultColor(defaultCol);
1490     dlg.setColor(theColor);
1491     int result = dlg.exec();
1492 
1493     if (result == Accepted) {
1494         theColor = dlg.color();
1495     }
1496 
1497     return result;
1498 }
1499 
1500 void KColorDialog::KColorDialogPrivate::slotRGBChanged(void)
1501 {
1502     if (bRecursion) {
1503         return;
1504     }
1505     int red = redit->value();
1506     int grn = gedit->value();
1507     int blu = bedit->value();
1508 
1509     if (red > 255 || red < 0) {
1510         return;
1511     }
1512     if (grn > 255 || grn < 0) {
1513         return;
1514     }
1515     if (blu > 255 || blu < 0) {
1516         return;
1517     }
1518 
1519     QColor col;
1520     col.setRgb(red, grn, blu, aedit->value());
1521     bEditRgb = true;
1522     _setColor(col);
1523     bEditRgb = false;
1524 }
1525 
1526 void KColorDialog::KColorDialogPrivate::slotAlphaChanged(void)
1527 {
1528     if (bRecursion) {
1529         return;
1530     }
1531     int alpha = aedit->value();
1532 
1533     if (alpha > 255 || alpha < 0) {
1534         return;
1535     }
1536 
1537     QColor col = selColor;
1538     col.setAlpha(alpha);
1539     _setColor(col);
1540 }
1541 
1542 void KColorDialog::KColorDialogPrivate::slotHtmlChanged(void)
1543 {
1544     if (bRecursion || htmlName->text().isEmpty()) {
1545         return;
1546     }
1547 
1548     QString strColor(htmlName->text());
1549 
1550     // Assume that a user does not want to type the # all the time
1551     if (strColor[0] != '#') {
1552         bool signalsblocked = htmlName->blockSignals(true);
1553         strColor.prepend("#");
1554         htmlName->setText(strColor);
1555         htmlName->blockSignals(signalsblocked);
1556     }
1557 
1558     const QColor color(strColor);
1559 
1560     if (color.isValid()) {
1561         QColor col(color);
1562         bEditHtml = true;
1563         _setColor(col);
1564         bEditHtml = false;
1565     }
1566 }
1567 
1568 void KColorDialog::KColorDialogPrivate::slotHSVChanged(void)
1569 {
1570     if (bRecursion) {
1571         return;
1572     }
1573     int hue = hedit->value();
1574     int sat = sedit->value();
1575     int val = vedit->value();
1576 
1577     if (hue > 359 || hue < 0) {
1578         return;
1579     }
1580     if (sat > 255 || sat < 0) {
1581         return;
1582     }
1583     if (val > 255 || val < 0) {
1584         return;
1585     }
1586 
1587     QColor col;
1588     col.setHsv(hue, sat, val, aedit->value());
1589     bEditHsv = true;
1590     _setColor(col);
1591     bEditHsv = false;
1592 }
1593 
1594 void KColorDialog::KColorDialogPrivate::slotHSChanged(int x, int y)
1595 {
1596     QColor col = selColor;
1597     KColorChooserMode xMode = chooserXMode(chooserMode());
1598     KColorChooserMode yMode = chooserYMode(chooserMode());
1599     setComponentValue(col, xMode, x / (xMode == ChooserHue ? 360.0 : 255.0));
1600     setComponentValue(col, yMode, y / (yMode == ChooserHue ? 360.0 : 255.0));
1601     _setColor(col);
1602 }
1603 
1604 void KColorDialog::KColorDialogPrivate::slotVChanged(int v)
1605 {
1606     QColor col = selColor;
1607     setComponentValue(col, chooserMode(), v / (chooserMode() == ChooserHue ? 360.0 : 255.0));
1608     _setColor(col);
1609 }
1610 
1611 void KColorDialog::KColorDialogPrivate::slotAChanged(int value)
1612 {
1613     QColor col = selColor;
1614     col.setAlpha(value);
1615     _setColor(col);
1616 }
1617 
1618 void KColorDialog::KColorDialogPrivate::slotColorSelected(const QColor &color)
1619 {
1620     _setColor(color);
1621 }
1622 
1623 void KColorDialog::KColorDialogPrivate::slotAddToCustomColors()
1624 {
1625     table->addToCustomColors(selColor);
1626 }
1627 
1628 void KColorDialog::KColorDialogPrivate::slotColorSelected(const QColor &color, const QString &name)
1629 {
1630     _setColor(color, name);
1631 }
1632 
1633 void KColorDialog::KColorDialogPrivate::slotColorDoubleClicked
1634 (
1635     const QColor   &color,
1636     const QString &name
1637 )
1638 {
1639     _setColor(color, name);
1640     q->accept();
1641 }
1642 
1643 void KColorDialog::KColorDialogPrivate::_setColor(const QColor &color, const QString &name)
1644 {
1645     if (color.isValid()) {
1646         if (cbDefaultColor && cbDefaultColor->isChecked()) {
1647             cbDefaultColor->setChecked(false);
1648         }
1649         selColor = color;
1650     } else {
1651         if (cbDefaultColor && cbDefaultColor->isChecked()) {
1652             cbDefaultColor->setChecked(true);
1653         }
1654         selColor = defaultColor;
1655     }
1656 
1657     showColor(selColor, name);
1658 
1659     emit q->colorSelected(selColor);
1660 }
1661 
1662 // show but don't set into selColor, nor emit colorSelected
1663 void KColorDialog::KColorDialogPrivate::showColor(const QColor &color, const QString &name)
1664 {
1665     bRecursion = true;
1666 
1667     if (name.isEmpty()) {
1668         colorName->setText(i18n("-unnamed-"));
1669     } else {
1670         colorName->setText(name);
1671     }
1672 
1673     patch->setColor(color);
1674 
1675     setRgbEdit(color);
1676     setHsvEdit(color);
1677     setHtmlEdit(color);
1678     aedit->setValue(color.alpha());
1679 
1680     QColor rgbColor = color.toRgb();
1681     bool ltr = q->layoutDirection() == Qt::LeftToRight;
1682     rgbColor.setAlpha(ltr ? 0 : 255);
1683     alphaSelector->setFirstColor(rgbColor);
1684     rgbColor.setAlpha(ltr ? 255 : 0);
1685     alphaSelector->setSecondColor(rgbColor);
1686     alphaSelector->setValue(color.alpha());
1687 
1688     KColorChooserMode xMode = chooserXMode(chooserMode());
1689     KColorChooserMode yMode = chooserYMode(chooserMode());
1690     int xValue = qRound(getComponentValue(color, xMode) * (xMode == ChooserHue ? 360.0 : 255.0));
1691     int yValue = qRound(getComponentValue(color, yMode) * (yMode == ChooserHue ? 360.0 : 255.0));
1692     int value = qRound(getComponentValue(color, chooserMode()) * (chooserMode() == ChooserHue ? 360.0 : 255.0));
1693     hsSelector->setValues(xValue, yValue);
1694     valuePal->setValue(value);
1695 
1696     bool blocked = valuePal->blockSignals(true);
1697 
1698     valuePal->setHue(color.hue());
1699     valuePal->setSaturation(color.saturation());
1700     valuePal->setColorValue(color.value());
1701     valuePal->updateContents();
1702     valuePal->blockSignals(blocked);
1703     valuePal->update();
1704 
1705     blocked = hsSelector->blockSignals(true);
1706 
1707     hsSelector->setHue(color.hue());
1708     hsSelector->setSaturation(color.saturation());
1709     hsSelector->setColorValue(color.value());
1710     hsSelector->updateContents();
1711     hsSelector->blockSignals(blocked);
1712     hsSelector->update();
1713 
1714     bRecursion = false;
1715 }
1716 
1717 void
1718 KColorDialog::KColorDialogPrivate::slotColorPicker()
1719 {
1720     bColorPicking = true;
1721     q->grabMouse(Qt::CrossCursor);
1722     q->grabKeyboard();
1723 }
1724 
1725 void
1726 KColorDialog::mouseMoveEvent(QMouseEvent *e)
1727 {
1728     if (d->bColorPicking) {
1729         d->_setColor(grabColor(e->globalPos()));
1730         return;
1731     }
1732 
1733     KDialog::mouseMoveEvent(e);
1734 }
1735 
1736 void
1737 KColorDialog::mouseReleaseEvent(QMouseEvent *e)
1738 {
1739     if (d->bColorPicking) {
1740         d->bColorPicking = false;
1741         releaseMouse();
1742         releaseKeyboard();
1743         d->_setColor(grabColor(e->globalPos()));
1744         return;
1745     }
1746     KDialog::mouseReleaseEvent(e);
1747 }
1748 
1749 QColor
1750 KColorDialog::grabColor(const QPoint &p)
1751 {
1752     auto fallback = [p]() {
1753         QWidget *desktop = QApplication::desktop();
1754         QPixmap pm = QPixmap::grabWindow(desktop->winId(), p.x(), p.y(), 1, 1);
1755         QImage i = pm.toImage();
1756         return i.pixel(0, 0);
1757     };
1758 #if HAVE_X11
1759     if (!QX11Info::isPlatformX11()) {
1760         return fallback();
1761     }
1762     // we use the X11 API directly in this case as we are not getting back a valid
1763     // return from QPixmap::grabWindow in the case where the application is using
1764     // an argb visual
1765     if (!qApp->desktop()->geometry().contains(p)) {
1766         return QColor();
1767     }
1768     Window root = RootWindow(QX11Info::display(), QX11Info::appScreen());
1769     XImage *ximg = XGetImage(QX11Info::display(), root, p.x(), p.y(), 1, 1, -1, ZPixmap);
1770     unsigned long xpixel = XGetPixel(ximg, 0, 0);
1771     XDestroyImage(ximg);
1772     XColor xcol;
1773     xcol.pixel = xpixel;
1774     xcol.flags = DoRed | DoGreen | DoBlue;
1775     XQueryColor(QX11Info::display(),
1776                 DefaultColormap(QX11Info::display(), QX11Info::appScreen()),
1777                 &xcol);
1778     return QColor::fromRgbF(xcol.red / 65535.0, xcol.green / 65535.0, xcol.blue / 65535.0);
1779 #else
1780     return fallback();
1781 #endif
1782 }
1783 
1784 void
1785 KColorDialog::keyPressEvent(QKeyEvent *e)
1786 {
1787     if (d->bColorPicking) {
1788         if (e->key() == Qt::Key_Escape) {
1789             d->bColorPicking = false;
1790             releaseMouse();
1791             releaseKeyboard();
1792         }
1793         e->accept();
1794         return;
1795     }
1796     KDialog::keyPressEvent(e);
1797 }
1798 
1799 void KColorDialog::KColorDialogPrivate::setRgbEdit(const QColor &col)
1800 {
1801     if (bEditRgb) {
1802         return;
1803     }
1804     int r, g, b;
1805     col.getRgb(&r, &g, &b);
1806 
1807     redit->setValue(r);
1808     gedit->setValue(g);
1809     bedit->setValue(b);
1810 }
1811 
1812 void KColorDialog::KColorDialogPrivate::setHtmlEdit(const QColor &col)
1813 {
1814     if (bEditHtml) {
1815         return;
1816     }
1817     int r, g, b;
1818     col.getRgb(&r, &g, &b);
1819     QString num;
1820 
1821     num.sprintf("#%02X%02X%02X", r, g, b);
1822     htmlName->setText(num);
1823 }
1824 
1825 void KColorDialog::KColorDialogPrivate::setHsvEdit(const QColor &col)
1826 {
1827     if (bEditHsv) {
1828         return;
1829     }
1830     int h, s, v;
1831     col.getHsv(&h, &s, &v);
1832 
1833     hedit->setValue(h);
1834     sedit->setValue(s);
1835     vedit->setValue(v);
1836 }
1837 
1838 #include "moc_kcolordialog.cpp"
1839 #include "moc_kcolordialog_p.cpp"