VirtualBox

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

Last change on this file since 103977 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

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