diff --git a/examples/window.cpp b/examples/window.cpp index 34c7ccf..7d71e87 100644 --- a/examples/window.cpp +++ b/examples/window.cpp @@ -1,283 +1,292 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur - Copyright (C) 2008-2016 Jarosław Staniek + Copyright (C) 2008-2017 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 "window.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include Window::Window() : QWidget() , m_set(this) , m_flatOption("flat", QCoreApplication::translate("main", "Flat display: do not display groups\n(useful for testing)")) , m_fontSizeOption("font-size", QCoreApplication::translate("main", "Set font size to (in points)\n(useful for testing whether editors keep the font settings)"), QCoreApplication::translate("main", "size")) , m_propertyOption("property", QCoreApplication::translate("main", "Display only specified property\n(useful when we want to focus on testing a single\nproperty editor)"), QCoreApplication::translate("main", "name")) , m_roOption("ro", QCoreApplication::translate("main", "Set all properties as read-only:\n(useful for testing read-only mode)")) { setObjectName("kpropertyexamplewindow"); setWindowIcon(QIcon::fromTheme("document-properties")); m_parser.setApplicationDescription(QCoreApplication::translate("main", "An example application for the KProperty library.")); m_parser.addHelpOption(); m_parser.addVersionOption(); parseCommandLine(); const QString singleProperty = m_parser.value(m_propertyOption); bool ok; const int fontSize = m_parser.value(m_fontSizeOption).toInt(&ok); if (fontSize > 0 && ok) { QFont f(font()); f.setPointSize(fontSize); setFont(f); } /* First, create a KPropertySet which will hold the properties. */ KProperty *p = 0; m_set.setReadOnly(m_parser.isSet(m_roOption)); QByteArray group; - if (!m_parser.isSet(m_flatOption)) { + const bool addGroups = !m_parser.isSet(m_flatOption); + if (addGroups) { group = "SimpleGroup"; m_set.setGroupCaption(group, "Simple Group"); } if (singleProperty.isEmpty() || singleProperty=="String") { m_set.addProperty(p = new KProperty("String", "String"), group); - p->setAutoSync(1); + p->setValueSyncPolicy(KProperty::ValueSyncPolicy::Auto); p->setReadOnly(false); // this should not work: // - not needed if the property set is read-write // - ignored if the property set is read-only } if (singleProperty.isEmpty() || singleProperty=="MultiLine") { m_set.addProperty(p = new KProperty("MultiLine", "Multi\nLine\nContent"), group); - p->setAutoSync(1); + p->setValueSyncPolicy(KProperty::ValueSyncPolicy::Auto); p->setOption("multiLine", true); } if (singleProperty.isEmpty() || singleProperty=="Int") { m_set.addProperty(new KProperty("Int", 2, "Int"), group); } if (singleProperty.isEmpty() || singleProperty=="Double") { m_set.addProperty(p = new KProperty("Double", 3.14159, "Double"), group); p->setOption("precision", 4); // will round to 3.1416 } if (singleProperty.isEmpty() || singleProperty=="cm") { const qreal cm = 1.0; // 28.3465058 points const qreal points = KPropertyUnit(KPropertyUnit::Centimeter).fromUserValue(cm); m_set.addProperty(p = new KProperty("cm", points, "Double cm"), group); p->setOption("unit", "cm"); // default precision == 2 } if (singleProperty.isEmpty() || singleProperty=="Bool") { m_set.addProperty(new KProperty("Bool", QVariant(true), "Bool"), group); } if (singleProperty.isEmpty() || singleProperty=="NullBool") { m_set.addProperty(new KProperty("NullBool", QVariant(), "Null Bool", QString(), KProperty::Bool), group); } if (singleProperty.isEmpty() || singleProperty=="3-State") { m_set.addProperty(p = new KProperty("3-State", QVariant(), "3 States", QString(), KProperty::Bool), group); p->setOption("3State", true); } if (singleProperty.isEmpty() || singleProperty=="Date") { m_set.addProperty(p = new KProperty("Date", QDate::currentDate(), "Date"), group); p->setIconName("date"); } if (singleProperty.isEmpty() || singleProperty=="Time") { m_set.addProperty(new KProperty("Time", QTime::currentTime(), "Time"), group); } if (singleProperty.isEmpty() || singleProperty=="DateTime") { m_set.addProperty(new KProperty("DateTime", QDateTime::currentDateTime(), "Date/Time"), group); } QStringList name_list; //strings name_list << "My Item" << "Other Item" << "Third Item"; if (singleProperty.isEmpty() || singleProperty=="List") { QStringList list;//keys list << "myitem" << "otheritem" << "3rditem"; m_set.addProperty(new KProperty("List", list, name_list, "otheritem", "List"), group); } if (singleProperty.isEmpty() || singleProperty=="List2") { // A valueFromList property matching strings with ints (could be any type supported by QVariant) QList keys; keys.append(1); keys.append(2); keys.append(3); KPropertyListData *listData = new KPropertyListData(keys, name_list); m_set.addProperty(new KProperty("List2", listData, 3, "List 2"), group); } // Complex - if (!m_parser.isSet(m_flatOption)) { + if (addGroups) { group = "ComplexGroup"; m_set.setGroupCaption(group, "Complex Group"); } if (singleProperty.isEmpty() || singleProperty=="Rect") { m_set.addProperty(new KProperty("Rect", QRect(5,11,100,200), "Rect"), group); } if (singleProperty.isEmpty() || singleProperty=="Point") { m_set.addProperty(new KProperty("Point", QPoint(3, 4), "Point"), group); } if (singleProperty.isEmpty() || singleProperty=="Size") { m_set.addProperty(new KProperty("Size", QSize(10, 20), "Size"), group); } if (singleProperty.isEmpty() || singleProperty=="RectF") { m_set.addProperty(new KProperty("RectF", QRectF(0.1, 0.5, 10.72, 18.21), "RectF"), group); } if (singleProperty.isEmpty() || singleProperty=="PointF") { m_set.addProperty(new KProperty("PointF", QPointF(3.14, 4.15), "PointF"), group); } if (singleProperty.isEmpty() || singleProperty=="SizeF") { m_set.addProperty(new KProperty("SizeF", QSizeF(1.1, 2.45), "SizeF"), group); } // Appearance - if (!m_parser.isSet(m_flatOption)) { + if (addGroups) { group = "Appearance Group"; m_set.setGroupCaption(group, "Appearance Group"); m_set.setGroupIconName(group, "appearance"); } if (singleProperty.isEmpty() || singleProperty=="Color") { m_set.addProperty(new KProperty("Color", palette().color(QPalette::Active, QPalette::Background), "Color"), group); } if (singleProperty.isEmpty() || singleProperty=="Pixmap") { QPixmap pm(QIcon::fromTheme("network-wired").pixmap(QSize(16,16))); m_set.addProperty(p = new KProperty("Pixmap", pm, "Pixmap"), group); p->setIconName("kpaint"); } if (singleProperty.isEmpty() || singleProperty=="Font") { QFont myFont("Times New Roman", 12); myFont.setUnderline(true); m_set.addProperty(p = new KProperty("Font", myFont, "Font"), group); p->setIconName("fonts"); } if (singleProperty.isEmpty() || singleProperty=="Cursor") { m_set.addProperty(new KProperty("Cursor", QCursor(Qt::WaitCursor), "Cursor"), group); } if (singleProperty.isEmpty() || singleProperty=="LineStyle") { m_set.addProperty(new KProperty("LineStyle", 3, "Line Style", QString(), KProperty::LineStyle), group); } if (singleProperty.isEmpty() || singleProperty=="SizePolicy") { QSizePolicy sp(sizePolicy()); sp.setHorizontalStretch(1); sp.setVerticalStretch(2); m_set.addProperty(new KProperty("SizePolicy", sp, "Size Policy"), group); } if (singleProperty.isEmpty() || singleProperty=="Invisible") { m_set.addProperty(p = new KProperty("Invisible", "I am invisible", "Invisible"), group); p->setVisible(false); } if (singleProperty.isEmpty() || singleProperty=="Url") { m_set.addProperty(p = new KProperty("Url", QUrl("https://community.kde.org/KProperty"), "Url"), group); } if (singleProperty.isEmpty() || singleProperty=="ExistingFile") { m_set.addProperty(p = new KProperty("ExistingFile", QUrl::fromLocalFile(QDir::homePath()), "Existing File"), group); p->setOption("fileMode", "existingFile"); } if (singleProperty.isEmpty() || singleProperty=="OverwriteFile") { m_set.addProperty(p = new KProperty("OverwriteFile", QUrl::fromLocalFile(QDir::homePath()), "Overwrite File"), group); p->setOption("fileMode", "existingFile"); p->setOption("confirmOverwrites", true); } if (singleProperty.isEmpty() || singleProperty=="Dir") { m_set.addProperty(p = new KProperty("Dir", QUrl::fromLocalFile(QDir::homePath()), "Dir"), group); p->setOption("fileMode", "dirsOnly"); } if (singleProperty.isEmpty() || singleProperty=="ReadOnly") { m_set.addProperty(p = new KProperty("Read-Only", "Read-only string"), group); p->setReadOnly(true); } -// qDebug() << m_set.groupNames(); QVBoxLayout *lyr = new QVBoxLayout(this); m_editorView = new KPropertyEditorView(this); lyr->addWidget(m_editorView); - m_editorView->changeSet(&m_set, KPropertyEditorView::ExpandChildItems); + m_editorView->changeSet(&m_set); lyr->addSpacing(lyr->spacing()); QHBoxLayout *hlyr = new QHBoxLayout; lyr->addLayout(hlyr); - m_showGrid = new QCheckBox("Show grid"); - m_showGrid->setChecked(true); - connect(m_showGrid, &QCheckBox::stateChanged, this, &Window::showGrid); - hlyr->addWidget(m_showGrid); + QCheckBox *showGrid = new QCheckBox("Show grid"); + showGrid->setChecked(true); + connect(showGrid, &QCheckBox::stateChanged, this, &Window::showGrid); + hlyr->addWidget(showGrid); - m_showFrame = new QCheckBox("Show frame"); - m_showFrame->setChecked(true); - connect(m_showFrame, &QCheckBox::stateChanged, this, &Window::showFrame); - hlyr->addWidget(m_showFrame); + QCheckBox *showFrame = new QCheckBox("Show frame"); + showFrame->setChecked(true); + connect(showFrame, &QCheckBox::stateChanged, this, &Window::showFrame); + hlyr->addWidget(showFrame); + + QCheckBox *showGroups = new QCheckBox("Show groups"); + if (addGroups) { + connect(showGroups, &QCheckBox::toggled, m_editorView, &KPropertyEditorView::setGroupsVisible); + showGroups->setChecked(m_editorView->groupsVisible()); + } else { + showGroups->setEnabled(false); + } + hlyr->addWidget(showGroups); QCheckBox *readOnly = new QCheckBox("Read-only"); connect(readOnly, &QCheckBox::toggled, &m_set, &KPropertySet::setReadOnly); readOnly->setChecked(m_set.isReadOnly()); hlyr->addWidget(readOnly); hlyr->addStretch(1); resize(400, qApp->desktop()->height() - 200); m_editorView->setFocus(); qDebug() << m_set; } Window::~Window() { } void Window::parseCommandLine() { m_parser.addOption(m_flatOption); m_parser.addOption(m_fontSizeOption); m_parser.addOption(m_propertyOption); m_parser.addOption(m_roOption); m_parser.process(*(QCoreApplication::instance())); } void Window::showGrid(int state) { m_editorView->setGridLineColor( state == Qt::Checked ? KPropertyEditorView::defaultGridLineColor() : QColor()); } void Window::showFrame(int state) { m_editorView->setFrameStyle(state == Qt::Checked ? QFrame::Box : QFrame::NoFrame); } diff --git a/examples/window.h b/examples/window.h index c9db58d..b937e39 100644 --- a/examples/window.h +++ b/examples/window.h @@ -1,58 +1,55 @@ /* This file is part of the KDE project Copyright (C) 2004-2005 Cedric Pasteur - Copyright (C) 2008-2009 Jarosław Staniek + Copyright (C) 2008-2017 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 WINDOW_H #define WINDOW_H #include #include #include -class QCheckBox; class KPropertyEditorView; /*! @internal * @short KPropertyExample application's main window */ class Window : public QWidget { Q_OBJECT public: Window(); virtual ~Window(); protected Q_SLOTS: void showGrid(int state); void showFrame(int state); private: void parseCommandLine(); KPropertySet m_set; QCommandLineParser m_parser; QCommandLineOption m_flatOption; QCommandLineOption m_fontSizeOption; QCommandLineOption m_propertyOption; QCommandLineOption m_roOption; KPropertyEditorView *m_editorView; - QCheckBox *m_showGrid; - QCheckBox *m_showFrame; }; #endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 227b919..77b5aee 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,331 +1,332 @@ # Options # ... set(kpropertycore_LIB_SRCS KProperty.cpp KPropertySet.cpp KPropertyUnit_p.cpp KPropertyFactory.cpp KPropertyCoreUtils.cpp kproperty_debug.cpp ) set(kpropertycore_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} ) # TODO: see T3992, Split kproperty_qt into kpropertycore_qt & kpropertywidgets_qt ecm_create_qm_loader(kpropertycore_LIB_SRCS kproperty_qt) add_library(KPropertyCore SHARED ${kpropertycore_LIB_SRCS}) set_coinstallable_lib_version(KPropertyCore) target_link_libraries(KPropertyCore PUBLIC Qt5::Core ) generate_export_header(KPropertyCore) target_include_directories(KPropertyCore PUBLIC "$" INTERFACE "$" ) if(KPROPERTY_WIDGETS) add_library(KPropertyUtilsPrivate STATIC KPropertyUtils_p.cpp ) target_link_libraries(KPropertyUtilsPrivate PUBLIC Qt5::Widgets ) add_subdirectory(editors) set(kpropertywidgets_LIB_SRCS editors/utils.cpp editors/booledit.cpp editors/coloredit.cpp editors/combobox.cpp editors/cursoredit.cpp editors/dateedit.cpp editors/datetimeedit.cpp # editors/dummywidget.cpp editors/fontedit.cpp editors/pixmapedit.cpp editors/pointedit.cpp editors/pointfedit.cpp editors/rectedit.cpp editors/KPropertyRectFEditor.cpp editors/sizeedit.cpp editors/sizefedit.cpp editors/sizepolicyedit.cpp editors/spinbox.cpp editors/KPropertyGenericSelectionEditor.cpp editors/KPropertyMultiLineStringEditor.cpp editors/KPropertyStringEditor.cpp editors/KPropertyUrlEditor.cpp editors/linestyleedit.cpp # editors/stringlistedit.cpp # editors/symbolcombo.cpp editors/timeedit.cpp #TODO editors/urledit.cpp kproperty_debug.cpp # needed here too KPropertyWidgetsFactory.cpp KPropertyWidgetsPluginManager.cpp KDefaultPropertyFactory.cpp KPropertyEditorView.cpp KPropertyEditorDataModel.cpp KPropertyUtils.cpp KPropertyLineStyleSelector_p.cpp KPropertyLineStyleModel_p.cpp KPropertyLineStyleItemDelegate_p.cpp # non-source: Mainpage.dox Messages.sh ) # TODO: reenable once kproperty_qt has been split # ecm_create_qm_loader(kpropertywidgets_LIB_SRCS kpropertywidgets_qt) set(kpropertywidgets_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/editors ) if(NOT KPROPERTY_KF) list(APPEND kpropertywidgets_LIB_SRCS editors/3rdparty/KColorCombo.cpp editors/3rdparty/KColorCollection.cpp ) list(APPEND kpropertywidgets_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/editors/3rdparty ) endif() add_library(KPropertyWidgets SHARED ${kpropertywidgets_LIB_SRCS}) set_coinstallable_lib_version(KPropertyWidgets) target_link_libraries(KPropertyWidgets PUBLIC KPropertyCore + Qt5::Widgets PRIVATE KPropertyUtilsPrivate ) if(KPROPERTY_KF) target_link_libraries(KPropertyUtilsPrivate PUBLIC KF5::ConfigGui #KConfigGroup KF5::GuiAddons #KColorCollection KF5::WidgetsAddons #KMessageBox ) endif() generate_export_header(KPropertyWidgets) target_include_directories(KPropertyWidgets PUBLIC "$" INTERFACE "$" PRIVATE editors ) endif() # Create a Config.cmake and a ConfigVersion.cmake file and install them set(CMAKECONFIG_CORE_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/${KPROPERTYCORE_BASE_NAME}") # A place for KProperty plugins set(KPROPERTY_PLUGIN_INSTALL_DIR ${PLUGIN_INSTALL_DIR}/kproperty${PROJECT_STABLE_VERSION_MAJOR}) ecm_setup_version(${PROJECT_VERSION} VARIABLE_PREFIX KPROPERTYCORE VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kproperty_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KPropertyCoreConfigVersion.cmake" ) ecm_configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/KPropertyCoreConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KPropertyCoreConfig.cmake" INSTALL_DESTINATION "${CMAKECONFIG_CORE_INSTALL_DIR}" ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KPropertyCoreConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KPropertyCoreConfigVersion.cmake" DESTINATION "${CMAKECONFIG_CORE_INSTALL_DIR}" COMPONENT Devel) if(SAILFISH) set(KDE_INSTALL_TARGETS_DEFAULT_ARGS LIBRARY DESTINATION lib) endif() install(TARGETS KPropertyCore EXPORT KPropertyCoreTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(EXPORT KPropertyCoreTargets DESTINATION "${CMAKECONFIG_CORE_INSTALL_DIR}" FILE KPropertyCoreTargets.cmake) if(KPROPERTY_WIDGETS) set(CMAKECONFIG_WIDGETS_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/${KPROPERTYWIDGETS_BASE_NAME}") ecm_setup_version(${PROJECT_VERSION} VARIABLE_PREFIX KPROPERTYWIDGETS VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kproperty_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KPropertyWidgetsConfigVersion.cmake" ) ecm_configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/KPropertyWidgetsConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KPropertyWidgetsConfig.cmake" INSTALL_DESTINATION "${CMAKECONFIG_WIDGETS_INSTALL_DIR}" ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KPropertyWidgetsConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KPropertyWidgetsConfigVersion.cmake" DESTINATION "${CMAKECONFIG_WIDGETS_INSTALL_DIR}" COMPONENT Devel) install(TARGETS KPropertyWidgets EXPORT KPropertyWidgetsTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(EXPORT KPropertyWidgetsTargets DESTINATION "${CMAKECONFIG_WIDGETS_INSTALL_DIR}" FILE KPropertyWidgetsTargets.cmake) endif() install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) if(KPROPERTY_GENERATE_PRI) ecm_generate_pri_file( BASE_NAME ${KPROPERTYCORE_BASE_NAME} LIB_NAME ${KPROPERTYCORE_BASE_NAME} DEPS "core" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KPROPERTYCORE_INCLUDE_INSTALL_DIR} ) if(KPROPERTY_WIDGETS) ecm_generate_pri_file( BASE_NAME ${KPROPERTYWIDGETS_BASE_NAME} LIB_NAME ${KPROPERTYWIDGETS_BASE_NAME} DEPS "widgets KPropertyCore" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KPROPERTYWIDGETS_INCLUDE_INSTALL_DIR} ) endif() endif() #ecm_install_icons(${DATA_INSTALL_DIR}/kproperty/icons) ecm_generate_headers(kpropertycore_FORWARDING_HEADERS REQUIRED_HEADERS kpropertycore_HEADERS ORIGINAL CAMELCASE HEADER_NAMES KProperty KPropertySet KPropertyFactory ) list(APPEND kpropertycore_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/kproperty_version.h) install( FILES ${kpropertycore_HEADERS} ${kpropertycore_FORWARDING_HEADERS} ${PROJECT_BINARY_DIR}/src/kpropertycore_export.h ${PROJECT_BINARY_DIR}/src/config-kproperty.h DESTINATION ${KPROPERTYCORE_INCLUDE_INSTALL_DIR} COMPONENT Devel ) if(KPROPERTY_WIDGETS) add_subdirectory(pics) ecm_generate_headers(kpropertywidgets_FORWARDING_HEADERS REQUIRED_HEADERS kpropertywidgets_HEADERS ORIGINAL CAMELCASE HEADER_NAMES KPropertyWidgetsFactory KPropertyWidgetsPluginManager KPropertyUtils KPropertyEditorView ) install( FILES ${kpropertywidgets_HEADERS} ${kpropertywidgets_FORWARDING_HEADERS} ${kproperty_editors_HEADERS} ${kproperty_editors_FORWARDING_HEADERS} ${PROJECT_BINARY_DIR}/src/kpropertywidgets_export.h DESTINATION ${KPROPERTYWIDGETS_INCLUDE_INSTALL_DIR} COMPONENT Devel ) endif() if(BUILD_QCH) kproperty_add_qch( KPropertyCore_QCH NAME KPropertyCore BASE_NAME ${KPROPERTYCORE_BASE_NAME} VERSION ${PROJECT_VERSION} NAMESPACE org.kde.${KPROPERTYCORE_BASE_NAME} SOURCES Mainpage.dox ${kpropertycore_HEADERS} LINK_QCHS Qt5Core_QCH BLANK_MACROS KPROPERTYCORE_EXPORT KPROPERTYCORE_DEPRECATED TAGFILE_INSTALL_DESTINATION ${KPROPERTY_QTQCH_FULL_INSTALL_DIR} QCH_INSTALL_DESTINATION ${KPROPERTY_QTQCH_FULL_INSTALL_DIR} ) set(kpropertycore_qch_targets KPropertyCore_QCH) endif() kproperty_install_qch_export( TARGETS ${kpropertycore_qch_targets} FILE KPropertyCoreQCHTargets.cmake DESTINATION "${CMAKECONFIG_CORE_INSTALL_DIR}" COMPONENT Devel ) if(KPROPERTY_WIDGETS) if(BUILD_QCH) if(KPROPERTY_KF) set(_KF5WidgetsAddons_QCH KF5WidgetsAddons_QCH) endif() kproperty_add_qch( KPropertyWidgets_QCH NAME KPropertyWidgets BASE_NAME ${KPROPERTYWIDGETS_BASE_NAME} VERSION ${PROJECT_VERSION} NAMESPACE org.kde.${KPROPERTYWIDGETS_BASE_NAME} SOURCES ${kpropertywidgets_HEADERS} ${kproperty_editors_HEADERS} LINK_QCHS Qt5Core_QCH Qt5Gui_QCH Qt5Widgets_QCH KPropertyCore_QCH ${_KF5WidgetsAddons_QCH} BLANK_MACROS KPROPERTYWIDGETS_EXPORT KPROPERTYWIDGETS_DEPRECATED TAGFILE_INSTALL_DESTINATION ${KPROPERTY_QTQCH_FULL_INSTALL_DIR} QCH_INSTALL_DESTINATION ${KPROPERTY_QTQCH_FULL_INSTALL_DIR} ) set(kpropertywidgets_qch_targets KPropertyWidgets_QCH) endif() kproperty_install_qch_export( TARGETS ${kpropertywidgets_qch_targets} FILE KPropertyWidgetsQCHTargets.cmake DESTINATION "${CMAKECONFIG_WIDGETS_INSTALL_DIR}" COMPONENT Devel ) endif() enable_testing() configure_file(config-kproperty.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kproperty.h) diff --git a/src/KProperty.cpp b/src/KProperty.cpp index 1d7f134..01bfd74 100644 --- a/src/KProperty.cpp +++ b/src/KProperty.cpp @@ -1,789 +1,788 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004 Alexander Dymo - Copyright (C) 2004-2015 Jarosław Staniek + Copyright (C) 2004-2017 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 "KProperty.h" #include "KProperty_p.h" #include "KPropertySet_p.h" #include "KPropertyFactory.h" #include "kproperty_debug.h" //! @return true if @a currentValue and @a value are compatible static bool compatibleTypes(const QVariant& currentValue, const QVariant &value) { if (currentValue.isNull() || value.isNull()) return true; const QVariant::Type t = currentValue.type(); const QVariant::Type newt = value.type(); if (t == newt) return true; if ( (t == QVariant::Int && newt == QVariant::UInt) || (t == QVariant::UInt && newt == QVariant::Int) || (t == QVariant::ByteArray && newt == QVariant::String) || (t == QVariant::String && newt == QVariant::ByteArray) || (t == QVariant::ULongLong && newt == QVariant::LongLong) || (t == QVariant::LongLong && newt == QVariant::ULongLong)) { return true; } return false; } // ---- KProperty::Private::Private(KProperty *prop) : q(prop), type(KProperty::Auto), caption(0), listData(0), changed(false), storable(true), readOnly(false), visible(true), - autosync(-1), composed(0), useComposedProperty(true), + composed(0), useComposedProperty(true), sets(0), parent(0), children(0), relatedProperties(0) { } void KProperty::Private::setCaptionForDisplaying(const QString& captionForDisplaying) { delete caption; if (captionForDisplaying.simplified() != captionForDisplaying) { if (captionForDisplaying.isEmpty()) { caption = 0; } else { caption = new QString(captionForDisplaying.simplified()); } } else { caption = 0; } this->captionForDisplaying = captionForDisplaying; } KProperty::Private::~Private() { delete caption; caption = 0; delete listData; if (children) { qDeleteAll(*children); delete children; } delete relatedProperties; delete composed; delete sets; } bool KProperty::Private::valueDiffersInternal(const QVariant &otherValue, KProperty::ValueOptions options) { if (!compatibleTypes(value, otherValue)) { kprWarning() << "INCOMPATIBLE TYPES! old=" << value << "new=" << otherValue << "in property" << q->name(); } const QVariant::Type t = value.type(); const QVariant::Type newt = otherValue.type(); if ( t == QVariant::DateTime || t == QVariant::Time) { //for date and datetime types: compare with strings, because there //can be miliseconds difference return value.toString() != otherValue.toString(); } else if (t == QVariant::String || t == QVariant::ByteArray) { //property is changed for string type, //if one of value is empty and other isn't.. return (value.toString().isEmpty() != otherValue.toString().isEmpty()) //..or both are not empty and values differ || (!value.toString().isEmpty() && !otherValue.toString().isEmpty() && value != otherValue); } else if (t == QVariant::Double) { const double factor = 1.0 / option("step", KPROPERTY_DEFAULT_DOUBLE_VALUE_STEP).toDouble(); //kprDebug() // << "double compared:" << value.toDouble() << otherValue.toDouble() // << ":" << static_cast(value.toDouble() * factor) << static_cast(otherValue.toDouble() * factor); return static_cast(value.toDouble() * factor) != static_cast(otherValue.toDouble() * factor); } else if (t == QVariant::Invalid && newt == QVariant::Invalid) { return false; } else if (composed && (options & UseComposedProperty)) { return !composed->valuesEqual(value, otherValue); } else { return value != otherValue; } } bool KProperty::Private::setValueInternal(const QVariant &newValue, KProperty::ValueOptions valueOptions) { if (name.isEmpty()) { kprWarning() << "COULD NOT SET value to a null property"; return false; } //1. Check if the value should be changed if (!valueDiffersInternal(newValue, valueOptions)) { return false; } //2. Then change it, and store old value if necessary if (valueOptions & KProperty::RememberOldValue) { if (!changed) { oldValue = value; } changed = true; } else { oldValue = QVariant(); // clear old value changed = false; } if (parent) { parent->childValueChanged(q, newValue, valueOptions & KProperty::RememberOldValue); } QVariant prevValue; if (composed && useComposedProperty) { prevValue = value; //??? composed->setChildValueChangedEnabled(false); composed->setValue(q, newValue, valueOptions & KProperty::RememberOldValue); composed->setChildValueChangedEnabled(true); } else { prevValue = value; } value = newValue; if (!parent) { // emit only if parent has not done it emitPropertyChanged(); // called as last step in this method! } return true; } void KProperty::Private::addChild(KProperty *prop) { if (!prop) { return; } if (!children || qFind(children->begin(), children->end(), prop) == children->end()) { // not in our list if (!children) { children = new QList(); } children->append(prop); prop->d->parent = q; } else { kprWarning() << "property" << name << ": child property" << prop->name() << "already added"; return; } } void KProperty::Private::addSet(KPropertySet *newSet) { if (!newSet) { return; } if (!set) {//simple case set = newSet; return; } if (set == newSet || (sets && sets->contains(newSet))) { return; } if (!sets) { sets = new QList< QPointer >; } sets->append(QPointer(newSet)); } void KProperty::Private::addRelatedProperty(KProperty *property) { if (!relatedProperties) relatedProperties = new QList(); if (!relatedProperties->contains(property)) { relatedProperties->append(property); } } void KProperty::Private::emitPropertyChanged() { QList< QPointer > *realSets = nullptr; if (sets) { realSets = sets; } else if (parent) { realSets = parent->d->sets; } if (realSets) { foreach (QPointer s, *realSets) { if (!s.isNull()) { //may be destroyed in the meantime emit s->propertyChangedInternal(*s, *q); emit s->propertyChanged(*s, *q); } } } else { QPointer realSet; if (set) { realSet = set; } else if (parent) { realSet = parent->d->set; } if (!realSet.isNull()) { //if the slot connect with that signal may call set->clear() - that's //the case e.g. at kexi/plugins/{macros|scripting}/* - this KProperty //may got destroyed ( see KPropertySet::removeProperty(KProperty*) ) while we are //still on it. So, if we try to access ourself/this once the signal //got emitted we may end in a very hard to reproduce crash. So, the //emit should happen as last step in this method! emit realSet->propertyChangedInternal(*realSet, *q); emit realSet->propertyChanged(*realSet, *q); } } } ///////////////////////////////////////////////////////////////// KPropertyListData::KPropertyListData(const QStringList& keys_, const QStringList& names_) : names(names_) { setKeysAsStringList(keys_); } KPropertyListData::KPropertyListData(const QList keys_, const QStringList& names_) : keys(keys_), names(names_) { } KPropertyListData::KPropertyListData() { } KPropertyListData::~KPropertyListData() { } void KPropertyListData::setKeysAsStringList(const QStringList& list) { keys.clear(); for (QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) { keys.append(*it); } } QStringList KPropertyListData::keysAsStringList() const { QStringList result; for (QList::ConstIterator it = keys.constBegin(); it != keys.constEnd(); ++it) { result.append((*it).toString()); } return result; } ///////////////////////////////////////////////////////////////// KProperty::KProperty(const QByteArray &name, const QVariant &value, const QString &caption, const QString &description, int type, KProperty* parent) : d(new KProperty::Private(this)) { d->name = name; d->setCaptionForDisplaying(caption); d->description = description; if (type == int(Auto)) { type = value.type(); } setType(type); if (parent) parent->d->addChild(this); setValue(value, false); } KProperty::KProperty(const QByteArray &name, const QStringList &keys, const QStringList &strings, const QVariant &value, const QString &caption, const QString &description, int type, KProperty* parent) : d(new KProperty::Private(this)) { d->name = name; d->setCaptionForDisplaying(caption); d->description = description; setListData(keys, strings); if (type == int(Auto)) { type = value.type(); } setType(type); if (parent) parent->d->addChild(this); setValue(value, false); } KProperty::KProperty(const QByteArray &name, KPropertyListData* listData, const QVariant &value, const QString &caption, const QString &description, int type, KProperty* parent) : d(new KProperty::Private(this)) { d->name = name; d->setCaptionForDisplaying(caption); d->description = description; d->listData = listData; if (type == int(Auto)) { type = value.type(); } setType(type); if (parent) parent->d->addChild(this); setValue(value, false); } KProperty::KProperty() : d(new KProperty::Private(this)) { } KProperty::KProperty(const KProperty &prop) : d(new KProperty::Private(this)) { *this = prop; } KProperty::~KProperty() { delete d; } QByteArray KProperty::name() const { return d->name; } void KProperty::setName(const QByteArray &name) { d->name = name; } QString KProperty::caption() const { return d->caption ? *d->caption : d->captionForDisplaying; } QString KProperty::captionForDisplaying() const { return d->captionForDisplaying; } void KProperty::setCaption(const QString &caption) { d->setCaptionForDisplaying(caption); } QString KProperty::description() const { return d->description; } void KProperty::setDescription(const QString &desc) { d->description = desc; } int KProperty::type() const { return d->type; } void KProperty::setType(int type) { if (d->type != type) { d->type = type; delete d->composed; d->composed = KPropertyFactoryManager::self()->createComposedProperty(this); } } QString KProperty::iconName() const { return d->iconName; } void KProperty::setIconName(const QString &name) { d->iconName = name; } QVariant KProperty::value() const { return d->value; } QVariant KProperty::oldValue() const { return d->oldValue; } void KProperty::childValueChanged(KProperty *child, const QVariant &value, bool rememberOldValue) { if (!d->composed) return; d->composed->childValueChangedInternal(child, value, rememberOldValue); } void KProperty::setValue(const QVariant &value, bool rememberOldValue, bool useComposedProperty) { (void)d->setValueInternal(value, (rememberOldValue ? KProperty::RememberOldValue : KProperty::ValueOptions()) | (useComposedProperty ? KProperty::UseComposedProperty : KProperty::ValueOptions())); } void KProperty::setValue(const QVariant &value, bool *changed, ValueOptions options) { const bool ch = d->setValueInternal(value, options); if (changed) { *changed = ch; } } bool KProperty::valueEqualsTo(const QVariant &value, ValueOptions valueOptions) const { return !d->valueDiffersInternal(value, valueOptions); } void KProperty::resetValue() { d->changed = false; bool cleared = false; if (d->set) { KPropertySetPrivate::d(d->set)->informAboutClearing(&cleared); //inform me about possibly clearing the property sets } setValue(oldValue(), false); if (cleared) return; //property set has been cleared: no further actions make sense as 'this' is dead // maybe parent prop is also unchanged now if (d->parent && d->parent->value() == d->parent->oldValue()) d->parent->d->changed = false; if (d->sets) { foreach (QPointer set, *d->sets) { if (!set.isNull()) //may be destroyed in the meantime emit set->propertyReset(*set, *this); } } else if (d->set) { emit d->set->propertyReset(*d->set, *this); } } KPropertyListData* KProperty::listData() const { return d->listData; } void KProperty::setListData(KPropertyListData* list) { if (list == d->listData) return; delete d->listData; d->listData = list; } void KProperty::setListData(const QStringList &keys, const QStringList &names) { KPropertyListData* list = new KPropertyListData(keys, names); setListData(list); } //////////////////////////////////////////////////////////////// bool KProperty::isNull() const { return d->name.isEmpty(); } bool KProperty::isModified() const { return d->changed; } void KProperty::clearModifiedFlag() { d->changed = false; } bool KProperty::isReadOnly() const { return d->readOnly; } void KProperty::setReadOnly(bool readOnly) { d->readOnly = readOnly; } bool KProperty::isVisible() const { return d->visible; } void KProperty::setVisible(bool visible) { d->visible = visible; } -int -KProperty::autoSync() const +KProperty::ValueSyncPolicy KProperty::valueSyncPolicy() const { - return d->autosync; + return d->valueSyncPolicy; } void -KProperty::setAutoSync(int sync) +KProperty::setValueSyncPolicy(KProperty::ValueSyncPolicy policy) { - d->autosync = sync; + d->valueSyncPolicy = policy; } bool KProperty::isStorable() const { return d->storable; } void KProperty::setStorable(bool storable) { d->storable = storable; } void KProperty::setOption(const char* name, const QVariant& val) { d->options[name] = val; } QVariant KProperty::option(const char* name, const QVariant& defaultValue) const { return d->option(name, defaultValue); } bool KProperty::hasOptions() const { return !d->options.isEmpty() || (d->parent && d->parent->hasOptions()); } ///////////////////////////////////////////////////////////////// KProperty& KProperty::operator= (const QVariant & val) { setValue(val); return *this; } KProperty& KProperty::operator= (const KProperty & property) { if (&property == this) return *this; delete d->listData; d->listData = 0; delete d->children; d->children = 0; delete d->relatedProperties; d->relatedProperties = 0; delete d->composed; d->composed = 0; d->name = property.d->name; d->setCaptionForDisplaying(property.captionForDisplaying()); d->description = property.d->description; d->type = property.d->type; d->iconName = property.d->iconName; - d->autosync = property.d->autosync; + d->valueSyncPolicy = property.d->valueSyncPolicy; d->visible = property.d->visible; d->storable = property.d->storable; d->readOnly = property.d->readOnly; d->options = property.d->options; if (property.d->listData) { d->listData = new KPropertyListData(*property.d->listData); } if (property.d->composed) { delete d->composed; d->composed = KPropertyFactoryManager::self()->createComposedProperty(this); // updates all children value, using KComposedPropertyInterface setValue(property.value()); } else { d->value = property.d->value; if (property.d->children) { // no KComposedPropertyInterface (should never happen), simply copy all children d->children = new QList(); QList::ConstIterator endIt = property.d->children->constEnd(); for (QList::ConstIterator it = property.d->children->constBegin(); it != endIt; ++it) { KProperty *child = new KProperty(*(*it)); d->addChild(child); } } } if (property.d->relatedProperties) { d->relatedProperties = new QList(*(property.d->relatedProperties)); } // update these later because they may have been changed when creating children d->oldValue = property.d->oldValue; d->changed = property.d->changed; return *this; } bool KProperty::operator ==(const KProperty &prop) const { return ((d->name == prop.d->name) && (value() == prop.value())); } ///////////////////////////////////////////////////////////////// const QList* KProperty::children() const { return d->children; } KProperty* KProperty::child(const QByteArray &name) { QList::ConstIterator endIt = d->children->constEnd(); for (QList::ConstIterator it = d->children->constBegin(); it != endIt; ++it) { if ((*it)->name() == name) return *it; } return 0; } KProperty* KProperty::parent() const { return d->parent; } KComposedPropertyInterface* KProperty::composedProperty() const { return d->composed; } void KProperty::setComposedProperty(KComposedPropertyInterface *prop) { if (d->composed == prop) return; delete d->composed; d->composed = prop; } #if 0 int Property::sortingKey() const { return d->sortingKey; } void Property::setSortingKey(int key) { d->sortingKey = key; } #endif ///////////////////////////////////////////////////////////////// KPROPERTYCORE_EXPORT QDebug operator<<(QDebug dbg, const KProperty &p) { dbg.nospace() << "KProperty(" << "NAME=" << p.name(); if (!p.caption().isEmpty()) { dbg.nospace() << " CAPTION=" << p.caption(); } if (!p.description().isEmpty()) { dbg.nospace() << " DESC=" << p.description(); } dbg.nospace() << " TYPE=" << p.type(); if (p.value().isValid()) { dbg.nospace() << " VALUE=" << p.value(); } else { dbg.nospace() << " VALUE="; } if (p.oldValue().isValid()) { dbg.nospace() << " OLDVALUE=" << p.oldValue(); } if (p.isModified()) { dbg.nospace() << " MODIFIED"; } if (!p.isVisible()) { dbg.nospace() << " HIDDEN"; } //! @todo children... if (p.hasOptions()) { dbg.nospace() << " OPTIONS(" << p.d->options.count() << "): ["; QList optionKeys( p.d->options.keys() ); qSort(optionKeys); bool first = true; foreach (const QByteArray& key, optionKeys) { if (first) { first = false; } else { dbg.space() << ","; } dbg.nospace() << key << ":" << p.option(key.constData()); } dbg.nospace() << "]"; } dbg.nospace() << ")"; return dbg.space(); } diff --git a/src/KProperty.h b/src/KProperty.h index c71c1a4..6499605 100644 --- a/src/KProperty.h +++ b/src/KProperty.h @@ -1,490 +1,494 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004 Alexander Dymo Copyright (C) 2004-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_PROPERTY_H #define KPROPERTY_PROPERTY_H #include #include #include #include #include "kpropertycore_export.h" /*! \brief Namespace for a set of classes implementing generic properties framework. Main classes of this framework are: - KProperty, representing a single property with its own type and value - KPropertySet, a set of properties - KPropertyEditorView, a widget for displaying and editing properties provided by a KPropertySet object. Every property has its own row displayed within the editor view. The editor view enables editing of property values. The KProperty framework also supports adding composed and property types and custom property editor types. Take a look at the example application, available in the examples/ directory. @author Cedric Pasteur @author Alexander Dymo @author Jarosław Staniek */ class KComposedPropertyInterface; class KPropertySet; class KPropertySetPrivate; /*! Data container for properties of list type. */ class KPROPERTYCORE_EXPORT KPropertyListData { public: /*! Data container for list-value property. We will be able to choose an item from this list. */ KPropertyListData(const QStringList& keys_, const QStringList& names_); KPropertyListData(const QList keys_, const QStringList& names_); KPropertyListData(); ~KPropertyListData(); void setKeysAsStringList(const QStringList& list); QStringList keysAsStringList() const; /*! The string list containing all possible keys for this property or NULL if this is not a property of type 'list'. The values in this list are ordered, so the first key element is associated with first element from the 'names' list, and so on. */ QList keys; // QStringList keys; //! @todo what about using QValueList here too? /*! The list of translated names that will be visible on the screen. First value is referenced by first key, and so on. */ QStringList names; //unused for now /*! True (the default), if the list has fixed number of possible //unused for now items (keys). If this is false, user can add or enter own values. */ //unused for now bool fixed; }; /*! \brief The base class representing a single property KProperty object can hold a property of given type supported by QVariant. Properties of custom types can be also created, see using KPropertyFactory. Composed or custome properties are not created using subclassing of KProperty but using @ref KComposedPropertyInterface. Each property stores old value to allows undoing that reverts the value to the old one. Property has a non-empty name (a QByteArray), a caption that is user-visible translated string displayed in property editor. Description is a translatable string that can be specified too in order to further explain meaning of the property. Propery also supports setting arbitrary number of options using KProperty::setOption() that allow to customize look or behavior of the property in the editor. @code // Creating a simple property: KProperty *property = new KProperty(name, value, caption, description); // name is a QByteArray, value is whatever type QVariant supports // Creating a valueFromList property matching keys with names: QStringList keys, names; keys << "one" << "two" << "three"; // possible values of the property // Names (possibly translated) shown in the editor instead of the keys names << tr("One") << tr("Two") << tr("Three"); property = new KProperty(name, keys, names, "two", caption); // Creating a valueFromList property matching QVariant keys with names: QValueList variantKeys; variantKeys << 1 << 2 << 3; KPropertyListData *listData = new KPropertyListData(variantKeys, names); propertySet->addProperty(new KProperty("List", listData, "otheritem", "List")); @endcode @note Sometimes it makes sense to split property captions that have with more words to multiple lines using a newline character, e.g. "Allow Zero Size" to "Allow Zero\nSize". This is suitable especially for the needs of property editor which can offer only limited area. The text of property caption containing newline characters is available in its original form using KProperty::captionForDisplaying(). KProperty::caption() returns modified caption text in which the newline characters are substituted with spaces and any trailing and leading whitespace is removed. \author Cedric Pasteur \author Alexander Dymo \author Jarosław Staniek */ class KPROPERTYCORE_EXPORT KProperty { public: /*! Defines types of properties. Properties defined by plugins should have a type number >= UserDefined .*/ enum Type { //standard supported QVariant types Auto = 0x00ffffff, Invalid = QVariant::Invalid, BitArray = QVariant::BitArray, Bitmap = QVariant::Bitmap, Bool = QVariant::Bool, Brush = QVariant::Brush, ByteArray = QVariant::ByteArray, Char = QVariant::Char, Color = QVariant::Color, Cursor = QVariant::Cursor, Date = QVariant::Date, DateTime = QVariant::DateTime, Double = QVariant::Double, Font = QVariant::Font, Icon = QVariant::Icon, Image = QVariant::Image, Int = QVariant::Int, KeySequence = QVariant::KeySequence, Line = QVariant::Line, LineF = QVariant::LineF, List = QVariant::List, Locale = QVariant::Locale, LongLong = QVariant::LongLong, Map = QVariant::Map, Matrix = QVariant::Matrix, Transform = QVariant::Transform, Palette = QVariant::Palette, Pen = QVariant::Pen, Pixmap = QVariant::Pixmap, Point = QVariant::Point, PointF = QVariant::PointF, Polygon = QVariant::Polygon, Rect = QVariant::Rect, RectF = QVariant::RectF, RegExp = QVariant::RegExp, Region = QVariant::Region, Size = QVariant::Size, SizeF = QVariant::SizeF, SizePolicy = QVariant::SizePolicy, String = QVariant::String, StringList = QVariant::StringList, TextFormat = QVariant::TextFormat, TextLength = QVariant::TextLength, Time = QVariant::Time, UInt = QVariant::UInt, ULongLong = QVariant::ULongLong, Url = QVariant::Url, //predefined custom types ValueFromList = 1000 /*** children() const; /*! \return a child property for \a name, or NULL if there is no property with that name. */ KProperty* child(const QByteArray &name); /*! \return parent property for this property, or NULL if there is no parent property. */ KProperty* parent() const; /*! \return the composed property for this property, or NULL if there was no composed property defined. */ KComposedPropertyInterface* composedProperty() const; /*! Sets composed property \a prop for this property. */ void setComposedProperty(KComposedPropertyInterface *prop); /*! \return true if this property is null. Null properties have empty names. */ bool isNull() const; //! \return true if this property value is changed. bool isModified() const; //! Clears "modified" flag, so isModified() will return false. void clearModifiedFlag(); /*! \return true if the property is read-only when used in a property editor. @c false by default. The property can be read-write but still not editable for the user if the parent property set's read-only flag is set. @see KPropertySet::isReadOnly() */ bool isReadOnly() const; /*! Sets this property to be read-only. @see isReadOnly() */ void setReadOnly(bool readOnly); /*! \return true if the property is visible. Only visible properties are displayed by the property editor view. */ bool isVisible() const; /*! Sets the visibility flag.*/ void setVisible(bool visible); /*! \return true if the property can be saved to a stream, xml, etc. There is a possibility to use "GUI" properties that aren't stored but used only in a GUI.*/ bool isStorable() const; /*! Sets "storable" flag for this property. @see isStorable() */ void setStorable(bool storable); - /*! \return 1 if the property should be synced automatically in the property editor - as soon as editor contents change (e.g. when the user types text). - If autoSync() == 0, property value will be updated when the user presses Enter - or when another editor gets the focus. - Property follows property editor's global rule if autoSync() !=0 and !=1 (the default). - */ - int autoSync() const; - - /*! If \a sync is 1, the property will be synced automatically in the property editor - as soon as editor's contents change (e.g. when the user types text). - If \a sync is 0, property value will be updated when the user presses - Enter or when another editor gets the focus. - Property follows property editor's global rule if sync !=0 and !=1 (the default). - */ - void setAutoSync(int sync); + //! Synchronization policy for property values + //! @since 3.1 + enum class ValueSyncPolicy { + Editor, //!< Allow to synchronize by the property editor using its valueSync setting (default) + FocusOut, //!< Synchronize the value when focus is out of the editor widget for this property + //!< or when the user presses the Enter key + Auto //!< Synchronize automatically as soon as the editor widget for this property signals + //! (using commitData) that the value has been changed, e.g. when the user types + //! another letter in a text box + }; + + //! @return synchronization policy for property values of this property + //! @since 3.1 + ValueSyncPolicy valueSyncPolicy() const; + + //! Sets synchronization policy for property values of this property + //! See ValueSyncPolicy for details. + //! @since 3.1 + void setValueSyncPolicy(ValueSyncPolicy policy); /*! Sets value \a val for option \a name. Options are used to override default settings of individual properties. This is most visible in property editor widget. Currently supported options are:
  • min: integer value describing minimum value for properties of integer and double types. The default is 0.
  • minValueText: user-visible translated string to be displayed in editor for integer type when minimum is set for the property. @see QAbstractSpinBox::specialValueText
  • max: integer describing minimum value for properties of integer type. Default is 0xffff.
  • precision: integer value describing the number of decimals after the decimal point for double type.
  • step: integer describing the size of the step that is taken when the user hits the up or down button of editor for double type.
  • 3State: boolean value used for boolean type; if @c true, the editor becomes a combobox (instead of checkable button) and accepts the third "null" state.
  • yesName: user-visible translated string used for boolean type (both 2- and 3-state) to visually represent the "true" value. If not present, tr("Yes") is used.
  • noName: user-visible translated string used for boolean type (both 2- and 3-state) to visually represent the "false" value. If not present, tr("No") is used.
  • 3rdStateName: user-visible translated string used for boolean type (both 2- and 3-state) to visually represent the third "null" value. If not present, tr("None") is used.
  • nullName: user-visible translated string used for boolean type to display the "null" value, if and only if the property accepts two states (i.e. when "3State" option is @c false). If the "nullName" option is not set, null values are displayed as @c false.
  • extraValueAllowed: boolean value, if @c true the user is able to manually add extra values to a combobox.
  • fileMode: string value that describes what objects may select in the file dialog of the url editor:
    • "dirsOnly": only support and display directories; @see QFileDialog::ShowDirsOnly QFileDialog::Directory
    • "existingFile": only allow to select one existing file; @see QFileDialog::ExistingFile
    • Any other value: any file is supported, whether it exists or not @see QFileDialog::AnyFile
  • confirmOverwrites: boolean value, if @c true, user will be asked for confirmation of file overwriting in the url editor. @c false by default. @note The line edit does not validate the content.
  • multiLine: boolean value used for string type. If @c true, a multi-line QPlainTextEdit-based widget is used for editor; otherwise a single-line QLineEdit widget is used. @c false by default. Added in version 3.1.
*/ void setOption(const char* name, const QVariant& val); /*! @brief Returns value of given option * If the option @a name is missing and parent property is present (see parent()), * parent property is checked. If the parent property offers the option, the value * is returned. If it is not present there, @a defaultValue value is returned. * Looking at parent property is available since 3.1. * @note The lookup is performed recursively, first in parent, then grand parent, etc. * @see setOption */ QVariant option(const char* name, const QVariant& defaultValue = QVariant()) const; /*! @brief Returns @c true if at least one option is specified for this property * If there are no options defined @c true can be still returned if parent property * is present and it has at least one option specified. * Looking at parent property is available since 3.1. * @note The lookup is performed recursively, first in parent, then grand parent, etc. */ bool hasOptions() const; /*! Equivalent to setValue(const QVariant &) */ KProperty& operator= (const QVariant& val); /*! Assigns a deep copy of all attributes of \a property to this property. */ KProperty& operator= (const KProperty &property); /*! Compares two properties.*/ bool operator ==(const KProperty &prop) const; #if 0 /*! \return a key used for sorting. Usually its set by KPropertySet::addProperty() and KProperty::addChild() to a unique value, so that this property can be sorted in a property editor in original order. \see EditorItem::compare() */ int sortingKey() const; #endif private: class Private; Private * const d; friend class KPropertySet; friend class KPropertySetPrivate; friend class KPropertyBuffer; friend KPROPERTYCORE_EXPORT QDebug operator<<(QDebug dbg, const KProperty &p); }; //! qDebug() stream operator. Writes property @a p to the debug output in a nicely formatted way. KPROPERTYCORE_EXPORT QDebug operator<<(QDebug dbg, const KProperty &p); Q_DECLARE_OPERATORS_FOR_FLAGS(KProperty::ValueOptions) #endif diff --git a/src/KPropertyEditorDataModel.cpp b/src/KPropertyEditorDataModel.cpp index 471e6da..199d1be 100644 --- a/src/KPropertyEditorDataModel.cpp +++ b/src/KPropertyEditorDataModel.cpp @@ -1,295 +1,402 @@ /* This file is part of the KDE project - Copyright (C) 2008-2009 Jarosław Staniek + Copyright (C) 2008-2017 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 "KPropertyEditorDataModel.h" #include "KPropertyWidgetsFactory.h" #include "KPropertySet_p.h" #include class Q_DECL_HIDDEN KPropertyEditorDataModel::Private { public: explicit Private(KPropertySet *_set, KPropertySetIterator::Order _order = KPropertySetIterator::InsertionOrder) : set(_set), order(_order) { Q_ASSERT(set); if (!set) { kprCritical() << "KPropertyEditorDataModel requires a KPropertySet object"; } } + inline KPropertySetPrivate* set_d() { return KPropertySetPrivate::d(set); } KPropertySet *set; KProperty rootItem; + KProperty groupItem; //!< Pseudo group item used for all group items QHash indicesForNames; KPropertySetIterator::Order order; //!< order of properties + bool groupsVisible = true; }; // ------------------- //! A property selector offering functor selecting only visible properties. /*! Used e.g. in EditorDataModel::index(). */ class VisiblePropertySelector : public KPropertySelector { public: VisiblePropertySelector() {} virtual bool operator()(const KProperty& prop) const { return prop.isVisible(); } KPropertySelector* clone() const { return new VisiblePropertySelector(); } }; // ------------------- KPropertyEditorDataModel::KPropertyEditorDataModel(KPropertySet *propertySet, QObject *parent, KPropertySetIterator::Order order) : QAbstractItemModel(parent) , d(new Private(propertySet, order)) { collectIndices(); } KPropertyEditorDataModel::~KPropertyEditorDataModel() { delete d; } typedef QPair NameAndCaption; #if 0 static inline bool nameAndCaptionLessThan(const NameAndCaption &n1, const NameAndCaption &n2) { return QString::compare(n1.second, n2.second, Qt::CaseInsensitive) < 0; } #endif void KPropertyEditorDataModel::collectIndices() const { - KPropertySetIterator it(*d->set, VisiblePropertySelector()); - if (d->order == KPropertySetIterator::AlphabeticalOrder) { - it.setOrder(KPropertySetIterator::AlphabeticalOrder); - } d->indicesForNames.clear(); - for (int row = 0; it.current(); row++, ++it) { - // kprDebug() << it.current()->name() << "->" << row; - d->indicesForNames.insert( it.current()->name(), QPersistentModelIndex( createIndex(row, 0, it.current()) ) ); + if (d->groupsVisible) { + for (const QByteArray &groupName : d->set_d()->groupNames) { + const QList* propertyNames = d->set_d()->propertiesOfGroup.value(groupName); + if (!propertyNames) { + continue; + } + int row = 0; // row within the group + //! @todo Care about sorting + for (const QByteArray &propertyName : *propertyNames) { + d->indicesForNames.insert(propertyName, + QPersistentModelIndex(createIndex(row, 0, d->set_d()->property(propertyName)))); + } + } + } else { + KPropertySetIterator it(*d->set, VisiblePropertySelector()); + if (d->order == KPropertySetIterator::AlphabeticalOrder) { + it.setOrder(KPropertySetIterator::AlphabeticalOrder); + } + for (int row = 0; it.current(); row++, ++it) { // flat list + d->indicesForNames.insert(it.current()->name(), + QPersistentModelIndex( createIndex(row, 0, it.current()))); + } } } QModelIndex KPropertyEditorDataModel::indexForPropertyName(const QByteArray& propertyName) const { return (const QModelIndex &)d->indicesForNames.value(propertyName); } QModelIndex KPropertyEditorDataModel::indexForColumn(const QModelIndex& index, int column) const { if (column == 0) return index; return createIndex(index.row(), column, propertyForIndex(index)); } int KPropertyEditorDataModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 2; } QVariant KPropertyEditorDataModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); const int col = index.column(); + const KProperty *prop = propertyForIndex(index); + if (role == PropertyGroupRole) { + return prop == &d->groupItem; + } if (col == 0) { - KProperty *prop = propertyForIndex(index); - if (role == Qt::DisplayRole) { + if (prop == &d->groupItem) { + const QByteArray groupName(d->set_d()->groupNames.value(index.row())); + Q_ASSERT(!groupName.isEmpty()); + switch(role) { + case Qt::DisplayRole: + return d->set->groupCaption(groupName); + case Qt::DecorationRole: + return QIcon::fromTheme(d->set->groupIconName(groupName)); + default:; + } + } else if (role == Qt::DisplayRole) { if (!prop->caption().isEmpty()) return prop->caption(); return prop->name(); } else if (role == PropertyModifiedRole) { return prop->isModified(); } } else if (col == 1) { - KProperty *prop = propertyForIndex(index); if (role == Qt::EditRole) { return prop->value(); } else if (role == Qt::DisplayRole) { return KPropertyFactoryManager::self()->propertyValueToLocalizedString(prop); } } return QVariant(); } Qt::ItemFlags KPropertyEditorDataModel::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::ItemIsEnabled; const int col = index.column(); - Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable; - KProperty *prop = propertyForIndex(index); - if (prop) { - if (col == 1 && !prop->isReadOnly() && !d->set->isReadOnly()) { + Qt::ItemFlags f = Qt::ItemIsEnabled; + const KProperty *prop = propertyForIndex(index); + if (prop != &d->groupItem) { + f |= Qt::ItemIsSelectable; + if (col == 1 && prop != &d->rootItem && !prop->isReadOnly() && !d->set->isReadOnly()) { f |= Qt::ItemIsEditable; } } return f; } KProperty *KPropertyEditorDataModel::propertyForIndex(const QModelIndex &index) const { if (index.isValid()) { KProperty *item = static_cast(index.internalPointer()); if (item) return item; } return &d->rootItem; } QVariant KPropertyEditorDataModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { if (section == 0) { return tr("Name", "Property name"); } else { return tr("Value", "Property value"); } } return QVariant(); } QModelIndex KPropertyEditorDataModel::index(int row, int column, const QModelIndex &parent) const { - if (parent.isValid() && parent.column() != 0) + if (row < 0 || column < 0 || /*!parent.isValid() ||*/ (parent.isValid() && parent.column() != 0)) { return QModelIndex(); + } KProperty *parentItem = propertyForIndex(parent); - KProperty *childItem; - if (parentItem == &d->rootItem) { // special case: top level - int visibleRows = 0; - KPropertySetIterator it(*d->set, VisiblePropertySelector()); - if (d->order == KPropertySetIterator::AlphabeticalOrder) { - it.setOrder(KPropertySetIterator::AlphabeticalOrder); + KProperty *childItem = nullptr; + if (parentItem == &d->rootItem && d->groupsVisible && d->set_d()->hasGroups()) { + // top level with groups: return group item + return createIndex(row, column, &d->groupItem); + } else if (parentItem == &d->rootItem || parentItem == &d->groupItem) { + // top level without groups or group level: return top-level visible property item + if (d->groupsVisible && d->set_d()->hasGroups()) { + const QByteArray groupName(d->set_d()->groupNames.value(parent.row())); + const QList* propertyNames = d->set_d()->propertiesOfGroup.value(groupName); + if (propertyNames) { + int visiblePropertiesForGroup = -1; + //! @todo sort? + for (const QByteArray &propertyName : *propertyNames) { + KProperty *property = d->set_d()->property(propertyName); + if (property->isVisible()) { + ++visiblePropertiesForGroup; + } + if (visiblePropertiesForGroup == row) { + childItem = property; + break; + } + } + } + } else { // all properties, flat + KPropertySetIterator it(*d->set, VisiblePropertySelector()); + if (d->order == KPropertySetIterator::AlphabeticalOrder) { + it.setOrder(KPropertySetIterator::AlphabeticalOrder); + } + //! @todo use qBinaryFind()? + for (int visibleRows = 0; visibleRows < row && it.current(); ++it) { + ++visibleRows; + } + childItem = it.current(); } -//! @todo use qBinaryFind()? - for (; visibleRows < row && it.current(); visibleRows++, ++it) - ; - childItem = it.current(); - } else { + } else { // child properties of composed properties const QList* children = parentItem->children(); - if (!children) - return QModelIndex(); - childItem = children->value(row); + if (children) { + childItem = children->value(row); + } } - if (!childItem) + if (!childItem) { return QModelIndex(); + } return createIndex(row, column, childItem); } QModelIndex KPropertyEditorDataModel::parent(const QModelIndex &index) const { - if (!index.isValid()) + if (!index.isValid()) { return QModelIndex(); - - KProperty *childItem = propertyForIndex(index); - KProperty *parentItem = childItem->parent(); - - if (!parentItem) + } + const KProperty *childItem = propertyForIndex(index); + if (childItem == &d->rootItem || childItem == &d->groupItem) { + // parent for the root or a group item: null + // (parent for a group item is root since group item is top level) return QModelIndex(); - - const QList* children = parentItem->children(); - Q_ASSERT(children); - const int indexOfItem = children->indexOf(childItem); - Q_ASSERT(indexOfItem != -1); - - return createIndex(indexOfItem, 0, parentItem); + } + KProperty *parentItem = childItem->parent(); + if (parentItem) { // child property: parent property is the parent + // find index of parent within the grandparent + const int indexOfParentItem = d->set_d()->indexOfProperty(parentItem); + return createIndex(indexOfParentItem, 0, parentItem); + } + if (d->groupsVisible && d->set_d()->hasGroups()) { + // top-level property within a group: group item is the parent + const QByteArray group(d->set_d()->groupForProperty(childItem)); + const int indexOfGroup = d->set_d()->groupNames.indexOf(group); + return createIndex(indexOfGroup, 0, &d->groupItem); + } + return QModelIndex(); } int KPropertyEditorDataModel::rowCount(const QModelIndex &parent) const { KProperty *parentItem = propertyForIndex(parent); - if (!parentItem || parentItem == &d->rootItem) { // top level - return d->set->count(VisiblePropertySelector()); + if (parentItem == &d->rootItem) { // top level: return group count or top-level properties count + if (d->groupsVisible && d->set_d()->hasGroups()) { + return d->set_d()->groupNames.count(); + } + return d->set->count(VisiblePropertySelector()); // number of visible properties + } else if (parentItem == &d->groupItem) { // group level: return property count within the group + const QByteArray groupName = d->set_d()->groupNames.value(parent.row()); + Q_ASSERT(!groupName.isEmpty()); + const QList* propertyNames = d->set_d()->propertiesOfGroup.value(groupName); + Q_ASSERT(propertyNames); + int visiblePropertiesForGroup = 0; + for(const QByteArray &propertyName : *propertyNames) { + if (d->set_d()->property(propertyName)->isVisible()) { + ++visiblePropertiesForGroup; + } + } + return visiblePropertiesForGroup; } + // property level: return child properties count const QList* children = parentItem->children(); return children ? children->count() : 0; } bool KPropertyEditorDataModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role != Qt::EditRole) return false; KProperty *item = propertyForIndex(index); - if (item == &d->rootItem) + if (item == &d->rootItem || item == &d->groupItem) return false; item->setValue(value); //don't do that or cursor position and editor state will be reset: //emit dataChanged(index, index, {Qt::EditRole}); return true; } bool KPropertyEditorDataModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) { Q_UNUSED(section); Q_UNUSED(orientation); Q_UNUSED(value); Q_UNUSED(role); return false; } QModelIndex KPropertyEditorDataModel::buddy(const QModelIndex & idx) const { if (idx.column() == 0) return index( idx.row(), 1, parent(idx)); return idx; } KPropertySet* KPropertyEditorDataModel::propertySet() const { return d->set; } void KPropertyEditorDataModel::setOrder(KPropertySetIterator::Order order) { if (d->order != order) { d->order = order; collectIndices(); } } KPropertySetIterator::Order KPropertyEditorDataModel::order() const { return d->order; } bool KPropertyEditorDataModel::hasChildren(const QModelIndex & parent) const { KProperty *parentItem = propertyForIndex(parent); - if (!parentItem || parentItem == &d->rootItem) { // top level + if (parentItem == &d->rootItem) { // top level return d->set->hasVisibleProperties(); + } else if (parentItem == &d->groupItem) { // group level + const QByteArray groupName(d->set_d()->groupNames.value(parent.row())); + Q_ASSERT(!groupName.isEmpty()); + const QList* propertyNames = d->set_d()->propertiesOfGroup.value(groupName); + Q_ASSERT(propertyNames); + for (const QByteArray &propertyName : *propertyNames) { + if (d->set_d()->property(propertyName)->isVisible()) { + return true; // at least one visible property in this group + } + } + return false; // no visible properties in this group } + // property level const QList* children = parentItem->children(); return children && !children->isEmpty(); } + +bool KPropertyEditorDataModel::groupsVisible() const +{ + return d->groupsVisible; +} + +void KPropertyEditorDataModel::setGroupsVisible(bool set) +{ + if (d->groupsVisible == set) { + return; + } + beginResetModel(); + d->groupsVisible = set; + collectIndices(); + endResetModel(); +} diff --git a/src/KPropertyEditorDataModel.h b/src/KPropertyEditorDataModel.h index 924c23e..41f9026 100644 --- a/src/KPropertyEditorDataModel.h +++ b/src/KPropertyEditorDataModel.h @@ -1,99 +1,111 @@ /* This file is part of the KDE project - Copyright (C) 2008 Jarosław Staniek + Copyright (C) 2008-2017 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_EDITORDATAMODEL_H #define KPROPERTY_EDITORDATAMODEL_H #include "kpropertywidgets_export.h" #include "KPropertySet.h" #include #include class KProperty; /*! @short A data model that integrates a KPropertySet object with the Qt's model/view API. @see KPropertyEditorView @internal */ class KPropertyEditorDataModel : public QAbstractItemModel { Q_OBJECT - public: //! Creates a new model. @a propertySet is required. explicit KPropertyEditorDataModel(KPropertySet *propertySet, QObject *parent = 0, KPropertySetIterator::Order order = KPropertySetIterator::InsertionOrder); ~KPropertyEditorDataModel(); enum Role { - PropertyModifiedRole = Qt::UserRole + 0 + PropertyModifiedRole = Qt::UserRole + 0, + PropertyGroupRole = Qt::UserRole + 1 }; QVariant data(const QModelIndex &index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &index) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; Qt::ItemFlags flags(const QModelIndex &index) const; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole); QModelIndex buddy(const QModelIndex & index) const; //! @return property set object for this model. It is never @c nullptr. KPropertySet* propertySet() const; //! @return property object for model index @a index //! or @c nullptr for invalid index or index without a property assigned. KProperty *propertyForIndex(const QModelIndex& index) const; //! @return model index for property named @a propertyName //! or invalid index if such property could not be found. QModelIndex indexForPropertyName(const QByteArray& propertyName) const; //! @return a sibling for model index @a index and columnd @a column QModelIndex indexForColumn(const QModelIndex& index, int column) const; - //! Sets order for properties. Restarts the iterator. - void setOrder(KPropertySetIterator::Order order); - //! @return order for properties. KPropertySetIterator::Order order() const; //! Reimplemented for optimization. bool hasChildren(const QModelIndex & parent = QModelIndex()) const; + /*! @return @c true if the property groups should be visible. + @see KPropertyEditorView::groupsVisible() + @since 3.1 */ + bool groupsVisible() const; + +public Q_SLOTS: + //! Sets order for properties. + void setOrder(KPropertySetIterator::Order order); + + /*! Shows the property groups if @a set is @c true. + @see KPropertyEditorView::setGroupsVisible(bool) + @since 3.1 */ + void setGroupsVisible(bool set); + private: + //! Collects persistent indices for the model. They are dependent on groupping and sorting. void collectIndices() const; class Private; Private * const d; friend class KPropertyEditorView; }; #endif diff --git a/src/KPropertyEditorView.cpp b/src/KPropertyEditorView.cpp index 70bc47f..2b43898 100644 --- a/src/KPropertyEditorView.cpp +++ b/src/KPropertyEditorView.cpp @@ -1,623 +1,722 @@ /* This file is part of the KDE project - Copyright (C) 2008-2016 Jarosław Staniek + Copyright (C) 2008-2017 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(const KProperty *property, bool defaultAutoSync) +static bool effectiveValueSyncPolicy(const KProperty *property, bool defaultValue) { - return (property->autoSync() != 0 && property->autoSync() != 1) ? - defaultAutoSync : (property->autoSync() != 0); + if (property->valueSyncPolicy() == KProperty::ValueSyncPolicy::Editor) { + return defaultValue; + } + return property->valueSyncPolicy() == KProperty::ValueSyncPolicy::Auto; } //---------- 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(const 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); - } const KPropertyUtilsPrivate::PainterSaver saver(painter); - QRect r(option.rect); const KPropertyEditorDataModel *editorModel = qobject_cast(index.model()); if (!editorModel) { return; } + + QRect r(option.rect); bool modified = false; + const QColor gridLineColor(qobject_cast(parent())->gridLineColor()); + if (gridLineColor.isValid()) { + alteredOption.rect.setTop(alteredOption.rect.top() + 1); + } if (index.column()==0) { r.setWidth(r.width() - 1); - r.setLeft(0); + r.setLeft(-1); // to avoid displaying double left border 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); - } + const bool isGroupHeader(editorModel->data(index, KPropertyEditorDataModel::PropertyGroupRole).toBool()); + if (!isGroupHeader) { + 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 (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); + + //!TODO + //QPixmap revertIcon(QIcon::fromTheme(QLatin1String("edit-undo")).pixmap(iconSize, iconSize)); + //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); + painter->drawLine(r.topLeft(), r.topRight() + QPoint(1, 0)); + painter->drawLine(r.bottomLeft() + QPoint(0, 1), r.bottomRight() + QPoint(1, 1)); + if (!isGroupHeader) { + painter->drawLine(r.topRight() + QPoint(1, 0), r.bottomRight() + QPoint(1, 1)); + painter->drawLine(r.topLeft(), r.bottomLeft() + QPoint(0, 1)); + } } 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(); } 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; const KProperty *property = KPropertyUtils::propertyForIndex(index); if (property && property->isReadOnly()) { return nullptr; } const int t = property ? typeForProperty(property) : KProperty::String; QStyleOptionViewItem alteredOption(option); 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() )) { + if (property && effectiveValueSyncPolicy(property, + qobject_cast(this->parent())->isValueSyncEnabled())) + { QObject::connect(w, SIGNAL(commitData(QWidget*)), this, SIGNAL(commitData(QWidget*))); } m_currentEditor = w; return w; } //---------- class Q_DECL_HIDDEN KPropertyEditorView::Private { public: - Private() + explicit Private(KPropertyEditorView *view) : set(0) , model(0) , gridLineColor( KPropertyEditorView::defaultGridLineColor() ) - , autoSync(true) + , valueSync(true) , slotPropertyChangedEnabled(true) + , q(view) { } + + //! Expands group and parent propertiey items if needed (based on settings) + void expandIfNeeded() { + const int rowCount = model->rowCount(); + for (int row = 0; row < rowCount; row++) { + expandChildItemsIfNeeded(model->index(row, 0)); + } + } + + //! Expands property child items in a subtree recursively if needed (based on settings) + void expandChildItemsIfNeeded(const QModelIndex &parent) { + const bool isGroupHeader(model->data(parent, KPropertyEditorDataModel::PropertyGroupRole).toBool()); + if (isGroupHeader) { + if (groupItemsExpanded) { + q->expand(parent); + } + } else { + if (childPropertyItemsExpanded) { + q->expand(parent); + } + } + const int rowCount = model->rowCount(parent); + for (int row = 0; row < rowCount; row++) { + const QModelIndex child(model->index(row, 0, parent)); + expandChildItemsIfNeeded(child); + } + } + KPropertySet *set; KPropertyEditorDataModel *model; ItemDelegate *itemDelegate; QColor gridLineColor; - bool autoSync; + bool valueSync; bool slotPropertyChangedEnabled; + bool childPropertyItemsExpanded = true; + bool groupItemsExpanded = true; + +private: + KPropertyEditorView * const q; }; KPropertyEditorView::KPropertyEditorView(QWidget* parent) : QTreeView(parent) - , d( new Private ) + , d(new Private(this)) { 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 KProperty *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())); connect(d->set, &KPropertySet::readOnlyFlagChanged, this, &KPropertyEditorView::slotReadOnlyFlagChanged); } 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) ); - } + if (d->model && d->set && !d->set->isEmpty()) { + d->expandIfNeeded(); } 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::slotReadOnlyFlagChanged() { const QModelIndex index = currentIndex(); setCurrentIndex(QModelIndex()); if (index.isValid()) { selectionModel()->select(index, QItemSelectionModel::Select); setCurrentIndex(index); } } -void KPropertyEditorView::setAutoSync(bool enable) +void KPropertyEditorView::setValueSyncEnabled(bool set) +{ + d->valueSync = set; +} + +bool KPropertyEditorView::isValueSyncEnabled() const +{ + return d->valueSync; +} + +void KPropertyEditorView::setChildPropertyItemsExpanded(bool set) +{ + d->childPropertyItemsExpanded = set; +} + +bool KPropertyEditorView::childPropertyItemsExpanded() const { - d->autoSync = enable; + return d->childPropertyItemsExpanded; } -bool KPropertyEditorView::isAutoSync() const +void KPropertyEditorView::setGroupItemsExpanded(bool set) { - return d->autoSync; + d->groupItemsExpanded = set; +} + +bool KPropertyEditorView::groupItemsExpanded() const +{ + return d->groupItemsExpanded; +} + +bool KPropertyEditorView::groupsVisible() const +{ + return d->model->groupsVisible(); +} + +void KPropertyEditorView::setGroupsVisible(bool set) +{ + if (d->model->groupsVisible() == set) { + return; + } + d->model->setGroupsVisible(set); + d->expandIfNeeded(); + viewport()->update(); } 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; if (!d->set || d->set->isReadOnly()) { result = false; } else { result = QTreeView::edit(index, trigger, event); } if (result) { QLineEdit *lineEditEditor = qobject_cast(d->itemDelegate->m_currentEditor.data()); 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 ); } +void KPropertyEditorView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + const KPropertyUtilsPrivate::PainterSaver saver(painter); + const bool isGroupHeader(d->model->data(index, KPropertyEditorDataModel::PropertyGroupRole).toBool()); + QStyleOptionViewItem alteredOption(option); + QTreeView::drawRow(painter, alteredOption, index); + if (isGroupHeader) { + // Special case: group header should be displayed over both columns. There's an issue with + // alternate background which is painted over text in the 2nd column, so draw the text here + // by hand. + QFont font(alteredOption.font); + font.setBold(true); + alteredOption.font = font; + painter->setFont(font); + painter->drawText( + alteredOption.rect.adjusted(style()->pixelMetric(QStyle::PM_TreeViewIndentation), 0, 0, 0), + index.data(Qt::DisplayRole).toString(), Qt::AlignLeft | Qt::AlignVCenter); + } +} + 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)); r.setLeft(x1); r.setRight(x2); 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 )) + if (effectiveValueSyncPolicy(property, d->valueSync)) { 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/KPropertyEditorView.h b/src/KPropertyEditorView.h index e1973f3..90402d9 100644 --- a/src/KPropertyEditorView.h +++ b/src/KPropertyEditorView.h @@ -1,148 +1,205 @@ /* This file is part of the KDE project - Copyright (C) 2008-2016 Jarosław Staniek + Copyright (C) 2008-2017 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_EDITORVIEW_H #define KPROPERTY_EDITORVIEW_H #include "kpropertywidgets_export.h" #include class KProperty; class KPropertySet; //! @brief A widget for editing properties class KPROPERTYWIDGETS_EXPORT KPropertyEditorView : public QTreeView { Q_OBJECT public: /*! Creates an empty property editor with @a parent as parent widget. */ explicit KPropertyEditorView(QWidget *parent = 0); ~KPropertyEditorView(); //! Options for changeSet(). enum SetOption { NoOptions = 0, PreservePreviousSelection = 1, //!< If used, previously selected editor item //!< will be kept selected. - AlphabeticalOrder = 2, //!< Alphabetical order of properties (the default is insert-order) - ExpandChildItems = 4 //!< Child property items are expanded (the default is "collapsed") + AlphabeticalOrder = 2 //!< Alphabetical order of properties (the default is insert-order) }; Q_DECLARE_FLAGS(SetOptions, SetOption) //! @return grid line color, defaultGridLineColor() by default QColor gridLineColor() const; //! @return default grid line color - Qt::gray static QColor defaultGridLineColor() { return Qt::gray; } //! Reimplemented to suggest widget size that is based on number of property items. QSize sizeHint() const Q_DECL_OVERRIDE; //! @return the property set object that is assigned to this view or nullptr is no set //! is currently assigned. KPropertySet* propertySet() const; + /*! @return @c true if items for parent composed properties are expanded so items for child + properties are displayed. + @since 3.1 */ + bool childPropertyItemsExpanded() const; + + /*! @return value of the valueSyncEnabled flag. + @since 3.1 */ + bool isValueSyncEnabled() const; + + /*! @return @c true if the property groups should be visible. + By default groups are visible. + A group is visualized as a subtree displaying group caption and group icon at its root node + (see KProperty::groupCaption and KProperty::groupIconName) and properties as children of this node. + A property is assigned to a group while KPropertySet::addProperty() is called. + + @note Regardless of this flag, no groups are displayed if there is only the default group + "common". + + When the group visibility flag is off or only the "common" group is present, all properties + are displayed on the same (top) level. + @since 3.1 */ + bool groupsVisible() const; + + /*! @return @c true if group items for newly added groups are exapanded so properties for these + groups are displayed. + @see setGroupItemsExpanded() + @since 3.1 */ + bool groupItemsExpanded() const; + public Q_SLOTS: - /*! Populates the editor view with items for each property from the @ set set. + /*! Populates the editor view with items for each property from the @a set set. Child items for composed properties are also created. See SetOption documentation for description of @a options options. If @a preservePreviousSelection is true, previously selected editor item will be kept selected, if present. */ void changeSet(KPropertySet *set, SetOptions options = NoOptions); - /*! Populates the editor view with items for each property from the @ set set. + /*! Populates the editor view with items for each property from the @a set set. Child items for composed properties are also created. If @a propertyToSelect is provided, item for this property name will be selected, if present. */ void changeSet(KPropertySet *set, const QByteArray& propertyToSelect, SetOptions options = NoOptions); - /*! If @a enable is true (the default), property values are automatically synced as + /*! If @a set is @c true (the default), items for parent composed properties are expanded + so items for child properties are displayed. + If @a set is @c false, the items are collapsed. + @note Appearance of the existing child items is not altered. This method can be typically called + before a changeSet() call or before adding properties. + @note Expansion of group items is not affected by this method. Use setGroupItemsExpanded() + to control expansion of group items. + @note To expand all items use expandAll(). To collapse all items use collapseAll(). + @since 3.1 */ + void setChildPropertyItemsExpanded(bool set); + + /*! If @a set is @c true (the default), property values are automatically synchronized as soon as editor contents change (e.g. every time the user types a character) - and the values are written back to the assigned property set. - If @a enable is false, property set is updated only when selection within - the property editor or user presses Enter/Return key. - Each property can overwrite this setting by changing its own autoSync flag. - */ - void setAutoSync(bool enable); - - /*! @return value of autoSync flag. */ - bool isAutoSync() const; + and the values are saved back to the assigned property set. + If @a enable is false, property set is updated only when selection within the property editor + or user presses Enter/Return key. + Each property can override this policy by changing its own valueSyncPolicy flag. + @see KProperty::setValueSyncPolicy() + @since 3.1 */ + void setValueSyncEnabled(bool set); /*! Accepts the changes made to the current editor item (if any) (as if the user had pressed Enter key). */ void acceptInput(); //! Sets color of grid lines. Use invalid color QColor() to hide grid lines. void setGridLineColor(const QColor& color); + /*! Shows the property groups if @a set is @c true. + @see groupsVisible() + @since 3.1 */ + void setGroupsVisible(bool set); + + /*! If @a set is @c true (the default), group items for newly added groups are exapanded + so properties for these groups are displayed. + If @a set is @c false, the items are collapsed. + @note Appearance of the existing group items is not altered. This method can be typically called + before a changeSet() call or before adding properties. + @note Expansion of child items for composed properties is not affected by this method. + Use setChildPropertyItemsExpanded() to control expansion child items for composed properties. + @note To expand all items use expandAll(). To collapse all items use collapseAll(). + @since 3.1 */ + void setGroupItemsExpanded(bool set); + Q_SIGNALS: /*! Emitted when current property set has been changed. May be 0. */ void propertySetChanged(KPropertySet *set); protected: virtual bool viewportEvent( QEvent * event ); protected Q_SLOTS: virtual void currentChanged( const QModelIndex & current, const QModelIndex & previous ); virtual void commitData( QWidget * editor ); /*! Called when current propertis of this set are about to be cleared. */ void slotSetWillBeCleared(); /*! Called when current property set is about to be destroyed. */ void slotSetWillBeDeleted(); /*! Called when property set's read-only flag has changed. Refreshes selection so editor is displayed again if needed. */ void slotReadOnlyFlagChanged(); /*! Updates editor widget in the editor.*/ void slotPropertyChanged(KPropertySet& set, KProperty& property); void slotPropertyReset(KPropertySet& set, KProperty& property); private: /*! Used by changeSet(). */ void changeSetInternal(KPropertySet *set, SetOptions options, const QByteArray& propertyToSelect); virtual bool edit( const QModelIndex & index, EditTrigger trigger, QEvent * event ); virtual void drawBranches( QPainter * painter, const QRect & rect, const QModelIndex & index ) const; + + //! Reimplemented to draw group header text by hand. + void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + virtual void mousePressEvent( QMouseEvent * event ); //! @return true if @a x is within the area of the revert button for @a index index. bool withinRevertButtonArea( int x, const QModelIndex& index ) const; //! @return area of revert button, if it is displayed for @a index index. //! Otherwise invalid QRect is returned. QRect revertButtonArea( const QModelIndex& index ) const; //! Updates item for @a index and all its children. void updateSubtree(const QModelIndex &index); /*! Undoes the last change in the property editor.*/ void undo(); class Private; Private * const d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(KPropertyEditorView::SetOptions) #endif diff --git a/src/KPropertyLineStyleSelector_p.h b/src/KPropertyLineStyleSelector_p.h index 818c825..60cdaab 100644 --- a/src/KPropertyLineStyleSelector_p.h +++ b/src/KPropertyLineStyleSelector_p.h @@ -1,73 +1,74 @@ /* 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. */ #ifndef KPROPERTYLINESTYLESELECTOR_H #define KPROPERTYLINESTYLESELECTOR_H #include "kpropertywidgets_export.h" #include /** * A custom combobox widget for selecting line styles. */ class KPROPERTYWIDGETS_EXPORT KPropertyLineStyleSelector : public QComboBox { Q_OBJECT public: explicit KPropertyLineStyleSelector(QWidget *parent = 0); virtual ~KPropertyLineStyleSelector(); + //! @return the current line style + Qt::PenStyle lineStyle() const; + + //! @return the dashes of the current line style + QVector lineDashes() const; + +public Q_SLOTS: /** * Adds a new line style to the combobox. * * If the style already exists, it is not added to the selector. * * @param style the line style to add * @return true if style is unique among the existing styles and was added, else false */ bool addCustomStyle(const QVector &style); /** * Selects the specified style. * * If the style was already added it gets selected. If the style was not added already * it gets temporary added and selected. * * @param style the style to display * @param dashes the dashes of the style if style == Qt::CustomDashLine */ void setLineStyle(Qt::PenStyle style, const QVector &dashes = QVector()); - //! @return the current line style - Qt::PenStyle lineStyle() const; - - //! @return the dashes of the current line style - QVector lineDashes() const; - protected: void paintEvent(QPaintEvent *pe); private: class Private; Private * const d; }; #endif diff --git a/src/KPropertySet.cpp b/src/KPropertySet.cpp index ae43346..54be58f 100644 --- a/src/KPropertySet.cpp +++ b/src/KPropertySet.cpp @@ -1,644 +1,679 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004 Alexander Dymo - Copyright (C) 2004-2009 Jarosław Staniek + Copyright (C) 2004-2017 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 "KPropertySet.h" #include "KPropertySet_p.h" #include "KProperty_p.h" #include KPropertySetPrivate::KPropertySetPrivate(KPropertySet *set) : q(set) { groupCaptions.insert("common", QObject::tr("General", "General properties")); } KPropertySetPrivate::~KPropertySetPrivate() { } void KPropertySetPrivate::addProperty(KProperty *property, const QByteArray &group/*, bool updateSortingKey*/) { if (!property) { kprWarning() << "property == 0"; return; } if (property->isNull()) { kprWarning() << "COULD NOT ADD NULL PROPERTY"; return; } const QByteArray realGroup(group.isEmpty() ? "common" : group); KProperty *p = this->property(property->name()); if (p) { addRelatedProperty(p, property); } else { list.append(property); hash.insert(property->name().toLower(), property); if (property->isVisible()) { m_visiblePropertiesCount++; } addToGroup(realGroup, property); } property->d->addSet(q); #if 0 if (updateSortingKey) property->setSortingKey(count()); #endif } void KPropertySetPrivate::removeProperty(KProperty *property) { if (!property) return; if (!list.removeOne(property)) { kprDebug() << "The property set does not contain property" << property; return; } KProperty *p = hash.take(property->name().toLower()); if (p) { removeFromGroup(p); if (p->isVisible()) { m_visiblePropertiesCount--; } if (ownProperty) { emit q->aboutToDeleteProperty(*q, *p); delete p; } } } void KPropertySetPrivate::clear() { if (m_informAboutClearing) { *m_informAboutClearing = true; } m_informAboutClearing = nullptr; emit q->aboutToBeCleared(); m_visiblePropertiesCount = 0; qDeleteAll(propertiesOfGroup); propertiesOfGroup.clear(); groupNames.clear(); groupForProperties.clear(); groupCaptions.clear(); groupIconNames.clear(); qDeleteAll(list); list.clear(); hash.clear(); } void KPropertySetPrivate::copyAttributesFrom(const KPropertySetPrivate &other) { KPropertySet *origSet = q; *this = other; q = origSet; // do not copy too deeply list.clear(); hash.clear(); propertiesOfGroup.clear(); groupForProperties.clear(); m_visiblePropertiesCount = 0; m_informAboutClearing = nullptr; } void KPropertySetPrivate::copyPropertiesFrom( const QList::ConstIterator& constBegin, const QList::ConstIterator& constEnd, const KPropertySet & set) { for (QList::ConstIterator it(constBegin); it!=constEnd; ++it) { KProperty *prop = new KProperty(*(*it)); addProperty(prop, set.d->groupForProperty( *it ) #if 0 , false /* don't updateSortingKey, because the key is already set in KProperty copy ctor.*/ #endif ); } } void KPropertySetPrivate::addToGroup(const QByteArray &group, KProperty *property) { if (!property || group.isEmpty()) { return; } //do not add the same property to the group twice const QByteArray groupLower(group.toLower()); if (groupForProperty(property) == groupLower) { kprWarning() << "Group" << group << "already contains property" << property->name(); return; } QList* propertiesOfGroup = this->propertiesOfGroup.value(groupLower); if (!propertiesOfGroup) { propertiesOfGroup = new QList(); this->propertiesOfGroup.insert(groupLower, propertiesOfGroup); groupNames.append(groupLower); } propertiesOfGroup->append(property->name()); addPropertyToGroup(property, groupLower); } void KPropertySetPrivate::removeFromGroup(KProperty *property) { if (!property) { return; } const QByteArray group(groupForProperty(property)); if (group.isEmpty()) { return; } QList* propertiesOfGroup = this->propertiesOfGroup.value(group); if (propertiesOfGroup) { propertiesOfGroup->removeAt(propertiesOfGroup->indexOf(property->name())); if (propertiesOfGroup->isEmpty()) { //remove group as well this->propertiesOfGroup.take(group); delete propertiesOfGroup; const int i = groupNames.indexOf(group); if (i != -1) { groupNames.removeAt(i); } } } removePropertyFromGroup(property); } +bool KPropertySetPrivate::hasGroups() const +{ + return groupNames.count() > 1 || (groupNames.count() == 1 && groupNames.first() != "common"); +} + void KPropertySetPrivate::informAboutClearing(bool* cleared) { Q_ASSERT(cleared); *cleared = false; m_informAboutClearing = cleared; } void KPropertySetPrivate::addRelatedProperty(KProperty *p1, KProperty *p2) const { p1->d->addRelatedProperty(p2); } +int KPropertySetPrivate::indexOfProperty(const KProperty *property) const +{ + KProperty *parentProperty = property->parent(); + if (parentProperty) { + const QList* children = parentProperty->children(); + Q_ASSERT(children); + const int index = children->indexOf(parentProperty); + Q_ASSERT(index != -1); + return index; + } + return indexOfPropertyInGroup(property); +} + +int KPropertySetPrivate::indexOfPropertyInGroup(const KProperty *property) const +{ + const QByteArray group(groupForProperties.value(const_cast(property))); + QList* propertiesOfGroup = this->propertiesOfGroup.value(group); + if (!propertiesOfGroup) { + return -1; + } + return propertiesOfGroup->indexOf(property->name()); +} + ////////////////////////////////////////////// KPropertySelector::KPropertySelector() { } KPropertySelector::~KPropertySelector() { } ////////////////////////////////////////////// typedef QPair Iterator_PropertyAndString; static inline bool Iterator_propertyAndStringLessThan( const Iterator_PropertyAndString &n1, const Iterator_PropertyAndString &n2) { return QString::compare(n1.second, n2.second, Qt::CaseInsensitive) < 0; } ////////////////////////////////////////////// KPropertySetIterator::KPropertySetIterator(const KPropertySet &set) : m_set(&set) , m_iterator(KPropertySetPrivate::d(&set)->listConstIterator()) , m_end(KPropertySetPrivate::d(&set)->listConstEnd() ) , m_selector( 0 ) , m_order(KPropertySetIterator::InsertionOrder) { } KPropertySetIterator::KPropertySetIterator(const KPropertySet &set, const KPropertySelector& selector) : m_set(&set) , m_iterator(KPropertySetPrivate::d(&set)->listConstIterator()) , m_end(KPropertySetPrivate::d(&set)->listConstEnd()) , m_selector( selector.clone() ) , m_order(KPropertySetIterator::InsertionOrder) { skipNotAcceptable(); } KPropertySetIterator::~KPropertySetIterator() { delete m_selector; } void KPropertySetIterator::skipNotAcceptable() { if (!m_selector) return; //kprDebug() << "FROM:" << *current(); if (current() && !(*m_selector)( *current() )) { // skip first items that not are acceptable by the selector ++(*this); } //kprDebug() << "TO:" << *current(); } void KPropertySetIterator::setOrder(KPropertySetIterator::Order order) { if (m_order == order) return; m_order = order; switch (m_order) { case KPropertySetIterator::AlphabeticalOrder: case KPropertySetIterator::AlphabeticalByName: { QList propertiesAndStrings; m_iterator = KPropertySetPrivate::d(m_set)->listConstIterator(); m_end = KPropertySetPrivate::d(m_set)->listConstEnd(); for (; m_iterator!=m_end; ++m_iterator) { KProperty *prop = *m_iterator; QString captionOrName; if (m_order == KPropertySetIterator::AlphabeticalOrder) { captionOrName = prop->caption(); } if (captionOrName.isEmpty()) { captionOrName = QLatin1String(prop->name()); } propertiesAndStrings.append( qMakePair(prop, captionOrName) ); } qSort(propertiesAndStrings.begin(), propertiesAndStrings.end(), Iterator_propertyAndStringLessThan); m_sorted.clear(); foreach (const Iterator_PropertyAndString& propertyAndString, propertiesAndStrings) { m_sorted.append(propertyAndString.first); } // restart the iterator m_iterator = m_sorted.constBegin(); m_end = m_sorted.constEnd(); break; } default: m_sorted.clear(); // restart the iterator m_iterator = KPropertySetPrivate::d(m_set)->listConstIterator(); m_end = KPropertySetPrivate::d(m_set)->listConstEnd(); } skipNotAcceptable(); } void KPropertySetIterator::operator ++() { while (true) { ++m_iterator; if (!m_selector) return; // selector exists if (!current()) // end encountered return; if ((*m_selector)( *current() )) return; } } ////////////////////////////////////////////// KPropertySet::KPropertySet(QObject *parent) : QObject(parent) , d(new KPropertySetPrivate(this)) { d->ownProperty = true; } KPropertySet::KPropertySet(const KPropertySet &set) : QObject(0 /* implicit sharing the parent is dangerous */) , d(new KPropertySetPrivate(this)) { setObjectName(set.objectName()); *this = set; } KPropertySet::KPropertySet(bool propertyOwner) : QObject(0) , d(new KPropertySetPrivate(this)) { d->ownProperty = propertyOwner; } KPropertySet::~KPropertySet() { emit aboutToBeCleared(); emit aboutToBeDeleted(); clear(); delete d; } ///////////////////////////////////////////////////// void KPropertySet::addProperty(KProperty *property, const QByteArray &group) { d->addProperty(property, group); } void KPropertySet::removeProperty(KProperty *property) { d->removeProperty(property); } void KPropertySet::removeProperty(const QByteArray &name) { KProperty *p = d->property(name); removeProperty(p); } void KPropertySet::clear() { d->clear(); } ///////////////////////////////////////////////////// QList KPropertySet::groupNames() const { return d->groupNames; } QList KPropertySet::propertyNamesForGroup(const QByteArray &group) const { QList* propertiesOfGroup = d->propertiesOfGroup.value(group); return propertiesOfGroup ? *propertiesOfGroup : QList(); } void KPropertySet::setGroupCaption(const QByteArray &group, const QString &caption) { d->groupCaptions.insert(group.toLower(), caption); } QString KPropertySet::groupCaption(const QByteArray &group) const { const QString result(d->groupCaptions.value(group.toLower())); if (!result.isEmpty()) return result; return QLatin1String(group); } void KPropertySet::setGroupIconName(const QByteArray &group, const QString& iconName) { d->groupIconNames.insert(group.toLower(), iconName); } QString KPropertySet::groupIconName(const QByteArray &group) const { return d->groupIconNames.value(group); } ///////////////////////////////////////////////////// uint KPropertySet::count() const { return d->count(); } uint KPropertySet::count(const KPropertySelector& selector) const { uint result = 0; for (KPropertySetIterator it(*this, selector); it.current(); ++it, result++) ; return result; } bool KPropertySet::isEmpty() const { return d->isEmpty(); } bool KPropertySet::hasVisibleProperties() const { return d->visiblePropertiesCount() > 0; } bool KPropertySet::hasProperties(const KPropertySelector& selector) const { KPropertySetIterator it(*this, selector); return it.current(); } bool KPropertySet::isReadOnly() const { return d->readOnly; } void KPropertySet::setReadOnly(bool readOnly) { if (d->readOnly != readOnly) { d->readOnly = readOnly; emit readOnlyFlagChanged(); } } bool KPropertySet::contains(const QByteArray &name) const { return d->property(name); } KProperty& KPropertySet::property(const QByteArray &name) const { return d->propertyOrNull(name); } +void KPropertySet::changePropertyIfExists(const QByteArray &property, const QVariant &value) +{ + if (contains(property)) { + changeProperty(property, value); + } +} + KProperty& KPropertySet::operator[](const QByteArray &name) const { return d->propertyOrNull(name); } KPropertySet& KPropertySet::operator= (const KPropertySet & set) { if (&set == this) return *this; clear(); d->copyAttributesFrom(*set.d); d->copyPropertiesFrom(set.d->listConstIterator(), set.d->listConstEnd(), set); return *this; } QVariant KPropertySet::propertyValue(const QByteArray &name, const QVariant& defaultValue) const { const KProperty *p = d->property(name); return p ? p->value() : defaultValue; } void KPropertySet::changeProperty(const QByteArray &property, const QVariant &value) { KProperty *p = d->property(property); if (p) p->setValue(value); } void KPropertySet::debug() const { kprDebug() << *this; } KPROPERTYCORE_EXPORT QDebug operator<<(QDebug dbg, const KPropertySet &set) { dbg.nospace() << "KPropertySet("; if (set.isEmpty()) { dbg.space() << ")"; return dbg.space(); } dbg.nospace() << " PROPERTIES(" << set.count() << "):\n"; KPropertySetIterator it(set); it.setOrder(KPropertySetIterator::AlphabeticalByName); bool first = true; for ( ; it.current(); ++it) { if (first) { first = false; } else { dbg.nospace() << "\n"; } dbg.nospace() << *it.current(); } dbg.nospace() << "\n)"; return dbg.space(); } QByteArray KPropertySet::previousSelection() const { return d->prevSelection; } void KPropertySet::setPreviousSelection(const QByteArray &prevSelection) { d->prevSelection = prevSelection; } QMap KPropertySet::propertyValues() const { QMap result; for (KPropertySetIterator it(*this); it.current(); ++it) { result.insert(it.current()->name(), it.current()->value()); } return result; } ///////////////////////////////////////////////////// KPropertyBuffer::KPropertyBuffer() : KPropertySet(false) { connect(this, SIGNAL(propertyChanged(KPropertySet&,KProperty&)), this, SLOT(intersectedChanged(KPropertySet&,KProperty&))); connect(this, SIGNAL(propertyReset(KPropertySet&,KProperty&)), this, SLOT(intersectedReset(KPropertySet&,KProperty&))); } KPropertyBuffer::KPropertyBuffer(const KPropertySet& set) : KPropertySet(false) { connect(this, SIGNAL(propertyChanged(KPropertySet&,KProperty&)), this, SLOT(intersectedChanged(KPropertySet&,KProperty&))); connect(this, SIGNAL(propertyReset(KPropertySet&,KProperty&)), this, SLOT(intersectedReset(KPropertySet&,KProperty&))); init(set); } void KPropertyBuffer::init(const KPropertySet& set) { //deep copy of set const QList::ConstIterator itEnd(KPropertySetPrivate::d(&set)->listConstEnd()); for (QList::ConstIterator it(KPropertySetPrivate::d(&set)->listConstIterator()); it!=itEnd; ++it) { KProperty *prop = new KProperty(*(*it)); QByteArray group = KPropertySetPrivate::d(&set)->groupForProperty(*it); const QString groupCaption = set.groupCaption(group); setGroupCaption(group, groupCaption); addProperty(prop, group); prop->d->addRelatedProperty(*it); } } void KPropertyBuffer::intersect(const KPropertySet& set) { if (isEmpty()) { init(set); return; } const QList::ConstIterator itEnd(KPropertySetPrivate::d(&set)->listConstEnd()); for (QList::ConstIterator it(KPropertySetPrivate::d(&set)->listConstIterator()); it!=itEnd; ++it) { const QByteArray key( (*it)->name() ); KProperty *property = KPropertySetPrivate::d(&set)->property( key ); if (property) { blockSignals(true); (*it)->resetValue(); (*it)->d->addRelatedProperty(property); blockSignals(false); } else { removeProperty(key); } } } void KPropertyBuffer::intersectedChanged(KPropertySet& set, KProperty& prop) { Q_UNUSED(set); if (!contains(prop.name())) return; const QList *props = prop.d->relatedProperties; for (QList::ConstIterator it = props->constBegin(); it != props->constEnd(); ++it) { (*it)->setValue(prop.value(), false); } } void KPropertyBuffer::intersectedReset(KPropertySet& set, KProperty& prop) { Q_UNUSED(set); if (!contains(prop.name())) return; const QList *props = prop.d->relatedProperties; for (QList::ConstIterator it = props->constBegin(); it != props->constEnd(); ++it) { (*it)->setValue(prop.value(), false); } } diff --git a/src/KPropertySet.h b/src/KPropertySet.h index 403263e..974077c 100644 --- a/src/KPropertySet.h +++ b/src/KPropertySet.h @@ -1,315 +1,314 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004 Alexander Dymo Copyright (C) 2004-2009 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_SET_H #define KPROPERTY_SET_H #include #include #include #include "KProperty.h" class KPropertySetPrivate; //! An interface for functor selecting properties. /*! Used in Iterator. */ class KPROPERTYCORE_EXPORT KPropertySelector { public: KPropertySelector(); virtual ~KPropertySelector(); //! An operator implementing the functor. virtual bool operator()(const KProperty& prop) const = 0; //! Creates a deep copy of the selector. //! Required for proper usage of the selector. virtual KPropertySelector* clone() const = 0; }; //! A class to iterate over a KPropertySet. /*! It behaves like a QList::ConstIterator. Usage: @code for (KPropertySetIterator it(set); it.current(); ++it) { .... } @endcode Usage with selector: @code for (KPropertySetIterator it(set, MySelector()); it.current(); ++it) { .... } @endcode */ class KPROPERTYCORE_EXPORT KPropertySetIterator { public: //! Creates iterator for @a set set of properties. /*! The properties are sorted by insertion order by default. Use setOrder(Iterator::Alphabetical) to have alphabetical order. */ explicit KPropertySetIterator(const KPropertySet &set); //! Creates iterator for @a set set of properties. /*! @a selector functor is used to iterate only over specified properties. The properties are sorted by insertion order by default. Use setOrder(Iterator::Alphabetical) to have alphabetical order. */ KPropertySetIterator(const KPropertySet &set, const KPropertySelector& selector); ~KPropertySetIterator(); //! Ordering options for properties /*! @see setOrder() */ enum Order { InsertionOrder, //!< insertion order AlphabeticalOrder, //!< alphabetical order (case-insensitively by captions) AlphabeticalByName //!< alphabetical order (case-insensitively by name) }; //! Sets order for properties. Restarts the iterator. void setOrder(Order order); //! @return order for properties. Order order() const { return m_order; } void operator ++(); KProperty* operator *() const { return current(); } KProperty* current() const { return m_iterator==m_end ? 0 : *m_iterator; } friend class KPropertySet; private: void skipNotAcceptable(); const KPropertySet *m_set; QList::ConstIterator m_iterator; QList::ConstIterator m_end; KPropertySelector *m_selector; Order m_order; QList m_sorted; //!< for sorted order }; /*! \brief Set of properties \author Cedric Pasteur \author Alexander Dymo \author Jarosław Staniek */ class KPROPERTYCORE_EXPORT KPropertySet : public QObject { Q_OBJECT - public: //! Constructs a new property set object. explicit KPropertySet(QObject *parent = 0); /*! Constructs a deep copy of \a set. The new object will not have a QObject parent even if \a set has such parent. */ explicit KPropertySet(const KPropertySet& set); virtual ~KPropertySet(); - /*! Adds the property to the set, in the group. - The property becomes owned by the set. - Any name can be used for the @a group. "common" is the default for a basic top-level group. */ - void addProperty(KProperty *property, const QByteArray &group = "common"); - - /*! Removes property from the set and deletes the object. - Emits aboutToDeleteProperty before removing. */ - void removeProperty(KProperty *property); - - /*! Removes property with the given name from the set and deletes the object. - Emits aboutToDeleteProperty() before removing.*/ - void removeProperty(const QByteArray &name); - - /*! Removes all property objects from the property set and deletes them. */ - void clear(); - /*! @return the number of top-level properties in the set. */ uint count() const; /*! @return the number of top-level properties in the set matching criteria defined by @a selector. */ uint count(const KPropertySelector& selector) const; /*! @return true if the set is empty, i.e. count() is 0; otherwise returns false. */ bool isEmpty() const; /*! @return true if the set is contains visible properties. */ bool hasVisibleProperties() const; /*! @return true if the set is contains properties matching criteria defined by @a selector. */ bool hasProperties(const KPropertySelector& selector) const; /*! \return true if the set is read-only when used in a property editor. @c false by default. In a read-only property set no property can be modified by the user regardless of read-only flag of any property (KProperty::isReadOnly()). On the other hand if KProperty::isReadOnly() is @c true and KPropertySet::isReadOnly() is @c false, the property is still read-only. Read-only property set prevents editing in the property editor but it is still possible to change value or other parameters of property programatically using KProperty::setValue(), KProperty::resetValue(), etc. */ bool isReadOnly() const; - /*! Sets this set to be read-only. - @see isReadOnly */ - void setReadOnly(bool readOnly); - /*! \return true if the set contains property names \a name. */ bool contains(const QByteArray &name) const; /*! \return property named with \a name. If no such property is found, null property (KProperty()) is returned. */ KProperty& property(const QByteArray &name) const; /*! Accesses a property by name. A property reference is returned, so all property modifications are allowed. If there is no such property, null property (KProperty()) is returned, so it's good practice to use contains() if it's not known if the property exists. For example to set a value of a property, use: @code KPropertySet set; ... if (!set.contains("myProperty")) { dosomething; } set["myProperty"].setValue("My Value"); @endcode @return \ref Property with given name. @see changeProperty(const QByteArray &, const QVariant &) @see changePropertyIfExists(const QByteArray &, const QVariant &) */ KProperty& operator[](const QByteArray &name) const; /*! @return value for property named with @a name. If no such property is found, default value @a defaultValue is returned. */ QVariant propertyValue(const QByteArray &name, const QVariant& defaultValue = QVariant()) const; /*! Creates a deep copy of \a set and assigns it to this property set. */ KPropertySet& operator= (const KPropertySet &set); - /*! Change the value of property whose key is \a property to \a value. - @see void changePropertyIfExists(const QByteArray &, const QVariant &) */ - void changeProperty(const QByteArray &property, const QVariant &value); - - /*! Change the value of property whose key is \a property to \a value - only if it exists in the set. - @see void changeProperty(const QByteArray &, const QVariant &) */ - void changePropertyIfExists(const QByteArray &property, const QVariant &value) { - if (contains(property)) - changeProperty(property, value); - } - - /*! Sets @a caption as a user-visible translated string that will be shown in editor to represent - \a group. */ - void setGroupCaption(const QByteArray &group, const QString &caption); - /*! \return the user-visible translated caption string for \a group that will be shown in property editor to represent \a group. If there is no special caption set for the group, \a group is just returned. */ QString groupCaption(const QByteArray &group) const; - /*! Sets the icon name \a icon to be displayed for \a group. */ - void setGroupIconName(const QByteArray &group, const QString& iconName); - /*! \return the icons name for \a group. */ QString groupIconName(const QByteArray &group) const; /*! \return a list of all group names. The order of items is undefined. */ QList groupNames() const; - /*! \return a list of all property names for group @ group. + /*! \return a list of all property names for group @a group. The order of items is undefined. */ QList propertyNamesForGroup(const QByteArray &group) const; /*! Used by property editor to preserve previous selection when this set is assigned again. */ QByteArray previousSelection() const; - void setPreviousSelection(const QByteArray& prevSelection); - /*! Prints debug output for this set. */ void debug() const; //! @return property values for this set QMap propertyValues() const; -protected: - /*! Constructs a set which owns or does not own it's properties.*/ - explicit KPropertySet(bool propertyOwner); +public Q_SLOTS: + /*! Adds the property to the set, in the group. + The property becomes owned by the set. + Any name can be used for the @a group. "common" is the default for a basic top-level group. */ + void addProperty(KProperty *property, const QByteArray &group = "common"); + + /*! Removes property from the set and deletes the object. + Emits aboutToDeleteProperty before removing. */ + void removeProperty(KProperty *property); + + /*! Removes property with the given name from the set and deletes the object. + Emits aboutToDeleteProperty() before removing.*/ + void removeProperty(const QByteArray &name); + + /*! Removes all property objects from the property set and deletes them. */ + void clear(); + + /*! Change the value of property whose key is \a property to \a value. + @see void changePropertyIfExists(const QByteArray &, const QVariant &) */ + void changeProperty(const QByteArray &property, const QVariant &value); + + /*! Change the value of property whose key is \a property to \a value + only if it exists in the set. + @see void changeProperty(const QByteArray &, const QVariant &) */ + void changePropertyIfExists(const QByteArray &property, const QVariant &value); + + /*! Sets @a caption as a user-visible translated string that will be shown in editor to represent + \a group. */ + void setGroupCaption(const QByteArray &group, const QString &caption); + + /*! Sets the icon name \a icon to be displayed for \a group. */ + void setGroupIconName(const QByteArray &group, const QString& iconName); + + //! Sets previous section. + //! @see previousSelection() + void setPreviousSelection(const QByteArray &prevSelection); + + /*! Sets this set to be read-only. + @see isReadOnly */ + void setReadOnly(bool readOnly); Q_SIGNALS: /*! Emitted when the value of the property is changed.*/ void propertyChanged(KPropertySet& set, KProperty& property); /*! @internal Exists to be sure that we emitted it before propertyChanged(), so editor object can handle this. */ void propertyChangedInternal(KPropertySet& set, KProperty& property); /*! Emitted when the value of the property is reset.*/ void propertyReset(KPropertySet& set, KProperty& property); /*! Emitted when property is about to be deleted.*/ void aboutToDeleteProperty(KPropertySet& set, KProperty& property); /*! Emitted when property set object is about to be cleared (using clear()). This signal is also emitted from destructor before emitting aboutToBeDeleted(). */ void aboutToBeCleared(); /*! Emitted when property set object is about to be deleted.*/ void aboutToBeDeleted(); /*! Emitted when property set object's read-only flag has changed.*/ void readOnlyFlagChanged(); +protected: + /*! Constructs a set which owns or does not own it's properties.*/ + explicit KPropertySet(bool propertyOwner); + private: KPropertySetPrivate * const d; friend class KPropertySetPrivate; }; //! qDebug() stream operator. Writes this set to the debug output in a nicely formatted way. KPROPERTYCORE_EXPORT QDebug operator<<(QDebug dbg, const KPropertySet &set); /*! A property buffer \author Cedric Pasteur \author Alexander Dymo \author Adam Treat @todo Find a better name to show it's a set that doesn't own property */ class KPROPERTYCORE_EXPORT KPropertyBuffer : public KPropertySet { Q_OBJECT public: KPropertyBuffer(); explicit KPropertyBuffer(const KPropertySet &set); /*! Intersects with other KPropertySet.*/ virtual void intersect(const KPropertySet& set); protected Q_SLOTS: void intersectedChanged(KPropertySet& set, KProperty& prop); void intersectedReset(KPropertySet& set, KProperty& prop); private: void init(const KPropertySet& set); Q_DISABLE_COPY(KPropertyBuffer) }; #endif diff --git a/src/KPropertySet_p.h b/src/KPropertySet_p.h index 2a20032..db948d7 100644 --- a/src/KPropertySet_p.h +++ b/src/KPropertySet_p.h @@ -1,141 +1,148 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004 Alexander Dymo - Copyright (C) 2004-2009 Jarosław Staniek + Copyright (C) 2004-2017 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_SET_P_H #define KPROPERTY_SET_P_H #include "KPropertySet.h" #include "kproperty_debug.h" class KPROPERTYCORE_EXPORT KPropertySetPrivate { public: explicit KPropertySetPrivate(KPropertySet *set); ~KPropertySetPrivate(); //! Asccessor within the KProperty* inline static KPropertySetPrivate* d(KPropertySet *set) { return set->d; } inline static const KPropertySetPrivate* d(const KPropertySet *set) { return set->d; } inline uint visiblePropertiesCount() const { return m_visiblePropertiesCount; } inline KProperty* property(const QByteArray &name) const { return hash.value(name.toLower()); } inline KProperty& propertyOrNull(const QByteArray &name) const { KProperty *p = property(name); if (p) return *p; nonConstNull.setName(0); //to ensure returned property is null kprWarning() << "PROPERTY" << name << "NOT FOUND"; return nonConstNull; } void addProperty(KProperty *property, const QByteArray &group/*, bool updateSortingKey*/); void removeProperty(KProperty *property); void clear(); inline int count() const { return list.count(); } inline bool isEmpty() const { return list.isEmpty(); } + /*! @return @c true if there are groups explicitly defined. + In this case groups are displayed by the property editor. + If there is only one "common" group, it means that all properties belong to this group, + and no groups are displayed. + @since 3.1 */ + bool hasGroups() const; + inline QByteArray groupForProperty(const KProperty *property) const { return groupForProperties.value(const_cast(property)); } inline void addPropertyToGroup(KProperty *property, const QByteArray &groupLower) { groupForProperties.insert(property, groupLower); } inline void removePropertyFromGroup(KProperty *property) { groupForProperties.remove(property); } //! Copy all attributes except complex ones void copyAttributesFrom(const KPropertySetPrivate &other); //! Copy all properties from the other set void copyPropertiesFrom( const QList::ConstIterator& constBegin, const QList::ConstIterator& constEnd, const KPropertySet & set); /*! Add property to a group.*/ void addToGroup(const QByteArray &group, KProperty *property); /*! Remove property from a group.*/ void removeFromGroup(KProperty *property); /*! Used to declare that \a property wants to be informed that the set has been cleared (all properties are deleted) */ void informAboutClearing(bool* cleared); /*! Helper for Private class. */ void addRelatedProperty(KProperty *p1, KProperty *p2) const; inline QList::ConstIterator listConstIterator() const { return list.constBegin(); } inline QList::ConstIterator listConstEnd() const { return list.constEnd(); } /*! @return index of property @a property within its parent or group. */ int indexOfProperty(const KProperty *property) const; /*! @return index of property @a property within its group. */ int indexOfPropertyInGroup(const KProperty *property) const; KPropertySet *q; //groups of properties: // list of group name: (list of property names) QMap* > propertiesOfGroup; QList groupNames; QHash groupCaptions; QHash groupIconNames; // map of property: group bool ownProperty; bool readOnly = false; QByteArray prevSelection; mutable KProperty nonConstNull; private: //! A list of properties, preserving their order, owner of KProperty objects QList list; //! A hash of properties in form name -> property QHash hash; QHash groupForProperties; uint m_visiblePropertiesCount = 0; //!< Cache for optimization, //!< used by @ref bool KPropertySet::hasVisibleProperties() //! Used in KPropertySetPrivate::informAboutClearing(bool&) to declare that the property wants //! to be informed that the set has been cleared (all properties are deleted) bool* m_informAboutClearing = nullptr; }; #endif diff --git a/src/KPropertyUtils.h b/src/KPropertyUtils.h index 3b15bdc..ef77423 100644 --- a/src/KPropertyUtils.h +++ b/src/KPropertyUtils.h @@ -1,54 +1,56 @@ /* This file is part of the KDE project 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. */ #ifndef KPROPERTY_UTILS_H #define KPROPERTY_UTILS_H #include "kpropertywidgets_export.h" #include class KProperty; //! @short A container widget that can be used to split information into hideable sections //! for a property editor-like panes. class KPROPERTYWIDGETS_EXPORT KPropertyGroupWidget : public QWidget { + Q_OBJECT public: explicit KPropertyGroupWidget(const QString& title, QWidget* parent = 0); ~KPropertyGroupWidget(); +public Q_SLOTS: void setContents(QWidget* contents); protected: virtual bool event(QEvent * e); class Private; Private * const d; }; namespace KPropertyUtils { //! @return property object for model index @a index or @c nullptr if there is no property //! referenced by the index. KPROPERTYWIDGETS_EXPORT KProperty* propertyForIndex(const QModelIndex &index); } // KPropertyUtils #endif diff --git a/src/KProperty_p.h b/src/KProperty_p.h index 125ecce..ae312c0 100644 --- a/src/KProperty_p.h +++ b/src/KProperty_p.h @@ -1,101 +1,101 @@ /* This file is part of the KDE project - Copyright (C) 2009-2016 Jarosław Staniek + Copyright (C) 2009-2017 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_PROPERTY_P_H #define KPROPERTY_PROPERTY_P_H #include "KPropertySet.h" #include //! Default value for "step" option. Used for spin boxes, etc. #define KPROPERTY_DEFAULT_DOUBLE_VALUE_STEP 0.01 //! @internal class Q_DECL_HIDDEN KProperty::Private { public: explicit Private(KProperty *prop); void setCaptionForDisplaying(const QString& captionForDisplaying); ~Private(); //! @return a value for option @a name or null value if there is no such option set. inline QVariant option(const char* name, const QVariant& defaultValue) const { if (options.contains(name)) return options[name]; return parent ? parent->option(name, defaultValue) : defaultValue; } //! @return true if value of this property differs from @a otherValue bool valueDiffersInternal(const QVariant &otherValue, KProperty::ValueOptions options); //! Sets value of the property to @a newValue bool setValueInternal(const QVariant &newValue, KProperty::ValueOptions valueOptions); /*! Adds @a prop as a child of this property. The children will be owned by this property. */ void addChild(KProperty *prop); /*! Adds @a set to this property. */ void addSet(KPropertySet *newSet); /*! Adds related property for this property. */ void addRelatedProperty(KProperty *property); /*! This method emits the @a KPropertySet::propertyChanged() signal. KProperty::setValue() calls this method if the value has been changed. */ void emitPropertyChanged(); KProperty * const q; int type; QByteArray name; QString captionForDisplaying; QString* caption; QString description; QVariant value; QVariant oldValue; /*! The string-to-value correspondence list of the property.*/ KPropertyListData* listData; QString iconName; bool changed; bool storable; bool readOnly; bool visible; - int autosync; + KProperty::ValueSyncPolicy valueSyncPolicy = KProperty::ValueSyncPolicy::Editor; QMap options; KComposedPropertyInterface *composed; //! Flag used to allow composed property to use setValue() without causing recursion bool useComposedProperty; //! Used when a single set is assigned for the property QPointer set; //! Used when multiple sets are assigned for the property QList< QPointer > *sets; KProperty *parent; QList *children; //! List of properties with the same name (when intersecting buffers) QList *relatedProperties; }; #endif diff --git a/src/editors/KPropertyGenericSelectionEditor.h b/src/editors/KPropertyGenericSelectionEditor.h index a46055c..168ccec 100644 --- a/src/editors/KPropertyGenericSelectionEditor.h +++ b/src/editors/KPropertyGenericSelectionEditor.h @@ -1,54 +1,54 @@ /* This file is part of the KDE project Copyright (C) 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 KPROPERTYGENERICSELECTIONEDITOR_H #define KPROPERTYGENERICSELECTIONEDITOR_H #include "kpropertywidgets_export.h" #include #include //! A base class for use by editors that have widget on the left and "..." select button on the right class KPROPERTYWIDGETS_EXPORT KPropertyGenericSelectionEditor : public QWidget { Q_OBJECT - public: explicit KPropertyGenericSelectionEditor(QWidget *parent = 0); ~KPropertyGenericSelectionEditor(); +public Q_SLOTS: //! Sets the visibility of the "..." select button void setSelectionButtonVisible(bool set); protected: void setMainWidget(QWidget *widget); protected Q_SLOTS: //! Reimplement to react on clicking the "..." select button virtual void selectButtonClicked(); private: Q_DISABLE_COPY(KPropertyGenericSelectionEditor) class Private; QScopedPointer const d; }; #endif diff --git a/src/editors/combobox.h b/src/editors/combobox.h index 6c3a6b3..0250046 100644 --- a/src/editors/combobox.h +++ b/src/editors/combobox.h @@ -1,100 +1,100 @@ /* 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. */ #ifndef KPROPERTY_COMBOBOX_H #define KPROPERTY_COMBOBOX_H #include "KPropertyWidgetsFactory.h" #include class KPROPERTYWIDGETS_EXPORT KPropertyComboBoxEditor : public QComboBox { Q_OBJECT Q_PROPERTY(QVariant value READ value WRITE setValue USER true) public: class Options { public: class IconProviderInterface { public: IconProviderInterface() {} virtual ~IconProviderInterface() {} virtual QIcon icon(int index) const = 0; virtual IconProviderInterface* clone() const = 0; }; Options(); Options(const Options& other); ~Options(); IconProviderInterface *iconProvider; bool extraValueAllowed; }; KPropertyComboBoxEditor(const KPropertyListData& listData, const Options& options, QWidget *parent = 0); virtual ~KPropertyComboBoxEditor(); virtual QVariant value() const; - void setListData(const KPropertyListData & listData); - static QString borderSheet(const QWidget *widget); Q_SIGNALS: void commitData( QWidget * editor ); public Q_SLOTS: + void setListData(const KPropertyListData & listData); + virtual void setValue(const QVariant &value); protected Q_SLOTS: void slotValueChanged(int value); protected: virtual void paintEvent( QPaintEvent * event ); QString keyForValue(const QVariant &value); void fillValues(); bool listDataKeysAvailable() const; KPropertyListData m_listData; bool m_setValueEnabled; Options m_options; }; class KPROPERTYWIDGETS_EXPORT KPropertyComboBoxDelegate : public KPropertyEditorCreatorInterface, public KPropertyValueDisplayInterface { public: KPropertyComboBoxDelegate(); virtual QString propertyValueToString(const KProperty* property, const QLocale &locale) const; QString valueToString(const QVariant& value, const QLocale &locale) const; virtual QWidget * createEditor( int type, QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const; }; #endif diff --git a/src/editors/cursoredit.h b/src/editors/cursoredit.h index aa5cffc..ea4d71d 100644 --- a/src/editors/cursoredit.h +++ b/src/editors/cursoredit.h @@ -1,56 +1,58 @@ /* 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. */ #ifndef KPROPERTY_CURSOREDIT_H #define KPROPERTY_CURSOREDIT_H #include "combobox.h" class KPROPERTYWIDGETS_EXPORT KPropertyCursorEditor : public KPropertyComboBoxEditor { Q_OBJECT Q_PROPERTY(QCursor value READ cursorValue WRITE setCursorValue USER true) public: explicit KPropertyCursorEditor(QWidget *parent = 0); virtual ~KPropertyCursorEditor(); virtual QCursor cursorValue() const; + +public Q_SLOTS: virtual void setCursorValue(const QCursor &value); }; class KPROPERTYWIDGETS_EXPORT KPropertyCursorDelegate : public KPropertyEditorCreatorInterface, public KPropertyValuePainterInterface, public KPropertyValueDisplayInterface { public: KPropertyCursorDelegate(); virtual QWidget * createEditor( int type, QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const; virtual void paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const; virtual QString valueToString(const QVariant& value, const QLocale &locale) const; }; #endif diff --git a/src/editors/dummywidget.h b/src/editors/dummywidget.h index 42cceb3..b3c5c25 100644 --- a/src/editors/dummywidget.h +++ b/src/editors/dummywidget.h @@ -1,49 +1,50 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004 Alexander Dymo 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_DUMMYWIDGET_H #define KPROPERTY_DUMMYWIDGET_H #include "KPropertyFactory.h" #include class KPROPERTYWIDGETS_EXPORT KPropertyDummyWidget: public Widget { Q_OBJECT - public: explicit KPropertyDummyWidget(KProperty *property, QWidget *parent = 0); virtual ~KPropertyDummyWidget(); virtual QVariant value() const; - virtual void setValue(const QVariant &value, bool emitChange = true); virtual void drawViewer(QPainter *p, const QColorGroup &cg, const QRect &r, const QVariant &value); -protected: +public Q_SLOTS: + virtual void setValue(const QVariant &value, bool emitChange = true); + +protected Q_SLOTS: virtual void setReadOnlyInternal(bool readOnly); private: QVariant m_value; }; #endif diff --git a/src/editors/stringlistedit.h b/src/editors/stringlistedit.h index 0a74adb..4c6a18f 100644 --- a/src/editors/stringlistedit.h +++ b/src/editors/stringlistedit.h @@ -1,56 +1,57 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004 Alexander Dymo 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_STRINGLISTEDIT_H #define KPROPERTY_STRINGLISTEDIT_H #include "KPropertyFactory.h" #include class QLineEdit; class QPushButton; class KPROPERTYWIDGETS_EXPORT KPropertyStringListEditor : public Widget { Q_OBJECT - public: explicit KPropertyStringListEditor(KProperty *property, QWidget *parent = 0); virtual ~KPropertyStringListEditor(); virtual QVariant value() const; - virtual void setValue(const QVariant &value, bool emitChange = true); virtual void drawViewer(QPainter *p, const QColorGroup &cg, const QRect &r, const QVariant &value); -protected: +public Q_SLOTS: + virtual void setValue(const QVariant &value, bool emitChange = true); + +protected Q_SLOTS: virtual void setReadOnlyInternal(bool readOnly); protected Q_SLOTS: void showEditor(); private: QLineEdit *m_edit; QStringList m_list; QPushButton *m_selectButton; }; #endif diff --git a/src/editors/symbolcombo.h b/src/editors/symbolcombo.h index dc09a31..4f6a32c 100644 --- a/src/editors/symbolcombo.h +++ b/src/editors/symbolcombo.h @@ -1,54 +1,56 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004 Alexander Dymo 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_SYMBOLCOMBO_H #define KPROPERTY_SYMBOLCOMBO_H #include "KPropertyFactory.h" class QLineEdit; class QPushButton; class KPROPERTYWIDGETS_EXPORT KPropertySymbolComboEditor : public Widget { Q_OBJECT public: explicit KPropertySymbolComboEditor(KProperty *property, QWidget *parent = 0); virtual ~KPropertySymbolComboEditor(); virtual QVariant value() const; - virtual void setValue(const QVariant &value, bool emitChange = true); virtual void drawViewer(QPainter *p, const QColorGroup &cg, const QRect &r, const QVariant &value); -protected: +public Q_SLOTS: + virtual void setValue(const QVariant &value, bool emitChange = true); + +protected Q_SLOTS: virtual void setReadOnlyInternal(bool readOnly); protected Q_SLOTS: void selectChar(); void slotValueChanged(const QString &text); private: QLineEdit *m_edit; QPushButton *m_select; }; #endif