VirtualBox

Ignore:
Timestamp:
Jul 12, 2017 11:03:34 AM (8 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
116915
Message:

FE/Qt: bugref:8400: Virtual Media Manager: Implementing possibility to change medium size.

Location:
trunk/src/VBox/Frontends/VirtualBox
Files:
7 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/VirtualBox2.qrc

    r67863 r67923  
    5151        <file alias="progress_media_delete_90px.png">images/progress_media_delete_90px.png</file>
    5252        <file alias="progress_media_move_90px.png">images/progress_media_move_90px.png</file>
     53        <file alias="progress_media_resize_90px.png">images/progress_media_resize_90px.png</file>
    5354        <file alias="progress_network_interface_90px.png">images/progress_network_interface_90px.png</file>
    5455        <file alias="progress_poweroff_90px.png">images/progress_poweroff_90px.png</file>
  • trunk/src/VBox/Frontends/VirtualBox/VirtualBox2_hidpi.qrc

    r67863 r67923  
    6060        <file alias="progress_media_delete_90px_hidpi.png">images/hidpi/progress_media_delete_90px_hidpi.png</file>
    6161        <file alias="progress_media_move_90px_hidpi.png">images/hidpi/progress_media_move_90px_hidpi.png</file>
     62        <file alias="progress_media_resize_90px_hidpi.png">images/hidpi/progress_media_resize_90px_hidpi.png</file>
    6263        <file alias="progress_network_interface_90px_hidpi.png">images/hidpi/progress_network_interface_90px_hidpi.png</file>
    6364        <file alias="progress_poweroff_90px_hidpi.png">images/hidpi/progress_poweroff_90px_hidpi.png</file>
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp

    r67863 r67923  
    13401340          tr("Failed to move the storage unit of the hard disk <b>%1</b> to <b>%2</b>.")
    13411341             .arg(strLocationOld, strLocationNew),
     1342          formatErrorInfo(comProgress));
     1343}
     1344
     1345void UIMessageCenter::cannotResizeHardDiskStorage(const CMedium &comMedium, const QString &strLocation, const QString &strSizeOld, const QString &strSizeNew, QWidget *pParent /* = 0 */) const
     1346{
     1347    error(pParent, MessageType_Error,
     1348          tr("Failed to resize the storage unit of the hard disk <b>%1</b> from <b>%2</b> to <b>%3</b>.")
     1349             .arg(strLocation, strSizeOld, strSizeNew),
     1350          formatErrorInfo(comMedium));
     1351}
     1352
     1353void UIMessageCenter::cannotResizeHardDiskStorage(const CProgress &comProgress, const QString &strLocation, const QString &strSizeOld, const QString &strSizeNew, QWidget *pParent /* = 0 */) const
     1354{
     1355    error(pParent, MessageType_Error,
     1356          tr("Failed to resize the storage unit of the hard disk <b>%1</b> from <b>%2</b> to <b>%3</b>.")
     1357             .arg(strLocation, strSizeOld, strSizeNew),
    13421358          formatErrorInfo(comProgress));
    13431359}
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.h

    r67863 r67923  
    252252    void cannotMoveHardDiskStorage(const CMedium &comMedium, const QString &strLocationOld, const QString &strLocationNew, QWidget *pParent = 0) const;
    253253    void cannotMoveHardDiskStorage(const CProgress &comProgress, const QString &strLocationOld, const QString &strLocationNew, QWidget *pParent = 0) const;
     254    void cannotResizeHardDiskStorage(const CMedium &comMedium, const QString &strLocation, const QString &strSizeOld, const QString &strSizeNew, QWidget *pParent = 0) const;
     255    void cannotResizeHardDiskStorage(const CProgress &comProgress, const QString &strLocation, const QString &strSizeOld, const QString &strSizeNew, QWidget *pParent = 0) const;
    254256    void cannotDetachDevice(const CMachine &machine, UIMediumType type, const QString &strLocation, const StorageSlot &storageSlot, QWidget *pParent = 0) const;
    255257    bool cannotRemountMedium(const CMachine &machine, const UIMedium &medium, bool fMount, bool fRetry, QWidget *pParent = 0) const;
  • trunk/src/VBox/Frontends/VirtualBox/src/medium/UIMediumDetailsWidget.cpp

    r67922 r67923  
    2424# include <QLabel>
    2525# include <QPushButton>
     26# include <QSlider>
    2627# include <QStackedLayout>
    2728# include <QVBoxLayout>
     
    3031# include "QIDialogButtonBox.h"
    3132# include "QILabel.h"
     33# include "QILineEdit.h"
    3234# include "QITabWidget.h"
    3335# include "UIConverter.h"
     
    3537# include "UIIconPool.h"
    3638# include "UIMediumDetailsWidget.h"
     39# include "VBoxGlobal.h"
     40
     41/* COM includes: */
     42# include "CSystemProperties.h"
    3743
    3844#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
     
    4753    , m_pLabelType(0), m_pComboBoxType(0), m_pErrorPaneType(0)
    4854    , m_pLabelLocation(0), m_pSelectorLocation(0), m_pErrorPaneLocation(0)
     55    , m_uMediumSizeMin(_4M)
     56    , m_uMediumSizeMax(vboxGlobal().virtualBox().GetSystemProperties().GetInfoVDSize())
     57    , m_iSliderScale(calculateSliderScale(m_uMediumSizeMax))
     58    , m_pLabelSize(0), m_pSliderSize(0), m_pLabelMinSize(0), m_pLabelMaxSize(0), m_pEditorSize(0), m_pErrorPaneSize(0)
    4959    , m_pButtonBox(0)
    5060    , m_pLayoutDetails(0)
     
    8494    m_pLabelType->setText(tr("&Type:"));
    8595    m_pLabelLocation->setText(tr("&Location:"));
     96    m_pLabelSize->setText(tr("&Size:"));
     97    m_pLabelMinSize->setText(vboxGlobal().formatSize(m_uMediumSizeMin));
     98    m_pLabelMaxSize->setText(vboxGlobal().formatSize(m_uMediumSizeMax));
    8699
    87100    /* Translate fields: */
     
    90103        m_pComboBoxType->setItemText(i, gpConverter->toString(m_pComboBoxType->itemData(i).value<KMediumType>()));
    91104    m_pSelectorLocation->setToolTip(tr("Holds the location of this medium."));
     105    m_pSliderSize->setToolTip(tr("Holds the size of this medium."));
     106    m_pEditorSize->setToolTip(tr("Holds the size of this medium."));
    92107
    93108    /* Translate button-box: */
     
    126141}
    127142
     143void UIMediumDetailsWidget::sltSizeSliderChanged(int iValue)
     144{
     145    m_newData.m_options.m_uLogicalSize = sliderToSizeMB(iValue, m_iSliderScale);
     146    m_pEditorSize->blockSignals(true);
     147    m_pEditorSize->setText(vboxGlobal().formatSize(m_newData.m_options.m_uLogicalSize));
     148    m_pEditorSize->blockSignals(false);
     149    revalidate(m_pErrorPaneSize);
     150    updateSizeToolTips(m_newData.m_options.m_uLogicalSize);
     151    updateButtonStates();
     152}
     153
     154void UIMediumDetailsWidget::sltSizeEditorChanged(const QString &strValue)
     155{
     156    m_newData.m_options.m_uLogicalSize = vboxGlobal().parseSize(strValue);
     157    m_pSliderSize->blockSignals(true);
     158    m_pSliderSize->setValue(sizeMBToSlider(m_newData.m_options.m_uLogicalSize, m_iSliderScale));
     159    m_pSliderSize->blockSignals(false);
     160    revalidate(m_pErrorPaneSize);
     161    updateSizeToolTips(m_newData.m_options.m_uLogicalSize);
     162    updateButtonStates();
     163}
     164
    128165void UIMediumDetailsWidget::sltHandleButtonBoxClick(QAbstractButton *pButton)
    129166{
     
    303340            }
    304341
     342            /* Create size label: */
     343            m_pLabelSize = new QLabel;
     344            AssertPtrReturnVoid(m_pLabelSize);
     345            {
     346                /* Configure label: */
     347                m_pLabelSize->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
     348
     349                /* Add into layout: */
     350                pLayoutOptions->addWidget(m_pLabelSize, 2, 0);
     351            }
     352
     353            /* Create size layout: */
     354            QGridLayout *pLayoutSize = new QGridLayout;
     355            AssertPtrReturnVoid(pLayoutSize);
     356            {
     357                /* Configure layout: */
     358                pLayoutSize->setContentsMargins(0, 0, 0, 0);
     359                pLayoutSize->setColumnStretch(0, 1);
     360                pLayoutSize->setColumnStretch(1, 1);
     361                pLayoutSize->setColumnStretch(2, 0);
     362                pLayoutSize->setColumnStretch(3, 0);
     363
     364                /* Create size slider: */
     365                m_pSliderSize = new QSlider;
     366                AssertPtrReturnVoid(m_pSliderSize);
     367                {
     368                    /* Configure slider: */
     369                    m_pSliderSize->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
     370                    m_pSliderSize->setOrientation(Qt::Horizontal);
     371                    m_pSliderSize->setTickPosition(QSlider::TicksBelow);
     372                    m_pSliderSize->setFocusPolicy(Qt::StrongFocus);
     373                    m_pSliderSize->setPageStep(m_iSliderScale);
     374                    m_pSliderSize->setSingleStep(m_iSliderScale / 8);
     375                    m_pSliderSize->setTickInterval(0);
     376                    m_pSliderSize->setMinimum(sizeMBToSlider(m_uMediumSizeMin, m_iSliderScale));
     377                    m_pSliderSize->setMaximum(sizeMBToSlider(m_uMediumSizeMax, m_iSliderScale));
     378                    connect(m_pSliderSize, &QSlider::valueChanged,
     379                            this, &UIMediumDetailsWidget::sltSizeSliderChanged);
     380
     381                    /* Add into layout: */
     382                    pLayoutSize->addWidget(m_pSliderSize, 0, 0, 1, 2);
     383                }
     384
     385                /* Create minimum size label: */
     386                m_pLabelMinSize = new QLabel;
     387                AssertPtrReturnVoid(m_pLabelMinSize);
     388                {
     389                    /* Configure label: */
     390                    m_pLabelMinSize->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
     391
     392                    /* Add into layout: */
     393                    pLayoutSize->addWidget(m_pLabelMinSize, 1, 0);
     394                }
     395
     396                /* Create maximum size label: */
     397                m_pLabelMaxSize = new QLabel;
     398                AssertPtrReturnVoid(m_pLabelMaxSize);
     399                {
     400                    /* Configure label: */
     401                    m_pLabelMaxSize->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
     402
     403                    /* Add into layout: */
     404                    pLayoutSize->addWidget(m_pLabelMaxSize, 1, 1);
     405                }
     406
     407                /* Create size editor: */
     408                m_pEditorSize = new QILineEdit;
     409                AssertPtrReturnVoid(m_pEditorSize);
     410                {
     411                    /* Configure editor: */
     412                    m_pLabelSize->setBuddy(m_pEditorSize);
     413                    m_pEditorSize->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
     414                    m_pEditorSize->setFixedWidthByText("88888.88 MB");
     415                    m_pEditorSize->setAlignment(Qt::AlignRight);
     416                    m_pEditorSize->setValidator(new QRegExpValidator(QRegExp(vboxGlobal().sizeRegexp()), this));
     417                    connect(m_pEditorSize, &QILineEdit::textChanged,
     418                            this, &UIMediumDetailsWidget::sltSizeEditorChanged);
     419
     420                    /* Add into layout: */
     421                    pLayoutSize->addWidget(m_pEditorSize, 0, 2);
     422                }
     423
     424                /* Create size error pane: */
     425                m_pErrorPaneSize = new QLabel;
     426                AssertPtrReturnVoid(m_pErrorPaneSize);
     427                {
     428                    /* Configure label: */
     429                    m_pErrorPaneSize->setAlignment(Qt::AlignCenter);
     430                    m_pErrorPaneSize->setPixmap(UIIconPool::iconSet(":/status_error_16px.png")
     431                                                    .pixmap(QSize(iIconMetric, iIconMetric)));
     432
     433                    /* Add into layout: */
     434                    pLayoutSize->addWidget(m_pErrorPaneSize, 0, 3);
     435                }
     436
     437                /* Add into layout: */
     438                pLayoutOptions->addLayout(pLayoutSize, 2, 1, 2, 1);
     439            }
     440
    305441            /* Create stretch: */
    306442            QSpacerItem *pSpacer2 = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
     
    308444            {
    309445                /* Add into layout: */
    310                 pLayoutOptions->addItem(pSpacer2, 2, 0, 1, 2);
     446                pLayoutOptions->addItem(pSpacer2, 4, 0, 1, 2);
    311447            }
    312448
     
    322458
    323459                /* Add into layout: */
    324                 pLayoutOptions->addWidget(m_pButtonBox, 3, 0, 1, 2);
     460                pLayoutOptions->addWidget(m_pButtonBox, 5, 0, 1, 2);
    325461            }
    326462        }
     
    453589    m_pSelectorLocation->setPath(m_newData.m_options.m_strLocation);
    454590    sltLocationPathChanged(m_pSelectorLocation->path());
     591
     592    /* Load size: */
     593    m_pLabelSize->setEnabled(m_newData.m_fValid && m_newData.m_enmType == UIMediumType_HardDisk);
     594    m_pSliderSize->setEnabled(m_newData.m_fValid && m_newData.m_enmType == UIMediumType_HardDisk);
     595    m_pLabelMinSize->setEnabled(m_newData.m_fValid && m_newData.m_enmType == UIMediumType_HardDisk);
     596    m_pLabelMaxSize->setEnabled(m_newData.m_fValid && m_newData.m_enmType == UIMediumType_HardDisk);
     597    m_pEditorSize->setEnabled(m_newData.m_fValid && m_newData.m_enmType == UIMediumType_HardDisk);
     598    m_pEditorSize->setText(vboxGlobal().formatSize(m_newData.m_options.m_uLogicalSize));
    455599}
    456600
     
    487631        m_pErrorPaneLocation->setVisible(fError);
    488632    }
     633    if (!pWidget || pWidget == m_pErrorPaneSize)
     634    {
     635        /* Always valid for now: */
     636        const bool fError = false;
     637        m_pErrorPaneSize->setVisible(fError);
     638    }
    489639
    490640    /* Retranslate validation: */
     
    501651//        m_pErrorPaneLocation->setToolTip(tr("Cannot change medium location from <b>%1</b> to <b>%2</b>.")
    502652//                                         .arg(m_oldData.m_options.m_strLocation).arg(m_newData.m_options.m_strLocation));
     653//    if (!pWidget || pWidget == m_pErrorPaneSize)
     654//        m_pErrorPaneSize->setToolTip(tr("Cannot change medium size from <b>%1</b> to <b>%2</b>.")
     655//                                         .arg(m_oldData.m_options.m_uLogicalSize).arg(m_newData.m_options.m_uLogicalSize));
    503656}
    504657
     
    520673}
    521674
     675/* static */
     676int UIMediumDetailsWidget::calculateSliderScale(qulonglong uMaximumMediumSize)
     677{
     678    /* Detect how many steps to recognize between adjacent powers of 2
     679     * to ensure that the last slider step is exactly that we need: */
     680    int iSliderScale = 0;
     681    int iPower = log2i(uMaximumMediumSize);
     682    qulonglong uTickMB = (qulonglong)1 << iPower;
     683    if (uTickMB < uMaximumMediumSize)
     684    {
     685        qulonglong uTickMBNext = (qulonglong)1 << (iPower + 1);
     686        qulonglong uGap = uTickMBNext - uMaximumMediumSize;
     687        iSliderScale = (int)((uTickMBNext - uTickMB) / uGap);
     688#ifdef VBOX_WS_MAC
     689        // WORKAROUND:
     690        // There is an issue with Qt5 QSlider under OSX:
     691        // Slider tick count (maximum - minimum) is limited with some
     692        // "magical number" - 588351, having it more than that brings
     693        // unpredictable results like slider token jumping and disappearing,
     694        // so we are limiting tick count by lowering slider-scale 128 times.
     695        iSliderScale /= 128;
     696#endif /* VBOX_WS_MAC */
     697    }
     698    return qMax(iSliderScale, 8);
     699}
     700
     701/* static */
     702int UIMediumDetailsWidget::log2i(qulonglong uValue)
     703{
     704    int iPower = -1;
     705    while (uValue)
     706    {
     707        ++iPower;
     708        uValue >>= 1;
     709    }
     710    return iPower;
     711}
     712
     713/* static */
     714int UIMediumDetailsWidget::sizeMBToSlider(qulonglong uValue, int iSliderScale)
     715{
     716    /* Make sure *any* slider value is multiple of 512: */
     717    uValue /= 512;
     718
     719    /* Calculate result: */
     720    int iPower = log2i(uValue);
     721    qulonglong uTickMB = qulonglong (1) << iPower;
     722    qulonglong uTickMBNext = qulonglong (1) << (iPower + 1);
     723    int iStep = (uValue - uTickMB) * iSliderScale / (uTickMBNext - uTickMB);
     724    int iResult = iPower * iSliderScale + iStep;
     725
     726    /* Return result: */
     727    return iResult;
     728}
     729
     730/* static */
     731qulonglong UIMediumDetailsWidget::sliderToSizeMB(int uValue, int iSliderScale)
     732{
     733    /* Calculate result: */
     734    int iPower = uValue / iSliderScale;
     735    int iStep = uValue % iSliderScale;
     736    qulonglong uTickMB = qulonglong (1) << iPower;
     737    qulonglong uTickMBNext = qulonglong (1) << (iPower + 1);
     738    qulonglong uResult = uTickMB + (uTickMBNext - uTickMB) * iStep / iSliderScale;
     739
     740    /* Make sure *any* slider value is multiple of 512: */
     741    uResult *= 512;
     742
     743    /* Return result: */
     744    return uResult;
     745}
     746
     747void UIMediumDetailsWidget::updateSizeToolTips(qulonglong uSize)
     748{
     749    const QString strToolTip = tr("<nobr>%1 (%2 B)</nobr>").arg(vboxGlobal().formatSize(uSize)).arg(uSize);
     750    m_pSliderSize->setToolTip(strToolTip);
     751    m_pEditorSize->setToolTip(strToolTip);
     752}
     753
    522754QWidget *UIMediumDetailsWidget::infoContainer(UIMediumType enmType) const
    523755{
  • trunk/src/VBox/Frontends/VirtualBox/src/medium/UIMediumDetailsWidget.h

    r67863 r67923  
    3434class QComboBox;
    3535class QLabel;
     36class QSlider;
    3637class QStackedLayout;
    3738class QWidget;
    3839class QILabel;
     40class QILineEdit;
    3941class QITabWidget;
    4042class UIFilePathSelector;
     
    4850        : m_enmType(KMediumType_Normal)
    4951        , m_strLocation(QString())
     52        , m_uLogicalSize(0)
    5053    {}
    5154
     
    5659               && (m_enmType == other.m_enmType)
    5760               && (m_strLocation == other.m_strLocation)
     61               && (m_uLogicalSize == other.m_uLogicalSize)
    5862               ;
    5963    }
     
    6872    /** Holds the location. */
    6973    QString m_strLocation;
     74    /** Holds the logical size. */
     75    qulonglong m_uLogicalSize;
    7076};
    7177
     
    190196        /** Handles location change. */
    191197        void sltLocationPathChanged(const QString &strPath);
     198        /** Handles size slider change. */
     199        void sltSizeSliderChanged(int iValue);
     200        /** Handles size editor change. */
     201        void sltSizeEditorChanged(const QString &strValue);
    192202
    193203        /** Handles button-box button click. */
     
    229239        /** Updates button states. */
    230240        void updateButtonStates();
     241
     242        /** Calculates slider scale according to passed @a uMaximumMediumSize. */
     243        static int calculateSliderScale(qulonglong uMaximumMediumSize);
     244        /** Returns log2 for passed @a uValue. */
     245        static int log2i(qulonglong uValue);
     246        /** Converts passed bytes @a uValue to slides scaled value using @a iSliderScale. */
     247        static int sizeMBToSlider(qulonglong uValue, int iSliderScale);
     248        /** Converts passed slider @a uValue to bytes unscaled value using @a iSliderScale. */
     249        static qulonglong sliderToSizeMB(int uValue, int iSliderScale);
     250        /** Updates slider/editor tool-tips. */
     251        void updateSizeToolTips(qulonglong uSize);
    231252    /** @} */
    232253
     
    271292        QLabel    *m_pErrorPaneLocation;
    272293
     294        /** Holds the minimum medium size. */
     295        const qulonglong  m_uMediumSizeMin;
     296        /** Holds the maximum medium size. */
     297        const qulonglong  m_uMediumSizeMax;
     298        /** Holds the slider scale. */
     299        const int         m_iSliderScale;
     300        /** Holds the size label. */
     301        QLabel           *m_pLabelSize;
     302        /** Holds the size slider. */
     303        QSlider          *m_pSliderSize;
     304        /** Holds the minimum size label. */
     305        QLabel           *m_pLabelMinSize;
     306        /** Holds the maximum size label. */
     307        QLabel           *m_pLabelMaxSize;
     308        /** Holds the size editor. */
     309        QILineEdit       *m_pEditorSize;
     310        /** Holds the size error pane. */
     311        QLabel           *m_pErrorPaneSize;
     312
    273313        /** Holds the button-box instance. */
    274314        QIDialogButtonBox *m_pButtonBox;
  • trunk/src/VBox/Frontends/VirtualBox/src/medium/UIMediumManager.cpp

    r67863 r67923  
    342342void UIMediumItem::refreshAll()
    343343{
    344     m_guiMedium.refresh();
     344    m_guiMedium.blockAndQueryState();
    345345    refresh();
    346346}
     
    386386    m_options.m_enmType = m_guiMedium.mediumType();
    387387    m_options.m_strLocation = m_guiMedium.location();
     388    m_options.m_uLogicalSize = m_guiMedium.logicalSizeInBytes();
    388389    /* Gather medium details data: */
    389390    m_details.m_aFields.clear();
     
    957958                                                      newData.m_options.m_strLocation,
    958959                                                      this);
     960        }
     961    }
     962
     963    /* Try to assign new medium size: */
     964    if (   comMedium.isOk()
     965        && newData.m_options.m_uLogicalSize != oldData.m_options.m_uLogicalSize)
     966    {
     967        /* Prepare resize storage progress: */
     968        CProgress comProgress = comMedium.Resize(newData.m_options.m_uLogicalSize);
     969
     970        /* Show error message if necessary: */
     971        if (!comMedium.isOk())
     972            msgCenter().cannotResizeHardDiskStorage(comMedium,
     973                                                    oldData.m_options.m_strLocation,
     974                                                    vboxGlobal().formatSize(oldData.m_options.m_uLogicalSize),
     975                                                    vboxGlobal().formatSize(newData.m_options.m_uLogicalSize),
     976                                                    this);
     977        else
     978        {
     979            /* Show resize storage progress: */
     980            msgCenter().showModalProgressDialog(comProgress, UIMediumManager::tr("Moving medium..."),
     981                                                ":/progress_media_move_90px.png", this);
     982
     983            /* Show error message if necessary: */
     984            if (!comProgress.isOk() || comProgress.GetResultCode() != 0)
     985                msgCenter().cannotResizeHardDiskStorage(comProgress,
     986                                                        oldData.m_options.m_strLocation,
     987                                                        vboxGlobal().formatSize(oldData.m_options.m_uLogicalSize),
     988                                                        vboxGlobal().formatSize(newData.m_options.m_uLogicalSize),
     989                                                        this);
    959990        }
    960991    }
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