VirtualBox

Changeset 44662 in vbox


Ignore:
Timestamp:
Feb 12, 2013 4:50:22 PM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
83753
Message:

FE/Qt: 6065: Hot-key model/view architecture classes added into Global settings / Input page (not used yet).

Location:
trunk/src/VBox/Frontends/VirtualBox/src/settings/global
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsInput.cpp

    r44654 r44662  
    77
    88/*
    9  * Copyright (C) 2006-2012 Oracle Corporation
     9 * Copyright (C) 2006-2013 Oracle Corporation
    1010 *
    1111 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1818 */
    1919
    20 /* Global includes */
     20/* Qt includes: */
    2121#include <QShortcut>
    22 
    23 /* Local includes */
     22#include <QHeaderView>
     23#include <QAbstractItemDelegate>
     24#include <QStyledItemDelegate>
     25#include <QItemEditorFactory>
     26
     27/* GUI includes: */
    2428#include "UIGlobalSettingsInput.h"
     29#include "UIShortcutPool.h"
     30#include "UIHotKeyEditor.h"
     31#include "UIHostComboEditor.h"
    2532#include "VBoxGlobalSettings.h"
    2633
     
    103110}
    104111
     112
     113UIHotKeyTableModel::UIHotKeyTableModel(QObject *pParent, UIActionPoolType type)
     114    : QAbstractTableModel(pParent)
     115    , m_type(type)
     116{
     117}
     118
     119void UIHotKeyTableModel::load(const UIShortcutCache &shortcuts)
     120{
     121    /* Load shortcuts: */
     122    foreach (const UIShortcutCacheItem &item, shortcuts)
     123    {
     124        /* Filter out unnecessary shortcuts: */
     125        if ((m_type == UIActionPoolType_Selector && item.key.startsWith(GUI_Input_MachineShortcuts)) ||
     126            (m_type == UIActionPoolType_Runtime && item.key.startsWith(GUI_Input_SelectorShortcuts)))
     127            continue;
     128        /* Load shortcut cache item into model: */
     129        m_shortcuts << item;
     130    }
     131    /* Apply filter: */
     132    applyFilter();
     133    /* Notify table: */
     134    emit sigShortcutsLoaded();
     135}
     136
     137void UIHotKeyTableModel::save(UIShortcutCache &shortcuts)
     138{
     139    /* Save shortcuts: */
     140    foreach (const UIShortcutCacheItem &item, m_shortcuts)
     141    {
     142        /* Search for corresponding cache item pointer: */
     143        UIShortcutCache::iterator cacheItemPointer = qFind(shortcuts.begin(), shortcuts.end(), item);
     144        /* Make sure the pointer is valid: */
     145        if (cacheItemPointer == shortcuts.end())
     146            continue;
     147        /* Save shortcut cache item into cache: */
     148        *cacheItemPointer = item;
     149    }
     150}
     151
     152void UIHotKeyTableModel::setFilter(const QString &strFilter)
     153{
     154    m_strFilter = strFilter;
     155    applyFilter();
     156}
     157
     158bool UIHotKeyTableModel::isAllShortcutsUnique()
     159{
     160    /* Enumerate all the sequences: */
     161    QMap<QString, QString> usedSequences;
     162    foreach (const UIShortcutCacheItem &item, m_shortcuts)
     163        if (!item.currentSequence.isEmpty())
     164            usedSequences.insertMulti(item.currentSequence, item.key);
     165    /* Enumerate all the duplicated sequences: */
     166    QSet<QString> duplicatedSequences;
     167    foreach (const QString &strKey, usedSequences.keys())
     168        if (usedSequences.count(strKey) > 1)
     169            duplicatedSequences.unite(usedSequences.values(strKey).toSet());
     170    /* Is there something changed? */
     171    if (m_duplicatedSequences != duplicatedSequences)
     172    {
     173        m_duplicatedSequences = duplicatedSequences;
     174        emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1));
     175    }
     176    /* Are there duplicated shortcuts? */
     177    if (!m_duplicatedSequences.isEmpty())
     178        return false;
     179    /* True by default: */
     180    return true;
     181}
     182
     183int UIHotKeyTableModel::rowCount(const QModelIndex& /*parent = QModelIndex()*/) const
     184{
     185    return m_filteredShortcuts.size();
     186}
     187
     188int UIHotKeyTableModel::columnCount(const QModelIndex& /*parent = QModelIndex()*/) const
     189{
     190    return 2;
     191}
     192
     193Qt::ItemFlags UIHotKeyTableModel::flags(const QModelIndex &index) const
     194{
     195    /* No flags for invalid index: */
     196    if (!index.isValid()) return Qt::NoItemFlags;
     197    /* Switch for different columns: */
     198    switch (index.column())
     199    {
     200        case UIHotKeyTableSection_Name: return Qt::ItemIsEnabled;
     201        case UIHotKeyTableSection_Value: return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
     202        default: break;
     203    }
     204    /* No flags by default: */
     205    return Qt::NoItemFlags;
     206}
     207
     208QVariant UIHotKeyTableModel::headerData(int iSection, Qt::Orientation orientation, int iRole /*= Qt::DisplayRole*/) const
     209{
     210    /* Switch for different roles: */
     211    switch (iRole)
     212    {
     213        case Qt::DisplayRole:
     214        {
     215            /* Invalid for vertical header: */
     216            if (orientation == Qt::Vertical) return QString();
     217            /* Switch for different columns: */
     218            switch (iSection)
     219            {
     220                case UIHotKeyTableSection_Name: return tr("Name");
     221                case UIHotKeyTableSection_Value: return tr("Shortcut");
     222                default: break;
     223            }
     224            /* Invalid for other cases: */
     225            return QString();
     226        }
     227        default: break;
     228    }
     229    /* Invalid by default: */
     230    return QVariant();
     231}
     232
     233QVariant UIHotKeyTableModel::data(const QModelIndex &index, int iRole /*= Qt::DisplayRole*/) const
     234{
     235    /* No data for invalid index: */
     236    if (!index.isValid()) return QVariant();
     237    int iIndex = index.row();
     238    /* Switch for different roles: */
     239    switch (iRole)
     240    {
     241        case Qt::DisplayRole:
     242        {
     243            /* Switch for different columns: */
     244            switch (index.column())
     245            {
     246                case UIHotKeyTableSection_Name: return m_filteredShortcuts[iIndex].description;
     247                case UIHotKeyTableSection_Value: return m_filteredShortcuts[iIndex].key == UIHostCombo::hostComboCacheKey() ?
     248                                                        UIHostCombo::toReadableString(m_filteredShortcuts[iIndex].currentSequence) :
     249                                                        m_filteredShortcuts[iIndex].currentSequence;
     250                default: break;
     251            }
     252            /* Invalid for other cases: */
     253            return QString();
     254        }
     255        case Qt::EditRole:
     256        {
     257            /* Switch for different columns: */
     258            switch (index.column())
     259            {
     260                case UIHotKeyTableSection_Value: return m_filteredShortcuts[iIndex].key == UIHostCombo::hostComboCacheKey() ?
     261                                                        QVariant::fromValue(UIHostComboWrapper(m_filteredShortcuts[iIndex].currentSequence)) :
     262                                                        QVariant::fromValue(UIHotKey(m_filteredShortcuts[iIndex].currentSequence,
     263                                                                                     m_filteredShortcuts[iIndex].defaultSequence));
     264                default: break;
     265            }
     266            /* Invalid for other cases: */
     267            return QString();
     268        }
     269        case Qt::FontRole:
     270        {
     271            /* Do we have a default font? */
     272            QFont font(QApplication::font());
     273            /* Switch for different columns: */
     274            switch (index.column())
     275            {
     276                case UIHotKeyTableSection_Value:
     277                {
     278                    if (m_filteredShortcuts[iIndex].key != UIHostCombo::hostComboCacheKey() &&
     279                        m_filteredShortcuts[iIndex].currentSequence != m_filteredShortcuts[iIndex].defaultSequence)
     280                        font.setBold(true);
     281                    break;
     282                }
     283                default: break;
     284            }
     285            /* Return resulting font: */
     286            return font;
     287        }
     288        case Qt::ForegroundRole:
     289        {
     290            /* Switch for different columns: */
     291            switch (index.column())
     292            {
     293                case UIHotKeyTableSection_Value:
     294                {
     295                    if (m_duplicatedSequences.contains(m_filteredShortcuts[iIndex].key))
     296                        return QBrush(Qt::red);
     297                    break;
     298                }
     299                default: break;
     300            }
     301            /* Default for other cases: */
     302            return QString();
     303        }
     304        default: break;
     305    }
     306    /* Invalid by default: */
     307    return QVariant();
     308}
     309
     310bool UIHotKeyTableModel::setData(const QModelIndex &index, const QVariant &value, int iRole /*= Qt::EditRole*/)
     311{
     312    /* Nothing to set for invalid index: */
     313    if (!index.isValid()) return false;
     314    /* Switch for different roles: */
     315    switch (iRole)
     316    {
     317        case Qt::EditRole:
     318        {
     319            /* Switch for different columns: */
     320            switch (index.column())
     321            {
     322                case UIHotKeyTableSection_Value:
     323                {
     324                    /* Get index: */
     325                    int iIndex = index.row();
     326                    /* Set sequence to shortcut: */
     327                    UIShortcutCacheItem &filteredShortcut = m_filteredShortcuts[iIndex];
     328                    UIShortcutCache::iterator shortcutPointer = qFind(m_shortcuts.begin(), m_shortcuts.end(), filteredShortcut);
     329                    if (shortcutPointer != m_shortcuts.end())
     330                    {
     331                        filteredShortcut.currentSequence = filteredShortcut.key == UIHostCombo::hostComboCacheKey() ?
     332                                                           value.value<UIHostComboWrapper>().toString() :
     333                                                           value.value<UIHotKey>().sequence();
     334                        *shortcutPointer = filteredShortcut;
     335                        emit sigRevalidationRequired();
     336                        return true;
     337                    }
     338                    break;
     339                }
     340                default: break;
     341            }
     342            break;
     343        }
     344        default: break;
     345    }
     346    /* Nothing to set by default: */
     347    return false;
     348}
     349
     350void UIHotKeyTableModel::sort(int iColumn, Qt::SortOrder order /*= Qt::AscendingOrder*/)
     351{
     352    qStableSort(m_shortcuts.begin(), m_shortcuts.end(), UIShortcutCacheItemFunctor(iColumn, order));
     353    applyFilter();
     354    emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1));
     355}
     356
     357void UIHotKeyTableModel::applyFilter()
     358{
     359    /* Erase items first: */
     360    beginRemoveRows(QModelIndex(), 0, m_filteredShortcuts.size() - 1);
     361    m_filteredShortcuts.clear();
     362    endRemoveRows();
     363
     364    /* If filter is empty: */
     365    if (m_strFilter.isEmpty())
     366    {
     367        /* Just add all the items: */
     368        m_filteredShortcuts = m_shortcuts;
     369    }
     370    else
     371    {
     372        /* Check if the description matches the filter: */
     373        foreach (const UIShortcutCacheItem &item, m_shortcuts)
     374        {
     375            /* If neither description nor sequence matches the filter, skip item: */
     376            if (!item.description.contains(m_strFilter, Qt::CaseInsensitive) &&
     377                !item.currentSequence.contains(m_strFilter, Qt::CaseInsensitive))
     378                continue;
     379            /* Add that item: */
     380            m_filteredShortcuts << item;
     381        }
     382    }
     383    beginInsertRows(QModelIndex(), 0, m_filteredShortcuts.size() - 1);
     384    endInsertRows();
     385}
     386
     387
     388UIHotKeyTable::UIHotKeyTable(UIHotKeyTableModel *pModel)
     389{
     390    /* Connect model: */
     391    setModel(pModel);
     392    connect(pModel, SIGNAL(sigShortcutsLoaded()), this, SLOT(sltHandleShortcutsLoaded()));
     393
     394    /* Configure self: */
     395    setTabKeyNavigation(false);
     396    setContextMenuPolicy(Qt::CustomContextMenu);
     397    setSelectionMode(QAbstractItemView::SingleSelection);
     398    setEditTriggers(QAbstractItemView::CurrentChanged | QAbstractItemView::SelectedClicked);
     399
     400    /* Configure headers: */
     401    verticalHeader()->hide();
     402    verticalHeader()->setDefaultSectionSize((int)(verticalHeader()->minimumSectionSize() * 1.33));
     403    horizontalHeader()->setStretchLastSection(false);
     404    horizontalHeader()->setResizeMode(UIHotKeyTableSection_Name, QHeaderView::Interactive);
     405    horizontalHeader()->setResizeMode(UIHotKeyTableSection_Value, QHeaderView::Stretch);
     406
     407    /* Register delegate editor: */
     408    if (QAbstractItemDelegate *pAbstractItemDelegate = itemDelegate())
     409    {
     410        if (QStyledItemDelegate *pStyledItemDelegate = qobject_cast<QStyledItemDelegate*>(pAbstractItemDelegate))
     411        {
     412            /* Create new item editor factory: */
     413            QItemEditorFactory *pNewItemEditorFactory = new QItemEditorFactory;
     414
     415            /* Register UIHotKeyEditor as the UIHotKey editor: */
     416            int iHotKeyTypeId = qRegisterMetaType<UIHotKey>();
     417            QStandardItemEditorCreator<UIHotKeyEditor> *pHotKeyItemEditorCreator = new QStandardItemEditorCreator<UIHotKeyEditor>();
     418            pNewItemEditorFactory->registerEditor((QVariant::Type)iHotKeyTypeId, pHotKeyItemEditorCreator);
     419
     420            /* Register UIHostComboEditor as the UIHostComboWrapper: */
     421            int iHostComboTypeId = qRegisterMetaType<UIHostComboWrapper>();
     422            QStandardItemEditorCreator<UIHostComboEditor> *pHostComboItemEditorCreator = new QStandardItemEditorCreator<UIHostComboEditor>();
     423            pNewItemEditorFactory->registerEditor((QVariant::Type)iHostComboTypeId, pHostComboItemEditorCreator);
     424
     425            /* Set configured item editor factory for table delegate: */
     426            pStyledItemDelegate->setItemEditorFactory(pNewItemEditorFactory);
     427        }
     428    }
     429}
     430
     431void UIHotKeyTable::sltHandleShortcutsLoaded()
     432{
     433    /* Resize columns to feat contents: */
     434    resizeColumnsToContents();
     435
     436    /* Configure sorting: */
     437    sortByColumn(UIHotKeyTableSection_Name, Qt::AscendingOrder);
     438    setSortingEnabled(true);
     439}
     440
  • trunk/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsInput.h

    r44658 r44662  
    2020#define __UIGlobalSettingsInput_h__
    2121
     22/* Qt includes: */
     23#include <QAbstractTableModel>
     24#include <QTableView>
     25
    2226/* GUI includes: */
    2327#include "UISettingsPage.h"
    2428#include "UIGlobalSettingsInput.gen.h"
     29#include "UIActionPool.h"
    2530
    2631/* Global settings / Input page / Cache / Shortcut cache item: */
     
    6469};
    6570
     71/* Global settings / Input page / Cache / Shortcut cache item sort functor: */
     72class UIShortcutCacheItemFunctor
     73{
     74public:
     75
     76    UIShortcutCacheItemFunctor(int iColumn, Qt::SortOrder order)
     77        : m_iColumn(iColumn)
     78        , m_order(order)
     79    {
     80    }
     81
     82    bool operator()(const UIShortcutCacheItem &item1, const UIShortcutCacheItem &item2)
     83    {
     84        switch (m_iColumn)
     85        {
     86            case 0: return m_order == Qt::AscendingOrder ? item1.description < item2.description : item1.description > item2.description;
     87            case 1: return m_order == Qt::AscendingOrder ? item1.currentSequence < item2.currentSequence : item1.currentSequence > item2.currentSequence;
     88            default: break;
     89        }
     90        return m_order == Qt::AscendingOrder ? item1.key < item2.key : item1.key > item2.key;
     91    }
     92
     93private:
     94
     95    int m_iColumn;
     96    Qt::SortOrder m_order;
     97};
     98
    6699/* Global settings / Input page / Cache / Shortcut cache: */
    67100typedef QList<UIShortcutCacheItem> UIShortcutCache;
     
    112145};
    113146
     147/* Hot-key table field indexes: */
     148enum UIHotKeyTableSection
     149{
     150    UIHotKeyTableSection_Name = 0,
     151    UIHotKeyTableSection_Value = 1
     152};
     153
     154/* A model representing hot-key combination table: */
     155class UIHotKeyTableModel : public QAbstractTableModel
     156{
     157    Q_OBJECT;
     158
     159signals:
     160
     161    /* Notifier: Readiness stuff: */
     162    void sigShortcutsLoaded();
     163
     164    /* Notifier: Validation stuff: */
     165    void sigRevalidationRequired();
     166
     167public:
     168
     169    /* Constructor: */
     170    UIHotKeyTableModel(QObject *pParent, UIActionPoolType type);
     171
     172    /* API: Loading/saving stuff: */
     173    void load(const UIShortcutCache &shortcuts);
     174    void save(UIShortcutCache &shortcuts);
     175
     176    /* API: Filtering stuff: */
     177    void setFilter(const QString &strFilter);
     178
     179    /* API: Validation stuff: */
     180    bool isAllShortcutsUnique();
     181
     182private:
     183
     184    /* Internal API: Size stuff: */
     185    int rowCount(const QModelIndex &parent = QModelIndex()) const;
     186    int columnCount(const QModelIndex &parent = QModelIndex()) const;
     187
     188    /* Internal API: Data stuff: */
     189    Qt::ItemFlags flags(const QModelIndex &index) const;
     190    QVariant headerData(int iSection, Qt::Orientation orientation, int iRole = Qt::DisplayRole) const;
     191    QVariant data(const QModelIndex &index, int iRole = Qt::DisplayRole) const;
     192    bool setData(const QModelIndex &index, const QVariant &value, int iRole = Qt::EditRole);
     193
     194    /* Internal API: Sorting stuff: */
     195    void sort(int iColumn, Qt::SortOrder order = Qt::AscendingOrder);
     196
     197    /* Helper: Filtering stuff: */
     198    void applyFilter();
     199
     200    /* Variables: */
     201    UIActionPoolType m_type;
     202    QString m_strFilter;
     203    UIShortcutCache m_shortcuts;
     204    UIShortcutCache m_filteredShortcuts;
     205    QSet<QString> m_duplicatedSequences;
     206};
     207
     208/* A table reflecting hot-key combinations: */
     209class UIHotKeyTable : public QTableView
     210{
     211    Q_OBJECT;
     212
     213public:
     214
     215    /* Constructor: */
     216    UIHotKeyTable(UIHotKeyTableModel *pModel);
     217
     218private slots:
     219
     220    /* Handler: Readiness stuff: */
     221    void sltHandleShortcutsLoaded();
     222};
     223
    114224#endif // __UIGlobalSettingsInput_h__
    115225
Note: See TracChangeset for help on using the changeset viewer.

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