VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/notificationcenter/UINotificationObjectItem.cpp@ 100347

Last change on this file since 100347 was 99946, checked in by vboxsync, 20 months ago

FE/Qt: bugref:10451. Refactoring the code which kicks of the help browser and navigates to the selected keyword in case it is there.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.6 KB
Line 
1/* $Id: UINotificationObjectItem.cpp 99946 2023-05-24 06:53:04Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UINotificationObjectItem class implementation.
4 */
5
6/*
7 * Copyright (C) 2021-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 <QApplication>
30#include <QFont>
31#include <QHBoxLayout>
32#include <QLabel>
33#include <QPainter>
34#include <QPaintEvent>
35#include <QProgressBar>
36#include <QVBoxLayout>
37
38/* GUI includes: */
39#include "QIRichTextLabel.h"
40#include "QIToolButton.h"
41#include "UIHelpBrowserDialog.h"
42#include "UIIconPool.h"
43#include "UIMessageCenter.h"
44#include "UINotificationObject.h"
45#include "UINotificationObjectItem.h"
46
47
48/*********************************************************************************************************************************
49* Class UINotificationObjectItem implementation. *
50*********************************************************************************************************************************/
51
52UINotificationObjectItem::UINotificationObjectItem(QWidget *pParent, UINotificationObject *pObject /* = 0 */)
53 : QWidget(pParent)
54 , m_pObject(pObject)
55 , m_pLayoutMain(0)
56 , m_pLayoutUpper(0)
57 , m_pLabelName(0)
58 , m_pButtonHelp(0)
59 , m_pButtonForget(0)
60 , m_pButtonClose(0)
61 , m_pLabelDetails(0)
62 , m_fHovered(false)
63 , m_fToggled(false)
64{
65 /* Make sure item is opaque. */
66 setAutoFillBackground(true);
67
68 /* Prepare main layout: */
69 m_pLayoutMain = new QVBoxLayout(this);
70 if (m_pLayoutMain)
71 {
72 /* Prepare upper layout: */
73 m_pLayoutUpper = new QHBoxLayout;
74 if (m_pLayoutUpper)
75 {
76 /* Prepare name label: */
77 m_pLabelName = new QLabel(this);
78 if (m_pLabelName)
79 {
80 m_pLabelName->setText(m_pObject->name());
81 m_pLayoutUpper->addWidget(m_pLabelName);
82 }
83
84 /* Prepare help button: */
85 if (!m_pObject->helpKeyword().isEmpty())
86 m_pButtonHelp = new QIToolButton(this);
87 if (m_pButtonHelp)
88 {
89 m_pButtonHelp->setIcon(UIIconPool::iconSet(":/help_16px.png"));
90 m_pButtonHelp->setIconSize(QSize(10, 10));
91 m_pButtonHelp->setProperty("helpkeyword", m_pObject->helpKeyword());
92 connect(m_pButtonHelp, &QIToolButton::clicked,
93 this, &UINotificationObjectItem::sltHandleHelpRequest);
94
95 m_pLayoutUpper->addWidget(m_pButtonHelp);
96 }
97
98 /* Prepare forget button: */
99 if (!m_pObject->internalName().isEmpty())
100 m_pButtonForget = new QIToolButton(this);
101 if (m_pButtonForget)
102 {
103 m_pButtonForget->setIcon(UIIconPool::iconSet(":/close_popup_16px.png"));
104 m_pButtonForget->setIconSize(QSize(10, 10));
105 connect(m_pButtonForget, &QIToolButton::clicked,
106 m_pObject, &UINotificationObject::dismiss);
107
108 m_pLayoutUpper->addWidget(m_pButtonForget);
109 }
110
111 /* Prepare close button: */
112 m_pButtonClose = new QIToolButton(this);
113 if (m_pButtonClose)
114 {
115 m_pButtonClose->setIcon(UIIconPool::iconSet(":/close_16px.png"));
116 m_pButtonClose->setIconSize(QSize(10, 10));
117 connect(m_pButtonClose, &QIToolButton::clicked,
118 m_pObject, &UINotificationObject::close);
119
120 m_pLayoutUpper->addWidget(m_pButtonClose);
121 }
122
123 /* Add to layout: */
124 m_pLayoutMain->addLayout(m_pLayoutUpper);
125 }
126
127 /* Prepare details label: */
128 m_pLabelDetails = new QIRichTextLabel(this);
129 if (m_pLabelDetails)
130 {
131 QFont myFont = m_pLabelDetails->font();
132 myFont.setPointSize(myFont.pointSize() - 1);
133 m_pLabelDetails->setBrowserFont(myFont);
134 m_pLabelDetails->setVisible(false);
135 int iHint = m_pLabelName->minimumSizeHint().width();
136 if (m_pButtonHelp)
137 iHint += m_pLayoutUpper->spacing() + m_pButtonHelp->minimumSizeHint().width();
138 if (m_pButtonForget)
139 iHint += m_pLayoutUpper->spacing() + m_pButtonForget->minimumSizeHint().width();
140 if (m_pButtonClose)
141 iHint += m_pLayoutUpper->spacing() + m_pButtonClose->minimumSizeHint().width();
142 m_pLabelDetails->setMinimumTextWidth(iHint);
143 m_pLabelDetails->setText(m_pObject->details());
144
145 m_pLayoutMain->addWidget(m_pLabelDetails);
146 }
147 }
148}
149
150bool UINotificationObjectItem::event(QEvent *pEvent)
151{
152 /* Handle required event types: */
153 switch (pEvent->type())
154 {
155 case QEvent::Enter:
156 case QEvent::MouseMove:
157 {
158 m_fHovered = true;
159 update();
160 break;
161 }
162 case QEvent::Leave:
163 {
164 m_fHovered = false;
165 update();
166 break;
167 }
168 case QEvent::MouseButtonRelease:
169 {
170 m_fToggled = !m_fToggled;
171 m_pLabelDetails->setVisible(m_fToggled);
172 break;
173 }
174 default:
175 break;
176 }
177
178 /* Call to base-class: */
179 return QWidget::event(pEvent);
180}
181
182void UINotificationObjectItem::paintEvent(QPaintEvent *pPaintEvent)
183{
184 /* Prepare painter: */
185 QPainter painter(this);
186 painter.setClipRect(pPaintEvent->rect());
187 /* Acquire palette: */
188 const bool fActive = isActiveWindow();
189 QPalette pal = QApplication::palette();
190
191 /* Gather suitable colors: */
192 QColor color = pal.color(fActive ? QPalette::Active : QPalette::Inactive, QPalette::Window);
193 QColor color1;
194 QColor color2;
195 if (color.black() > 128)
196 {
197 color1 = color.lighter(110);
198 color2 = color.lighter(105);
199 }
200 else
201 {
202 color1 = color.darker(105);
203 color2 = color.darker(110);
204 }
205 /* Prepare background gradient: */
206 QLinearGradient grad(QPointF(0, 0), QPointF(width(), height()));
207 {
208 grad.setColorAt(0, color1);
209 grad.setColorAt(1, color2);
210 }
211 /* Fill background: */
212 painter.fillRect(rect(), grad);
213
214 /* If item is hovered: */
215 if (m_fHovered)
216 {
217 /* Gather suitable color: */
218 QColor color3 = pal.color(fActive ? QPalette::Active : QPalette::Inactive, QPalette::Highlight);
219 /* Override painter pen: */
220 painter.setPen(color3);
221 /* Draw frame: */
222 painter.drawRect(rect());
223 }
224}
225
226
227/*********************************************************************************************************************************
228* Class UINotificationProgressItem implementation. *
229*********************************************************************************************************************************/
230
231UINotificationProgressItem::UINotificationProgressItem(QWidget *pParent, UINotificationProgress *pProgress /* = 0 */)
232 : UINotificationObjectItem(pParent, pProgress)
233 , m_pProgressBar(0)
234{
235 /* Main layout was prepared in base-class: */
236 if (m_pLayoutMain)
237 {
238 /* Name label was prepared in base-class: */
239 if (m_pLabelName)
240 m_pLabelName->setText(progress()->name());
241 /* Details label was prepared in base-class: */
242 if (m_pLabelDetails)
243 {
244 const int iHint = m_pLabelName->minimumSizeHint().width()
245 + m_pLayoutUpper->spacing()
246 + m_pButtonClose->minimumSizeHint().width();
247 m_pLabelDetails->setMinimumTextWidth(iHint);
248 updateDetails();
249 }
250
251 /* Prepare progress-bar: */
252 m_pProgressBar = new QProgressBar(this);
253 if (m_pProgressBar)
254 {
255 m_pProgressBar->setMinimum(0);
256 m_pProgressBar->setMaximum(100);
257 m_pProgressBar->setValue(progress()->percent());
258
259 m_pLayoutMain->addWidget(m_pProgressBar);
260 }
261 }
262
263 /* Prepare progress connections: */
264 connect(progress(), &UINotificationProgress::sigProgressStarted,
265 this, &UINotificationProgressItem::sltHandleProgressStarted);
266 connect(progress(), &UINotificationProgress::sigProgressChange,
267 this, &UINotificationProgressItem::sltHandleProgressChange);
268 connect(progress(), &UINotificationProgress::sigProgressFinished,
269 this, &UINotificationProgressItem::sltHandleProgressFinished);
270}
271
272void UINotificationProgressItem::sltHandleProgressStarted()
273{
274 /* Init close-button and progress-bar states: */
275 if (m_pButtonClose)
276 m_pButtonClose->setEnabled(progress()->isCancelable());
277 if (m_pProgressBar)
278 m_pProgressBar->setValue(0);
279 /* Update details with fetched stuff if any: */
280 if (m_pLabelDetails)
281 updateDetails();
282}
283
284void UINotificationProgressItem::sltHandleProgressChange(ulong uPercent)
285{
286 /* Update close-button and progress-bar states: */
287 if (m_pButtonClose)
288 m_pButtonClose->setEnabled(progress()->isCancelable());
289 if (m_pProgressBar)
290 m_pProgressBar->setValue(uPercent);
291}
292
293void UINotificationProgressItem::sltHandleProgressFinished()
294{
295 /* Finalize close-button and progress-bar states: */
296 if (m_pButtonClose)
297 m_pButtonClose->setEnabled(true);
298 if (m_pProgressBar)
299 m_pProgressBar->setValue(100);
300 /* Update details with error text if any: */
301 if (m_pLabelDetails)
302 updateDetails();
303}
304
305UINotificationProgress *UINotificationProgressItem::progress() const
306{
307 return qobject_cast<UINotificationProgress*>(m_pObject);
308}
309
310void UINotificationProgressItem::updateDetails()
311{
312 AssertPtrReturnVoid(m_pLabelDetails);
313 const QString strDetails = progress()->details();
314 const QString strError = progress()->error();
315 const QString strFullDetails = strError.isNull()
316 ? strDetails
317 : QString("%1<br>%2").arg(strDetails, strError);
318 m_pLabelDetails->setText(strFullDetails);
319 if (!strError.isEmpty())
320 {
321 m_fToggled = true;
322 m_pLabelDetails->setVisible(m_fToggled);
323 }
324}
325
326
327#ifdef VBOX_GUI_WITH_NETWORK_MANAGER
328
329
330/*********************************************************************************************************************************
331* Class UINotificationDownloaderItem implementation. *
332*********************************************************************************************************************************/
333
334UINotificationDownloaderItem::UINotificationDownloaderItem(QWidget *pParent, UINotificationDownloader *pDownloader /* = 0 */)
335 : UINotificationObjectItem(pParent, pDownloader)
336 , m_pProgressBar(0)
337{
338 /* Main layout was prepared in base-class: */
339 if (m_pLayoutMain)
340 {
341 /* Name label was prepared in base-class: */
342 if (m_pLabelName)
343 m_pLabelName->setText(downloader()->name());
344 /* Details label was prepared in base-class: */
345 if (m_pLabelDetails)
346 {
347 const int iHint = m_pLabelName->minimumSizeHint().width()
348 + m_pLayoutUpper->spacing()
349 + m_pButtonClose->minimumSizeHint().width();
350 m_pLabelDetails->setMinimumTextWidth(iHint);
351 updateDetails();
352 }
353
354 /* Prepare progress-bar: */
355 m_pProgressBar = new QProgressBar(this);
356 if (m_pProgressBar)
357 {
358 m_pProgressBar->setMinimum(0);
359 m_pProgressBar->setMaximum(100);
360 m_pProgressBar->setValue(downloader()->percent());
361
362 m_pLayoutMain->addWidget(m_pProgressBar);
363 }
364 }
365
366 /* Prepare downloader connections: */
367 connect(downloader(), &UINotificationDownloader::sigProgressStarted,
368 this, &UINotificationDownloaderItem::sltHandleProgressStarted);
369 connect(downloader(), &UINotificationDownloader::sigProgressChange,
370 this, &UINotificationDownloaderItem::sltHandleProgressChange);
371 connect(downloader(), &UINotificationDownloader::sigProgressFailed,
372 this, &UINotificationDownloaderItem::sltHandleProgressFinished);
373 connect(downloader(), &UINotificationDownloader::sigProgressCanceled,
374 this, &UINotificationDownloaderItem::sltHandleProgressFinished);
375 connect(downloader(), &UINotificationDownloader::sigProgressFinished,
376 this, &UINotificationDownloaderItem::sltHandleProgressFinished);
377}
378
379void UINotificationDownloaderItem::sltHandleProgressStarted()
380{
381 /* Init progress-bar state: */
382 if (m_pProgressBar)
383 m_pProgressBar->setValue(0);
384 /* Update details with fetched stuff if any: */
385 if (m_pLabelDetails)
386 updateDetails();
387}
388
389void UINotificationDownloaderItem::sltHandleProgressChange(ulong uPercent)
390{
391 /* Update progress-bar state: */
392 if (m_pProgressBar)
393 m_pProgressBar->setValue(uPercent);
394}
395
396void UINotificationDownloaderItem::sltHandleProgressFinished()
397{
398 /* Finalize progress-bar state: */
399 if (m_pProgressBar)
400 m_pProgressBar->setValue(100);
401 /* Update details with error text if any: */
402 if (m_pLabelDetails)
403 updateDetails();
404}
405
406UINotificationDownloader *UINotificationDownloaderItem::downloader() const
407{
408 return qobject_cast<UINotificationDownloader*>(m_pObject);
409}
410
411void UINotificationDownloaderItem::updateDetails()
412{
413 AssertPtrReturnVoid(m_pLabelDetails);
414 const QString strDetails = downloader()->details();
415 const QString strError = downloader()->error();
416 const QString strFullDetails = strError.isNull()
417 ? strDetails
418 : QString("%1<br>%2").arg(strDetails, strError);
419 m_pLabelDetails->setText(strFullDetails);
420 if (!strError.isEmpty())
421 {
422 m_fToggled = true;
423 m_pLabelDetails->setVisible(m_fToggled);
424 }
425}
426
427#endif /* VBOX_GUI_WITH_NETWORK_MANAGER */
428
429
430/*********************************************************************************************************************************
431* Namespace UINotificationProgressItem implementation. *
432*********************************************************************************************************************************/
433
434UINotificationObjectItem *UINotificationItem::create(QWidget *pParent, UINotificationObject *pObject)
435{
436 /* Handle known types: */
437 if (pObject->inherits("UINotificationProgress"))
438 return new UINotificationProgressItem(pParent, static_cast<UINotificationProgress*>(pObject));
439#ifdef VBOX_GUI_WITH_NETWORK_MANAGER
440 else if (pObject->inherits("UINotificationDownloader"))
441 return new UINotificationDownloaderItem(pParent, static_cast<UINotificationDownloader*>(pObject));
442#endif
443 /* Handle defaults: */
444 return new UINotificationObjectItem(pParent, pObject);
445}
446
447void UINotificationObjectItem::sltHandleHelpRequest()
448{
449 UIHelpBrowserDialog::findManualFileAndShow("helpkeyword");
450}
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