VirtualBox

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

Last change on this file was 104358, checked in by vboxsync, 5 weeks ago

FE/Qt. bugref:10622. More refactoring around the retranslation functionality.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.2 KB
Line 
1/* $Id: UIMediumSizeEditor.cpp 104358 2024-04-18 05:33:40Z 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#include "UITranslationEventListener.h"
41
42/* COM includes: */
43#include "CSystemProperties.h"
44
45
46const qulonglong UIMediumSizeEditor::m_uSectorSize = 512;
47
48UIMediumSizeEditor::UIMediumSizeEditor(QWidget *pParent, qulonglong uMinimumSize /* = _4M */)
49 : QWidget(pParent)
50 , m_uSizeMin(uMinimumSize)
51 , m_uSizeMax(gpGlobalSession->virtualBox().GetSystemProperties().GetInfoVDSize())
52 , m_iSliderScale(calculateSliderScale(m_uSizeMax))
53 , m_uSize(0)
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_strSizeSuffix = gpConverter->toString(UITranslator::parseSizeSuffix(m_pEditor->text()));
77 m_pEditor->blockSignals(false);
78}
79
80void UIMediumSizeEditor::sltRetranslateUI()
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_strSizeSuffix = gpConverter->toString(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_strSizeSuffix: */
131 if (UITranslator::hasSizeSuffix(strSizeString))
132 m_strSizeSuffix = gpConverter->toString(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(m_strSizeSuffix);
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 sltRetranslateUI();
214 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
215 this, &UIMediumSizeEditor::sltRetranslateUI);
216}
217
218/* static */
219int UIMediumSizeEditor::calculateSliderScale(qulonglong uMaximumMediumSize)
220{
221 /* Detect how many steps to recognize between adjacent powers of 2
222 * to ensure that the last slider step is exactly that we need: */
223 int iSliderScale = 0;
224 int iPower = log2i(uMaximumMediumSize);
225 qulonglong uTickMB = (qulonglong)1 << iPower;
226 if (uTickMB < uMaximumMediumSize)
227 {
228 qulonglong uTickMBNext = (qulonglong)1 << (iPower + 1);
229 qulonglong uGap = uTickMBNext - uMaximumMediumSize;
230 iSliderScale = (int)((uTickMBNext - uTickMB) / uGap);
231#ifdef VBOX_WS_MAC
232 // WORKAROUND:
233 // There is an issue with Qt5 QSlider under OSX:
234 // Slider tick count (maximum - minimum) is limited with some
235 // "magical number" - 588351, having it more than that brings
236 // unpredictable results like slider token jumping and disappearing,
237 // so we are limiting tick count by lowering slider-scale 128 times.
238 iSliderScale /= 128;
239#endif /* VBOX_WS_MAC */
240 }
241 return qMax(iSliderScale, 8);
242}
243
244/* static */
245int UIMediumSizeEditor::log2i(qulonglong uValue)
246{
247 if (!uValue)
248 return 0;
249 int iPower = -1;
250 while (uValue)
251 {
252 ++iPower;
253 uValue >>= 1;
254 }
255 return iPower;
256}
257
258/* static */
259int UIMediumSizeEditor::sizeMBToSlider(qulonglong uValue, int iSliderScale)
260{
261 /* Make sure *any* slider value is multiple of m_uSectorSize: */
262 uValue /= m_uSectorSize;
263
264 /* Calculate result: */
265 int iPower = log2i(uValue);
266 qulonglong uTickMB = qulonglong (1) << iPower;
267 qulonglong uTickMBNext = qulonglong (1) << (iPower + 1);
268 int iStep = (uValue - uTickMB) * iSliderScale / (uTickMBNext - uTickMB);
269 int iResult = iPower * iSliderScale + iStep;
270
271 /* Return result: */
272 return iResult;
273}
274
275/* static */
276qulonglong UIMediumSizeEditor::sliderToSizeMB(int uValue, int iSliderScale)
277{
278 /* Calculate result: */
279 int iPower = uValue / iSliderScale;
280 int iStep = uValue % iSliderScale;
281 qulonglong uTickMB = qulonglong (1) << iPower;
282 qulonglong uTickMBNext = qulonglong (1) << (iPower + 1);
283 qulonglong uResult = uTickMB + (uTickMBNext - uTickMB) * iStep / iSliderScale;
284
285 /* Make sure *any* slider value is multiple of m_uSectorSize: */
286 uResult *= m_uSectorSize;
287
288 /* Return result: */
289 return uResult;
290}
291
292void UIMediumSizeEditor::updateSizeToolTips(qulonglong uSize)
293{
294 const QString strToolTip = tr("<nobr>%1 (%2 B)</nobr>").arg(UITranslator::formatSize(uSize)).arg(uSize);
295 m_pSlider->setToolTip(strToolTip);
296 m_pEditor->setToolTip(strToolTip);
297}
298
299qulonglong UIMediumSizeEditor::checkSectorSizeAlignment(qulonglong uSize)
300{
301 if (m_uSectorSize == 0 || uSize % m_uSectorSize == 0)
302 return uSize;
303 qulonglong uNewSize = (uSize / m_uSectorSize) * m_uSectorSize;
304 return uNewSize;
305}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use