VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIWidgetValidator.cpp@ 35740

Last change on this file since 35740 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.8 KB
Line 
1/* $Id: QIWidgetValidator.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 *
4 * VBox frontends: Qt GUI ("VirtualBox"):
5 * VirtualBox Qt extensions: QIWidgetValidator class implementation
6 */
7
8/*
9 * Copyright (C) 2006-2007 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#include "QIWidgetValidator.h"
21
22/* Qt includes */
23#include <QLineEdit>
24#include <QComboBox>
25#include <QLabel>
26
27#include <iprt/assert.h>
28
29#include "VBoxGlobal.h"
30
31/** @class QIWidgetValidator
32 *
33 * The QIWidgetValidator class is a widget validator. Its purpose is to
34 * answer the question: whether all relevant (grand) children of the given
35 * widget are valid or not. Relevant children are those widgets which
36 * receive some user input that can be checked for validity (i.e. they
37 * have a validator() method that returns a pointer to a QValidator instance
38 * used to validate widget's input). The QLineEdit class is an example of
39 * such a widget.
40 *
41 * When a QIWidgetValidator instance is created it receives a pointer to
42 * a widget whose children should be checked for validity. The instance
43 * connects itself to signals emitted by input widgets when their contents
44 * changes, and emits its own signal, validityChanged() (common for all
45 * child widgets being observed), whenever the change happens.
46 *
47 * Objects that want to know when the validity state changes should connect
48 * themselves to the validityChanged() signal and then use the isValid()
49 * method to determine whether all children are valid or not.
50 *
51 * It is assumed that all children that require validity checks have been
52 * already added to the widget when it is passed to the QIWidgetValidator
53 * constructor. If other children (that need to be validated) are added
54 * later, it's necessary to call the rescan() method to rescan the widget
55 * hierarchy again, otherwise the results of validity checks are undefined.
56 *
57 * It's also necessary to call the revalidate() method every time the
58 * enabled state of the child widget is changed, because QIWidgetValidator
59 * skips disabled widgets when it calculates the combined validity state.
60 *
61 * This class is useful for example for QWizard dialogs, where a separate
62 * instance validates every page of the wizard that has children to validate,
63 * and the validityChanged() signal of every instance is connected to some
64 * signal of the QWizard subclass, that enables or disables the Next button,
65 * depending on the result of the validity check.
66 *
67 * Currently, only QLineEdit and QComboBox classes and their successors are
68 * recognized by QIWidgetValidator. It uses the QLineEdit::hasAcceptableInput()
69 * and QCombobox::validator() methods to determine the validity state o
70 * the corresponding widgets (note that the QComboBox widget must be editable,
71 * otherwise it will be skipped).
72 */
73
74/**
75 * Constructs a new instance that will check the validity of children
76 * of the given widget.
77 *
78 * @param aWidget Widget whose children should be checked.
79 */
80QIWidgetValidator::QIWidgetValidator (QWidget *aWidget, QObject *aParent)
81 : QObject (aParent)
82 , mWidget (aWidget)
83 , mOtherValid (true)
84{
85 rescan();
86}
87
88/**
89 * Constructs a new instance that will check the validity of children
90 * of the given widget.
91 *
92 * @param aCaption Caption to use for the warning message.
93 * @param aWidget Widget whose children should be checked.
94 */
95QIWidgetValidator::QIWidgetValidator (const QString &aCaption,
96 QWidget *aWidget, QObject *aParent)
97 : QObject (aParent)
98 , mCaption (aCaption)
99 , mWidget (aWidget)
100 , mOtherValid (true)
101{
102 rescan();
103}
104
105/**
106 * Destructs this validator instance.
107 * Before destruction, the #validityChanged() signal is emitted; the
108 * value of #isValid() is always true at this time.
109 */
110QIWidgetValidator::~QIWidgetValidator()
111{
112 mWidget = 0;
113 doRevalidate();
114}
115
116//
117// Public members
118/////////////////////////////////////////////////////////////////////////////
119
120/** @fn QIWidgetValidator::widget() const
121 *
122 * Returns a widget managed by this instance.
123 */
124
125/**
126 * Returns true if all relevant children of the widget managed by this
127 * instance are valid AND if #isOtherValid() returns true; otherwise returns
128 * false. Disabled children and children without validation
129 * are skipped and don't affect the result.
130 *
131 * The method emits the #isValidRequested() signal before calling
132 * #isOtherValid(), thus giving someone an opportunity to affect its result by
133 * calling #setOtherValid() from the signal handler. Note that #isOtherValid()
134 * returns true by default, until #setOtherValid( false ) is called.
135 *
136 * @note If #isOtherValid() returns true this method does a hierarchy scan, so
137 * it's a good idea to store the returned value in a local variable if needed
138 * more than once within a context of a single check.
139 */
140bool QIWidgetValidator::isValid() const
141{
142 // wgt is null, we assume we're valid
143 if (!mWidget)
144 return true;
145
146 QIWidgetValidator *that = const_cast <QIWidgetValidator *> (this);
147 emit that->isValidRequested (that);
148 if (!isOtherValid())
149 return false;
150
151 QValidator::State state = QValidator::Acceptable;
152
153 foreach (Watched watched, mWatched)
154 {
155 if (watched.widget->inherits ("QLineEdit"))
156 {
157 QLineEdit *le = ((QLineEdit *) watched.widget);
158 Assert (le->validator());
159 if (!le->validator() || !le->isEnabled())
160 continue;
161 QString text = le->text();
162 int pos;
163 state = le->validator()->validate (text, pos);
164 }
165 else if (watched.widget->inherits ("QComboBox"))
166 {
167 QComboBox *cb = ((QComboBox *) watched.widget);
168 Assert (cb->validator());
169 if (!cb->validator() || !cb->isEnabled())
170 continue;
171 QString text = cb->lineEdit()->text();
172 int pos;
173 state = cb->lineEdit()->validator()->validate (text, pos);
174 }
175
176 if (state != QValidator::Acceptable)
177 {
178 that->mLastInvalid = watched;
179 that->mLastInvalid.state = state;
180 return false;
181 }
182 }
183
184 /* reset last invalid */
185 that->mLastInvalid = Watched();
186 return true;
187}
188
189/**
190 * Rescans all (grand) children of the managed widget and:
191 *
192 * 1) remembers all supported widgets with validators to speed up further
193 * validation;
194 *
195 * 2) connects itself to those that can be validated, in order to emit the
196 * validityChanged() signal to give its receiver an opportunity to do
197 * useful actions.
198 *
199 * Must be called every time a child widget is added or removed.
200 */
201void QIWidgetValidator::rescan()
202{
203 if (!mWidget)
204 return;
205
206 mWatched.clear();
207
208 Watched watched;
209
210 QList<QWidget *> list = mWidget->findChildren<QWidget *>();
211 QWidget *wgt;
212
213 /* detect all widgets that support validation */
214 QListIterator<QWidget *> it (list);
215 while (it.hasNext())
216 {
217 wgt = it.next();
218
219 if (QLineEdit *le = qobject_cast<QLineEdit *> (wgt))
220 {
221 if (!le->validator())
222 continue;
223 /* disconnect to avoid duplicate connections */
224 disconnect (le, SIGNAL (editingFinished ()),
225 this, SLOT (doRevalidate()));
226 disconnect (le, SIGNAL (cursorPositionChanged (int, int)),
227 this, SLOT (doRevalidate()));
228 disconnect (le, SIGNAL (textChanged (const QString &)),
229 this, SLOT (doRevalidate()));
230 /* Use all signals which indicate some change in the text. The
231 * textChanged signal isn't sufficient in Qt4. */
232 connect (le, SIGNAL (textChanged (const QString &)),
233 this, SLOT (doRevalidate()));
234 connect (le, SIGNAL (cursorPositionChanged (int, int)),
235 this, SLOT (doRevalidate()));
236 connect (le, SIGNAL (editingFinished ()),
237 this, SLOT (doRevalidate()));
238 }
239 else if (QComboBox *cb = qobject_cast<QComboBox *> (wgt))
240 {
241
242 if (!cb->validator() || !cb->lineEdit())
243 continue;
244 /* disconnect to avoid duplicate connections */
245 disconnect (cb, SIGNAL (textChanged (const QString &)),
246 this, SLOT (doRevalidate()));
247 connect (cb, SIGNAL (textChanged (const QString &)),
248 this, SLOT (doRevalidate()));
249 }
250
251 watched.widget = wgt;
252
253 /* try to find a buddy widget in order to determine the title for
254 * the watched widget which is used in the warning text */
255 QListIterator<QWidget *> it2 (list);
256 while (it2.hasNext())
257 {
258 wgt = it2.next();
259 if (QLabel *label = qobject_cast<QLabel *> (wgt))
260 if (label->buddy() == watched.widget)
261 {
262 watched.buddy = label;
263 break;
264 }
265 }
266
267 /* memorize */
268 mWatched << watched;
269 }
270}
271
272/**
273 * Returns a message that describes the last detected error (invalid or
274 * incomplete input).
275 *
276 * This message uses the caption text passed to the constructor as a page
277 * name to refer to. If the caption is NULL, this function will return a null
278 * string.
279 *
280 * Also, if the failed widget has a buddy widget, this buddy widget's text
281 * will be used as a field name to refer to.
282 */
283QString QIWidgetValidator::warningText() const
284{
285 /* cannot generate an informative message if no caption provided */
286 if (mCaption.isEmpty())
287 return QString::null;
288
289 if (mLastInvalid.state == QValidator::Acceptable)
290 return QString::null;
291
292 AssertReturn (mLastInvalid.widget, QString::null);
293
294 QString title;
295 if (mLastInvalid.buddy != NULL)
296 {
297 if (mLastInvalid.buddy->inherits ("QLabel"))
298 {
299 /* Remove '&' symbol from the buddy field name */
300 title = VBoxGlobal::
301 removeAccelMark (((QLabel *) mLastInvalid.buddy)->text());
302
303 /* Remove ':' symbol from the buddy field name */
304 title = title.remove (':');
305 }
306 }
307
308 QString state;
309 if (mLastInvalid.state == QValidator::Intermediate)
310 state = tr ("not complete", "value state");
311 else
312 state = tr ("invalid", "value state");
313
314 if (!title.isEmpty())
315 return tr ("<qt>The value of the <b>%1</b> field "
316 "on the <b>%2</b> page is %3.</qt>")
317 .arg (title, mCaption, state);
318
319 return tr ("<qt>One of the values "
320 "on the <b>%1</b> page is %2.</qt>")
321 .arg (mCaption, state);
322}
323
324/** @fn QIWidgetValidator::setOtherValid()
325 *
326 * Sets the generic validity flag to true or false depending on the
327 * argument.
328 *
329 * @see #isOtherValid()
330 */
331
332/** @fn QIWidgetValidator::isOtherValid()
333 *
334 * Returns the current value of the generic validity flag.
335 * This generic validity flag is used by #isValid() to determine
336 * the overall validity of the managed widget. This flag is true by default,
337 * until #setOtherValid( false ) is called.
338 */
339
340/** @fn QIWidgetValidator::validityChanged( const QIWidgetValidator * ) const
341 *
342 * Emitted when any of the relevant children of the widget managed by this
343 * instance changes its validity state. The argument is this instance.
344 */
345
346/** @fn QIWidgetValidator::isValidRequested( const QIWidgetValidator * ) const
347 *
348 * Emitted whenever #sValid() is called, right before querying the generic
349 * validity value using the #isOtherValid() method.
350 * The argument is this instance.
351 */
352
353/** @fn QIWidgetValidator::revalidate()
354 *
355 * Emits the validityChanged() signal, from where receivers can use the
356 * isValid() method to check for validity.
357 */
358
359
360/** @class QIULongValidator
361 *
362 * The QIULongValidator class is a QIntValidator-like class to validate
363 * unsigned integer numbers. As opposed to QIntValidator, this class accepts
364 * all three integer number formats: decimal, hexadecimal (the string starts
365 * with "0x") and octal (the string starts with "0").
366 */
367
368QValidator::State QIULongValidator::validate (QString &aInput, int &aPos) const
369{
370 Q_UNUSED (aPos);
371
372 QString stripped = aInput.trimmed();
373
374 if (stripped.isEmpty() ||
375 stripped.toUpper() == QString ("0x").toUpper())
376 return Intermediate;
377
378 bool ok;
379 ulong entered = aInput.toULong (&ok, 0);
380
381 if (!ok)
382 return Invalid;
383
384 if (entered >= mBottom && entered <= mTop)
385 return Acceptable;
386
387 return (entered > mTop ) ? Invalid : Intermediate;
388}
389
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use