VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/widgets/UIFormEditorWidget.cpp@ 100347

Last change on this file since 100347 was 100346, checked in by vboxsync, 17 months ago

FE/Qt: bugref:10450: Actually QItemEditorFactory was never using QVariant::Type, which is deprecated now.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 61.3 KB
Line 
1/* $Id: UIFormEditorWidget.cpp 100346 2023-07-03 11:22:58Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIFormEditorWidget class implementation.
4 */
5
6/*
7 * Copyright (C) 2019-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QComboBox>
30#include <QEvent>
31#include <QHeaderView>
32#include <QItemEditorFactory>
33#include <QLineEdit>
34#include <QPointer>
35#include <QPushButton>
36#include <QSortFilterProxyModel>
37#include <QSpinBox>
38#include <QTextEdit>
39#include <QVBoxLayout>
40
41/* GUI includes: */
42#include "QIDialog.h"
43#include "QIDialogButtonBox.h"
44#include "QIStyledItemDelegate.h"
45#include "QITableView.h"
46#include "QIWithRetranslateUI.h"
47#include "UIFormEditorWidget.h"
48#include "UIIconPool.h"
49#include "UINotificationCenter.h"
50
51/* COM includes: */
52#include "CBooleanFormValue.h"
53#include "CChoiceFormValue.h"
54#include "CForm.h"
55#include "CFormValue.h"
56#include "CRangedIntegerFormValue.h"
57#include "CRangedInteger64FormValue.h"
58#include "CStringFormValue.h"
59#include "CSystemProperties.h"
60#include "CVirtualSystemDescriptionForm.h"
61
62/* VirtualBox interface declarations: */
63#include <VBox/com/VirtualBox.h>
64
65/* External includes: */
66#include <math.h>
67
68
69/** Form Editor data types. */
70enum UIFormEditorDataType
71{
72 UIFormEditorDataType_Name,
73 UIFormEditorDataType_Value,
74 UIFormEditorDataType_Max
75};
76
77
78/** Class used to hold text data. */
79class TextData
80{
81public:
82
83 /** Constructs null text data. */
84 TextData() {}
85 /** Constructs text data on the basis of passed @a strText and @a index. */
86 TextData(const QString &strText, const QModelIndex index = QModelIndex())
87 : m_strText(strText), m_index(index) {}
88 /** Constructs text data on the basis of @a another text data. */
89 TextData(const TextData &another)
90 : m_strText(another.text()), m_index(another.index()) {}
91
92 /** Assigns values of @a another text to this one. */
93 TextData &operator=(const TextData &another)
94 {
95 m_strText = another.text();
96 m_index = another.index();
97 return *this;
98 }
99
100 /** Returns text value. */
101 QString text() const { return m_strText; }
102
103 /** Defines model @a index. */
104 void setIndex(const QModelIndex &index) { m_index = index; }
105 /** Returns model index. */
106 QModelIndex index() const { return m_index; }
107
108private:
109
110 /** Holds text value. */
111 QString m_strText;
112 /** Holds model index. */
113 QModelIndex m_index;
114};
115Q_DECLARE_METATYPE(TextData);
116
117
118/** Class used to hold choice data. */
119class ChoiceData
120{
121public:
122
123 /** Constructs null choice data. */
124 ChoiceData()
125 : m_iSelectedIndex(-1) {}
126 /** Constructs choice data on the basis of passed @a values and @a iSelectedIndex. */
127 ChoiceData(const QVector<QString> &values, int iSelectedIndex)
128 : m_values(values), m_iSelectedIndex(iSelectedIndex) {}
129 /** Constructs choice data on the basis of @a another choice data. */
130 ChoiceData(const ChoiceData &another)
131 : m_values(another.values()), m_iSelectedIndex(another.selectedIndex()) {}
132
133 /** Assigns values of @a another choice to this one. */
134 ChoiceData &operator=(const ChoiceData &another)
135 {
136 m_values = another.values();
137 m_iSelectedIndex = another.selectedIndex();
138 return *this;
139 }
140
141 /** Returns values vector. */
142 QVector<QString> values() const { return m_values; }
143 /** Returns selected index. */
144 int selectedIndex() const { return m_iSelectedIndex; }
145 /** Returns selected value. */
146 QString selectedValue() const
147 {
148 return m_iSelectedIndex >= 0 && m_iSelectedIndex < m_values.size()
149 ? m_values.at(m_iSelectedIndex) : QString();
150 }
151
152private:
153
154 /** Holds values vector. */
155 QVector<QString> m_values;
156 /** Holds selected index. */
157 int m_iSelectedIndex;
158};
159Q_DECLARE_METATYPE(ChoiceData);
160
161
162/** Class used to hold ranged-integer data. */
163class RangedIntegerData
164{
165public:
166
167 /** Constructs null ranged-integer data. */
168 RangedIntegerData()
169 : m_iMinimum(-1), m_iMaximum(-1)
170 , m_iInteger(-1), m_strSuffix(QString()) {}
171 /** Constructs ranged-integer data on the basis of passed @a iMinimum, @a iMaximum, @a iInteger and @a strSuffix. */
172 RangedIntegerData(int iMinimum, int iMaximum, int iInteger, const QString strSuffix)
173 : m_iMinimum(iMinimum), m_iMaximum(iMaximum)
174 , m_iInteger(iInteger), m_strSuffix(strSuffix) {}
175 /** Constructs ranged-integer data on the basis of @a another ranged-integer data. */
176 RangedIntegerData(const RangedIntegerData &another)
177 : m_iMinimum(another.minimum()), m_iMaximum(another.maximum())
178 , m_iInteger(another.integer()), m_strSuffix(another.suffix()) {}
179
180 /** Assigns values of @a another ranged-integer to this one. */
181 RangedIntegerData &operator=(const RangedIntegerData &another)
182 {
183 m_iMinimum = another.minimum();
184 m_iMaximum = another.maximum();
185 m_iInteger = another.integer();
186 m_strSuffix = another.suffix();
187 return *this;
188 }
189
190 /** Returns minimum value. */
191 int minimum() const { return m_iMinimum; }
192 /** Returns maximum value. */
193 int maximum() const { return m_iMaximum; }
194 /** Returns current value. */
195 int integer() const { return m_iInteger; }
196 /** Returns suffix value. */
197 QString suffix() const { return m_strSuffix; }
198
199private:
200
201 /** Holds minimum value. */
202 int m_iMinimum;
203 /** Holds maximum value. */
204 int m_iMaximum;
205 /** Holds current value. */
206 int m_iInteger;
207 /** Holds suffix value. */
208 QString m_strSuffix;
209};
210Q_DECLARE_METATYPE(RangedIntegerData);
211
212
213/** Class used to hold ranged-integer64 data. */
214class RangedInteger64Data
215{
216public:
217
218 /** Constructs null ranged-integer64 data. */
219 RangedInteger64Data()
220 : m_iMinimum(-1), m_iMaximum(-1)
221 , m_iInteger(-1), m_strSuffix(QString()) {}
222 /** Constructs ranged-integer64 data on the basis of passed @a iMinimum, @a iMaximum, @a iInteger and @a strSuffix. */
223 RangedInteger64Data(qlonglong iMinimum, qlonglong iMaximum, qlonglong iInteger, const QString strSuffix)
224 : m_iMinimum(iMinimum), m_iMaximum(iMaximum)
225 , m_iInteger(iInteger), m_strSuffix(strSuffix) {}
226 /** Constructs ranged-integer64 data on the basis of @a another ranged-integer data. */
227 RangedInteger64Data(const RangedInteger64Data &another)
228 : m_iMinimum(another.minimum()), m_iMaximum(another.maximum())
229 , m_iInteger(another.integer()), m_strSuffix(another.suffix()) {}
230
231 /** Assigns values of @a another ranged-integer to this one. */
232 RangedInteger64Data &operator=(const RangedInteger64Data &another)
233 {
234 m_iMinimum = another.minimum();
235 m_iMaximum = another.maximum();
236 m_iInteger = another.integer();
237 m_strSuffix = another.suffix();
238 return *this;
239 }
240
241 /** Returns minimum value. */
242 qlonglong minimum() const { return m_iMinimum; }
243 /** Returns maximum value. */
244 qlonglong maximum() const { return m_iMaximum; }
245 /** Returns current value. */
246 qlonglong integer() const { return m_iInteger; }
247 /** Returns suffix value. */
248 QString suffix() const { return m_strSuffix; }
249
250private:
251
252 /** Holds minimum value. */
253 qlonglong m_iMinimum;
254 /** Holds maximum value. */
255 qlonglong m_iMaximum;
256 /** Holds current value. */
257 qlonglong m_iInteger;
258 /** Holds suffix value. */
259 QString m_strSuffix;
260};
261Q_DECLARE_METATYPE(RangedInteger64Data);
262
263
264/** QWidget extension used as dummy TextData editor.
265 * It's not actually an editor, but Edit... button instead which opens
266 * real editor passing stored model index received from TextData value. */
267class TextEditor : public QIWithRetranslateUI<QWidget>
268{
269 Q_OBJECT;
270 Q_PROPERTY(TextData text READ text WRITE setText USER true);
271
272public:
273
274 /** Constructs TextData editor passing @a pParent to the base-class. */
275 TextEditor(QWidget *pParent = 0);
276
277protected:
278
279 /** Handles translation event. */
280 virtual void retranslateUi() RT_OVERRIDE;
281
282private slots:
283
284 /** Handles button click. */
285 void sltHandleButtonClick();
286
287private:
288
289 /** Prepares all. */
290 void prepare();
291
292 /** Defines @a text. */
293 void setText(const TextData &text);
294 /** Returns text. */
295 TextData text() const;
296
297 /** Holds the button instance. */
298 QPushButton *m_pButton;
299 /** Holds the multiline text. */
300 QString m_strMultilineText;
301 /** Holds the model index. */
302 QModelIndex m_index;
303};
304
305
306/** QComboBox extension used as ChoiceData editor. */
307class ChoiceEditor : public QComboBox
308{
309 Q_OBJECT;
310 Q_PROPERTY(ChoiceData choice READ choice WRITE setChoice USER true);
311
312signals:
313
314 /** Notifies listener about data should be committed. */
315 void sigCommitData(QWidget *pThis);
316
317public:
318
319 /** Constructs ChoiceData editor passing @a pParent to the base-class. */
320 ChoiceEditor(QWidget *pParent = 0);
321
322private slots:
323
324 /** Handles current index change. */
325 void sltCurrentIndexChanged();
326
327private:
328
329 /** Defines the @a choice. */
330 void setChoice(const ChoiceData &choice);
331 /** Returns the choice. */
332 ChoiceData choice() const;
333};
334
335
336/** QSpinBox extension used as RangedIntegerData editor. */
337class RangedIntegerEditor : public QSpinBox
338{
339 Q_OBJECT;
340 Q_PROPERTY(RangedIntegerData rangedInteger READ rangedInteger WRITE setRangedInteger USER true);
341
342public:
343
344 /** Constructs RangedIntegerData editor passing @a pParent to the base-class. */
345 RangedIntegerEditor(QWidget *pParent = 0);
346
347private:
348
349 /** Defines @a rangedInteger. */
350 void setRangedInteger(const RangedIntegerData &rangedInteger);
351 /** Returns ranged-integer. */
352 RangedIntegerData rangedInteger() const;
353
354 /** Holds the unchanged suffix. */
355 QString m_strSuffix;
356};
357
358
359/** QLineEdit extension used as RangedInteger64Data editor. */
360class RangedInteger64Editor : public QLineEdit
361{
362 Q_OBJECT;
363 Q_PROPERTY(RangedInteger64Data rangedInteger64 READ rangedInteger64 WRITE setRangedInteger64 USER true);
364
365public:
366
367 /** Constructs RangedInteger64Data editor passing @a pParent to the base-class. */
368 RangedInteger64Editor(QWidget *pParent = 0);
369
370private:
371
372 /** Defines @a rangedInteger. */
373 void setRangedInteger64(const RangedInteger64Data &rangedInteger64);
374 /** Returns ranged-integer. */
375 RangedInteger64Data rangedInteger64() const;
376
377 /** Holds the minimum guest RAM in MBs. */
378 qlonglong m_iMinimumGuestRAM;
379 /** Holds the maximum value. */
380 qlonglong m_iMaximumGuestRAM;
381
382 /** Holds the minimum value. */
383 qlonglong m_iMinimum;
384 /** Holds the maximum value. */
385 qlonglong m_iMaximum;
386 /** Holds the unchanged suffix. */
387 QString m_strSuffix;
388};
389
390
391/** QITableViewCell extension used as Form Editor table-view cell. */
392class UIFormEditorCell : public QITableViewCell
393{
394 Q_OBJECT;
395
396public:
397
398 /** Constructs table cell on the basis of certain @a strText, passing @a pParent to the base-class. */
399 UIFormEditorCell(QITableViewRow *pParent, const QString &strText = QString());
400
401 /** Returns the cell text. */
402 virtual QString text() const RT_OVERRIDE { return m_strText; }
403
404 /** Defines the cell @a strText. */
405 void setText(const QString &strText) { m_strText = strText; }
406
407private:
408
409 /** Holds the cell text. */
410 QString m_strText;
411};
412
413
414/** QITableViewRow extension used as Form Editor table-view row. */
415class UIFormEditorRow : public QITableViewRow
416{
417 Q_OBJECT;
418
419public:
420
421 /** Constructs table row on the basis of certain @a comValue, passing @a pParent to the base-class.
422 * @param pFormEditorWidget Brings the root form-editor widget reference. */
423 UIFormEditorRow(QITableView *pParent, UIFormEditorWidget *pFormEditorWidget, const CFormValue &comValue);
424 /** Destructs table row. */
425 virtual ~UIFormEditorRow() RT_OVERRIDE;
426
427 /** Returns value type. */
428 KFormValueType valueType() const { return m_enmValueType; }
429
430 /** Returns the row name as string. */
431 QString nameToString() const;
432 /** Returns the row value as string. */
433 QString valueToString() const;
434
435 /** Returns whether the row is enabled. */
436 bool isEnabled() const;
437 /** Returns whether the row is visible. */
438 bool isVisible() const;
439
440 /** Returns value cast to bool. */
441 bool toBool() const;
442 /** Defines @a fBool value. */
443 void setBool(bool fBool);
444
445 /** Returns whether cached string value is multiline. */
446 bool isMultilineString() const;
447 /** Returns value cast to text. */
448 TextData toText() const;
449 /** Defines @a text value. */
450 void setText(const TextData &text);
451 /** Returns value cast to string. */
452 QString toString() const;
453 /** Defines @a strString value. */
454 void setString(const QString &strString);
455
456 /** Returns value cast to choice. */
457 ChoiceData toChoice() const;
458 /** Defines @a choice value. */
459 void setChoice(const ChoiceData &choice);
460
461 /** Returns value cast to ranged-integer. */
462 RangedIntegerData toRangedInteger() const;
463 /** Defines @a rangedInteger value. */
464 void setRangedInteger(const RangedIntegerData &rangedInteger);
465
466 /** Returns value cast to ranged-integer64. */
467 RangedInteger64Data toRangedInteger64() const;
468 /** Defines @a rangedInteger64 value. */
469 void setRangedInteger64(const RangedInteger64Data &rangedInteger64);
470
471 /** Updates value cells. */
472 void updateValueCells();
473
474 /** Check whether generation value is changed. */
475 bool isGenerationChanged() const;
476
477protected:
478
479 /** Returns the number of children. */
480 virtual int childCount() const RT_OVERRIDE;
481 /** Returns the child item with @a iIndex. */
482 virtual QITableViewCell *childItem(int iIndex) const RT_OVERRIDE;
483
484private:
485
486 /** Prepares all. */
487 void prepare();
488 /** Cleanups all. */
489 void cleanup();
490
491 /** Holds the root form-editor widget reference. */
492 UIFormEditorWidget *m_pFormEditorWidget;
493
494 /** Holds the row value. */
495 CFormValue m_comValue;
496
497 /** Holds the value type. */
498 KFormValueType m_enmValueType;
499
500 /** Holds current generation value. */
501 int m_iGeneration;
502
503 /** Holds cached bool value. */
504 bool m_fBool;
505 /** Holds whether cached string value is multiline. */
506 bool m_fMultilineString;
507 /** Holds cached text value. */
508 TextData m_text;
509 /** Holds cached string value. */
510 QString m_strString;
511 /** Holds cached choice value. */
512 ChoiceData m_choice;
513 /** Holds cached ranged-integer value. */
514 RangedIntegerData m_rangedInteger;
515 /** Holds cached ranged-integer64 value. */
516 RangedInteger64Data m_rangedInteger64;
517
518 /** Holds the cell instances. */
519 QVector<UIFormEditorCell*> m_cells;
520};
521
522
523/** QAbstractTableModel subclass used as Form Editor data model. */
524class UIFormEditorModel : public QAbstractTableModel
525{
526 Q_OBJECT;
527
528public:
529
530 /** Constructs Form Editor model passing @a pParent to the base-class. */
531 UIFormEditorModel(UIFormEditorWidget *pParent);
532 /** Destructs Port Forwarding model. */
533 virtual ~UIFormEditorModel() RT_OVERRIDE;
534
535 /** Clears form. */
536 void clearForm();
537 /** Defines form @a values. */
538 void setFormValues(const CFormValueVector &values);
539
540 /** Returns the number of children. */
541 int childCount() const;
542 /** Returns the child item with @a iIndex. */
543 QITableViewRow *childItem(int iIndex) const;
544
545 /** Returns the index of the item in the model specified by the given @a iRow, @a iColumn and @a parentIdx. */
546 virtual QModelIndex index(int iRow, int iColumn, const QModelIndex &parentIdx = QModelIndex()) const RT_OVERRIDE;
547
548 /** Returns flags for item with certain @a index. */
549 virtual Qt::ItemFlags flags(const QModelIndex &index) const RT_OVERRIDE;
550
551 /** Returns row count of certain @a parent. */
552 virtual int rowCount(const QModelIndex &parent = QModelIndex()) const RT_OVERRIDE;
553 /** Returns column count of certain @a parent. */
554 virtual int columnCount(const QModelIndex &parent = QModelIndex()) const RT_OVERRIDE;
555
556 /** Returns header data for @a iSection, @a enmOrientation and @a iRole specified. */
557 virtual QVariant headerData(int iSection, Qt::Orientation enmOrientation, int iRole) const RT_OVERRIDE;
558
559 /** Defines the @a iRole data for item with @a index as @a value. */
560 virtual bool setData(const QModelIndex &index, const QVariant &value, int iRole = Qt::EditRole) RT_OVERRIDE;
561 /** Returns the @a iRole data for item with @a index. */
562 virtual QVariant data(const QModelIndex &index, int iRole) const RT_OVERRIDE;
563
564 /** Creates actual TextData editor for specified @a index. */
565 void createTextDataEditor(const QModelIndex &index);
566
567private:
568
569 /** Prepares all. */
570 void prepare();
571
572 /** Returns the parent table-view reference. */
573 QITableView *view() const;
574
575 /** Updates row generation values. */
576 void updateGeneration();
577
578 /** Returns icon hint for specified @a strItemName. */
579 QIcon iconHint(const QString &strItemName) const;
580
581 /** Holds the root form-editor widget reference. */
582 UIFormEditorWidget *m_pFormEditorWidget;
583
584 /** Holds the Form Editor row list. */
585 QList<UIFormEditorRow*> m_dataList;
586
587 /** Holds the hardcoded icon name map. */
588 QMap<QString, QIcon> m_icons;
589};
590
591
592/** QSortFilterProxyModel subclass used as the Form Editor proxy-model. */
593class UIFormEditorProxyModel : public QSortFilterProxyModel
594{
595 Q_OBJECT;
596
597public:
598
599 /** Constructs the Form Editor proxy-model passing @a pParent to the base-class. */
600 UIFormEditorProxyModel(QObject *pParent = 0);
601
602 /** Returns the number of children. */
603 int childCount() const;
604 /** Returns the child item with @a iIndex. */
605 QITableViewRow *childItem(int iIndex) const;
606
607protected:
608
609 /** Returns whether item in the row indicated by the given @a iSourceRow and @a srcParenIdx should be included in the model. */
610 virtual bool filterAcceptsRow(int iSourceRow, const QModelIndex &srcParenIdx) const RT_OVERRIDE;
611};
612
613
614/** QITableView extension used as Form Editor table-view. */
615class UIFormEditorView : public QITableView
616{
617 Q_OBJECT;
618
619public:
620
621 /** Constructs Form Editor table-view. */
622 UIFormEditorView(QWidget *pParent = 0);
623
624protected:
625
626 /** Returns the number of children. */
627 virtual int childCount() const RT_OVERRIDE;
628 /** Returns the child item with @a iIndex. */
629 virtual QITableViewRow *childItem(int iIndex) const RT_OVERRIDE;
630};
631
632
633/*********************************************************************************************************************************
634* Class TextEditor implementation. *
635*********************************************************************************************************************************/
636
637TextEditor::TextEditor(QWidget *pParent /* = 0 */)
638 : QIWithRetranslateUI<QWidget>(pParent)
639 , m_pButton(0)
640{
641 prepare();
642}
643
644void TextEditor::retranslateUi()
645{
646 m_pButton->setText(UIFormEditorWidget::tr("Edit..."));
647}
648
649void TextEditor::sltHandleButtonClick()
650{
651 /* Redirect the edit call if possible: */
652 do
653 {
654 /* Get the view: */
655 if ( !parent()
656 || !parent()->parent())
657 break;
658 UIFormEditorView *pView = qobject_cast<UIFormEditorView*>(parent()->parent());
659
660 /* Get the proxy model: */
661 if ( !pView
662 || !pView->model())
663 break;
664 UIFormEditorProxyModel *pProxyModel = qobject_cast<UIFormEditorProxyModel*>(pView->model());
665
666 /* Get the source model: */
667 if ( !pProxyModel
668 || !pProxyModel->sourceModel())
669 break;
670 UIFormEditorModel *pSourceModel = qobject_cast<UIFormEditorModel*>(pProxyModel->sourceModel());
671
672 /* Execute the call: */
673 if (!pSourceModel)
674 break;
675 pSourceModel->createTextDataEditor(m_index);
676 }
677 while (0);
678}
679
680void TextEditor::prepare()
681{
682 /* Create layout: */
683 QVBoxLayout *pLayout = new QVBoxLayout(this);
684 if (pLayout)
685 {
686 pLayout->setContentsMargins(0, 0, 0 ,0);
687 /* Create button: */
688 m_pButton = new QPushButton(this);
689 if (m_pButton)
690 {
691 connect(m_pButton, &QPushButton::clicked, this, &TextEditor::sltHandleButtonClick);
692 pLayout->addWidget(m_pButton);
693 }
694 }
695
696 /* Apply language settings: */
697 retranslateUi();
698}
699
700void TextEditor::setText(const TextData &text)
701{
702 m_strMultilineText = text.text();
703 m_index = text.index();
704}
705
706TextData TextEditor::text() const
707{
708 return TextData(m_strMultilineText, m_index);
709}
710
711
712/*********************************************************************************************************************************
713* Class ChoiceEditor implementation. *
714*********************************************************************************************************************************/
715
716ChoiceEditor::ChoiceEditor(QWidget *pParent /* = 0 */)
717 : QComboBox(pParent)
718{
719 /* Make sure QIStyledDelegate aware of us: */
720 setProperty("has_sigCommitData", true);
721 /* Configure connections: */
722 connect(this, static_cast<void(ChoiceEditor::*)(int)>(&ChoiceEditor::currentIndexChanged),
723 this, &ChoiceEditor::sltCurrentIndexChanged);
724}
725
726void ChoiceEditor::sltCurrentIndexChanged()
727{
728 emit sigCommitData(this);
729}
730
731void ChoiceEditor::setChoice(const ChoiceData &choice)
732{
733 clear();
734 addItems(choice.values().toList());
735 setCurrentIndex(choice.selectedIndex());
736}
737
738ChoiceData ChoiceEditor::choice() const
739{
740 QVector<QString> choices(count());
741 for (int i = 0; i < count(); ++i)
742 choices[i] = itemText(i);
743 return ChoiceData(choices, currentIndex());
744}
745
746
747/*********************************************************************************************************************************
748* Class RangedIntegerEditor implementation. *
749*********************************************************************************************************************************/
750
751RangedIntegerEditor::RangedIntegerEditor(QWidget *pParent /* = 0 */)
752 : QSpinBox(pParent)
753{
754}
755
756void RangedIntegerEditor::setRangedInteger(const RangedIntegerData &rangedInteger)
757{
758 setMinimum(rangedInteger.minimum());
759 setMaximum(rangedInteger.maximum());
760 setValue(rangedInteger.integer());
761 m_strSuffix = rangedInteger.suffix();
762 setSuffix(m_strSuffix.isEmpty() ? QString() :
763 QString(" %1").arg(QApplication::translate("UICommon", m_strSuffix.toUtf8().constData())));
764}
765
766RangedIntegerData RangedIntegerEditor::rangedInteger() const
767{
768 return RangedIntegerData(minimum(), maximum(), value(), m_strSuffix);
769}
770
771
772/*********************************************************************************************************************************
773* Class RangedInteger64Editor implementation. *
774*********************************************************************************************************************************/
775
776RangedInteger64Editor::RangedInteger64Editor(QWidget *pParent /* = 0 */)
777 : QLineEdit(pParent)
778 , m_iMinimumGuestRAM(0)
779 , m_iMaximumGuestRAM(0)
780 , m_iMinimum(0)
781 , m_iMaximum(0)
782{
783 /* Acquire min/max amount of RAM guest in theory could have: */
784 CSystemProperties comProps = uiCommon().virtualBox().GetSystemProperties();
785 if (comProps.isOk())
786 {
787 m_iMinimumGuestRAM = comProps.GetMinGuestRAM();
788 m_iMaximumGuestRAM = comProps.GetMaxGuestRAM();
789 }
790}
791
792void RangedInteger64Editor::setRangedInteger64(const RangedInteger64Data &rangedInteger64)
793{
794 /* Parse incoming rangedInteger64: */
795 m_iMinimum = rangedInteger64.minimum();
796 m_iMaximum = rangedInteger64.maximum();
797 m_strSuffix = rangedInteger64.suffix();
798 const qlonglong iValue = rangedInteger64.integer();
799
800 /* Acquire effective values: */
801 qlonglong iMinEffective = 0;
802 qlonglong iMaxEffective = 0;
803 qlonglong iValueEffective = 0;
804 /* We wish to represent bytes as megabytes: */
805 if (m_strSuffix == "B")
806 {
807 iMinEffective = m_iMinimum / _1M;
808 iMaxEffective = m_iMaximum / _1M;
809 iValueEffective = iValue / _1M;
810 }
811 /* For now we will keep all the other suffixes untouched: */
812 else
813 {
814 iMinEffective = m_iMinimum;
815 iMaxEffective = m_iMaximum;
816 iValueEffective = iValue;
817 }
818
819 /* Make sure minimum, maximum and actual values are within the bounds: */
820 iMinEffective = qMax(iMinEffective, m_iMinimumGuestRAM);
821 iMaxEffective = qMin(iMaxEffective, m_iMaximumGuestRAM);
822 iValueEffective = qMax(iValueEffective, m_iMinimumGuestRAM);
823 iValueEffective = qMin(iValueEffective, m_iMaximumGuestRAM);
824
825 /* Finally assign validator bounds and actual value: */
826 setValidator(new QIntValidator((int)iMinEffective, (int)iMaxEffective, this));
827 setText(QString::number(iValueEffective));
828}
829
830RangedInteger64Data RangedInteger64Editor::rangedInteger64() const
831{
832 const qlonglong iValueEffective = locale().toLongLong(text());
833
834 /* Acquire literal value: */
835 qlonglong iValue = 0;
836 /* We should bring megabytes back to bytes: */
837 if (m_strSuffix == "B")
838 iValue = iValueEffective * _1M;
839 /* For now we will keep all the other suffixes untouched: */
840 else
841 iValue = iValueEffective;
842 return RangedInteger64Data(m_iMinimum, m_iMaximum, iValue, m_strSuffix);
843}
844
845
846/*********************************************************************************************************************************
847* Class UIFormEditorCell implementation. *
848*********************************************************************************************************************************/
849
850UIFormEditorCell::UIFormEditorCell(QITableViewRow *pParent, const QString &strText /* = QString() */)
851 : QITableViewCell(pParent)
852 , m_strText(strText)
853{
854}
855
856
857/*********************************************************************************************************************************
858* Class UIFormEditorRow implementation. *
859*********************************************************************************************************************************/
860
861UIFormEditorRow::UIFormEditorRow(QITableView *pParent, UIFormEditorWidget *pFormEditorWidget, const CFormValue &comValue)
862 : QITableViewRow(pParent)
863 , m_pFormEditorWidget(pFormEditorWidget)
864 , m_comValue(comValue)
865 , m_enmValueType(KFormValueType_Max)
866 , m_iGeneration(0)
867 , m_fBool(false)
868 , m_fMultilineString(false)
869 , m_text(TextData())
870 , m_strString(QString())
871 , m_choice(ChoiceData())
872 , m_rangedInteger(RangedIntegerData())
873 , m_rangedInteger64(RangedInteger64Data())
874{
875 prepare();
876}
877
878UIFormEditorRow::~UIFormEditorRow()
879{
880 cleanup();
881}
882
883QString UIFormEditorRow::nameToString() const
884{
885 return m_cells.at(UIFormEditorDataType_Name)->text();
886}
887
888QString UIFormEditorRow::valueToString() const
889{
890 return m_cells.at(UIFormEditorDataType_Value)->text();
891}
892
893bool UIFormEditorRow::isEnabled() const
894{
895 return m_comValue.GetEnabled();
896}
897
898bool UIFormEditorRow::isVisible() const
899{
900 return m_comValue.GetVisible();
901}
902
903bool UIFormEditorRow::toBool() const
904{
905 AssertReturn(valueType() == KFormValueType_Boolean, false);
906 return m_fBool;
907}
908
909void UIFormEditorRow::setBool(bool fBool)
910{
911 AssertReturnVoid(valueType() == KFormValueType_Boolean);
912 CBooleanFormValue comValue(m_comValue);
913 UINotificationProgressVsdFormValueSet *pNotification = new UINotificationProgressVsdFormValueSet(comValue,
914 fBool);
915 UINotificationCenter *pCenter = m_pFormEditorWidget->notificationCenter()
916 ? m_pFormEditorWidget->notificationCenter() : gpNotificationCenter;
917 pCenter->handleNow(pNotification);
918 updateValueCells();
919}
920
921bool UIFormEditorRow::isMultilineString() const
922{
923 AssertReturn(valueType() == KFormValueType_String, false);
924 return m_fMultilineString;
925}
926
927TextData UIFormEditorRow::toText() const
928{
929 AssertReturn(valueType() == KFormValueType_String, TextData());
930 return m_text;
931}
932
933void UIFormEditorRow::setText(const TextData &text)
934{
935 AssertReturnVoid(valueType() == KFormValueType_String);
936 CStringFormValue comValue(m_comValue);
937 UINotificationProgressVsdFormValueSet *pNotification = new UINotificationProgressVsdFormValueSet(comValue,
938 text.text());
939 UINotificationCenter *pCenter = m_pFormEditorWidget->notificationCenter()
940 ? m_pFormEditorWidget->notificationCenter() : gpNotificationCenter;
941 pCenter->handleNow(pNotification);
942 updateValueCells();
943}
944
945QString UIFormEditorRow::toString() const
946{
947 AssertReturn(valueType() == KFormValueType_String, QString());
948 return m_strString;
949}
950
951void UIFormEditorRow::setString(const QString &strString)
952{
953 AssertReturnVoid(valueType() == KFormValueType_String);
954 CStringFormValue comValue(m_comValue);
955 UINotificationProgressVsdFormValueSet *pNotification = new UINotificationProgressVsdFormValueSet(comValue,
956 strString);
957 UINotificationCenter *pCenter = m_pFormEditorWidget->notificationCenter()
958 ? m_pFormEditorWidget->notificationCenter() : gpNotificationCenter;
959 pCenter->handleNow(pNotification);
960 updateValueCells();
961}
962
963ChoiceData UIFormEditorRow::toChoice() const
964{
965 AssertReturn(valueType() == KFormValueType_Choice, ChoiceData());
966 return m_choice;
967}
968
969void UIFormEditorRow::setChoice(const ChoiceData &choice)
970{
971 /* Do nothing for empty choices: */
972 if (choice.selectedIndex() == -1)
973 return;
974
975 AssertReturnVoid(valueType() == KFormValueType_Choice);
976 CChoiceFormValue comValue(m_comValue);
977 UINotificationProgressVsdFormValueSet *pNotification = new UINotificationProgressVsdFormValueSet(comValue,
978 choice.selectedIndex());
979 UINotificationCenter *pCenter = m_pFormEditorWidget->notificationCenter()
980 ? m_pFormEditorWidget->notificationCenter() : gpNotificationCenter;
981 pCenter->handleNow(pNotification);
982 updateValueCells();
983}
984
985RangedIntegerData UIFormEditorRow::toRangedInteger() const
986{
987 AssertReturn(valueType() == KFormValueType_RangedInteger, RangedIntegerData());
988 return m_rangedInteger;
989}
990
991void UIFormEditorRow::setRangedInteger(const RangedIntegerData &rangedInteger)
992{
993 AssertReturnVoid(valueType() == KFormValueType_RangedInteger);
994 CRangedIntegerFormValue comValue(m_comValue);
995 UINotificationProgressVsdFormValueSet *pNotification = new UINotificationProgressVsdFormValueSet(comValue,
996 rangedInteger.integer());
997 UINotificationCenter *pCenter = m_pFormEditorWidget->notificationCenter()
998 ? m_pFormEditorWidget->notificationCenter() : gpNotificationCenter;
999 pCenter->handleNow(pNotification);
1000 updateValueCells();
1001}
1002
1003RangedInteger64Data UIFormEditorRow::toRangedInteger64() const
1004{
1005 AssertReturn(valueType() == KFormValueType_RangedInteger64, RangedInteger64Data());
1006 return m_rangedInteger64;
1007}
1008
1009void UIFormEditorRow::setRangedInteger64(const RangedInteger64Data &rangedInteger64)
1010{
1011 AssertReturnVoid(valueType() == KFormValueType_RangedInteger64);
1012 CRangedInteger64FormValue comValue(m_comValue);
1013 UINotificationProgressVsdFormValueSet *pNotification = new UINotificationProgressVsdFormValueSet(comValue,
1014 rangedInteger64.integer());
1015 UINotificationCenter *pCenter = m_pFormEditorWidget->notificationCenter()
1016 ? m_pFormEditorWidget->notificationCenter() : gpNotificationCenter;
1017 pCenter->handleNow(pNotification);
1018 updateValueCells();
1019}
1020
1021void UIFormEditorRow::updateValueCells()
1022{
1023 m_iGeneration = m_comValue.GetGeneration();
1024 /// @todo check for errors
1025
1026 switch (m_enmValueType)
1027 {
1028 case KFormValueType_Boolean:
1029 {
1030 CBooleanFormValue comValue(m_comValue);
1031 m_fBool = comValue.GetSelected();
1032 m_cells[UIFormEditorDataType_Value]->setText(m_fBool ? "True" : "False");
1033 /// @todo check for errors
1034 break;
1035 }
1036 case KFormValueType_String:
1037 {
1038 CStringFormValue comValue(m_comValue);
1039 m_fMultilineString = comValue.GetMultiline();
1040 const QString strString = comValue.GetString();
1041 if (m_fMultilineString)
1042 m_text = TextData(strString);
1043 else
1044 m_strString = strString;
1045 m_cells[UIFormEditorDataType_Value]->setText(strString);
1046 /// @todo check for errors
1047 break;
1048 }
1049 case KFormValueType_Choice:
1050 {
1051 CChoiceFormValue comValue(m_comValue);
1052 const QVector<QString> values = comValue.GetValues();
1053 const int iSelectedIndex = comValue.GetSelectedIndex();
1054 m_choice = ChoiceData(values, iSelectedIndex);
1055 m_cells[UIFormEditorDataType_Value]->setText(m_choice.selectedValue());
1056 /// @todo check for errors
1057 break;
1058 }
1059 case KFormValueType_RangedInteger:
1060 {
1061 CRangedIntegerFormValue comValue(m_comValue);
1062 const int iMinimum = comValue.GetMinimum();
1063 const int iMaximum = comValue.GetMaximum();
1064 const int iInteger = comValue.GetInteger();
1065 const QString strSuffix = comValue.GetSuffix();
1066 m_rangedInteger = RangedIntegerData(iMinimum, iMaximum, iInteger, strSuffix);
1067 m_cells[UIFormEditorDataType_Value]->setText( strSuffix.isEmpty()
1068 ? QString::number(iInteger)
1069 : QString("%1 %2").arg(iInteger)
1070 .arg(strSuffix));
1071 /// @todo check for errors
1072 break;
1073 }
1074 case KFormValueType_RangedInteger64:
1075 {
1076 CRangedInteger64FormValue comValue(m_comValue);
1077 const qlonglong iMinimum = comValue.GetMinimum();
1078 const qlonglong iMaximum = comValue.GetMaximum();
1079 const qlonglong iInteger = comValue.GetInteger();
1080 const QString strSuffix = comValue.GetSuffix();
1081 m_rangedInteger64 = RangedInteger64Data(iMinimum, iMaximum, iInteger, strSuffix);
1082 /* Display suffix and effective value can be different: */
1083 QString strEffectiveSuffix = strSuffix;
1084 QString strEffectiveValue;
1085 if (strSuffix.isEmpty())
1086 strEffectiveValue = QString::number(iInteger);
1087 else if (strSuffix != "B")
1088 strEffectiveValue = QString("%1 %2").arg(iInteger).arg(strEffectiveSuffix);
1089 else
1090 {
1091 /* We wish to convert bytes to megabytes: */
1092 strEffectiveSuffix = "MB";
1093 strEffectiveValue = QString("%1 %2").arg(iInteger / _1M).arg(strEffectiveSuffix);
1094 }
1095 m_cells[UIFormEditorDataType_Value]->setText(strEffectiveValue);
1096 /// @todo check for errors
1097 break;
1098 }
1099 default:
1100 break;
1101 }
1102}
1103
1104bool UIFormEditorRow::isGenerationChanged() const
1105{
1106 const int iGeneration = m_comValue.GetGeneration();
1107 /// @todo check for errors
1108 return m_iGeneration != iGeneration;
1109}
1110
1111int UIFormEditorRow::childCount() const
1112{
1113 /* Return cell count: */
1114 return UIFormEditorDataType_Max;
1115}
1116
1117QITableViewCell *UIFormEditorRow::childItem(int iIndex) const
1118{
1119 /* Make sure index within the bounds: */
1120 AssertReturn(iIndex >= 0 && iIndex < m_cells.size(), 0);
1121 /* Return corresponding cell: */
1122 return m_cells.at(iIndex);
1123}
1124
1125void UIFormEditorRow::prepare()
1126{
1127 /* Cache value type: */
1128 m_enmValueType = m_comValue.GetType();
1129 /// @todo check for errors
1130
1131 /* Create cells on the basis of variables we have: */
1132 m_cells.resize(UIFormEditorDataType_Max);
1133 const QString strName = m_comValue.GetLabel();
1134 /// @todo check for errors
1135 m_cells[UIFormEditorDataType_Name] = new UIFormEditorCell(this, strName);
1136 m_cells[UIFormEditorDataType_Value] = new UIFormEditorCell(this);
1137 updateValueCells();
1138}
1139
1140void UIFormEditorRow::cleanup()
1141{
1142 /* Destroy cells: */
1143 qDeleteAll(m_cells);
1144 m_cells.clear();
1145}
1146
1147
1148/*********************************************************************************************************************************
1149* Class UIFormEditorModel implementation. *
1150*********************************************************************************************************************************/
1151
1152UIFormEditorModel::UIFormEditorModel(UIFormEditorWidget *pParent)
1153 : QAbstractTableModel(pParent)
1154 , m_pFormEditorWidget(pParent)
1155{
1156 prepare();
1157}
1158
1159UIFormEditorModel::~UIFormEditorModel()
1160{
1161 /* Delete the cached data: */
1162 qDeleteAll(m_dataList);
1163 m_dataList.clear();
1164}
1165
1166void UIFormEditorModel::clearForm()
1167{
1168 beginRemoveRows(QModelIndex(), 0, m_dataList.size());
1169 qDeleteAll(m_dataList);
1170 m_dataList.clear();
1171 endRemoveRows();
1172}
1173
1174void UIFormEditorModel::setFormValues(const CFormValueVector &values)
1175{
1176 /* Delete old lines: */
1177 clearForm();
1178
1179 /* Add new lines: */
1180 beginInsertRows(QModelIndex(), 0, values.size() - 1);
1181 foreach (const CFormValue &comValue, values)
1182 m_dataList << new UIFormEditorRow(view(), m_pFormEditorWidget, comValue);
1183 endInsertRows();
1184}
1185
1186int UIFormEditorModel::childCount() const
1187{
1188 return rowCount();
1189}
1190
1191QITableViewRow *UIFormEditorModel::childItem(int iIndex) const
1192{
1193 /* Make sure index within the bounds: */
1194 AssertReturn(iIndex >= 0 && iIndex < m_dataList.size(), 0);
1195 /* Return corresponding row: */
1196 return m_dataList[iIndex];
1197}
1198
1199QModelIndex UIFormEditorModel::index(int iRow, int iColumn, const QModelIndex &parentIdx /* = QModelIndex() */) const
1200{
1201 /* No index for unknown items: */
1202 if (!hasIndex(iRow, iColumn, parentIdx))
1203 return QModelIndex();
1204
1205 /* Provide index users with packed item pointer: */
1206 UIFormEditorRow *pItem = iRow >= 0 && iRow < m_dataList.size() ? m_dataList.at(iRow) : 0;
1207 return pItem ? createIndex(iRow, iColumn, pItem) : QModelIndex();
1208}
1209
1210Qt::ItemFlags UIFormEditorModel::flags(const QModelIndex &index) const
1211{
1212 /* Check index validness: */
1213 if (!index.isValid())
1214 return Qt::NoItemFlags;
1215 /* Switch for different columns: */
1216 switch (index.column())
1217 {
1218 case UIFormEditorDataType_Name:
1219 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
1220 case UIFormEditorDataType_Value:
1221 {
1222 Qt::ItemFlags enmFlags = Qt::NoItemFlags;
1223 if (m_dataList[index.row()]->isEnabled())
1224 {
1225 enmFlags |= Qt::ItemIsEnabled | Qt::ItemIsSelectable;
1226 enmFlags |= m_dataList[index.row()]->valueType() == KFormValueType_Boolean
1227 ? Qt::ItemIsUserCheckable : Qt::ItemIsEditable;
1228 }
1229 return enmFlags;
1230 }
1231 default:
1232 return Qt::NoItemFlags;
1233 }
1234}
1235
1236int UIFormEditorModel::rowCount(const QModelIndex &) const
1237{
1238 return m_dataList.size();
1239}
1240
1241int UIFormEditorModel::columnCount(const QModelIndex &) const
1242{
1243 return UIFormEditorDataType_Max;
1244}
1245
1246QVariant UIFormEditorModel::headerData(int iSection, Qt::Orientation enmOrientation, int iRole) const
1247{
1248 /* Check argument validness: */
1249 if (iRole != Qt::DisplayRole || enmOrientation != Qt::Horizontal)
1250 return QVariant();
1251 /* Switch for different columns: */
1252 switch (iSection)
1253 {
1254 case UIFormEditorDataType_Name:
1255 return UIFormEditorWidget::tr("Name");
1256 case UIFormEditorDataType_Value:
1257 return UIFormEditorWidget::tr("Value");
1258 default:
1259 return QVariant();
1260 }
1261}
1262
1263bool UIFormEditorModel::setData(const QModelIndex &index, const QVariant &value, int iRole /* = Qt::EditRole */)
1264{
1265 /* Check index validness: */
1266 if (!index.isValid())
1267 return false;
1268 /* Switch for different roles: */
1269 switch (iRole)
1270 {
1271 /* Checkstate role: */
1272 case Qt::CheckStateRole:
1273 {
1274 /* Switch for different columns: */
1275 switch (index.column())
1276 {
1277 case UIFormEditorDataType_Value:
1278 {
1279 if (m_dataList[index.row()]->valueType() == KFormValueType_Boolean)
1280 {
1281 const Qt::CheckState enmCheckState = static_cast<Qt::CheckState>(value.toInt());
1282 m_dataList[index.row()]->setBool(enmCheckState == Qt::Checked);
1283 emit dataChanged(index, index);
1284 updateGeneration();
1285 return true;
1286 }
1287 else
1288 return false;
1289 }
1290 default:
1291 return false;
1292 }
1293 }
1294 /* Edit role: */
1295 case Qt::EditRole:
1296 {
1297 /* Switch for different columns: */
1298 switch (index.column())
1299 {
1300 case UIFormEditorDataType_Value:
1301 {
1302 switch (m_dataList[index.row()]->valueType())
1303 {
1304 case KFormValueType_String:
1305 {
1306 if (value.canConvert<TextData>())
1307 m_dataList[index.row()]->setText(value.value<TextData>());
1308 else
1309 m_dataList[index.row()]->setString(value.toString());
1310 emit dataChanged(index, index);
1311 updateGeneration();
1312 return true;
1313 }
1314 case KFormValueType_Choice:
1315 {
1316 m_dataList[index.row()]->setChoice(value.value<ChoiceData>());
1317 emit dataChanged(index, index);
1318 updateGeneration();
1319 return true;
1320 }
1321 case KFormValueType_RangedInteger:
1322 {
1323 m_dataList[index.row()]->setRangedInteger(value.value<RangedIntegerData>());
1324 emit dataChanged(index, index);
1325 updateGeneration();
1326 return true;
1327 }
1328 case KFormValueType_RangedInteger64:
1329 {
1330 m_dataList[index.row()]->setRangedInteger64(value.value<RangedInteger64Data>());
1331 emit dataChanged(index, index);
1332 updateGeneration();
1333 return true;
1334 }
1335 default:
1336 return false;
1337 }
1338 }
1339 default:
1340 return false;
1341 }
1342 }
1343 default:
1344 return false;
1345 }
1346}
1347
1348QVariant UIFormEditorModel::data(const QModelIndex &index, int iRole) const
1349{
1350 /* Check index validness: */
1351 if (!index.isValid())
1352 return QVariant();
1353 /* Switch for different roles: */
1354 switch (iRole)
1355 {
1356 /* Decoration role: */
1357 case Qt::DecorationRole:
1358 {
1359 /* Switch for different columns: */
1360 switch (index.column())
1361 {
1362 case UIFormEditorDataType_Name: return iconHint(m_dataList[index.row()]->nameToString());
1363 default: return QVariant();
1364 }
1365 }
1366 /* Checkstate role: */
1367 case Qt::CheckStateRole:
1368 {
1369 /* Switch for different columns: */
1370 switch (index.column())
1371 {
1372 case UIFormEditorDataType_Value:
1373 return m_dataList[index.row()]->valueType() == KFormValueType_Boolean
1374 ? m_dataList[index.row()]->toBool()
1375 ? Qt::Checked
1376 : Qt::Unchecked
1377 : QVariant();
1378 default:
1379 return QVariant();
1380 }
1381 }
1382 /* Display role: */
1383 case Qt::DisplayRole:
1384 {
1385 /* Switch for different columns: */
1386 switch (index.column())
1387 {
1388 case UIFormEditorDataType_Name:
1389 return m_dataList[index.row()]->nameToString();
1390 case UIFormEditorDataType_Value:
1391 return m_dataList[index.row()]->valueType() != KFormValueType_Boolean
1392 ? m_dataList[index.row()]->valueToString()
1393 : QVariant();
1394 default:
1395 return QVariant();
1396 }
1397 }
1398 /* Edit role: */
1399 case Qt::EditRole:
1400 {
1401 /* Switch for different columns: */
1402 switch (index.column())
1403 {
1404 case UIFormEditorDataType_Value:
1405 {
1406 switch (m_dataList[index.row()]->valueType())
1407 {
1408 case KFormValueType_String:
1409 {
1410 if (m_dataList[index.row()]->isMultilineString())
1411 {
1412 TextData td = m_dataList[index.row()]->toText();
1413 td.setIndex(index);
1414 return QVariant::fromValue(td);
1415 }
1416 else
1417 return QVariant::fromValue(m_dataList[index.row()]->toString());
1418 }
1419 case KFormValueType_Choice:
1420 return QVariant::fromValue(m_dataList[index.row()]->toChoice());
1421 case KFormValueType_RangedInteger:
1422 return QVariant::fromValue(m_dataList[index.row()]->toRangedInteger());
1423 case KFormValueType_RangedInteger64:
1424 return QVariant::fromValue(m_dataList[index.row()]->toRangedInteger64());
1425 default:
1426 return QVariant();
1427 }
1428 }
1429 default:
1430 return QVariant();
1431 }
1432 }
1433 /* Alignment role: */
1434 case Qt::TextAlignmentRole:
1435 {
1436 /* Switch for different columns: */
1437 switch (index.column())
1438 {
1439 case UIFormEditorDataType_Name:
1440 return (int)(Qt::AlignLeft | Qt::AlignVCenter);
1441 case UIFormEditorDataType_Value:
1442 return m_dataList[index.row()]->valueType() != KFormValueType_Boolean
1443 ? (int)(Qt::AlignLeft | Qt::AlignVCenter)
1444 : (int)(Qt::AlignCenter);
1445 default:
1446 return QVariant();
1447 }
1448 }
1449 default:
1450 return QVariant();
1451 }
1452}
1453
1454void UIFormEditorModel::createTextDataEditor(const QModelIndex &index)
1455{
1456 /* Create dialog on-the-fly: */
1457 QPointer<QIDialog> pDialog = new QIDialog(view());
1458 if (pDialog)
1459 {
1460 /* We will need that pointer: */
1461 QTextEdit *pEditor = 0;
1462 /* Create layout: */
1463 QVBoxLayout *pLayout = new QVBoxLayout(pDialog);
1464 if (pLayout)
1465 {
1466 /* Create text-editor: */
1467 pEditor = new QTextEdit;
1468 if (pEditor)
1469 {
1470 const TextData td = data(index, Qt::EditRole).value<TextData>();
1471 pEditor->setPlainText(td.text());
1472 pLayout->addWidget(pEditor);
1473 }
1474 /* Create button-box: */
1475 QIDialogButtonBox *pBox = new QIDialogButtonBox;
1476 if (pBox)
1477 {
1478 pBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
1479 connect(pBox, &QIDialogButtonBox::accepted, pDialog.data(), &QIDialog::accept);
1480 connect(pBox, &QIDialogButtonBox::rejected, pDialog.data(), &QIDialog::reject);
1481 pLayout->addWidget(pBox);
1482 }
1483 }
1484 /* Execute the dialog: */
1485 if (pDialog->execute() == QDialog::Accepted)
1486 {
1487 const TextData td = TextData(pEditor->toPlainText(), index);
1488 setData(index, QVariant::fromValue(td));
1489 }
1490 /* Cleanup: */
1491 delete pDialog;
1492 }
1493}
1494
1495void UIFormEditorModel::prepare()
1496{
1497 /* Prepare hardcoded icons map: */
1498 m_icons["Name"] = UIIconPool::iconSet(":/name_16px.png");
1499 m_icons["Display Name"] = UIIconPool::iconSet(":/name_16px.png");
1500 m_icons["Type"] = UIIconPool::iconSet(":/system_type_16px.png");
1501 m_icons["Version"] = UIIconPool::iconSet(":/system_version_16px.png");
1502 m_icons["CPU"] = UIIconPool::iconSet(":/cpu_16px.png");
1503 m_icons["Memory"] = UIIconPool::iconSet(":/ram_16px.png");
1504 m_icons["Description"] = UIIconPool::iconSet(":/description_16px.png");
1505 m_icons["Bucket"] = UIIconPool::iconSet(":/bucket_16px.png");
1506 m_icons["Keep Object"] = UIIconPool::iconSet(":/keep_object_16px.png");
1507 m_icons["Launch VM"] = UIIconPool::iconSet(":/launch_vm_16px.png");
1508 m_icons["Availability Domain"] = UIIconPool::iconSet(":/availability_domain_16px.png");
1509 m_icons["Shape"] = UIIconPool::iconSet(":/shape_16px.png");
1510 m_icons["Disk Size"] = UIIconPool::iconSet(":/disk_size_16px.png");
1511 m_icons["VCN"] = UIIconPool::iconSet(":/vcn_16px.png");
1512 m_icons["Subnet"] = UIIconPool::iconSet(":/subnet_16px.png");
1513 m_icons["Assign Public IP"] = UIIconPool::iconSet(":/assign_public_ip_16px.png");
1514}
1515
1516QITableView *UIFormEditorModel::view() const
1517{
1518 return m_pFormEditorWidget->view();
1519}
1520
1521void UIFormEditorModel::updateGeneration()
1522{
1523 for (int i = 0; i < m_dataList.size(); ++i)
1524 {
1525 UIFormEditorRow *pRow = m_dataList.at(i);
1526 if (pRow->isGenerationChanged())
1527 {
1528 pRow->updateValueCells();
1529 const QModelIndex changedIndex = index(i, 1);
1530 emit dataChanged(changedIndex, changedIndex);
1531 }
1532 }
1533}
1534
1535QIcon UIFormEditorModel::iconHint(const QString &strItemName) const
1536{
1537 return m_icons.value(strItemName, UIIconPool::iconSet(":/session_info_16px.png"));
1538}
1539
1540
1541/*********************************************************************************************************************************
1542* Class UIFormEditorProxyModel implementation. *
1543*********************************************************************************************************************************/
1544
1545UIFormEditorProxyModel::UIFormEditorProxyModel(QObject *pParent /* = 0 */)
1546 : QSortFilterProxyModel(pParent)
1547{
1548}
1549
1550int UIFormEditorProxyModel::childCount() const
1551{
1552 return rowCount();
1553}
1554
1555QITableViewRow *UIFormEditorProxyModel::childItem(int iIndex) const
1556{
1557 /* Make sure iIndex within the bounds: */
1558 AssertReturn(iIndex >= 0 && iIndex < rowCount(), 0);
1559 /* Acquire actual index of source model: */
1560 const QModelIndex i = sourceModel()->index(iIndex, 0);
1561 AssertReturn(i.isValid(), 0);
1562 /* Get packed item pointer: */
1563 UIFormEditorRow *pItem = static_cast<UIFormEditorRow*>(i.internalPointer());
1564 AssertReturn(pItem, 0);
1565 return pItem;
1566}
1567
1568bool UIFormEditorProxyModel::filterAcceptsRow(int iSourceRow, const QModelIndex &sourceParent) const
1569{
1570 /* Acquire actual index of source model: */
1571 QModelIndex i = sourceModel()->index(iSourceRow, 0, sourceParent);
1572 if (i.isValid())
1573 {
1574 /* Get packed item pointer: */
1575 UIFormEditorRow *pItem = static_cast<UIFormEditorRow*>(i.internalPointer());
1576 /* Filter invisible items: */
1577 if (!pItem->isVisible())
1578 return false;
1579 }
1580 return true;
1581}
1582
1583
1584/*********************************************************************************************************************************
1585* Class UIFormEditorView implementation. *
1586*********************************************************************************************************************************/
1587
1588UIFormEditorView::UIFormEditorView(QWidget * /* pParent = 0 */)
1589{
1590 /* Configure widget a bit: */
1591 setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked | QAbstractItemView::EditKeyPressed);
1592}
1593
1594int UIFormEditorView::childCount() const
1595{
1596 /* Redirect request to model: */
1597 AssertPtrReturn(model(), 0);
1598 return qobject_cast<UIFormEditorProxyModel*>(model())->childCount();
1599}
1600
1601QITableViewRow *UIFormEditorView::childItem(int iIndex) const
1602{
1603 /* Redirect request to model: */
1604 AssertPtrReturn(model(), 0);
1605 return qobject_cast<UIFormEditorProxyModel*>(model())->childItem(iIndex);
1606}
1607
1608
1609/*********************************************************************************************************************************
1610* Class UIFormEditorWidget implementation. *
1611*********************************************************************************************************************************/
1612
1613UIFormEditorWidget::UIFormEditorWidget(QWidget *pParent /* = 0 */,
1614 UINotificationCenter *pNotificationCenter /* = 0 */)
1615 : QWidget(pParent)
1616 , m_pNotificationCenter(pNotificationCenter)
1617 , m_pTableView(0)
1618 , m_pTableModel(0)
1619 , m_pItemEditorFactory(0)
1620{
1621 prepare();
1622}
1623
1624UIFormEditorWidget::~UIFormEditorWidget()
1625{
1626 cleanup();
1627}
1628
1629UIFormEditorView *UIFormEditorWidget::view() const
1630{
1631 return m_pTableView;
1632}
1633
1634QHeaderView *UIFormEditorWidget::horizontalHeader() const
1635{
1636 AssertPtrReturn(m_pTableView, 0);
1637 return m_pTableView->horizontalHeader();
1638}
1639
1640QHeaderView *UIFormEditorWidget::verticalHeader() const
1641{
1642 AssertPtrReturn(m_pTableView, 0);
1643 return m_pTableView->verticalHeader();
1644}
1645
1646void UIFormEditorWidget::setWhatsThis(const QString &strWhatsThis)
1647{
1648 AssertPtrReturnVoid(m_pTableView);
1649 m_pTableView->setWhatsThis(strWhatsThis);
1650}
1651
1652void UIFormEditorWidget::clearForm()
1653{
1654 m_pTableModel->clearForm();
1655 adjustTable();
1656}
1657
1658void UIFormEditorWidget::setValues(const QVector<CFormValue> &values)
1659{
1660 m_pTableModel->setFormValues(values);
1661 adjustTable();
1662}
1663
1664void UIFormEditorWidget::setForm(const CForm &comForm)
1665{
1666 AssertPtrReturnVoid(m_pTableModel);
1667 /// @todo add some check..
1668 setValues(comForm.GetValues());
1669}
1670
1671void UIFormEditorWidget::setVirtualSystemDescriptionForm(const CVirtualSystemDescriptionForm &comForm)
1672{
1673 AssertPtrReturnVoid(m_pTableModel);
1674 /// @todo add some check..
1675 setValues(comForm.GetValues());
1676}
1677
1678void UIFormEditorWidget::makeSureEditorDataCommitted()
1679{
1680 m_pTableView->makeSureEditorDataCommitted();
1681}
1682
1683bool UIFormEditorWidget::eventFilter(QObject *pObject, QEvent *pEvent)
1684{
1685 /* Process events for table only: */
1686 if (pObject != m_pTableView)
1687 return QWidget::eventFilter(pObject, pEvent);
1688
1689 /* Process different event-types: */
1690 switch (pEvent->type())
1691 {
1692 case QEvent::Show:
1693 case QEvent::Resize:
1694 {
1695 /* Adjust table: */
1696 adjustTable();
1697 break;
1698 }
1699 default:
1700 break;
1701 }
1702
1703 /* Call to base-class: */
1704 return QWidget::eventFilter(pObject, pEvent);
1705}
1706
1707void UIFormEditorWidget::prepare()
1708{
1709 /* Create layout: */
1710 QVBoxLayout *pLayout = new QVBoxLayout(this);
1711 if (pLayout)
1712 {
1713 pLayout->setContentsMargins(0, 0, 0, 0);
1714
1715 /* Create model: */
1716 m_pTableModel = new UIFormEditorModel(this);
1717
1718 /* Create proxy-model: */
1719 UIFormEditorProxyModel *pProxyModel = new UIFormEditorProxyModel(this);
1720 if (pProxyModel)
1721 pProxyModel->setSourceModel(m_pTableModel);
1722
1723 /* Create view: */
1724 m_pTableView = new UIFormEditorView(this);
1725 if (m_pTableView)
1726 {
1727 m_pTableView->setModel(pProxyModel);
1728 m_pTableView->setTabKeyNavigation(false);
1729 m_pTableView->verticalHeader()->hide();
1730 m_pTableView->verticalHeader()->setDefaultSectionSize((int)(m_pTableView->verticalHeader()->minimumSectionSize() * 1.33));
1731 m_pTableView->setSelectionMode(QAbstractItemView::SingleSelection);
1732 m_pTableView->installEventFilter(this);
1733
1734 /* We certainly have abstract item delegate: */
1735 QAbstractItemDelegate *pAbstractItemDelegate = m_pTableView->itemDelegate();
1736 if (pAbstractItemDelegate)
1737 {
1738 /* But is this also styled item delegate? */
1739 QIStyledItemDelegate *pStyledItemDelegate = qobject_cast<QIStyledItemDelegate*>(pAbstractItemDelegate);
1740 if (pStyledItemDelegate)
1741 {
1742 /* Configure item delegate: */
1743 pStyledItemDelegate->setWatchForEditorDataCommits(true);
1744
1745 /* Create new item editor factory: */
1746 m_pItemEditorFactory = new QItemEditorFactory;
1747 if (m_pItemEditorFactory)
1748 {
1749 /* Register TextEditor as the TextData editor: */
1750 int iTextId = qRegisterMetaType<TextData>();
1751 QStandardItemEditorCreator<TextEditor> *pTextEditorItemCreator = new QStandardItemEditorCreator<TextEditor>();
1752 m_pItemEditorFactory->registerEditor(iTextId, pTextEditorItemCreator);
1753
1754 /* Register ChoiceEditor as the ChoiceData editor: */
1755 int iChoiceId = qRegisterMetaType<ChoiceData>();
1756 QStandardItemEditorCreator<ChoiceEditor> *pChoiceEditorItemCreator = new QStandardItemEditorCreator<ChoiceEditor>();
1757 m_pItemEditorFactory->registerEditor(iChoiceId, pChoiceEditorItemCreator);
1758
1759 /* Register RangedIntegerEditor as the RangedIntegerData editor: */
1760 int iRangedIntegerId = qRegisterMetaType<RangedIntegerData>();
1761 QStandardItemEditorCreator<RangedIntegerEditor> *pRangedIntegerEditorItemCreator = new QStandardItemEditorCreator<RangedIntegerEditor>();
1762 m_pItemEditorFactory->registerEditor(iRangedIntegerId, pRangedIntegerEditorItemCreator);
1763
1764 /* Register RangedInteger64Editor as the RangedInteger64Data editor: */
1765 int iRangedInteger64Id = qRegisterMetaType<RangedInteger64Data>();
1766 QStandardItemEditorCreator<RangedInteger64Editor> *pRangedInteger64EditorItemCreator = new QStandardItemEditorCreator<RangedInteger64Editor>();
1767 m_pItemEditorFactory->registerEditor(iRangedInteger64Id, pRangedInteger64EditorItemCreator);
1768
1769 /* Set newly created item editor factory for table delegate: */
1770 pStyledItemDelegate->setItemEditorFactory(m_pItemEditorFactory);
1771 }
1772 }
1773 }
1774
1775 /* Add into layout: */
1776 pLayout->addWidget(m_pTableView);
1777 }
1778 }
1779}
1780
1781void UIFormEditorWidget::cleanup()
1782{
1783 delete m_pItemEditorFactory;
1784 m_pItemEditorFactory = 0;
1785}
1786
1787void UIFormEditorWidget::adjustTable()
1788{
1789 m_pTableView->horizontalHeader()->setStretchLastSection(false);
1790 /* If table is NOT empty: */
1791 if (m_pTableModel->rowCount())
1792 {
1793 /* Resize table to contents size-hint and emit a spare place for first column: */
1794 m_pTableView->resizeColumnsToContents();
1795 const int iFullWidth = m_pTableView->viewport()->width();
1796 const int iNameWidth = m_pTableView->horizontalHeader()->sectionSize(UIFormEditorDataType_Name);
1797 const int iValueWidth = qMax(0, iFullWidth - iNameWidth);
1798 m_pTableView->horizontalHeader()->resizeSection(UIFormEditorDataType_Value, iValueWidth);
1799 }
1800 /* If table is empty: */
1801 else
1802 {
1803 /* Resize table columns to be equal in size: */
1804 const int iFullWidth = m_pTableView->viewport()->width();
1805 m_pTableView->horizontalHeader()->resizeSection(UIFormEditorDataType_Name, iFullWidth / 2);
1806 m_pTableView->horizontalHeader()->resizeSection(UIFormEditorDataType_Value, iFullWidth / 2);
1807 }
1808 m_pTableView->horizontalHeader()->setStretchLastSection(true);
1809}
1810
1811
1812#include "UIFormEditorWidget.moc"
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette