VirtualBox

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

Last change on this file was 104313, checked in by vboxsync, 5 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: 15.9 KB
Line 
1/* $Id: UISettingsSerializer.cpp 104313 2024-04-12 13:10:30Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UISettingsSerializer 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 <QCloseEvent>
30#include <QHBoxLayout>
31#include <QLabel>
32#include <QProgressBar>
33#include <QTimer>
34#include <QVBoxLayout>
35
36/* GUI includes: */
37#include "QILabel.h"
38#include "UIIconPool.h"
39#include "UIMessageCenter.h"
40#include "UISettingsPage.h"
41#include "UISettingsSerializer.h"
42#include "UITranslationEventListener.h"
43
44
45/*********************************************************************************************************************************
46* Class UISettingsSerializer implementation. *
47*********************************************************************************************************************************/
48
49UISettingsSerializer::UISettingsSerializer(QObject *pParent, SerializationDirection enmDirection,
50 const QVariant &data, const UISettingsPageList &pages)
51 : QThread(pParent)
52 , m_enmDirection(enmDirection)
53 , m_data(data)
54 , m_fSavingComplete(m_enmDirection == Load)
55 , m_iIdOfHighPriorityPage(-1)
56{
57 /* Copy the page(s) from incoming list to our map: */
58 foreach (UISettingsPage *pPage, pages)
59 m_pages.insert(pPage->id(), pPage);
60
61 /* Handling internal signals, they are also redirected in their handlers: */
62 connect(this, &UISettingsSerializer::sigNotifyAboutPageProcessed, this, &UISettingsSerializer::sltHandleProcessedPage, Qt::QueuedConnection);
63 connect(this, &UISettingsSerializer::sigNotifyAboutPagesProcessed, this, &UISettingsSerializer::sltHandleProcessedPages, Qt::QueuedConnection);
64
65 /* Redirecting unhandled internal signals: */
66 connect(this, &UISettingsSerializer::finished, this, &UISettingsSerializer::sigNotifyAboutProcessFinished, Qt::QueuedConnection);
67}
68
69UISettingsSerializer::~UISettingsSerializer()
70{
71 /* If serializer is being destructed by it's parent,
72 * thread could still be running, we have to wait
73 * for it to be finished! */
74 if (isRunning())
75 wait();
76}
77
78void UISettingsSerializer::raisePriorityOfPage(int iPageId)
79{
80 /* If that page is present and was not processed already =>
81 * we should remember which page should be processed next: */
82 if (m_pages.contains(iPageId) && !(m_pages[iPageId]->processed()))
83 m_iIdOfHighPriorityPage = iPageId;
84}
85
86void UISettingsSerializer::start(Priority priority /* = InheritPriority */)
87{
88 /* Notify listeners about we are starting: */
89 emit sigNotifyAboutProcessStarted();
90
91 /* If serializer saves settings: */
92 if (m_enmDirection == Save)
93 {
94 /* We should update internal page cache first: */
95 foreach (UISettingsPage *pPage, m_pages.values())
96 pPage->putToCache();
97 }
98
99 /* Start async serializing thread: */
100 QThread::start(priority);
101}
102
103void UISettingsSerializer::sltHandleProcessedPage(int iPageId)
104{
105 /* Make sure such page present: */
106 AssertReturnVoid(m_pages.contains(iPageId));
107
108 /* Get the page being processed: */
109 UISettingsPage *pSettingsPage = m_pages.value(iPageId);
110
111 /* If serializer loads settings: */
112 if (m_enmDirection == Load)
113 {
114 /* We should fetch internal page cache: */
115 pSettingsPage->setValidatorBlocked(true);
116 pSettingsPage->getFromCache();
117 pSettingsPage->setValidatorBlocked(false);
118 }
119
120 /* Add processed page into corresponding map: */
121 m_pagesDone.insert(iPageId, pSettingsPage);
122
123 /* Notify listeners about process reached n%: */
124 const int iValue = 100 * m_pagesDone.size() / m_pages.size();
125 emit sigNotifyAboutProcessProgressChanged(iValue);
126}
127
128void UISettingsSerializer::sltHandleProcessedPages()
129{
130 /* If serializer saves settings: */
131 if (m_enmDirection == Save)
132 {
133 /* We should flag GUI thread to unlock itself: */
134 if (!m_fSavingComplete)
135 m_fSavingComplete = true;
136 }
137 /* If serializer loads settings: */
138 else
139 {
140 /* We have to do initial validation finally: */
141 foreach (UISettingsPage *pPage, m_pages.values())
142 pPage->revalidate();
143 }
144
145 /* Notify listeners about process reached 100%: */
146 emit sigNotifyAboutProcessProgressChanged(100);
147}
148
149void UISettingsSerializer::run()
150{
151 /* Initialize COM for other thread: */
152 COMBase::InitializeCOM(false);
153
154 /* Mark all the pages initially as NOT processed: */
155 foreach (UISettingsPage *pPage, m_pages.values())
156 pPage->setProcessed(false);
157
158 /* Iterate over the all left settings pages: */
159 UISettingsPageMap pages(m_pages);
160 while (!pages.empty())
161 {
162 /* Get required page pointer, protect map by mutex while getting pointer: */
163 UISettingsPage *pPage = m_iIdOfHighPriorityPage != -1 && pages.contains(m_iIdOfHighPriorityPage) ?
164 pages.value(m_iIdOfHighPriorityPage) : *pages.begin();
165 /* Reset request of high priority: */
166 if (m_iIdOfHighPriorityPage != -1)
167 m_iIdOfHighPriorityPage = -1;
168 /* Process this page if its enabled: */
169 connect(pPage, &UISettingsPage::sigOperationProgressChange,
170 this, &UISettingsSerializer::sigOperationProgressChange);
171 connect(pPage, &UISettingsPage::sigOperationProgressError,
172 this, &UISettingsSerializer::sigOperationProgressError);
173 if (pPage->isEnabled())
174 {
175 if (m_enmDirection == Load)
176 pPage->loadToCacheFrom(m_data);
177 if (m_enmDirection == Save)
178 pPage->saveFromCacheTo(m_data);
179 }
180 /* Remember what page was processed: */
181 disconnect(pPage, &UISettingsPage::sigOperationProgressChange,
182 this, &UISettingsSerializer::sigOperationProgressChange);
183 disconnect(pPage, &UISettingsPage::sigOperationProgressError,
184 this, &UISettingsSerializer::sigOperationProgressError);
185 pPage->setProcessed(true);
186 /* Remove processed page from our map: */
187 pages.remove(pPage->id());
188 /* Notify listeners about page was processed: */
189 emit sigNotifyAboutPageProcessed(pPage->id());
190 /* If serializer saves settings => wake up GUI thread: */
191 if (m_enmDirection == Save)
192 m_condition.wakeAll();
193 /* Break further processing if page had failed: */
194 if (pPage->failed())
195 break;
196 }
197 /* Notify listeners about all pages were processed: */
198 emit sigNotifyAboutPagesProcessed();
199 /* If serializer saves settings => wake up GUI thread: */
200 if (m_enmDirection == Save)
201 m_condition.wakeAll();
202
203 /* Deinitialize COM for other thread: */
204 COMBase::CleanupCOM();
205}
206
207
208/*********************************************************************************************************************************
209* Class UISettingsSerializerProgress implementation. *
210*********************************************************************************************************************************/
211
212QString UISettingsSerializerProgress::s_strProgressDescriptionTemplate = QString("<compact elipsis=\"middle\">%1 (%2/%3)</compact>");
213
214UISettingsSerializerProgress::UISettingsSerializerProgress(QWidget *pParent,
215 UISettingsSerializer::SerializationDirection enmDirection,
216 const QVariant &data,
217 const UISettingsPageList &pages)
218 : QIDialog(pParent)
219 , m_enmDirection(enmDirection)
220 , m_data(data)
221 , m_pages(pages)
222 , m_pSerializer(0)
223 , m_pLabelOperationProgress(0)
224 , m_pBarOperationProgress(0)
225 , m_pLabelSubOperationProgress(0)
226 , m_pBarSubOperationProgress(0)
227 , m_fClean(true)
228{
229 /* Prepare: */
230 prepare();
231 /* Translate: */
232 sltRetranslateUI();
233 connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
234 this, &UISettingsSerializerProgress::sltRetranslateUI);
235}
236
237int UISettingsSerializerProgress::exec()
238{
239 /* Ask for process start: */
240 emit sigAskForProcessStart();
241
242 /* Call to base-class: */
243 return QIDialog::exec();
244}
245
246QVariant &UISettingsSerializerProgress::data()
247{
248 AssertPtrReturn(m_pSerializer, m_data);
249 return m_pSerializer->data();
250}
251
252void UISettingsSerializerProgress::prepare()
253{
254 /* Configure self: */
255 setWindowModality(Qt::WindowModal);
256 setWindowTitle(parentWidget()->windowTitle());
257 connect(this, &UISettingsSerializerProgress::sigAskForProcessStart,
258 this, &UISettingsSerializerProgress::sltStartProcess, Qt::QueuedConnection);
259
260 /* Create serializer: */
261 m_pSerializer = new UISettingsSerializer(this, m_enmDirection, m_data, m_pages);
262 AssertPtrReturnVoid(m_pSerializer);
263 {
264 /* Install progress handler: */
265 connect(m_pSerializer, &UISettingsSerializer::sigNotifyAboutProcessProgressChanged,
266 this, &UISettingsSerializerProgress::sltHandleProcessProgressChange);
267 connect(m_pSerializer, &UISettingsSerializer::sigOperationProgressChange,
268 this, &UISettingsSerializerProgress::sltHandleOperationProgressChange);
269 connect(m_pSerializer, &UISettingsSerializer::sigOperationProgressError,
270 this, &UISettingsSerializerProgress::sltHandleOperationProgressError);
271 }
272
273 /* Create layout: */
274 QVBoxLayout *pLayout = new QVBoxLayout(this);
275 AssertPtrReturnVoid(pLayout);
276 {
277 /* Create top layout: */
278 QHBoxLayout *pLayoutTop = new QHBoxLayout;
279 AssertPtrReturnVoid(pLayoutTop);
280 {
281 /* Create pixmap layout: */
282 QVBoxLayout *pLayoutPixmap = new QVBoxLayout;
283 AssertPtrReturnVoid(pLayoutPixmap);
284 {
285 /* Create pixmap label: */
286 QLabel *pLabelPixmap = new QLabel;
287 AssertPtrReturnVoid(pLabelPixmap);
288 {
289 /* Configure label: */
290 const QIcon icon = UIIconPool::iconSet(":/progress_settings_90px.png");
291 pLabelPixmap->setPixmap(icon.pixmap(icon.availableSizes().value(0, QSize(90, 90))));
292 /* Add label into layout: */
293 pLayoutPixmap->addWidget(pLabelPixmap);
294 }
295 /* Add stretch: */
296 pLayoutPixmap->addStretch();
297 /* Add layout into parent: */
298 pLayoutTop->addLayout(pLayoutPixmap);
299 }
300 /* Create progress layout: */
301 QVBoxLayout *pLayoutProgress = new QVBoxLayout;
302 AssertPtrReturnVoid(pLayoutProgress);
303 {
304 /* Create operation progress label: */
305 m_pLabelOperationProgress = new QLabel;
306 AssertPtrReturnVoid(m_pLabelOperationProgress);
307 {
308 /* Add label into layout: */
309 pLayoutProgress->addWidget(m_pLabelOperationProgress);
310 }
311 /* Create operation progress bar: */
312 m_pBarOperationProgress = new QProgressBar;
313 AssertPtrReturnVoid(m_pBarOperationProgress);
314 {
315 /* Configure progress bar: */
316 m_pBarOperationProgress->setMinimumWidth(300);
317 m_pBarOperationProgress->setMaximum(100);
318 m_pBarOperationProgress->setMinimum(0);
319 m_pBarOperationProgress->setValue(0);
320 /* Add bar into layout: */
321 pLayoutProgress->addWidget(m_pBarOperationProgress);
322 }
323 /* Create sub-operation progress label: */
324 m_pLabelSubOperationProgress = new QILabel;
325 AssertPtrReturnVoid(m_pLabelSubOperationProgress);
326 {
327 /* Configure label: */
328 m_pLabelSubOperationProgress->hide();
329 m_pLabelSubOperationProgress->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed));
330 /* Add label into layout: */
331 pLayoutProgress->addWidget(m_pLabelSubOperationProgress);
332 }
333 /* Create sub-operation progress bar: */
334 m_pBarSubOperationProgress = new QProgressBar;
335 AssertPtrReturnVoid(m_pBarSubOperationProgress);
336 {
337 /* Configure progress bar: */
338 m_pBarSubOperationProgress->hide();
339 m_pBarSubOperationProgress->setMinimumWidth(300);
340 m_pBarSubOperationProgress->setMaximum(100);
341 m_pBarSubOperationProgress->setMinimum(0);
342 m_pBarSubOperationProgress->setValue(0);
343 /* Add bar into layout: */
344 pLayoutProgress->addWidget(m_pBarSubOperationProgress);
345 }
346 /* Add stretch: */
347 pLayoutProgress->addStretch();
348 /* Add layout into parent: */
349 pLayoutTop->addLayout(pLayoutProgress);
350 }
351 /* Add layout into parent: */
352 pLayout->addLayout(pLayoutTop);
353 }
354 }
355}
356
357void UISettingsSerializerProgress::sltRetranslateUI()
358{
359 /* Translate operation progress label: */
360 AssertPtrReturnVoid(m_pLabelOperationProgress);
361 switch (m_pSerializer->direction())
362 {
363 case UISettingsSerializer::Load: m_pLabelOperationProgress->setText(tr("Loading Settings...")); break;
364 case UISettingsSerializer::Save: m_pLabelOperationProgress->setText(tr("Saving Settings...")); break;
365 }
366}
367
368void UISettingsSerializerProgress::closeEvent(QCloseEvent *pEvent)
369{
370 /* No need to close the dialog: */
371 pEvent->ignore();
372}
373
374void UISettingsSerializerProgress::reject()
375{
376 /* No need to reject the dialog. */
377}
378
379void UISettingsSerializerProgress::sltStartProcess()
380{
381 /* Start the serializer: */
382 m_pSerializer->start();
383}
384
385void UISettingsSerializerProgress::sltHandleProcessProgressChange(int iValue)
386{
387 /* Update the operation progress-bar with incoming value: */
388 AssertPtrReturnVoid(m_pBarOperationProgress);
389 m_pBarOperationProgress->setValue(iValue);
390 /* Hide the progress-dialog upon reaching the 100% progress: */
391 if (iValue == m_pBarOperationProgress->maximum())
392 hide();
393}
394
395void UISettingsSerializerProgress::sltHandleOperationProgressChange(ulong iOperations, QString strOperation,
396 ulong iOperation, ulong iPercent)
397{
398 /* Update the sub-operation progress label and bar: */
399 AssertPtrReturnVoid(m_pLabelSubOperationProgress);
400 AssertPtrReturnVoid(m_pBarSubOperationProgress);
401 m_pLabelSubOperationProgress->show();
402 m_pBarSubOperationProgress->show();
403 m_pLabelSubOperationProgress->setText(s_strProgressDescriptionTemplate.arg(strOperation).arg(iOperation).arg(iOperations));
404 m_pBarSubOperationProgress->setValue(iPercent);
405}
406
407void UISettingsSerializerProgress::sltHandleOperationProgressError(QString strErrorInfo)
408{
409 /* Mark the serialization process dirty: */
410 m_fClean = false;
411
412 /* Show the error message: */
413 msgCenter().cannotSaveSettings(strErrorInfo, this);
414}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use