KProperty

spinbox.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
3 Copyright (C) 2004 Alexander Dymo <cloudtemple@mskat.net>
4 Copyright (C) 2008-2017 Jarosław Staniek <staniek@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20*/
21
22#include "spinbox.h"
23#include "KProperty.h"
24#include "KProperty_p.h"
25#include "KPropertyEditorView.h"
26#include "KPropertyUtils.h"
27#include "KPropertyUtils_p.h"
28#include "KPropertyWidgetsFactory.h"
29#include "kproperty_debug.h"
30
31#include <QVariant>
32#include <QLineEdit>
33#include <QLocale>
34
35//! @return font size expressed in points (pt)
36//! or if points are not available - in pixels (px) for @a font
37static QString fontSizeForCSS(const QFont& font)
38{
39 return font.pointSize() > 0
40 ? QString::fromLatin1("%1pt").arg(font.pointSize())
41 : QString::fromLatin1("%1px").arg(font.pixelSize());
42}
43
44static QString cssForSpinBox(const char *_class, const QFont& font, int itemHeight)
45{
47 "%5 { border-left: 0; border-right: 0; font-size: %3; } "
48 "%5::down-button { height: %1px; %4 } "
49 "%5::up-button { height: %2px; } "
50 "QLineEdit { border-width:0px; } "
51 )
52 .arg(itemHeight/2 - 1).arg(itemHeight - itemHeight/2 - 1)
53 .arg(fontSizeForCSS(font))
54 .arg(QLatin1String((itemHeight/2 <= 9) ? "bottom: 2px;" : "bottom: 0px;"))
55 .arg(QLatin1String(_class));
56}
57
58namespace {
59
60void intRangeValue(const KProperty &property, QVariant *min, QVariant *max)
61{
62 Q_ASSERT(min);
63 Q_ASSERT(max);
64 *min = property.option("min");
65 *max = property.option("max");
66 if (!min->canConvert(QMetaType::Int) || min->toInt() < -INT_MAX) {
67 min->clear();
68 }
69 if (!max->canConvert(QMetaType::Int) || max->toInt() > INT_MAX) {
70 max->clear();
71 }
73 && min->toInt() > max->toInt())
74 {
75 min->clear();
76 max->clear();
77 }
78 if (min->isNull()) {
79 switch (property.type()) {
80 case KProperty::UInt:
81 *min = 0;
82 break;
83 default:
84 *min = -INT_MAX;
85 }
86 }
87 if (max->isNull()) {
88 *max = INT_MAX;
89 }
90}
91
92//! Fixes @a value to fit in range @a min to @a max.
93//! Displays qWarning if @a warn is @c true.
94int fixIntValue(const QVariant &value, int min, int max, bool warn)
95{
96 if (value.toInt() < min) {
97 if (warn) {
98 kprWarning() << "Could not assign value" << value.toInt() << "smaller than minimum" << min
99 << "-- setting to" << min;
100 }
101 return min;
102 }
103 if (value.toInt() > max) {
104 if (warn) {
105 kprWarning() << "Could not assign value" << value.toInt() << "larger than maximum" << max
106 << "-- setting to" << max;
107 }
108 return max;
109 }
110 return value.toInt();
111}
112
113} // namespace
114
115class Q_DECL_HIDDEN KPropertyIntSpinBox::Private
116{
117public:
118 explicit Private(const KProperty& prop) : property(&prop)
119 {
120 }
121
122 const KProperty * const property;
123};
124
125KPropertyIntSpinBox::KPropertyIntSpinBox(const KProperty& prop, QWidget *parent, int itemHeight)
126 : QSpinBox(parent)
127 , d(new Private(prop))
128{
129 QLineEdit* le = findChild<QLineEdit*>();
130 setContentsMargins(0,0,0,0);
131 if (le) {
133 le->setContentsMargins(0,0,0,0);
134 }
135 setFrame(true);
136 QString css = cssForSpinBox("QSpinBox", font(), itemHeight);
137 KPropertyWidgetsFactory::setTopAndBottomBordersUsingStyleSheet(this, css);
138 setStyleSheet(css);
139
140 QVariant minVal;
141 QVariant maxVal;
142 intRangeValue(prop, &minVal, &maxVal);
143 setRange(minVal.toInt(), maxVal.toInt());
144 const KPropertyUtilsPrivate::ValueOptionsHandler options(prop);
145 if (!options.minValueText.isNull()) {
146 setSpecialValueText(options.minValueText.toString());
147 }
148 if (!options.prefix.isEmpty()) {
149 setPrefix(options.prefix + QLatin1Char(' '));
150 }
151 if (!options.suffix.isEmpty()) {
152 setSuffix(QLatin1Char(' ') + options.suffix);
153 }
154 connect(this, SIGNAL(valueChanged(int)), this, SLOT(slotValueChanged(int)));
155}
156
157KPropertyIntSpinBox::~KPropertyIntSpinBox()
158{
159 delete d;
160}
161
162QVariant KPropertyIntSpinBox::value() const
163{
164 if (d->property->type() == KProperty::UInt) {
165 return uint(QSpinBox::value());
166 }
167 return QSpinBox::value();
168}
169
170void KPropertyIntSpinBox::setValue(const QVariant& value)
171{
172 QVariant minVal;
173 QVariant maxVal;
174 intRangeValue(*d->property, &minVal, &maxVal);
175 QSpinBox::setValue(fixIntValue(value, minVal.toInt(), maxVal.toInt(), true));
176}
177
178void KPropertyIntSpinBox::slotValueChanged(int value)
179{
180 Q_UNUSED(value);
181 emit commitData(this);
182}
183
184//-----------------------
185
186class Q_DECL_HIDDEN KPropertyDoubleSpinBox::Private
187{
188public:
189 explicit Private(const KProperty& prop) : property(&prop)
190 {
191 }
192
193 const KProperty * const property;
194};
195
196namespace {
197
198void doubleRangeValue(const KProperty &property, QVariant *min, QVariant *max)
199{
200 Q_ASSERT(min);
201 Q_ASSERT(max);
202 *min = property.option("min");
203 *max = property.option("max");
204 if (!min->canConvert(QMetaType::Double) || min->toDouble() < KPROPERTY_MIN_PRECISE_DOUBLE) {
205 min->clear();
206 }
207 if (!max->canConvert(QMetaType::Double) || max->toDouble() > KPROPERTY_MAX_PRECISE_DOUBLE) {
208 max->clear();
209 }
211 && min->toDouble() > max->toDouble())
212 {
213 min->clear();
214 max->clear();
215 }
216 if (min->isNull()) {
217 *min = 0.0;
218 }
219 if (max->isNull()) {
220 *max = KPROPERTY_MAX_PRECISE_DOUBLE;
221 }
222}
223
224//! Fixes @a value to fit in range @a min to @a max.
225//! Displays qWarning if @a warn is @c true.
226double fixDoubleValue(const QVariant &value, double min, double max, bool warn)
227{
228 if (value.toDouble() < min) {
229 if (warn) {
230 kprWarning() << "Could not assign value" << value.toDouble() << "smaller than minimum" << min
231 << "-- setting to" << min;
232 }
233 return min;
234 }
235 if (value.toDouble() > max) {
236 if (warn) {
237 kprWarning() << "Could not assign value" << value.toDouble() << "larger than maximum" << max
238 << "-- setting to" << max;
239 }
240 return max;
241 }
242 return value.toDouble();
243}
244
245QVariant precisionValue(const KProperty &property)
246{
247 QVariant result = property.option("precision", KPROPERTY_DEFAULT_DOUBLE_VALUE_PRECISION);
248 if (result.canConvert(QMetaType::Int) && result.toInt() >= 0) {
249 return result;
250 }
251 return QVariant();
252}
253
254} // namespace
255
257 : QDoubleSpinBox(parent)
258 , d(new Private(prop))
259{
260 setFrame(false);
261 QLineEdit* le = findChild<QLineEdit*>();
262 if (le) {
264 le->setContentsMargins(0,0,0,0);
265 le->setFrame(false);
266 }
267/* KPropertyFactory::setTopAndBottomBordersUsingStyleSheet(sb,
268 QString::fromLatin1(
269 "QDoubleSpinBox { border-left: 0; border-right: 0; } "
270 "QDoubleSpinBox::down-button { height: %1px; } "
271 "QDoubleSpinBox::up-button { height: %2px; }"
272 ).arg(itemHeight/2).arg(itemHeight - itemHeight/2)
273 );*/
274 QString css = cssForSpinBox("QDoubleSpinBox", font(), itemHeight);
275 KPropertyWidgetsFactory::setTopAndBottomBordersUsingStyleSheet(this, css);
276 setStyleSheet(css);
277
278 QVariant minVal;
279 QVariant maxVal;
280 doubleRangeValue(prop, &minVal, &maxVal);
281 setRange(minVal.toDouble(), maxVal.toDouble());
282 QVariant step = prop.option("step", KPROPERTY_DEFAULT_DOUBLE_VALUE_STEP);
283 if (step.canConvert(QMetaType::Double) && step.toDouble() > 0.0) {
284 setSingleStep(step.toDouble());
285 }
286 const QVariant precision = precisionValue(prop);
287 if (precision.isValid()) {
288 setDecimals(precision.toInt());
289 }
290 //! @todo implement slider
291 // bool slider = prop->option("slider", false).toBool();
292 const KPropertyUtilsPrivate::ValueOptionsHandler options(prop);
293 if (!options.minValueText.isNull()) {
294 setSpecialValueText(options.minValueText.toString());
295 }
296 if (!options.prefix.isEmpty()) {
297 setPrefix(options.prefix + QLatin1Char(' '));
298 }
299 if (!options.suffix.isEmpty()) {
300 setSuffix(QLatin1Char(' ') + options.suffix);
301 }
302 connect(this, SIGNAL(valueChanged(double)), this, SLOT(slotValueChanged(double)));
303}
304
305KPropertyDoubleSpinBox::~KPropertyDoubleSpinBox()
306{
307 delete d;
308}
309
310void KPropertyDoubleSpinBox::resizeEvent( QResizeEvent * event )
311{
313}
314
315void KPropertyDoubleSpinBox::setValue(const QVariant& value)
316{
317 QVariant minVal;
318 QVariant maxVal;
319 doubleRangeValue(*d->property, &minVal, &maxVal);
320 QDoubleSpinBox::setValue(fixDoubleValue(value, minVal.toDouble(), maxVal.toDouble(), true));
321}
322
323void KPropertyDoubleSpinBox::slotValueChanged(double value)
324{
325 Q_UNUSED(value);
326 emit commitData(this);
327}
328
329//-----------------------
330
331KPropertyIntSpinBoxDelegate::KPropertyIntSpinBoxDelegate()
332{
333}
334
335QString KPropertyIntSpinBoxDelegate::propertyValueToString(const KProperty* prop,
336 const QLocale &locale) const
337{
338 //replace min value with minValueText if defined
339 const KPropertyUtilsPrivate::ValueOptionsHandler options(*prop);
340 QVariant minVal;
341 QVariant maxVal;
342 intRangeValue(*prop, &minVal, &maxVal);
343 const int fixedValue = fixIntValue(prop->value(), minVal.toInt(), maxVal.toInt(), false);
344 if (minVal.isValid() && minVal.toInt() == fixedValue && !options.minValueText.isNull())
345 {
346 return options.minValueText.toString();
347 }
348 return options.valueWithPrefixAndSuffix(valueToString(fixedValue, locale), locale);
349}
350
351QString KPropertyIntSpinBoxDelegate::valueToString(const QVariant& value, const QLocale &locale) const
352{
353 return locale.toString(value.toReal(), 'f', 0);
354}
355
356QWidget* KPropertyIntSpinBoxDelegate::createEditor( int type, QWidget *parent,
357 const QStyleOptionViewItem & option, const QModelIndex & index ) const
358{
359 Q_UNUSED(type);
360
361 KProperty *prop = KPropertyUtils::propertyForIndex(index);
362 if (!prop) {
363 return nullptr;
364 }
365 return new KPropertyIntSpinBox(*prop, parent, option.rect.height() - 2);
366}
367
368//-----------------------
369
370KPropertyDoubleSpinBoxDelegate::KPropertyDoubleSpinBoxDelegate()
371{
372}
373
374QString KPropertyDoubleSpinBoxDelegate::propertyValueToString(const KProperty* prop,
375 const QLocale &locale) const
376{
377 //replace min value with minValueText if defined
378 QVariant minVal;
379 QVariant maxVal;
380 const KPropertyUtilsPrivate::ValueOptionsHandler options(*prop);
381 doubleRangeValue(*prop, &minVal, &maxVal);
382 const double fixedValue = fixDoubleValue(prop->value(), minVal.toDouble(), maxVal.toDouble(), false);
383 if (minVal.isValid() && minVal.toDouble() == fixedValue && !options.minValueText.isNull())
384 {
385 return options.minValueText.toString();
386 }
387 QString valueString;
388 const QVariant precision = precisionValue(*prop);
389 if (precision.isValid()) {
390 valueString = locale.toString(fixedValue, 'f', precision.toInt());
391 } else {
392 valueString = valueToString(fixedValue, locale);
393 }
394 return options.valueWithPrefixAndSuffix(valueString, locale);
395}
396
397QString KPropertyDoubleSpinBoxDelegate::valueToString(const QVariant& value, const QLocale &locale) const
398{
399 return locale.toString(value.toReal());
400}
401
402QWidget* KPropertyDoubleSpinBoxDelegate::createEditor( int type, QWidget *parent,
403 const QStyleOptionViewItem & option, const QModelIndex & index ) const
404{
405 Q_UNUSED(type);
406
407 KProperty *prop = KPropertyUtils::propertyForIndex(index);
408 if (!prop) {
409 return nullptr;
410 }
411 return new KPropertyDoubleSpinBox(*prop, parent, option.rect.height() - 2 - 1);
412}
Double editor.
Definition spinbox.h:62
KPropertyDoubleSpinBox(const KProperty &prop, QWidget *parent, int itemHeight)
Definition spinbox.cpp:256
const KPropertyEditorCreatorOptions * options() const
Options for editor creating.
A delegate supporting Int and UInt types.
Definition spinbox.h:35
The base class representing a single property.
Definition KProperty.h:96
QVariant option(const char *name, const QVariant &defaultValue=QVariant()) const
Returns value of given option Option is set if returned value is not null. If there is no option for ...
int type() const
QVariant value() const
virtual bool event(QEvent *event) override
void setFrame(bool)
virtual void resizeEvent(QResizeEvent *event) override
void setSpecialValueText(const QString &txt)
void setDecimals(int prec)
void setPrefix(const QString &prefix)
void setRange(double minimum, double maximum)
void setSingleStep(double val)
void setSuffix(const QString &suffix)
void setValue(double val)
void valueChanged(double d)
int pixelSize() const const
int pointSize() const const
void setAlignment(Qt::Alignment flag)
void setFrame(bool)
QString toString(qlonglong i) const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString fromLatin1(const char *str, int size)
AlignLeft
bool canConvert(int targetTypeId) const const
void clear()
bool isNull() const const
bool isValid() const const
double toDouble(bool *ok) const const
int toInt(bool *ok) const const
qreal toReal(bool *ok) const const
void setContentsMargins(int left, int top, int right, int bottom)
void setStyleSheet(const QString &styleSheet)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sun Feb 25 2024 18:41:55 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.