VirtualBox

Changeset 51931 in vbox for trunk/src/VBox/Frontends


Ignore:
Timestamp:
Jul 8, 2014 1:20:51 PM (11 years ago)
Author:
vboxsync
Message:

FE/Qt: 6660: Extra-data Manager: Initial GUI implementation (NOTE: Debug build only).

Location:
trunk/src/VBox/Frontends/VirtualBox/src
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/src/extradata/UIExtraDataDefs.cpp

    r51679 r51931  
    134134#endif /* VBOX_WITH_DEBUGGER_GUI */
    135135
     136#ifdef DEBUG
     137/* VirtualBox: Extra-data Manager window: */
     138const char* UIExtraDataDefs::GUI_ExtraDataManager_Geometry = "GUI/ExtraDataManager/Geometry";
     139const char* UIExtraDataDefs::GUI_ExtraDataManager_SplitterHints = "GUI/ExtraDataManager/SplitterHints";
     140#endif /* DEBUG */
     141
  • trunk/src/VBox/Frontends/VirtualBox/src/extradata/UIExtraDataDefs.h

    r51679 r51931  
    238238
    239239#ifdef VBOX_WITH_DEBUGGER_GUI
    240     /** @name Virtual Machine Debug UI
     240    /** @name Virtual Machine: Debug UI
    241241      * @{ */
    242242        /** Holds whether debugger UI enabled. */
     
    246246    /** @} */
    247247#endif /* VBOX_WITH_DEBUGGER_GUI */
     248
     249#ifdef DEBUG
     250    /** @name VirtualBox: Extra-data Manager window
     251      * @{ */
     252        /** Holds extra-data manager geometry. */
     253        extern const char* GUI_ExtraDataManager_Geometry;
     254        /** Holds extra-data manager splitter hints. */
     255        extern const char* GUI_ExtraDataManager_SplitterHints;
     256    /** @} */
     257#endif /* DEBUG */
    248258}
    249259
  • trunk/src/VBox/Frontends/VirtualBox/src/extradata/UIExtraDataManager.cpp

    r51930 r51931  
    1919#include <QMutex>
    2020#include <QDesktopWidget>
     21#ifdef DEBUG
     22# include <QMainWindow>
     23# include <QMenuBar>
     24# include <QListView>
     25# include <QTableView>
     26# include <QHeaderView>
     27# include <QStandardItemModel>
     28# include <QSortFilterProxyModel>
     29# include <QStyledItemDelegate>
     30# include <QPainter>
     31# include <QLabel>
     32# include <QLineEdit>
     33# include <QPushButton>
     34# include <QXmlStreamWriter>
     35# include <QXmlStreamReader>
     36#endif /* DEBUG */
    2137
    2238/* GUI includes: */
     
    2743#include "UIActionPool.h"
    2844#include "UIConverter.h"
     45#ifdef DEBUG
     46# include "VBoxUtils.h"
     47# include "UIMessageCenter.h"
     48# include "UIVirtualBoxEventHandler.h"
     49# include "UIIconPool.h"
     50# include "UIToolBar.h"
     51# include "QIWidgetValidator.h"
     52# include "QIDialogButtonBox.h"
     53# include "QIFileDialog.h"
     54# include "QISplitter.h"
     55# include "QIDialog.h"
     56#endif /* DEBUG */
    2957
    3058/* COM includes: */
     
    117145
    118146
     147#ifdef DEBUG
     148/** Data fields. */
     149enum Field
     150{
     151    Field_ID = Qt::UserRole + 1,
     152    Field_Name,
     153    Field_OsTypeID,
     154    Field_Known
     155};
     156
     157
     158/** QStyledItemDelegate extension
     159  * reflecting items of Extra Data Manager window: Chooser pane. */
     160class UIChooserPaneDelegate : public QStyledItemDelegate
     161{
     162    Q_OBJECT;
     163
     164public:
     165
     166    /** Constructor. */
     167    UIChooserPaneDelegate(QObject *pParent);
     168
     169private:
     170
     171    /** Size-hint calculation routine. */
     172    QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
     173
     174    /** Paint routine. */
     175    void paint(QPainter *pPainter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
     176
     177    /** Fetch pixmap info for passed QModelIndex. */
     178    static void fetchPixmapInfo(const QModelIndex &index, QPixmap &pixmap, QSize &pixmapSize);
     179
     180    /** Margin. */
     181    int m_iMargin;
     182    /** Spacing. */
     183    int m_iSpacing;
     184};
     185
     186UIChooserPaneDelegate::UIChooserPaneDelegate(QObject *pParent)
     187    : QStyledItemDelegate(pParent)
     188    , m_iMargin(3)
     189    , m_iSpacing(3)
     190{
     191}
     192
     193QSize UIChooserPaneDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
     194{
     195    /* Font metrics: */
     196    const QFontMetrics &fm = option.fontMetrics;
     197    /* Pixmap: */
     198    QPixmap pixmap;
     199    QSize pixmapSize;
     200    fetchPixmapInfo(index, pixmap, pixmapSize);
     201
     202    /* Calculate width: */
     203    const int iWidth = m_iMargin +
     204                       pixmapSize.width() +
     205                       2 * m_iSpacing +
     206                       qMax(fm.width(index.data(Field_Name).toString()),
     207                            fm.width(index.data(Field_ID).toString())) +
     208                       m_iMargin;
     209    /* Calculate height: */
     210    const int iHeight = m_iMargin +
     211                        qMax(pixmapSize.height(),
     212                             fm.height() + m_iSpacing + fm.height()) +
     213                        m_iMargin;
     214
     215    /* Return result: */
     216    return QSize(iWidth, iHeight);
     217}
     218
     219void UIChooserPaneDelegate::paint(QPainter *pPainter, const QStyleOptionViewItem &option, const QModelIndex &index) const
     220{
     221    /* Item rect: */
     222    const QRect &optionRect = option.rect;
     223    /* Palette: */
     224    const QPalette &palette = option.palette;
     225    /* Font metrics: */
     226    const QFontMetrics &fm = option.fontMetrics;
     227    /* Pixmap: */
     228    QPixmap pixmap;
     229    QSize pixmapSize;
     230    fetchPixmapInfo(index, pixmap, pixmapSize);
     231
     232    /* If item selected: */
     233    if (option.state & QStyle::State_Selected)
     234    {
     235        /* Fill background with selection color: */
     236        QColor highlight = palette.color(option.state & QStyle::State_Active ?
     237                                         QPalette::Active : QPalette::Inactive,
     238                                         QPalette::Highlight);
     239        QLinearGradient bgGrad(optionRect.topLeft(), optionRect.bottomLeft());
     240        bgGrad.setColorAt(0, highlight.lighter(120));
     241        bgGrad.setColorAt(1, highlight);
     242        pPainter->fillRect(optionRect, bgGrad);
     243        /* Draw focus frame: */
     244        QStyleOptionFocusRect focusOption;
     245        focusOption.rect = optionRect;
     246        QApplication::style()->drawPrimitive(QStyle::PE_FrameFocusRect, &focusOption, pPainter);
     247    }
     248
     249    /* Draw pixmap: */
     250    const QPoint pixmapOrigin = optionRect.topLeft() +
     251                                QPoint(m_iMargin, m_iMargin);
     252    pPainter->drawPixmap(pixmapOrigin, pixmap);
     253
     254    /* Is that known item? */
     255    bool fKnown = index.data(Field_Known).toBool();
     256    if (fKnown)
     257    {
     258        pPainter->save();
     259        QFont font = pPainter->font();
     260        font.setBold(true);
     261        pPainter->setFont(font);
     262    }
     263
     264    /* Draw item name: */
     265    const QPoint nameOrigin = pixmapOrigin +
     266                              QPoint(pixmapSize.width(), 0) +
     267                              QPoint(2 * m_iSpacing, 0) +
     268                              QPoint(0, fm.ascent());
     269    pPainter->drawText(nameOrigin, index.data(Field_Name).toString());
     270
     271    /* Was that known item? */
     272    if (fKnown)
     273        pPainter->restore();
     274
     275    /* Draw item ID: */
     276    const QPoint idOrigin = nameOrigin +
     277                            QPoint(0, m_iSpacing) +
     278                            QPoint(0, fm.height());
     279    pPainter->drawText(idOrigin, index.data(Field_ID).toString());
     280}
     281
     282/* static */
     283void UIChooserPaneDelegate::fetchPixmapInfo(const QModelIndex &index, QPixmap &pixmap, QSize &pixmapSize)
     284{
     285    /* If proper machine ID passed => return corresponding pixmap/size: */
     286    if (index.data(Field_ID).toString() != UIExtraDataManager::GlobalID)
     287        pixmap = vboxGlobal().vmGuestOSTypeIcon(index.data(Field_OsTypeID).toString(), &pixmapSize);
     288    else
     289    {
     290        /* For global ID we return static pixmap/size: */
     291        const QIcon icon = UIIconPool::iconSet(":/edataglobal_32px.png");
     292        pixmapSize = icon.availableSizes().first();
     293        pixmap = icon.pixmap(pixmapSize);
     294    }
     295}
     296
     297
     298/** QSortFilterProxyModel extension
     299  * used by the chooser-pane of the UIExtraDataManagerWindow. */
     300class UIChooserPaneSortingModel : public QSortFilterProxyModel
     301{
     302    Q_OBJECT;
     303
     304public:
     305
     306    /** Constructor, passes @a pParent to the QIRichToolButton constructor. */
     307    UIChooserPaneSortingModel(QObject *pParent) : QSortFilterProxyModel(pParent) {}
     308
     309protected:
     310
     311    /** Returns true if the value of the item referred to by the given index left
     312      * is less than the value of the item referred to by the given index right,
     313      * otherwise returns false. */
     314    bool lessThan(const QModelIndex &leftIdx, const QModelIndex &rightIdx) const
     315    {
     316        /* Compare by ID first: */
     317        const QString strID1 = leftIdx.data(Field_ID).toString();
     318        const QString strID2 = rightIdx.data(Field_ID).toString();
     319        if (strID1 == UIExtraDataManager::GlobalID)
     320            return true;
     321        else if (strID2 == UIExtraDataManager::GlobalID)
     322            return false;
     323        /* Compare role finally: */
     324        return QSortFilterProxyModel::lessThan(leftIdx, rightIdx);
     325    }
     326};
     327
     328
     329/** QMainWindow extension
     330  * providing Extra Data Manager with UI features. */
     331class UIExtraDataManagerWindow : public QMainWindow
     332{
     333    Q_OBJECT;
     334
     335public:
     336
     337    /** @name Constructor/Destructor
     338      * @{ */
     339        /** Extra-data Manager Window constructor. */
     340        UIExtraDataManagerWindow();
     341        /** Extra-data Manager Window destructor. */
     342        ~UIExtraDataManagerWindow();
     343    /** @} */
     344
     345    /** @name Management
     346      * @{ */
     347        /** Show and raise. */
     348        void showAndRaise(QWidget *pCenterWidget);
     349    /** @} */
     350
     351private slots:
     352
     353    /** @name General
     354      * @{ */
     355        /** Handles machine (un)registration. */
     356        void sltMachineRegistered(QString strID, bool fAdded);
     357        /** Handles extra-data change. */
     358        void sltExtraDataChange(QString strID, QString strKey, QString strValue);
     359    /** @} */
     360
     361    /** @name Chooser-pane
     362      * @{ */
     363        /** Handles filter-apply signal for the chooser-pane. */
     364        void sltChooserApplyFilter(const QString &strFilter);
     365        /** Handles current-changed signal for the chooser-pane: */
     366        void sltChooserHandleCurrentChanged(const QModelIndex &index);
     367        /** Handles item-selection-changed signal for the chooser-pane: */
     368        void sltChooserHandleSelectionChanged(const QItemSelection &selected,
     369                                              const QItemSelection &deselected);
     370    /** @} */
     371
     372    /** @name Data-pane
     373      * @{ */
     374        /** Handles filter-apply signal for the data-pane. */
     375        void sltDataApplyFilter(const QString &strFilter);
     376        /** Handles item-selection-changed signal for the data-pane: */
     377        void sltDataHandleSelectionChanged(const QItemSelection &selected,
     378                                           const QItemSelection &deselected);
     379        /** Handles item-changed signal for the data-pane: */
     380        void sltDataHandleItemChanged(QStandardItem *pItem);
     381        /** Handles context-menu-requested signal for the data-pane: */
     382        void sltDataHandleCustomContextMenuRequested(const QPoint &pos);
     383    /** @} */
     384
     385    /** @name Actions
     386      * @{ */
     387        /** Add handler. */
     388        void sltAdd();
     389        /** Remove handler. */
     390        void sltDel();
     391        /** Save handler. */
     392        void sltSave();
     393        /** Load handler. */
     394        void sltLoad();
     395    /** @} */
     396
     397private:
     398
     399    /** @name Prepare/Cleanup
     400      * @{ */
     401        /** Prepare instance. */
     402        void prepare();
     403        /** Prepare this. */
     404        void prepareThis();
     405        /** Prepare connections. */
     406        void prepareConnections();
     407        /** Prepare menu. */
     408        void prepareMenu();
     409        /** Prepare central widget. */
     410        void prepareCentralWidget();
     411        /** Prepare tool-bar. */
     412        void prepareToolBar();
     413        /** Prepare splitter. */
     414        void prepareSplitter();
     415        /** Prepare panes: */
     416        void preparePanes();
     417        /** Prepare chooser pane. */
     418        void preparePaneChooser();
     419        /** Prepare data pane. */
     420        void preparePaneData();
     421        /** Prepare button-box. */
     422        void prepareButtonBox();
     423        /** Load window settings. */
     424        void loadSettings();
     425
     426        /** Save window settings. */
     427        void saveSettings();
     428        /** Cleanup instance. */
     429        void cleanup();
     430    /** @} */
     431
     432    /** @name Event Processing
     433      * @{ */
     434        /** Common event-handler. */
     435        bool event(QEvent *pEvent);
     436    /** @} */
     437
     438    /** @name Actions
     439      * @{ */
     440        /** */
     441        void updateActionsAvailability();
     442    /** @} */
     443
     444    /** @name Chooser-pane
     445      * @{ */
     446        /** Returns chooser index for @a iRow. */
     447        QModelIndex chooserIndex(int iRow) const;
     448        /** Returns current chooser index. */
     449        QModelIndex currentChooserIndex() const;
     450
     451        /** Returns chooser ID for @a iRow. */
     452        QString chooserID(int iRow) const;
     453        /** Returns current chooser ID. */
     454        QString currentChooserID() const;
     455
     456        /** Returns chooser Name for @a iRow. */
     457        QString chooserName(int iRow) const;
     458        /** Returns current Name. */
     459        QString currentChooserName() const;
     460
     461        /** Adds chooser item. */
     462        void addChooserItem(const QString &strID,
     463                            const QString &strName,
     464                            const QString &strOsTypeID,
     465                            const int iPosition = -1);
     466        /** Adds chooser item by machine. */
     467        void addChooserItemByMachine(const CMachine &machine,
     468                                     const int iPosition = -1);
     469        /** Adds chooser item by ID. */
     470        void addChooserItemByID(const QString &strID,
     471                                const int iPosition = -1);
     472
     473        /** Make sure chooser have current-index if possible. */
     474        void makeSureChooserHaveCurrentIndexIfPossible();
     475    /** @} */
     476
     477    /** @name Data-pane
     478      * @{ */
     479        /** Returns data index for @a iRow and @a iColumn. */
     480        QModelIndex dataIndex(int iRow, int iColumn) const;
     481
     482        /** Returns data-key index for @a iRow. */
     483        QModelIndex dataKeyIndex(int iRow) const;
     484
     485        /** Returns data-value index for @a iRow. */
     486        QModelIndex dataValueIndex(int iRow) const;
     487
     488        /** Returns current data-key. */
     489        QString dataKey(int iRow) const;
     490
     491        /** Returns current data-value. */
     492        QString dataValue(int iRow) const;
     493
     494        /** Adds data item. */
     495        void addDataItem(const QString &strKey,
     496                         const QString &strValue,
     497                         const int iPosition = -1);
     498
     499        /** Sorts data items. */
     500        void sortData();
     501    /** @} */
     502
     503
     504    /** @name General
     505      * @{ */
     506        /** Current geometry. */
     507        QRect m_geometry;
     508        QVBoxLayout *m_pMainLayout;
     509        /** Data pane: Tool-bar. */
     510        UIToolBar *m_pToolBar;
     511        /** Splitter. */
     512        QISplitter *m_pSplitter;
     513    /** @} */
     514
     515    /** @name Chooser-pane
     516      * @{ */
     517        /** Chooser pane. */
     518        QWidget *m_pPaneOfChooser;
     519        /** Chooser filter. */
     520        QLineEdit *m_pFilterOfChooser;
     521        /** Chooser pane: List-view. */
     522        QListView *m_pViewOfChooser;
     523        /** Chooser pane: Source-model. */
     524        QStandardItemModel *m_pModelSourceOfChooser;
     525        /** Chooser pane: Proxy-model. */
     526        UIChooserPaneSortingModel *m_pModelProxyOfChooser;
     527    /** @} */
     528
     529    /** @name Data-pane
     530      * @{ */
     531        /** Data pane. */
     532        QWidget *m_pPaneOfData;
     533        /** Dta filter. */
     534        QLineEdit *m_pFilterOfData;
     535        /** Data pane: Table-view. */
     536        QTableView *m_pViewOfData;
     537        /** Data pane: Item-model. */
     538        QStandardItemModel *m_pModelSourceOfData;
     539        /** Data pane: Proxy-model. */
     540        QSortFilterProxyModel *m_pModelProxyOfData;
     541    /** @} */
     542
     543    /** @name Button Box
     544      * @{ */
     545        /** Dialog button-box. */
     546        QIDialogButtonBox *m_pButtonBox;
     547    /** @} */
     548
     549    /** @name Actions
     550      * @{ */
     551        /** Add action. */
     552        QAction *m_pActionAdd;
     553        /** Del action. */
     554        QAction *m_pActionDel;
     555        /** Load action. */
     556        QAction *m_pActionLoad;
     557        /** Save action. */
     558        QAction *m_pActionSave;
     559    /** @} */
     560};
     561
     562UIExtraDataManagerWindow::UIExtraDataManagerWindow()
     563    : m_pMainLayout(0), m_pToolBar(0), m_pSplitter(0)
     564    , m_pPaneOfChooser(0), m_pFilterOfChooser(0), m_pViewOfChooser(0)
     565    , m_pModelSourceOfChooser(0), m_pModelProxyOfChooser(0)
     566    , m_pPaneOfData(0), m_pFilterOfData(0), m_pViewOfData(0),
     567      m_pModelSourceOfData(0), m_pModelProxyOfData(0)
     568    , m_pButtonBox(0)
     569    , m_pActionAdd(0), m_pActionDel(0)
     570    , m_pActionLoad(0), m_pActionSave(0)
     571{
     572    /* Prepare: */
     573    prepare();
     574}
     575
     576UIExtraDataManagerWindow::~UIExtraDataManagerWindow()
     577{
     578    /* Cleanup: */
     579    cleanup();
     580}
     581
     582void UIExtraDataManagerWindow::showAndRaise(QWidget *pCenterWidget)
     583{
     584    /* Show: */
     585    show();
     586    /* Restore from minimized state: */
     587    setWindowState(windowState() & ~Qt::WindowMinimized);
     588    /* Raise: */
     589    activateWindow();
     590//    /* Center according passed widget: */
     591//    VBoxGlobal::centerWidget(this, pCenterWidget, false);
     592}
     593
     594void UIExtraDataManagerWindow::sltMachineRegistered(QString strID, bool fRegistered)
     595{
     596    /* Machine registered: */
     597    if (fRegistered)
     598    {
     599        /* Gather list of 'known IDs': */
     600        QStringList knownIDs;
     601        for (int iRow = 0; iRow < m_pModelSourceOfChooser->rowCount(); ++iRow)
     602            knownIDs << chooserID(iRow);
     603
     604        /* Get machine items: */
     605        const CMachineVector machines = vboxGlobal().virtualBox().GetMachines();
     606        /* Look for the proper place to insert new machine item: */
     607        QString strPositionID = UIExtraDataManager::GlobalID;
     608        foreach (const CMachine &machine, machines)
     609        {
     610            /* Get iterated machine ID: */
     611            const QString strIteratedID = machine.GetId();
     612            /* If 'iterated ID' equal to 'added ID' => break now: */
     613            if (strIteratedID == strID)
     614                break;
     615            /* If 'iterated ID' is 'known ID' => remember it: */
     616            if (knownIDs.contains(strIteratedID))
     617                strPositionID = strIteratedID;
     618        }
     619
     620        /* Add new chooser item into source-model: */
     621        addChooserItemByID(strID, knownIDs.indexOf(strPositionID) + 1);
     622        /* And sort proxy-model: */
     623        m_pModelProxyOfChooser->sort(0, Qt::AscendingOrder);
     624        /* Make sure chooser have current-index if possible: */
     625        makeSureChooserHaveCurrentIndexIfPossible();
     626    }
     627    /* Machine unregistered: */
     628    else
     629    {
     630        /* Remove chooser item with 'removed ID' if it is among 'known IDs': */
     631        for (int iRow = 0; iRow < m_pModelSourceOfChooser->rowCount(); ++iRow)
     632            if (chooserID(iRow) == strID)
     633                m_pModelSourceOfChooser->removeRow(iRow);
     634    }
     635}
     636
     637void UIExtraDataManagerWindow::sltExtraDataChange(QString strID, QString strKey, QString strValue)
     638{
     639    /* Skip unrelated IDs: */
     640    if (currentChooserID() != strID)
     641        return;
     642
     643    /* List of 'known keys': */
     644    QStringList knownKeys;
     645    for (int iRow = 0; iRow < m_pModelSourceOfData->rowCount(); ++iRow)
     646        knownKeys << dataKey(iRow);
     647
     648    /* Check if 'changed key' is 'known key': */
     649    int iPosition = knownKeys.indexOf(strKey);
     650    /* If that is 'known key': */
     651    if (iPosition != -1)
     652    {
     653        /* If 'changed value' is empty => REMOVE item: */
     654        if (strValue.isEmpty())
     655            m_pModelSourceOfData->removeRow(iPosition);
     656        /* If 'changed value' is NOT empty => UPDATE item: */
     657        else
     658            m_pModelSourceOfData->itemFromIndex(dataValueIndex(iPosition))->setText(strValue);
     659    }
     660    /* Else if 'changed value' is NOT empty: */
     661    else if (!strValue.isEmpty())
     662    {
     663        /* Look for the proper place for 'changed key': */
     664        QString strPositionKey;
     665        foreach (const QString &strIteratedKey, gEDataManager->map(strID).keys())
     666        {
     667            /* If 'iterated key' equal to 'changed key' => break now: */
     668            if (strIteratedKey == strKey)
     669                break;
     670            /* If 'iterated key' is 'known key' => remember it: */
     671            if (knownKeys.contains(strIteratedKey))
     672                strPositionKey = strIteratedKey;
     673        }
     674        /* Calculate resulting position: */
     675        iPosition = knownKeys.indexOf(strPositionKey) + 1;
     676        /* INSERT item to the required position: */
     677        addDataItem(strKey, strValue, iPosition);
     678        /* And sort proxy-model: */
     679        sortData();
     680    }
     681}
     682
     683void UIExtraDataManagerWindow::sltChooserApplyFilter(const QString &strFilter)
     684{
     685    /* Apply filtering rule: */
     686    m_pModelProxyOfChooser->setFilterWildcard(strFilter);
     687    /* Make sure chooser have current-index if possible: */
     688    makeSureChooserHaveCurrentIndexIfPossible();
     689}
     690
     691void UIExtraDataManagerWindow::sltChooserHandleCurrentChanged(const QModelIndex &index)
     692{
     693    /* Remove all the old items first: */
     694    while (m_pModelSourceOfData->rowCount())
     695        m_pModelSourceOfData->removeRow(0);
     696
     697    /* Ignore invalid indexes: */
     698    if (!index.isValid())
     699        return;
     700
     701    /* Add all the new items finally: */
     702    const QString strID = index.data(Field_ID).toString();
     703    AssertReturnVoid(gEDataManager->contains(strID));
     704    const ExtraDataMap data = gEDataManager->map(strID);
     705    foreach (const QString &strKey, data.keys())
     706        addDataItem(strKey, data.value(strKey));
     707    /* And sort proxy-model: */
     708    sortData();
     709}
     710
     711void UIExtraDataManagerWindow::sltChooserHandleSelectionChanged(const QItemSelection &selected,
     712                                                                const QItemSelection &deselected)
     713{
     714    /* Update actions availability: */
     715    updateActionsAvailability();
     716}
     717
     718void UIExtraDataManagerWindow::sltDataApplyFilter(const QString &strFilter)
     719{
     720    /* Apply filtering rule: */
     721    m_pModelProxyOfData->setFilterWildcard(strFilter);
     722}
     723
     724void UIExtraDataManagerWindow::sltDataHandleSelectionChanged(const QItemSelection &selected,
     725                                                             const QItemSelection &deselected)
     726{
     727    /* Update actions availability: */
     728    updateActionsAvailability();
     729}
     730
     731void UIExtraDataManagerWindow::sltDataHandleItemChanged(QStandardItem *pItem)
     732{
     733    /* Value-data index: */
     734    const QModelIndex valueIndex = m_pModelSourceOfData->indexFromItem(pItem);
     735    const int iRow = valueIndex.row();
     736    const int iColumn = valueIndex.column();
     737    AssertMsgReturnVoid(iColumn == 1, ("Only 2nd column can be changed!\n"));
     738
     739    /* Key-data index: */
     740    const QModelIndex keyIndex = dataKeyIndex(iRow);
     741
     742    /* Update extra-data: */
     743    gEDataManager->setExtraDataString(keyIndex.data().toString(),
     744                                      valueIndex.data().toString(),
     745                                      currentChooserID());
     746}
     747
     748void UIExtraDataManagerWindow::sltDataHandleCustomContextMenuRequested(const QPoint &pos)
     749{
     750    /* Prepare menu: */
     751    QMenu menu;
     752    menu.addAction(m_pActionDel);
     753    menu.addAction(m_pActionSave);
     754    /* Execute menu: */
     755    m_pActionSave->setProperty("CalledFromContextMenu", true);
     756    menu.exec(m_pViewOfData->viewport()->mapToGlobal(pos));
     757    m_pActionSave->setProperty("CalledFromContextMenu", QVariant());
     758}
     759
     760void UIExtraDataManagerWindow::sltAdd()
     761{
     762    /* Make sure this slot called by corresponding action only: */
     763    QAction *pSenderAction = qobject_cast<QAction*>(sender());
     764    AssertReturnVoid(pSenderAction && m_pActionAdd);
     765
     766    /* Create input-dialog: */
     767    QPointer<QIDialog> pInputDialog = new QIDialog(this);
     768    AssertPtrReturnVoid(pInputDialog.data());
     769    {
     770        /* Configure input-dialog: */
     771        pInputDialog->setWindowTitle("Add extra-data record..");
     772        pInputDialog->setMinimumWidth(400);
     773        /* Create main-layout: */
     774        QVBoxLayout *pMainLayout = new QVBoxLayout(pInputDialog);
     775        AssertPtrReturnVoid(pMainLayout);
     776        {
     777            /* Create dialog validator group: */
     778            QObjectValidatorGroup *pValidatorGroup = new QObjectValidatorGroup(pInputDialog);
     779            AssertReturnVoid(pValidatorGroup);
     780            /* Create input-layout: */
     781            QGridLayout *pInputLayout = new QGridLayout;
     782            AssertPtrReturnVoid(pInputLayout);
     783            {
     784                /* Create key-label: */
     785                QLabel *pLabelKey = new QLabel("&Name:");
     786                {
     787                    /* Configure key-label: */
     788                    pLabelKey->setAlignment(Qt::AlignRight);
     789                    /* Add key-label into input-layout: */
     790                    pInputLayout->addWidget(pLabelKey, 0, 0);
     791                }
     792                /* Create key-editor: */
     793                QLineEdit *pEditorKey = new QLineEdit;
     794                {
     795                    /* Configure key-editor: */
     796                    pLabelKey->setBuddy(pEditorKey);
     797                    /* Create key-editor property setter: */
     798                    QObjectPropertySetter *pKeyPropertySetter = new QObjectPropertySetter(pInputDialog, "Key");
     799                    AssertPtrReturnVoid(pKeyPropertySetter);
     800                    {
     801                        /* Configure key-editor property setter: */
     802                        connect(pEditorKey, SIGNAL(textEdited(const QString&)),
     803                                pKeyPropertySetter, SLOT(sltAssignProperty(const QString&)));
     804                    }
     805                    /* Create key-editor validator: */
     806                    QObjectValidator *pKeyValidator = new QObjectValidator(new QRegExpValidator(QRegExp("[\\s\\S]+")));
     807                    AssertPtrReturnVoid(pKeyValidator);
     808                    {
     809                        /* Configure key-editor validator: */
     810                        connect(pEditorKey, SIGNAL(textEdited(const QString&)),
     811                                pKeyValidator, SLOT(sltValidate(QString)));
     812                        /* Add key-editor validator into dialog validator group: */
     813                        pValidatorGroup->addObjectValidator(pKeyValidator);
     814                    }
     815                    /* Add key-editor into input-layout: */
     816                    pInputLayout->addWidget(pEditorKey, 0, 1);
     817                }
     818                /* Create value-label: */
     819                QLabel *pLabelValue = new QLabel("&Value:");
     820                {
     821                    /* Configure value-label: */
     822                    pLabelValue->setAlignment(Qt::AlignRight);
     823                    /* Add value-label into input-layout: */
     824                    pInputLayout->addWidget(pLabelValue, 1, 0);
     825                }
     826                /* Create value-editor: */
     827                QLineEdit *pEditorValue = new QLineEdit;
     828                {
     829                    /* Configure value-editor: */
     830                    pLabelValue->setBuddy(pEditorValue);
     831                    /* Create value-editor property setter: */
     832                    QObjectPropertySetter *pValuePropertySetter = new QObjectPropertySetter(pInputDialog, "Value");
     833                    AssertPtrReturnVoid(pValuePropertySetter);
     834                    {
     835                        /* Configure value-editor property setter: */
     836                        connect(pEditorValue, SIGNAL(textEdited(const QString&)),
     837                                pValuePropertySetter, SLOT(sltAssignProperty(const QString&)));
     838                    }
     839                    /* Create value-editor validator: */
     840                    QObjectValidator *pValueValidator = new QObjectValidator(new QRegExpValidator(QRegExp("[\\s\\S]+")));
     841                    AssertPtrReturnVoid(pValueValidator);
     842                    {
     843                        /* Configure value-editor validator: */
     844                        connect(pEditorValue, SIGNAL(textEdited(const QString&)),
     845                                pValueValidator, SLOT(sltValidate(QString)));
     846                        /* Add value-editor validator into dialog validator group: */
     847                        pValidatorGroup->addObjectValidator(pValueValidator);
     848                    }
     849                    /* Add value-editor into input-layout: */
     850                    pInputLayout->addWidget(pEditorValue, 1, 1);
     851                }
     852                /* Add input-layout into main-layout: */
     853                pMainLayout->addLayout(pInputLayout);
     854            }
     855            /* Create stretch: */
     856            pMainLayout->addStretch();
     857            /* Create dialog button-box: */
     858            QIDialogButtonBox *pButtonBox = new QIDialogButtonBox;
     859            AssertPtrReturnVoid(pButtonBox);
     860            {
     861                /* Configure button-box: */
     862                pButtonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
     863                pButtonBox->button(QDialogButtonBox::Ok)->setDefault(true);
     864                pButtonBox->button(QDialogButtonBox::Ok)->setEnabled(pValidatorGroup->result());
     865                pButtonBox->button(QDialogButtonBox::Cancel)->setShortcut(Qt::Key_Escape);
     866                connect(pValidatorGroup, SIGNAL(sigValidityChange(bool)),
     867                        pButtonBox->button(QDialogButtonBox::Ok), SLOT(setEnabled(bool)));
     868                connect(pButtonBox, SIGNAL(accepted()), pInputDialog, SLOT(accept()));
     869                connect(pButtonBox, SIGNAL(rejected()), pInputDialog, SLOT(reject()));
     870                /* Add button-box into main-layout: */
     871                pMainLayout->addWidget(pButtonBox);
     872            }
     873        }
     874    }
     875
     876    /* Execute input-dialog: */
     877    if (pInputDialog->exec() == QDialog::Accepted)
     878    {
     879        gEDataManager->setExtraDataString(pInputDialog->property("Key").toString(),
     880                                          pInputDialog->property("Value").toString(),
     881                                          currentChooserID());
     882    }
     883
     884    /* Destroy input-dialog: */
     885    if (pInputDialog)
     886        delete pInputDialog;
     887}
     888
     889void UIExtraDataManagerWindow::sltDel()
     890{
     891    /* Make sure this slot called by corresponding action only: */
     892    QAction *pSenderAction = qobject_cast<QAction*>(sender());
     893    AssertReturnVoid(pSenderAction && m_pActionDel);
     894
     895    /* Gather the map of chosen items: */
     896    QMap<QString, QString> items;
     897    foreach (const QModelIndex &keyIndex, m_pViewOfData->selectionModel()->selectedRows(0))
     898        items.insert(keyIndex.data().toString(), dataValueIndex(keyIndex.row()).data().toString());
     899
     900    /* Prepare details: */
     901    const QString strTableTemplate("<!--EOM--><table border=0 cellspacing=10 cellpadding=0 width=500>%1</table>");
     902    const QString strRowTemplate("<tr><td><tt>%1</tt></td><td align=right><tt>%2</tt></td></tr>");
     903    QString strDetails;
     904    foreach (const QString &strKey, items.keys())
     905        strDetails += strRowTemplate.arg(strKey, items.value(strKey));
     906    strDetails = strTableTemplate.arg(strDetails);
     907
     908    /* Ask for user' confirmation: */
     909    if (!msgCenter().errorWithQuestion(this, MessageType_Question,
     910                                       QString("<p>Do you really wish to "
     911                                               "remove chosen records?</p>"),
     912                                       strDetails))
     913        return;
     914
     915    /* Erase all the chosen extra-data records: */
     916    foreach (const QString &strKey, items.keys())
     917        gEDataManager->setExtraDataString(strKey, QString(), currentChooserID());
     918}
     919
     920void UIExtraDataManagerWindow::sltSave()
     921{
     922    /* Make sure this slot called by corresponding action only: */
     923    QAction *pSenderAction = qobject_cast<QAction*>(sender());
     924    AssertReturnVoid(pSenderAction && m_pActionSave);
     925
     926    /* Compose initial file-name: */
     927    const CVirtualBox vbox = vboxGlobal().virtualBox();
     928    const QString strInitialFileName = QDir(vbox.GetHomeFolder()).absoluteFilePath(QString("%1_ExtraData.xml").arg(currentChooserName()));
     929    /* Open file-save dialog to choose file to save extra-data into: */
     930    const QString strFileName = QIFileDialog::getSaveFileName(strInitialFileName, "XML files (*.xml)", this,
     931                                                              "Choose file to save extra-data into..", 0, true, true);
     932    /* Make sure file-name was chosen: */
     933    if (strFileName.isEmpty())
     934        return;
     935
     936    /* Create file: */
     937    QFile output(strFileName);
     938    /* Open file for writing: */
     939    bool fOpened = output.open(QIODevice::WriteOnly);
     940    AssertReturnVoid(fOpened);
     941    {
     942        /* Create XML stream writer: */
     943        QXmlStreamWriter stream(&output);
     944        /* Configure XML stream writer: */
     945        stream.setAutoFormatting(true);
     946        stream.setAutoFormattingIndent(2);
     947        /* Write document: */
     948        stream.writeStartDocument();
     949        {
     950            stream.writeStartElement("VirtualBox");
     951            {
     952                const QString strID = currentChooserID();
     953                bool fIsMachine = strID != UIExtraDataManager::GlobalID;
     954                const QString strType = fIsMachine ? "Machine" : "Global";
     955                stream.writeStartElement(strType);
     956                {
     957                    if (fIsMachine)
     958                        stream.writeAttribute("uuid", QString("{%1}").arg(strID));
     959                    stream.writeStartElement("ExtraData");
     960                    {
     961                        /* Called from context-menu: */
     962                        if (pSenderAction->property("CalledFromContextMenu").toBool() &&
     963                            !m_pViewOfData->selectionModel()->selection().isEmpty())
     964                        {
     965                            foreach (const QModelIndex &keyIndex, m_pViewOfData->selectionModel()->selectedRows())
     966                            {
     967                                /* Get data-value index: */
     968                                const QModelIndex valueIndex = dataValueIndex(keyIndex.row());
     969                                /* Write corresponding extra-data item into stream: */
     970                                stream.writeStartElement("ExtraDataItem");
     971                                {
     972                                    stream.writeAttribute("name", keyIndex.data().toString());
     973                                    stream.writeAttribute("value", valueIndex.data().toString());
     974                                }
     975                                stream.writeEndElement(); /* ExtraDataItem */
     976                            }
     977                        }
     978                        /* Called from menu-bar/tool-bar: */
     979                        else
     980                        {
     981                            for (int iRow = 0; iRow < m_pModelProxyOfData->rowCount(); ++iRow)
     982                            {
     983                                /* Get indexes: */
     984                                const QModelIndex keyIndex = m_pModelProxyOfData->index(iRow, 0);
     985                                const QModelIndex valueIndex = m_pModelProxyOfData->index(iRow, 1);
     986                                /* Write corresponding extra-data item into stream: */
     987                                stream.writeStartElement("ExtraDataItem");
     988                                {
     989                                    stream.writeAttribute("name", keyIndex.data().toString());
     990                                    stream.writeAttribute("value", valueIndex.data().toString());
     991                                }
     992                                stream.writeEndElement(); /* ExtraDataItem */
     993                            }
     994                        }
     995                    }
     996                    stream.writeEndElement(); /* ExtraData */
     997                }
     998                stream.writeEndElement(); /* strType */
     999            }
     1000            stream.writeEndElement(); /* VirtualBox */
     1001        }
     1002        stream.writeEndDocument();
     1003        /* Close file: */
     1004        output.close();
     1005    }
     1006}
     1007
     1008void UIExtraDataManagerWindow::sltLoad()
     1009{
     1010    /* Make sure this slot called by corresponding action only: */
     1011    QAction *pSenderAction = qobject_cast<QAction*>(sender());
     1012    AssertReturnVoid(pSenderAction && m_pActionLoad);
     1013
     1014    /* Compose initial file-name: */
     1015    const CVirtualBox vbox = vboxGlobal().virtualBox();
     1016    const QString strInitialFileName = QDir(vbox.GetHomeFolder()).absoluteFilePath(QString("%1_ExtraData.xml").arg(currentChooserName()));
     1017    /* Open file-open dialog to choose file to open extra-data into: */
     1018    const QString strFileName = QIFileDialog::getOpenFileName(strInitialFileName, "XML files (*.xml)", this,
     1019                                                              "Choose file to load extra-data from..");
     1020    /* Make sure file-name was chosen: */
     1021    if (strFileName.isEmpty())
     1022        return;
     1023
     1024    /* Create file: */
     1025    QFile input(strFileName);
     1026    /* Open file for writing: */
     1027    bool fOpened = input.open(QIODevice::ReadOnly);
     1028    AssertReturnVoid(fOpened);
     1029    {
     1030        /* Create XML stream reader: */
     1031        QXmlStreamReader stream(&input);
     1032        /* Read XML stream: */
     1033        while (!stream.atEnd())
     1034        {
     1035            /* Read subsequent token: */
     1036            const QXmlStreamReader::TokenType tokenType = stream.readNext();
     1037            /* Skip non-interesting tokens: */
     1038            if (tokenType != QXmlStreamReader::StartElement)
     1039                continue;
     1040
     1041            /* Get the name of the current element: */
     1042            const QStringRef strElementName = stream.name();
     1043
     1044            /* Search for the scope ID: */
     1045            QString strLoadingID;
     1046            if (strElementName == "Global")
     1047                strLoadingID = UIExtraDataManager::GlobalID;
     1048            else if (strElementName == "Machine")
     1049            {
     1050                const QXmlStreamAttributes attributes = stream.attributes();
     1051                if (attributes.hasAttribute("uuid"))
     1052                {
     1053                    const QString strUuid = attributes.value("uuid").toString();
     1054                    const QUuid uuid = strUuid;
     1055                    if (!uuid.isNull())
     1056                        strLoadingID = uuid.toString().remove(QRegExp("[{}]"));
     1057                    else
     1058                        msgCenter().alert(this, MessageType_Warning,
     1059                                          QString("<p>Invalid extra-data ID:</p>"
     1060                                                  "<p>%1</p>").arg(strUuid));
     1061                }
     1062            }
     1063            /* Look particular extra-data entries: */
     1064            else if (strElementName == "ExtraDataItem")
     1065            {
     1066                const QXmlStreamAttributes attributes = stream.attributes();
     1067                if (attributes.hasAttribute("name") && attributes.hasAttribute("value"))
     1068                {
     1069                    const QString strName = attributes.value("name").toString();
     1070                    const QString strValue = attributes.value("value").toString();
     1071                    gEDataManager->setExtraDataString(strName, strValue, currentChooserID());
     1072                }
     1073            }
     1074
     1075            /* Check extra-data ID: */
     1076            if (!strLoadingID.isNull() && strLoadingID != currentChooserID() &&
     1077                !msgCenter().questionBinary(this, MessageType_Question,
     1078                                            QString("<p>Inconsistent extra-data ID:</p>"
     1079                                                    "<p>Current: {%1}</p>"
     1080                                                    "<p>Loading: {%2}</p>"
     1081                                                    "<p>Continue with loading?</p>")
     1082                                                    .arg(currentChooserID(), strLoadingID)))
     1083                break;
     1084        }
     1085        /* Handle XML stream error: */
     1086        if (stream.hasError())
     1087            msgCenter().alert(this, MessageType_Warning,
     1088                              QString("<p>Error reading XML file:</p>"
     1089                                      "<p>%1</p>").arg(stream.error()));
     1090        /* Close file: */
     1091        input.close();
     1092    }
     1093}
     1094
     1095void UIExtraDataManagerWindow::prepare()
     1096{
     1097    /* Prepare this: */
     1098    prepareThis();
     1099    /* Prepare connections: */
     1100    prepareConnections();
     1101    /* Prepare menu: */
     1102    prepareMenu();
     1103    /* Prepare central-widget: */
     1104    prepareCentralWidget();
     1105    /* Load settings: */
     1106    loadSettings();
     1107}
     1108
     1109void UIExtraDataManagerWindow::prepareThis()
     1110{
     1111#ifndef Q_WS_MAC
     1112    /* Apply window icons: */
     1113    setWindowIcon(UIIconPool::iconSetFull(":/edataman_32px.png",
     1114                                          ":/edataman_16px.png"));
     1115#endif /* !Q_WS_MAC */
     1116
     1117    /* Apply window title: */
     1118    setWindowTitle("Extra-data Manager");
     1119
     1120    /* Do not count that window as important for application,
     1121     * it will NOT be taken into account when other top-level windows will be closed: */
     1122    setAttribute(Qt::WA_QuitOnClose, false);
     1123
     1124    /* Delete window when closed: */
     1125    setAttribute(Qt::WA_DeleteOnClose);
     1126}
     1127
     1128void UIExtraDataManagerWindow::prepareConnections()
     1129{
     1130    /* Prepare connections: */
     1131    connect(gVBoxEvents, SIGNAL(sigMachineRegistered(QString, bool)),
     1132            this, SLOT(sltMachineRegistered(QString, bool)));
     1133}
     1134
     1135void UIExtraDataManagerWindow::prepareMenu()
     1136{
     1137    /* Create 'Actions' menu: */
     1138    QMenu *pActionsMenu = menuBar()->addMenu("Actions");
     1139    AssertReturnVoid(pActionsMenu);
     1140    {
     1141        /* Create 'Add' action: */
     1142        m_pActionAdd = pActionsMenu->addAction("Add");
     1143        AssertReturnVoid(m_pActionAdd);
     1144        {
     1145            /* Configure 'Add' action: */
     1146            m_pActionAdd->setIcon(UIIconPool::iconSetFull(":/edata_add_22px.png", ":/edata_add_16px.png",
     1147                                                          ":/edata_add_disabled_22px.png", ":/edata_add_disabled_16px.png"));
     1148            m_pActionAdd->setShortcut(Qt::Key_Insert);
     1149            connect(m_pActionAdd, SIGNAL(triggered(bool)), this, SLOT(sltAdd()));
     1150        }
     1151        /* Create 'Del' action: */
     1152        m_pActionDel = pActionsMenu->addAction("Remove");
     1153        AssertReturnVoid(m_pActionDel);
     1154        {
     1155            /* Configure 'Del' action: */
     1156            m_pActionDel->setIcon(UIIconPool::iconSetFull(":/edata_remove_22px.png", ":/edata_remove_16px.png",
     1157                                                          ":/edata_remove_disabled_22px.png", ":/edata_remove_disabled_16px.png"));
     1158            m_pActionDel->setShortcut(Qt::Key_Delete);
     1159            connect(m_pActionDel, SIGNAL(triggered(bool)), this, SLOT(sltDel()));
     1160        }
     1161
     1162        /* Add separator: */
     1163        pActionsMenu->addSeparator();
     1164
     1165        /* Create 'Load' action: */
     1166        m_pActionLoad = pActionsMenu->addAction("Load");
     1167        AssertReturnVoid(m_pActionLoad);
     1168        {
     1169            /* Configure 'Load' action: */
     1170            m_pActionLoad->setIcon(UIIconPool::iconSetFull(":/edata_load_22px.png", ":/edata_load_16px.png",
     1171                                                           ":/edata_load_disabled_22px.png", ":/edata_load_disabled_16px.png"));
     1172            m_pActionLoad->setShortcut(QKeySequence("Ctrl+L"));
     1173            connect(m_pActionLoad, SIGNAL(triggered(bool)), this, SLOT(sltLoad()));
     1174        }
     1175        /* Create 'Save' action: */
     1176        m_pActionSave = pActionsMenu->addAction("Save");
     1177        AssertReturnVoid(m_pActionSave);
     1178        {
     1179            /* Configure 'Save' action: */
     1180            m_pActionSave->setIcon(UIIconPool::iconSetFull(":/edata_save_22px.png", ":/edata_save_16px.png",
     1181                                                           ":/edata_save_disabled_22px.png", ":/edata_save_disabled_16px.png"));
     1182            m_pActionSave->setShortcut(QKeySequence("Ctrl+S"));
     1183            connect(m_pActionSave, SIGNAL(triggered(bool)), this, SLOT(sltSave()));
     1184        }
     1185    }
     1186}
     1187
     1188void UIExtraDataManagerWindow::prepareCentralWidget()
     1189{
     1190    /* Prepare central-widget: */
     1191    setCentralWidget(new QWidget);
     1192    AssertPtrReturnVoid(centralWidget());
     1193    {
     1194        /* Prepare layout: */
     1195        m_pMainLayout = new QVBoxLayout(centralWidget());
     1196        AssertReturnVoid(m_pMainLayout && centralWidget()->layout() &&
     1197                         m_pMainLayout == centralWidget()->layout());
     1198        {
     1199#if MAC_LEOPARD_STYLE
     1200            /* No spacing/margins on the Mac: */
     1201            m_pMainLayout->setContentsMargins(0, 0, 0, 0);
     1202            m_pMainLayout->insertSpacing(0, 10);
     1203#else /* !MAC_LEOPARD_STYLE */
     1204            /* Set spacing/margin like in the selector window: */
     1205            m_pMainLayout->setSpacing(5);
     1206            m_pMainLayout->setContentsMargins(5, 5, 5, 5);
     1207#endif /* !MAC_LEOPARD_STYLE */
     1208            /* Prepare tool-bar: */
     1209            prepareToolBar();
     1210            /* Prepare splitter: */
     1211            prepareSplitter();
     1212            /* Prepare button-box: */
     1213            prepareButtonBox();
     1214        }
     1215        /* Initial focus: */
     1216        m_pViewOfChooser->setFocus();
     1217    }
     1218}
     1219
     1220void UIExtraDataManagerWindow::prepareToolBar()
     1221{
     1222    /* Create tool-bar: */
     1223    m_pToolBar = new UIToolBar;
     1224    AssertPtrReturnVoid(m_pToolBar);
     1225    {
     1226        /* Configure tool-bar: */
     1227        m_pToolBar->setIconSize(QSize(22, 22));
     1228        m_pToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
     1229        /* Add actions: */
     1230        m_pToolBar->addAction(m_pActionAdd);
     1231        m_pToolBar->addAction(m_pActionDel);
     1232        m_pToolBar->addSeparator();
     1233        m_pToolBar->addAction(m_pActionLoad);
     1234        m_pToolBar->addAction(m_pActionSave);
     1235        /* Integrate tool-bar into dialog: */
     1236#if MAC_LEOPARD_STYLE
     1237        /* Enable unified tool-bars on Mac OS X. Available on Qt >= 4.3: */
     1238        addToolBar(m_pToolBar);
     1239        m_pToolBar->setMacToolbar();
     1240#else /* !MAC_LEOPARD_STYLE */
     1241        /* Add tool-bar into main-layout: */
     1242        m_pMainLayout->addWidget(m_pToolBar);
     1243#endif /* !MAC_LEOPARD_STYLE */
     1244    }
     1245}
     1246
     1247void UIExtraDataManagerWindow::prepareSplitter()
     1248{
     1249    /* Create splitter: */
     1250    m_pSplitter = new QISplitter;
     1251    AssertPtrReturnVoid(m_pSplitter);
     1252    {
     1253        /* Prepare panes: */
     1254        preparePanes();
     1255        /* Configure splitter: */
     1256        m_pSplitter->setChildrenCollapsible(false);
     1257        m_pSplitter->setStretchFactor(0, 0);
     1258        m_pSplitter->setStretchFactor(1, 1);
     1259        /* Add splitter into main layout: */
     1260        m_pMainLayout->addWidget(m_pSplitter);
     1261    }
     1262}
     1263
     1264void UIExtraDataManagerWindow::preparePanes()
     1265{
     1266    /* Prepare chooser-pane: */
     1267    preparePaneChooser();
     1268    /* Prepare data-pane: */
     1269    preparePaneData();
     1270    /* Link chooser and data panes: */
     1271    connect(m_pViewOfChooser->selectionModel(),
     1272            SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
     1273            this, SLOT(sltChooserHandleCurrentChanged(const QModelIndex&)));
     1274    connect(m_pViewOfChooser->selectionModel(),
     1275            SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
     1276            this, SLOT(sltChooserHandleSelectionChanged(const QItemSelection&, const QItemSelection&)));
     1277    connect(m_pViewOfData->selectionModel(),
     1278            SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
     1279            this, SLOT(sltDataHandleSelectionChanged(const QItemSelection&, const QItemSelection&)));
     1280    connect(m_pModelSourceOfData, SIGNAL(itemChanged(QStandardItem*)),
     1281            this, SLOT(sltDataHandleItemChanged(QStandardItem*)));
     1282    /* Make sure chooser have current-index if possible: */
     1283    makeSureChooserHaveCurrentIndexIfPossible();
     1284}
     1285
     1286void UIExtraDataManagerWindow::preparePaneChooser()
     1287{
     1288    /* Create chooser-pane: */
     1289    m_pPaneOfChooser = new QWidget;
     1290    AssertPtrReturnVoid(m_pPaneOfChooser);
     1291    {
     1292        /* Create layout: */
     1293        QVBoxLayout *pLayout = new QVBoxLayout(m_pPaneOfChooser);
     1294        AssertReturnVoid(pLayout && m_pPaneOfChooser->layout() &&
     1295                         pLayout == m_pPaneOfChooser->layout());
     1296        {
     1297            /* Configure layout: */
     1298            pLayout->setContentsMargins(0, 0, 3, 0);
     1299            /* Create chooser-filter: */
     1300            m_pFilterOfChooser = new QLineEdit;
     1301            {
     1302                /* Configure chooser-filter: */
     1303                m_pFilterOfChooser->setPlaceholderText("Search..");
     1304                connect(m_pFilterOfChooser, SIGNAL(textChanged(const QString&)),
     1305                        this, SLOT(sltChooserApplyFilter(const QString&)));
     1306                /* Add chooser-filter into layout: */
     1307                pLayout->addWidget(m_pFilterOfChooser);
     1308            }
     1309            /* Create chooser-view: */
     1310            m_pViewOfChooser = new QListView;
     1311            AssertPtrReturnVoid(m_pViewOfChooser);
     1312            {
     1313                /* Configure chooser-view: */
     1314                delete m_pViewOfChooser->itemDelegate();
     1315                m_pViewOfChooser->setItemDelegate(new UIChooserPaneDelegate(m_pViewOfChooser));
     1316                m_pViewOfChooser->setSelectionMode(QAbstractItemView::SingleSelection);
     1317                /* Create source-model: */
     1318                m_pModelSourceOfChooser = new QStandardItemModel(m_pViewOfChooser);
     1319                AssertPtrReturnVoid(m_pModelSourceOfChooser);
     1320                {
     1321                    /* Create proxy-model: */
     1322                    m_pModelProxyOfChooser = new UIChooserPaneSortingModel(m_pViewOfChooser);
     1323                    AssertPtrReturnVoid(m_pModelProxyOfChooser);
     1324                    {
     1325                        /* Configure proxy-model: */
     1326                        m_pModelProxyOfChooser->setSortRole(Field_Name);
     1327                        m_pModelProxyOfChooser->setFilterRole(Field_Name);
     1328                        m_pModelProxyOfChooser->setSortCaseSensitivity(Qt::CaseInsensitive);
     1329                        m_pModelProxyOfChooser->setFilterCaseSensitivity(Qt::CaseInsensitive);
     1330                        m_pModelProxyOfChooser->setSourceModel(m_pModelSourceOfChooser);
     1331                        m_pViewOfChooser->setModel(m_pModelProxyOfChooser);
     1332                    }
     1333                    /* Add global chooser item into source-model: */
     1334                    addChooserItemByID(UIExtraDataManager::GlobalID);
     1335                    /* Add machine chooser items into source-model: */
     1336                    CMachineVector machines = vboxGlobal().virtualBox().GetMachines();
     1337                    foreach (const CMachine &machine, machines)
     1338                        addChooserItemByMachine(machine);
     1339                    /* And sort proxy-model: */
     1340                    m_pModelProxyOfChooser->sort(0, Qt::AscendingOrder);
     1341                }
     1342                /* Add chooser-view into layout: */
     1343                pLayout->addWidget(m_pViewOfChooser);
     1344            }
     1345        }
     1346        /* Add chooser-pane into splitter: */
     1347        m_pSplitter->addWidget(m_pPaneOfChooser);
     1348    }
     1349}
     1350
     1351void UIExtraDataManagerWindow::preparePaneData()
     1352{
     1353    /* Create data-pane: */
     1354    m_pPaneOfData = new QWidget;
     1355    AssertPtrReturnVoid(m_pPaneOfData);
     1356    {
     1357        /* Create layout: */
     1358        QVBoxLayout *pLayout = new QVBoxLayout(m_pPaneOfData);
     1359        AssertReturnVoid(pLayout && m_pPaneOfData->layout() &&
     1360                         pLayout == m_pPaneOfData->layout());
     1361        {
     1362            /* Configure layout: */
     1363            pLayout->setContentsMargins(3, 0, 0, 0);
     1364            /* Create data-filter: */
     1365            m_pFilterOfData = new QLineEdit;
     1366            {
     1367                /* Configure data-filter: */
     1368                m_pFilterOfData->setPlaceholderText("Search..");
     1369                connect(m_pFilterOfData, SIGNAL(textChanged(const QString&)),
     1370                        this, SLOT(sltDataApplyFilter(const QString&)));
     1371                /* Add data-filter into layout: */
     1372                pLayout->addWidget(m_pFilterOfData);
     1373            }
     1374            /* Create data-view: */
     1375            m_pViewOfData = new QTableView;
     1376            AssertPtrReturnVoid(m_pViewOfData);
     1377            {
     1378                /* Create item-model: */
     1379                m_pModelSourceOfData = new QStandardItemModel(0, 2, m_pViewOfData);
     1380                AssertPtrReturnVoid(m_pModelSourceOfData);
     1381                {
     1382                    /* Create proxy-model: */
     1383                    m_pModelProxyOfData = new QSortFilterProxyModel(m_pViewOfChooser);
     1384                    AssertPtrReturnVoid(m_pModelProxyOfData);
     1385                    {
     1386                        /* Configure proxy-model: */
     1387                        m_pModelProxyOfData->setSortCaseSensitivity(Qt::CaseInsensitive);
     1388                        m_pModelProxyOfData->setFilterCaseSensitivity(Qt::CaseInsensitive);
     1389                        m_pModelProxyOfData->setSourceModel(m_pModelSourceOfData);
     1390                        m_pViewOfData->setModel(m_pModelProxyOfData);
     1391                    }
     1392                    /* Configure item-model: */
     1393                    m_pModelSourceOfData->setHorizontalHeaderLabels(QStringList() << "Key" << "Value");
     1394                }
     1395                /* Configure data-view: */
     1396                m_pViewOfData->setSortingEnabled(true);
     1397                m_pViewOfData->setAlternatingRowColors(true);
     1398                m_pViewOfData->setContextMenuPolicy(Qt::CustomContextMenu);
     1399                m_pViewOfData->setSelectionMode(QAbstractItemView::ExtendedSelection);
     1400                m_pViewOfData->setSelectionBehavior(QAbstractItemView::SelectRows);
     1401                connect(m_pViewOfData, SIGNAL(customContextMenuRequested(const QPoint&)),
     1402                        this, SLOT(sltDataHandleCustomContextMenuRequested(const QPoint&)));
     1403                QHeaderView *pVHeader = m_pViewOfData->verticalHeader();
     1404                QHeaderView *pHHeader = m_pViewOfData->horizontalHeader();
     1405                pVHeader->hide();
     1406                pHHeader->setSortIndicator(0, Qt::AscendingOrder);
     1407                pHHeader->resizeSection(0, qMin(300, pHHeader->width() / 3));
     1408                pHHeader->setStretchLastSection(true);
     1409                /* Add data-view into layout: */
     1410                pLayout->addWidget(m_pViewOfData);
     1411            }
     1412        }
     1413        /* Add data-pane into splitter: */
     1414        m_pSplitter->addWidget(m_pPaneOfData);
     1415    }
     1416}
     1417
     1418void UIExtraDataManagerWindow::prepareButtonBox()
     1419{
     1420    /* Create button-box: */
     1421    m_pButtonBox = new QIDialogButtonBox;
     1422    AssertPtrReturnVoid(m_pButtonBox);
     1423    {
     1424        /* Configure button-box: */
     1425        m_pButtonBox->setStandardButtons(QDialogButtonBox::Help | QDialogButtonBox::Close);
     1426        m_pButtonBox->button(QDialogButtonBox::Close)->setShortcut(Qt::Key_Escape);
     1427        connect(m_pButtonBox, SIGNAL(helpRequested()), &msgCenter(), SLOT(sltShowHelpHelpDialog()));
     1428        connect(m_pButtonBox, SIGNAL(rejected()), this, SLOT(close()));
     1429        /* Add button-box into main layout: */
     1430        m_pMainLayout->addWidget(m_pButtonBox);
     1431    }
     1432}
     1433
     1434void UIExtraDataManagerWindow::loadSettings()
     1435{
     1436    /* Load window geometry: */
     1437    {
     1438        /* Load geometry: */
     1439        m_geometry = gEDataManager->extraDataManagerGeometry(this);
     1440#ifdef Q_WS_MAC
     1441        move(m_geometry.topLeft());
     1442        resize(m_geometry.size());
     1443#else /* Q_WS_MAC */
     1444        setGeometry(m_geometry);
     1445#endif /* !Q_WS_MAC */
     1446        LogRel(("UIExtraDataManagerWindow: Geometry loaded to: %dx%d @ %dx%d.\n",
     1447                m_geometry.x(), m_geometry.y(), m_geometry.width(), m_geometry.height()));
     1448
     1449        /* Maximize (if necessary): */
     1450        if (gEDataManager->extraDataManagerShouldBeMaximized())
     1451            showMaximized();
     1452    }
     1453
     1454    /* Load splitter hints: */
     1455    {
     1456        m_pSplitter->setSizes(gEDataManager->extraDataManagerSplitterHints(this));
     1457    }
     1458}
     1459
     1460void UIExtraDataManagerWindow::saveSettings()
     1461{
     1462    /* Save splitter hints: */
     1463    {
     1464        gEDataManager->setExtraDataManagerSplitterHints(m_pSplitter->sizes());
     1465    }
     1466
     1467    /* Save window geometry: */
     1468    {
     1469        /* Save geometry: */
     1470#ifdef Q_WS_MAC
     1471        gEDataManager->setExtraDataManagerGeometry(m_geometry, ::darwinIsWindowMaximized(this));
     1472#else /* Q_WS_MAC */
     1473        gEDataManager->setExtraDataManagerGeometry(m_geometry, isMaximized());
     1474#endif /* !Q_WS_MAC */
     1475        LogRel(("UIExtraDataManagerWindow: Geometry saved as: %dx%d @ %dx%d.\n",
     1476                m_geometry.x(), m_geometry.y(), m_geometry.width(), m_geometry.height()));
     1477    }
     1478}
     1479
     1480void UIExtraDataManagerWindow::cleanup()
     1481{
     1482    /* Save settings: */
     1483    saveSettings();
     1484}
     1485
     1486bool UIExtraDataManagerWindow::event(QEvent *pEvent)
     1487{
     1488    /* Pre-process through base-class: */
     1489    bool fResult = QMainWindow::event(pEvent);
     1490
     1491    /* Process required events: */
     1492    switch (pEvent->type())
     1493    {
     1494        /* Handle every Resize and Move we keep track of the geometry. */
     1495        case QEvent::Resize:
     1496        {
     1497            if (isVisible() && (windowState() & (Qt::WindowMaximized | Qt::WindowMinimized | Qt::WindowFullScreen)) == 0)
     1498            {
     1499                QResizeEvent *pResizeEvent = static_cast<QResizeEvent*>(pEvent);
     1500                m_geometry.setSize(pResizeEvent->size());
     1501            }
     1502            break;
     1503        }
     1504        case QEvent::Move:
     1505        {
     1506            if (isVisible() && (windowState() & (Qt::WindowMaximized | Qt::WindowMinimized | Qt::WindowFullScreen)) == 0)
     1507            {
     1508#ifdef Q_WS_MAC
     1509                QMoveEvent *pMoveEvent = static_cast<QMoveEvent*>(pEvent);
     1510                m_geometry.moveTo(pMoveEvent->pos());
     1511#else /* !Q_WS_MAC */
     1512                m_geometry.moveTo(geometry().x(), geometry().y());
     1513#endif /* !Q_WS_MAC */
     1514            }
     1515            break;
     1516        }
     1517        default:
     1518            break;
     1519    }
     1520
     1521    /* Return result: */
     1522    return fResult;
     1523}
     1524
     1525void UIExtraDataManagerWindow::updateActionsAvailability()
     1526{
     1527    /* Is there something selected in chooser-view? */
     1528    bool fChooserHasSelection = !m_pViewOfChooser->selectionModel()->selection().isEmpty();
     1529    /* Is there something selected in data-view? */
     1530    bool fDataHasSelection = !m_pViewOfData->selectionModel()->selection().isEmpty();
     1531
     1532    /* Enable/disable corresponding actions: */
     1533    m_pActionAdd->setEnabled(fChooserHasSelection);
     1534    m_pActionDel->setEnabled(fChooserHasSelection && fDataHasSelection);
     1535    m_pActionLoad->setEnabled(fChooserHasSelection);
     1536    m_pActionSave->setEnabled(fChooserHasSelection);
     1537}
     1538
     1539QModelIndex UIExtraDataManagerWindow::chooserIndex(int iRow) const
     1540{
     1541    return m_pModelSourceOfChooser->index(iRow, 0);
     1542}
     1543
     1544QModelIndex UIExtraDataManagerWindow::currentChooserIndex() const
     1545{
     1546    return m_pViewOfChooser->currentIndex();
     1547}
     1548
     1549QString UIExtraDataManagerWindow::chooserID(int iRow) const
     1550{
     1551    return chooserIndex(iRow).data(Field_ID).toString();
     1552}
     1553
     1554QString UIExtraDataManagerWindow::currentChooserID() const
     1555{
     1556    return currentChooserIndex().data(Field_ID).toString();
     1557}
     1558
     1559QString UIExtraDataManagerWindow::chooserName(int iRow) const
     1560{
     1561    return chooserIndex(iRow).data(Field_Name).toString();
     1562}
     1563
     1564QString UIExtraDataManagerWindow::currentChooserName() const
     1565{
     1566    return currentChooserIndex().data(Field_Name).toString();
     1567}
     1568
     1569void UIExtraDataManagerWindow::addChooserItem(const QString &strID,
     1570                                              const QString &strName,
     1571                                              const QString &strOsTypeID,
     1572                                              const int iPosition /* = -1 */)
     1573{
     1574    /* Create item: */
     1575    QStandardItem *pItem = new QStandardItem;
     1576    AssertPtrReturnVoid(pItem);
     1577    {
     1578        /* Which is NOT editable: */
     1579        pItem->setEditable(false);
     1580        /* Contains passed ID: */
     1581        pItem->setData(strID, Field_ID);
     1582        /* Contains passed name: */
     1583        pItem->setData(strName, Field_Name);
     1584        /* Contains passed OS Type ID: */
     1585        pItem->setData(strOsTypeID, Field_OsTypeID);
     1586        /* And designated as known/unknown depending on extra-data manager status: */
     1587        pItem->setData(gEDataManager->contains(strID), Field_Known);
     1588        /* If insert position defined: */
     1589        if (iPosition != -1)
     1590        {
     1591            /* Insert this item at specified position: */
     1592            m_pModelSourceOfChooser->insertRow(iPosition, pItem);
     1593        }
     1594        /* If insert position undefined: */
     1595        else
     1596        {
     1597            /* Add this item as the last one: */
     1598            m_pModelSourceOfChooser->appendRow(pItem);
     1599        }
     1600    }
     1601}
     1602
     1603void UIExtraDataManagerWindow::addChooserItemByMachine(const CMachine &machine,
     1604                                                       const int iPosition /* = -1 */)
     1605{
     1606    /* Call to wrapper above: */
     1607    addChooserItem(machine.GetId(), machine.GetName(), machine.GetOSTypeId(), iPosition);
     1608}
     1609
     1610void UIExtraDataManagerWindow::addChooserItemByID(const QString &strID,
     1611                                                  const int iPosition /* = -1 */)
     1612{
     1613    /* Prepare arguments: */
     1614    QString strName;
     1615    QString strOsTypeID;
     1616    /* Global ID? */
     1617    if (strID == UIExtraDataManager::GlobalID)
     1618        strName = "Global";
     1619    /* Machine ID? */
     1620    else
     1621    {
     1622        /* Search for the corresponding machine by ID: */
     1623        CVirtualBox vbox = vboxGlobal().virtualBox();
     1624        const CMachine machine = vbox.FindMachine(strID);
     1625        /* Acquire actual arguments if possible: */
     1626        if (vbox.isOk() && !machine.isNull())
     1627        {
     1628            strName = machine.GetName();
     1629            strOsTypeID = machine.GetOSTypeId();
     1630        }
     1631        /* Or use default: */
     1632        else
     1633        {
     1634            strName = "Unknown VM";
     1635            strOsTypeID = "Other";
     1636        }
     1637    }
     1638    /* Call to wrapper above: */
     1639    addChooserItem(strID, strName, strOsTypeID, iPosition);
     1640}
     1641
     1642void UIExtraDataManagerWindow::makeSureChooserHaveCurrentIndexIfPossible()
     1643{
     1644    /* Make sure chooser have current-index if possible: */
     1645    if (!m_pViewOfChooser->currentIndex().isValid())
     1646    {
     1647        /* Do we still have anything to select? */
     1648        const QModelIndex firstIndex = m_pModelProxyOfChooser->index(0, 0);
     1649        if (firstIndex.isValid())
     1650            m_pViewOfChooser->setCurrentIndex(firstIndex);
     1651    }
     1652}
     1653
     1654QModelIndex UIExtraDataManagerWindow::dataIndex(int iRow, int iColumn) const
     1655{
     1656    return m_pModelSourceOfData->index(iRow, iColumn);
     1657}
     1658
     1659QModelIndex UIExtraDataManagerWindow::dataKeyIndex(int iRow) const
     1660{
     1661    return dataIndex(iRow, 0);
     1662}
     1663
     1664QModelIndex UIExtraDataManagerWindow::dataValueIndex(int iRow) const
     1665{
     1666    return dataIndex(iRow, 1);
     1667}
     1668
     1669QString UIExtraDataManagerWindow::dataKey(int iRow) const
     1670{
     1671    return dataKeyIndex(iRow).data().toString();
     1672}
     1673
     1674QString UIExtraDataManagerWindow::dataValue(int iRow) const
     1675{
     1676    return dataValueIndex(iRow).data().toString();
     1677}
     1678
     1679void UIExtraDataManagerWindow::addDataItem(const QString &strKey,
     1680                                           const QString &strValue,
     1681                                           const int iPosition /* = -1 */)
     1682{
     1683    /* Prepare items: */
     1684    QList<QStandardItem*> items;
     1685    /* Create key item: */
     1686    items << new QStandardItem(strKey);
     1687    items.last()->setEditable(false);
     1688    AssertPtrReturnVoid(items.last());
     1689    /* Create value item: */
     1690    items << new QStandardItem(strValue);
     1691    AssertPtrReturnVoid(items.last());
     1692    /* If insert position defined: */
     1693    if (iPosition != -1)
     1694    {
     1695        /* Insert these items as the row at the required position: */
     1696        m_pModelSourceOfData->insertRow(iPosition, items);
     1697    }
     1698    /* If insert position undefined: */
     1699    else
     1700    {
     1701        /* Add these items as the last one row: */
     1702        m_pModelSourceOfData->appendRow(items);
     1703    }
     1704}
     1705
     1706void UIExtraDataManagerWindow::sortData()
     1707{
     1708    /* Sort using current rules: */
     1709    const QHeaderView *pHHeader = m_pViewOfData->horizontalHeader();
     1710    const int iSortSection = pHHeader->sortIndicatorSection();
     1711    const Qt::SortOrder sortOrder = pHHeader->sortIndicatorOrder();
     1712    m_pModelProxyOfData->sort(iSortSection, sortOrder);
     1713}
     1714#endif /* DEBUG */
     1715
     1716
    1191717/* static */
    1201718UIExtraDataManager *UIExtraDataManager::m_spInstance = 0;
     
    1441742    }
    1451743}
     1744
     1745#ifdef DEBUG
     1746/* static */
     1747void UIExtraDataManager::openWindow(QWidget *pCenterWidget)
     1748{
     1749    /* Pass to instance: */
     1750    instance()->open(pCenterWidget);
     1751}
     1752#endif /* DEBUG */
    1461753
    1471754QString UIExtraDataManager::extraDataString(const QString &strKey, const QString &strID /* = GlobalID */)
     
    12542861}
    12552862#endif /* VBOX_WITH_DEBUGGER_GUI */
     2863
     2864#ifdef DEBUG
     2865QRect UIExtraDataManager::extraDataManagerGeometry(QWidget *pWidget)
     2866{
     2867    /* Get corresponding extra-data: */
     2868    const QStringList data = extraDataStringList(GUI_ExtraDataManager_Geometry);
     2869
     2870    /* Parse loaded data: */
     2871    int iX = 0, iY = 0, iW = 0, iH = 0;
     2872    bool fOk = data.size() >= 4;
     2873    do
     2874    {
     2875        if (!fOk) break;
     2876        iX = data[0].toInt(&fOk);
     2877        if (!fOk) break;
     2878        iY = data[1].toInt(&fOk);
     2879        if (!fOk) break;
     2880        iW = data[2].toInt(&fOk);
     2881        if (!fOk) break;
     2882        iH = data[3].toInt(&fOk);
     2883    }
     2884    while (0);
     2885
     2886    /* Use geometry (loaded or default): */
     2887    QRect geometry = fOk ? QRect(iX, iY, iW, iH) : QRect(0, 0, 800, 600);
     2888
     2889    /* Take hint-widget into account: */
     2890    if (pWidget)
     2891        geometry.setSize(geometry.size().expandedTo(pWidget->minimumSizeHint()));
     2892
     2893    /* Get screen-geometry [of screen with point (iX, iY) if possible]: */
     2894    const QRect screenGeometry = fOk ? QApplication::desktop()->availableGeometry(QPoint(iX, iY)) :
     2895                                       QApplication::desktop()->availableGeometry();
     2896
     2897    /* Make sure resulting geometry is within current bounds: */
     2898    geometry = geometry.intersected(screenGeometry);
     2899
     2900    /* Move default-geometry to current screen center: */
     2901    if (!fOk)
     2902        geometry.moveCenter(screenGeometry.center());
     2903
     2904    /* Return result: */
     2905    return geometry;
     2906}
     2907
     2908bool UIExtraDataManager::extraDataManagerShouldBeMaximized()
     2909{
     2910    /* Get corresponding extra-data: */
     2911    const QStringList data = extraDataStringList(GUI_ExtraDataManager_Geometry);
     2912
     2913    /* Make sure 5th item has required value: */
     2914    return data.size() == 5 && data[4] == GUI_Geometry_State_Max;
     2915}
     2916
     2917void UIExtraDataManager::setExtraDataManagerGeometry(const QRect &geometry, bool fMaximized)
     2918{
     2919    /* Serialize passed values: */
     2920    QStringList data;
     2921    data << QString::number(geometry.x());
     2922    data << QString::number(geometry.y());
     2923    data << QString::number(geometry.width());
     2924    data << QString::number(geometry.height());
     2925    if (fMaximized)
     2926        data << GUI_Geometry_State_Max;
     2927
     2928    /* Re-cache corresponding extra-data: */
     2929    setExtraDataStringList(GUI_ExtraDataManager_Geometry, data);
     2930}
     2931
     2932QList<int> UIExtraDataManager::extraDataManagerSplitterHints(QWidget *pWidget)
     2933{
     2934    /* Get corresponding extra-data: */
     2935    const QStringList data = extraDataStringList(GUI_ExtraDataManager_SplitterHints);
     2936
     2937    /* Parse loaded data: */
     2938    int iLeft = 0, iRight = 0;
     2939    bool fOk = data.size() == 2;
     2940    do
     2941    {
     2942        if (!fOk) break;
     2943        iLeft = data[0].toInt(&fOk);
     2944        if (!fOk) break;
     2945        iRight = data[1].toInt(&fOk);
     2946    }
     2947    while (0);
     2948
     2949    /* Prepare hints (loaded or adviced): */
     2950    QList<int> hints;
     2951    if (fOk)
     2952    {
     2953        hints << iLeft;
     2954        hints << iRight;
     2955    }
     2956    else
     2957    {
     2958        hints << pWidget->width() * .9 * (1.0 / 3);
     2959        hints << pWidget->width() * .9 * (2.0 / 3);
     2960    }
     2961
     2962    /* Return hints: */
     2963    return hints;
     2964}
     2965
     2966void UIExtraDataManager::setExtraDataManagerSplitterHints(const QList<int> &hints)
     2967{
     2968    /* Parse passed hints: */
     2969    QStringList data;
     2970    data << (hints.size() > 0 ? QString::number(hints[0]) : QString());
     2971    data << (hints.size() > 1 ? QString::number(hints[1]) : QString());
     2972
     2973    /* Re-cache corresponding extra-data: */
     2974    setExtraDataStringList(GUI_ExtraDataManager_SplitterHints, data);
     2975}
     2976#endif /* DEBUG */
    12562977
    12572978void UIExtraDataManager::sltExtraDataChange(QString strMachineID, QString strKey, QString strValue)
     
    13693090}
    13703091
     3092#ifdef DEBUG
     3093void UIExtraDataManager::cleanupWindow()
     3094{
     3095    delete m_pWindow;
     3096}
     3097#endif /* DEBUG */
     3098
    13713099void UIExtraDataManager::cleanupMainEventListener()
    13723100{
     
    13783106void UIExtraDataManager::cleanup()
    13793107{
     3108#ifdef DEBUG
     3109    /* Cleanup window: */
     3110    cleanupWindow();
     3111#endif /* DEBUG */
    13803112    /* Cleanup Main event-listener: */
    13813113    cleanupMainEventListener();
    13823114}
     3115
     3116#ifdef DEBUG
     3117void UIExtraDataManager::open(QWidget *pCenterWidget)
     3118{
     3119    /* If necessary: */
     3120    if (!m_pWindow)
     3121    {
     3122        /* Create window: */
     3123        m_pWindow = new UIExtraDataManagerWindow;
     3124        /* Configure window connections: */
     3125        connect(this, SIGNAL(sigExtraDataChange(QString, QString, QString)),
     3126                m_pWindow, SLOT(sltExtraDataChange(QString, QString, QString)));
     3127    }
     3128    /* Show and raise window: */
     3129    m_pWindow->showAndRaise(pCenterWidget);
     3130}
     3131#endif /* DEBUG */
    13833132
    13843133void UIExtraDataManager::hotloadMachineExtraDataMap(const QString &strID)
  • trunk/src/VBox/Frontends/VirtualBox/src/extradata/UIExtraDataManager.h

    r51930 r51931  
    2121#include <QObject>
    2222#include <QMap>
     23#ifdef DEBUG
     24# include <QPointer>
     25#endif /* DEBUG */
    2326
    2427/* GUI includes: */
     
    3033/* Forward declarations: */
    3134class UIExtraDataEventHandler;
     35#ifdef DEBUG
     36class UIExtraDataManagerWindow;
     37#endif /* DEBUG */
    3238
    3339/* Type definitions: */
     
    7884    /** Static Extra-data Manager destructor. */
    7985    static void destroy();
     86
     87#ifdef DEBUG
     88    /** Static show and raise API. */
     89    static void openWindow(QWidget *pCenterWidget);
     90#endif /* DEBUG */
    8091
    8192    /** @name General
     
    406417#endif /* VBOX_WITH_DEBUGGER_GUI */
    407418
     419#ifdef DEBUG
     420    /** @name VirtualBox: Extra-data Manager window
     421      * @{ */
     422        /** Returns Extra-data Manager geometry using @a pWidget as hint. */
     423        QRect extraDataManagerGeometry(QWidget *pWidget);
     424        /** Returns whether Extra-data Manager should be maximized or not. */
     425        bool extraDataManagerShouldBeMaximized();
     426        /** Defines Extra-data Manager @a geometry and @a fMaximized state. */
     427        void setExtraDataManagerGeometry(const QRect &geometry, bool fMaximized);
     428
     429        /** Returns Extra-data Manager splitter hints using @a pWidget as hint. */
     430        QList<int> extraDataManagerSplitterHints(QWidget *pWidget);
     431        /** Defines Extra-data Manager splitter @a hints. */
     432        void setExtraDataManagerSplitterHints(const QList<int> &hints);
     433    /** @} */
     434#endif /* DEBUG */
     435
    408436private slots:
    409437
     
    421449    /** Prepare Main event-listener. */
    422450    void prepareMainEventListener();
    423 
     451#ifdef DEBUG
     452    // /** Prepare window. */
     453    // void prepareWindow();
     454
     455    /** Cleanup window. */
     456    void cleanupWindow();
     457#endif /* DEBUG */
    424458    /** Cleanup Main event-listener. */
    425459    void cleanupMainEventListener();
     
    431465    void cleanup();
    432466
     467#ifdef DEBUG
     468    /** Open window. */
     469    void open(QWidget *pCenterWidget);
     470#endif /* DEBUG */
     471
    433472    /** Hot-load machine extra-data map. */
    434473    void hotloadMachineExtraDataMap(const QString &strID);
     
    460499    /** Holds extra-data map instance. */
    461500    QMap<QString, ExtraDataMap> m_data;
     501
     502#ifdef DEBUG
     503    /** Holds Extra-data Manager window instance. */
     504    QPointer<UIExtraDataManagerWindow> m_pWindow;
     505#endif /* DEBUG */
    462506};
    463507
  • trunk/src/VBox/Frontends/VirtualBox/src/selector/UIActionPoolSelector.cpp

    r51668 r51931  
    144144    }
    145145};
     146
     147#ifdef DEBUG
     148class UIActionSimpleExtraDataManagerWindow : public UIActionSimple
     149{
     150    Q_OBJECT;
     151
     152public:
     153
     154    UIActionSimpleExtraDataManagerWindow(UIActionPool *pParent)
     155        : UIActionSimple(pParent, ":/edataman_16px.png")
     156    {
     157        retranslateUi();
     158    }
     159
     160protected:
     161
     162    QString shortcutExtraDataID() const
     163    {
     164        return QString("ExtraDataManager");
     165    }
     166
     167    QKeySequence defaultShortcut(UIActionPoolType) const
     168    {
     169        return QKeySequence("Ctrl+X");
     170    }
     171
     172    void retranslateUi()
     173    {
     174        setName(QApplication::translate("UIActionPool", "E&xtra Data Manager..."));
     175        setStatusTip(QApplication::translate("UIActionPool", "Display the Extra Data Manager window"));
     176    }
     177};
     178#endif /* DEBUG */
    146179
    147180class UIActionSimpleExit : public UIActionSimple
     
    9791012    m_pool[UIActionIndexSelector_Simple_File_ImportApplianceWizard] = new UIActionSimpleImportApplianceWizard(this);
    9801013    m_pool[UIActionIndexSelector_Simple_File_ExportApplianceWizard] = new UIActionSimpleExportApplianceWizard(this);
     1014#ifdef DEBUG
     1015    m_pool[UIActionIndexSelector_Simple_File_ExtraDataManagerWindow] = new UIActionSimpleExtraDataManagerWindow(this);
     1016#endif /* DEBUG */
    9811017    m_pool[UIActionIndexSelector_Simple_File_Exit] = new UIActionSimpleExit(this);
    9821018
  • trunk/src/VBox/Frontends/VirtualBox/src/selector/UIActionPoolSelector.h

    r51390 r51931  
    3131    UIActionIndexSelector_Simple_File_ImportApplianceWizard,
    3232    UIActionIndexSelector_Simple_File_ExportApplianceWizard,
     33#ifdef DEBUG
     34    UIActionIndexSelector_Simple_File_ExtraDataManagerWindow,
     35#endif /* DEBUG */
    3336    UIActionIndexSelector_Simple_File_Exit,
    3437
  • trunk/src/VBox/Frontends/VirtualBox/src/selector/UISelectorWindow.cpp

    r51679 r51931  
    310310}
    311311
     312#ifdef DEBUG
     313void UISelectorWindow::sltOpenExtraDataManagerWindow()
     314{
     315    gEDataManager->openWindow(this);
     316}
     317#endif /* DEBUG */
     318
    312319void UISelectorWindow::sltShowPreferencesDialog()
    313320{
     
    11471154    pMenu->addSeparator();
    11481155#endif /* Q_WS_MAC */
     1156#ifdef DEBUG
     1157    m_pExtraDataManagerWindowAction = gActionPool->action(UIActionIndexSelector_Simple_File_ExtraDataManagerWindow);
     1158    pMenu->addAction(m_pExtraDataManagerWindowAction);
     1159#endif /* DEBUG */
    11491160    m_pPreferencesDialogAction = gActionPool->action(UIActionIndex_Simple_Preferences);
    11501161    pMenu->addAction(m_pPreferencesDialogAction);
     
    14221433    connect(m_pImportApplianceWizardAction, SIGNAL(triggered()), this, SLOT(sltShowImportApplianceWizard()));
    14231434    connect(m_pExportApplianceWizardAction, SIGNAL(triggered()), this, SLOT(sltShowExportApplianceWizard()));
     1435#ifdef DEBUG
     1436    connect(m_pExtraDataManagerWindowAction, SIGNAL(triggered()), this, SLOT(sltOpenExtraDataManagerWindow()));
     1437#endif /* DEBUG */
    14241438    connect(m_pPreferencesDialogAction, SIGNAL(triggered()), this, SLOT(sltShowPreferencesDialog()));
    14251439    connect(m_pExitAction, SIGNAL(triggered()), this, SLOT(sltPerformExit()));
  • trunk/src/VBox/Frontends/VirtualBox/src/selector/UISelectorWindow.h

    r51665 r51931  
    7272    void sltShowImportApplianceWizard(const QString &strFileName = QString());
    7373    void sltShowExportApplianceWizard();
     74#ifdef DEBUG
     75    void sltOpenExtraDataManagerWindow();
     76#endif /* DEBUG */
    7477    void sltShowPreferencesDialog();
    7578    void sltPerformExit();
     
    182185    UIAction *m_pExportApplianceWizardAction;
    183186    UIAction *m_pPreferencesDialogAction;
     187#ifdef DEBUG
     188    UIAction *m_pExtraDataManagerWindowAction;
     189#endif /* DEBUG */
    184190    UIAction *m_pExitAction;
    185191
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