VirtualBox

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

Last change on this file since 82781 was 80861, checked in by vboxsync, 5 years ago

FE/Qt: bugref:9335: Restorıng the cursor position instead of moving to end of the text

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

© 2023 Oracle
ContactPrivacy policyTerms of Use