diff --git a/autotests/KPropertyTest.cpp b/autotests/KPropertyTest.cpp index 6418f14..43b620c 100644 --- a/autotests/KPropertyTest.cpp +++ b/autotests/KPropertyTest.cpp @@ -1,212 +1,198 @@ /* This file is part of the KDE project Copyright (C) 2017 Jarosław Staniek This program 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 program 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 program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include class KPropertyTest : public QObject { Q_OBJECT private Q_SLOTS: void testNull(); private: }; void KPropertyTest::testNull() { { // isNull const KProperty nullProperty; QVERIFY(nullProperty.isNull()); const KProperty nullPropertyCopy(nullProperty); QVERIFY(nullPropertyCopy.isNull()); QVERIFY2(nullProperty == nullPropertyCopy, "two null properties are equal"); QVERIFY2(nullProperty == KProperty(), "two null properties are equal v2"); QVERIFY2(!(nullProperty != nullPropertyCopy), "two null properties are equal v2"); } { // name const KProperty nullProperty; const KProperty nullPropertyCopy(nullProperty); KProperty notNullProperty("notNull"); QVERIFY(!notNullProperty.isNull()); QVERIFY2(!(nullProperty == notNullProperty), "null property is not equal to not null property"); notNullProperty.setName(QByteArray()); QVERIFY2(notNullProperty.isNull(), "Not null property becomes null after setting empty name"); notNullProperty.setName(""); QVERIFY2(notNullProperty.isNull(), "Not null property becomes null after setting empty name v2"); notNullProperty.setName("other"); QVERIFY2(!notNullProperty.isNull(), "Null property becomes not-null after setting non-empty name"); QVERIFY(nullProperty.name().isEmpty()); QVERIFY(nullPropertyCopy.name().isEmpty()); } { // caption const KProperty nullProperty; const KProperty nullPropertyCopy(nullProperty); KProperty notNullProperty("notNull"); QVERIFY(nullProperty.caption().isEmpty()); QVERIFY(nullPropertyCopy.caption().isEmpty()); QVERIFY(notNullProperty.caption().isEmpty()); KProperty propertyWithCaption("withCaption", 17, "My caption"); QVERIFY(!propertyWithCaption.isNull()); propertyWithCaption.setName(QByteArray()); QVERIFY2(propertyWithCaption.isNull(), "Property with name and caption is null after setting " "empty name"); } { // caption does not influence null KProperty propertyWithCaption("withCaption", 17, "My caption"); propertyWithCaption.setCaption(QByteArray()); QVERIFY2(!propertyWithCaption.isNull(), "Property with name and caption is still not null " "after setting empty caption"); } { // description KProperty nullProperty; nullProperty.setDescription("My desc"); QVERIFY2(nullProperty.isNull(), "Null property with non-empty description is still null"); } { // value KProperty nullProperty; QTest::ignoreMessage(QtWarningMsg, "COULD NOT SET value to a null property"); nullProperty.setValue(0.123); QTest::ignoreMessage(QtWarningMsg, "COULD NOT SET value to a null property"); KProperty nullPropertyWithValue(QByteArray(), 177); QVERIFY2(nullPropertyWithValue.isNull(), "Null property with value set from ctor is still null"); QVERIFY2(nullPropertyWithValue.value().isNull(), "Null property with value set from " "ctor still has no value"); } } /* TODO KProperty::KProperty(KProperty const&) KProperty::KProperty(QByteArray const&, KPropertyListData*, QVariant const&, QString const&, QString const&, int, KProperty*) KProperty::KProperty(QByteArray const&, QStringList const&, QStringList const&, QVariant const&, QString const&, QString const&, int, KProperty*) KProperty::KProperty(QByteArray const&, QVariant const&, QString const&, QString const&, int, KProperty*) KProperty::KProperty() KProperty::captionForDisplaying() const KProperty::caption() const KProperty::childValueChanged(KProperty*, QVariant const&, bool) KProperty::children() const KProperty::child(QByteArray const&) KProperty::clearModifiedFlag() KProperty::composedProperty() const KProperty::description() const KProperty::hasOptions() const KProperty::iconName() const KProperty::isModified() const OK KProperty::isNull() const KProperty::isReadOnly() const KProperty::isStorable() const KProperty::isVisible() const KProperty::listData() const KProperty::name() const KProperty::oldValue() const KProperty::operator=(KProperty const&) KProperty::operator=(QVariant const&) KProperty::operator==(KProperty const&) const KProperty::option(char const*, QVariant const&) const KProperty::parent() const KProperty::resetValue() KProperty::setCaption(QString const&) KProperty::setComposedProperty(KComposedPropertyInterface*) KProperty::setDescription(QString const&) KProperty::setIconName(QString const&) KProperty::setListData(KPropertyListData*) KProperty::setListData(QStringList const&, QStringList const&) KProperty::setName(QByteArray const&) KProperty::setOption(char const*, QVariant const&) KProperty::setReadOnly(bool) KProperty::setStorable(bool) KProperty::setType(int) KProperty::setValueSyncPolicy(KProperty::ValueSyncPolicy) KProperty::setValue(QVariant const&, bool*, QFlags) KProperty::setValue(QVariant const&, bool, bool) KProperty::setVisible(bool) KProperty::type() const KProperty::valueEqualsTo(QVariant const&, QFlags) const KProperty::valueSyncPolicy() const KProperty::value() const KPropertyListData::~KPropertyListData() KPropertyListData::KPropertyListData(QList, QStringList const&) KPropertyListData::KPropertyListData(QStringList const&, QStringList const&) KPropertyListData::KPropertyListData() KPropertyListData::keysAsStringList() const KPropertyListData::setKeysAsStringList(QStringList const&) */ /* Full API TODO: KComposedPropertyCreatorInterface::~KComposedPropertyCreatorInterface() KComposedPropertyCreatorInterface::KComposedPropertyCreatorInterface() KComposedPropertyInterface::~KComposedPropertyInterface() KComposedPropertyInterface::KComposedPropertyInterface(KProperty*) KPropertyBuffer::KPropertyBuffer(KPropertySet const&) KPropertyBuffer::KPropertyBuffer() KPropertyBuffer::init(KPropertySet const&) KPropertyBuffer::intersectedChanged(KPropertySet&, KProperty&) KPropertyBuffer::intersectedReset(KPropertySet&, KProperty&) KPropertyBuffer::intersect(KPropertySet const&) KPropertyFactoryManager::~KPropertyFactoryManager() KPropertyFactoryManager::KPropertyFactoryManager() KPropertyFactoryManager::addInitFunction(void (*)()) KPropertyFactoryManager::canConvertValueToText(KProperty const*) const KPropertyFactoryManager::canConvertValueToText(int) const KPropertyFactoryManager::createComposedProperty(KProperty*) KPropertyFactoryManager::propertyValueToLocalizedString(KProperty const*) const KPropertyFactoryManager::propertyValueToString(KProperty const*) const KPropertyFactoryManager::registerFactory(KPropertyFactory*) KPropertyFactoryManager::self() KPropertyFactoryManager::valueToLocalizedString(int, QVariant const&) const KPropertyFactoryManager::valueToString(int, QVariant const&) const KPropertyFactory::~KPropertyFactory() KPropertyFactory::KPropertyFactory() KPropertyFactory::addComposedPropertyCreatorInternal(int, KComposedPropertyCreatorInterface*, bool) KPropertyFactory::addComposedPropertyCreator(int, KComposedPropertyCreatorInterface*) KPropertyFactory::addDisplayInternal(int, KPropertyValueDisplayInterface*, bool) KPropertyFactory::addDisplay(int, KPropertyValueDisplayInterface*) KPropertyFactory::composedPropertyCreators() const KPropertyFactory::valueDisplays() const -KPropertyUnit::convertFromUnitToUnit(double, KPropertyUnit const&, KPropertyUnit const&, double) -KPropertyUnit::fromListForUi(int, QFlags, double) -KPropertyUnit::fromSymbol(QString const&, bool*) -KPropertyUnit::fromUserValue(QString const&, bool*) const -KPropertyUnit::fromUserValue(double) const -KPropertyUnit::indexInListForUi(QFlags) const -KPropertyUnit::listOfUnitNameForUi(QFlags) -KPropertyUnit::parseAngle(QString const&, double) -KPropertyUnit::parseValue(QString const&, double) -KPropertyUnit::ptToUnit(double, KPropertyUnit const&) -KPropertyUnit::symbol() const -KPropertyUnit::toUserStringValue(double) const -KPropertyUnit::toUserValue(double) const -KPropertyUnit::unitDescription(KPropertyUnit::Type) KPropertyUtils::keyForEnumValue(char const*, int) KPropertyValueDisplayInterface::~KPropertyValueDisplayInterface() KPropertyValueDisplayInterface::KPropertyValueDisplayInterface() KPropertyValueDisplayInterface::maxStringValueLength() KPropertyValueDisplayInterface::valueToLocalizedString(QVariant const&) */ QTEST_MAIN(KPropertyTest) #include "KPropertyTest.moc" diff --git a/examples/window.cpp b/examples/window.cpp index 902ccc2..5896ea4 100644 --- a/examples/window.cpp +++ b/examples/window.cpp @@ -1,292 +1,323 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur 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; const bool addGroups = !m_parser.isSet(m_flatOption); if (addGroups) { - group = "SimpleGroup"; - m_set.setGroupCaption(group, "Simple Group"); + group = "BasicGroup"; + m_set.setGroupCaption(group, "Basic Properties"); } if (singleProperty.isEmpty() || singleProperty=="String") { m_set.addProperty(p = new KProperty("String", "String"), group); 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->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::Type::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 (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); + group = "ComposedGroup"; + m_set.setGroupCaption(group, "Composed Properties"); } 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=="Rect") { + m_set.addProperty(new KProperty("Rect", QRect(5,11,100,200), "Rect"), 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); } + if (singleProperty.isEmpty() || singleProperty == "RectF") { + m_set.addProperty( + new KProperty("RectF", QRectF(0.1, 0.5, 10.72, 18.21), "RectF"), group); + } + +// With suffixes and prefixes + if (addGroups) { + group = "PrefixesSuffixesGroup"; + m_set.setGroupCaption(group, "Prefixes & Suffixes"); + } + if (singleProperty.isEmpty() || singleProperty=="dollars") { + m_set.addProperty(p = new KProperty("dollars", 100, "Dollars"), group); + p->setOption("prefix", "$"); + } + if (singleProperty.isEmpty() || singleProperty == "billions") { + m_set.addProperty(p = new KProperty("billions", 5.0, "Billions"), group); + p->setOption("prefix", "£"); + p->setOption("suffix", "bn"); + // default precision == 2 and step == 0.01 + } + if (singleProperty.isEmpty() || singleProperty == "PointF-mm") { + m_set.addProperty( + p = new KProperty("PointF-mm", QPointF(2.5, 3.5), "PointF [mm]"), group); + p->setOption("suffix", "mm"); + p->setOption("step", 0.1); + p->setOption("precision", 2); + } + if (singleProperty.isEmpty() || singleProperty == "SizeF-dm") { + m_set.addProperty( + p = new KProperty("SizeF-dm", QSizeF(7.0, 6.5), "SizeF [dm]"), group); + p->setOption("suffix", "dm"); + p->setOption("step", 0.001); + p->setOption("precision", 3); + } + if (singleProperty.isEmpty() || singleProperty=="RectF-px") { + m_set.addProperty( + p = new KProperty("RectF-px", QRectF(21.2, 22.2, 9.1, 1.0), "RectF [px]"), + group); + p->setOption("suffix", "px"); + p->setOption("step", 0.1); + p->setOption("precision", 1); + } // Appearance if (addGroups) { - group = "Appearance Group"; + group = "AppearanceGroup"; 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); } QVBoxLayout *lyr = new QVBoxLayout(this); m_editorView = new KPropertyEditorView(this); lyr->addWidget(m_editorView); m_editorView->changeSet(&m_set); lyr->addSpacing(lyr->spacing()); QHBoxLayout *hlyr = new QHBoxLayout; lyr->addLayout(hlyr); QCheckBox *showGrid = new QCheckBox("Show grid"); showGrid->setChecked(true); connect(showGrid, &QCheckBox::stateChanged, this, &Window::showGrid); hlyr->addWidget(showGrid); 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/src/CMakeLists.txt b/src/CMakeLists.txt index fed1c80..a1808bc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,328 +1,327 @@ # 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" ) 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) 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" ) 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.h b/src/KProperty.h index dcc1274..a60ebc0 100644 --- a/src/KProperty.h +++ b/src/KProperty.h @@ -1,522 +1,541 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004 Alexander Dymo 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_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 custom 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. Property is null if it has empty name. */ 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); //! 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. +
      +
    • min: value describing minimum value for properties of integer, double, + date, date/time and time types. Default is 0 for double and unsigned integer types, + -INT_MAX for signed integer type. Defaults for date, date/time and time types are + specified in documentation of QDateEdit::minimumDate, + QDateTimeEdit::minimumDateTime and QTime::minimumTime, respectively. + The value is ignored if it is larger than the value of "max" option.
    • +
    • minValueText: user-visible translated string to be displayed in editor for integer, + double, date, date/time and time types when the value is equal to the value of + "min" option. @see QAbstractSpinBox::specialValueText
    • -
    • max: integer describing minimum value for properties of integer type. Default is 0xffff.
    • +
    • max: value describing minimum value for properties of integer type. + Default is pow(2, std::numeric_limits::digits) for double type (2^53 on 64-bit + systems -- maximum precise value), and INT_MAX for integer type. + Defaults for date, date/time and time types are specified in documentation + of QDateEdit::maximumDate, QDateTimeEdit::maximumDateTime and QTime::maximumTime, respectively. + The value is ignored if it is smaller than the value of "min" option.
    • precision: integer value >= 0 describing the number of decimals after the decimal point for double type. Default value is 2. @see QDoubleSpinBox::decimals
    • step: double value > 0.0 describing the size of the step that is taken when the user hits the up or down button of editor for double type. Default value is 0.01. @see QDoubleSpinBox::singleStep
    • 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.
    • +
    • prefix: string to display before the value, e.g. '$'. Supported for double and integer + types and composed types based on double and integer types (Point*, Size*, Rect*). + @see QDoubleSpinBox::prefix QSpinBox::prefix
    • +
    • suffix: string to display after the value, e.g. unit such as 'mm'. + Supported for double and integer types and composed types based on double and + integer types (Point*, Size*, Rect*). Note that only display is affected, value + is not converted to any unit. + @see QDoubleSpinBox::suffix QSpinBox::suffix
    */ 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); /** * @return @c true if the property is equal to @a prop; otherwise returns @c false. * Two properties are equal if they have the same name and type. * @note All null properties are equal * @todo Compare properties deeper? */ bool operator==(const KProperty &prop) const; /** * @return @c true if the property is different from @a prop; otherwise returns @c false. * Two properties are different if they have different names or types. * @since 3.1 */ 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: //! Added only to help porting old code. Use public setValue() methods. void setValue(const QVariant &value, bool a1, bool a2 = true); 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/KPropertyUnit_p.cpp b/src/KPropertyUnit_p.cpp deleted file mode 100644 index b53b4e1..0000000 --- a/src/KPropertyUnit_p.cpp +++ /dev/null @@ -1,386 +0,0 @@ -/* This file is part of the KDE project - Copyright (C) 2001 David Faure - Copyright (C) 2004, Nicolas GOUTTE - Copyright 2012 Friedrich W. H. Kossebau - - 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 "KPropertyUnit_p.h" -#include "kproperty_debug.h" - -#include - -// ensure the same order as in KPropertyUnit::Unit -static const char* const unitNameList[int(KPropertyUnit::Type::TypeCount)] = -{ - "mm", - "pt", - "in", - "cm", - "dm", - "pi", - "cc", - "px" -}; - -QString KPropertyUnit::unitDescription(KPropertyUnit::Type type) -{ - switch (type) { - case KPropertyUnit::Type::Millimeter: - return QObject::tr("Millimeters (mm)"); - case KPropertyUnit::Type::Centimeter: - return QObject::tr("Centimeters (cm)"); - case KPropertyUnit::Type::Decimeter: - return QObject::tr("Decimeters (dm)"); - case KPropertyUnit::Type::Inch: - return QObject::tr("Inches (in)"); - case KPropertyUnit::Type::Pica: - return QObject::tr("Pica (pi)"); - case KPropertyUnit::Type::Cicero: - return QObject::tr("Cicero (cc)"); - case KPropertyUnit::Type::Point: - return QObject::tr("Points (pt)"); - case KPropertyUnit::Type::Pixel: - return QObject::tr("Pixels (px)"); - default: - return QObject::tr("Unsupported unit"); - } -} - -// grouped by units which are similar -static const KPropertyUnit::Type typesInUi[int(KPropertyUnit::Type::TypeCount)] = -{ - KPropertyUnit::Type::Millimeter, - KPropertyUnit::Type::Centimeter, - KPropertyUnit::Type::Decimeter, - KPropertyUnit::Type::Inch, - KPropertyUnit::Type::Pica, - KPropertyUnit::Type::Cicero, - KPropertyUnit::Type::Point, - KPropertyUnit::Type::Pixel, -}; - -QStringList KPropertyUnit::listOfUnitNameForUi(ListOptions listOptions) -{ - QStringList lst; - for (int i = 0; i < int(KPropertyUnit::Type::TypeCount); ++i) { - const Type type = typesInUi[i]; - if (type != Type::Pixel || !(listOptions & ListOption::HidePixel)) { - lst.append(unitDescription(type)); - } - } - return lst; -} - -KPropertyUnit KPropertyUnit::fromListForUi(int index, ListOptions listOptions, qreal factor) -{ - KPropertyUnit::Type type = KPropertyUnit::Type::Point; - - if ((0 <= index) && (index < int(KPropertyUnit::Type::TypeCount))) { - // iterate through all enums and skip the Pixel enum if needed - for (int i = 0; i < int(KPropertyUnit::Type::TypeCount); ++i) { - if ((listOptions & ListOption::HidePixel) && (typesInUi[i] == Type::Pixel)) { - ++index; - continue; - } - if (i == index) { - type = typesInUi[i]; - break; - } - } - } - - return KPropertyUnit(type, factor); -} - -int KPropertyUnit::indexInListForUi(ListOptions listOptions) const -{ - if ((listOptions & ListOption::HidePixel) && (m_type == Type::Pixel)) { - return -1; - } - - int result = -1; - - int skipped = 0; - for (int i = 0; i < int(KPropertyUnit::Type::TypeCount); ++i) { - if ((listOptions & ListOption::HidePixel) && (typesInUi[i] == Type::Pixel)) { - ++skipped; - continue; - } - if (typesInUi[i] == m_type) { - result = i - skipped; - break; - } - } - - return result; -} - -qreal KPropertyUnit::toUserValue(qreal ptValue) const -{ - switch (m_type) { - case Type::Millimeter: - return toMillimeter(ptValue); - case Type::Centimeter: - return toCentimeter(ptValue); - case Type::Decimeter: - return toDecimeter(ptValue); - case Type::Inch: - return toInch(ptValue); - case Type::Pica: - return toPica(ptValue); - case Type::Cicero: - return toCicero(ptValue); - case Type::Pixel: - return ptValue * m_pixelConversion; - case Type::Point: - default: - return toPoint(ptValue); - } -} - -qreal KPropertyUnit::ptToUnit(qreal ptValue, const KPropertyUnit &unit) -{ - switch (unit.m_type) { - case Type::Millimeter: - return POINT_TO_MM(ptValue); - case Type::Centimeter: - return POINT_TO_CM(ptValue); - case Type::Decimeter: - return POINT_TO_DM(ptValue); - case Type::Inch: - return POINT_TO_INCH(ptValue); - case Type::Pica: - return POINT_TO_PI(ptValue); - case Type::Cicero: - return POINT_TO_CC(ptValue); - case Type::Pixel: - return ptValue * unit.m_pixelConversion; - case Type::Point: - default: - return ptValue; - } -} - -QString KPropertyUnit::toUserStringValue(qreal ptValue) const -{ - return QLocale::system().toString(toUserValue(ptValue)); -} - -qreal KPropertyUnit::fromUserValue(qreal value) const -{ - switch (m_type) { - case Type::Millimeter: - return MM_TO_POINT(value); - case Type::Centimeter: - return CM_TO_POINT(value); - case Type::Decimeter: - return DM_TO_POINT(value); - case Type::Inch: - return INCH_TO_POINT(value); - case Type::Pica: - return PI_TO_POINT(value); - case Type::Cicero: - return CC_TO_POINT(value); - case Type::Pixel: - return value / m_pixelConversion; - case Type::Point: - default: - return value; - } -} - -qreal KPropertyUnit::fromUserValue(const QString &value, bool *ok) const -{ - return fromUserValue(QLocale::system().toDouble(value, ok)); -} - -qreal KPropertyUnit::parseValue(const QString& _value, qreal defaultVal) -{ - if (_value.isEmpty()) - return defaultVal; - - QString value(_value.simplified()); - value.remove(QLatin1Char(' ')); - - int firstLetter = -1; - for (int i = 0; i < value.length(); ++i) { - if (value.at(i).isLetter()) { - if (value.at(i) == QLatin1Char('e')) - continue; - firstLetter = i; - break; - } - } - - bool ok; - if (firstLetter == -1) { - const qreal result = QVariant(value).toReal(&ok); - return ok ? result : defaultVal; - } - - const QByteArray symbol = value.mid(firstLetter).toLatin1(); - value.truncate(firstLetter); - const qreal val = value.toDouble(); - - if (symbol == "pt" || symbol.isEmpty()) { - return val; - } - - KPropertyUnit u = KPropertyUnit::fromSymbol(QLatin1String(symbol), &ok); - if (ok) - return u.fromUserValue(val); - - if (symbol == "m") { - return DM_TO_POINT(val * 10.0); - } else if (symbol == "km") { - return DM_TO_POINT(val * 10000.0); - } - kprWarning() << "KPropertyUnit::parseValue: Unit " << symbol << " is not supported, please report."; - - //! @todo add support for mi/ft ? - return defaultVal; -} - -KPropertyUnit KPropertyUnit::fromSymbol(const QString &symbol, bool *ok) -{ - Type result = Type::Point; - - if (symbol == QLatin1String("inch") /*compat*/) { - result = Type::Inch; - if (ok) - *ok = true; - } else { - if (ok) - *ok = false; - - for (int i = 0; i < int(Type::TypeCount); ++i) { - if (symbol == QLatin1String(unitNameList[i])) { - result = static_cast(i); - if (ok) - *ok = true; - } - } - } - - return KPropertyUnit(result); -} - -qreal KPropertyUnit::convertFromUnitToUnit(qreal value, const KPropertyUnit &fromUnit, const KPropertyUnit &toUnit, qreal factor) -{ - qreal pt; - switch (fromUnit.type()) { - case Type::Millimeter: - pt = MM_TO_POINT(value); - break; - case Type::Centimeter: - pt = CM_TO_POINT(value); - break; - case Type::Decimeter: - pt = DM_TO_POINT(value); - break; - case Type::Inch: - pt = INCH_TO_POINT(value); - break; - case Type::Pica: - pt = PI_TO_POINT(value); - break; - case Type::Cicero: - pt = CC_TO_POINT(value); - break; - case Type::Pixel: - pt = value / factor; - break; - case Type::Point: - default: - pt = value; - } - - switch (toUnit.type()) { - case Type::Millimeter: - return POINT_TO_MM(pt); - case Type::Centimeter: - return POINT_TO_CM(pt); - case Type::Decimeter: - return POINT_TO_DM(pt); - case Type::Inch: - return POINT_TO_INCH(pt); - case Type::Pica: - return POINT_TO_PI(pt); - case Type::Cicero: - return POINT_TO_CC(pt); - case Type::Pixel: - return pt * factor; - case Type::Point: - default: - return pt; - } - -} - -QString KPropertyUnit::symbol() const -{ - return QLatin1String(unitNameList[int(m_type)]); -} - -qreal KPropertyUnit::parseAngle(const QString& _value, qreal defaultVal) -{ - if (_value.isEmpty()) - return defaultVal; - - QString value(_value.simplified()); - value.remove(QLatin1Char(' ')); - - int firstLetter = -1; - for (int i = 0; i < value.length(); ++i) { - if (value.at(i).isLetter()) { - if (value.at(i) == QLatin1Char('e')) - continue; - firstLetter = i; - break; - } - } - - if (firstLetter == -1) - return value.toDouble(); - - const QString type = value.mid(firstLetter); - value.truncate(firstLetter); - const qreal val = value.toDouble(); - - if (type == QLatin1String("deg")) - return val; - else if (type == QLatin1String("rad")) - return val * 180 / M_PI; - else if (type == QLatin1String("grad")) - return val * 0.9; - - return defaultVal; -} - -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug debug, const KPropertyUnit &unit) -{ -#ifndef NDEBUG - debug.nospace() << unit.symbol(); -#else - Q_UNUSED(unit); -#endif - return debug.space(); - -} -#endif diff --git a/src/KPropertyUnit_p.h b/src/KPropertyUnit_p.h deleted file mode 100644 index 7081217..0000000 --- a/src/KPropertyUnit_p.h +++ /dev/null @@ -1,258 +0,0 @@ -/* This file is part of the KDE project - Copyright (C) 1998, 1999 Reginald Stadlbauer - Copyright (C) 1998, 1999 Torben Weis - Copyright (C) 2004, Nicolas GOUTTE - Copyright (C) 2010 Thomas Zander - Copyright 2012 Friedrich W. H. Kossebau - - 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 KPROPERTYUNIT_H -#define KPROPERTYUNIT_H - -#include "kpropertycore_export.h" - -#include -#include -#include -#include - -#include // for floor - -// 1 inch ^= 72 pt -// 1 inch ^= 25.399956 mm (-pedantic ;p) -// 1 pt = 1/12 pi -// 1 pt ^= 0.0077880997 cc -// 1 cc = 12 dd -// Note: I don't use division but multiplication with the inverse value -// because it's faster ;p (Werner) -#define POINT_TO_MM(px) qreal((px)*0.352777167) -#define MM_TO_POINT(mm) qreal((mm)*2.83465058) -#define POINT_TO_CM(px) qreal((px)*0.0352777167) -#define CM_TO_POINT(cm) qreal((cm)*28.3465058) -#define POINT_TO_DM(px) qreal((px)*0.00352777167) -#define DM_TO_POINT(dm) qreal((dm)*283.465058) -#define POINT_TO_INCH(px) qreal((px)*0.01388888888889) -#define INCH_TO_POINT(inch) qreal((inch)*72.0) -#define MM_TO_INCH(mm) qreal((mm)*0.039370147) -#define INCH_TO_MM(inch) qreal((inch)*25.399956) -#define POINT_TO_PI(px) qreal((px)*0.083333333) -#define POINT_TO_CC(px) qreal((px)*0.077880997) -#define PI_TO_POINT(pi) qreal((pi)*12) -#define CC_TO_POINT(cc) qreal((cc)*12.840103) -/** - * %KProperty stores everything in pt (using "qreal") internally. - * When displaying a value to the user, the value is converted to the user's unit - * of choice, and rounded to a reasonable precision to avoid 0.999999 - * - * For implementing the selection of a unit type in the UI use the *ForUi() methods. - * They ensure the same order of the unit types in all places, with the order not - * bound to the order in the enum (so ABI-compatible extension is possible) and - * with the order and scope of listed types controlled by the @c ListOptions parameter. - */ -class KPROPERTYCORE_EXPORT KPropertyUnit -{ -public: - /** Length units supported by %KProperty. */ - enum class Type { - Millimeter = 0, - Point, //!< Postscript point, 1/72th of an Inco - Inch, - Centimeter, - Decimeter, - Pica, - Cicero, - Pixel, - TypeCount //!< @internal - }; - - //! Used to control the scope of the unit types listed in the UI - enum class ListOption { - All = 0, - HidePixel = 1 - }; - Q_DECLARE_FLAGS(ListOptions, ListOption) - - /** Returns a KPropertyUnit instance with the type at the @p index of the UI list with the given @p listOptions. */ - static KPropertyUnit fromListForUi(int index, ListOptions listOptions = ListOption::All, qreal factor = 1.0); - - //! Convert a unit symbol string into a KPropertyUnit - //! @param symbol symbol to convert - //! @param ok if set, it will be true if the unit was known, false if unknown - static KPropertyUnit fromSymbol(const QString &symbol, bool *ok = 0); - - /** Construction requires initialization. The factor is for variable factor units like pixel */ - explicit KPropertyUnit(Type unit = Type::Point, qreal factor = 1.0) { - m_type = unit; - m_pixelConversion = factor; - } - - KPropertyUnit& operator=(Type unit) { - m_type = unit; m_pixelConversion = 1.0; return *this; - } - - bool operator!=(const KPropertyUnit &other) const { - return !operator==(other); - } - - bool operator==(const KPropertyUnit &other) const { - return m_type == other.m_type && - (m_type != Type::Pixel || - qFuzzyCompare(m_pixelConversion, other.m_pixelConversion)); - } - - KPropertyUnit::Type type() const { - return m_type; - } - - void setFactor(qreal factor) { - m_pixelConversion = factor; - } - /** - * Prepare ptValue to be displayed in pt - * This method will round to 0.001 precision - */ - static qreal toPoint(qreal ptValue) { - // No conversion, only rounding (to 0.001 precision) - return floor(ptValue * 1000.0) / 1000.0; - } - - /** - * Prepare ptValue to be displayed in mm - * This method will round to 0.0001 precision, use POINT_TO_MM() for lossless conversion. - */ - static qreal toMillimeter(qreal ptValue) { - // "mm" values are rounded to 0.0001 millimeters - return floor(POINT_TO_MM(ptValue) * 10000.0) / 10000.0; - } - - /** - * Prepare ptValue to be displayed in cm - * This method will round to 0.0001 precision, use POINT_TO_CM() for lossless conversion. - */ - static qreal toCentimeter(qreal ptValue) { - return floor(POINT_TO_CM(ptValue) * 10000.0) / 10000.0; - } - - /** - * Prepare ptValue to be displayed in dm - * This method will round to 0.0001 precision, use POINT_TO_DM() for lossless conversion. - */ - static qreal toDecimeter(qreal ptValue) { - return floor(POINT_TO_DM(ptValue) * 10000.0) / 10000.0; - } - - /** - * Prepare ptValue to be displayed in inch - * This method will round to 0.00001 precision, use POINT_TO_INCH() for lossless conversion. - */ - static qreal toInch(qreal ptValue) { - // "in" values are rounded to 0.00001 inches - return floor(POINT_TO_INCH(ptValue) * 100000.0) / 100000.0; - } - - /** - * Prepare ptValue to be displayed in pica - * This method will round to 0.00001 precision, use POINT_TO_PI() for lossless conversion. - */ - static qreal toPica(qreal ptValue) { - // "pi" values are rounded to 0.00001 inches - return floor(POINT_TO_PI(ptValue) * 100000.0) / 100000.0; - } - - /** - * Prepare ptValue to be displayed in cicero - * This method will round to 0.00001 precision, use POINT_TO_CC() for lossless conversion. - */ - static qreal toCicero(qreal ptValue) { - // "cc" values are rounded to 0.00001 inches - return floor(POINT_TO_CC(ptValue) * 100000.0) / 100000.0; - } - - /** - * convert the given value directly from one unit to another - */ - static qreal convertFromUnitToUnit(qreal value, const KPropertyUnit &fromUnit, const KPropertyUnit &toUnit, qreal factor = 1.0); - - /** - * This method is the one to use to display a value in a dialog - * \return the value @p ptValue converted to unit and rounded, ready to be displayed - */ - qreal toUserValue(qreal ptValue) const; - - /** - * Convert the value @p ptValue to a given unit @p unit - * Unlike KPropertyUnit::ptToUnit the return value remains unrounded, so that it can be used in complex calculation - * \return the converted value - */ - static qreal ptToUnit(qreal ptValue, const KPropertyUnit &unit); - - //! This method is the one to use to display a value in a dialog - //! @return the value @p ptValue converted the unit and rounded, ready to be displayed - QString toUserStringValue(qreal ptValue) const; - - //! This method is the one to use to read a value from a dialog - //! @return the value converted to points for internal use - qreal fromUserValue(qreal value) const; - - //! This method is the one to use to read a value from a dialog - //! @param value value entered by the user - //! @param ok if set, the pointed bool is set to true if the value could be - //! converted to a qreal, and to false otherwise. - //! @return the value converted to points for internal use - qreal fromUserValue(const QString &value, bool *ok = 0) const; - - //! Get the description string of the given unit - static QString unitDescription(KPropertyUnit::Type type); - - //! Get the symbol string of the unit - QString symbol() const; - - //! Returns the list of unit types for the UI, controlled with the given @p listOptions. - static QStringList listOfUnitNameForUi(ListOptions listOptions = ListOption::All); - - //! Get the index of this unit in the list of unit types for the UI, - //! if it is controlled with the given @p listOptions. - int indexInListForUi(ListOptions listOptions = ListOption::All) const; - - /** - * Parses common %KProperty and ODF values, like "10cm", "5mm" to pt. - * If no unit is specified, pt is assumed. - */ - static qreal parseValue(const QString &value, qreal defaultVal = 0.0); - - //! Parse an angle to its value in degrees - static qreal parseAngle(const QString &value, qreal defaultVal = 0.0); - - //! Equal to symbol(): returns the symbol string of the unit. - inline QString toString() const { - return symbol(); - } - -private: - Type m_type; - qreal m_pixelConversion; -}; - -#ifndef QT_NO_DEBUG_STREAM -KPROPERTYCORE_EXPORT QDebug operator<<(QDebug, const KPropertyUnit &); -#endif - -Q_DECLARE_METATYPE(KPropertyUnit) -Q_DECLARE_OPERATORS_FOR_FLAGS(KPropertyUnit::ListOptions) - -#endif diff --git a/src/KPropertyUtils_p.cpp b/src/KPropertyUtils_p.cpp index eddca85..eabf09c 100644 --- a/src/KPropertyUtils_p.cpp +++ b/src/KPropertyUtils_p.cpp @@ -1,397 +1,427 @@ /* This file is part of the KDE project - Copyright (C) 2010-2016 Jarosław Staniek + Copyright (C) 2010-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 "KPropertyUtils_p.h" #include "KPropertyEditorView.h" +#include "KProperty.h" #include #if defined KPropertyCore_EXPORTS || defined KPropertyWidgets_EXPORTS #include "kproperty_debug.h" #else # define kprDebug qDebug # define kprWarning qWarning # define kprCritical qCritical #endif #include #include #include #include #include #include #include #include #ifdef KPROPERTY_KF #include #include #include #else #include #endif #ifdef QT_GUI_LIB #include #endif class QColor; class QWidget; namespace KPropertyUtilsPrivate { void showMessageBox(QWidget *parent, const QString &errorMessage, const QString &detailedErrorMessage) { if (detailedErrorMessage.isEmpty()) { #ifdef KPROPERTY_KF KMessageBox::error(parent, errorMessage); #else QMessageBox::warning(parent, QString(), errorMessage); #endif } else { #ifdef KPROPERTY_KF KMessageBox::detailedError(parent, errorMessage, detailedErrorMessage); #else QMessageBox::warning(parent, QString(), errorMessage + QLatin1Char('\n') + detailedErrorMessage); #endif } } // -- icon support QString supportedIconTheme() { return QLatin1String("breeze"); } //! @brief @return true if @a path is readable bool fileReadable(const QString &path) { return !path.isEmpty() && QFileInfo(path).isReadable(); } //! @brief Used for a workaround: locations for QStandardPaths::AppDataLocation end with app name. //! If this is not an expected app but for example a test app, replace //! the subdir name with app name so we can find resource file(s). QStringList correctStandardLocations(const QString &privateName, QStandardPaths::StandardLocation location, const QString &extraLocation) { QSet result; if (!privateName.isEmpty()) { QRegularExpression re(QLatin1Char('/') + QCoreApplication::applicationName() + QLatin1Char('$')); QStringList standardLocations(QStandardPaths::standardLocations(location)); if (!extraLocation.isEmpty()) { standardLocations.append(extraLocation); } for(const QString &dir : standardLocations) { if (dir.indexOf(re) != -1) { QString realDir(dir); realDir.replace(re, QLatin1Char('/') + privateName); result.insert(realDir); } } } return result.toList(); } #ifdef Q_OS_WIN #define KPATH_SEPARATOR ';' #else #define KPATH_SEPARATOR ':' #endif /*! @brief Locates a file path for specified parameters * @param privateName Name to be used instead of application name for resource lookup * @param path Relative path to the resource file * @param location Standard file location to use for file lookup * @param extraLocation Extra directory path for file lookup * @return Empty string on failure */ QString locateFile(const QString &privateName, const QString& path, QStandardPaths::StandardLocation location, const QString &extraLocation) { // let QStandardPaths handle this, it will look for app local stuff QString fullPath = QFileInfo( QStandardPaths::locate(location, path)).canonicalFilePath(); if (fileReadable(fullPath)) { return fullPath; } // Try extra location fullPath = QFileInfo(extraLocation + QLatin1Char('/') + path).canonicalFilePath(); if (fileReadable(fullPath)) { return fullPath; } // Try in PATH subdirs, useful for running apps from the build dir, without installing for(const QByteArray &pathDir : qgetenv("PATH").split(KPATH_SEPARATOR)) { const QString dataDirFromPath = QFileInfo(QFile::decodeName(pathDir) + QStringLiteral("/data/") + path).canonicalFilePath(); if (fileReadable(dataDirFromPath)) { return dataDirFromPath; } } const QStringList correctedStandardLocations(correctStandardLocations(privateName, location, extraLocation)); for(const QString &dir : correctedStandardLocations) { fullPath = QFileInfo(dir + QLatin1Char('/') + path).canonicalFilePath(); if (fileReadable(fullPath)) { return fullPath; } } return QString(); } /*! @brief Registers icons resource file * @param privateName Name to be used instead of application name for resource lookup * @param path Relative path to the resource file * @param location Standard file location to use for file lookup * @param resourceRoot A resource root for QResource::registerResource() * @param errorMessage On failure it is set to a brief error message. * @param errorDescription On failure it is set to a detailed error message. * other for warning */ bool registerIconsResource(const QString &privateName, const QString& path, QStandardPaths::StandardLocation location, const QString &resourceRoot, const QString &extraLocation, QString *errorMessage, QString *detailedErrorMessage) { const QString fullPath = locateFile(privateName, path, location, extraLocation); if (fullPath.isEmpty() || !QFileInfo(fullPath).isReadable() || !QResource::registerResource(fullPath, resourceRoot)) { QStringList triedLocations(QStandardPaths::standardLocations(location)); if (!extraLocation.isEmpty()) { triedLocations.append(extraLocation); } triedLocations.append(correctStandardLocations(privateName, location, extraLocation)); const QString triedLocationsString = QLocale().createSeparatedList(triedLocations); #ifdef QT_ONLY *errorMessage = QString("Could not open icon resource file %1.").arg(path); *detailedErrorMessage = QString("Tried to find in %1.").arg(triedLocationsString); #else //! @todo 3.1 Re-add translation *errorMessage = /*QObject::tr*/ QString::fromLatin1( "Could not open icon resource file \"%1\". " "Application will not start. " "Please check if it is properly installed.") .arg(QFileInfo(path).fileName()); //! @todo 3.1 Re-add translation *detailedErrorMessage = QString::fromLatin1("Tried to find in %1.").arg(triedLocationsString); #endif return false; } *errorMessage = QString(); *detailedErrorMessage = QString(); return true; } /*! @brief Registers a global icon resource file * @param themeName A name of icon theme to use. * @param errorMessage On failure it is set to a brief error message. * @param errorDescription On failure it is set to a detailed error message. * other for warning */ bool registerGlobalIconsResource(const QString &themeName, QString *errorMessage, QString *detailedErrorMessage) { QString extraLocation; #ifdef CMAKE_INSTALL_FULL_ICONDIR extraLocation = QDir::fromNativeSeparators(QFile::decodeName(CMAKE_INSTALL_FULL_ICONDIR)); if (extraLocation.endsWith("/icons")) { extraLocation.chop(QLatin1String("/icons").size()); } #elif defined(Q_OS_WIN) extraLocation = QCoreApplication::applicationDirPath() + QStringLiteral("/data"); #endif return registerIconsResource(QString(), QString::fromLatin1("icons/%1/%1-icons.rcc").arg(themeName), QStandardPaths::GenericDataLocation, QStringLiteral("/icons/") + themeName, extraLocation, errorMessage, detailedErrorMessage); } /*! @brief Registers a global icon resource file * @param themeName A name of icon theme to use. */ bool registerGlobalIconsResource(const QString &themeName) { QString errorMessage; QString detailedErrorMessage; if (!registerGlobalIconsResource(themeName, &errorMessage, &detailedErrorMessage)) { showMessageBox(nullptr, errorMessage, detailedErrorMessage); kprWarning() << qPrintable(errorMessage); return false; } return true; } /*! @brief Registers a global icon resource file for default theme name. */ bool registerGlobalIconsResource() { return registerGlobalIconsResource(supportedIconTheme()); } /*! @brief Sets up a private icon resource file * @return @c false on failure and sets error message. Does not warn or exit on failure. * @param privateName Name to be used instead of application name for resource lookup * @param path Relative path to the resource file * @param themeName Icon theme to use. It affects filename. * @param errorMessage On failure it is set to a brief error message * @param errorDescription On failure it is set to a detailed error message * other for warning * @param prefix Resource path prefix. The default is useful for library-global resource, * other values is useful for plugins. */ bool setupPrivateIconsResource(const QString &privateName, const QString& path, const QString &themeName, QString *errorMessage, QString *detailedErrorMessage, const QString &prefix = QLatin1String(":/icons")) { // Register application's resource first to have priority over the theme. // Some icons may exists in both resources. QString extraLocation = QCoreApplication::applicationDirPath() + QStringLiteral("/data"); if (!registerIconsResource(privateName, path, QStandardPaths::AppDataLocation, QString(), QString(), errorMessage, detailedErrorMessage)) { return false; } bool changeTheme = false; #ifdef QT_GUI_LIB QIcon::setThemeSearchPaths(QStringList() << prefix << QIcon::themeSearchPaths()); changeTheme = 0 != QIcon::themeName().compare(themeName, Qt::CaseInsensitive); if (changeTheme) { QIcon::setThemeName(themeName); } #endif #ifdef KPROPERTY_KF KConfigGroup cg(KSharedConfig::openConfig(), "Icons"); changeTheme = changeTheme || 0 != cg.readEntry("Theme", QString()).compare(themeName, Qt::CaseInsensitive); // tell KIconLoader an co. about the theme if (changeTheme) { cg.writeEntry("Theme", themeName); cg.sync(); } #endif return true; } /*! @brief Sets up a private icon resource file * @return @c false on failure and sets error message. * @param privateName Name to be used instead of application name for resource lookup * @param path Relative path to the resource file * @param themeName Icon theme to use. It affects filename. * @param errorMessage On failure it is set to a brief error message. * @param errorDescription On failure it is set to a detailed error message. * other for warning * @param prefix Resource path prefix. The default is useful for library-global resource, * other values is useful for plugins. */ bool setupPrivateIconsResourceWithMessage(const QString &privateName, const QString& path, const QString &themeName, QString *errorMessage, QString *detailedErrorMessage, const QString &prefix = QLatin1String(":/icons")) { if (!setupPrivateIconsResource(privateName, path, themeName, errorMessage, detailedErrorMessage, prefix)) { showMessageBox(nullptr, *errorMessage, *detailedErrorMessage); return false; } return true; } /*! @overload setupPrivateIconsResourceWithMessage(QString &privateName, const QString& path, const QString &themeName, QString *errorMessage, QString *detailedErrorMessage, const QString &prefix = QLatin1String(":/icons")) Uses default theme name. */ bool setupPrivateIconsResourceWithMessage(const QString &privateName, const QString& path, QString *errorMessage, QString *detailedErrorMessage, const QString &prefix = QLatin1String(":/icons")) { return setupPrivateIconsResourceWithMessage(privateName, path, supportedIconTheme(), errorMessage, detailedErrorMessage, prefix); } bool setupPrivateIconsResourceWithMessage(const QString &privateName, const QString& path, QtMsgType messageType, const QString &prefix) { QString errorMessage; QString detailedErrorMessage; if (!setupPrivateIconsResourceWithMessage(privateName, path, &errorMessage, &detailedErrorMessage, prefix)) { if (messageType == QtFatalMsg) { kprCritical() << qPrintable(errorMessage) << qPrintable(detailedErrorMessage); } else { kprWarning() << qPrintable(errorMessage) << qPrintable(detailedErrorMessage); } return false; } return true; } bool setupGlobalIconTheme() { if (0 != QIcon::themeName().compare(supportedIconTheme(), Qt::CaseInsensitive)) { const QString message = QString::fromLatin1( "\"%1\" supports only \"%2\" icon theme but current system theme is \"%3\". " "Application's icon theme will be changed to \"%2\". " "Please consider adding support for other themes to %4.") .arg(QLatin1String(KPROPERTYWIDGETS_BASE_NAME)).arg(supportedIconTheme()).arg(QIcon::themeName()) .arg(QCoreApplication::applicationName()); kprDebug() << qPrintable(message); if (!registerGlobalIconsResource()) { // don't fail, just warn const QString message = QString::fromLatin1( "Failed to set icon theme to \"%1\". Icons in the application will be inconsistent. " "Please install .rcc file(s) for the system theme.") .arg(supportedIconTheme()); kprDebug() << qPrintable(message); return false; } } return true; } // ---- +ValueOptionsHandler::ValueOptionsHandler(const KProperty &property) +{ + minValueText = property.option("minValueText").toString(); + prefix = property.option("prefix").toString().trimmed(); + suffix = property.option("suffix").toString().trimmed(); +} + +QString ValueOptionsHandler::valueWithPrefixAndSuffix(const QString &valueString, const QLocale &locale) const +{ + QString result = valueString; + if (!suffix.isEmpty()) { + if (locale.language() == QLocale::C) { + result = QString::fromLatin1("%1 %2").arg(result).arg(suffix); + } else { + result = QObject::tr("%1 %2", " ").arg(result).arg(suffix); + } + } + if (!prefix.isEmpty()) { + if (locale.language() == QLocale::C) { + result = QString::fromLatin1("%1 %2").arg(prefix).arg(result); + } else { + result = QObject::tr("%1 %2", " ").arg(prefix).arg(result); + } + } + return result; +} + +// ---- + PainterSaver::PainterSaver(QPainter *p) : m_painter(p) { if (m_painter) { m_painter->save(); } } PainterSaver::~PainterSaver() { if (m_painter) { m_painter->restore(); } } } // namespace KPropertyUtilsPrivate diff --git a/src/KPropertyUtils_p.h b/src/KPropertyUtils_p.h index 4031971..db8761f 100644 --- a/src/KPropertyUtils_p.h +++ b/src/KPropertyUtils_p.h @@ -1,86 +1,102 @@ /* This file is part of the KDE project - Copyright (C) 2010-2016 Jarosław Staniek + Copyright (C) 2010-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_UTILS_P_H #define KPROPERTY_UTILS_P_H #include #include +class KProperty; + namespace KPropertyUtilsPrivate { //! @return contrast color for @a c color. QColor contrastColor(const QColor& c); //! @return grid line color defined by a KPropertyEditorView widget contains @a widget //! Invalid color is returned if no grid is defined or KPropertyEditorView was not found. QColor gridLineColor(const QWidget *widget); //! @return supported icon theme //! @todo Support other themes QString supportedIconTheme(); /*! @brief Sets up a private icon resource file * Warns on failure and returns @c false. * @param privateName Name to be used instead of application name for resource lookup * @param path Relative path to the resource file * @param messageType Type of message to use on error, QtFatalMsg for fatal exit and any * other for warning * @param prefix Resource path prefix. The default is useful for library-global resource, * other values is useful for plugins. */ bool setupPrivateIconsResourceWithMessage(const QString &privateName, const QString& path, QtMsgType messageType, const QString &prefix = QLatin1String(":/icons")); //! Sets up a global icon theme if it is different from supported. //! Warns on failure and returns @c false. bool setupGlobalIconTheme(); +//! Helper for handling minValueText, prefix and suffix property options +class ValueOptionsHandler +{ +public: + explicit ValueOptionsHandler(const KProperty &property); + + //! @return @a valueString value with prefix and suffix, if present + QString valueWithPrefixAndSuffix(const QString &valueString, const QLocale &locale) const; + + QString minValueText; + QString prefix; + QString suffix; +}; + //! @short Manages the QPainter::save()/QPainter::restore() block using RAII /*! The PainterSaver class makes sure that restore() is called when exiting from the block of code. Instead of: @code painter.save(); // (code) painter.restore(); @endcode Use this: @code const PainterSaver saver(&painter); // (code) @endcode */ class PainterSaver { public: explicit PainterSaver(QPainter *p); ~PainterSaver(); private: QPainter* const m_painter; }; } // namespace KPropertyUtilsPrivate #endif diff --git a/src/KPropertyWidgetsFactory.cpp b/src/KPropertyWidgetsFactory.cpp index ce6e833..21c27d0 100644 --- a/src/KPropertyWidgetsFactory.cpp +++ b/src/KPropertyWidgetsFactory.cpp @@ -1,229 +1,232 @@ /* 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 "KPropertyFactory.h" #include "KDefaultPropertyFactory.h" #include "KPropertyEditorView.h" #include "KPropertyStringEditor.h" +#include "KPropertyUtils.h" #include "KPropertyUtils_p.h" -KPropertyLabel::KPropertyLabel(QWidget *parent, const KPropertyValueDisplayInterface *iface) - : QLabel(parent) - , m_iface(iface) +KPropertyLabel::KPropertyLabel(QWidget *parent, const KProperty *property, + const KPropertyValueDisplayInterface *iface) + : QLabel(parent), m_property(property), m_iface(iface) { - setAutoFillBackground(true); + setAutoFillBackground(true); - KPropertyEditorView* view = 0; - if (parent) { - view = qobject_cast(parent->parentWidget()); - } - const QColor gridLineColor(view ? view->gridLineColor() : KPropertyEditorView::defaultGridLineColor()); - const int top = 1 + (gridLineColor.isValid() ? 1 : 0); + KPropertyEditorView *view = 0; + if (parent) { + view = qobject_cast(parent->parentWidget()); + } + const QColor gridLineColor(view ? view->gridLineColor() + : KPropertyEditorView::defaultGridLineColor()); + const int top = 1 + (gridLineColor.isValid() ? 1 : 0); - setContentsMargins(0, top, 0, 0); - setIndent(1); + setContentsMargins(0, top, 0, 0); + setIndent(1); } QVariant KPropertyLabel::value() const { return m_value; } void KPropertyLabel::setValue(const QVariant& value) { - setText( m_iface->valueToString(value, QLocale()) ); m_value = value; + setText(m_iface->propertyValueToString(m_property, QLocale())); } void KPropertyLabel::paintEvent( QPaintEvent * event ) { QLabel::paintEvent(event); KPropertyWidgetsFactory::paintTopGridLine(this); } //--------------- //! @internal class Q_DECL_HIDDEN KPropertyWidgetsFactory::Private { public: Private() { } ~Private() { qDeleteAll(editorCreatorsSet); qDeleteAll(valuePaintersSet); } QHash editorCreators; QHash valuePainters; QSet editorCreatorsSet; QSet valuePaintersSet; }; KPropertyWidgetsFactory::KPropertyWidgetsFactory() : d( new Private ) { } KPropertyWidgetsFactory::~KPropertyWidgetsFactory() { delete d; } QHash KPropertyWidgetsFactory::editorCreators() const { return d->editorCreators; } QHash KPropertyWidgetsFactory::valuePainters() const { return d->valuePainters; } void KPropertyWidgetsFactory::addEditor(int type, KPropertyEditorCreatorInterface *creator) { addEditorInternal( type, creator, true ); if (dynamic_cast(creator)) { addComposedPropertyCreatorInternal( type, dynamic_cast(creator), false/* !own*/ ); } if (dynamic_cast(creator)) { addPainterInternal( type, dynamic_cast(creator), false/* !own*/ ); } if (dynamic_cast(creator)) { addDisplayInternal( type, dynamic_cast(creator), false/* !own*/ ); } } void KPropertyWidgetsFactory::addPainter(int type, KPropertyValuePainterInterface *painter) { addPainterInternal(type, painter, true); if (dynamic_cast(painter)) { addComposedPropertyCreatorInternal( type, dynamic_cast(painter), false/* !own*/ ); } if (dynamic_cast(painter)) { addEditorInternal( type, dynamic_cast(painter), false/* !own*/ ); } if (dynamic_cast(painter)) { addDisplayInternal( type, dynamic_cast(painter), false/* !own*/ ); } } void KPropertyWidgetsFactory::addEditorInternal(int type, KPropertyEditorCreatorInterface *editor, bool own) { if (own) d->editorCreatorsSet.insert(editor); d->editorCreators.insert(type, editor); } void KPropertyWidgetsFactory::addPainterInternal(int type, KPropertyValuePainterInterface *painter, bool own) { if (own) d->valuePaintersSet.insert(painter); d->valuePainters.insert(type, painter); } //static void KPropertyWidgetsFactory::paintTopGridLine(QWidget *widget) { // paint top grid line KPropertyEditorView* view = 0; if (widget->parentWidget()) { view = qobject_cast(widget->parentWidget()->parentWidget()); } const QColor gridLineColor(view ? view->gridLineColor() : KPropertyEditorView::defaultGridLineColor()); if (gridLineColor.isValid()) { const QAbstractScrollArea *area = qobject_cast(widget); QWidget *widgetToPaint; if (area && area->viewport()) { widgetToPaint = area->viewport(); } else { widgetToPaint = widget; } QPainter p(widgetToPaint); p.setPen(QPen( QBrush(gridLineColor), 1)); p.drawLine(0, 0, widget->width()-1, 0); } } //static void KPropertyWidgetsFactory::setTopAndBottomBordersUsingStyleSheet(QWidget *widget, const QString& extraStyleSheet) { KPropertyEditorView* view = 0; if (widget->parentWidget()) { view = qobject_cast(widget->parentWidget()->parentWidget()); } const QColor gridLineColor(view ? view->gridLineColor() : KPropertyEditorView::defaultGridLineColor()); widget->setStyleSheet( QString::fromLatin1("%1 { border-top: 1px solid %2;border-bottom: 1px solid %2; } %3") .arg(QLatin1String(widget->metaObject()->className())) .arg(gridLineColor.name()).arg(extraStyleSheet)); } //------------ KPropertyEditorCreatorInterface::KPropertyEditorCreatorInterface() { } KPropertyEditorCreatorInterface::~KPropertyEditorCreatorInterface() { } QWidget* KPropertyEditorCreatorInterface::createEditor(int type, QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index) const { Q_UNUSED(type); Q_UNUSED(option); Q_UNUSED(index); return new KPropertyStringEditor(parent); } KPropertyEditorCreatorInterface::Options::Options() : removeBorders(true) { } KPropertyValuePainterInterface::KPropertyValuePainterInterface() { } KPropertyValuePainterInterface::~KPropertyValuePainterInterface() { } //static void KPropertyValuePainterInterface::paint(const KPropertyValueDisplayInterface *iface, QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) { const KPropertyUtilsPrivate::PainterSaver saver(painter); QRect r(option.rect); - r.setLeft(r.left()+1); - painter->drawText( r, Qt::AlignLeft | Qt::AlignVCenter, - iface->valueToString(index.data(Qt::EditRole), QLocale())); + r.setLeft(r.left() + 1); + KProperty *prop = KPropertyUtils::propertyForIndex(index); + painter->drawText(r, Qt::AlignLeft | Qt::AlignVCenter, + iface->propertyValueToString(prop, QLocale())); } diff --git a/src/KPropertyWidgetsFactory.h b/src/KPropertyWidgetsFactory.h index 1a2437a..2302f27 100644 --- a/src/KPropertyWidgetsFactory.h +++ b/src/KPropertyWidgetsFactory.h @@ -1,160 +1,161 @@ /* This file is part of the KDE project Copyright (C) 2008-2015 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KPROPERTYWIDGETS_FACTORY_H #define KPROPERTYWIDGETS_FACTORY_H -#include "kpropertywidgets_export.h" #include "KProperty.h" #include "KPropertyFactory.h" +#include "KPropertyUtils.h" #include #include #include #include #include #include //! An interface for editor widget creators. /*! Options can be set in the options attribute in order to customize widget creation process. Do this in the EditorCreatorInterface constructor. */ class KPROPERTYWIDGETS_EXPORT KPropertyEditorCreatorInterface { public: KPropertyEditorCreatorInterface(); virtual ~KPropertyEditorCreatorInterface(); virtual QWidget * createEditor(int type, QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; /*! Options for altering the editor widget creation process, used by KPropertyFactoryManager::createEditor(). */ class Options { public: Options(); /*! In order to have better look of the widget within the property editor view, we usually remove borders from the widget (see FactoryManager::createEditor()). and adding 1 pixel 'gray border' on the top. Default value is true. */ bool removeBorders; }; //! Options for altering the editor widget creation process Options options; }; class KPROPERTYWIDGETS_EXPORT KPropertyValuePainterInterface { public: KPropertyValuePainterInterface(); virtual ~KPropertyValuePainterInterface(); virtual void paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const = 0; //! A helper that draws text obtained from index (EditRole data) on painter @a painter. //! iface->valueToString() is used to convert value to string. //! @since 3.1 static void paint(const KPropertyValueDisplayInterface *iface, QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index); }; //! Label widget that can be used for displaying text-based read-only items //! Used in KPropertyLabelCreator. class KPROPERTYWIDGETS_EXPORT KPropertyLabel : public QLabel { Q_OBJECT Q_PROPERTY(QVariant value READ value WRITE setValue USER true) public: - KPropertyLabel(QWidget *parent, const KPropertyValueDisplayInterface *iface); + KPropertyLabel(QWidget *parent, const KProperty *property, const KPropertyValueDisplayInterface *iface); QVariant value() const; Q_SIGNALS: void commitData( QWidget * editor ); public Q_SLOTS: void setValue(const QVariant& value); protected: virtual void paintEvent( QPaintEvent * event ); private: + const KProperty *m_property; const KPropertyValueDisplayInterface *m_iface; QVariant m_value; }; //! Creator returning editor template class KPROPERTYWIDGETS_EXPORT KPropertyEditorCreator : public KPropertyEditorCreatorInterface, public KPropertyValueDisplayInterface, public KPropertyValuePainterInterface { public: KPropertyEditorCreator() : KPropertyEditorCreatorInterface() {} virtual ~KPropertyEditorCreator() {} virtual QWidget * createEditor( int type, QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const { Q_UNUSED(type); Q_UNUSED(option); - Q_UNUSED(index); - return new Widget(parent, this); + KProperty *prop = KPropertyUtils::propertyForIndex(index); + return new Widget(parent, prop, this); } virtual void paint(QPainter *painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { KPropertyValuePainterInterface::paint(this, painter, option, index); } }; typedef KPropertyEditorCreator KPropertyLabelCreator; class KPROPERTYWIDGETS_EXPORT KPropertyWidgetsFactory : public KPropertyFactory { public: KPropertyWidgetsFactory(); virtual ~KPropertyWidgetsFactory(); QHash editorCreators() const; QHash valuePainters() const; //! Adds editor creator @a creator for type @a type. //! The creator becomes owned by the factory. void addEditor(int type, KPropertyEditorCreatorInterface *creator); void addPainter(int type, KPropertyValuePainterInterface *painter); static void paintTopGridLine(QWidget *widget); static void setTopAndBottomBordersUsingStyleSheet(QWidget *widget, const QString& extraStyleSheet = QString()); protected: void addEditorInternal(int type, KPropertyEditorCreatorInterface *editor, bool own = true); //! Adds value painter @a painter for type @a type. //! The painter becomes owned by the factory. void addPainterInternal(int type, KPropertyValuePainterInterface *painter, bool own = true); class Private; Private * const d; }; #endif diff --git a/src/editors/KPropertyRectFEditor.cpp b/src/editors/KPropertyRectFEditor.cpp index e064c0b..37185ec 100644 --- a/src/editors/KPropertyRectFEditor.cpp +++ b/src/editors/KPropertyRectFEditor.cpp @@ -1,91 +1,99 @@ /* This file is part of the KDE project - Copyright (C) 2015 Jarosław Staniek + Copyright (C) 2015-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 "KPropertyRectFEditor.h" +#include "KPropertyUtils_p.h" #include KPropertyRectFDelegate::KPropertyRectFDelegate() { } +QString KPropertyRectFDelegate::propertyValueToString(const KProperty *property, + const QLocale &locale) const +{ + const KPropertyUtilsPrivate::ValueOptionsHandler options(*property); + return options.valueWithPrefixAndSuffix(valueToString(property->value(), locale), locale); +} + QString KPropertyRectFDelegate::valueToString(const QVariant& value, const QLocale &locale) const { const QRectF r(value.toRectF()); if (r.isNull()) { if (locale.language() == QLocale::C) { return QString(); } return QObject::tr("None", "Null value"); } if (locale.language() == QLocale::C) { return QString::fromLatin1("%1, %2, %3x%4").arg(r.x()).arg(r.y()).arg(r.width()).arg(r.height()); } return QObject::tr("%1, %2, %3x%4", "Rectangle") .arg(locale.toString(r.x())) .arg(locale.toString(r.y())) .arg(locale.toString(r.width())) .arg(locale.toString(r.height())); } //------------ KRectFComposedProperty::KRectFComposedProperty(KProperty *property) : KComposedPropertyInterface(property) { (void)new KProperty("x", QVariant(), QObject::tr("X", "Property: X coordinate"), QObject::tr("X Coordinate", "Property: X coordinate"), KProperty::Double, property); (void)new KProperty("y", QVariant(), QObject::tr("Y", "Property: Y coordinate"), QObject::tr("Y Coordinate", "Property: Y coordinate"), KProperty::Double, property); (void)new KProperty("width", QVariant(), QObject::tr("Width", "Property: width of rectangle"), QObject::tr("Width", "Property: width of rectangle"), KProperty::Double, property); (void)new KProperty("height", QVariant(), QObject::tr("Height", "Property: height of rectangle"), QObject::tr("Height", "Property: height of rectangle"), KProperty::Double, property); } void KRectFComposedProperty::setValue(KProperty *property, const QVariant &value, KProperty::ValueOptions valueOptions) { const QRectF r(value.toRectF()); property->child("x")->setValue(r.x(), valueOptions); property->child("y")->setValue(r.y(), valueOptions); property->child("width")->setValue(r.width(), valueOptions); property->child("height")->setValue(r.height(), valueOptions); } void KRectFComposedProperty::childValueChanged(KProperty *child, const QVariant &value, KProperty::ValueOptions valueOptions) { QRectF r(child->parent()->value().toRectF()); if (child->name() == "x") r.moveLeft(value.toReal()); else if (child->name() == "y") r.moveTop(value.toReal()); else if (child->name() == "width") r.setWidth(value.toReal()); else if (child->name() == "height") r.setHeight(value.toReal()); child->parent()->setValue(r, valueOptions); } diff --git a/src/editors/KPropertyRectFEditor.h b/src/editors/KPropertyRectFEditor.h index 3c363f6..6cb27c0 100644 --- a/src/editors/KPropertyRectFEditor.h +++ b/src/editors/KPropertyRectFEditor.h @@ -1,46 +1,49 @@ /* This file is part of the KDE project - Copyright (C) 2015 Jarosław Staniek + Copyright (C) 2015-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_RECTFEDITOR_H #define KPROPERTY_RECTFEDITOR_H #include "KPropertyWidgetsFactory.h" class KPROPERTYWIDGETS_EXPORT KRectFComposedProperty : public KComposedPropertyInterface { public: explicit KRectFComposedProperty(KProperty *parent); virtual void setValue(KProperty *property, const QVariant &value, KProperty::ValueOptions valueOptions); virtual void childValueChanged(KProperty *child, const QVariant &value, KProperty::ValueOptions valueOptions); }; class KPROPERTYWIDGETS_EXPORT KPropertyRectFDelegate : public KPropertyLabelCreator, public KComposedPropertyCreator { public: KPropertyRectFDelegate(); + QString propertyValueToString(const KProperty *property, + const QLocale &locale) const override; + virtual QString valueToString(const QVariant& value, const QLocale &locale) const; }; #endif diff --git a/src/editors/pointfedit.cpp b/src/editors/pointfedit.cpp index 408dd64..1b16a45 100644 --- a/src/editors/pointfedit.cpp +++ b/src/editors/pointfedit.cpp @@ -1,80 +1,88 @@ /* 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 + Copyright (C) 2008-2017 Jarosław Staniek Copyright (C) 2010 Adam Pigg 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 "pointfedit.h" +#include "KPropertyUtils_p.h" #include KPropertyPointFDelegate::KPropertyPointFDelegate() { } +QString KPropertyPointFDelegate::propertyValueToString(const KProperty *property, + const QLocale &locale) const +{ + const KPropertyUtilsPrivate::ValueOptionsHandler options(*property); + return options.valueWithPrefixAndSuffix(valueToString(property->value(), locale), locale); +} + QString KPropertyPointFDelegate::valueToString(const QVariant& value, const QLocale &locale) const { const QPointF p(value.toPointF()); if (p.isNull()) { if (locale.language() == QLocale::C) { return QString(); } return QObject::tr("None", "Null value"); } if (locale.language() == QLocale::C) { return QString::fromLatin1("%1, %2").arg(p.x()).arg(p.y()); } return QObject::tr("%1, %2", "Point") .arg(locale.toString(p.x())) .arg(locale.toString(p.y())); } //------------ KPointFComposedProperty::KPointFComposedProperty(KProperty *property) : KComposedPropertyInterface(property) { (void)new KProperty("x", QVariant(), QObject::tr("X", "Property: X coordinate"), QObject::tr("X Coordinate", "Property: X coordinate"), KProperty::Double, property); (void)new KProperty("y", QVariant(), QObject::tr("Y", "Property: Y coordinate"), QObject::tr("Y Coordinate", "Property: Y coordinate"), KProperty::Double, property); } void KPointFComposedProperty::setValue(KProperty *property, const QVariant &value, KProperty::ValueOptions valueOptions) { const QPointF p( value.toPointF() ); property->child("x")->setValue(p.x(), valueOptions); property->child("y")->setValue(p.y(), valueOptions); } void KPointFComposedProperty::childValueChanged(KProperty *child, const QVariant &value, KProperty::ValueOptions valueOptions) { QPointF p( child->parent()->value().toPointF() ); if (child->name() == "x") p.setX(value.toDouble()); else if (child->name() == "y") p.setY(value.toDouble()); child->parent()->setValue(p, valueOptions); } diff --git a/src/editors/pointfedit.h b/src/editors/pointfedit.h index ea11625..4546e9f 100644 --- a/src/editors/pointfedit.h +++ b/src/editors/pointfedit.h @@ -1,49 +1,52 @@ /* 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 Copyright (C) 2010 Adam Pigg 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_POINTFEDIT_H #define KPROPERTY_POINTFEDIT_H #include "KPropertyWidgetsFactory.h" class KPROPERTYWIDGETS_EXPORT KPointFComposedProperty : public KComposedPropertyInterface { public: explicit KPointFComposedProperty(KProperty *parent); virtual void setValue(KProperty *property, const QVariant &value, KProperty::ValueOptions valueOptions); virtual void childValueChanged(KProperty *child, const QVariant &value, KProperty::ValueOptions valueOptions); }; class KPROPERTYWIDGETS_EXPORT KPropertyPointFDelegate : public KPropertyLabelCreator, public KComposedPropertyCreator { public: KPropertyPointFDelegate(); + QString propertyValueToString(const KProperty *property, + const QLocale &locale) const override; + virtual QString valueToString(const QVariant& value, const QLocale &locale) const; }; #endif diff --git a/src/editors/sizefedit.cpp b/src/editors/sizefedit.cpp index eb85a7d..8157a33 100644 --- a/src/editors/sizefedit.cpp +++ b/src/editors/sizefedit.cpp @@ -1,74 +1,82 @@ /* This file is part of the KDE project - Copyright (C) 2008-2015 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 "sizefedit.h" +#include "KPropertyUtils_p.h" #include KPropertySizeFDelegate::KPropertySizeFDelegate() { } +QString KPropertySizeFDelegate::propertyValueToString(const KProperty *property, + const QLocale &locale) const +{ + const KPropertyUtilsPrivate::ValueOptionsHandler options(*property); + return options.valueWithPrefixAndSuffix(valueToString(property->value(), locale), locale); +} + QString KPropertySizeFDelegate::valueToString(const QVariant& value, const QLocale &locale) const { const QSizeF s(value.toSizeF()); if (s.isNull()) { if (locale.language() == QLocale::C) { return QString(); } return QObject::tr("None", "Null value"); } if (locale.language() == QLocale::C) { return QString::fromLatin1("%1x%2").arg(s.width()).arg(s.height()); } return QObject::tr("%1x%2", "Size") .arg(locale.toString(s.width())) .arg(locale.toString(s.height())); } //------------ KSizeFComposedProperty::KSizeFComposedProperty(KProperty *property) : KComposedPropertyInterface(property) { (void)new KProperty("width", QVariant(), QObject::tr("Width"), QObject::tr("Width"), KProperty::Double, property); (void)new KProperty("height", QVariant(), QObject::tr("Height"), QObject::tr("Height"), KProperty::Double, property); } void KSizeFComposedProperty::setValue(KProperty *property, const QVariant &value, KProperty::ValueOptions valueOptions) { const QSizeF s( value.toSizeF() ); property->child("width")->setValue(s.width(), valueOptions); property->child("height")->setValue(s.height(), valueOptions); } void KSizeFComposedProperty::childValueChanged(KProperty *child, const QVariant &value, KProperty::ValueOptions valueOptions) { QSizeF s( child->parent()->value().toSizeF() ); if (child->name() == "width") s.setWidth(value.toDouble()); else if (child->name() == "height") s.setHeight(value.toDouble()); child->parent()->setValue(s, valueOptions); } diff --git a/src/editors/sizefedit.h b/src/editors/sizefedit.h index c68618b..38a818c 100644 --- a/src/editors/sizefedit.h +++ b/src/editors/sizefedit.h @@ -1,48 +1,51 @@ /* 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 + 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_SIZEFEDIT_H #define KPROPERTY_SIZEFEDIT_H #include "KPropertyWidgetsFactory.h" class KPROPERTYWIDGETS_EXPORT KSizeFComposedProperty : public KComposedPropertyInterface { public: explicit KSizeFComposedProperty(KProperty *parent); virtual void setValue(KProperty *property, const QVariant &value, KProperty::ValueOptions valueOptions); virtual void childValueChanged(KProperty *child, const QVariant &value, KProperty::ValueOptions valueOptions); }; class KPROPERTYWIDGETS_EXPORT KPropertySizeFDelegate : public KPropertyLabelCreator, public KComposedPropertyCreator { public: KPropertySizeFDelegate(); + QString propertyValueToString(const KProperty *property, + const QLocale &locale) const override; + virtual QString valueToString(const QVariant& value, const QLocale &locale) const; }; #endif diff --git a/src/editors/spinbox.cpp b/src/editors/spinbox.cpp index 2f2ddac..bdb0cad 100644 --- a/src/editors/spinbox.cpp +++ b/src/editors/spinbox.cpp @@ -1,349 +1,328 @@ /* 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 + 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 "spinbox.h" #include "KProperty.h" #include "KProperty_p.h" #include "KPropertyEditorView.h" -#include "KPropertyUnit_p.h" #include "KPropertyUtils.h" #include "KPropertyUtils_p.h" #include "KPropertyWidgetsFactory.h" #include "kproperty_debug.h" #include #include #include -#include -#include +#include + +/** + * Maximum double value working precisely. The spin box has localized contents and its code + * supports just this maximum. For a 64-bit machine it's 2**53. + * See also https://phabricator.kde.org/D5419#inline-22329 + */ +#define MAX_PRECISE_DOUBLE (pow(2, std::numeric_limits::digits)) //! @return font size expressed in points (pt) //! or if points are not available - in pixels (px) for @a font static QString fontSizeForCSS(const QFont& font) { return font.pointSize() > 0 ? QString::fromLatin1("%1pt").arg(font.pointSize()) : QString::fromLatin1("%1px").arg(font.pixelSize()); } static QString cssForSpinBox(const char *_class, const QFont& font, int itemHeight) { return QString::fromLatin1( "%5 { border-left: 0; border-right: 0; font-size: %3; } " "%5::down-button { height: %1px; %4 } " "%5::up-button { height: %2px; } " "QLineEdit { border-width:0px; } " ) .arg(itemHeight/2 - 1).arg(itemHeight - itemHeight/2 - 1) .arg(fontSizeForCSS(font)) .arg(QLatin1String((itemHeight/2 <= 9) ? "bottom: 2px;" : "bottom: 0px;")) .arg(QLatin1String(_class)); } +namespace { + +bool intRangeValue(const KProperty &property, QVariant *min, QVariant *max) +{ + Q_ASSERT(min); + Q_ASSERT(max); + *min = property.option("min", (property.type() == KProperty::UInt) ? 0 : -INT_MAX); + *max = property.option("max", INT_MAX); + if (!min->canConvert(QMetaType::Int)) { + min->clear(); + } + if (!max->canConvert(QMetaType::Int)) { + max->clear(); + } + return min->isValid() && max->isValid() && min->toInt() <= max->toInt(); +} + +} // namespace + KPropertyIntSpinBox::KPropertyIntSpinBox(const KProperty* prop, QWidget *parent, int itemHeight) : QSpinBox(parent) , m_unsigned(prop->type() == KProperty::UInt) { QLineEdit* le = findChild(); setContentsMargins(0,0,0,0); if (le) { le->setAlignment(Qt::AlignLeft); le->setContentsMargins(0,0,0,0); } setFrame(true); QString css = cssForSpinBox("QSpinBox", font(), itemHeight); KPropertyWidgetsFactory::setTopAndBottomBordersUsingStyleSheet(this, css); setStyleSheet(css); - QVariant minVal(prop->option("min", m_unsigned ? 0 : -INT_MAX)); - QVariant maxVal(prop->option("max", INT_MAX)); - setMinimum(minVal.toInt()); - setMaximum(maxVal.toInt()); - QString minValueText(prop->option("minValueText").toString()); - if (!minValueText.isEmpty()) - setSpecialValueText(minValueText); + QVariant minVal; + QVariant maxVal; + if (intRangeValue(*prop, &minVal, &maxVal)) { + setRange(minVal.toInt(), maxVal.toInt()); + } + const KPropertyUtilsPrivate::ValueOptionsHandler options(*prop); + if (!options.minValueText.isEmpty()) { + setSpecialValueText(options.minValueText); + } + if (!options.prefix.isEmpty()) { + setPrefix(options.prefix + QLatin1Char(' ')); + } + if (!options.suffix.isEmpty()) { + setSuffix(QLatin1Char(' ') + options.suffix); + } connect(this, SIGNAL(valueChanged(int)), this, SLOT(slotValueChanged(int))); } KPropertyIntSpinBox::~KPropertyIntSpinBox() { } QVariant KPropertyIntSpinBox::value() const { if (m_unsigned) return uint(QSpinBox::value()); return QSpinBox::value(); } void KPropertyIntSpinBox::setValue(const QVariant& value) { int v( value.toInt() ); if (m_unsigned && v<0) { kprWarning() << "could not assign negative value" << v << "- assigning 0"; v = 0; } QSpinBox::setValue(v); } void KPropertyIntSpinBox::slotValueChanged(int value) { Q_UNUSED(value); emit commitData(this); } //----------------------- class Q_DECL_HIDDEN KPropertyDoubleSpinBox::Private { public: - KPropertyUnit unit; - bool hasUnit; + bool dummy = false; }; namespace { -void decodeUnit(const KProperty &property, KPropertyUnit *unit, bool *hasUnit) +bool doubleRangeValue(const KProperty &property, QVariant *min, QVariant *max) { - const QString unitString = property.option("unit").toString(); - if (unitString.isEmpty()) { - *hasUnit = false; + Q_ASSERT(min); + Q_ASSERT(max); + *min = property.option("min", 0.0); + *max = property.option("max", MAX_PRECISE_DOUBLE); + if (!min->canConvert(QMetaType::Double)) { + min->clear(); } - else { - *unit = KPropertyUnit::fromSymbol(unitString, hasUnit); + if (!max->canConvert(QMetaType::Double)) { + max->clear(); } + return min->isValid() && max->isValid() && min->toDouble() <= max->toDouble(); } -//! Helper for testing property options -struct DoubleValueOptions { - explicit DoubleValueOptions(const KProperty &property) - { - minVal = property.option("min", 0.0); - maxVal = property.option("max", DBL_MAX / 100.0); - if (!minVal.canConvert(QMetaType::Double) || !maxVal.canConvert(QMetaType::Double) - || minVal.toReal() > maxVal.toReal()) - { - minVal.clear(); - maxVal.clear(); - } - step = property.option("step", KPROPERTY_DEFAULT_DOUBLE_VALUE_STEP); - if (!step.canConvert(QMetaType::Double) || step.toDouble() <= 0.0) { - step.clear(); - } - precision = property.option("precision", KPROPERTY_DEFAULT_DOUBLE_VALUE_PRECISION); - if (!precision.canConvert(QMetaType::Int) || precision.toInt() < 0) { - precision.clear(); - } - minValueText = property.option("minValueText").toString(); +QVariant precisionValue(const KProperty &property) +{ + QVariant result = property.option("precision", KPROPERTY_DEFAULT_DOUBLE_VALUE_PRECISION); + if (result.canConvert(QMetaType::Int) && result.toInt() >= 0) { + return result; } - QVariant minVal; - QVariant maxVal; - QVariant step; - QVariant precision; - QString minValueText; -}; + return QVariant(); +} + } // namespace KPropertyDoubleSpinBox::KPropertyDoubleSpinBox(const KProperty* prop, QWidget *parent, int itemHeight) : QDoubleSpinBox(parent) , d(new Private) { setFrame(false); QLineEdit* le = findChild(); if (le) { le->setAlignment(Qt::AlignLeft); le->setContentsMargins(0,0,0,0); le->setFrame(false); } /* KPropertyFactory::setTopAndBottomBordersUsingStyleSheet(sb, QString::fromLatin1( "QDoubleSpinBox { border-left: 0; border-right: 0; } " "QDoubleSpinBox::down-button { height: %1px; } " "QDoubleSpinBox::up-button { height: %2px; }" ).arg(itemHeight/2).arg(itemHeight - itemHeight/2) );*/ QString css = cssForSpinBox("QDoubleSpinBox", font(), itemHeight); KPropertyWidgetsFactory::setTopAndBottomBordersUsingStyleSheet(this, css); setStyleSheet(css); - const DoubleValueOptions options(*prop); - if (options.minVal.isValid() && options.maxVal.isValid()) { - setRange(options.minVal.toDouble(), options.maxVal.toDouble()); + QVariant minVal; + QVariant maxVal; + if (doubleRangeValue(*prop, &minVal, &maxVal)) { + setRange(minVal.toDouble(), maxVal.toDouble()); + } + QVariant step = prop->option("step", KPROPERTY_DEFAULT_DOUBLE_VALUE_STEP); + if (step.canConvert(QMetaType::Double) && step.toDouble() > 0.0) { + setSingleStep(step.toDouble()); } - if (options.step.isValid()) { - setSingleStep(options.step.toDouble()); + const QVariant precision = precisionValue(*prop); + if (precision.isValid()) { + setDecimals(precision.toInt()); } //! @todo implement slider // bool slider = prop->option("slider", false).toBool(); - if (options.precision.isValid()) { - setDecimals(options.precision.toInt()); - } + const KPropertyUtilsPrivate::ValueOptionsHandler options(*prop); if (!options.minValueText.isEmpty()) { setSpecialValueText(options.minValueText); } - decodeUnit(*prop, &d->unit, &d->hasUnit); - if (d->hasUnit) { - setSuffix( - QObject::tr("%1 %2", " ") // this adds necessary space - .arg(QString()).arg(d->unit.toString())); + if (!options.prefix.isEmpty()) { + setPrefix(options.prefix + QLatin1Char(' ')); + } + if (!options.suffix.isEmpty()) { + setSuffix(QLatin1Char(' ') + options.suffix); } connect(this, SIGNAL(valueChanged(double)), this, SLOT(slotValueChanged(double))); } KPropertyDoubleSpinBox::~KPropertyDoubleSpinBox() { delete d; } void KPropertyDoubleSpinBox::resizeEvent( QResizeEvent * event ) { setFixedHeight(height() + 1); QDoubleSpinBox::resizeEvent(event); } -void KPropertyDoubleSpinBox::setValue(double v) -{ - if (d->hasUnit) { - QDoubleSpinBox::setValue(d->unit.toUserValue(v)); - return; - } - QDoubleSpinBox::setValue(v); -} - -double KPropertyDoubleSpinBox::value() const -{ - if (d->hasUnit) { - return d->unit.fromUserValue(QDoubleSpinBox::value()); - } - return QDoubleSpinBox::value(); -} - void KPropertyDoubleSpinBox::slotValueChanged(double value) { Q_UNUSED(value); emit commitData(this); } //----------------------- KPropertyIntSpinBoxDelegate::KPropertyIntSpinBoxDelegate() { } QString KPropertyIntSpinBoxDelegate::propertyValueToString(const KProperty* prop, const QLocale &locale) const { - KPropertyUnit unit; - bool hasUnit; - decodeUnit(*prop, &unit, &hasUnit); - if (prop->hasOptions()) { - //replace min value with minValueText if defined - QVariant minValue(prop->option("min")); - QString minValueText(prop->option("minValueText").toString()); - if (!minValue.isNull() && !minValueText.isEmpty() - && minValue.toInt() == prop->value().toInt()) - { - return minValueText; - } - } - if (!hasUnit) { - return valueToString(prop->value(), locale); - } - if (locale.language() == QLocale::C) { - return QString::fromLatin1("%1 %2") - .arg(valueToString(prop->value(), locale)) - .arg(unit.toString()); + //replace min value with minValueText if defined + QVariant minVal; + QVariant maxVal; + const KPropertyUtilsPrivate::ValueOptionsHandler options(*prop); + (void)intRangeValue(*prop, &minVal, &maxVal); + if (minVal.isValid() && minVal.toInt() == prop->value().toInt()) { + return options.minValueText; } - return QObject::tr("%1 %2", " ") - .arg(valueToString(unit.toUserValue(prop->value().toDouble()), locale)) - .arg(unit.toString()); + return options.valueWithPrefixAndSuffix(valueToString(prop->value(), locale), locale); } QString KPropertyIntSpinBoxDelegate::valueToString(const QVariant& value, const QLocale &locale) const { - return locale.toString(value.toDouble(), 'f', 0); + return locale.toString(value.toReal(), 'f', 0); } QWidget* KPropertyIntSpinBoxDelegate::createEditor( int type, QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const { Q_UNUSED(type); KProperty *prop = KPropertyUtils::propertyForIndex(index); if (!prop) { return 0; } return new KPropertyIntSpinBox(prop, parent, option.rect.height() - 2); } //----------------------- KPropertyDoubleSpinBoxDelegate::KPropertyDoubleSpinBoxDelegate() { } QString KPropertyDoubleSpinBoxDelegate::propertyValueToString(const KProperty* prop, const QLocale &locale) const { - const DoubleValueOptions options(*prop); //replace min value with minValueText if defined - if (options.minVal.isValid() && !options.minValueText.isEmpty() - && options.minVal.toDouble() == prop->value().toDouble()) - { + QVariant minVal; + QVariant maxVal; + const KPropertyUtilsPrivate::ValueOptionsHandler options(*prop); + (void)doubleRangeValue(*prop, &minVal, &maxVal); + if (minVal.isValid() && minVal.toDouble() == prop->value().toDouble()) { return options.minValueText; } - KPropertyUnit unit; - bool hasUnit; - decodeUnit(*prop, &unit, &hasUnit); - const qreal realValue = hasUnit ? unit.toUserValue(prop->value().toReal()) : prop->value().toReal(); QString valueString; - if (options.precision.isValid()) { - valueString = locale.toString(realValue, 'f', options.precision.toInt()); + const QVariant precision = precisionValue(*prop); + if (precision.isValid()) { + valueString = locale.toString(prop->value().toReal(), 'f', precision.toInt()); } else { - valueString = valueToString(realValue, locale); - } - - if (!hasUnit) { - return valueString; - } - if (locale.language() == QLocale::C) { - return QString::fromLatin1("%1 %2").arg(valueString).arg(unit.toString()); + valueString = valueToString(prop->value().toReal(), locale); } - return QObject::tr("%1 %2", " ").arg(valueString).arg(unit.toString()); + return options.valueWithPrefixAndSuffix(valueString, locale); } QString KPropertyDoubleSpinBoxDelegate::valueToString(const QVariant& value, const QLocale &locale) const { - return locale.toString(value.toDouble()); + return locale.toString(value.toReal()); } QWidget* KPropertyDoubleSpinBoxDelegate::createEditor( int type, QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const { Q_UNUSED(type); KProperty *prop = KPropertyUtils::propertyForIndex(index); if (!prop) { return 0; } return new KPropertyDoubleSpinBox(prop, parent, option.rect.height() - 2 - 1); } diff --git a/src/editors/spinbox.h b/src/editors/spinbox.h index f5018cb..4e8528b 100644 --- a/src/editors/spinbox.h +++ b/src/editors/spinbox.h @@ -1,125 +1,120 @@ /* 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 + 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_SPINBOX_H #define KPROPERTY_SPINBOX_H #include "KPropertyWidgetsFactory.h" #include #include //! A delegate supporting Int and UInt types /*! Note that due to KIntNumInput limitations, for UInt the maximum value is INT_MAX, not UINT_MAX. */ class KPROPERTYWIDGETS_EXPORT KPropertyIntSpinBox : public QSpinBox { Q_OBJECT Q_PROPERTY(QVariant value READ value WRITE setValue USER true) public: KPropertyIntSpinBox(const KProperty* prop, QWidget *parent, int itemHeight); virtual ~KPropertyIntSpinBox(); QVariant value() const; Q_SIGNALS: void commitData(QWidget* editor); public Q_SLOTS: void setValue(const QVariant& value); //! @todo virtual bool eventFilter(QObject *o, QEvent *e); /* QLineEdit * lineEdit() const { return KIntSpinBox::lineEdit(); }*/ protected Q_SLOTS: void slotValueChanged(int value); private: bool m_unsigned; }; //! Double editor class KPROPERTYWIDGETS_EXPORT KPropertyDoubleSpinBox : public QDoubleSpinBox { Q_OBJECT Q_PROPERTY(double value READ value WRITE setValue USER true) public: KPropertyDoubleSpinBox(const KProperty* prop, QWidget *parent, int itemHeight); virtual ~KPropertyDoubleSpinBox(); // virtual bool eventFilter(QObject *o, QEvent *e); /* QLineEdit * lineEdit() const { return QDoubleSpinBox::lineEdit(); }*/ - double value() const; - Q_SIGNALS: void commitData(QWidget* editor); -public Q_SLOTS: - void setValue(double value); - protected Q_SLOTS: void slotValueChanged(double value); protected: //! Used to fix height of the internal spin box virtual void resizeEvent( QResizeEvent * event ); class Private; Private * const d; }; //! A delegate supporting Int, UInt, LongLong and ULongLong types class KPROPERTYWIDGETS_EXPORT KPropertyIntSpinBoxDelegate : public KPropertyEditorCreatorInterface, public KPropertyValueDisplayInterface { public: KPropertyIntSpinBoxDelegate(); virtual QString propertyValueToString(const KProperty* prop, const QLocale &locale) const; virtual QString valueToString(const QVariant& value, const QLocale &locale) const; virtual QWidget * createEditor( int type, QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const; }; class KPROPERTYWIDGETS_EXPORT KPropertyDoubleSpinBoxDelegate : public KPropertyEditorCreatorInterface, public KPropertyValueDisplayInterface { public: KPropertyDoubleSpinBoxDelegate(); virtual QString propertyValueToString(const KProperty* prop, const QLocale &locale) const; virtual QString valueToString(const QVariant& value, const QLocale &locale) const; virtual QWidget * createEditor( int type, QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const; }; #endif