File indexing completed on 2024-04-14 14:53:39

0001 /* This file is part of the KDE project
0002    Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
0003    Copyright (C) 2008-2018 Jarosław Staniek <staniek@kde.org>
0004    Copyright (C) 2018 Dmitry Baryshev <dmitrymq@gmail.com>
0005 
0006    This library is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Library General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 
0011    This library is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014    Library General Public License for more details.
0015 
0016    You should have received a copy of the GNU Library General Public License
0017    along with this library; see the file COPYING.LIB.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include "window.h"
0023 
0024 #include <KProperty>
0025 #include <KPropertyComposedUrl>
0026 #include <KPropertyListData>
0027 #include <KPropertyEditorView>
0028 
0029 #include <QDate>
0030 #include <QDateTime>
0031 #include <QPixmap>
0032 #include <QCursor>
0033 #include <QApplication>
0034 #include <QDesktopWidget>
0035 #include <QVBoxLayout>
0036 #include <QIcon>
0037 #include <QCommandLineParser>
0038 #include <QDebug>
0039 #include <QDate>
0040 #include <QCheckBox>
0041 #include <QUrl>
0042 #include <QDir>
0043 
0044 Window::Window()
0045         : QWidget()
0046         , m_set(this)
0047         , m_flatOption("flat", QCoreApplication::translate("main",
0048                        "Flat display: do not display groups\n(useful for testing)"))
0049         , m_fontSizeOption("font-size", QCoreApplication::translate("main",
0050                            "Set font size to <size> (in points)\n(useful for testing whether editors keep the font settings)"),
0051                            QCoreApplication::translate("main", "size"))
0052         , m_propertyOption("property", QCoreApplication::translate("main",
0053                            "Display only specified property\n(useful when we want to focus on testing a single\nproperty editor)"),
0054                            QCoreApplication::translate("main", "name"))
0055         , m_roOption("ro", QCoreApplication::translate("main",
0056                      "Set all properties as read-only:\n(useful for testing read-only mode)"))
0057 {
0058     setObjectName("kpropertyexamplewindow");
0059     setWindowIcon(QIcon::fromTheme("document-properties"));
0060     m_parser.setApplicationDescription(QCoreApplication::translate("main", "An example application for the KProperty library."));
0061     m_parser.addHelpOption();
0062     m_parser.addVersionOption();
0063     parseCommandLine();
0064 
0065     const QString singleProperty = m_parser.value(m_propertyOption);
0066     bool ok;
0067     const int fontSize = m_parser.value(m_fontSizeOption).toInt(&ok);
0068     if (fontSize > 0 && ok) {
0069         QFont f(font());
0070         f.setPointSize(fontSize);
0071         setFont(f);
0072     }
0073 
0074     /*  First, create a KPropertySet which will hold the properties.  */
0075     connect(&m_set, &KPropertySet::propertyChanged, this, &Window::propertyChanged);
0076 
0077     KProperty *p = nullptr;
0078     m_set.setReadOnly(m_parser.isSet(m_roOption));
0079     QByteArray group;
0080     const bool addGroups = !m_parser.isSet(m_flatOption);
0081     if (addGroups) {
0082         group = "BasicGroup";
0083         m_set.setGroupCaption(group, "Basic Properties");
0084     }
0085     if (singleProperty.isEmpty() || singleProperty=="String") {
0086         m_set.addProperty(p = new KProperty("String", "String"), group);
0087         p->setValueSyncPolicy(KProperty::ValueSyncPolicy::Auto);
0088         p->setReadOnly(false); // this should not work:
0089                                // - not needed if the property set is read-write
0090                                // - ignored if the property set is read-only
0091     }
0092     if (singleProperty.isEmpty() || singleProperty=="MultiLine") {
0093         m_set.addProperty(p = new KProperty("MultiLine", "Multi\nLine\nContent"), group);
0094         p->setValueSyncPolicy(KProperty::ValueSyncPolicy::Auto);
0095         p->setOption("multiLine", true);
0096     }
0097 
0098     if (singleProperty.isEmpty() || singleProperty=="Int") {
0099         m_set.addProperty(new KProperty("Int", 2, "Int"), group);
0100     }
0101     if (singleProperty.isEmpty() || singleProperty=="Double") {
0102         m_set.addProperty(p = new KProperty("Double", 3.14159, "Double"), group);
0103         p->setOption("precision", 4); // will round to 3.1416
0104     }
0105     if (singleProperty.isEmpty() || singleProperty=="Bool") {
0106         m_set.addProperty(new KProperty("Bool", QVariant(true), "Bool"), group);
0107     }
0108     if (singleProperty.isEmpty() || singleProperty=="NullBool") {
0109         m_set.addProperty(new KProperty("NullBool", QVariant(), "Null Bool", QString(), KProperty::Bool), group);
0110     }
0111     if (singleProperty.isEmpty() || singleProperty=="3-State") {
0112         m_set.addProperty(p = new KProperty("3-State", QVariant(), "3 States", QString(),
0113                                             KProperty::Bool), group);
0114         p->setOption("3State", true);
0115     }
0116     if (singleProperty.isEmpty() || singleProperty=="Date") {
0117         m_set.addProperty(p = new KProperty("Date", QDate::currentDate(), "Date"), group);
0118         p->setIconName("date");
0119     }
0120     if (singleProperty.isEmpty() || singleProperty=="Time") {
0121         m_set.addProperty(new KProperty("Time", QTime::currentTime(), "Time"), group);
0122     }
0123     if (singleProperty.isEmpty() || singleProperty=="DateTime") {
0124         m_set.addProperty(new KProperty("DateTime", QDateTime::currentDateTime(), "Date/Time"), group);
0125     }
0126 
0127     QStringList name_list({"First Item", "Second Item", "Third Item"}); //strings
0128     if (singleProperty.isEmpty() || singleProperty=="List") {
0129         const QStringList keys({"1stitem", "2nditem", "3rditem"});
0130         KPropertyListData *listData = new KPropertyListData(keys, name_list);
0131         m_set.addProperty(new KProperty("List", listData, QVariant(keys[1]), "List"), group);
0132     }
0133 
0134     QVariantList list_keys({1, 2, 3});
0135     if (singleProperty.isEmpty() || singleProperty=="List2") {
0136         // A valueFromList property matching strings with ints (could be any type supported by QVariant)
0137         KPropertyListData *listData = new KPropertyListData;
0138         listData->setKeys(list_keys);
0139         listData->setNamesAsStringList(name_list);
0140         m_set.addProperty(new KProperty("List2", listData, list_keys.last(), "List 2"), group);
0141     }
0142     if (singleProperty.isEmpty() || singleProperty=="EditableList") {
0143         // A valueFromList property matching strings with ints (could be any type supported by QVariant)
0144         KPropertyListData *listData = new KPropertyListData;
0145         listData->setKeys(list_keys);
0146         listData->setNamesAsStringList(name_list);
0147         p = new KProperty("EditableList", listData, list_keys.first(), "Editable List");
0148         p->setOption("extraValueAllowed", true);
0149         m_set.addProperty(p, group);
0150     }
0151 
0152 //  Complex
0153     if (addGroups) {
0154         group = "ComposedGroup";
0155         m_set.setGroupCaption(group, "Composed Properties");
0156     }
0157     if (singleProperty.isEmpty() || singleProperty=="Point") {
0158         m_set.addProperty(new KProperty("Point", QPoint(3, 4), "Point"), group);
0159     }
0160     if (singleProperty.isEmpty() || singleProperty=="Size") {
0161         m_set.addProperty(new KProperty("Size", QSize(10, 20), "Size"), group);
0162     }
0163     if (singleProperty.isEmpty() || singleProperty=="Rect") {
0164         m_set.addProperty(new KProperty("Rect", QRect(5,11,100,200), "Rect"), group);
0165     }
0166     if (singleProperty.isEmpty() || singleProperty=="PointF") {
0167         m_set.addProperty(new KProperty("PointF", QPointF(3.14, 4.15), "PointF"), group);
0168     }
0169     if (singleProperty.isEmpty() || singleProperty=="SizeF") {
0170         m_set.addProperty(new KProperty("SizeF", QSizeF(1.1, 2.45), "SizeF"), group);
0171     }
0172     if (singleProperty.isEmpty() || singleProperty == "RectF") {
0173         m_set.addProperty(
0174             new KProperty("RectF", QRectF(0.1, 0.5, 10.72, 18.21), "RectF"), group);
0175     }
0176 
0177 //  With suffixes and prefixes
0178     if (addGroups) {
0179         group = "PrefixesSuffixesGroup";
0180         m_set.setGroupCaption(group, "Prefixes & Suffixes");
0181     }
0182     if (singleProperty.isEmpty() || singleProperty=="dollars") {
0183         m_set.addProperty(p = new KProperty("dollars", 100, "Dollars"), group);
0184         p->setOption("prefix", "$");
0185     }
0186     if (singleProperty.isEmpty() || singleProperty == "billions") {
0187         m_set.addProperty(p = new KProperty("billions", 5.0, "Billions"), group);
0188         p->setOption("prefix", "£");
0189         p->setOption("suffix", "bn");
0190         // default precision == 2 and step == 0.01
0191     }
0192     if (singleProperty.isEmpty() || singleProperty == "PointF-mm") {
0193         m_set.addProperty(
0194             p = new KProperty("PointF-mm", QPointF(2.5, 3.5), "PointF [mm]"), group);
0195         p->setOption("suffix", "mm");
0196         p->setOption("step", 0.1);
0197         p->setOption("precision", 2);
0198     }
0199     if (singleProperty.isEmpty() || singleProperty == "SizeF-dm") {
0200         m_set.addProperty(
0201             p = new KProperty("SizeF-dm", QSizeF(7.0, 6.5), "SizeF [dm]"), group);
0202         p->setOption("suffix", "dm");
0203         p->setOption("step", 0.001);
0204         p->setOption("precision", 3);
0205     }
0206     if (singleProperty.isEmpty() || singleProperty=="RectF-px") {
0207         m_set.addProperty(
0208             p = new KProperty("RectF-px", QRectF(21.2, 22.2, 9.1, 1.0), "RectF [px]"),
0209             group);
0210         p->setOption("suffix", "px");
0211         p->setOption("step", 0.1);
0212         p->setOption("precision", 1);
0213     }
0214 
0215 //  Limits
0216     if (addGroups) {
0217         group = "LimitsGroup";
0218         m_set.setGroupCaption(group, "Limits");
0219     }
0220     if (singleProperty.isEmpty() || singleProperty=="uint") {
0221         m_set.addProperty(new KProperty("uint", 3, "Unsigned Int", QString(), KProperty::UInt), group);
0222     }
0223     if (singleProperty.isEmpty() || singleProperty=="uint+mintext") {
0224         m_set.addProperty(p = new KProperty("uint+mintext", 0, "Unsigned Int\n+min.text", QString(), KProperty::UInt), group);
0225         p->setOption("minValueText", "Minimum value");
0226     }
0227     if (singleProperty.isEmpty() || singleProperty=="limit0_10") {
0228         m_set.addProperty(p = new KProperty("limit0_10", 9, "0..10", QString(), KProperty::UInt), group);
0229         p->setOption("max", 10);
0230     }
0231     if (singleProperty.isEmpty() || singleProperty == "limit1_5+mintext") {
0232         // This is a good test for fixing value out of range: "Could not assign value 9 larger than
0233         // maximum 5 -- setting to 5" warning is displayed and 5 is assigned.
0234         m_set.addProperty(p = new KProperty("limit1_5+mintext", 9, "1..5\n+mintext", QString(),
0235                                             KProperty::UInt), group);
0236         p->setOption("min", 1);
0237         p->setOption("max", 5);
0238         p->setOption("minValueText", "Minimum value");
0239     }
0240     if (singleProperty.isEmpty() || singleProperty=="negative-int") {
0241         m_set.addProperty(p = new KProperty("negative-int", -2, "Negative Int", QString(), KProperty::Int), group);
0242         p->setOption("max", -1);
0243     }
0244     if (singleProperty.isEmpty() || singleProperty=="double-unlimited") {
0245         m_set.addProperty(p = new KProperty("double-unlimited", -1.11, "Double unlimited"), group);
0246         p->setOption("min", KPROPERTY_MIN_PRECISE_DOUBLE);
0247         p->setOption("precision", 1);
0248         p->setOption("step", 0.1);
0249     }
0250     if (singleProperty.isEmpty() || singleProperty=="double-negative") {
0251         m_set.addProperty(p = new KProperty("double-negative", -0.2, "Double negative"), group);
0252         p->setOption("min", KPROPERTY_MIN_PRECISE_DOUBLE);
0253         p->setOption("max", -0.1);
0254         p->setOption("precision", 1);
0255         p->setOption("step", 0.1);
0256     }
0257     if (singleProperty.isEmpty() || singleProperty=="double-minus1-0+mintext") {
0258         // This is a good test for fixing value out of range: "Could not assign value -9.0 smaller than
0259         // minimum -1.0 -- setting to -1.0" warning is displayed and -1.0 is assigned.
0260         m_set.addProperty(p = new KProperty("double-minus1-0+mintext", -9.0, "Double -1..0\n+mintext"), group);
0261         p->setOption("min", -1.0);
0262         p->setOption("max", 0.0);
0263         p->setOption("precision", 1);
0264         p->setOption("step", 0.1);
0265         p->setOption("minValueText", "Minimum value");
0266     }
0267 
0268 //  Appearance
0269     if (addGroups) {
0270         group = "AppearanceGroup";
0271         m_set.setGroupCaption(group, "Appearance");
0272         m_set.setGroupIconName(group, "appearance");
0273     }
0274     if (singleProperty.isEmpty() || singleProperty=="Color") {
0275         m_set.addProperty(new KProperty("Color", palette().color(QPalette::Active, QPalette::Background), "Color"), group);
0276     }
0277     if (singleProperty.isEmpty() || singleProperty=="Pixmap") {
0278         QPixmap pm(QIcon::fromTheme("network-wired").pixmap(QSize(64, 64)));
0279         m_set.addProperty(p = new KProperty("Pixmap", pm, "Pixmap"), group);
0280         p->setIconName("kpaint");
0281     }
0282     if (singleProperty.isEmpty() || singleProperty=="Font") {
0283         QFont myFont("Times New Roman", 12);
0284         myFont.setUnderline(true);
0285         m_set.addProperty(p = new KProperty("Font", myFont, "Font"), group);
0286         p->setIconName("fonts");
0287     }
0288     if (singleProperty.isEmpty() || singleProperty=="Cursor") {
0289         m_set.addProperty(new KProperty("Cursor", QCursor(Qt::WaitCursor), "Cursor"), group);
0290     }
0291     if (singleProperty.isEmpty() || singleProperty=="LineStyle") {
0292         m_set.addProperty(new KProperty("LineStyle", 3, "Line Style", QString(),
0293                                         KProperty::LineStyle), group);
0294     }
0295     if (singleProperty.isEmpty() || singleProperty=="SizePolicy") {
0296         QSizePolicy sp(sizePolicy());
0297         sp.setHorizontalStretch(1);
0298         sp.setVerticalStretch(2);
0299         m_set.addProperty(new KProperty("SizePolicy", sp, "Size Policy"), group);
0300     }
0301     if (singleProperty.isEmpty() || singleProperty=="Invisible") {
0302         m_set.addProperty(p = new KProperty("Invisible", "I am invisible", "Invisible"), group);
0303         p->setVisible(false);
0304     }
0305     if (singleProperty.isEmpty() || singleProperty=="Url") {
0306         m_set.addProperty(p = new KProperty("Url", QUrl("https://community.kde.org/KProperty"), "Url"), group);
0307     }
0308     if (singleProperty.isEmpty() || singleProperty=="RelativeComposedUrl") {
0309         const KPropertyComposedUrl composedUrl(QUrl::fromLocalFile(QApplication::applicationDirPath()),
0310                                                QLatin1String("data/icons/kproperty_breeze.rcc"));
0311         p = new KProperty("RelativeComposedUrl", QVariant::fromValue(composedUrl), "ComposedUrl with\nrelative path",
0312                           QString(), KProperty::ComposedUrl);
0313         m_set.addProperty(p, group);
0314     }
0315     if (singleProperty.isEmpty() || singleProperty=="AbsoluteComposedUrl") {
0316         const KPropertyComposedUrl composedUrl(QUrl::fromLocalFile(QApplication::applicationDirPath()),
0317                                                QUrl("https://community.kde.org/KProperty"));
0318         p = new KProperty("AbsoluteComposedUrl", QVariant::fromValue(composedUrl), "ComposedUrl with\nabsolute URL",
0319                           QString(), KProperty::ComposedUrl);
0320         m_set.addProperty(p, group);
0321     }
0322     if (singleProperty.isEmpty() || singleProperty=="ExistingFile") {
0323         m_set.addProperty(p = new KProperty("ExistingFile",
0324             QUrl::fromLocalFile(QCoreApplication::applicationFilePath()), "Existing\nFile"), group);
0325         p->setOption("fileMode", "existingFile");
0326     }
0327     if (singleProperty.isEmpty() || singleProperty=="OverwriteFile") {
0328         m_set.addProperty(p = new KProperty("OverwriteFile",
0329             QUrl::fromLocalFile(QDir::homePath() + "/" + QCoreApplication::applicationName() + ".txt"),
0330                                             "New File or\nOverwrite Existing"), group);
0331         p->setOption("confirmOverwrites", true);
0332     }
0333     if (singleProperty.isEmpty() || singleProperty=="Dir") {
0334         m_set.addProperty(p = new KProperty("Dir", QUrl::fromLocalFile(QDir::homePath()), "Dir"), group);
0335         p->setOption("fileMode", "dirsOnly");
0336     }
0337     if (singleProperty.isEmpty() || singleProperty=="ReadOnly") {
0338         m_set.addProperty(p = new KProperty("Read-Only", "Read-only string"), group);
0339         p->setReadOnly(true);
0340     }
0341 
0342     // Properties for testing tooltips
0343     if (singleProperty.isEmpty() || singleProperty == "StaticToolTip") {
0344         m_set.addProperty(new KProperty("StaticToolTip", "Some value", "Static Tooltip",
0345           "This is a static tooltip based on value of KProperty::description()"), group);
0346         m_set.addProperty(
0347             m_dynamicToolTipProperty = new KProperty("DynamicToolTip", "Some dynamic value",
0348                                                      "Dynamic Tooltip"), group);
0349         propertyChanged(m_set, *m_dynamicToolTipProperty); // this updates description
0350     }
0351 
0352     QVBoxLayout *lyr = new QVBoxLayout(this);
0353     m_editorView = new KPropertyEditorView(this);
0354     m_editorView->setToolTipsVisible(true);
0355     lyr->addWidget(m_editorView);
0356     m_editorView->changeSet(&m_set);
0357     m_editorView->resizeColumnToContents(0);
0358     lyr->addSpacing(lyr->spacing());
0359 
0360     QHBoxLayout *hlyr = new QHBoxLayout;
0361     lyr->addLayout(hlyr);
0362 
0363     QCheckBox *showGrid = new QCheckBox("Show grid");
0364     showGrid->setChecked(true);
0365     connect(showGrid, &QCheckBox::stateChanged, this, &Window::showGrid);
0366     hlyr->addWidget(showGrid);
0367 
0368     QCheckBox *showFrame = new QCheckBox("Show frame");
0369     showFrame->setChecked(true);
0370     connect(showFrame, &QCheckBox::stateChanged, this, &Window::showFrame);
0371     hlyr->addWidget(showFrame);
0372 
0373     QCheckBox *showGroups = new QCheckBox("Show groups");
0374     if (addGroups) {
0375         connect(showGroups, &QCheckBox::toggled, m_editorView, &KPropertyEditorView::setGroupsVisible);
0376         showGroups->setChecked(m_editorView->groupsVisible());
0377     } else {
0378         showGroups->setEnabled(false);
0379     }
0380     hlyr->addWidget(showGroups);
0381 
0382     QCheckBox *showToolTips = new QCheckBox("Show tooltips");
0383     connect(showToolTips, &QCheckBox::toggled, m_editorView, &KPropertyEditorView::setToolTipsVisible);
0384     showToolTips->setChecked(m_editorView->toolTipsVisible());
0385     hlyr->addWidget(showToolTips);
0386 
0387     QCheckBox *readOnly = new QCheckBox("Read-only");
0388     connect(readOnly, &QCheckBox::toggled, &m_set, &KPropertySet::setReadOnly);
0389     readOnly->setChecked(m_set.isReadOnly());
0390     hlyr->addWidget(readOnly);
0391 
0392     hlyr->addStretch(1);
0393     resize(400, qApp->desktop()->height() - 200);
0394     m_editorView->setFocus();
0395     qDebug() << m_set;
0396 }
0397 
0398 Window::~Window()
0399 {
0400 }
0401 
0402 void Window::parseCommandLine()
0403 {
0404     m_parser.addOption(m_flatOption);
0405     m_parser.addOption(m_fontSizeOption);
0406     m_parser.addOption(m_propertyOption);
0407     m_parser.addOption(m_roOption);
0408     m_parser.process(*(QCoreApplication::instance()));
0409 }
0410 
0411 void Window::showGrid(int state)
0412 {
0413     m_editorView->setGridLineColor(
0414         state == Qt::Checked ? KPropertyEditorView::defaultGridLineColor() : QColor());
0415 }
0416 
0417 void Window::showFrame(int state)
0418 {
0419     m_editorView->setFrameStyle(state == Qt::Checked ? QFrame::Box : QFrame::NoFrame);
0420 }
0421 
0422 void Window::propertyChanged(KPropertySet& set, KProperty& property)
0423 {
0424     Q_UNUSED(set)
0425     if (&property == m_dynamicToolTipProperty) {
0426         property.setDescription(QString::fromLatin1("This is a dynamic tooltip based on value of "
0427                                                     "\"%1\" property which is currently \"%2\"")
0428                                     .arg(property.caption(), property.value().toString()));
0429     }
0430 }