VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/widgets/UIMediumSizeEditor.cpp@ 103977

Last change on this file since 103977 was 103771, checked in by vboxsync, 9 months ago

FE/Qt: UICommon: Switching dependency from UICommon to UIGlobalSession whenever is possible.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.0 KB
Line 
1/* $Id: UIMediumSizeEditor.cpp 103771 2024-03-11 15:16:04Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIMediumSizeEditor class implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QGridLayout>
30#include <QLabel>
31#include <QRegularExpressionValidator>
32#include <QSlider>
33
34/* GUI includes: */
35#include "QILineEdit.h"
36#include "UIConverter.h"
37#include "UIGlobalSession.h"
38#include "UIMediumSizeEditor.h"
39#include "UITranslator.h"
40
41/* COM includes: */
42#include "CSystemProperties.h"
43
44
45const qulonglong UIMediumSizeEditor::m_uSectorSize = 512;
46
47UIMediumSizeEditor::UIMediumSizeEditor(QWidget *pParent, qulonglong uMinimumSize /* = _4M */)
48 : QIWithRetranslateUI<QWidget>(pParent)
49 , m_uSizeMin(uMinimumSize)
50 , m_uSizeMax(gpGlobalSession->virtualBox().GetSystemProperties().GetInfoVDSize())
51 , m_iSliderScale(calculateSliderScale(m_uSizeMax))
52 , m_uSize(0)
53 , m_pSlider(0)
54 , m_pLabelMinSize(0)
55 , m_pLabelMaxSize(0)
56 , m_pEditor(0)
57{
58 /* Prepare: */
59 prepare();
60 QString strRegEx = QString("[^\\d%1]").arg(UITranslator::decimalSep());
61 m_regExNonDigitOrSeparator = QRegularExpression(strRegEx);
62}
63
64void UIMediumSizeEditor::setMediumSize(qulonglong uSize)
65{
66 /* Remember the new size: */
67 m_uSize = uSize;
68
69 /* And assign it to the slider & editor: */
70 m_pSlider->blockSignals(true);
71 m_pSlider->setValue(sizeMBToSlider(m_uSize, m_iSliderScale));
72 m_pSlider->blockSignals(false);
73 m_pEditor->blockSignals(true);
74 m_pEditor->setText(UITranslator::formatSize(m_uSize));
75 m_strSizeSuffix = gpConverter->toString(UITranslator::parseSizeSuffix(m_pEditor->text()));
76 m_pEditor->blockSignals(false);
77}
78
79void UIMediumSizeEditor::retranslateUi()
80{
81 /* Translate labels: */
82 m_pLabelMinSize->setText(UITranslator::formatSize(m_uSizeMin));
83 m_pLabelMaxSize->setText(UITranslator::formatSize(m_uSizeMax));
84
85 /* Translate fields: */
86 m_pSlider->setToolTip(tr("Holds the size of this medium."));
87 m_pEditor->setToolTip(tr("Holds the size of this medium."));
88 m_pLabelMinSize->setToolTip(tr("Minimum size for this medium."));
89 m_pLabelMaxSize->setToolTip(tr("Maximum size for this medium."));
90}
91
92void UIMediumSizeEditor::sltSizeSliderChanged(int iValue)
93{
94 /* Update the current size: */
95 m_uSize = sliderToSizeMB(iValue, m_iSliderScale);
96 /* Update the other widget: */
97 m_pEditor->blockSignals(true);
98 m_pEditor->setText(UITranslator::formatSize(m_uSize));
99 m_strSizeSuffix = gpConverter->toString(UITranslator::parseSizeSuffix(m_pEditor->text()));
100 m_pEditor->blockSignals(false);
101 /* Notify the listeners: */
102 emit sigSizeChanged(m_uSize);
103}
104
105void UIMediumSizeEditor::sltSizeEditorTextChanged()
106{
107 QString strSizeString = ensureSizeSuffix(m_pEditor->text());
108
109
110 m_pEditor->blockSignals(true);
111 int iCursorPosition = m_pEditor->cursorPosition();
112 m_pEditor->setText(strSizeString);
113 m_pEditor->setCursorPosition(iCursorPosition);
114 m_pEditor->blockSignals(false);
115
116 /* Update the current size: */
117 m_uSize = checkSectorSizeAlignment(UITranslator::parseSize(strSizeString));
118
119 /* Update the other widget: */
120 m_pSlider->blockSignals(true);
121 m_pSlider->setValue(sizeMBToSlider(m_uSize, m_iSliderScale));
122 m_pSlider->blockSignals(false);
123 /* Notify the listeners: */
124 emit sigSizeChanged(m_uSize);
125}
126
127QString UIMediumSizeEditor::ensureSizeSuffix(const QString &strSizeString)
128{
129 /* Try to update the m_strSizeSuffix: */
130 if (UITranslator::hasSizeSuffix(strSizeString))
131 m_strSizeSuffix = gpConverter->toString(UITranslator::parseSizeSuffix(strSizeString));
132
133 QString strOnlyDigits(strSizeString);
134 /* Remove any chars from the string except digits and decimal separator and then add a space and size suffix: */
135 return QString("%1 %2").arg(strOnlyDigits.remove(m_regExNonDigitOrSeparator)).arg(m_strSizeSuffix);
136}
137
138void UIMediumSizeEditor::prepare()
139{
140 /* Create layout: */
141 QGridLayout *pLayout = new QGridLayout(this);
142 if (pLayout)
143 {
144 /* Configure layout: */
145 pLayout->setContentsMargins(0, 0, 0, 0);
146 pLayout->setColumnStretch(0, 1);
147 pLayout->setColumnStretch(1, 1);
148 pLayout->setColumnStretch(2, 0);
149
150 /* Create size slider: */
151 m_pSlider = new QSlider;
152 if (m_pSlider)
153 {
154 /* Configure slider: */
155 m_pSlider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
156 m_pSlider->setOrientation(Qt::Horizontal);
157 m_pSlider->setTickPosition(QSlider::TicksBelow);
158 m_pSlider->setFocusPolicy(Qt::StrongFocus);
159 m_pSlider->setPageStep(m_iSliderScale);
160 m_pSlider->setSingleStep(m_iSliderScale / 8);
161 m_pSlider->setTickInterval(0);
162 m_pSlider->setMinimum(sizeMBToSlider(m_uSizeMin, m_iSliderScale));
163 m_pSlider->setMaximum(sizeMBToSlider(m_uSizeMax, m_iSliderScale));
164 connect(m_pSlider, &QSlider::valueChanged,
165 this, &UIMediumSizeEditor::sltSizeSliderChanged);
166
167 /* Add into layout: */
168 pLayout->addWidget(m_pSlider, 0, 0, 1, 2, Qt::AlignTop);
169 }
170
171 /* Create minimum size label: */
172 m_pLabelMinSize = new QLabel;
173 if (m_pLabelMinSize)
174 {
175 /* Configure label: */
176 m_pLabelMinSize->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
177
178 /* Add into layout: */
179 pLayout->addWidget(m_pLabelMinSize, 1, 0);
180 }
181
182 /* Create maximum size label: */
183 m_pLabelMaxSize = new QLabel;
184 if (m_pLabelMaxSize)
185 {
186 /* Configure label: */
187 m_pLabelMaxSize->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
188
189 /* Add into layout: */
190 pLayout->addWidget(m_pLabelMaxSize, 1, 1);
191 }
192
193 /* Create size editor: */
194 m_pEditor = new QILineEdit;
195 if (m_pEditor)
196 {
197 /* Configure editor: */
198 m_pEditor->installEventFilter(this);
199 m_pEditor->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
200 m_pEditor->setFixedWidthByText("88888.88 MB");
201 m_pEditor->setAlignment(Qt::AlignRight);
202 m_pEditor->setValidator(new QRegularExpressionValidator(QRegularExpression(UITranslator::sizeRegexp()), this));
203 connect(m_pEditor, &QILineEdit::textChanged,
204 this, &UIMediumSizeEditor::sltSizeEditorTextChanged);
205
206 /* Add into layout: */
207 pLayout->addWidget(m_pEditor, 0, 2, Qt::AlignTop);
208 }
209 }
210
211 /* Apply language settings: */
212 retranslateUi();
213}
214
215/* static */
216int UIMediumSizeEditor::calculateSliderScale(qulonglong uMaximumMediumSize)
217{
218 /* Detect how many steps to recognize between adjacent powers of 2
219 * to ensure that the last slider step is exactly that we need: */
220 int iSliderScale = 0;
221 int iPower = log2i(uMaximumMediumSize);
222 qulonglong uTickMB = (qulonglong)1 << iPower;
223 if (uTickMB < uMaximumMediumSize)
224 {
225 qulonglong uTickMBNext = (qulonglong)1 << (iPower + 1);
226 qulonglong uGap = uTickMBNext - uMaximumMediumSize;
227 iSliderScale = (int)((uTickMBNext - uTickMB) / uGap);
228#ifdef VBOX_WS_MAC
229 // WORKAROUND:
230 // There is an issue with Qt5 QSlider under OSX:
231 // Slider tick count (maximum - minimum) is limited with some
232 // "magical number" - 588351, having it more than that brings
233 // unpredictable results like slider token jumping and disappearing,
234 // so we are limiting tick count by lowering slider-scale 128 times.
235 iSliderScale /= 128;
236#endif /* VBOX_WS_MAC */
237 }
238 return qMax(iSliderScale, 8);
239}
240
241/* static */
242int UIMediumSizeEditor::log2i(qulonglong uValue)
243{
244 if (!uValue)
245 return 0;
246 int iPower = -1;
247 while (uValue)
248 {
249 ++iPower;
250 uValue >>= 1;
251 }
252 return iPower;
253}
254
255/* static */
256int UIMediumSizeEditor::sizeMBToSlider(qulonglong uValue, int iSliderScale)
257{
258 /* Make sure *any* slider value is multiple of m_uSectorSize: */
259 uValue /= m_uSectorSize;
260
261 /* Calculate result: */
262 int iPower = log2i(uValue);
263 qulonglong uTickMB = qulonglong (1) << iPower;
264 qulonglong uTickMBNext = qulonglong (1) << (iPower + 1);
265 int iStep = (uValue - uTickMB) * iSliderScale / (uTickMBNext - uTickMB);
266 int iResult = iPower * iSliderScale + iStep;
267
268 /* Return result: */
269 return iResult;
270}
271
272/* static */
273qulonglong UIMediumSizeEditor::sliderToSizeMB(int uValue, int iSliderScale)
274{
275 /* Calculate result: */
276 int iPower = uValue / iSliderScale;
277 int iStep = uValue % iSliderScale;
278 qulonglong uTickMB = qulonglong (1) << iPower;
279 qulonglong uTickMBNext = qulonglong (1) << (iPower + 1);
280 qulonglong uResult = uTickMB + (uTickMBNext - uTickMB) * iStep / iSliderScale;
281
282 /* Make sure *any* slider value is multiple of m_uSectorSize: */
283 uResult *= m_uSectorSize;
284
285 /* Return result: */
286 return uResult;
287}
288
289void UIMediumSizeEditor::updateSizeToolTips(qulonglong uSize)
290{
291 const QString strToolTip = tr("<nobr>%1 (%2 B)</nobr>").arg(UITranslator::formatSize(uSize)).arg(uSize);
292 m_pSlider->setToolTip(strToolTip);
293 m_pEditor->setToolTip(strToolTip);
294}
295
296qulonglong UIMediumSizeEditor::checkSectorSizeAlignment(qulonglong uSize)
297{
298 if (m_uSectorSize == 0 || uSize % m_uSectorSize == 0)
299 return uSize;
300 qulonglong uNewSize = (uSize / m_uSectorSize) * m_uSectorSize;
301 return uNewSize;
302}
Note: See TracBrowser for help on using the repository browser.

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