VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/extensions/QIArrowSplitter.cpp@ 98103

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

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.3 KB
RevLine 
[26714]1/* $Id: QIArrowSplitter.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
[25177]2/** @file
[71900]3 * VBox Qt GUI - Qt extensions: QIArrowSplitter class implementation.
[25177]4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[25177]8 *
[96407]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
[25177]26 */
27
[51873]28/* Qt includes: */
[76606]29#include <QApplication>
30#include <QHBoxLayout>
31#include <QStyle>
32#include <QTextEdit>
[25177]33
[51873]34/* GUI includes: */
[76606]35#include "QIArrowSplitter.h"
36#include "QIArrowButtonPress.h"
37#include "QIArrowButtonSwitch.h"
38#include "UIDesktopWidgetWatchdog.h"
39#include "UIIconPool.h"
[51873]40
41/* Other VBox includes: */
[76606]42#include "iprt/assert.h"
[51873]43
44
45/** QTextEdit extension
46 * taking into account text-document size-hint.
47 * @note Used with QIMessageBox class only.
48 * @todo Should be moved/renamed accordingly. */
49class QIDetailsBrowser : public QTextEdit
[25177]50{
[51873]51 Q_OBJECT;
[25177]52
[51873]53public:
[25177]54
[71395]55 /** Constructs details-browser passing @a pParent to the base-class. */
[51873]56 QIDetailsBrowser(QWidget *pParent = 0);
[25177]57
[51873]58 /** Returns minimum size-hint. */
59 QSize minimumSizeHint() const;
60 /** Returns size-hint. */
61 QSize sizeHint() const;
[25177]62
[51873]63 /** Update scroll-bars. */
64 void updateScrollBars();
65};
[25177]66
[71395]67
68/*********************************************************************************************************************************
69* Class QIDetailsBrowser implementation. *
70*********************************************************************************************************************************/
71
[51873]72QIDetailsBrowser::QIDetailsBrowser(QWidget *pParent /* = 0 */)
73 : QTextEdit(pParent)
74{
75 /* Prepare: */
76 setReadOnly(true);
77}
[45307]78
[51873]79QSize QIDetailsBrowser::minimumSizeHint() const
80{
81 /* Get document size as the basis: */
82 QSize documentSize = document()->size().toSize();
83 /* But only document ideal-width can advice wise width: */
[56217]84 const int iDocumentIdealWidth = (int)document()->idealWidth();
[51873]85 /* Moreover we should take document margins into account: */
[56217]86 const int iDocumentMargin = (int)document()->documentMargin();
[51873]87
88 /* Compose minimum size-hint on the basis of values above: */
89 documentSize.setWidth(iDocumentIdealWidth + iDocumentMargin);
90 documentSize.setHeight(documentSize.height() + iDocumentMargin);
91
92 /* Get 40% of the screen-area to limit the resulting hint: */
[97682]93 const QSize screenGeometryDot4 = gpDesktop->screenGeometry(this).size() * .4;
[51873]94
95 /* Calculate minimum size-hint which is document-size limited by screen-area: */
96 QSize mSizeHint = documentSize.boundedTo(screenGeometryDot4);
97
98 /* If there is not enough of vertical space: */
99 if (mSizeHint.height() < documentSize.height())
100 {
101 /* We should also take into account vertical scroll-bar extent: */
102 int iExtent = QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent);
103 mSizeHint.setWidth(mSizeHint.width() + iExtent);
104 }
105
106 /* Always bound cached hint by 40% of current screen-area: */
107 return mSizeHint;
[25177]108}
109
[51873]110QSize QIDetailsBrowser::sizeHint() const
[25177]111{
[51873]112 /* Return minimum size-hint: */
113 return minimumSizeHint();
[25177]114}
115
[51873]116void QIDetailsBrowser::updateScrollBars()
[25177]117{
[51873]118 /* Some Qt issue prevents scroll-bars from update.. */
119 Qt::ScrollBarPolicy horizontalPolicy = horizontalScrollBarPolicy();
120 Qt::ScrollBarPolicy verticalPolicy = verticalScrollBarPolicy();
121 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
122 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
123 setHorizontalScrollBarPolicy(horizontalPolicy);
124 setVerticalScrollBarPolicy(verticalPolicy);
[25177]125}
126
[51873]127
[71395]128/*********************************************************************************************************************************
129* Class QIArrowSplitter implementation. *
130*********************************************************************************************************************************/
131
[51873]132QIArrowSplitter::QIArrowSplitter(QWidget *pParent /* = 0 */)
133 : QIWithRetranslateUI<QWidget>(pParent)
134 , m_pMainLayout(0)
135 , m_pSwitchButton(0)
136 , m_pBackButton(0)
137 , m_pNextButton(0)
138 , m_pDetailsBrowser(0)
139 , m_iDetailsIndex(-1)
[25177]140{
[51873]141 /* Prepare: */
142 prepare();
[25177]143}
144
[45307]145QSize QIArrowSplitter::minimumSizeHint() const
146{
[51873]147 /* Get minimum size-hints: */
148 const QSize switchButtonHint = m_pSwitchButton->minimumSizeHint();
149 const QSize backButtonHint = m_pBackButton->minimumSizeHint();
150 const QSize nextButtonHint = m_pNextButton->minimumSizeHint();
151 const QSize detailsBrowserHint = m_pDetailsBrowser->minimumSizeHint();
[45307]152
153 /* Calculate width-hint: */
154 int iWidthHint = 0;
155 iWidthHint += switchButtonHint.width();
[51873]156 iWidthHint += 100 /* button spacing */;
[45307]157 iWidthHint += backButtonHint.width();
158 iWidthHint += nextButtonHint.width();
[51873]159 iWidthHint = qMax(iWidthHint, detailsBrowserHint.width());
[45307]160
161 /* Calculate height-hint: */
162 int iHeightHint = 0;
163 iHeightHint = qMax(iHeightHint, switchButtonHint.height());
164 iHeightHint = qMax(iHeightHint, backButtonHint.height());
165 iHeightHint = qMax(iHeightHint, nextButtonHint.height());
[51873]166 if (m_pDetailsBrowser->isVisible())
167 iHeightHint += m_pMainLayout->spacing() + detailsBrowserHint.height();
[45307]168
169 /* Return result: */
170 return QSize(iWidthHint, iHeightHint);
171}
172
[51873]173void QIArrowSplitter::setName(const QString &strName)
[25177]174{
[51873]175 /* Assign name for the switch-button: */
176 m_pSwitchButton->setText(strName);
177 /* Update size-hints: */
178 sltUpdateSizeHints();
[25177]179}
180
[51873]181void QIArrowSplitter::setDetails(const QStringPairList &details)
[25177]182{
[51873]183 /* Assign new details: */
184 m_details = details;
185 /* Reset the details-list index: */
186 m_iDetailsIndex = m_details.isEmpty() ? -1 : 0;
187 /* Update navigation-buttons visibility: */
188 sltUpdateNavigationButtonsVisibility();
189 /* Update details-browser visibility: */
190 sltUpdateDetailsBrowserVisibility();
191 /* Update details: */
192 updateDetails();
193}
[25177]194
[51873]195void QIArrowSplitter::sltUpdateSizeHints()
196{
197 /* Let parent layout know our size-hint changed: */
198 updateGeometry();
199 /* Notify parent about our size-hint changed: */
200 emit sigSizeHintChange();
201 /* Update details-browser scroll-bars: */
202 m_pDetailsBrowser->updateScrollBars();
203}
[25177]204
[51873]205void QIArrowSplitter::sltUpdateNavigationButtonsVisibility()
206{
207 /* Depending on switch-button state: */
208 const bool fExpanded = m_pSwitchButton->isExpanded();
209 /* Update back/next button visibility: */
210 m_pBackButton->setVisible(m_details.size() > 1 && fExpanded);
211 m_pNextButton->setVisible(m_details.size() > 1 && fExpanded);
212}
213
214void QIArrowSplitter::sltUpdateDetailsBrowserVisibility()
215{
216 /* Update details-browser visibility according switch-button state: */
217 m_pDetailsBrowser->setVisible(m_details.size() > 0 && m_pSwitchButton->isExpanded());
218 /* Update size-hints: */
219 sltUpdateSizeHints();
220}
221
222void QIArrowSplitter::sltSwitchDetailsPageBack()
223{
224 /* Make sure details-page index feats the bounds: */
225 AssertReturnVoid(m_iDetailsIndex > 0);
226 /* Decrease details-list index: */
227 --m_iDetailsIndex;
228 /* Update details: */
229 updateDetails();
230}
231
232void QIArrowSplitter::sltSwitchDetailsPageNext()
233{
234 /* Make sure details-page index feats the bounds: */
235 AssertReturnVoid(m_iDetailsIndex < m_details.size() - 1);
236 /* Increase details-list index: */
237 ++m_iDetailsIndex;
238 /* Update details: */
239 updateDetails();
240}
241
[71395]242void QIArrowSplitter::retranslateUi()
243{
244 /* Update details: */
245 updateDetails();
246}
247
[51873]248void QIArrowSplitter::prepare()
249{
250 /* Create main-layout: */
251 m_pMainLayout = new QVBoxLayout(this);
252 AssertPtrReturnVoid(m_pMainLayout);
[25177]253 {
[51873]254 /* Configure main-layout: */
255 m_pMainLayout->setContentsMargins(0, 0, 0, 0);
[70523]256#ifdef VBOX_WS_MAC
257 m_pMainLayout->setSpacing(5);
258#else
259 m_pMainLayout->setSpacing(qApp->style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing) / 2);
260#endif
[51873]261 /* Create button-layout: */
262 QHBoxLayout *pButtonLayout = new QHBoxLayout;
263 AssertPtrReturnVoid(pButtonLayout);
[25177]264 {
[55932]265 /* Determine icon metric: */
266 const QStyle *pStyle = QApplication::style();
[56217]267 const int iIconMetric = (int)(pStyle->pixelMetric(QStyle::PM_SmallIconSize) * .625);
[51873]268 /* Configure button-layout: */
269 pButtonLayout->setContentsMargins(0, 0, 0, 0);
270 pButtonLayout->setSpacing(0);
271 /* Create switch-button: */
272 m_pSwitchButton = new QIArrowButtonSwitch;
273 AssertPtrReturnVoid(m_pSwitchButton);
[25177]274 {
[51873]275 /* Configure switch-button: */
[55932]276 m_pSwitchButton->setIconSize(QSize(iIconMetric, iIconMetric));
[62143]277 m_pSwitchButton->setIcons(UIIconPool::iconSet(":/arrow_right_10px.png"),
278 UIIconPool::iconSet(":/arrow_down_10px.png"));
[68079]279 connect(m_pSwitchButton, &QIArrowButtonSwitch::sigClicked, this, &QIArrowSplitter::sltUpdateNavigationButtonsVisibility);
280 connect(m_pSwitchButton, &QIArrowButtonSwitch::sigClicked, this, &QIArrowSplitter::sltUpdateDetailsBrowserVisibility);
281
[51873]282 /* Add switch-button into button-layout: */
283 pButtonLayout->addWidget(m_pSwitchButton);
[25177]284 }
[51873]285 /* Add stretch: */
286 pButtonLayout->addStretch();
287 /* Create back-button: */
288 m_pBackButton = new QIArrowButtonPress(QIArrowButtonPress::ButtonType_Back);
289 AssertPtrReturnVoid(m_pBackButton);
[25177]290 {
[51873]291 /* Configure back-button: */
[55932]292 m_pBackButton->setIconSize(QSize(iIconMetric, iIconMetric));
[51873]293 m_pBackButton->setIcon(UIIconPool::iconSet(":/arrow_left_10px.png"));
[68079]294 connect(m_pBackButton, &QIArrowButtonPress::sigClicked, this, &QIArrowSplitter::sltSwitchDetailsPageBack);
295
[51873]296 /* Add back-button into button-layout: */
297 pButtonLayout->addWidget(m_pBackButton);
[25177]298 }
[51873]299 /* Create next-button: */
300 m_pNextButton = new QIArrowButtonPress(QIArrowButtonPress::ButtonType_Next);
301 AssertPtrReturnVoid(m_pNextButton);
[25177]302 {
[51873]303 /* Configure next-button: */
[55932]304 m_pNextButton->setIconSize(QSize(iIconMetric, iIconMetric));
[51873]305 m_pNextButton->setIcon(UIIconPool::iconSet(":/arrow_right_10px.png"));
[68079]306 connect(m_pNextButton, &QIArrowButtonPress::sigClicked, this, &QIArrowSplitter::sltSwitchDetailsPageNext);
307
[51873]308 /* Add next-button into button-layout: */
309 pButtonLayout->addWidget(m_pNextButton);
[25177]310 }
[51873]311 /* Add button layout into main-layout: */
312 m_pMainLayout->addLayout(pButtonLayout);
313 /* Update navigation-buttons visibility: */
314 sltUpdateNavigationButtonsVisibility();
[25177]315 }
[51873]316 /* Create details-browser: */
317 m_pDetailsBrowser = new QIDetailsBrowser;
318 AssertPtrReturnVoid(m_pDetailsBrowser);
319 {
320 /* Add details-browser into main-layout: */
321 m_pMainLayout->addWidget(m_pDetailsBrowser);
322 /* Update details-browser visibility: */
323 sltUpdateDetailsBrowserVisibility();
324 /* Update details: */
325 updateDetails();
326 }
[25177]327 }
328
[51873]329 /* Apply size-policy finally: */
330 setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
[25177]331}
332
[51873]333void QIArrowSplitter::updateDetails()
334{
335 /* If details are empty: */
336 if (m_details.isEmpty())
337 {
338 /* Make sure details-list index is invalid: */
339 AssertReturnVoid(m_iDetailsIndex == -1);
340
341 /* Reset name: */
342 setName(QString());
343 }
344 /* If details are NOT empty: */
345 else
346 {
347 /* Make sure details-list index feats the bounds: */
348 AssertReturnVoid(m_iDetailsIndex >= 0 && m_iDetailsIndex < m_details.size());
349
350 /* Single page: */
351 if (m_details.size() == 1)
352 {
[62038]353 setName(tr("&Details"));
[51873]354 m_pBackButton->setEnabled(false);
355 m_pNextButton->setEnabled(false);
356 }
357 /* Multi-paging: */
358 else if (m_details.size() > 1)
359 {
[62038]360 setName(tr("&Details (%1 of %2)").arg(m_iDetailsIndex + 1).arg(m_details.size()));
[51873]361 m_pBackButton->setEnabled(m_iDetailsIndex > 0);
362 m_pNextButton->setEnabled(m_iDetailsIndex < m_details.size() - 1);
363 }
364
365 /* Update details-browser: */
366 const QString strFirstPart = m_details[m_iDetailsIndex].first;
367 const QString strSecondPart = m_details[m_iDetailsIndex].second;
368 if (strFirstPart.isEmpty())
369 m_pDetailsBrowser->setText(strSecondPart);
370 else
371 m_pDetailsBrowser->setText(QString("%1<br>%2").arg(strFirstPart, strSecondPart));
372 }
373 /* Update size-hints: */
374 sltUpdateSizeHints();
375}
376
[71900]377
[51873]378#include "QIArrowSplitter.moc"
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