VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/widgets/UIFileTableNavigationWidget.cpp@ 100347

Last change on this file since 100347 was 100324, checked in by vboxsync, 16 months ago

FE/Qt: bugref:6699, bugref:9080. A bit better API for forward/backward action toggle.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.1 KB
Line 
1/* $Id: UIFileTableNavigationWidget.cpp 100324 2023-06-28 12:35:20Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIFileTableNavigationWidget class definitions.
4 */
5
6/*
7 * Copyright (C) 2009-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 <QComboBox>
31#include <QDir>
32#include <QFont>
33#include <QHBoxLayout>
34#include <QLabel>
35#include <QLineEdit>
36#include <QStackedWidget>
37#include <QToolButton>
38
39/* GUI includes: */
40#include "UIFileTableNavigationWidget.h"
41#include "UIPathOperations.h"
42
43/* Other VBox includes: */
44#include <iprt/cdefs.h>
45
46
47/*********************************************************************************************************************************
48* UIFileManagerHistoryComboBox definition. *
49*********************************************************************************************************************************/
50/** A QCombo extension used as location history list in the UIFileTableNavigationWidget. */
51class UIFileManagerHistoryComboBox : public QComboBox
52{
53 Q_OBJECT;
54
55signals:
56
57 void sigHidePopup();
58
59public:
60
61 UIFileManagerHistoryComboBox(QWidget *pParent = 0);
62 /** Emit sigHidePopup as the popup is hidded. */
63 virtual void hidePopup() RT_OVERRIDE;
64};
65
66
67/*********************************************************************************************************************************
68* UIFileManagerBreadCrumbs definition. *
69*********************************************************************************************************************************/
70/** A QLabel extension. It shows the current path as text and hightligts the folder name
71 * as the mouse hovers over it. Clicking on the highlighted folder name make the file table to
72 * navigate to that folder. */
73class UIFileManagerBreadCrumbs : public QLabel
74{
75 Q_OBJECT;
76
77public:
78
79 UIFileManagerBreadCrumbs(QWidget *pParent = 0);
80 void setPath(const QString &strPath);
81 void setPathSeparator(const QChar &separator);
82
83protected:
84
85 virtual void resizeEvent(QResizeEvent *pEvent) RT_OVERRIDE;
86
87private:
88
89 QString m_strPath;
90 QChar m_pathSeparator;
91};
92
93
94/*********************************************************************************************************************************
95* UIFileManagerHistoryComboBox implementation. *
96*********************************************************************************************************************************/
97
98UIFileManagerHistoryComboBox::UIFileManagerHistoryComboBox(QWidget *pParent /* = 0 */)
99 :QComboBox(pParent)
100{
101
102}
103
104void UIFileManagerHistoryComboBox::hidePopup()
105{
106 QComboBox::hidePopup();
107 emit sigHidePopup();
108}
109
110
111/*********************************************************************************************************************************
112* UIFileManagerBreadCrumbs implementation. *
113*********************************************************************************************************************************/
114
115UIFileManagerBreadCrumbs::UIFileManagerBreadCrumbs(QWidget *pParent /* = 0 */)
116 :QLabel(pParent)
117 , m_pathSeparator('/')
118{
119 float fFontMult = 1.f;
120 QFont mFont = font();
121 if (mFont.pixelSize() == -1)
122 mFont.setPointSize(fFontMult * mFont.pointSize());
123 else
124 mFont.setPixelSize(fFontMult * mFont.pixelSize());
125 setFont(mFont);
126
127 setFrameShape(QFrame::Box);
128 setLineWidth(1);
129 setAutoFillBackground(true);
130 QPalette pal = QApplication::palette();
131 pal.setColor(QPalette::Active, QPalette::Window, pal.color(QPalette::Active, QPalette::Base));
132 setPalette(pal);
133 /* Allow the label become smaller than the current text. calling setpath in resizeEvent truncated the text anyway: */
134 setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
135}
136
137void UIFileManagerBreadCrumbs::setPath(const QString &strPath)
138{
139 m_strPath = strPath;
140
141 const QChar separator('/');
142 clear();
143
144 if (strPath.isEmpty())
145 return;
146
147 QStringList folderList = UIPathOperations::pathTrail(strPath);
148 folderList.push_front(separator);
149
150 QString strLabelText;
151 QVector<QString> strPathUpto;
152 strPathUpto.resize(folderList.size());
153
154 for (int i = 0; i < folderList.size(); ++i)
155 {
156 QString strFolder = UIPathOperations::removeTrailingDelimiters(folderList.at(i));
157 if (i != 0)
158 strPathUpto[i] = strPathUpto[i - 1];
159 if (i == 0 || i == folderList.size() - 1)
160 strPathUpto[i].append(QString("%1").arg(strFolder));
161 else
162 strPathUpto[i].append(QString("%1%2").arg(strFolder).arg(separator));
163 }
164
165 int iWidth = 0;
166 for (int i = folderList.size() - 1; i >= 0; --i)
167 {
168 QString strFolder = UIPathOperations::removeTrailingDelimiters(folderList.at(i)).replace('/', m_pathSeparator);
169 QString strWord = QString("<a href=\"%1\" style=\"color:black;text-decoration:none;\">%2</a>").arg(strPathUpto[i]).arg(strFolder);
170
171 if (i < folderList.size() - 1)
172 {
173#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
174 iWidth += fontMetrics().horizontalAdvance(" > ");
175#else
176 iWidth += fontMetrics().width(" > ");
177#endif
178 strWord.append("<b> > </b>");
179 }
180#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
181 iWidth += fontMetrics().horizontalAdvance(strFolder);
182#else
183 iWidth += fontMetrics().width(strFolder);
184#endif
185
186 if (iWidth < width())
187 strLabelText.prepend(strWord);
188 }
189 setText(strLabelText);
190}
191
192void UIFileManagerBreadCrumbs::setPathSeparator(const QChar &separator)
193{
194 m_pathSeparator = separator;
195}
196
197void UIFileManagerBreadCrumbs::resizeEvent(QResizeEvent *pEvent)
198{
199 /* Truncate the text the way we want: */
200 setPath(m_strPath);
201 QLabel::resizeEvent(pEvent);
202}
203
204
205/*********************************************************************************************************************************
206* UIFileTableNavigationWidget implementation. *
207*********************************************************************************************************************************/
208
209UIFileTableNavigationWidget::UIFileTableNavigationWidget(QWidget *pParent /* = 0 */)
210 :QWidget(pParent)
211 , m_pContainer(0)
212 , m_pBreadCrumbs(0)
213 , m_pHistoryComboBox(0)
214 , m_pAddressLineEdit(0)
215 , m_pSwitchButton(0)
216 , m_pathSeparator('/')
217{
218 prepare();
219}
220
221void UIFileTableNavigationWidget::setPath(const QString &strLocation)
222{
223 if (m_strCurrentPath == QDir::fromNativeSeparators(strLocation))
224 return;
225
226 m_strCurrentPath = QDir::fromNativeSeparators(strLocation);
227
228 if (m_pBreadCrumbs)
229 m_pBreadCrumbs->setPath(strLocation);
230
231 if (m_pHistoryComboBox)
232 {
233 QString strNativeLocation(strLocation);
234 strNativeLocation.replace('/', m_pathSeparator);
235 int itemIndex = m_pHistoryComboBox->findText(strNativeLocation,
236 Qt::MatchExactly | Qt::MatchCaseSensitive);
237 if (itemIndex == -1)
238 {
239 m_pHistoryComboBox->insertItem(m_pHistoryComboBox->count(), strNativeLocation);
240 itemIndex = m_pHistoryComboBox->count() - 1;
241 }
242 m_pHistoryComboBox->setCurrentIndex(itemIndex);
243 emit sigHistoryListChanged();
244 }
245}
246
247void UIFileTableNavigationWidget::reset()
248{
249 if (m_pHistoryComboBox)
250 {
251 m_pHistoryComboBox->blockSignals(true);
252 m_pHistoryComboBox->clear();
253 m_pHistoryComboBox->blockSignals(false);
254 emit sigHistoryListChanged();
255 }
256
257 if (m_pBreadCrumbs)
258 m_pBreadCrumbs->setPath(QString());
259}
260
261void UIFileTableNavigationWidget::setPathSeparator(const QChar &separator)
262{
263 m_pathSeparator = separator;
264 if (m_pBreadCrumbs)
265 m_pBreadCrumbs->setPathSeparator(m_pathSeparator);
266}
267
268bool UIFileTableNavigationWidget::canGoForward() const
269{
270 if (!m_pHistoryComboBox)
271 return false;
272 return (m_pHistoryComboBox->currentIndex() < m_pHistoryComboBox->count() - 1);
273}
274
275bool UIFileTableNavigationWidget::canGoBackward() const
276{
277 if (!m_pHistoryComboBox)
278 return false;
279 return (m_pHistoryComboBox->currentIndex() > 0);
280}
281
282
283void UIFileTableNavigationWidget::goForwardInHistory()
284{
285 if (!m_pHistoryComboBox || m_pHistoryComboBox->currentIndex() >= m_pHistoryComboBox->count() - 1)
286 return;
287 m_pHistoryComboBox->setCurrentIndex(m_pHistoryComboBox->currentIndex() + 1);
288}
289
290void UIFileTableNavigationWidget::goBackwardInHistory()
291{
292 if (!m_pHistoryComboBox || m_pHistoryComboBox->currentIndex() <= 0)
293 return;
294 m_pHistoryComboBox->setCurrentIndex(m_pHistoryComboBox->currentIndex() - 1);
295}
296
297void UIFileTableNavigationWidget::prepare()
298{
299 QHBoxLayout *pLayout = new QHBoxLayout;
300 if (!pLayout)
301 return;
302 pLayout->setSpacing(0);
303 pLayout->setContentsMargins(0, 0, 0, 0);
304
305 m_pContainer = new QStackedWidget;
306 if (m_pContainer)
307 {
308 m_pBreadCrumbs = new UIFileManagerBreadCrumbs;
309 m_pHistoryComboBox = new UIFileManagerHistoryComboBox;
310 m_pAddressLineEdit = new QLineEdit;
311 if (m_pBreadCrumbs && m_pHistoryComboBox)
312 {
313 m_pBreadCrumbs->setIndent(0.5 * qApp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin));
314 m_pBreadCrumbs->installEventFilter(this);
315 m_pAddressLineEdit->installEventFilter(this);
316 connect(m_pBreadCrumbs, &UIFileManagerBreadCrumbs::linkActivated,
317 this, &UIFileTableNavigationWidget::sltHandlePathChange);
318 connect(m_pHistoryComboBox, &UIFileManagerHistoryComboBox::sigHidePopup,
319 this, &UIFileTableNavigationWidget::sltHandleHidePopup);
320 connect(m_pHistoryComboBox, &UIFileManagerHistoryComboBox::currentTextChanged,
321 this, &UIFileTableNavigationWidget::sltHandlePathChange);
322 connect(m_pAddressLineEdit, &QLineEdit::returnPressed,
323 this, &UIFileTableNavigationWidget::sltAddressLineEdited);
324 m_pContainer->insertWidget(StackedWidgets_BreadCrumbs, m_pBreadCrumbs);
325 m_pContainer->insertWidget(StackedWidgets_History, m_pHistoryComboBox);
326 m_pContainer->insertWidget(StackedWidgets_AddressLine, m_pAddressLineEdit);
327 m_pContainer->setCurrentIndex(StackedWidgets_BreadCrumbs);
328 }
329 pLayout->addWidget(m_pContainer);
330 }
331
332 m_pSwitchButton = new QToolButton;
333 if (m_pSwitchButton)
334 {
335 QStyle *pStyle = QApplication::style();
336 QIcon buttonIcon;
337 if (pStyle)
338 {
339 buttonIcon = pStyle->standardIcon(QStyle::SP_TitleBarUnshadeButton);
340 m_pSwitchButton->setIcon(buttonIcon);
341 }
342 pLayout->addWidget(m_pSwitchButton);
343 connect(m_pSwitchButton, &QToolButton::clicked,
344 this, &UIFileTableNavigationWidget::sltHandleSwitch);
345 }
346 setLayout(pLayout);
347}
348
349bool UIFileTableNavigationWidget::eventFilter(QObject *pObject, QEvent *pEvent)
350{
351 if (pObject == m_pBreadCrumbs && pEvent && pEvent->type() == QEvent::MouseButtonDblClick)
352 {
353 m_pContainer->setCurrentIndex(StackedWidgets_AddressLine);
354 m_pAddressLineEdit->setText(QDir::toNativeSeparators(m_strCurrentPath));
355 m_pAddressLineEdit->setFocus();
356
357 }
358 else if(pObject == m_pAddressLineEdit && pEvent && pEvent->type() == QEvent::FocusOut)
359 m_pContainer->setCurrentIndex(StackedWidgets_BreadCrumbs);
360
361 return QWidget::eventFilter(pObject, pEvent);
362}
363
364void UIFileTableNavigationWidget::sltHandleHidePopup()
365{
366 m_pContainer->setCurrentIndex(StackedWidgets_BreadCrumbs);
367}
368
369void UIFileTableNavigationWidget::sltHandlePathChange(const QString &strPath)
370{
371 emit sigPathChanged(QDir::fromNativeSeparators(strPath));
372}
373
374void UIFileTableNavigationWidget::sltHandleSwitch()
375{
376 if (m_pContainer->currentIndex() == StackedWidgets_BreadCrumbs)
377 {
378 m_pContainer->setCurrentIndex(StackedWidgets_History);
379 m_pHistoryComboBox->showPopup();
380 }
381 else
382 {
383 m_pContainer->setCurrentIndex(StackedWidgets_BreadCrumbs);
384 m_pHistoryComboBox->hidePopup();
385 }
386}
387
388void UIFileTableNavigationWidget::sltAddressLineEdited()
389{
390 sigPathChanged(QDir::fromNativeSeparators(m_pAddressLineEdit->text()));
391}
392
393#include "UIFileTableNavigationWidget.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