VirtualBox

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

Last change on this file since 100347 was 98103, checked in by vboxsync, 22 months ago

Copyright year updates by scm.

  • 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 98103 2023-01-17 14:15:46Z 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 "UICommon.h"
37#include "UIConverter.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(uiCommon().virtualBox().GetSystemProperties().GetInfoVDSize())
51 , m_iSliderScale(calculateSliderScale(m_uSizeMax))
52 , m_uSize(0)
53 , m_enmSizeSuffix(SizeSuffix_Byte)
54 , m_pSlider(0)
55 , m_pLabelMinSize(0)
56 , m_pLabelMaxSize(0)
57 , m_pEditor(0)
58{
59 /* Prepare: */
60 prepare();
61 QString strRegEx = QString("[^\\d%1]").arg(UITranslator::decimalSep());
62 m_regExNonDigitOrSeparator = QRegularExpression(strRegEx);
63}
64
65void UIMediumSizeEditor::setMediumSize(qulonglong uSize)
66{
67 /* Remember the new size: */
68 m_uSize = uSize;
69
70 /* And assign it to the slider & editor: */
71 m_pSlider->blockSignals(true);
72 m_pSlider->setValue(sizeMBToSlider(m_uSize, m_iSliderScale));
73 m_pSlider->blockSignals(false);
74 m_pEditor->blockSignals(true);
75 m_pEditor->setText(UITranslator::formatSize(m_uSize));
76 m_enmSizeSuffix = UITranslator::parseSizeSuffix(m_pEditor->text());
77 m_pEditor->blockSignals(false);
78}
79
80void UIMediumSizeEditor::retranslateUi()
81{
82 /* Translate labels: */
83 m_pLabelMinSize->setText(UITranslator::formatSize(m_uSizeMin));
84 m_pLabelMaxSize->setText(UITranslator::formatSize(m_uSizeMax));
85
86 /* Translate fields: */
87 m_pSlider->setToolTip(tr("Holds the size of this medium."));
88 m_pEditor->setToolTip(tr("Holds the size of this medium."));
89 m_pLabelMinSize->setToolTip(tr("Minimum size for this medium."));
90 m_pLabelMaxSize->setToolTip(tr("Maximum size for this medium."));
91}
92
93void UIMediumSizeEditor::sltSizeSliderChanged(int iValue)
94{
95 /* Update the current size: */
96 m_uSize = sliderToSizeMB(iValue, m_iSliderScale);
97 /* Update the other widget: */
98 m_pEditor->blockSignals(true);
99 m_pEditor->setText(UITranslator::formatSize(m_uSize));
100 m_enmSizeSuffix = UITranslator::parseSizeSuffix(m_pEditor->text());
101 m_pEditor->blockSignals(false);
102 /* Notify the listeners: */
103 emit sigSizeChanged(m_uSize);
104}
105
106void UIMediumSizeEditor::sltSizeEditorTextChanged()
107{
108 QString strSizeString = ensureSizeSuffix(m_pEditor->text());
109
110
111 m_pEditor->blockSignals(true);
112 int iCursorPosition = m_pEditor->cursorPosition();
113 m_pEditor->setText(strSizeString);
114 m_pEditor->setCursorPosition(iCursorPosition);
115 m_pEditor->blockSignals(false);
116
117 /* Update the current size: */
118 m_uSize = checkSectorSizeAlignment(UITranslator::parseSize(strSizeString));
119
120 /* Update the other widget: */
121 m_pSlider->blockSignals(true);
122 m_pSlider->setValue(sizeMBToSlider(m_uSize, m_iSliderScale));
123 m_pSlider->blockSignals(false);
124 /* Notify the listeners: */
125 emit sigSizeChanged(m_uSize);
126}
127
128QString UIMediumSizeEditor::ensureSizeSuffix(const QString &strSizeString)
129{
130 /* Try to update the m_enmSizeSuffix: */
131 if (UITranslator::hasSizeSuffix(strSizeString))
132 m_enmSizeSuffix = UITranslator::parseSizeSuffix(strSizeString);
133
134 QString strOnlyDigits(strSizeString);
135 /* Remove any chars from the string except digits and decimal separator and then add a space and size suffix: */
136 return QString("%1 %2").arg(strOnlyDigits.remove(m_regExNonDigitOrSeparator)).arg(gpConverter->toString(m_enmSizeSuffix));
137}
138
139void UIMediumSizeEditor::prepare()
140{
141 /* Create layout: */
142 QGridLayout *pLayout = new QGridLayout(this);
143 if (pLayout)
144 {
145 /* Configure layout: */
146 pLayout->setContentsMargins(0, 0, 0, 0);
147 pLayout->setColumnStretch(0, 1);
148 pLayout->setColumnStretch(1, 1);
149 pLayout->setColumnStretch(2, 0);
150
151 /* Create size slider: */
152 m_pSlider = new QSlider;
153 if (m_pSlider)
154 {
155 /* Configure slider: */
156 m_pSlider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
157 m_pSlider->setOrientation(Qt::Horizontal);
158 m_pSlider->setTickPosition(QSlider::TicksBelow);
159 m_pSlider->setFocusPolicy(Qt::StrongFocus);
160 m_pSlider->setPageStep(m_iSliderScale);
161 m_pSlider->setSingleStep(m_iSliderScale / 8);
162 m_pSlider->setTickInterval(0);
163 m_pSlider->setMinimum(sizeMBToSlider(m_uSizeMin, m_iSliderScale));
164 m_pSlider->setMaximum(sizeMBToSlider(m_uSizeMax, m_iSliderScale));
165 connect(m_pSlider, &QSlider::valueChanged,
166 this, &UIMediumSizeEditor::sltSizeSliderChanged);
167
168 /* Add into layout: */
169 pLayout->addWidget(m_pSlider, 0, 0, 1, 2, Qt::AlignTop);
170 }
171
172 /* Create minimum size label: */
173 m_pLabelMinSize = new QLabel;
174 if (m_pLabelMinSize)
175 {
176 /* Configure label: */
177 m_pLabelMinSize->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
178
179 /* Add into layout: */
180 pLayout->addWidget(m_pLabelMinSize, 1, 0);
181 }
182
183 /* Create maximum size label: */
184 m_pLabelMaxSize = new QLabel;
185 if (m_pLabelMaxSize)
186 {
187 /* Configure label: */
188 m_pLabelMaxSize->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
189
190 /* Add into layout: */
191 pLayout->addWidget(m_pLabelMaxSize, 1, 1);
192 }
193
194 /* Create size editor: */
195 m_pEditor = new QILineEdit;
196 if (m_pEditor)
197 {
198 /* Configure editor: */
199 m_pEditor->installEventFilter(this);
200 m_pEditor->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
201 m_pEditor->setFixedWidthByText("88888.88 MB");
202 m_pEditor->setAlignment(Qt::AlignRight);
203 m_pEditor->setValidator(new QRegularExpressionValidator(QRegularExpression(UITranslator::sizeRegexp()), this));
204 connect(m_pEditor, &QILineEdit::textChanged,
205 this, &UIMediumSizeEditor::sltSizeEditorTextChanged);
206
207 /* Add into layout: */
208 pLayout->addWidget(m_pEditor, 0, 2, Qt::AlignTop);
209 }
210 }
211
212 /* Apply language settings: */
213 retranslateUi();
214}
215
216/* static */
217int UIMediumSizeEditor::calculateSliderScale(qulonglong uMaximumMediumSize)
218{
219 /* Detect how many steps to recognize between adjacent powers of 2
220 * to ensure that the last slider step is exactly that we need: */
221 int iSliderScale = 0;
222 int iPower = log2i(uMaximumMediumSize);
223 qulonglong uTickMB = (qulonglong)1 << iPower;
224 if (uTickMB < uMaximumMediumSize)
225 {
226 qulonglong uTickMBNext = (qulonglong)1 << (iPower + 1);
227 qulonglong uGap = uTickMBNext - uMaximumMediumSize;
228 iSliderScale = (int)((uTickMBNext - uTickMB) / uGap);
229#ifdef VBOX_WS_MAC
230 // WORKAROUND:
231 // There is an issue with Qt5 QSlider under OSX:
232 // Slider tick count (maximum - minimum) is limited with some
233 // "magical number" - 588351, having it more than that brings
234 // unpredictable results like slider token jumping and disappearing,
235 // so we are limiting tick count by lowering slider-scale 128 times.
236 iSliderScale /= 128;
237#endif /* VBOX_WS_MAC */
238 }
239 return qMax(iSliderScale, 8);
240}
241
242/* static */
243int UIMediumSizeEditor::log2i(qulonglong uValue)
244{
245 if (!uValue)
246 return 0;
247 int iPower = -1;
248 while (uValue)
249 {
250 ++iPower;
251 uValue >>= 1;
252 }
253 return iPower;
254}
255
256/* static */
257int UIMediumSizeEditor::sizeMBToSlider(qulonglong uValue, int iSliderScale)
258{
259 /* Make sure *any* slider value is multiple of m_uSectorSize: */
260 uValue /= m_uSectorSize;
261
262 /* Calculate result: */
263 int iPower = log2i(uValue);
264 qulonglong uTickMB = qulonglong (1) << iPower;
265 qulonglong uTickMBNext = qulonglong (1) << (iPower + 1);
266 int iStep = (uValue - uTickMB) * iSliderScale / (uTickMBNext - uTickMB);
267 int iResult = iPower * iSliderScale + iStep;
268
269 /* Return result: */
270 return iResult;
271}
272
273/* static */
274qulonglong UIMediumSizeEditor::sliderToSizeMB(int uValue, int iSliderScale)
275{
276 /* Calculate result: */
277 int iPower = uValue / iSliderScale;
278 int iStep = uValue % iSliderScale;
279 qulonglong uTickMB = qulonglong (1) << iPower;
280 qulonglong uTickMBNext = qulonglong (1) << (iPower + 1);
281 qulonglong uResult = uTickMB + (uTickMBNext - uTickMB) * iStep / iSliderScale;
282
283 /* Make sure *any* slider value is multiple of m_uSectorSize: */
284 uResult *= m_uSectorSize;
285
286 /* Return result: */
287 return uResult;
288}
289
290void UIMediumSizeEditor::updateSizeToolTips(qulonglong uSize)
291{
292 const QString strToolTip = tr("<nobr>%1 (%2 B)</nobr>").arg(UITranslator::formatSize(uSize)).arg(uSize);
293 m_pSlider->setToolTip(strToolTip);
294 m_pEditor->setToolTip(strToolTip);
295}
296
297qulonglong UIMediumSizeEditor::checkSectorSizeAlignment(qulonglong uSize)
298{
299 if (m_uSectorSize == 0 || uSize % m_uSectorSize == 0)
300 return uSize;
301 qulonglong uNewSize = (uSize / m_uSectorSize) * m_uSectorSize;
302 return uNewSize;
303}
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