diff --git a/lgpl/generic/kpColorCollection.cpp b/lgpl/generic/kpColorCollection.cpp index 47cc6278..afa56e2b 100644 --- a/lgpl/generic/kpColorCollection.cpp +++ b/lgpl/generic/kpColorCollection.cpp @@ -1,535 +1,537 @@ // REFACT0R: Remote open/save file logic is duplicated in kpDocument. // HITODO: Test when remote file support in KDE 4 stabilizes /* This file is part of the KDE libraries Copyright (C) 1999 Waldo Bastian (bastian@kde.org) Copyright (C) 2007 Clarence Dang (dang@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //----------------------------------------------------------------------------- // KDE color collection #define DEBUG_KP_COLOR_COLLECTION 0 #include "kpColorCollection.h" #include "kpUrlFormatter.h" #include // kdelibs4support #include #include #include "kpLogCategories.h" #include #include #include #include #include #include #include #include struct ColorNode { ColorNode(const QColor &c, const QString &n) : color(c), name(n) {} QColor color; QString name; }; //--------------------------------------------------------------------- +Q_LOGGING_CATEGORY(kpLogColorCollection, "kp.colorCollection") + //BEGIN kpColorCollectionPrivate class kpColorCollectionPrivate { public: kpColorCollectionPrivate(); kpColorCollectionPrivate(const kpColorCollectionPrivate&); QList colorList; QString name; QString desc; kpColorCollection::Editable editable; }; kpColorCollectionPrivate::kpColorCollectionPrivate() : editable(kpColorCollection::Yes) { } kpColorCollectionPrivate::kpColorCollectionPrivate(const kpColorCollectionPrivate& p) : colorList(p.colorList), name(p.name), desc(p.desc), editable(p.editable) { } //END kpColorCollectionPrivate //--------------------------------------------------------------------- QStringList kpColorCollection::installedCollections() { QStringList paletteList; QStringList paths = QStandardPaths::locateAll(QStandardPaths::GenericConfigLocation, QStringLiteral("colors"), QStandardPaths::LocateDirectory); for (const auto &path : paths) { paletteList.append(QDir(path).entryList(QStringList(), QDir::Files)); } return paletteList; } kpColorCollection::kpColorCollection() { d = new kpColorCollectionPrivate(); } kpColorCollection::kpColorCollection(const kpColorCollection &p) { d = new kpColorCollectionPrivate(*p.d); } kpColorCollection::~kpColorCollection() { // Need auto-save? delete d; } static void CouldNotOpenDialog (const QUrl &url, QWidget *parent) { KMessageBox::sorry (parent, i18n ("Could not open color palette \"%1\".", kpUrlFormatter::PrettyFilename (url))); } // TODO: Set d->editable? bool kpColorCollection::open(const QUrl &url, QWidget *parent) { QString tempPaletteFilePath; if (url.isEmpty () || !KIO::NetAccess::download (url, tempPaletteFilePath, parent)) { #if DEBUG_KP_COLOR_COLLECTION - qCDebug(kpLogMisc) << "\tcould not download"; + qCDebug(kpLogColorCollection) << "\tcould not download"; #endif ::CouldNotOpenDialog (url, parent); return false; } // sync: remember to "KIO::NetAccess::removeTempFile (tempPaletteFilePath)" in all exit paths QFile paletteFile(tempPaletteFilePath); if (!paletteFile.exists() || !paletteFile.open(QIODevice::ReadOnly)) { #if DEBUG_KP_COLOR_COLLECTION - qCDebug(kpLogMisc) << "\tcould not open qfile"; + qCDebug(kpLogColorCollection) << "\tcould not open qfile"; #endif KIO::NetAccess::removeTempFile (tempPaletteFilePath); ::CouldNotOpenDialog (url, parent); return false; } // Read first line // Expected "GIMP Palette" QString line = QString::fromLocal8Bit(paletteFile.readLine()); if (line.indexOf(QLatin1String(" Palette")) == -1) { KIO::NetAccess::removeTempFile (tempPaletteFilePath); KMessageBox::sorry (parent, i18n ("Could not open color palette \"%1\" - unsupported format.\n" "The file may be corrupt.", kpUrlFormatter::PrettyFilename (url))); return false; } QList newColorList; QString newDesc; while( !paletteFile.atEnd() ) { line = QString::fromLocal8Bit(paletteFile.readLine()); if (line[0] == '#') { // This is a comment line line = line.mid(1); // Strip '#' line = line.trimmed(); // Strip remaining white space.. if (!line.isEmpty()) { newDesc += line+'\n'; // Add comment to description } } else { // This is a color line, hopefully line = line.trimmed(); if (line.isEmpty()) continue; int r, g, b; int pos = 0; if (sscanf(line.toLatin1(), "%d %d %d%n", &r, &g, &b, &pos) >= 3) { r = qBound(0, r, 255); g = qBound(0, g, 255); b = qBound(0, b, 255); QString name = line.mid(pos).trimmed(); newColorList.append(ColorNode(QColor(r, g, b), name)); } } } d->colorList = newColorList; d->name.clear (); d->desc = newDesc; KIO::NetAccess::removeTempFile (tempPaletteFilePath); return true; } static void CouldNotOpenKDEDialog (const QString &name, QWidget *parent) { KMessageBox::sorry (parent, i18n ("Could not open KDE color palette \"%1\".", name)); } bool kpColorCollection::openKDE(const QString &name, QWidget *parent) { #if DEBUG_KP_COLOR_COLLECTION - qCDebug(kpLogMisc) << "name=" << name; + qCDebug(kpLogColorCollection) << "name=" << name; #endif if (name.isEmpty()) { #if DEBUG_KP_COLOR_COLLECTION - qCDebug(kpLogMisc) << "name.isEmpty"; + qCDebug(kpLogColorCollection) << "name.isEmpty"; #endif ::CouldNotOpenKDEDialog (name, parent); return false; } QString filename = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, "colors/" + name); if (filename.isEmpty()) { #if DEBUG_KP_COLOR_COLLECTION - qCDebug(kpLogMisc) << "could not find file"; + qCDebug(kpLogColorCollection) << "could not find file"; #endif ::CouldNotOpenKDEDialog (name, parent); return false; } // (this will pop up an error dialog on failure) if (!open (QUrl::fromLocalFile (filename), parent)) { #if DEBUG_KP_COLOR_COLLECTION - qCDebug(kpLogMisc) << "could not open"; + qCDebug(kpLogColorCollection) << "could not open"; #endif return false; } d->name = name; #if DEBUG_KP_COLOR_COLLECTION - qCDebug(kpLogMisc) << "opened"; + qCDebug(kpLogColorCollection) << "opened"; #endif return true; } static void CouldNotSaveDialog (const QUrl &url, QWidget *parent) { // TODO: use file.errorString() KMessageBox::error (parent, i18n ("Could not save color palette as \"%1\".", kpUrlFormatter::PrettyFilename (url))); } static void SaveToFile (kpColorCollectionPrivate *d, QIODevice *device) { // HITODO: QTextStream can fail but does not report errors. // Bug in KColorCollection too. QTextStream str (device); QString description = d->desc.trimmed(); description = '#'+description.split( '\n', QString::KeepEmptyParts).join(QLatin1String("\n#")); str << "KDE RGB Palette\n"; str << description << "\n"; for (const auto &node : d->colorList) { // Added for KolourPaint. if(!node.color.isValid ()) continue; int r,g,b; node.color.getRgb(&r, &g, &b); str << r << " " << g << " " << b << " " << node.name << "\n"; } str.flush(); } bool kpColorCollection::saveAs(const QUrl &url, bool showOverwritePrompt, QWidget *parent) const { if (showOverwritePrompt && KIO::NetAccess::exists (url, KIO::NetAccess::DestinationSide/*write*/, parent)) { int result = KMessageBox::warningContinueCancel (parent, i18n ("A color palette called \"%1\" already exists.\n" "Do you want to overwrite it?", kpUrlFormatter::PrettyFilename (url)), QString (), KStandardGuiItem::overwrite ()); if (result != KMessageBox::Continue) return false; } if (url.isLocalFile ()) { const QString filename = url.toLocalFile (); // sync: All failure exit paths _must_ call QSaveFile::cancelWriting() or // else, the QSaveFile destructor will overwrite the file, // , despite the failure. QSaveFile atomicFileWriter (filename); { if (!atomicFileWriter.open (QIODevice::WriteOnly)) { // We probably don't need this as has not been // opened. atomicFileWriter.cancelWriting (); #if DEBUG_KP_COLOR_COLLECTION - qCDebug(kpLogMisc) << "\treturning false because could not open QSaveFile" + qCDebug(kpLogColorCollection) << "\treturning false because could not open QSaveFile" << " error=" << atomicFileWriter.error (); #endif ::CouldNotSaveDialog (url, parent); return false; } // Write to local temporary file. ::SaveToFile (d, &atomicFileWriter); // Atomically overwrite local file with the temporary file // we saved to. if (!atomicFileWriter.commit ()) { atomicFileWriter.cancelWriting (); #if DEBUG_KP_COLOR_COLLECTION - qCDebug(kpLogMisc) << "\tcould not close QSaveFile"; + qCDebug(kpLogColorCollection) << "\tcould not close QSaveFile"; #endif ::CouldNotSaveDialog (url, parent); return false; } } // sync QSaveFile.cancelWriting() } // Remote file? else { // Create temporary file that is deleted when the variable goes // out of scope. QTemporaryFile tempFile; if (!tempFile.open ()) { #if DEBUG_KP_COLOR_COLLECTION - qCDebug(kpLogMisc) << "\treturning false because could not open tempFile"; + qCDebug(kpLogColorCollection) << "\treturning false because could not open tempFile"; #endif ::CouldNotSaveDialog (url, parent); return false; } // Write to local temporary file. ::SaveToFile (d, &tempFile); // Collect name of temporary file now, as QTemporaryFile::fileName() // stops working after close() is called. const QString tempFileName = tempFile.fileName (); #if DEBUG_KP_COLOR_COLLECTION - qCDebug(kpLogMisc) << "\ttempFileName='" << tempFileName << "'"; + qCDebug(kpLogColorCollection) << "\ttempFileName='" << tempFileName << "'"; #endif Q_ASSERT (!tempFileName.isEmpty ()); tempFile.close (); if (tempFile.error () != QFile::NoError) { #if DEBUG_KP_COLOR_COLLECTION - qCDebug(kpLogMisc) << "\treturning false because could not close"; + qCDebug(kpLogColorCollection) << "\treturning false because could not close"; #endif ::CouldNotSaveDialog (url, parent); return false; } // Copy local temporary file to overwrite remote. // TODO: No one seems to know how to do this atomically // [http://lists.kde.org/?l=kde-core-devel&m=117845162728484&w=2]. // At least, fish:// (ssh) is definitely not atomic. if (!KIO::NetAccess::upload (tempFileName, url, parent)) { #if DEBUG_KP_COLOR_COLLECTION - qCDebug(kpLogMisc) << "\treturning false because could not upload"; + qCDebug(kpLogColorCollection) << "\treturning false because could not upload"; #endif ::CouldNotSaveDialog (url, parent); return false; } } d->name.clear (); return true; } bool kpColorCollection::saveKDE(QWidget *parent) const { const QString name = d->name; QString filename = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "colors/" + name; const bool ret = saveAs (QUrl::fromLocalFile (filename), false/*no overwite prompt*/, parent); // (d->name is wiped by saveAs()). d->name = name; return ret; } QString kpColorCollection::description() const { return d->desc; } void kpColorCollection::setDescription(const QString &desc) { d->desc = desc; } QString kpColorCollection::name() const { return d->name; } void kpColorCollection::setName(const QString &name) { d->name = name; } kpColorCollection::Editable kpColorCollection::editable() const { return d->editable; } void kpColorCollection::setEditable(Editable editable) { d->editable = editable; } int kpColorCollection::count() const { return (int) d->colorList.count(); } void kpColorCollection::resize(int newCount) { if (newCount == count()) return; else if (newCount < count()) { d->colorList.erase(d->colorList.begin() + newCount, d->colorList.end()); } else if (newCount > count()) { while(newCount > count()) { const int ret = addColor(QColor(), QString()/*color name*/); Q_ASSERT(ret == count() - 1); } } } kpColorCollection& kpColorCollection::operator=( const kpColorCollection &p) { if (&p == this) return *this; d->colorList = p.d->colorList; d->name = p.d->name; d->desc = p.d->desc; d->editable = p.d->editable; return *this; } QColor kpColorCollection::color(int index) const { if ((index < 0) || (index >= count())) return {}; return d->colorList[index].color; } int kpColorCollection::findColor(const QColor &color) const { for (int i = 0; i < d->colorList.size(); ++i) { if (d->colorList[i].color == color) return i; } return -1; } QString kpColorCollection::name(int index) const { if ((index < 0) || (index >= count())) return {}; return d->colorList[index].name; } QString kpColorCollection::name(const QColor &color) const { return name(findColor(color)); } int kpColorCollection::addColor(const QColor &newColor, const QString &newColorName) { d->colorList.append(ColorNode(newColor, newColorName)); return count() - 1; } int kpColorCollection::changeColor(int index, const QColor &newColor, const QString &newColorName) { if ((index < 0) || (index >= count())) return -1; ColorNode& node = d->colorList[index]; node.color = newColor; node.name = newColorName; return index; } int kpColorCollection::changeColor(const QColor &oldColor, const QColor &newColor, const QString &newColorName) { return changeColor( findColor(oldColor), newColor, newColorName); } diff --git a/lgpl/generic/widgets/kpColorCellsBase.cpp b/lgpl/generic/widgets/kpColorCellsBase.cpp index 0755c79a..ac29994c 100644 --- a/lgpl/generic/widgets/kpColorCellsBase.cpp +++ b/lgpl/generic/widgets/kpColorCellsBase.cpp @@ -1,563 +1,563 @@ /* This file is part of the KDE libraries Copyright (C) 1997 Martin Jones (mjones@kde.org) Copyright (C) 2007 Roberto Raggi (roberto@kdevelop.org) Copyright (C) 2007 Clarence Dang (dang@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //----------------------------------------------------------------------------- #define DEBUG_KP_COLOR_CELLS_BASE 0 #include "kpColorCellsBase.h" #include #include #include #include #include #include #include #include #include #include #include "kpLogCategories.h" #include class kpColorCellsBase::kpColorCellsBasePrivate { public: kpColorCellsBasePrivate(kpColorCellsBase *q): q(q) { colors = nullptr; inMouse = false; selected = -1; shade = false; acceptDrags = false; cellsResizable = true; } kpColorCellsBase *q; // Note: This is a good thing and is _not_ data duplication with the // colors of QTableWidget cells, for the following reasons: // // 1. QColor in Qt4 is full-quality RGB. However, QTableWidget // cells are lossy as their colors may be dithered on the screen. // // Eventually, this field will be changed to a kpColor. // // 2. We change the QTableWidget cells' colors when the widget is // disabled (see changeEvent()). // // Therefore, do not remove this field without better reasons. QColor *colors; QPoint mousePos; int selected; bool shade; bool acceptDrags; bool cellsResizable; bool inMouse; }; kpColorCellsBase::kpColorCellsBase( QWidget *parent, int rows, int cols ) : QTableWidget( parent ), d(new kpColorCellsBasePrivate(this)) { setItemDelegate(new QItemDelegate(this)); setFrameShape(QFrame::NoFrame); d->shade = true; setRowCount( rows ); setColumnCount( cols ); verticalHeader()->setMinimumSectionSize(16); verticalHeader()->hide(); horizontalHeader()->setMinimumSectionSize(16); horizontalHeader()->hide(); d->colors = new QColor [ rows * cols ]; d->selected = 0; d->inMouse = false; // Drag'n'Drop setAcceptDrops( true); setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); viewport()->setBackgroundRole( QPalette::Window ); setBackgroundRole( QPalette::Window ); } kpColorCellsBase::~kpColorCellsBase() { delete [] d->colors; delete d; } void kpColorCellsBase::invalidateAllColors () { for (int r = 0; r < rowCount (); r++) for (int c = 0; c < columnCount (); c++) d->colors [r * columnCount () + c] = QColor (); } void kpColorCellsBase::clear() { invalidateAllColors (); QTableWidget::clear (); } void kpColorCellsBase::clearContents() { invalidateAllColors (); QTableWidget::clearContents (); } void kpColorCellsBase::setRowColumnCounts (int rows, int columns) { const int oldRows = rowCount (), oldCols = columnCount (); const int newRows = rows, newCols = columns; #if DEBUG_KP_COLOR_CELLS_BASE - qCDebug(kpLogMisc) << "oldRows=" << oldRows << "oldCols=" << oldCols + qCDebug(kpLogColorCollection) << "oldRows=" << oldRows << "oldCols=" << oldCols << "newRows=" << newRows << "newCols=" << newCols; #endif if (oldRows == newRows && oldCols == newCols) return; QTableWidget::setColumnCount (newCols); QTableWidget::setRowCount (newRows); QColor *oldColors = d->colors; d->colors = new QColor [newRows * newCols]; for (int r = 0; r < qMin (oldRows, newRows); r++) for (int c = 0; c < qMin (oldCols, newCols); c++) d->colors [r * newCols + c] = oldColors [r * oldCols + c]; delete [] oldColors; } void kpColorCellsBase::setColumnCount (int newColumns) { setRowColumnCounts (rowCount (), newColumns); } void kpColorCellsBase::setRowCount (int newRows) { setRowColumnCounts (newRows, columnCount ()); } QColor kpColorCellsBase::color(int index) const { return d->colors[index]; } int kpColorCellsBase::count() const { return rowCount() * columnCount(); } void kpColorCellsBase::setShading(bool _shade) { d->shade = _shade; } void kpColorCellsBase::setAcceptDrags(bool _acceptDrags) { d->acceptDrags = _acceptDrags; } void kpColorCellsBase::setCellsResizable(bool yes) { d->cellsResizable = yes; } void kpColorCellsBase::setSelected(int index) { Q_ASSERT( index >= 0 && index < count() ); d->selected = index; } int kpColorCellsBase::selectedIndex() const { return d->selected; } //--------------------------------------------------------------------- static void TableWidgetItemSetColor (QTableWidgetItem *tableItem, const QColor &color) { Q_ASSERT (tableItem); QImage image(16, 16, QImage::Format_ARGB32_Premultiplied); QPainter painter(&image); const int StippleSize = 4; QColor useColor; for (int dy = 0; dy < 16; dy += StippleSize) { for (int dx = 0; dx < 16; dx += StippleSize) { const bool parity = ((dy + dx) / StippleSize) % 2; if (!parity) useColor = Qt::white; else useColor = Qt::lightGray; painter.fillRect(dx, dy, StippleSize, StippleSize, useColor); } } painter.fillRect(image.rect(), color); painter.end(); tableItem->setData(Qt::BackgroundRole , QBrush(image)); } //--------------------------------------------------------------------- void kpColorCellsBase::setColor( int column, const QColor &colorIn ) { const int tableRow = column / columnCount(); const int tableColumn = column % columnCount(); Q_ASSERT( tableRow >= 0 && tableRow < rowCount() ); Q_ASSERT( tableColumn >= 0 && tableColumn < columnCount() ); QColor color = colorIn; d->colors[column] = color; QTableWidgetItem* tableItem = item(tableRow,tableColumn); if (color.isValid ()) { if ( tableItem == nullptr ) { tableItem = new QTableWidgetItem(); setItem(tableRow,tableColumn,tableItem); } if (isEnabled ()) ::TableWidgetItemSetColor (tableItem, color); } else { delete tableItem; } emit colorChanged (column, color); } void kpColorCellsBase::changeEvent( QEvent* event ) { QTableWidget::changeEvent (event); if (event->type () != QEvent::EnabledChange) return; for (int r = 0; r < rowCount (); r++) { for (int c = 0; c < columnCount (); c++) { const int index = r * columnCount () + c; QTableWidgetItem* tableItem = item(r, c); // See API Doc for this invariant. Q_ASSERT (!!tableItem == d->colors [index].isValid ()); if (!tableItem) continue; QColor color; if (isEnabled ()) color = d->colors [index]; else color = palette ().color (backgroundRole ()); ::TableWidgetItemSetColor (tableItem, color); } } } /*void kpColorCellsBase::paintCell( QPainter *painter, int row, int col ) { painter->setRenderHint( QPainter::Antialiasing , true ); QBrush brush; int w = 1; if (shade) { qDrawShadePanel( painter, 1, 1, cellWidth()-2, cellHeight()-2, palette(), true, 1, &brush ); w = 2; } QColor color = colors[ row * numCols() + col ]; if (!color.isValid()) { if (!shade) return; color = palette().color(backgroundRole()); } const QRect colorRect( w, w, cellWidth()-w*2, cellHeight()-w*2 ); painter->fillRect( colorRect, color ); if ( row * numCols() + col == selected ) { painter->setPen( qGray(color.rgb())>=127 ? Qt::black : Qt::white ); painter->drawLine( colorRect.topLeft(), colorRect.bottomRight() ); painter->drawLine( colorRect.topRight(), colorRect.bottomLeft() ); } }*/ void kpColorCellsBase::resizeEvent( QResizeEvent* e ) { if (d->cellsResizable) { // According to the Qt doc: // If you need to set the width of a given column to a fixed value, call // QHeaderView::resizeSection() on the table's {horizontal,vertical} // header. // Therefore we iterate over each row and column and set the header section // size, as the sizeHint does indeed appear to be ignored in favor of a // minimum size that is larger than what we want. for ( int index = 0 ; index < columnCount() ; index++ ) horizontalHeader()->resizeSection( index, sizeHintForColumn(index) ); for ( int index = 0 ; index < rowCount() ; index++ ) verticalHeader()->resizeSection( index, sizeHintForRow(index) ); } else { // Update scrollbars if they're forced on by a subclass. // TODO: Should the d->cellsResizable path (from kdelibs) do this as well? QTableWidget::resizeEvent (e); } } int kpColorCellsBase::sizeHintForColumn(int /*column*/) const { // TODO: Should it be "(width() - frameWidth() * 2) / columnCount()"? return width() / columnCount() ; } int kpColorCellsBase::sizeHintForRow(int /*row*/) const { // TODO: Should be "(height() - frameWidth() * 2) / rowCount()"? return height() / rowCount() ; } void kpColorCellsBase::mousePressEvent( QMouseEvent *e ) { d->inMouse = true; d->mousePos = e->pos(); } int kpColorCellsBase::positionToCell(const QPoint &pos, bool ignoreBorders, bool allowEmptyCell) const { //TODO ignoreBorders not yet handled Q_UNUSED( ignoreBorders ) const int r = indexAt (pos).row (), c = indexAt (pos).column (); #if DEBUG_KP_COLOR_CELLS_BASE - qCDebug(kpLogMisc) << "r=" << r << "c=" << c; + qCDebug(kpLogColorCollection) << "r=" << r << "c=" << c; #endif if (r == -1 || c == -1) return -1; if (!allowEmptyCell && !itemAt(pos)) return -1; const int cell = r * columnCount() + c; /*if (!ignoreBorders) { int border = 2; int x = pos.x() - col * cellWidth(); int y = pos.y() - row * cellHeight(); if ( (x < border) || (x > cellWidth()-border) || (y < border) || (y > cellHeight()-border)) return -1; }*/ return cell; } void kpColorCellsBase::mouseMoveEvent( QMouseEvent *e ) { if( !(e->buttons() & Qt::LeftButton)) return; if(d->inMouse) { int delay = QApplication::startDragDistance(); if(e->x() > d->mousePos.x()+delay || e->x() < d->mousePos.x()-delay || e->y() > d->mousePos.y()+delay || e->y() < d->mousePos.y()-delay){ // Drag color object int cell = positionToCell(d->mousePos); if (cell != -1) { #if DEBUG_KP_COLOR_CELLS_BASE - qCDebug(kpLogMisc) << "beginning drag from cell=" << cell + qCDebug(kpLogColorCollection) << "beginning drag from cell=" << cell << "color: isValid=" << d->colors [cell].isValid () << " rgba=" << (int *) d->colors [cell].rgba(); #endif Q_ASSERT (d->colors[cell].isValid()); KColorMimeData::createDrag(d->colors[cell], this)->start(Qt::CopyAction | Qt::MoveAction); #if DEBUG_KP_COLOR_CELLS_BASE - qCDebug(kpLogMisc) << "finished drag"; + qCDebug(kpLogColorCollection) << "finished drag"; #endif } } } } // LOTODO: I'm not quite clear on how the drop actions logic is supposed // to be done e.g.: // // 1. Who is supposed to call setDropAction(). // 2. Which variant of accept(), setAccepted(), acceptProposedAction() etc. // is supposed to be called to accept a move -- rather than copy -- // action. // // Nevertheless, it appears to work -- probably because we restrict // the non-Qt-default move/swap action to be intrawidget. static void SetDropAction (QWidget *self, QDropEvent *event) { // TODO: Would be nice to default to CopyAction if the destination cell // is null. if (event->source () == self && (event->keyboardModifiers () & Qt::ControlModifier) == 0) event->setDropAction(Qt::MoveAction); else event->setDropAction(Qt::CopyAction); } void kpColorCellsBase::dragEnterEvent( QDragEnterEvent *event) { #if DEBUG_KP_COLOR_CELLS_BASE - qCDebug(kpLogMisc) << "kpColorCellsBase::dragEnterEvent() acceptDrags=" + qCDebug(kpLogColorCollection) << "kpColorCellsBase::dragEnterEvent() acceptDrags=" << d->acceptDrags << " canDecode=" << KColorMimeData::canDecode(event->mimeData()); #endif event->setAccepted( d->acceptDrags && KColorMimeData::canDecode( event->mimeData())); if (event->isAccepted ()) ::SetDropAction (this, event); } // Reimplemented to override QTableWidget's override. Else dropping doesn't work. void kpColorCellsBase::dragMoveEvent (QDragMoveEvent *event) { #if DEBUG_KP_COLOR_CELLS_BASE - qCDebug(kpLogMisc) << "kpColorCellsBase::dragMoveEvent() acceptDrags=" + qCDebug(kpLogColorCollection) << "kpColorCellsBase::dragMoveEvent() acceptDrags=" << d->acceptDrags << " canDecode=" << KColorMimeData::canDecode(event->mimeData()); #endif // TODO: Disallow drag that isn't onto a cell. event->setAccepted( d->acceptDrags && KColorMimeData::canDecode( event->mimeData())); if (event->isAccepted ()) ::SetDropAction (this, event); } void kpColorCellsBase::dropEvent( QDropEvent *event) { QColor c=KColorMimeData::fromMimeData(event->mimeData()); const int dragSourceCell = event->source () == this ? positionToCell (d->mousePos, true) : -1; #if DEBUG_KP_COLOR_CELLS_BASE - qCDebug(kpLogMisc) << "kpColorCellsBase::dropEvent()" + qCDebug(kpLogColorCollection) << "kpColorCellsBase::dropEvent()" << "color: rgba=" << (const int *) c.rgba () << "isValid=" << c.isValid() << "source=" << event->source () << "dragSourceCell=" << dragSourceCell; #endif if( c.isValid()) { ::SetDropAction (this, event); int cell = positionToCell(event->pos(), true, true/*allow empty cell*/); #if DEBUG_KP_COLOR_CELLS_BASE - qCDebug(kpLogMisc) << "\tcell=" << cell; + qCDebug(kpLogColorCollection) << "\tcell=" << cell; #endif // TODO: I believe kdelibs forgets to do this. if (cell == -1) return; // Avoid NOP. if (cell == dragSourceCell) return; QColor destOldColor = d->colors [cell]; setColor(cell,c); #if DEBUG_KP_COLOR_CELLS_BASE - qCDebug(kpLogMisc) << "\tdropAction=" << event->dropAction () + qCDebug(kpLogColorCollection) << "\tdropAction=" << event->dropAction () << "destOldColor.rgba=" << (const int *) destOldColor.rgba (); #endif if (event->dropAction () == Qt::MoveAction && dragSourceCell != -1) { setColor(dragSourceCell, destOldColor); } } } void kpColorCellsBase::mouseReleaseEvent( QMouseEvent *e ) { int cell = positionToCell(d->mousePos); int currentCell = positionToCell(e->pos()); // If we release the mouse in another cell and we don't have // a drag we should ignore this event. if (currentCell != cell) cell = -1; if ( (cell != -1) && (d->selected != cell) ) { d->selected = cell; const int newRow = cell/columnCount(); const int newColumn = cell%columnCount(); clearSelection(); // we do not want old violet selected cells item(newRow,newColumn)->setSelected(true); } d->inMouse = false; if (cell != -1) { emit colorSelected( cell , color(cell) ); emit colorSelectedWhitButton( cell , color(cell), e->button() ); } } void kpColorCellsBase::mouseDoubleClickEvent( QMouseEvent * /*e*/ ) { int cell = positionToCell(d->mousePos, false, true/*allow empty cell*/); if (cell != -1) emit colorDoubleClicked( cell , color(cell) ); } diff --git a/lgpl/generic/widgets/kpColorCellsBase.h b/lgpl/generic/widgets/kpColorCellsBase.h index 4d8f10b9..e05b5d6d 100644 --- a/lgpl/generic/widgets/kpColorCellsBase.h +++ b/lgpl/generic/widgets/kpColorCellsBase.h @@ -1,185 +1,188 @@ // SYNC: Periodically merge in changes from: // // trunk/KDE/kdelibs/kdeui/colors/kcolordialog.{h,cpp} // // which this is a fork of. // // Our changes can be merged back into KDE (grep for "Added for KolourPaint" and similar). /* This file is part of the KDE libraries Copyright (C) 1997 Martin Jones (mjones@kde.org) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //---------------------------------------------------------------------- // KDE color selection dialog. // layout management added Oct 1997 by Mario Weilguni // #ifndef kpColorCellsBase_H #define kpColorCellsBase_H #include #include +#include + +Q_DECLARE_LOGGING_CATEGORY(kpLogColorCollection) /** * A table of editable color cells. * * @author Martin Jones * * Added for KolourPaint: * * If you have not called setColor() for a cell, its widget will not exist. * So it is possible to have "holes" in this rectangular table of cells. * You can delete a cell widget by calling setColor() with an invalid QColor. * * An invariant is that color() returns an invalid color iff the cells' widget * does not exist. Note that: * * 1. You can double click on cells that don't contain a widget * 2. You can drop onto -- but not drag from -- a cell that doesn't contain a * widget * * If a color is dragged and dropped to-and-from the same instance of this * widget, then the colors in the source and destination cells are swapped * (this is a "move action"). * * If CTRL is held or they are not from the same instance, then the source * cell's color is copied into the destination cell, without any change to * the source cell (this is a "copy action"). */ class KOLOURPAINT_LGPL_EXPORT kpColorCellsBase : public QTableWidget { Q_OBJECT public: /** * Constructs a new table of color cells, consisting of * @p rows * @p columns colors. * * @param parent The parent of the new widget * @param rows The number of rows in the table * @param columns The number of columns in the table * * Specifying and was made optional for KolourPaint. */ kpColorCellsBase( QWidget *parent, int rows = 0, int columns = 0 ); ~kpColorCellsBase() override; private: /** Added for KolourPaint. */ void invalidateAllColors (); public: /** Added for KolourPaint. WARNING: These are not virtual in QTableWidget. */ void clear (); void clearContents (); /** Added for KolourPaint. */ void setRowColumnCounts (int rows, int columns); /** Added for KolourPaint. WARNING: These are not virtual in QTableWidget. */ void setColumnCount (int columns); void setRowCount (int rows); /** Sets the color in the given index in the table. The following behavior change was added for KolourPaint: If is not valid, the cell widget at is deleted. */ void setColor( int index, const QColor &col ); /** Returns the color at a given index in the table. If a cell widget does not exist at , the invalid color is returned. */ QColor color( int index ) const; /** Returns the total number of color cells in the table */ int count() const; void setShading(bool shade); void setAcceptDrags(bool acceptDrags); /** Whether component cells should resize with the entire widget. Default is true. Added for KolourPaint. */ void setCellsResizable(bool yes); /** Sets the currently selected cell to @p index */ void setSelected(int index); /** Returns the index of the cell which is currently selected */ int selectedIndex() const; Q_SIGNALS: /** Emitted when a color is selected in the table */ void colorSelected( int index , const QColor& color ); /** Emitted with the above. Added for KolourPaint. */ void colorSelectedWhitButton( int index , const QColor& color, Qt::MouseButton button ); /** Emitted when a color in the table is double-clicked */ void colorDoubleClicked( int index , const QColor& color ); /** Emitted when setColor() is called. This includes when a color is dropped onto the table, via drag-and-drop. Added for KolourPaint. */ void colorChanged( int index , const QColor& color ); protected: /** Grays out the cells, when the object is disabled. Added for KolourPaint. */ void changeEvent( QEvent* event ) override; // the three methods below are used to ensure equal column widths and row heights // for all cells and to update the widths/heights when the widget is resized int sizeHintForColumn(int column) const override; int sizeHintForRow(int column) const override; void resizeEvent( QResizeEvent* event ) override; void mouseReleaseEvent( QMouseEvent * ) override; void mousePressEvent( QMouseEvent * ) override; void mouseMoveEvent( QMouseEvent * ) override; void dragEnterEvent( QDragEnterEvent * ) override; void dragMoveEvent( QDragMoveEvent * ) override; void dropEvent( QDropEvent *) override; void mouseDoubleClickEvent( QMouseEvent * ) override; /** was added for KolourPaint. */ int positionToCell(const QPoint &pos, bool ignoreBorders=false, bool allowEmptyCell=false) const; private: class kpColorCellsBasePrivate; friend class kpColorCellsBasePrivate; kpColorCellsBasePrivate *const d; Q_DISABLE_COPY(kpColorCellsBase) }; #endif // kpColorCellsBase_H