VirtualBox

Ignore:
Timestamp:
Jun 3, 2019 1:20:41 PM (6 years ago)
Author:
vboxsync
Message:

FE/Qt: bugref:9434: Import Appliance wizard: Form Editor widget: A tricky way of providing user with possibility to edit multi-line text values.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/src/wizards/importappliance/UIFormEditorWidget.cpp

    r78935 r78936  
    2121#include <QHeaderView>
    2222#include <QItemEditorFactory>
     23#include <QPointer>
     24#include <QPushButton>
    2325#include <QSortFilterProxyModel>
    2426#include <QSpinBox>
    2527#include <QStyledItemDelegate>
     28#include <QTextEdit>
    2629#include <QVBoxLayout>
    2730
    2831/* GUI includes: */
     32#include "QIDialog.h"
     33#include "QIDialogButtonBox.h"
    2934#include "QITableView.h"
     35#include "QIWithRetranslateUI.h"
    3036#include "UIFormEditorWidget.h"
    3137#include "UIMessageCenter.h"
     
    5056    UIFormEditorDataType_Max
    5157};
     58
     59
     60/** Class used to hold text data. */
     61class TextData
     62{
     63public:
     64
     65    /** Constructs null text data. */
     66    TextData() {}
     67    /** Constructs text data on the basis of passed @a strText and @a index. */
     68    TextData(const QString &strText, const QModelIndex index = QModelIndex())
     69        : m_strText(strText), m_index(index) {}
     70    /** Constructs text data on the basis of @a another text data. */
     71    TextData(const TextData &another)
     72        : m_strText(another.text()), m_index(another.index()) {}
     73
     74    /** Assigns values of @a another text to this one. */
     75    TextData &operator=(const TextData &another)
     76    {
     77        m_strText = another.text();
     78        m_index = another.index();
     79        return *this;
     80    }
     81
     82    /** Returns text value. */
     83    QString text() const { return m_strText; }
     84
     85    /** Defines model @a index. */
     86    void setIndex(const QModelIndex &index) { m_index = index; }
     87    /** Returns model index. */
     88    QModelIndex index() const { return m_index; }
     89
     90private:
     91
     92    /** Holds text value. */
     93    QString      m_strText;
     94    /** Holds model index. */
     95    QModelIndex  m_index;
     96};
     97Q_DECLARE_METATYPE(TextData);
    5298
    5399
     
    139185
    140186
     187/** QWidget extension used as dummy TextData editor.
     188  * It's not actually an editor, but Edit... button instead which opens
     189  * real editor passing stored model index received from TextData value. */
     190class TextEditor : public QIWithRetranslateUI<QWidget>
     191{
     192    Q_OBJECT;
     193    Q_PROPERTY(TextData text READ text WRITE setText USER true);
     194
     195public:
     196
     197    /** Constructs TextData editor passing @a pParent to the base-class. */
     198    TextEditor(QWidget *pParent = 0);
     199
     200protected:
     201
     202    /** Handles translation event. */
     203    virtual void retranslateUi() /* override */;
     204
     205private slots:
     206
     207    /** Handles button click. */
     208    void sltHandleButtonClick();
     209
     210private:
     211
     212    /** Prepares all. */
     213    void prepare();
     214
     215    /** Defines @a text. */
     216    void setText(const TextData &text);
     217    /** Returns text. */
     218    TextData text() const;
     219
     220    /** Holds the button instance. */
     221    QPushButton *m_pButton;
     222    /** Holds the multiline text. */
     223    QString      m_strMultilineText;
     224    /** Holds the model index. */
     225    QModelIndex  m_index;
     226};
     227
     228
    141229/** QComboBox extension used as ChoiceData editor. */
    142230class ChoiceEditor : public QComboBox
     
    230318    void setBool(bool fBool);
    231319
     320    /** Returns whether cached string value is multiline. */
     321    bool isMultilineString() const;
     322    /** Returns value cast to text. */
     323    TextData toText() const;
     324    /** Defines @a text value. */
     325    void setText(const TextData &text);
    232326    /** Returns value cast to string. */
    233327    QString toString() const;
     
    276370    /** Holds cached bool value. */
    277371    bool               m_fBool;
     372    /** Holds whether cached string value is multiline. */
     373    bool               m_fMultilineString;
     374    /** Holds cached text value. */
     375    TextData           m_text;
    278376    /** Holds cached string value. */
    279377    QString            m_strString;
     
    327425    virtual QVariant data(const QModelIndex &index, int iRole) const /* override */;
    328426
     427    /** Creates actual TextData editor for specified @a index. */
     428    void createTextDataEditor(const QModelIndex &index);
     429
    329430private:
    330431
     
    374475    virtual QITableViewRow *childItem(int iIndex) const /* override */;
    375476};
     477
     478
     479/*********************************************************************************************************************************
     480*   Class TextEditor implementation.                                                                                             *
     481*********************************************************************************************************************************/
     482
     483TextEditor::TextEditor(QWidget *pParent /* = 0 */)
     484    : QIWithRetranslateUI<QWidget>(pParent)
     485    , m_pButton(0)
     486{
     487    prepare();
     488}
     489
     490void TextEditor::retranslateUi()
     491{
     492    m_pButton->setText(UIFormEditorWidget::tr("Edit..."));
     493}
     494
     495void TextEditor::sltHandleButtonClick()
     496{
     497    /* Redirect the edit call if possible: */
     498    do
     499    {
     500        /* Get the view: */
     501        if (   !parent()
     502            || !parent()->parent())
     503            break;
     504        UIFormEditorView *pView = qobject_cast<UIFormEditorView*>(parent()->parent());
     505
     506        /* Get the proxy model: */
     507        if (   !pView
     508            || !pView->model())
     509            break;
     510        UIFormEditorProxyModel *pProxyModel = qobject_cast<UIFormEditorProxyModel*>(pView->model());
     511
     512        /* Get the source model: */
     513        if (   !pProxyModel
     514            || !pProxyModel->sourceModel())
     515            break;
     516        UIFormEditorModel *pSourceModel = qobject_cast<UIFormEditorModel*>(pProxyModel->sourceModel());
     517
     518        /* Execute the call: */
     519        if (!pSourceModel)
     520            break;
     521        pSourceModel->createTextDataEditor(m_index);
     522    }
     523    while (0);
     524}
     525
     526void TextEditor::prepare()
     527{
     528    /* Create layout: */
     529    QVBoxLayout *pLayout = new QVBoxLayout(this);
     530    if (pLayout)
     531    {
     532        pLayout->setContentsMargins(0, 0, 0 ,0);
     533        /* Create button: */
     534        m_pButton = new QPushButton(this);
     535        if (m_pButton)
     536        {
     537            connect(m_pButton, &QPushButton::clicked, this, &TextEditor::sltHandleButtonClick);
     538            pLayout->addWidget(m_pButton);
     539        }
     540    }
     541
     542    /* Apply language settings: */
     543    retranslateUi();
     544}
     545
     546void TextEditor::setText(const TextData &text)
     547{
     548    m_strMultilineText = text.text();
     549    m_index = text.index();
     550}
     551
     552TextData TextEditor::text() const
     553{
     554    return TextData(m_strMultilineText, m_index);
     555}
    376556
    377557
     
    443623    , m_iGeneration(0)
    444624    , m_fBool(false)
     625    , m_fMultilineString(false)
     626    , m_text(TextData())
    445627    , m_strString(QString())
    446628    , m_choice(ChoiceData())
     
    500682}
    501683
    502 QString UIFormEditorRow::toString() const
    503 {
    504     AssertReturn(valueType() == KFormValueType_String, QString());
    505     return m_strString;
    506 }
    507 
    508 void UIFormEditorRow::setString(const QString &strString)
     684bool UIFormEditorRow::isMultilineString() const
     685{
     686    AssertReturn(valueType() == KFormValueType_String, false);
     687    return m_fMultilineString;
     688}
     689
     690TextData UIFormEditorRow::toText() const
     691{
     692    AssertReturn(valueType() == KFormValueType_String, TextData());
     693    return m_text;
     694}
     695
     696void UIFormEditorRow::setText(const TextData &text)
    509697{
    510698    AssertReturnVoid(valueType() == KFormValueType_String);
    511699    CStringFormValue comValue(m_comValue);
    512     CProgress comProgress = comValue.SetString(strString);
     700    CProgress comProgress = comValue.SetString(text.text());
    513701
    514702    /* Show error message if necessary: */
     
    530718}
    531719
    532 ChoiceData UIFormEditorRow::toChoice() const
    533 {
    534     AssertReturn(valueType() == KFormValueType_Choice, ChoiceData());
    535     return m_choice;
    536 }
    537 
    538 void UIFormEditorRow::setChoice(const ChoiceData &choice)
    539 {
    540     /* Do nothing for empty choices: */
    541     if (choice.selectedIndex() == -1)
    542         return;
    543 
    544     AssertReturnVoid(valueType() == KFormValueType_Choice);
    545     CChoiceFormValue comValue(m_comValue);
    546     CProgress comProgress = comValue.SetSelectedIndex(choice.selectedIndex());
     720QString UIFormEditorRow::toString() const
     721{
     722    AssertReturn(valueType() == KFormValueType_String, QString());
     723    return m_strString;
     724}
     725
     726void UIFormEditorRow::setString(const QString &strString)
     727{
     728    AssertReturnVoid(valueType() == KFormValueType_String);
     729    CStringFormValue comValue(m_comValue);
     730    CProgress comProgress = comValue.SetString(strString);
    547731
    548732    /* Show error message if necessary: */
     
    564748}
    565749
    566 RangedIntegerData UIFormEditorRow::toRangedInteger() const
    567 {
    568     AssertReturn(valueType() == KFormValueType_RangedInteger, RangedIntegerData());
    569     return m_rangedInteger;
    570 }
    571 
    572 void UIFormEditorRow::setRangedInteger(const RangedIntegerData &rangedInteger)
    573 {
    574     AssertReturnVoid(valueType() == KFormValueType_RangedInteger);
    575     CRangedIntegerFormValue comValue(m_comValue);
    576     CProgress comProgress = comValue.SetInteger(rangedInteger.integer());
     750ChoiceData UIFormEditorRow::toChoice() const
     751{
     752    AssertReturn(valueType() == KFormValueType_Choice, ChoiceData());
     753    return m_choice;
     754}
     755
     756void UIFormEditorRow::setChoice(const ChoiceData &choice)
     757{
     758    /* Do nothing for empty choices: */
     759    if (choice.selectedIndex() == -1)
     760        return;
     761
     762    AssertReturnVoid(valueType() == KFormValueType_Choice);
     763    CChoiceFormValue comValue(m_comValue);
     764    CProgress comProgress = comValue.SetSelectedIndex(choice.selectedIndex());
    577765
    578766    /* Show error message if necessary: */
     
    594782}
    595783
     784RangedIntegerData UIFormEditorRow::toRangedInteger() const
     785{
     786    AssertReturn(valueType() == KFormValueType_RangedInteger, RangedIntegerData());
     787    return m_rangedInteger;
     788}
     789
     790void UIFormEditorRow::setRangedInteger(const RangedIntegerData &rangedInteger)
     791{
     792    AssertReturnVoid(valueType() == KFormValueType_RangedInteger);
     793    CRangedIntegerFormValue comValue(m_comValue);
     794    CProgress comProgress = comValue.SetInteger(rangedInteger.integer());
     795
     796    /* Show error message if necessary: */
     797    if (!comValue.isOk())
     798        msgCenter().cannotAssignFormValue(comValue);
     799    else
     800    {
     801        /* Show "Acquire export form" progress: */
     802        msgCenter().showModalProgressDialog(comProgress, UIFormEditorWidget::tr("Assign value..."),
     803                                            ":/progress_reading_appliance_90px.png",
     804                                            0 /* parent */, 0 /* duration */);
     805
     806        /* Show error message if necessary: */
     807        if (!comProgress.isOk() || comProgress.GetResultCode() != 0)
     808            msgCenter().cannotAssignFormValue(comProgress);
     809        else
     810            updateValueCells();
     811    }
     812}
     813
    596814void UIFormEditorRow::updateValueCells()
    597815{
     
    612830        {
    613831            CStringFormValue comValue(m_comValue);
    614             m_strString = comValue.GetString();
    615             m_cells[UIFormEditorDataType_Value]->setText(m_strString);
     832            m_fMultilineString = comValue.GetMultiline();
     833            const QString strString = comValue.GetString();
     834            if (m_fMultilineString)
     835                m_text = TextData(strString);
     836            else
     837                m_strString = strString;
     838            m_cells[UIFormEditorDataType_Value]->setText(strString);
    616839            /// @todo check for errors
    617840            break;
     
    8311054                        case KFormValueType_String:
    8321055                        {
    833                             m_dataList[index.row()]->setString(value.toString());
     1056                            if (value.canConvert<TextData>())
     1057                                m_dataList[index.row()]->setText(value.value<TextData>());
     1058                            else
     1059                                m_dataList[index.row()]->setString(value.toString());
    8341060                            emit dataChanged(index, index);
    8351061                            updateGeneration();
     
    9141140                    {
    9151141                        case KFormValueType_String:
    916                             return QVariant::fromValue(m_dataList[index.row()]->toString());
     1142                        {
     1143                            if (m_dataList[index.row()]->isMultilineString())
     1144                            {
     1145                                TextData td = m_dataList[index.row()]->toText();
     1146                                td.setIndex(index);
     1147                                return QVariant::fromValue(td);
     1148                            }
     1149                            else
     1150                                return QVariant::fromValue(m_dataList[index.row()]->toString());
     1151                        }
    9171152                        case KFormValueType_Choice:
    9181153                            return QVariant::fromValue(m_dataList[index.row()]->toChoice());
     
    9481183}
    9491184
     1185void UIFormEditorModel::createTextDataEditor(const QModelIndex &index)
     1186{
     1187    /* Create dialog on-the-fly: */
     1188    QPointer<QIDialog> pDialog = new QIDialog(parentTable());
     1189    if (pDialog)
     1190    {
     1191        /* We will need that pointer: */
     1192        QTextEdit *pEditor = 0;
     1193        /* Create layout: */
     1194        QVBoxLayout *pLayout = new QVBoxLayout(pDialog);
     1195        if (pLayout)
     1196        {
     1197            /* Create text-editor: */
     1198            pEditor = new QTextEdit;
     1199            if (pEditor)
     1200            {
     1201                const TextData td = data(index, Qt::EditRole).value<TextData>();
     1202                pEditor->setPlainText(td.text());
     1203                pLayout->addWidget(pEditor);
     1204            }
     1205            /* Create button-box: */
     1206            QIDialogButtonBox *pBox = new QIDialogButtonBox;
     1207            if (pBox)
     1208            {
     1209                pBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
     1210                connect(pBox, &QIDialogButtonBox::accepted, pDialog, &QIDialog::accept);
     1211                connect(pBox, &QIDialogButtonBox::rejected, pDialog, &QIDialog::reject);
     1212                pLayout->addWidget(pBox);
     1213            }
     1214        }
     1215        /* Execute the dialog: */
     1216        if (pDialog->execute() == QDialog::Accepted)
     1217        {
     1218            const TextData td = TextData(pEditor->toPlainText(), index);
     1219            setData(index, QVariant::fromValue(td));
     1220        }
     1221        /* Cleanup: */
     1222        delete pDialog;
     1223    }
     1224}
     1225
    9501226QITableView *UIFormEditorModel::parentTable() const
    9511227{
     
    11031379                    if (pNewItemEditorFactory)
    11041380                    {
     1381                        /* Register TextEditor as the TextData editor: */
     1382                        int iTextId = qRegisterMetaType<TextData>();
     1383                        QStandardItemEditorCreator<TextEditor> *pTextEditorItemCreator = new QStandardItemEditorCreator<TextEditor>();
     1384                        pNewItemEditorFactory->registerEditor((QVariant::Type)iTextId, pTextEditorItemCreator);
     1385
    11051386                        /* Register ChoiceEditor as the ChoiceData editor: */
    11061387                        int iChoiceId = qRegisterMetaType<ChoiceData>();
Note: See TracChangeset for help on using the changeset viewer.

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