VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/settings/editors/UIBaseMemoryEditor.cpp

Last change on this file was 104313, checked in by vboxsync, 7 weeks ago

FE/Qt. bugref:10622. Using new UITranslationEventListener in the settings related GUI classes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.3 KB
Line 
1/* $Id: UIBaseMemoryEditor.cpp 104313 2024-04-12 13:10:30Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIBaseMemoryEditor class implementation.
4 */
5
6/*
7 * Copyright (C) 2019-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 <QHBoxLayout>
31#include <QLabel>
32#include <QSpinBox>
33#include <QVBoxLayout>
34
35/* GUI includes: */
36#include "QIAdvancedSlider.h"
37#include "UIBaseMemoryEditor.h"
38#include "UIGlobalSession.h"
39
40/* COM includes: */
41#include "CSystemProperties.h"
42
43
44/** QIAdvancedSlider subclass used as a base memory slider. */
45class SHARED_LIBRARY_STUFF UIBaseMemorySlider : public QIAdvancedSlider
46{
47 Q_OBJECT;
48
49public:
50
51 /** Constructs guest RAM slider passing @a pParent to the base-class. */
52 UIBaseMemorySlider(QWidget *pParent = 0);
53 /** Constructs guest RAM slider passing @a pParent and @a enmOrientation to the base-class. */
54 UIBaseMemorySlider(Qt::Orientation enmOrientation, QWidget *pParent = 0);
55
56 /** Returns the minimum RAM. */
57 uint minRAM() const;
58 /** Returns the maximum optimal RAM. */
59 uint maxRAMOpt() const;
60 /** Returns the maximum allowed RAM. */
61 uint maxRAMAlw() const;
62 /** Returns the maximum possible RAM. */
63 uint maxRAM() const;
64
65private:
66
67 /** Prepares all. */
68 void prepare();
69
70 /** Calculates page step for passed @a iMaximum value. */
71 int calcPageStep(int iMaximum) const;
72
73 /** Holds the minimum RAM. */
74 uint m_uMinRAM;
75 /** Holds the maximum optimal RAM. */
76 uint m_uMaxRAMOpt;
77 /** Holds the maximum allowed RAM. */
78 uint m_uMaxRAMAlw;
79 /** Holds the maximum possible RAM. */
80 uint m_uMaxRAM;
81};
82
83
84/*********************************************************************************************************************************
85* Class UIBaseMemorySlider implementation. *
86*********************************************************************************************************************************/
87
88UIBaseMemorySlider::UIBaseMemorySlider(QWidget *pParent /* = 0 */)
89 : QIAdvancedSlider(pParent)
90 , m_uMinRAM(0)
91 , m_uMaxRAMOpt(0)
92 , m_uMaxRAMAlw(0)
93 , m_uMaxRAM(0)
94{
95 prepare();
96}
97
98UIBaseMemorySlider::UIBaseMemorySlider(Qt::Orientation enmOrientation, QWidget *pParent /* = 0 */)
99 : QIAdvancedSlider(enmOrientation, pParent)
100 , m_uMinRAM(0)
101 , m_uMaxRAMOpt(0)
102 , m_uMaxRAMAlw(0)
103 , m_uMaxRAM(0)
104{
105 prepare();
106}
107
108uint UIBaseMemorySlider::minRAM() const
109{
110 return m_uMinRAM;
111}
112
113uint UIBaseMemorySlider::maxRAMOpt() const
114{
115 return m_uMaxRAMOpt;
116}
117
118uint UIBaseMemorySlider::maxRAMAlw() const
119{
120 return m_uMaxRAMAlw;
121}
122
123uint UIBaseMemorySlider::maxRAM() const
124{
125 return m_uMaxRAM;
126}
127
128void UIBaseMemorySlider::prepare()
129{
130 ulong uFullSize = gpGlobalSession->host().GetMemorySize();
131 CSystemProperties sys = gpGlobalSession->virtualBox().GetSystemProperties();
132 m_uMinRAM = sys.GetMinGuestRAM();
133 m_uMaxRAM = RT_MIN(RT_ALIGN(uFullSize, _1G / _1M), sys.GetMaxGuestRAM());
134
135 /* Come up with some nice round percent boundaries relative to
136 * the system memory. A max of 75% on a 256GB config is ridiculous,
137 * even on an 8GB rig reserving 2GB for the OS is way to conservative.
138 * The max numbers can be estimated using the following program:
139 *
140 * double calcMaxPct(uint64_t cbRam)
141 * {
142 * double cbRamOverhead = cbRam * 0.0390625; // 160 bytes per page.
143 * double cbRamForTheOS = RT_MAX(RT_MIN(_512M, cbRam * 0.25), _64M);
144 * double OSPct = (cbRamOverhead + cbRamForTheOS) * 100.0 / cbRam;
145 * double MaxPct = 100 - OSPct;
146 * return MaxPct;
147 * }
148 *
149 * int main()
150 * {
151 * uint64_t cbRam = _1G;
152 * for (; !(cbRam >> 33); cbRam += _1G)
153 * printf("%8lluGB %.1f%% %8lluKB\n", cbRam >> 30, calcMaxPct(cbRam),
154 * (uint64_t)(cbRam * calcMaxPct(cbRam) / 100.0) >> 20);
155 * for (; !(cbRam >> 51); cbRam <<= 1)
156 * printf("%8lluGB %.1f%% %8lluKB\n", cbRam >> 30, calcMaxPct(cbRam),
157 * (uint64_t)(cbRam * calcMaxPct(cbRam) / 100.0) >> 20);
158 * return 0;
159 * }
160 *
161 * Note. We might wanna put these calculations somewhere global later. */
162
163 /* System RAM amount test: */
164 m_uMaxRAMAlw = (uint)(0.75 * uFullSize);
165 m_uMaxRAMOpt = (uint)(0.50 * uFullSize);
166 if (uFullSize < 3072)
167 /* done */;
168 else if (uFullSize < 4096) /* 3GB */
169 m_uMaxRAMAlw = (uint)(0.80 * uFullSize);
170 else if (uFullSize < 6144) /* 4-5GB */
171 {
172 m_uMaxRAMAlw = (uint)(0.84 * uFullSize);
173 m_uMaxRAMOpt = (uint)(0.60 * uFullSize);
174 }
175 else if (uFullSize < 8192) /* 6-7GB */
176 {
177 m_uMaxRAMAlw = (uint)(0.88 * uFullSize);
178 m_uMaxRAMOpt = (uint)(0.65 * uFullSize);
179 }
180 else if (uFullSize < 16384) /* 8-15GB */
181 {
182 m_uMaxRAMAlw = (uint)(0.90 * uFullSize);
183 m_uMaxRAMOpt = (uint)(0.70 * uFullSize);
184 }
185 else if (uFullSize < 32768) /* 16-31GB */
186 {
187 m_uMaxRAMAlw = (uint)(0.93 * uFullSize);
188 m_uMaxRAMOpt = (uint)(0.75 * uFullSize);
189 }
190 else if (uFullSize < 65536) /* 32-63GB */
191 {
192 m_uMaxRAMAlw = (uint)(0.94 * uFullSize);
193 m_uMaxRAMOpt = (uint)(0.80 * uFullSize);
194 }
195 else if (uFullSize < 131072) /* 64-127GB */
196 {
197 m_uMaxRAMAlw = (uint)(0.95 * uFullSize);
198 m_uMaxRAMOpt = (uint)(0.85 * uFullSize);
199 }
200 else /* 128GB- */
201 {
202 m_uMaxRAMAlw = (uint)(0.96 * uFullSize);
203 m_uMaxRAMOpt = (uint)(0.90 * uFullSize);
204 }
205 /* Now check the calculated maximums are out of the range for the guest
206 * RAM. If so change it accordingly. */
207 m_uMaxRAMAlw = RT_MIN(m_uMaxRAMAlw, m_uMaxRAM);
208 m_uMaxRAMOpt = RT_MIN(m_uMaxRAMOpt, m_uMaxRAM);
209
210 setPageStep(calcPageStep(m_uMaxRAM));
211 setSingleStep(pageStep() / 4);
212 setTickInterval(pageStep());
213 /* Setup the scale so that ticks are at page step boundaries */
214 if (m_uMinRAM >= static_cast<uint>(pageStep()))
215 setMinimum((m_uMinRAM / pageStep()) * pageStep());
216 else
217 setMinimum(m_uMinRAM);
218
219 setMaximum(m_uMaxRAM);
220 setSnappingEnabled(true);
221 setOptimalHint(m_uMinRAM, m_uMaxRAMOpt);
222 setWarningHint(m_uMaxRAMOpt, m_uMaxRAMAlw);
223 setErrorHint(m_uMaxRAMAlw, m_uMaxRAM);
224}
225
226int UIBaseMemorySlider::calcPageStep(int iMaximum) const
227{
228 /* Calculate a suitable page step size for the given max value.
229 * The returned size is so that there will be no more than 32
230 * pages. The minimum returned page size is 4. */
231
232 /* Reasonable max. number of page steps is 32: */
233 uint uPage = ((uint)iMaximum + 31) / 32;
234 /* Make it a power of 2: */
235 uint p = uPage, p2 = 0x1;
236 while ((p >>= 1))
237 p2 <<= 1;
238 if (uPage != p2)
239 p2 <<= 1;
240 if (p2 < 4)
241 p2 = 4;
242 return (int) p2;
243}
244
245
246/*********************************************************************************************************************************
247* Class UIBaseMemoryEditor implementation. *
248*********************************************************************************************************************************/
249
250UIBaseMemoryEditor::UIBaseMemoryEditor(QWidget *pParent /* = 0 */)
251 : UIEditor(pParent, true /* show in basic mode? */)
252 , m_iValue(0)
253 , m_pLayout(0)
254 , m_pLabelMemory(0)
255 , m_pSlider(0)
256 , m_pLabelMemoryMin(0)
257 , m_pLabelMemoryMax(0)
258 , m_pSpinBox(0)
259{
260 prepare();
261}
262
263void UIBaseMemoryEditor::setValue(int iValue)
264{
265 /* Update cached value and
266 * slider if value has changed: */
267 if (m_iValue != iValue)
268 {
269 m_iValue = iValue;
270 if (m_pSlider)
271 m_pSlider->setValue(m_iValue);
272 }
273}
274
275int UIBaseMemoryEditor::value() const
276{
277 return m_pSlider ? m_pSlider->value() : m_iValue;
278}
279
280uint UIBaseMemoryEditor::maxRAMOpt() const
281{
282 return m_pSlider ? m_pSlider->maxRAMOpt() : 0;
283}
284
285uint UIBaseMemoryEditor::maxRAMAlw() const
286{
287 return m_pSlider ? m_pSlider->maxRAMAlw() : 0;
288}
289
290int UIBaseMemoryEditor::minimumLabelHorizontalHint() const
291{
292 return m_pLabelMemory ? m_pLabelMemory->minimumSizeHint().width() : 0;
293}
294
295void UIBaseMemoryEditor::setMinimumLayoutIndent(int iIndent)
296{
297 if (m_pLayout)
298 m_pLayout->setColumnMinimumWidth(0, iIndent);
299}
300
301void UIBaseMemoryEditor::sltRetranslateUI()
302{
303 if (m_pLabelMemory)
304 m_pLabelMemory->setText(tr("Base &Memory:"));
305
306 const QString strToolTip(tr("Holds the amount of base memory the virtual machine will have."));
307 if (m_pSlider)
308 m_pSlider->setToolTip(strToolTip);
309 if (m_pSpinBox)
310 {
311 m_pSpinBox->setSuffix(QString(" %1").arg(tr("MB")));
312 m_pSpinBox->setToolTip(strToolTip);
313 }
314
315 if (m_pLabelMemoryMin)
316 {
317 m_pLabelMemoryMin->setText(tr("%1 MB").arg(m_pSlider->minRAM()));
318 m_pLabelMemoryMin->setToolTip(tr("Minimum possible base memory size."));
319 }
320 if (m_pLabelMemoryMax)
321 {
322 m_pLabelMemoryMax->setText(tr("%1 MB").arg(m_pSlider->maxRAM()));
323 m_pLabelMemoryMax->setToolTip(tr("Maximum possible base memory size."));
324 }
325}
326
327void UIBaseMemoryEditor::sltHandleSliderChange()
328{
329 /* Apply spin-box value keeping it's signals disabled: */
330 if (m_pSpinBox && m_pSlider)
331 {
332 m_pSpinBox->blockSignals(true);
333 m_pSpinBox->setValue(m_pSlider->value());
334 m_pSpinBox->blockSignals(false);
335 }
336
337 /* Revalidate to send signal to listener: */
338 revalidate();
339}
340
341void UIBaseMemoryEditor::sltHandleSpinBoxChange()
342{
343 /* Apply slider value keeping it's signals disabled: */
344 if (m_pSpinBox && m_pSlider)
345 {
346 m_pSlider->blockSignals(true);
347 m_pSlider->setValue(m_pSpinBox->value());
348 m_pSlider->blockSignals(false);
349 }
350
351 /* Revalidate to send signal to listener: */
352 revalidate();
353}
354
355void UIBaseMemoryEditor::prepare()
356{
357 /* Create main layout: */
358 m_pLayout = new QGridLayout(this);
359 if (m_pLayout)
360 {
361 m_pLayout->setContentsMargins(0, 0, 0, 0);
362
363 /* Create memory label: */
364 m_pLabelMemory = new QLabel(this);
365 if (m_pLabelMemory)
366 {
367 m_pLabelMemory->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
368 m_pLayout->addWidget(m_pLabelMemory, 0, 0);
369 }
370
371 /* Create slider layout: */
372 QVBoxLayout *pSliderLayout = new QVBoxLayout;
373 if (pSliderLayout)
374 {
375 pSliderLayout->setContentsMargins(0, 0, 0, 0);
376
377 /* Create memory slider: */
378 m_pSlider = new UIBaseMemorySlider(this);
379 if (m_pSlider)
380 {
381 m_pSlider->setMinimumWidth(150);
382 connect(m_pSlider, &UIBaseMemorySlider::valueChanged,
383 this, &UIBaseMemoryEditor::sltHandleSliderChange);
384 pSliderLayout->addWidget(m_pSlider);
385 }
386
387 /* Create legend layout: */
388 QHBoxLayout *pLegendLayout = new QHBoxLayout;
389 if (pLegendLayout)
390 {
391 pLegendLayout->setContentsMargins(0, 0, 0, 0);
392
393 /* Create min label: */
394 m_pLabelMemoryMin = new QLabel(this);
395 if (m_pLabelMemoryMin)
396 pLegendLayout->addWidget(m_pLabelMemoryMin);
397
398 /* Push labels from each other: */
399 pLegendLayout->addStretch();
400
401 /* Create max label: */
402 m_pLabelMemoryMax = new QLabel(this);
403 if (m_pLabelMemoryMax)
404 pLegendLayout->addWidget(m_pLabelMemoryMax);
405
406 /* Add legend layout to slider layout: */
407 pSliderLayout->addLayout(pLegendLayout);
408 }
409
410 /* Add slider layout to main layout: */
411 m_pLayout->addLayout(pSliderLayout, 0, 1, 2, 1);
412 }
413
414 /* Create memory spin-box: */
415 m_pSpinBox = new QSpinBox(this);
416 if (m_pSpinBox)
417 {
418 setFocusProxy(m_pSpinBox);
419 if (m_pLabelMemory)
420 m_pLabelMemory->setBuddy(m_pSpinBox);
421 m_pSpinBox->setMinimum(m_pSlider->minRAM());
422 m_pSpinBox->setMaximum(m_pSlider->maxRAM());
423 connect(m_pSpinBox, &QSpinBox::valueChanged,
424 this, &UIBaseMemoryEditor::sltHandleSpinBoxChange);
425 m_pLayout->addWidget(m_pSpinBox, 0, 2);
426 }
427 }
428
429 /* Apply language settings: */
430 sltRetranslateUI();
431}
432
433void UIBaseMemoryEditor::revalidate()
434{
435 if (m_pSlider)
436 {
437 emit sigValidChanged(m_pSlider->value() < (int)m_pSlider->maxRAMAlw());
438 emit sigValueChanged(m_pSlider->value());
439 }
440}
441
442
443#include "UIBaseMemoryEditor.moc"
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use