KProperty

spinbox.cpp
1 /* This file is part of the KDE project
2  Copyright (C) 2004 Cedric Pasteur <[email protected]>
3  Copyright (C) 2004 Alexander Dymo <[email protected]>
4  Copyright (C) 2008-2017 Jarosław Staniek <[email protected]>
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 
37 static 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 
44 static QString cssForSpinBox(const char *_class, const QFont& font, int itemHeight)
45 {
46  return QString::fromLatin1(
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 
58 namespace {
59 
60 void 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 
94 int 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 
115 class Q_DECL_HIDDEN KPropertyIntSpinBox::Private
116 {
117 public:
118  explicit Private(const KProperty& prop) : property(&prop)
119  {
120  }
121 
122  const KProperty * const property;
123 };
124 
125 KPropertyIntSpinBox::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 
157 KPropertyIntSpinBox::~KPropertyIntSpinBox()
158 {
159  delete d;
160 }
161 
162 QVariant KPropertyIntSpinBox::value() const
163 {
164  if (d->property->type() == KProperty::UInt) {
165  return uint(QSpinBox::value());
166  }
167  return QSpinBox::value();
168 }
169 
170 void 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 
178 void KPropertyIntSpinBox::slotValueChanged(int value)
179 {
180  Q_UNUSED(value);
181  emit commitData(this);
182 }
183 
184 //-----------------------
185 
186 class Q_DECL_HIDDEN KPropertyDoubleSpinBox::Private
187 {
188 public:
189  explicit Private(const KProperty& prop) : property(&prop)
190  {
191  }
192 
193  const KProperty * const property;
194 };
195 
196 namespace {
197 
198 void 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 
226 double 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 
245 QVariant 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  }
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 
305 KPropertyDoubleSpinBox::~KPropertyDoubleSpinBox()
306 {
307  delete d;
308 }
309 
310 void KPropertyDoubleSpinBox::resizeEvent( QResizeEvent * event )
311 {
313 }
314 
315 void 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 
323 void KPropertyDoubleSpinBox::slotValueChanged(double value)
324 {
325  Q_UNUSED(value);
326  emit commitData(this);
327 }
328 
329 //-----------------------
330 
331 KPropertyIntSpinBoxDelegate::KPropertyIntSpinBoxDelegate()
332 {
333 }
334 
335 QString 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 
351 QString KPropertyIntSpinBoxDelegate::valueToString(const QVariant& value, const QLocale &locale) const
352 {
353  return locale.toString(value.toReal(), 'f', 0);
354 }
355 
356 QWidget* 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 
370 KPropertyDoubleSpinBoxDelegate::KPropertyDoubleSpinBoxDelegate()
371 {
372 }
373 
374 QString 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 
397 QString KPropertyDoubleSpinBoxDelegate::valueToString(const QVariant& value, const QLocale &locale) const
398 {
399  return locale.toString(value.toReal());
400 }
401 
402 QWidget* 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 }
bool canConvert(int targetTypeId) const const
void setStyleSheet(const QString &styleSheet)
virtual bool event(QEvent *event) override
int pixelSize() const const
QString toString(qlonglong i) const const
A delegate supporting Int and UInt types.
Definition: spinbox.h:34
void setRange(double minimum, double maximum)
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 ...
Definition: KProperty.cpp:564
AlignLeft
void setPrefix(const QString &prefix)
KPropertyDoubleSpinBox(const KProperty &prop, QWidget *parent, int itemHeight)
Definition: spinbox.cpp:256
void setSingleStep(double val)
int toInt(bool *ok) const const
bool isNull() const const
void valueChanged(double d)
void setDecimals(int prec)
void setSuffix(const QString &suffix)
void setValue(double val)
Double editor.
Definition: spinbox.h:61
QLocale locale() const const
void clear()
const QFont & font() const const
void setAlignment(Qt::Alignment flag)
The base class representing a single property.
Definition: KProperty.h:95
int type() const
Definition: KProperty.cpp:366
void setFrame(bool)
QVariant value() const
Definition: KProperty.cpp:394
virtual void resizeEvent(QResizeEvent *event) override
int value() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
void setFrame(bool)
void setSpecialValueText(const QString &txt)
QString fromLatin1(const char *str, int size)
bool isValid() const const
double toDouble(bool *ok) const const
qreal toReal(bool *ok) const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int pointSize() const const
void setContentsMargins(int left, int top, int right, int bottom)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Wed Sep 23 2020 23:03:56 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.