VirtualBox

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

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

FE/Qt: bugref:8938. Converting connection syntaxes under settings.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use