diff --git a/src/KPropertyEditorView.cpp b/src/KPropertyEditorView.cpp index d27057d..228f59e 100644 --- a/src/KPropertyEditorView.cpp +++ b/src/KPropertyEditorView.cpp @@ -1,606 +1,605 @@ /* This file is part of the KDE project Copyright (C) 2008-2016 Jarosław Staniek 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. */ #include "KPropertyEditorView.h" #include "KPropertyEditorDataModel.h" #include "KProperty.h" #include "KPropertySet.h" #include "KPropertyWidgetsFactory.h" #include "KPropertyWidgetsPluginManager.h" #include "kproperty_debug.h" #include "KPropertyUtils.h" #include "KPropertyUtils_p.h" #include #include #include #include #include #include #include #include #include #if 0 // not sure if we should use it, better to fix Oxygen? #include //! Used to alter the widget's style at design time class EditorViewStyle : public KexiUtils::StyleProxy { public: explicit EditorViewStyle(QStyle* parentStyle) : KexiUtils::StyleProxy(parentStyle) { } virtual void drawPrimitive(PrimitiveElement elem, const QStyleOption* option, QPainter* painter, const QWidget* widget) const { /* if (elem == PE_PanelLineEdit) { const QStyleOptionFrame *panel = qstyleoption_cast(option); if (panel) { QStyleOptionFrame alteredOption(*panel); alteredOption.lineWidth = 0; KexiUtils::StyleProxy::drawPrimitive(elem, &alteredOption, painter, widget); return; } }*/ KexiUtils::StyleProxy::drawPrimitive(elem, option, painter, widget); } }; #endif static bool computeAutoSync(KProperty *property, bool defaultAutoSync) { return (property->autoSync() != 0 && property->autoSync() != 1) ? defaultAutoSync : (property->autoSync() != 0); } //---------- class ItemDelegate : public QItemDelegate { public: explicit ItemDelegate(KPropertyEditorView *parent); virtual ~ItemDelegate(); virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; virtual QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const; mutable QPointer m_currentEditor; }; ItemDelegate::ItemDelegate(KPropertyEditorView *parent) : QItemDelegate(parent) { } ItemDelegate::~ItemDelegate() { } static int getIconSize(int fontPixelSize) { return fontPixelSize * 0.85; } static int typeForProperty( KProperty* prop ) { if (prop->listData()) return KProperty::ValueFromList; else return prop->type(); } void ItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem alteredOption(option); const QColor gridLineColor(qobject_cast(parent())->gridLineColor()); if (gridLineColor.isValid()) { alteredOption.rect.setTop(alteredOption.rect.top() + 1); } - painter->save(); + const KPropertyUtils::PainterSaver saver(painter); QRect r(option.rect); const KPropertyEditorDataModel *editorModel = dynamic_cast(index.model()); if (!editorModel) { return; } bool modified = false; if (index.column()==0) { r.setWidth(r.width() - 1); r.setLeft(0); QVariant modifiedVariant( editorModel->data(index, KPropertyEditorDataModel::PropertyModifiedRole) ); if (modifiedVariant.isValid() && modifiedVariant.toBool()) { modified = true; QFont font(alteredOption.font); font.setBold(true); alteredOption.font = font; } } else { r.setLeft(r.left()-1); } const int x2 = alteredOption.rect.right(); const int y2 = alteredOption.rect.bottom(); const int iconSize = getIconSize( alteredOption.font.pixelSize() ); if (modified) { alteredOption.rect.setRight( alteredOption.rect.right() - iconSize * 1 ); } KProperty *property = editorModel->propertyForIndex(index); const int t = typeForProperty( property ); bool useQItemDelegatePaint = true; // ValueDisplayInterface is used by default if (index.column() == 1 && KPropertyWidgetsPluginManager::self()->paint(t, painter, alteredOption, index)) { useQItemDelegatePaint = false; } if (useQItemDelegatePaint) { QItemDelegate::paint(painter, alteredOption, index); } if (modified) { alteredOption.rect.setRight( alteredOption.rect.right() - iconSize * 3 / 2 ); int y1 = alteredOption.rect.top(); QLinearGradient grad(x2 - iconSize * 2, y1, x2 - iconSize / 2, y1); QColor color( alteredOption.palette.color( (alteredOption.state & QStyle::State_Selected) ? QPalette::Highlight : QPalette::Base )); color.setAlpha(0); grad.setColorAt(0.0, color); color.setAlpha(255); grad.setColorAt(0.5, color); QBrush gradBrush(grad); painter->fillRect(x2 - iconSize * 2, y1, iconSize * 2, y2 - y1 + 1, gradBrush); QPixmap revertIcon(QIcon::fromTheme(QLatin1String("edit-undo")).pixmap(iconSize, iconSize)); //!TODO //revertIcon = KIconEffect().apply(revertIcon, KIconEffect::Colorize, 1.0, // alteredOption.palette.color( // (alteredOption.state & QStyle::State_Selected) ? QPalette::HighlightedText : QPalette::Text ), false); //painter->drawPixmap( x2 - iconSize - 2, // y1 + 1 + (alteredOption.rect.height() - revertIcon.height()) / 2, revertIcon); } if (gridLineColor.isValid()) { QPen pen(gridLineColor); painter->setPen(pen); painter->drawRect(r); } else { QPen pen(alteredOption.palette.color(QPalette::AlternateBase)); painter->setPen(pen); painter->drawLine(r.topLeft(), r.topRight()); } //kprDebug()<<"rect:" << r << "viewport:" << painter->viewport() << "window:"<window(); - painter->restore(); } QSize ItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { return QItemDelegate::sizeHint(option, index) + QSize(0, 2); } QWidget * ItemDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const { if (!index.isValid()) return 0; QStyleOptionViewItem alteredOption(option); KProperty *property = KPropertyUtils::propertyForIndex(index); const int t = property ? typeForProperty(property) : KProperty::String; alteredOption.rect.setHeight(alteredOption.rect.height()+3); QWidget *w = KPropertyWidgetsPluginManager::self()->createEditor(t, parent, alteredOption, index); if (!w) { // fall back to String type w = KPropertyWidgetsPluginManager::self()->createEditor(KProperty::String, parent, alteredOption, index); } if (w) { if (-1 != w->metaObject()->indexOfSignal(QMetaObject::normalizedSignature("commitData(QWidget*)").constData()) && property && !property->children()) { } } else { w = QItemDelegate::createEditor(parent, alteredOption, index); } QObject::disconnect(w, SIGNAL(commitData(QWidget*)), this, SIGNAL(commitData(QWidget*))); if (property && computeAutoSync( property, static_cast(this->parent())->isAutoSync() )) { QObject::connect(w, SIGNAL(commitData(QWidget*)), this, SIGNAL(commitData(QWidget*))); } m_currentEditor = w; return w; } //---------- class KPropertyEditorView::Private { public: Private() : set(0) , model(0) , gridLineColor( KPropertyEditorView::defaultGridLineColor() ) , autoSync(true) , slotPropertyChangedEnabled(true) { } KPropertySet *set; KPropertyEditorDataModel *model; ItemDelegate *itemDelegate; QColor gridLineColor; bool autoSync; bool slotPropertyChangedEnabled; }; KPropertyEditorView::KPropertyEditorView(QWidget* parent) : QTreeView(parent) , d( new Private ) { setObjectName(QLatin1String("KPropertyEditorView")); setAlternatingRowColors(true); setSelectionBehavior(QAbstractItemView::SelectRows); setSelectionMode(QAbstractItemView::SingleSelection); setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); setAnimated(false); setAllColumnsShowFocus(true); header()->setSectionsMovable(false); setEditTriggers( QAbstractItemView::CurrentChanged | QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed | QAbstractItemView::AnyKeyPressed | QAbstractItemView::AllEditTriggers); setItemDelegate(d->itemDelegate = new ItemDelegate(this)); } KPropertyEditorView::~KPropertyEditorView() { delete d; } void KPropertyEditorView::changeSet(KPropertySet *set, SetOptions options) { changeSetInternal(set, options, QByteArray()); } void KPropertyEditorView::changeSet(KPropertySet *set, const QByteArray& propertyToSelect, SetOptions options) { changeSetInternal(set, options, propertyToSelect); } void KPropertyEditorView::changeSetInternal(KPropertySet *set, SetOptions options, const QByteArray& propertyToSelect) { //! @todo port?? #if 0 if (d->insideSlotValueChanged) { //changeSet() called from inside of slotValueChanged() //this is dangerous, because there can be pending events, //especially for the GUI stuff, so let's do delayed work d->setListLater_list = set; d->preservePrevSelection_preservePrevSelection = preservePrevSelection; d->preservePrevSelection_propertyToSelect = propertyToSelect; qApp->processEvents(QEventLoop::AllEvents); if (d->set) { //store prev. selection for this prop set if (d->currentItem) d->set->setPrevSelection(d->currentItem->property()->name()); kprDebug() << d->set->prevSelection(); } if (!d->setListLater_set) { d->setListLater_set = true; d->changeSetLaterTimer.setSingleShot(true); d->changeSetLaterTimer.start(10); } return; } #endif const bool setChanged = d->set != set; if (d->set) { acceptInput(); //store prev. selection for this prop set QModelIndex index = currentIndex(); if (index.isValid()) { //! @todo This crashes when changing the interpreter type in the script plugin #if 0 Property *property = d->model->propertyForIndex(index); //if (property->isNull()) // kprDebug() << "WTF? a NULL property?"; //else //d->set->setPreviousSelection(property->name()); #endif } else { d->set->setPreviousSelection(QByteArray()); } if (setChanged) { d->set->disconnect(this); } } QByteArray selectedPropertyName1 = propertyToSelect; QByteArray selectedPropertyName2 = propertyToSelect; if (options & PreservePreviousSelection) { //try to find prev. selection: //1. in new list's prev. selection if (set) selectedPropertyName1 = set->previousSelection(); //2. in prev. list's current selection if (d->set) selectedPropertyName2 = d->set->previousSelection(); } if (setChanged) { d->set = set; } if (d->set && setChanged) { //receive property changes connect(d->set, SIGNAL(propertyChangedInternal(KPropertySet&,KProperty&)), this, SLOT(slotPropertyChanged(KPropertySet&,KProperty&))); connect(d->set, SIGNAL(propertyReset(KPropertySet&,KProperty&)), this, SLOT(slotPropertyReset(KPropertySet&,KProperty&))); connect(d->set, SIGNAL(aboutToBeCleared()), this, SLOT(slotSetWillBeCleared())); connect(d->set, SIGNAL(aboutToBeDeleted()), this, SLOT(slotSetWillBeDeleted())); } KPropertyEditorDataModel *oldModel = d->model; const KPropertySetIterator::Order setOrder = (options & AlphabeticalOrder) ? KPropertySetIterator::AlphabeticalOrder : KPropertySetIterator::InsertionOrder; d->model = d->set ? new KPropertyEditorDataModel(d->set, this, setOrder) : 0; setModel( d->model ); delete oldModel; if (d->model && d->set && !d->set->isEmpty() && (options & ExpandChildItems)) { const int rowCount = d->model->rowCount(); for (int row = 0; row < rowCount; row++) { expand( d->model->index(row, 0) ); } } emit propertySetChanged(d->set); if (d->set) { //select prev. selected item QModelIndex index; if (!selectedPropertyName2.isEmpty()) //try other one for old prop set index = d->model->indexForPropertyName( selectedPropertyName2 ); if (!index.isValid() && !selectedPropertyName1.isEmpty()) //try old one for current prop set index = d->model->indexForPropertyName( selectedPropertyName1 ); if (index.isValid()) { setCurrentIndex(index); scrollTo(index); } } } void KPropertyEditorView::slotSetWillBeCleared() { changeSet(0, QByteArray()); } void KPropertyEditorView::slotSetWillBeDeleted() { changeSet(0, QByteArray()); } void KPropertyEditorView::setAutoSync(bool enable) { d->autoSync = enable; } bool KPropertyEditorView::isAutoSync() const { return d->autoSync; } void KPropertyEditorView::currentChanged( const QModelIndex & current, const QModelIndex & previous ) { QTreeView::currentChanged( current, previous ); } bool KPropertyEditorView::edit( const QModelIndex & index, EditTrigger trigger, QEvent * event ) { bool result = QTreeView::edit( index, trigger, event ); if (result) { QLineEdit *lineEditEditor = dynamic_cast( (QObject*)d->itemDelegate->m_currentEditor ); if (lineEditEditor) { lineEditEditor->deselect(); lineEditEditor->end(false); } } return result; } void KPropertyEditorView::drawBranches( QPainter * painter, const QRect & rect, const QModelIndex & index ) const { QTreeView::drawBranches( painter, rect, index ); } QRect KPropertyEditorView::revertButtonArea( const QModelIndex& index ) const { if (index.column() != 0) return QRect(); QVariant modifiedVariant( d->model->data(index, KPropertyEditorDataModel::PropertyModifiedRole) ); if (!modifiedVariant.isValid() || !modifiedVariant.toBool()) return QRect(); const int iconSize = getIconSize( fontInfo().pixelSize() ); int x2 = columnWidth(0); int x1 = x2 - iconSize - 2; QRect r(visualRect(index)); // kprDebug() << r; r.setLeft(x1); r.setRight(x2); // kprDebug() << r; return r; } bool KPropertyEditorView::withinRevertButtonArea( int x, const QModelIndex& index ) const { QRect r(revertButtonArea( index )); if (!r.isValid()) return false; return r.left() < x && x < r.right(); } void KPropertyEditorView::mousePressEvent ( QMouseEvent * event ) { QTreeView::mousePressEvent( event ); QModelIndex index = indexAt( event->pos() ); setCurrentIndex(index); if (withinRevertButtonArea( event->x(), index )) { undo(); } } void KPropertyEditorView::undo() { if (!d->set || d->set->isReadOnly()) return; KProperty *property = d->model->propertyForIndex(currentIndex()); if (computeAutoSync( property, d->autoSync )) property->resetValue(); } void KPropertyEditorView::acceptInput() { //! @todo } void KPropertyEditorView::commitData( QWidget * editor ) { d->slotPropertyChangedEnabled = false; QAbstractItemView::commitData( editor ); d->slotPropertyChangedEnabled = true; } bool KPropertyEditorView::viewportEvent( QEvent * event ) { if (event->type() == QEvent::ToolTip) { QHelpEvent *hevent = static_cast(event); const QModelIndex index = indexAt(hevent->pos()); if (index.column() == 0 && withinRevertButtonArea( hevent->x(), index )) { QRect r(revertButtonArea( index )); QToolTip::showText(hevent->globalPos(), tr("Undo changes"), this, r); } else { QToolTip::hideText(); } } return QTreeView::viewportEvent(event); } QSize KPropertyEditorView::sizeHint() const { return viewportSizeHint(); } KPropertySet* KPropertyEditorView::propertySet() const { return d->model ? d->model->propertySet() : nullptr; } QColor KPropertyEditorView::gridLineColor() const { return d->gridLineColor; } void KPropertyEditorView::setGridLineColor(const QColor& color) { d->gridLineColor = color; viewport()->update(); } static QModelIndex findChildItem(const KProperty& property, const QModelIndex &parent) { if (parent.model() && KPropertyUtils::propertyForIndex(parent) == &property) { return parent; } int row = 0; while (true) { QModelIndex childItem = parent.child(row, 0); if (childItem.isValid()) { QModelIndex subchild = findChildItem(property, childItem); if (subchild.isValid()) { return subchild; } } else { return QModelIndex(); } row++; } } void KPropertyEditorView::slotPropertyChanged(KPropertySet& set, KProperty& property) { Q_UNUSED(set); if (!d->slotPropertyChangedEnabled) return; d->slotPropertyChangedEnabled = false; KProperty *realProperty = &property; while (realProperty->parent()) { // find top-level property realProperty = realProperty->parent(); } const QModelIndex parentIndex( d->model->indexForPropertyName(realProperty->name()) ); if (parentIndex.isValid()) { QModelIndex index = findChildItem(property, parentIndex); updateSubtree(index); } d->slotPropertyChangedEnabled = true; } void KPropertyEditorView::updateSubtree(const QModelIndex &index) { if (!index.isValid()) { return; } update(index); QModelIndex valueIndex = d->model->indexForColumn(index, 1); if (valueIndex.isValid()) { update(valueIndex); } KProperty *property = static_cast(index.internalPointer()); if (property->children()) { int row = 0; foreach (KProperty* p, *property->children()) { updateSubtree(d->model->createIndex(row, 0, p)); ++row; } } } void KPropertyEditorView::slotPropertyReset(KPropertySet& set, KProperty& property) { //! @todo OK? slotPropertyChanged(set, property); } diff --git a/src/KPropertyLineStyleItemDelegate_p.cpp b/src/KPropertyLineStyleItemDelegate_p.cpp index 7977d1d..a401d10 100644 --- a/src/KPropertyLineStyleItemDelegate_p.cpp +++ b/src/KPropertyLineStyleItemDelegate_p.cpp @@ -1,101 +1,99 @@ /* This file is part of the KDE project * Copyright (C) 2007 Jan Hambrecht * Copyright (C) 2015 Jarosław Staniek * * 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. */ #include "KPropertyLineStyleItemDelegate_p.h" #include "KPropertyCoreUtils_p.h" +#include "KPropertyUtils_p.h" #include -#include KPropertyLineStyleItemDelegate::KPropertyLineStyleItemDelegate(QObject * parent) : QAbstractItemDelegate(parent) { } KPropertyLineStyleItemDelegate::~KPropertyLineStyleItemDelegate() { } class PenStyleData : public QHash { public: PenStyleData() { insert(Qt::NoPen, QObject::tr("None", "No Line")); insert(Qt::SolidLine, QObject::tr("Solid Line")); insert(Qt::DashLine, QObject::tr("Dash Line")); insert(Qt::DotLine, QObject::tr("Dot Line")); insert(Qt::DashDotLine, QObject::tr("Dash-Dot Line")); insert(Qt::DashDotDotLine, QObject::tr("Dash-Dot-Dot Line")); insert(Qt::CustomDashLine, QObject::tr("Custom Dash Line")); } }; Q_GLOBAL_STATIC(PenStyleData, g_penStyleData) //static QString KPropertyLineStyleItemDelegate::styleName(Qt::PenStyle style, const QLocale &locale) { if (locale.language() == QLocale::C) { return KPropertyUtils::keyForEnumValue("PenStyle", style); } return g_penStyleData->value(style); } //static void KPropertyLineStyleItemDelegate::paintItem(QPainter *painter, const QPen &pen_, const QRect &rect, const QStyleOption &option) { - painter->save(); + const KPropertyUtils::PainterSaver saver(painter); QPen pen(pen_); pen.setBrush(option.state & QStyle::State_Selected ? option.palette.highlightedText() : option.palette.text()); if (pen.style() == Qt::NoPen) { pen.setWidth(0); pen.setStyle(Qt::SolidLine); painter->setPen(pen); painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, g_penStyleData->value(Qt::NoPen)); } else { pen.setWidth(3); painter->setPen(pen); painter->drawLine(rect.left(), rect.center().y(), rect.right(), rect.center().y()); } - painter->restore(); } void KPropertyLineStyleItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { - painter->save(); - - if (option.state & QStyle::State_Selected) + const KPropertyUtils::PainterSaver saver(painter); + if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); + } QPen pen = index.data(Qt::DecorationRole).value(); paintItem(painter, pen, option.rect, option); - painter->restore(); } QSize KPropertyLineStyleItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(option); Q_UNUSED(index); return QSize(100, 15); } diff --git a/src/KPropertyUtils_p.h b/src/KPropertyUtils_p.h index 678c558..caed6b0 100644 --- a/src/KPropertyUtils_p.h +++ b/src/KPropertyUtils_p.h @@ -1,374 +1,401 @@ /* This file is part of the KDE project - Copyright (C) 2010 Jarosław Staniek + Copyright (C) 2010-2016 Jarosław Staniek 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. */ #ifndef KPROPERTY_UTILS_P_H #define KPROPERTY_UTILS_P_H #include #include -#include #include #include #include +#include #include #include #include #ifdef KPROPERTY_KF #include #include #include #endif class QColor; class QWidget; namespace KPropertyUtils { //! @return contrast color for @a c color. QColor contrastColor(const QColor& c); //! @return grid line color defined by a KPropertyEditorView widget contains @a widget //! Invalid color is returned if no grid is defined or KPropertyEditorView was not found. QColor gridLineColor(const QWidget *widget); // -- icon support //! @todo Support other themes const QString supportedIconTheme = QLatin1String("breeze"); //! @brief @return true if @a path is readable inline bool fileReadable(const QString &path) { return !path.isEmpty() && QFileInfo(path).isReadable(); } //! @brief Used for a workaround: locations for QStandardPaths::AppDataLocation end with app name. //! If this is not an expected app but for example a test app, replace //! the subdir name with app name so we can find resource file(s). inline QStringList correctStandardLocations(const QString &privateName, QStandardPaths::StandardLocation location, const QString &extraLocation) { QSet result; if (!privateName.isEmpty()) { QRegularExpression re(QLatin1Char('/') + QCoreApplication::applicationName() + QLatin1Char('$')); QStringList standardLocations(QStandardPaths::standardLocations(location)); if (!extraLocation.isEmpty()) { standardLocations.append(extraLocation); } for(const QString &dir : standardLocations) { if (dir.indexOf(re) != -1) { QString realDir(dir); realDir.replace(re, QLatin1Char('/') + privateName); result.insert(realDir); } } } return result.toList(); } #ifdef Q_OS_WIN #define KPATH_SEPARATOR ';' #else #define KPATH_SEPARATOR ':' #endif /*! @brief Locates a file path for specified parameters * @param privateName Name to be used instead of application name for resource lookup * @param path Relative path to the resource file * @param location Standard file location to use for file lookup * @param extraLocation Extra directory path for file lookup * @return Empty string on failure */ inline QString locateFile(const QString &privateName, const QString& path, QStandardPaths::StandardLocation location, const QString &extraLocation) { // let QStandardPaths handle this, it will look for app local stuff QString fullPath = QFileInfo( QStandardPaths::locate(location, path)).canonicalFilePath(); if (fileReadable(fullPath)) { return fullPath; } // Try extra location fullPath = QFileInfo(extraLocation + QLatin1Char('/') + path).canonicalFilePath(); if (fileReadable(fullPath)) { return fullPath; } // Try in PATH subdirs, useful for running apps from the build dir, without installing for(const QByteArray &pathDir : qgetenv("PATH").split(KPATH_SEPARATOR)) { const QString dataDirFromPath = QFileInfo(QFile::decodeName(pathDir) + QStringLiteral("/data/") + path).canonicalFilePath(); if (fileReadable(dataDirFromPath)) { return dataDirFromPath; } } const QStringList correctedStandardLocations(correctStandardLocations(privateName, location, extraLocation)); for(const QString &dir : correctedStandardLocations) { fullPath = QFileInfo(dir + QLatin1Char('/') + path).canonicalFilePath(); if (fileReadable(fullPath)) { return fullPath; } } return QString(); } /*! @brief Registers icons resource file * @param privateName Name to be used instead of application name for resource lookup * @param path Relative path to the resource file * @param location Standard file location to use for file lookup * @param resourceRoot A resource root for QResource::registerResource() * @param errorMessage On failure it is set to a brief error message. * @param errorDescription On failure it is set to a detailed error message. * other for warning */ inline bool registerIconsResource(const QString &privateName, const QString& path, QStandardPaths::StandardLocation location, const QString &resourceRoot, const QString &extraLocation, QString *errorMessage, QString *detailedErrorMessage) { const QString fullPath = locateFile(privateName, path, location, extraLocation); if (fullPath.isEmpty() || !QFileInfo(fullPath).isReadable() || !QResource::registerResource(fullPath, resourceRoot)) { QStringList triedLocations(QStandardPaths::standardLocations(location)); if (!extraLocation.isEmpty()) { triedLocations.append(extraLocation); } triedLocations.append(correctStandardLocations(privateName, location, extraLocation)); const QString triedLocationsString = QLocale().createSeparatedList(triedLocations); #ifdef QT_ONLY *errorMessage = QString("Could not open icon resource file %1.").arg(path); *detailedErrorMessage = QString("Tried to find in %1.").arg(triedLocationsString); #else //! @todo 3.1 Re-add translation *errorMessage = /*QObject::tr*/ QString::fromLatin1( "Could not open icon resource file \"%1\". " "Application will not start. " "Please check if it is properly installed.") .arg(QFileInfo(path).fileName()); //! @todo 3.1 Re-add translation *detailedErrorMessage = QString::fromLatin1("Tried to find in %1.").arg(triedLocationsString); #endif return false; } *errorMessage = QString(); *detailedErrorMessage = QString(); return true; } /*! @brief Registers a global icon resource file * @param themeName A name of icon theme to use. * @param errorMessage On failure it is set to a brief error message. * @param errorDescription On failure it is set to a detailed error message. * other for warning */ inline bool registerGlobalIconsResource(const QString &themeName, QString *errorMessage, QString *detailedErrorMessage) { QString extraLocation; #ifdef CMAKE_INSTALL_FULL_ICONDIR extraLocation = QDir::fromNativeSeparators(QFile::decodeName(CMAKE_INSTALL_FULL_ICONDIR)); if (extraLocation.endsWith("/icons")) { extraLocation.chop(QLatin1String("/icons").size()); } #elif defined(Q_OS_WIN) extraLocation = QCoreApplication::applicationDirPath() + QStringLiteral("/data"); #endif return registerIconsResource(QString(), QString::fromLatin1("icons/%1/%1-icons.rcc").arg(themeName), QStandardPaths::GenericDataLocation, QStringLiteral("/icons/") + themeName, extraLocation, errorMessage, detailedErrorMessage); } /*! @brief Registers a global icon resource file * @param themeName A name of icon theme to use. */ inline bool registerGlobalIconsResource(const QString &themeName) { QString errorMessage; QString detailedErrorMessage; if (!registerGlobalIconsResource(themeName, &errorMessage, &detailedErrorMessage)) { if (detailedErrorMessage.isEmpty()) { KMessageBox::error(nullptr, errorMessage); } else { KMessageBox::detailedError(nullptr, errorMessage, detailedErrorMessage); } qWarning() << qPrintable(errorMessage); return false; } return true; } /*! @brief Registers a global icon resource file for default theme name. */ inline bool registerGlobalIconsResource() { return registerGlobalIconsResource(supportedIconTheme); } /*! @brief Sets up a private icon resource file * @return @c false on failure and sets error message. Does not warn or exit on failure. * @param privateName Name to be used instead of application name for resource lookup * @param path Relative path to the resource file * @param themeName Icon theme to use. It affects filename. * @param errorMessage On failure it is set to a brief error message * @param errorDescription On failure it is set to a detailed error message * other for warning * @param prefix Resource path prefix. The default is useful for library-global resource, * other values is useful for plugins. */ inline bool setupPrivateIconsResource(const QString &privateName, const QString& path, const QString &themeName, QString *errorMessage, QString *detailedErrorMessage, const QString &prefix = QLatin1String(":/icons")) { // Register application's resource first to have priority over the theme. // Some icons may exists in both resources. QString extraLocation = QCoreApplication::applicationDirPath() + QStringLiteral("/data"); if (!registerIconsResource(privateName, path, QStandardPaths::AppDataLocation, QString(), QString(), errorMessage, detailedErrorMessage)) { return false; } bool changeTheme = false; #ifdef QT_GUI_LIB QIcon::setThemeSearchPaths(QStringList() << prefix << QIcon::themeSearchPaths()); changeTheme = 0 != QIcon::themeName().compare(themeName, Qt::CaseInsensitive); if (changeTheme) { QIcon::setThemeName(themeName); } #endif KConfigGroup cg(KSharedConfig::openConfig(), "Icons"); changeTheme = changeTheme || 0 != cg.readEntry("Theme", QString()).compare(themeName, Qt::CaseInsensitive); // tell KIconLoader an co. about the theme if (changeTheme) { cg.writeEntry("Theme", themeName); cg.sync(); } return true; } /*! @brief Sets up a private icon resource file * @return @c false on failure and sets error message. * @param privateName Name to be used instead of application name for resource lookup * @param path Relative path to the resource file * @param themeName Icon theme to use. It affects filename. * @param errorMessage On failure it is set to a brief error message. * @param errorDescription On failure it is set to a detailed error message. * other for warning * @param prefix Resource path prefix. The default is useful for library-global resource, * other values is useful for plugins. */ inline bool setupPrivateIconsResourceWithMessage(const QString &privateName, const QString& path, const QString &themeName, QString *errorMessage, QString *detailedErrorMessage, const QString &prefix = QLatin1String(":/icons")) { if (!setupPrivateIconsResource(privateName, path, themeName, errorMessage, detailedErrorMessage, prefix)) { if (detailedErrorMessage->isEmpty()) { KMessageBox::error(nullptr, *errorMessage); } else { KMessageBox::detailedError(nullptr, *errorMessage, *detailedErrorMessage); } return false; } return true; } /*! @overload setupPrivateIconsResourceWithMessage(QString &privateName, const QString& path, const QString &themeName, QString *errorMessage, QString *detailedErrorMessage, const QString &prefix = QLatin1String(":/icons")) Uses default theme name. */ inline bool setupPrivateIconsResourceWithMessage(const QString &privateName, const QString& path, QString *errorMessage, QString *detailedErrorMessage, const QString &prefix = QLatin1String(":/icons")) { return setupPrivateIconsResourceWithMessage(privateName, path, supportedIconTheme, errorMessage, detailedErrorMessage, prefix); } /*! @brief Sets up a private icon resource file * Warns on failure and returns @c false. * @param privateName Name to be used instead of application name for resource lookup * @param path Relative path to the resource file * @param messageType Type of message to use on error, QtFatalMsg for fatal exit and any * other for warning * @param prefix Resource path prefix. The default is useful for library-global resource, * other values is useful for plugins. */ inline bool setupPrivateIconsResourceWithMessage(const QString &privateName, const QString& path, QtMsgType messageType, const QString &prefix = QLatin1String(":/icons")) { QString errorMessage; QString detailedErrorMessage; if (!setupPrivateIconsResourceWithMessage(privateName, path, &errorMessage, &detailedErrorMessage, prefix)) { if (messageType == QtFatalMsg) { qFatal("%s %s", qPrintable(errorMessage), qPrintable(detailedErrorMessage)); } else { qWarning() << qPrintable(errorMessage) << qPrintable(detailedErrorMessage); } return false; } return true; } //! Sets up a global icon theme if it is different from supported. //! Warns on failure and returns @c false. inline bool setupGlobalIconTheme() { if (0 != QIcon::themeName().compare(supportedIconTheme, Qt::CaseInsensitive)) { const QString message = QString::fromLatin1( "\"%1\" supports only \"%2\" icon theme but current system theme is \"%3\". " "Application's icon theme will be changed to \"%2\". " "Please consider adding support for other themes to %4.") .arg(QLatin1String(KPROPERTYWIDGETS_BASE_NAME)).arg(supportedIconTheme).arg(QIcon::themeName()) .arg(QCoreApplication::applicationName()); qDebug() << qPrintable(message); if (!registerGlobalIconsResource()) { // don't fail, just warn const QString message = QString::fromLatin1( "Failed to set icon theme to \"%1\". Icons in the application will be inconsistent. " "Please install .rcc file(s) for the system theme.") .arg(supportedIconTheme); qDebug() << qPrintable(message); return false; } } return true; } +//! @short Manages the QPainter::save()/QPainter::restore() block using RAII +/*! The PainterSaver class makes sure that restore() is called when exiting from the block of code. + + Instead of: + @code + painter.save(); + // (code) + painter.restore(); + @endcode + + Use this: + @code + const PainterSaver saver(&painter); + // (code) + @endcode +*/ +class PainterSaver +{ +public: + explicit PainterSaver(QPainter *p) : m_painter(p) { if (m_painter) { m_painter->save(); } } + + ~PainterSaver() { if (m_painter) { m_painter->restore(); } } + +private: + QPainter* const m_painter; +}; + } #endif diff --git a/src/KPropertyWidgetsFactory.cpp b/src/KPropertyWidgetsFactory.cpp index f5cd97c..f4952d1 100644 --- a/src/KPropertyWidgetsFactory.cpp +++ b/src/KPropertyWidgetsFactory.cpp @@ -1,222 +1,222 @@ /* This file is part of the KDE project Copyright (C) 2008-2015 Jarosław Staniek 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. */ #include "KPropertyFactory.h" #include "KDefaultPropertyFactory.h" #include "KPropertyEditorView.h" #include "KPropertyStringEditor.h" +#include "KPropertyUtils_p.h" KPropertyLabel::KPropertyLabel(QWidget *parent, const KPropertyValueDisplayInterface *iface) : QLabel(parent) , m_iface(iface) { setAutoFillBackground(true); KPropertyEditorView* view = 0; if (parent) { view = qobject_cast(parent->parentWidget()); } const QColor gridLineColor(view ? view->gridLineColor() : KPropertyEditorView::defaultGridLineColor()); const int top = 1 + (gridLineColor.isValid() ? 1 : 0); setContentsMargins(0, top, 0, 0); setIndent(1); } QVariant KPropertyLabel::value() const { return m_value; } void KPropertyLabel::setValue(const QVariant& value) { setText( m_iface->valueToString(value, QLocale()) ); m_value = value; } void KPropertyLabel::paintEvent( QPaintEvent * event ) { QLabel::paintEvent(event); KPropertyWidgetsFactory::paintTopGridLine(this); } //--------------- void paintInternal(const KPropertyValueDisplayInterface *iface, QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) { - painter->save(); + const KPropertyUtils::PainterSaver saver(painter); QRect r(option.rect); r.setLeft(r.left()+1); painter->drawText( r, Qt::AlignLeft | Qt::AlignVCenter, iface->valueToString(index.data(Qt::EditRole), QLocale())); - painter->restore(); } //--------------- //! @internal class KPropertyWidgetsFactory::Private { public: Private() { } ~Private() { qDeleteAll(editorCreatorsSet); qDeleteAll(valuePaintersSet); } QHash editorCreators; QHash valuePainters; QSet editorCreatorsSet; QSet valuePaintersSet; }; KPropertyWidgetsFactory::KPropertyWidgetsFactory() : d( new Private ) { } KPropertyWidgetsFactory::~KPropertyWidgetsFactory() { delete d; } QHash KPropertyWidgetsFactory::editorCreators() const { return d->editorCreators; } QHash KPropertyWidgetsFactory::valuePainters() const { return d->valuePainters; } void KPropertyWidgetsFactory::addEditor(int type, KPropertyEditorCreatorInterface *creator) { addEditorInternal( type, creator, true ); if (dynamic_cast(creator)) { addComposedPropertyCreatorInternal( type, dynamic_cast(creator), false/* !own*/ ); } if (dynamic_cast(creator)) { addPainterInternal( type, dynamic_cast(creator), false/* !own*/ ); } if (dynamic_cast(creator)) { addDisplayInternal( type, dynamic_cast(creator), false/* !own*/ ); } } void KPropertyWidgetsFactory::addPainter(int type, KPropertyValuePainterInterface *painter) { addPainterInternal(type, painter, true); if (dynamic_cast(painter)) { addComposedPropertyCreatorInternal( type, dynamic_cast(painter), false/* !own*/ ); } if (dynamic_cast(painter)) { addEditorInternal( type, dynamic_cast(painter), false/* !own*/ ); } if (dynamic_cast(painter)) { addDisplayInternal( type, dynamic_cast(painter), false/* !own*/ ); } } void KPropertyWidgetsFactory::addEditorInternal(int type, KPropertyEditorCreatorInterface *editor, bool own) { if (own) d->editorCreatorsSet.insert(editor); d->editorCreators.insert(type, editor); } void KPropertyWidgetsFactory::addPainterInternal(int type, KPropertyValuePainterInterface *painter, bool own) { if (own) d->valuePaintersSet.insert(painter); d->valuePainters.insert(type, painter); } //static void KPropertyWidgetsFactory::paintTopGridLine(QWidget *widget) { // paint top grid line KPropertyEditorView* view = 0; if (widget->parentWidget()) { view = qobject_cast(widget->parentWidget()->parentWidget()); } const QColor gridLineColor(view ? view->gridLineColor() : KPropertyEditorView::defaultGridLineColor()); if (gridLineColor.isValid()) { QPainter p(widget); p.setPen(QPen( QBrush(gridLineColor), 1)); p.drawLine(0, 0, widget->width()-1, 0); } } //static void KPropertyWidgetsFactory::setTopAndBottomBordersUsingStyleSheet(QWidget *widget, const QString& extraStyleSheet) { KPropertyEditorView* view = 0; if (widget->parentWidget()) { view = qobject_cast(widget->parentWidget()->parentWidget()); } const QColor gridLineColor(view ? view->gridLineColor() : KPropertyEditorView::defaultGridLineColor()); widget->setStyleSheet( QString::fromLatin1("%1 { border-top: 1px solid %2;border-bottom: 1px solid %2; } %3") .arg(QLatin1String(widget->metaObject()->className())) .arg(gridLineColor.name()).arg(extraStyleSheet)); } //------------ KPropertyEditorCreatorInterface::KPropertyEditorCreatorInterface() { } KPropertyEditorCreatorInterface::~KPropertyEditorCreatorInterface() { } QWidget* KPropertyEditorCreatorInterface::createEditor(int type, QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index) const { Q_UNUSED(type); Q_UNUSED(option); Q_UNUSED(index); return new KPropertyStringEditor(parent); } KPropertyEditorCreatorInterface::Options::Options() : removeBorders(true) { } KPropertyValuePainterInterface::KPropertyValuePainterInterface() { } KPropertyValuePainterInterface::~KPropertyValuePainterInterface() { } diff --git a/src/editors/booledit.cpp b/src/editors/booledit.cpp index d3a40bf..8425774 100644 --- a/src/editors/booledit.cpp +++ b/src/editors/booledit.cpp @@ -1,359 +1,357 @@ /* This file is part of the KDE project Copyright (C) 2004 Alexander Dymo Copyright (C) 2006-2016 Jarosław Staniek 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. */ #include "booledit.h" #include "KPropertyUtils.h" +#include "KPropertyUtils_p.h" #include "kproperty_debug.h" #include -#include -#include #include /*! @return name for state with index @a index, where 0 means true, 1 means false and 2 means none */ static QString stateName(int index, const QLocale &locale, const KProperty* prop = 0) { QString stateNameString; if (index == 0) { stateNameString = prop ? prop->option("yesName", QString()).toString() : QString(); if (stateNameString.isEmpty()) { return locale.language() == QLocale::C ? QString::fromLatin1("true") : QObject::tr("Yes", "Property value: Boolean state Yes"); } } else if (index == 1) { stateNameString = prop ? prop->option("noName", QString()).toString() : QString(); if (stateNameString.isEmpty()) { return locale.language() == QLocale::C ? QString::fromLatin1("false") : QObject::tr("No", "Property value: Boolean state No"); } } else { stateNameString = prop ? prop->option("3rdStateName", QString()).toString() : QString(); if (stateNameString.isEmpty()) { return locale.language() == QLocale::C ? QString::fromLatin1("null") : QObject::tr("None", "Property value: Boolean (3rd) undefined state None"); } } return stateNameString; } //! Sets up @a data list data with keys and names for true, false, none values, respectively static void setupThreeStateListData(KPropertyListData &data, const KProperty* prop) { data.keys << true << false << QVariant(); data.names << stateName(0, QLocale(), prop) << stateName(1, QLocale(), prop) << stateName(2, QLocale(), prop); } static int valueToIndex(const QVariant& value) { if (value.isNull() || !value.isValid()) return 2; else return value.toBool() ? 0 : 1; } //------------------------- class BoolEditGlobal { public: BoolEditGlobal() : yesIcon(QIcon::fromTheme(QLatin1String("dialog-ok"))) , noIcon(QIcon::fromTheme(QLatin1String("kproperty-value-false"))) { QPixmap none(16, 16); none.fill(Qt::transparent); noneIcon.addPixmap(none); none = QPixmap(22, 22); none.fill(Qt::transparent); noneIcon.addPixmap(none); } QIcon yesIcon; QIcon noIcon; QIcon noneIcon; }; Q_GLOBAL_STATIC(BoolEditGlobal, g_boolEdit) class KPropertyBoolEditor::Private { public: Private(const KProperty *prop) : yesText( stateName(0, QLocale(), prop) ) , noText( stateName(1, QLocale(), prop) ) { } QVariant value; QString yesText; QString noText; }; KPropertyBoolEditor::KPropertyBoolEditor(const KProperty *prop, QWidget *parent) : QToolButton(parent), d(new Private(prop)) { setFocusPolicy(Qt::WheelFocus); setCheckable(true); // setToolButtonStyle(Qt::ToolButtonTextBesideIcon); setAutoFillBackground(true); // setFlat(false); // setStyle(qApp->style()); // setPalette(qApp->palette()); // setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); //we're not using layout to because of problems with button size // m_toggle->move(0, 0); // m_toggle->resize(width(), height()); /* KColorScheme cs(QPalette::Active); QColor focus = cs.decoration(KColorScheme::FocusColor).color(); setStyleSheet( QString::fromLatin1("QToolButton { " "border: 1px solid %1; " "border-radius: 0px; " "padding: 0 0px; }").arg(focus.name())); */ // setFocusWidget(m_toggle); // setStyleSheet( // QLatin1String(" QPushButton { border: none; padding:0;background-color: red; }") ); connect(this, SIGNAL(toggled(bool)), this, SLOT(slotValueChanged(bool))); } KPropertyBoolEditor::~KPropertyBoolEditor() { delete d; } QVariant KPropertyBoolEditor::value() const { return d->value; } void KPropertyBoolEditor::setValue(const QVariant &value) { // m_toggle->blockSignals(true); d->value = value; if (value.type() == QVariant::Bool) { setChecked(value.toBool()); } // setState(value); // m_toggle->blockSignals(false); // if (emitChange) // emit valueChanged(this); } void KPropertyBoolEditor::slotValueChanged(bool state) { d->value = state; emit commitData(this); // setState(state); //// emit valueChanged(this); } void KPropertyBoolEditor::draw(QPainter *p, const QRect &r, const QVariant &value, const QString& text, bool threeState) { QIcon icon; QSize actualIconSize; QPoint textOffset; if (valueToIndex(value) == 2) { // draw icon for the 3rd state for Three-State editor icon = g_boolEdit->noneIcon; actualIconSize = g_boolEdit->yesIcon.actualSize(r.size()); textOffset = QPoint(actualIconSize.width() + 6, 0); } else { // draw true or false icon regardless of the 2 or 3 state version icon = value.toBool() ? g_boolEdit->yesIcon : g_boolEdit->noIcon; actualIconSize = icon.actualSize(r.size()); textOffset = QPoint(actualIconSize.width() + 6, 0); } QRect r2(r); r2.moveTop(r2.top() + 2); r2.setLeft(r2.left() + 3); //r2.setTop(r2.top() + (r.height() - actualIconSize.height()) / 2); if (!threeState && value.isNull()) { // 2 states but null value p->drawText(r2.translated(textOffset), Qt::AlignVCenter | Qt::AlignLeft, text); } else { icon.paint(p, r2, Qt::AlignVCenter | Qt::AlignLeft); p->drawText(r2.translated(textOffset), Qt::AlignVCenter | Qt::AlignLeft, text); } } void KPropertyBoolEditor::paintEvent( QPaintEvent * event ) { QToolButton::paintEvent(event); QPainter p(this); const QVariant v( value() ); KPropertyBoolEditor::draw(&p, rect(), v, v.toBool() ? d->yesText : d->noText, false /*2state*/); } bool KPropertyBoolEditor::eventFilter(QObject* watched, QEvent* e) { if (e->type() == QEvent::KeyPress) { QKeyEvent* ev = static_cast(e); const int k = ev->key(); if (k == Qt::Key_Space || k == Qt::Key_Enter || k == Qt::Key_Return) { // if (m_toggle) toggle(); return true; } } return QToolButton::eventFilter(watched, e); } /*void BoolEdit::setReadOnlyInternal(bool readOnly) { setVisibleFlag(!readOnly); }*/ //-------------------------------------------------- class ThreeStateBoolIconProvider : public KPropertyComboBoxEditor::Options::IconProviderInterface { public: ThreeStateBoolIconProvider() {} virtual QIcon icon(int index) const { if (index == 0) return g_boolEdit->yesIcon; else if (index == 1) return g_boolEdit->noIcon; return g_boolEdit->noneIcon; } virtual IconProviderInterface* clone() const { return new ThreeStateBoolIconProvider(); } }; static KPropertyComboBoxEditor::Options initThreeStateBoolOptions() { KPropertyComboBoxEditor::Options options; options.iconProvider = new ThreeStateBoolIconProvider(); return options; } KPropertyThreeStateBoolEditor::KPropertyThreeStateBoolEditor( const KPropertyListData& listData, QWidget *parent) : KPropertyComboBoxEditor(listData, initThreeStateBoolOptions(), parent) { // QPixmap nullIcon(m_yesIcon.size()); //transparent pixmap of appropriate size // nullIcon.fill(Qt::transparent); // m_edit->addItem(nullIcon, thirdState.toString().isEmpty() ? tr("None") : thirdState.toString()); setCurrentIndex(2); } KPropertyThreeStateBoolEditor::~KPropertyThreeStateBoolEditor() { } QVariant KPropertyThreeStateBoolEditor::value() const { // list items: true, false, NULL const int idx = currentIndex(); if (idx == 0) return true; else return idx == 1 ? false : QVariant(); } /*void ThreeStateBoolEdit::setProperty(Property *prop) { m_setValueEnabled = false; //setValue() couldn't be called before fillBox() Widget::setProperty(prop); m_setValueEnabled = true; if (prop) setValue(prop->value(), false); //now the value can be set }*/ void KPropertyThreeStateBoolEditor::setValue(const QVariant &value) { // if (!m_setValueEnabled) // return; setCurrentIndex( valueToIndex(value) ); // if (emitChange) // emit valueChanged(this); } //--------------- KPropertyBoolDelegate::KPropertyBoolDelegate() { options.removeBorders = false; } QWidget * KPropertyBoolDelegate::createEditor( int type, QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const { Q_UNUSED(type); Q_UNUSED(option); KProperty *prop = KPropertyUtils::propertyForIndex(index); // boolean editors can optionally accept 3rd state: if (prop->option("3State", false).toBool()) { KPropertyListData threeStateListData; setupThreeStateListData(threeStateListData, prop); return new KPropertyThreeStateBoolEditor(threeStateListData, parent); } else { return new KPropertyBoolEditor(prop, parent); } } void KPropertyBoolDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const { - painter->save(); + const KPropertyUtils::PainterSaver saver(painter); KProperty *prop = KPropertyUtils::propertyForIndex(index); if (!prop) { return; } const QVariant value( index.data(Qt::EditRole) ); QRect rect(option.rect); const bool threeState = prop->option("3State", false).toBool(); KPropertyBoolEditor::draw(painter, rect.translated(0, -2), value, propertyValueToString(prop, QLocale()), threeState); - painter->restore(); } QString KPropertyBoolDelegate::propertyValueToString(const KProperty* prop, const QLocale &locale) const { if (prop->option("3State", false).toBool()) { int listIndex = valueToIndex(prop->value()); return stateName(listIndex, locale, prop); } if (prop->value().isNull() && !prop->option("nullName", QString()).toString().isEmpty()) { return prop->option("nullName", QString()).toString(); } return valueToString(prop->value(), locale); } QString KPropertyBoolDelegate::valueToString(const QVariant& value, const QLocale &locale) const { // assume 2-state return stateName(value.toBool() ? 0 : 1, locale); } diff --git a/src/editors/coloredit.cpp b/src/editors/coloredit.cpp index 810d055..a2ce097 100644 --- a/src/editors/coloredit.cpp +++ b/src/editors/coloredit.cpp @@ -1,116 +1,114 @@ /* This file is part of the KDE project Copyright (C) 2010-2015 Jarosław Staniek 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. */ #include "coloredit.h" #include "KPropertyUtils_p.h" #include -#include #ifdef KPROPERTY_KF #include Q_GLOBAL_STATIC_WITH_ARGS(KColorCollection, g_oxygenColors, (QLatin1String("Oxygen.colors"))) KPropertyColorComboEditor::KPropertyColorComboEditor(QWidget *parent) : KColorCombo(parent) { connect(this, SIGNAL(activated(QColor)), this, SLOT(slotValueChanged(QColor))); QList< QColor > colors; const int oxygenColorsCount = g_oxygenColors->count(); for (int i = 0; i < oxygenColorsCount; i++) { colors += g_oxygenColors->color(i); } setColors(colors); int paddingTop = 1; if (!KPropertyUtils::gridLineColor(this).isValid()) { setFrame(false); paddingTop = 0; } QString styleSheet = QString::fromLatin1("QComboBox { \ border: 1px; \ padding-top: %1px; padding-left: 1px; }").arg(paddingTop); setStyleSheet(styleSheet); } KPropertyColorComboEditor::~KPropertyColorComboEditor() { } QVariant KPropertyColorComboEditor::value() const { return color(); } void KPropertyColorComboEditor::setValue(const QVariant &value) { setColor(value.value()); } void KPropertyColorComboEditor::slotValueChanged(const QColor&) { emit commitData(this); } #endif // KPROPERTY_KF QWidget * KPropertyColorComboDelegate::createEditor(int type, QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(type) Q_UNUSED(option) Q_UNUSED(index) #ifdef KPROPERTY_KF return new KPropertyColorComboEditor(parent); #else return KPropertyEditorCreatorInterface::createEditor(type, parent, option, index); #endif } static QString colorToName(const QColor &color, const QLocale &locale) { if (!color.isValid()) { return locale.language() == QLocale::C ? QString::fromLatin1("#invalid") : QObject::tr("#invalid", "Invalid color"); } return color.alpha() == 255 ? color.name(QColor::HexRgb) : color.name(QColor::HexArgb); } void KPropertyColorComboDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const { - painter->save(); + const KPropertyUtils::PainterSaver saver(painter); const QBrush b(index.data(Qt::EditRole).value()); painter->setBrush(b); painter->setPen(QPen(Qt::NoPen)); painter->drawRect(option.rect); painter->setBrush(KPropertyUtils::contrastColor(b.color())); painter->setPen(KPropertyUtils::contrastColor(b.color())); QFont f(option.font); f.setFamily(QLatin1String("courier")); painter->setFont(f); painter->drawText(option.rect, Qt::AlignCenter, colorToName(b.color(), QLocale())); - painter->restore(); } QString KPropertyColorComboDelegate::valueToString(const QVariant& value, const QLocale &locale) const { return colorToName(value.value(), locale); } diff --git a/src/editors/cursoredit.cpp b/src/editors/cursoredit.cpp index 49b1fed..9c13788 100644 --- a/src/editors/cursoredit.cpp +++ b/src/editors/cursoredit.cpp @@ -1,266 +1,265 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004 Alexander Dymo Copyright (C) 2008-2015 Jarosław Staniek 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. */ #include "cursoredit.h" #include "KProperty.h" #include "KPropertyCoreUtils_p.h" #include "KPropertyUtils_p.h" #include "xpm/blank_cursor.xpm" #include "xpm/arrow_cursor.xpm" #include "xpm/bdiag_cursor.xpm" #include "xpm/busy_cursor.xpm" #include "xpm/closedhand_cursor.xpm" #include "xpm/cross_cursor.xpm" #include "xpm/fdiag_cursor.xpm" #include "xpm/forbidden_cursor.xpm" #include "xpm/hand_cursor.xpm" #include "xpm/ibeam_cursor.xpm" #include "xpm/openhand_cursor.xpm" #include "xpm/sizeall_cursor.xpm" #include "xpm/sizehor_cursor.xpm" #include "xpm/sizever_cursor.xpm" #include "xpm/splith_cursor.xpm" #include "xpm/splitv_cursor.xpm" #include "xpm/uparrow_cursor.xpm" #include "xpm/wait_cursor.xpm" #include "xpm/whatsthis_cursor.xpm" #include #include class CursorListData : public KPropertyListData { public: CursorListData() : KPropertyListData(keysInternal(), stringsInternal()) { } Qt::CursorShape indexToShape(int index) const { if (index < 0 || index >= keys.count()) return Qt::ArrowCursor; return (Qt::CursorShape)(keys[index].toInt()); } int shapeToIndex(Qt::CursorShape _shape) const { int index = 0; foreach (const QVariant& shape, keys) { if (shape.toInt() == _shape) return index; index++; } return 0; } QPixmap pixmapForIndex(int index, const QPalette& pal, bool transparentBackground = false) const { if (index < 0 || index > 18) index = 0; QPixmap xpm(m_xpms[index]); if (transparentBackground) return xpm; QPixmap px(xpm.size()); QColor bg( pal.color(QPalette::Base) ); // paint bg with to avoid invisible black-on-black painting bg.setAlpha(127); px.fill(bg); QPainter p(&px); p.drawPixmap(0, 2, xpm); return px; } private: static QList keysInternal() { QList keys; keys << int(Qt::BlankCursor) << int(Qt::ArrowCursor) << int(Qt::UpArrowCursor) << int(Qt::CrossCursor) << int(Qt::WaitCursor) << int(Qt::IBeamCursor) << int(Qt::SizeVerCursor) << int(Qt::SizeHorCursor) << int(Qt::SizeBDiagCursor) << int(Qt::SizeFDiagCursor) << int(Qt::SizeAllCursor) << int(Qt::SplitVCursor) << int(Qt::SplitHCursor) << int(Qt::PointingHandCursor) << int(Qt::ForbiddenCursor) << int(Qt::WhatsThisCursor) << int(Qt::BusyCursor) << int(Qt::OpenHandCursor) << int(Qt::ClosedHandCursor); return keys; } static QStringList stringsInternal() { QStringList strings; strings << QObject::tr("No cursor", "Mouse Cursor Shape") //0 << QObject::tr("Arrow", "Mouse Cursor Shape") //1 << QObject::tr("Up arrow", "Mouse Cursor Shape") //2 << QObject::tr("Cross", "Mouse Cursor Shape") //3 << QObject::tr("Waiting", "Mouse Cursor Shape") //4 << QObject::tr("Text cursor", "Mouse Cursor Shape") //5 << QObject::tr("Size vertical", "Mouse Cursor Shape") //6 << QObject::tr("Size horizontal", "Mouse Cursor Shape") //7 << QObject::tr("Size slash", "Mouse Cursor Shape") //8 << QObject::tr("Size backslash", "Mouse Cursor Shape") //9 << QObject::tr("Size all", "Mouse Cursor Shape") //10 << QObject::tr("Split vertical", "Mouse Cursor Shape") //11 << QObject::tr("Split horizontal", "Mouse Cursor Shape") //12 << QObject::tr("Pointing hand", "Mouse Cursor Shape") //13 << QObject::tr("Forbidden", "Mouse Cursor Shape") //14 << QObject::tr("What's this?", "Mouse Cursor Shape") //15 << QObject::tr("Busy", "Mouse Cursor Shape") //16 << QObject::tr("Open hand", "Mouse Cursor Shape") //17 << QObject::tr("Closed hand", "Mouse Cursor Shape"); //18 return strings; } static const char * const * const m_xpms[]; }; const char * const * const CursorListData::m_xpms[] = { blank_cursor_xpm, arrow_cursor_xpm, uparrow_cursor_xpm, cross_cursor_xpm, wait_cursor_xpm, ibeam_cursor_xpm, sizever_cursor_xpm, sizehor_cursor_xpm, bdiag_cursor_xpm, fdiag_cursor_xpm, sizeall_cursor_xpm, splitv_cursor_xpm, splith_cursor_xpm, hand_cursor_xpm, forbidden_cursor_xpm, whatsthis_cursor_xpm, busy_cursor_xpm, openhand_cursor_xpm, closedhand_cursor_xpm }; Q_GLOBAL_STATIC(CursorListData, s_cursorListData) //---------------------- class CursorIconProvider : public KPropertyComboBoxEditor::Options::IconProviderInterface { public: explicit CursorIconProvider(QWidget* parent) : m_parent(parent) {} virtual QIcon icon(int index) const { return s_cursorListData->pixmapForIndex(index, m_parent->palette()); } virtual IconProviderInterface* clone() const { return new CursorIconProvider(m_parent); } QWidget* m_parent; }; //---------------------- static KPropertyComboBoxEditor::Options initComboBoxOptions(QWidget* parent) { KPropertyComboBoxEditor::Options options; options.iconProvider = new CursorIconProvider(parent); return options; } KPropertyCursorEditor::KPropertyCursorEditor(QWidget *parent) : KPropertyComboBoxEditor(*s_cursorListData, initComboBoxOptions( this ), parent) { int paddingTop = 1; int paddingLeft = 2; const QString style(parent->style()->objectName()); if (!KPropertyUtils::gridLineColor(this).isValid()) { setFrame(false); paddingTop = 0; } if (style == QLatin1String("windowsvista") || style == QLatin1String("fusion")) { paddingLeft = 1; } QString styleSheet = QString::fromLatin1("QComboBox { \ %1 \ padding-top: %2px; padding-left: %3px; }").arg(KPropertyComboBoxEditor::borderSheet(this)) .arg(paddingTop).arg(paddingLeft); setStyleSheet(styleSheet); } KPropertyCursorEditor::~KPropertyCursorEditor() { } QCursor KPropertyCursorEditor::cursorValue() const { return QCursor((Qt::CursorShape)KPropertyComboBoxEditor::value().toInt()); } void KPropertyCursorEditor::setCursorValue(const QCursor &value) { KPropertyComboBoxEditor::setValue( (int)(value.shape()) ); } //--------------- KPropertyCursorDelegate::KPropertyCursorDelegate() { options.removeBorders = false; } QWidget * KPropertyCursorDelegate::createEditor( int type, QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const { Q_UNUSED(type); Q_UNUSED(option); Q_UNUSED(index); return new KPropertyCursorEditor(parent); } void KPropertyCursorDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const { - painter->save(); + const KPropertyUtils::PainterSaver saver(painter); int comboIndex = s_cursorListData->shapeToIndex( index.data(Qt::EditRole).value().shape() ); int pmSize = (option.rect.height() >= 32) ? 32 : 16; const QPixmap pm( s_cursorListData->pixmapForIndex(comboIndex, option.palette) .scaled(pmSize, pmSize, Qt::KeepAspectRatio, Qt::SmoothTransformation) ); QPoint pmPoint(option.rect.topLeft() + QPoint(2, 1)); painter->drawPixmap(pmPoint, pm); QRect r(option.rect); r.setLeft(7 + r.left() + 1 + pm.width()); painter->drawText(r, Qt::AlignVCenter | Qt::AlignLeft, valueToString(index.data(Qt::EditRole), QLocale())); - painter->restore(); } QString KPropertyCursorDelegate::valueToString(const QVariant& value, const QLocale &locale) const { const Qt::CursorShape shape = value.value().shape(); if (locale.language() == QLocale::C) { return KPropertyUtils::keyForEnumValue("CursorShape", shape); } const int comboIndex = s_cursorListData->shapeToIndex(shape); return s_cursorListData->names[comboIndex]; } diff --git a/src/editors/fontedit.cpp b/src/editors/fontedit.cpp index 4f7d450..ccd385f 100644 --- a/src/editors/fontedit.cpp +++ b/src/editors/fontedit.cpp @@ -1,154 +1,151 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004 Alexander Dymo Copyright (C) 2005-2015 Jarosław Staniek 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. */ #include "fontedit.h" #include "fontedit_p.h" #include "utils.h" #include "kproperty_debug.h" +#include "KPropertyUtils_p.h" -#include #include -#include #include #include #include -#include #include -#include #include #include KPropertyFontEditRequester::KPropertyFontEditRequester(QWidget *parent) : QWidget(parent) , m_paletteChangedEnabled(true) { setBackgroundRole(QPalette::Base); QHBoxLayout *lyr = new QHBoxLayout(this); lyr->setContentsMargins(0,0,0,0); lyr->setSpacing( 1 ); lyr->addStretch(1); m_button = new QPushButton(this); setFocusProxy(m_button); KPropertyUtils::setupDotDotDotButton(m_button, tr("Click to select a font"), tr("Selects font")); connect( m_button, SIGNAL( clicked() ), SLOT( slotSelectFontClicked() ) ); lyr->addWidget(m_button); setValue(qApp->font()); } QFont KPropertyFontEditRequester::value() const { return m_font; } void KPropertyFontEditRequester::setValue(const QFont &value) { //kprDebug() << QFontDatabase().families(); m_font = value; } void KPropertyFontEditRequester::slotSelectFontClicked() { bool ok; QFont font; font = QFontDialog::getFont(&ok, m_font, parentWidget()); if (ok) { m_font = font; setValue(m_font); emit commitData(this); } } bool KPropertyFontEditRequester::event( QEvent * event ) { return QWidget::event(event); } // ----------- KPropertyFontDelegate::KPropertyFontDelegate() { } QWidget * KPropertyFontDelegate::createEditor( int type, QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const { Q_UNUSED(type); Q_UNUSED(option); Q_UNUSED(index); return new KPropertyFontEditRequester(parent); } void KPropertyFontDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const { - painter->save(); + const KPropertyUtils::PainterSaver saver(painter); const QFont origFont( painter->font() ); QFont f( index.data(Qt::EditRole).value() ); if (option.font.pointSize() > 0) f.setPointSize(option.font.pointSize()); else if (option.font.pixelSize() > 0) f.setPixelSize(option.font.pixelSize()); painter->setFont( f ); QRect rect( option.rect ); rect.setLeft( rect.left() + 1 ); const QString txt( QObject::tr("Abc", "Font sample for property editor item, typically \"Abc\"") ); painter->drawText( rect, Qt::AlignLeft | Qt::AlignVCenter, QObject::tr("Abc", "Font sample for property editor item, typically \"Abc\"") ); rect.setLeft(rect.left() + 5 + painter->fontMetrics().width( txt )); painter->setFont(origFont); painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, valueToString(index.data(Qt::EditRole), QLocale())); - painter->restore(); + } QString KPropertyFontDelegate::valueToString(const QVariant& value, const QLocale &locale) const { const QFont f(value.value()); qreal size = f.pointSizeF(); QString unit; if (size == -1) { size = f.pixelSize(); unit = QLatin1String("px"); } else { unit = QLatin1String("pt"); } QStringList list; list << f.family(); const bool translate = locale.language() == QLocale::C; list << (translate ? QObject::tr("%1%2", ", e.g. 12pt").arg(size).arg(unit) : QString::fromLatin1("%1%2").arg(size).arg(unit)); if (f.bold()) { list << (translate ? QObject::tr("bold", "bold font") : QLatin1String("bold")); } if (f.italic()) { list << (translate ? QObject::tr("italic", "italic font") : QLatin1String("italic")); } if (f.strikeOut()) { list << (translate ? QObject::tr("strikeout", "strikeout font") : QLatin1String("strikeout")); } if (f.underline()) { list << (translate ? QObject::tr("underline", "underline font") : QLatin1String("underline")); } return QLocale::c().createSeparatedList(list); // yes, C locale, we just want ',' separator. } diff --git a/src/editors/linestyleedit.cpp b/src/editors/linestyleedit.cpp index 1675ee7..4afe65c 100644 --- a/src/editors/linestyleedit.cpp +++ b/src/editors/linestyleedit.cpp @@ -1,115 +1,112 @@ /* This file is part of the KDE project Copyright (C) 2010-2015 Jarosław Staniek 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. */ #include "linestyleedit.h" #include "KPropertyWidgetsFactory.h" #include "combobox.h" #include "KPropertyLineStyleItemDelegate_p.h" #include "KPropertyUtils_p.h" -#include -#include #include KPropertyLineStyleComboEditor::KPropertyLineStyleComboEditor(QWidget *parent) : KPropertyLineStyleSelector(parent) { connect(this, SIGNAL(activated(int)), this, SLOT(slotValueChanged(int))); int paddingTop = 1; int paddingLeft = 0; const QString style(parent->style()->objectName()); if (!KPropertyUtils::gridLineColor(this).isValid()) { setFrame(false); paddingTop = 0; } if (style == QLatin1String("windows") || style == QLatin1String("fusion")) { paddingLeft = 3; } else if (style == QLatin1String("windowsvista")) { paddingLeft = 2; } QString styleSheet = QString::fromLatin1("KPropertyLineStyleSelector { \ %1 \ padding-top: %2px; padding-left: %3px; }").arg(KPropertyComboBoxEditor::borderSheet(this)) .arg(paddingTop).arg(paddingLeft); setStyleSheet(styleSheet); } KPropertyLineStyleComboEditor::~KPropertyLineStyleComboEditor() { } QVariant KPropertyLineStyleComboEditor::value() const { return int(lineStyle()); } static bool hasVisibleStyle(const QVariant &value) { return !value.isNull() && value.canConvert(QVariant::Int) && value.toInt() < Qt::CustomDashLine && value.toInt() >= Qt::NoPen; } void KPropertyLineStyleComboEditor::setValue(const QVariant &value) { if (!hasVisibleStyle(value)) { setLineStyle(Qt::NoPen); return; } setLineStyle(static_cast(value.toInt())); } void KPropertyLineStyleComboEditor::slotValueChanged(int) { emit commitData(this); } QWidget * KPropertyLineStyleComboDelegate::createEditor( int type, QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const { Q_UNUSED(type) Q_UNUSED(option) Q_UNUSED(index) return new KPropertyLineStyleComboEditor(parent); } void KPropertyLineStyleComboDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const { - painter->save(); + const KPropertyUtils::PainterSaver saver(painter); Qt::PenStyle penStyle = Qt::NoPen; if (hasVisibleStyle(index.data(Qt::EditRole))) { penStyle = static_cast(index.data(Qt::EditRole).toInt()); } const QWidget *paintedWidget = dynamic_cast(painter->device()); const QStyle *style = paintedWidget ? paintedWidget->style() : qApp->style(); QStyleOptionComboBox cbOption; cbOption.rect = option.rect; QRect r = style->subControlRect(QStyle::CC_ComboBox, &cbOption, QStyle::SC_ComboBoxEditField, 0); r.setRight(option.rect.right() - (r.left() - option.rect.left())); KPropertyLineStyleItemDelegate::paintItem(painter, QPen(penStyle), r, option); - painter->restore(); } QString KPropertyLineStyleComboDelegate::valueToString(const QVariant& value, const QLocale &locale) const { Qt::PenStyle style = (value.isNull() || !value.canConvert(QVariant::Int) || value.toInt() > Qt::CustomDashLine || value.toInt() < Qt::NoPen) ? Qt::NoPen : static_cast(value.toInt()); return KPropertyLineStyleItemDelegate::styleName(style, locale); } diff --git a/src/editors/pixmapedit.cpp b/src/editors/pixmapedit.cpp index 198a003..b2b37ee 100644 --- a/src/editors/pixmapedit.cpp +++ b/src/editors/pixmapedit.cpp @@ -1,279 +1,277 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004 Alexander Dymo Copyright (C) 2005-2015 Jarosław Staniek 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. */ #include "pixmapedit.h" #include "utils.h" #include "KProperty.h" #include "KPropertyUtils.h" +#include "KPropertyUtils_p.h" -#include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include KPropertyPixmapEditor::KPropertyPixmapEditor(KProperty *prop, QWidget *parent) : QWidget(parent) , m_property(prop) { setBackgroundRole(QPalette::Base); QHBoxLayout *lyr = new QHBoxLayout(this); lyr->setContentsMargins(0,0,0,0); m_edit = new QLabel(this); lyr->addWidget(m_edit); m_edit->setContentsMargins(0, 1, 0, 0); m_edit->setToolTip(tr("Click to show image preview")); m_edit->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); // m_edit->setMinimumHeight(5); m_edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); m_edit->setBackgroundRole(QPalette::Base); m_edit->setMouseTracking(true); m_edit->installEventFilter(this); m_button = new QPushButton(this); lyr->addWidget(m_button); KPropertyUtils::setupDotDotDotButton(m_button, tr("Insert image from file"), tr("Inserts image from file")); m_popup = new QLabel(0, Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint); m_popup->setBackgroundRole(QPalette::Base); m_popup->setFrameStyle(QFrame::Plain | QFrame::Box); m_popup->setMargin(2); m_popup->setLineWidth(1); m_popup->hide(); setFocusProxy(m_edit); connect(m_button, SIGNAL(clicked()), this, SLOT(selectPixmap())); } KPropertyPixmapEditor::~KPropertyPixmapEditor() { delete m_popup; } QVariant KPropertyPixmapEditor::value() const { return m_pixmap; } void KPropertyPixmapEditor::setValue(const QVariant &value) { m_pixmap = value.value(); if (m_pixmap.isNull() || (m_pixmap.height() <= height())) { // m_edit->setPixmap(m_pixmap); m_previewPixmap = m_pixmap; } else { QImage img(m_pixmap.toImage()); const QSize sz(size() - QSize(0,1)); if (!QRect(QPoint(0, 0), sz).contains(m_pixmap.rect())) { img = img.scaled(sz, Qt::KeepAspectRatio, Qt::SmoothTransformation); m_previewPixmap = QPixmap::fromImage(img);//preview pixmap is a bit larger } else { m_previewPixmap = m_pixmap; // img = img.scaled(sz, Qt::KeepAspectRatio, Qt::SmoothTransformation); } // const QPixmap pm( QPixmap::fromImage(img) ); // m_edit->setPixmap(pm); } // if (emitChange) // emit valueChanged(this); emit commitData(this); } QString KPropertyPixmapEditor::selectPixmapFileName() { /*#ifdef PURE_QT QString url = QFileDialog::getOpenFileName(); if (!url.isEmpty()) { m_edit->setPixmap(QPixmap(url)); emit valueChanged(this); } #endif*/ const QString caption(tr("Insert Image From File (for \"%1\" property)").arg(m_property->caption())); /*KDE4: #ifdef Q_OS_WIN QString recentDir; QString fileName = Q3FileDialog::getOpenFileName( KFileDialog::getStartURL(":lastVisitedImagePath", recentDir).path(), convertKFileDialogFilterToQFileDialogFilter(KImageIO::pattern(KImageIO::Reading)), this, 0, caption); #else*/ const QUrl url(QFileDialog::getOpenFileUrl(this, caption)); QString fileName = url.isLocalFile() ? url.toLocalFile() : url.toString(); //! @todo download the file if remote, then set fileName properly //#endif return fileName; } void KPropertyPixmapEditor::selectPixmap() { const QString fileName(selectPixmapFileName()); if (fileName.isEmpty()) return; QPixmap pm; if (!pm.load(fileName)) { //! @todo err msg return; } setValue(pm); /* KDE4: #ifdef Q_OS_WIN //save last visited path QUrl url(fileName); if (url.isLocalFile()) KRecentDirs::add(":lastVisitedImagePath", url.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path()); #endif */ } /* void PixmapEdit::resizeEvent(QResizeEvent *e) { Widget::resizeEvent(e); m_edit->move(0, 0); m_edit->resize(e->size() - QSize(m_button->width(), -1)); m_button->move(m_edit->width(), 0); m_button->setFixedSize(m_button->width(), height()); }*/ bool KPropertyPixmapEditor::eventFilter(QObject *o, QEvent *ev) { if (o == m_edit) { if (ev->type() == QEvent::MouseButtonPress && static_cast(ev)->button() == Qt::LeftButton) { if (m_previewPixmap.height() <= m_edit->height() && m_previewPixmap.width() <= m_edit->width()) return false; m_popup->setPixmap(m_previewPixmap.isNull() ? m_pixmap : m_previewPixmap); m_popup->resize(m_previewPixmap.size() + QSize(2*3, 2*3)); QPoint pos = QCursor::pos() + QPoint(3, 15); const QRect screenRect = QApplication::desktop()->availableGeometry(this); if ((pos.x() + m_popup->width()) > screenRect.width()) pos.setX(screenRect.width() - m_popup->width()); if ((pos.y() + m_popup->height()) > screenRect.height()) pos.setY(mapToGlobal(QPoint(0, 0)).y() - m_popup->height()); m_popup->move(pos); m_popup->show(); } else if (ev->type() == QEvent::MouseButtonRelease || ev->type() == QEvent::Hide) { if (m_popup->isVisible()) { m_popup->hide(); } } else if (ev->type() == QEvent::KeyPress) { QKeyEvent* e = static_cast(ev); if ((e->key() == Qt::Key_Enter) || (e->key() == Qt::Key_Space) || (e->key() == Qt::Key_Return)) { m_button->animateClick(); return true; } } } return QWidget::eventFilter(o, ev); } /* void PixmapEdit::setReadOnlyInternal(bool readOnly) { m_button->setEnabled(!readOnly); }*/ //----------------------- KPropertyPixmapDelegate::KPropertyPixmapDelegate() { // options.removeBorders = false; } QWidget* KPropertyPixmapDelegate::createEditor( int type, QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const { Q_UNUSED(type); Q_UNUSED(option); KProperty *property = KPropertyUtils::propertyForIndex(index); if (!property) { return 0; } KPropertyPixmapEditor *pe = new KPropertyPixmapEditor(property, parent); return pe; } void KPropertyPixmapDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const { + const KPropertyUtils::PainterSaver saver(painter); QPixmap pm( index.data(Qt::EditRole).value() ); - painter->save(); if (!pm.isNull()) { if (pm.height() > option.rect.height() || pm.width() > option.rect.width()) { //scale down QImage img(pm.toImage()); img = img.scaled(option.rect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); pm = QPixmap::fromImage(img); } //! @todo /* if (m_recentlyPainted != value) { m_recentlyPainted = value; m_scaledPixmap = value.value(); if (m_scaledPixmap.height() > r2.height() || m_scaledPixmap.width() > r2.width()) { //scale down QImage img(m_scaledPixmap.toImage()); img = img.scaled(r2.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); m_scaledPixmap = QPixmap::fromImage(img); } }*/ painter->drawPixmap(option.rect.topLeft().x(), option.rect.topLeft().y() + (option.rect.height() - pm.height()) / 2, pm); } QRect r(option.rect); r.setLeft(r.left() + pm.width() + 2); painter->drawText(r, valueToString(index.data(Qt::EditRole), QLocale())); - painter->restore(); } QString KPropertyPixmapDelegate::valueToString(const QVariant& value, const QLocale &locale) const { const QPixmap pm(value.value()); if (pm.isNull()) { if (locale.language() == QLocale::C) { return QString(); } return QObject::tr("None", "No pixmap"); } if (locale.language() == QLocale::C) { return QString::fromLatin1("%1x%2px").arg(pm.width()).arg(pm.height()); } return QObject::tr("%1x%2px").arg(locale.toString(pm.width())).arg(locale.toString(pm.height())); }