VirtualBox

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

Last change on this file since 103977 was 103771, checked in by vboxsync, 9 months ago

FE/Qt: UICommon: Switching dependency from UICommon to UIGlobalSession whenever is possible.

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