VirtualBox

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

Last change on this file was 104358, checked in by vboxsync, 5 weeks ago

FE/Qt. bugref:10622. More refactoring around the retranslation functionality.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 61.4 KB
Line 
1/* $Id: UIFormEditorWidget.cpp 104358 2024-04-18 05:33:40Z 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 <QApplication>
30#include <QComboBox>
31#include <QEvent>
32#include <QHeaderView>
33#include <QItemEditorFactory>
34#include <QLineEdit>
35#include <QPointer>
36#include <QPushButton>
37#include <QSortFilterProxyModel>
38#include <QSpinBox>
39#include <QTextEdit>
40#include <QVBoxLayout>
41
42/* GUI includes: */
43#include "QIDialog.h"
44#include "QIDialogButtonBox.h"
45#include "QIStyledItemDelegate.h"
46#include "QITableView.h"
47#include "UIFormEditorWidget.h"
48#include "UIGlobalSession.h"
49#include "UIIconPool.h"
50#include "UINotificationCenter.h"
51#include "UITranslationEventListener.h"
52
53/* COM includes: */
54#include "CBooleanFormValue.h"
55#include "CChoiceFormValue.h"
56#include "CForm.h"
57#include "CFormValue.h"
58#include "CRangedIntegerFormValue.h"
59#include "CRangedInteger64FormValue.h"
60#include "CStringFormValue.h"
61#include "CSystemProperties.h"
62#include "CVirtualSystemDescriptionForm.h"
63
64/* VirtualBox interface declarations: */
65#include <VBox/com/VirtualBox.h>
66
67/* External includes: */
68#include <math.h>
69
70
71/** Form Editor data types. */
72enum UIFormEditorDataType
73{
74 UIFormEditorDataType_Name,
75 UIFormEditorDataType_Value,
76 UIFormEditorDataType_Max
77};
78
79
80/** Class used to hold text data. */
81class TextData
82{
83public:
84
85 /** Constructs null text data. */
86 TextData() {}
87 /** Constructs text data on the basis of passed @a strText and @a index. */
88 TextData(const QString &strText, const QModelIndex index = QModelIndex())
89 : m_strText(strText), m_index(index) {}
90 /** Constructs text data on the basis of @a another text data. */
91 TextData(const TextData &another)
92 : m_strText(another.text()), m_index(another.index()) {}
93
94 /** Assigns values of @a another text to this one. */
95 TextData &operator=(const TextData &another)
96 {
97 m_strText = another.text();
98 m_index = another.index();
99 return *this;
100 }
101
102 /** Returns text value. */
103 QString text() const { return m_strText; }
104
105 /** Defines model @a index. */
106 void setIndex(const QModelIndex &index) { m_index = index; }
107 /** Returns model index. */
108 QModelIndex index() const { return m_index; }
109
110private:
111
112 /** Holds text value. */
113 QString m_strText;
114 /** Holds model index. */
115 QModelIndex m_index;
116};
117Q_DECLARE_METATYPE(TextData);
118
119
120/** Class used to hold choice data. */
121class ChoiceData
122{
123public:
124
125 /** Constructs null choice data. */
126 ChoiceData()
127 : m_iSelectedIndex(-1) {}
128 /** Constructs choice data on the basis of passed @a values and @a iSelectedIndex. */
129 ChoiceData(const QVector<QString> &values, int iSelectedIndex)
130 : m_values(values), m_iSelectedIndex(iSelectedIndex) {}
131 /** Constructs choice data on the basis of @a another choice data. */
132 ChoiceData(const ChoiceData &another)
133 : m_values(another.values()), m_iSelectedIndex(another.selectedIndex()) {}
134
135 /** Assigns values of @a another choice to this one. */
136 ChoiceData &operator=(const ChoiceData &another)
137 {
138 m_values = another.values();
139 m_iSelectedIndex = another.selectedIndex();
140 return *this;
141 }
142
143 /** Returns values vector. */
144 QVector<QString> values() const { return m_values; }
145 /** Returns selected index. */
146 int selectedIndex() const { return m_iSelectedIndex; }
147 /** Returns selected value. */
148 QString selectedValue() const
149 {
150 return m_iSelectedIndex >= 0 && m_iSelectedIndex < m_values.size()
151 ? m_values.at(m_iSelectedIndex) : QString();
152 }
153
154private:
155
156 /** Holds values vector. */
157 QVector<QString> m_values;
158 /** Holds selected index. */
159 int m_iSelectedIndex;
160};
161Q_DECLARE_METATYPE(ChoiceData);
162
163
164/** Class used to hold ranged-integer data. */
165class RangedIntegerData
166{
167public:
168
169 /** Constructs null ranged-integer data. */
170 RangedIntegerData()
171 : m_iMinimum(-1), m_iMaximum(-1)
172 , m_iInteger(-1), m_strSuffix(QString()) {}
173 /** Constructs ranged-integer data on the basis of passed @a iMinimum, @a iMaximum, @a iInteger and @a strSuffix. */
174 RangedIntegerData(int iMinimum, int iMaximum, int iInteger, const QString strSuffix)
175 : m_iMinimum(iMinimum), m_iMaximum(iMaximum)
176 , m_iInteger(iInteger), m_strSuffix(strSuffix) {}
177 /** Constructs ranged-integer data on the basis of @a another ranged-integer data. */
178 RangedIntegerData(const RangedIntegerData &another)
179 : m_iMinimum(another.minimum()), m_iMaximum(another.maximum())
180 , m_iInteger(another.integer()), m_strSuffix(another.suffix()) {}
181
182 /** Assigns values of @a another ranged-integer to this one. */
183 RangedIntegerData &operator=(const RangedIntegerData &another)
184 {
185 m_iMinimum = another.minimum();
186 m_iMaximum = another.maximum();
187 m_iInteger = another.integer();
188 m_strSuffix = another.suffix();
189 return *this;
190 }
191
192 /** Returns minimum value. */
193 int minimum() const { return m_iMinimum; }
194 /** Returns maximum value. */
195 int maximum() const { return m_iMaximum; }
196 /** Returns current value. */
197 int integer() const { return m_iInteger; }
198 /** Returns suffix value. */
199 QString suffix() const { return m_strSuffix; }
200
201private:
202
203 /** Holds minimum value. */
204 int m_iMinimum;
205 /** Holds maximum value. */
206 int m_iMaximum;
207 /** Holds current value. */
208 int m_iInteger;
209 /** Holds suffix value. */
210 QString m_strSuffix;
211};
212Q_DECLARE_METATYPE(RangedIntegerData);
213
214
215/** Class used to hold ranged-integer64 data. */
216class RangedInteger64Data
217{
218public:
219
220 /** Constructs null ranged-integer64 data. */
221 RangedInteger64Data()
222 : m_iMinimum(-1), m_iMaximum(-1)
223 , m_iInteger(-1), m_strSuffix(QString()) {}
224 /** Constructs ranged-integer64 data on the basis of passed @a iMinimum, @a iMaximum, @a iInteger and @a strSuffix. */
225 RangedInteger64Data(qlonglong iMinimum, qlonglong iMaximum, qlonglong iInteger, const QString strSuffix)
226 : m_iMinimum(iMinimum), m_iMaximum(iMaximum)
227 , m_iInteger(iInteger), m_strSuffix(strSuffix) {}
228 /** Constructs ranged-integer64 data on the basis of @a another ranged-integer data. */
229 RangedInteger64Data(const RangedInteger64Data &another)
230 : m_iMinimum(another.minimum()), m_iMaximum(another.maximum())
231 , m_iInteger(another.integer()), m_strSuffix(another.suffix()) {}
232
233 /** Assigns values of @a another ranged-integer to this one. */
234 RangedInteger64Data &operator=(const RangedInteger64Data &another)
235 {
236 m_iMinimum = another.minimum();
237 m_iMaximum = another.maximum();
238 m_iInteger = another.integer();
239 m_strSuffix = another.suffix();
240 return *this;
241 }
242
243 /** Returns minimum value. */
244 qlonglong minimum() const { return m_iMinimum; }
245 /** Returns maximum value. */
246 qlonglong maximum() const { return m_iMaximum; }
247 /** Returns current value. */
248 qlonglong integer() const { return m_iInteger; }
249 /** Returns suffix value. */
250 QString suffix() const { return m_strSuffix; }
251
252private:
253
254 /** Holds minimum value. */
255 qlonglong m_iMinimum;
256 /** Holds maximum value. */
257 qlonglong m_iMaximum;
258 /** Holds current value. */
259 qlonglong m_iInteger;
260 /** Holds suffix value. */
261 QString m_strSuffix;
262};
263Q_DECLARE_METATYPE(RangedInteger64Data);
264
265
266/** QWidget extension used as dummy TextData editor.
267 * It's not actually an editor, but Edit... button instead which opens
268 * real editor passing stored model index received from TextData value. */
269class TextEditor : public QWidget
270{
271 Q_OBJECT;
272 Q_PROPERTY(TextData text READ text WRITE setText USER true);
273
274public:
275
276 /** Constructs TextData editor passing @a pParent to the base-class. */
277 TextEditor(QWidget *pParent = 0);
278
279private slots:
280
281 /** Handles translation event. */
282 void sltRetranslateUI();
283 /** Handles button click. */
284 void sltHandleButtonClick();
285
286private:
287
288 /** Prepares all. */
289 void prepare();
290
291 /** Defines @a text. */
292 void setText(const TextData &text);
293 /** Returns text. */
294 TextData text() const;
295
296 /** Holds the button instance. */
297 QPushButton *m_pButton;
298 /** Holds the multiline text. */
299 QString m_strMultilineText;
300 /** Holds the model index. */
301 QModelIndex m_index;
302};
303
304
305/** QComboBox extension used as ChoiceData editor. */
306class ChoiceEditor : public QComboBox
307{
308 Q_OBJECT;
309 Q_PROPERTY(ChoiceData choice READ choice WRITE setChoice USER true);
310
311signals:
312
313 /** Notifies listener about data should be committed. */
314 void sigCommitData(QWidget *pThis);
315
316public:
317
318 /** Constructs ChoiceData editor passing @a pParent to the base-class. */
319 ChoiceEditor(QWidget *pParent = 0);
320
321private slots:
322
323 /** Handles current index change. */
324 void sltCurrentIndexChanged();
325
326private:
327
328 /** Defines the @a choice. */
329 void setChoice(const ChoiceData &choice);
330 /** Returns the choice. */
331 ChoiceData choice() const;
332};
333
334
335/** QSpinBox extension used as RangedIntegerData editor. */
336class RangedIntegerEditor : public QSpinBox
337{
338 Q_OBJECT;
339 Q_PROPERTY(RangedIntegerData rangedInteger READ rangedInteger WRITE setRangedInteger USER true);
340
341public:
342
343 /** Constructs RangedIntegerData editor passing @a pParent to the base-class. */
344 RangedIntegerEditor(QWidget *pParent = 0);
345
346private:
347
348 /** Defines @a rangedInteger. */
349 void setRangedInteger(const RangedIntegerData &rangedInteger);
350 /** Returns ranged-integer. */
351 RangedIntegerData rangedInteger() const;
352
353 /** Holds the unchanged suffix. */
354 QString m_strSuffix;
355};
356
357
358/** QLineEdit extension used as RangedInteger64Data editor. */
359class RangedInteger64Editor : public QLineEdit
360{
361 Q_OBJECT;
362 Q_PROPERTY(RangedInteger64Data rangedInteger64 READ rangedInteger64 WRITE setRangedInteger64 USER true);
363
364public:
365
366 /** Constructs RangedInteger64Data editor passing @a pParent to the base-class. */
367 RangedInteger64Editor(QWidget *pParent = 0);
368
369private:
370
371 /** Defines @a rangedInteger. */
372 void setRangedInteger64(const RangedInteger64Data &rangedInteger64);
373 /** Returns ranged-integer. */
374 RangedInteger64Data rangedInteger64() const;
375
376 /** Holds the minimum guest RAM in MBs. */
377 qlonglong m_iMinimumGuestRAM;
378 /** Holds the maximum value. */
379 qlonglong m_iMaximumGuestRAM;
380
381 /** Holds the minimum value. */
382 qlonglong m_iMinimum;
383 /** Holds the maximum value. */
384 qlonglong m_iMaximum;
385 /** Holds the unchanged suffix. */
386 QString m_strSuffix;
387};
388
389
390/** QITableViewCell extension used as Form Editor table-view cell. */
391class UIFormEditorCell : public QITableViewCell
392{
393 Q_OBJECT;
394
395public:
396
397 /** Constructs table cell on the basis of certain @a strText, passing @a pParent to the base-class. */
398 UIFormEditorCell(QITableViewRow *pParent, const QString &strText = QString());
399
400 /** Returns the cell text. */
401 virtual QString text() const RT_OVERRIDE { return m_strText; }
402
403 /** Defines the cell @a strText. */
404 void setText(const QString &strText) { m_strText = strText; }
405
406private:
407
408 /** Holds the cell text. */
409 QString m_strText;
410};
411
412
413/** QITableViewRow extension used as Form Editor table-view row. */
414class UIFormEditorRow : public QITableViewRow
415{
416 Q_OBJECT;
417
418public:
419
420 /** Constructs table row on the basis of certain @a comValue, passing @a pParent to the base-class.
421 * @param pFormEditorWidget Brings the root form-editor widget reference. */
422 UIFormEditorRow(QITableView *pParent, UIFormEditorWidget *pFormEditorWidget, const CFormValue &comValue);
423 /** Destructs table row. */
424 virtual ~UIFormEditorRow() RT_OVERRIDE;
425
426 /** Returns value type. */
427 KFormValueType valueType() const { return m_enmValueType; }
428
429 /** Returns the row name as string. */
430 QString nameToString() const;
431 /** Returns the row value as string. */
432 QString valueToString() const;
433
434 /** Returns whether the row is enabled. */
435 bool isEnabled() const;
436 /** Returns whether the row is visible. */
437 bool isVisible() const;
438
439 /** Returns value cast to bool. */
440 bool toBool() const;
441 /** Defines @a fBool value. */
442 void setBool(bool fBool);
443
444 /** Returns whether cached string value is multiline. */
445 bool isMultilineString() const;
446 /** Returns value cast to text. */
447 TextData toText() const;
448 /** Defines @a text value. */
449 void setText(const TextData &text);
450 /** Returns value cast to string. */
451 QString toString() const;
452 /** Defines @a strString value. */
453 void setString(const QString &strString);
454
455 /** Returns value cast to choice. */
456 ChoiceData toChoice() const;
457 /** Defines @a choice value. */
458 void setChoice(const ChoiceData &choice);
459
460 /** Returns value cast to ranged-integer. */
461 RangedIntegerData toRangedInteger() const;
462 /** Defines @a rangedInteger value. */
463 void setRangedInteger(const RangedIntegerData &rangedInteger);
464
465 /** Returns value cast to ranged-integer64. */
466 RangedInteger64Data toRangedInteger64() const;
467 /** Defines @a rangedInteger64 value. */
468 void setRangedInteger64(const RangedInteger64Data &rangedInteger64);
469
470 /** Updates value cells. */
471 void updateValueCells();
472
473 /** Check whether generation value is changed. */
474 bool isGenerationChanged() const;
475
476protected:
477
478 /** Returns the number of children. */
479 virtual int childCount() const RT_OVERRIDE;
480 /** Returns the child item with @a iIndex. */
481 virtual QITableViewCell *childItem(int iIndex) const RT_OVERRIDE;
482
483private:
484
485 /** Prepares all. */
486 void prepare();
487 /** Cleanups all. */
488 void cleanup();
489
490 /** Holds the root form-editor widget reference. */
491 UIFormEditorWidget *m_pFormEditorWidget;
492
493 /** Holds the row value. */
494 CFormValue m_comValue;
495
496 /** Holds the value type. */
497 KFormValueType m_enmValueType;
498
499 /** Holds current generation value. */
500 int m_iGeneration;
501
502 /** Holds cached bool value. */
503 bool m_fBool;
504 /** Holds whether cached string value is multiline. */
505 bool m_fMultilineString;
506 /** Holds cached text value. */
507 TextData m_text;
508 /** Holds cached string value. */
509 QString m_strString;
510 /** Holds cached choice value. */
511 ChoiceData m_choice;
512 /** Holds cached ranged-integer value. */
513 RangedIntegerData m_rangedInteger;
514 /** Holds cached ranged-integer64 value. */
515 RangedInteger64Data m_rangedInteger64;
516
517 /** Holds the cell instances. */
518 QVector<UIFormEditorCell*> m_cells;
519};
520
521
522/** QAbstractTableModel subclass used as Form Editor data model. */
523class UIFormEditorModel : public QAbstractTableModel
524{
525 Q_OBJECT;
526
527public:
528
529 /** Constructs Form Editor model passing @a pParent to the base-class. */
530 UIFormEditorModel(UIFormEditorWidget *pParent);
531 /** Destructs Port Forwarding model. */
532 virtual ~UIFormEditorModel() RT_OVERRIDE;
533
534 /** Clears form. */
535 void clearForm();
536 /** Defines form @a values. */
537 void setFormValues(const CFormValueVector &values);
538
539 /** Returns the number of children. */
540 int childCount() const;
541 /** Returns the child item with @a iIndex. */
542 QITableViewRow *childItem(int iIndex) const;
543
544 /** Returns the index of the item in the model specified by the given @a iRow, @a iColumn and @a parentIdx. */
545 virtual QModelIndex index(int iRow, int iColumn, const QModelIndex &parentIdx = QModelIndex()) const RT_OVERRIDE;
546
547 /** Returns flags for item with certain @a index. */
548 virtual Qt::ItemFlags flags(const QModelIndex &index) const RT_OVERRIDE;
549
550 /** Returns row count of certain @a parent. */
551 virtual int rowCount(const QModelIndex &parent = QModelIndex()) const RT_OVERRIDE;
552 /** Returns column count of certain @a parent. */
553 virtual int columnCount(const QModelIndex &parent = QModelIndex()) const RT_OVERRIDE;
554
555 /** Returns header data for @a iSection, @a enmOrientation and @a iRole specified. */
556 virtual QVariant headerData(int iSection, Qt::Orientation enmOrientation, int iRole) const RT_OVERRIDE;
557
558 /** Defines the @a iRole data for item with @a index as @a value. */
559 virtual bool setData(const QModelIndex &index, const QVariant &value, int iRole = Qt::EditRole) RT_OVERRIDE;
560 /** Returns the @a iRole data for item with @a index. */
561 virtual QVariant data(const QModelIndex &index, int iRole) const RT_OVERRIDE;
562
563 /** Creates actual TextData editor for specified @a index. */
564 void createTextDataEditor(const QModelIndex &index);
565
566private:
567
568 /** Prepares all. */
569 void prepare();
570
571 /** Returns the parent table-view reference. */
572 QITableView *view() const;
573
574 /** Updates row generation values. */
575 void updateGeneration();
576
577 /** Returns icon hint for specified @a strItemName. */
578 QIcon iconHint(const QString &strItemName) const;
579
580 /** Holds the root form-editor widget reference. */
581 UIFormEditorWidget *m_pFormEditorWidget;
582
583 /** Holds the Form Editor row list. */
584 QList<UIFormEditorRow*> m_dataList;
585
586 /** Holds the hardcoded icon name map. */
587 QMap<QString, QIcon> m_icons;
588};
589
590
591/** QSortFilterProxyModel subclass used as the Form Editor proxy-model. */
592class UIFormEditorProxyModel : public QSortFilterProxyModel
593{
594 Q_OBJECT;
595
596public:
597
598 /** Constructs the Form Editor proxy-model passing @a pParent to the base-class. */
599 UIFormEditorProxyModel(QObject *pParent = 0);
600
601 /** Returns the number of children. */
602 int childCount() const;
603 /** Returns the child item with @a iIndex. */
604 QITableViewRow *childItem(int iIndex) const;
605
606protected:
607
608 /** Returns whether item in the row indicated by the given @a iSourceRow and @a srcParenIdx should be included in the model. */
609 virtual bool filterAcceptsRow(int iSourceRow, const QModelIndex &srcParenIdx) const RT_OVERRIDE;
610};
611
612
613/** QITableView extension used as Form Editor table-view. */
614class UIFormEditorView : public QITableView
615{
616 Q_OBJECT;
617
618public:
619
620 /** Constructs Form Editor table-view. */
621 UIFormEditorView(QWidget *pParent = 0);
622
623protected:
624
625 /** Returns the number of children. */
626 virtual int childCount() const RT_OVERRIDE;
627 /** Returns the child item with @a iIndex. */
628 virtual QITableViewRow *childItem(int iIndex) const RT_OVERRIDE;
629};
630
631
632/*********************************************************************************************************************************
633* Class TextEditor implementation. *
634*********************************************************************************************************************************/
635
636TextEditor::TextEditor(QWidget *pParent /* = 0 */)
637 : QWidget(pParent)
638 , m_pButton(0)
639{
640 prepare();
641}
642
643void TextEditor::sltRetranslateUI()
644{
645 m_pButton->setText(UIFormEditorWidget::tr("Edit..."));
646}
647
648void TextEditor::sltHandleButtonClick()
649{
650 /* Redirect the edit call if possible: */
651 do
652 {
653 /* Get the view: */
654 if ( !parent()
655 || !parent()->parent())
656 break;
657 UIFormEditorView *pView = qobject_cast<UIFormEditorView*>(parent()->parent());
658
659 /* Get the proxy model: */
660 if ( !pView
661 || !pView->model())
662 break;
663 UIFormEditorProxyModel *pProxyModel = qobject_cast<UIFormEditorProxyModel*>(pView->model());
664
665 /* Get the source model: */
666 if ( !pProxyModel
667 || !pProxyModel->sourceModel())
668 break;
669 UIFormEditorModel *pSourceModel = qobject_cast<UIFormEditorModel*>(pProxyModel->sourceModel());
670
671 /* Execute the call: */
672 if (!pSourceModel)
673 break;
674 pSourceModel->createTextDataEditor(m_index);
675 }
676 while (0);
677}
678
679void TextEditor::prepare()
680{
681 /* Create layout: */
682 QVBoxLayout *pLayout = new QVBoxLayout(this);
683 if (pLayout)
684 {
685 pLayout->setContentsMargins(0, 0, 0 ,0);
686 /* Create button: */
687 m_pButton = new QPushButton(this);
688 if (m_pButton)
689 {
690 connect(m_pButton, &QPushButton::clicked, this, &TextEditor::sltHandleButtonClick);
691 pLayout->addWidget(m_pButton);
692 }
693 }
694
695 /* Apply language settings: */
696 sltRetranslateUI();
697 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
698 this, &TextEditor::sltRetranslateUI);
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.

© 2023 Oracle
ContactPrivacy policyTerms of Use