QGIS API Documentation 3.99.0-Master (8e76e220402)
Loading...
Searching...
No Matches
qgshistorywidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgshistorywidget.cpp
3 ------------------
4 Date : April 2023
5 Copyright : (C) 2023 Nyall Dawson
6 Email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgshistorywidget.h"
17
18#include "qgsgui.h"
20#include "qgshistoryentrynode.h"
21#include "qgsnative.h"
22#include "qgssettings.h"
23
24#include <QDesktopServices>
25#include <QFileInfo>
26#include <QMenu>
27#include <QString>
28#include <QTextBrowser>
29#include <QtGlobal>
30
31#include "moc_qgshistorywidget.cpp"
32
33using namespace Qt::StringLiterals;
34
35QgsHistoryWidget::QgsHistoryWidget( const QString &providerId, Qgis::HistoryProviderBackends backends, QgsHistoryProviderRegistry *registry, const QgsHistoryWidgetContext &context, QWidget *parent )
36 : QgsPanelWidget( parent )
37 , mContext( context )
38{
39 setupUi( this );
40 mContext.setHistoryWidget( this );
41
42 mModel = new QgsHistoryEntryModel( providerId, backends, registry, mContext, this );
43 mProxyModel = new QgsHistoryEntryProxyModel( this );
44 mProxyModel->setSourceModel( mModel );
45
46 mTreeView->setModel( mProxyModel );
47
48 mFilterEdit->setShowClearButton( true );
49 mFilterEdit->setShowSearchIcon( true );
50 connect( mFilterEdit, &QLineEdit::textChanged, mProxyModel, &QgsHistoryEntryProxyModel::setFilter );
51 connect( mTreeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsHistoryWidget::currentItemChanged );
52 connect( mTreeView, &QTreeView::doubleClicked, this, &QgsHistoryWidget::nodeDoubleClicked );
53 mTreeView->setExpandsOnDoubleClick( false );
54
55 mTreeView->setContextMenuPolicy( Qt::CustomContextMenu );
56 connect( mTreeView, &QWidget::customContextMenuRequested, this, &QgsHistoryWidget::showNodeContextMenu );
57
58 // expand first group (usually most recent date group)
59 const QModelIndex firstGroup = mProxyModel->index( 0, 0, QModelIndex() );
60 mTreeView->expand( firstGroup );
61
62 QgsSettings settings;
63 mSplitter->restoreState( settings.value( u"history/splitterState%1"_s.arg( providerId ) ).toByteArray() );
64
65 connect( mSplitter, &QSplitter::splitterMoved, this, [providerId, this] {
66 QgsSettings settings;
67 settings.setValue( u"history/splitterState%1"_s.arg( providerId ), mSplitter->saveState() );
68 } );
69}
70
71void QgsHistoryWidget::currentItemChanged( const QModelIndex &selected, const QModelIndex & )
72{
73 QWidget *newWidget = nullptr;
74 if ( QgsHistoryEntryNode *node = mModel->index2node( mProxyModel->mapToSource( selected ) ) )
75 {
76 newWidget = node->createWidget( mContext );
77 if ( !newWidget )
78 {
79 const QString html = node->html( mContext );
80 if ( !html.isEmpty() )
81 {
82 QTextBrowser *htmlBrowser = new QTextBrowser();
83 htmlBrowser->setOpenLinks( false );
84 htmlBrowser->setHtml( html );
85 connect( htmlBrowser, &QTextBrowser::anchorClicked, this, &QgsHistoryWidget::urlClicked );
86
87 newWidget = htmlBrowser;
88 }
89 }
90 if ( newWidget )
91 {
92 mContainerStackedWidget->addWidget( newWidget );
93 mContainerStackedWidget->setCurrentWidget( newWidget );
94 }
95 }
96
97 if ( !newWidget )
98 {
99 //remove current widget, if any
100 if ( mContainerStackedWidget->count() > 1 )
101 {
102 mContainerStackedWidget->removeWidget( mContainerStackedWidget->widget( 1 ) );
103 mContainerStackedWidget->setCurrentIndex( 0 );
104 }
105 }
106}
107
108void QgsHistoryWidget::nodeDoubleClicked( const QModelIndex &index )
109{
110 if ( QgsHistoryEntryNode *node = mModel->index2node( mProxyModel->mapToSource( index ) ) )
111 {
112 if ( node->doubleClicked( mContext ) )
113 return; // double-click handled
114 }
115
116 // otherwise double-clicks expands/collapses the node
117 if ( mTreeView->isExpanded( index ) )
118 mTreeView->collapse( index );
119 else
120 mTreeView->expand( index );
121}
122
123void QgsHistoryWidget::showNodeContextMenu( const QPoint &pos )
124{
125 if ( QgsHistoryEntryNode *node = mModel->index2node( mProxyModel->mapToSource( mTreeView->currentIndex() ) ) )
126 {
127 QMenu *menu = new QMenu();
128
129 node->populateContextMenu( menu, mContext );
130 if ( !menu->isEmpty() )
131 {
132 menu->exec( mTreeView->mapToGlobal( pos ) );
133 }
134 delete menu;
135 }
136}
137
138void QgsHistoryWidget::urlClicked( const QUrl &url )
139{
140 const QFileInfo file( url.toLocalFile() );
141 if ( file.exists() && !file.isDir() )
142 QgsGui::nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
143 else
144 QDesktopServices::openUrl( url );
145}
146
147//
148// QgsHistoryEntryProxyModel
149//
150
152QgsHistoryEntryProxyModel::QgsHistoryEntryProxyModel( QObject *parent )
153 : QSortFilterProxyModel( parent )
154{
155 setDynamicSortFilter( true );
156 setRecursiveFilteringEnabled( true );
157}
158
159void QgsHistoryEntryProxyModel::setFilter( const QString &filter )
160{
161 if ( filter == mFilter )
162 return;
163
164 mFilter = filter;
165 invalidateFilter();
166}
167
168bool QgsHistoryEntryProxyModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
169{
170 if ( mFilter.isEmpty() )
171 return true;
172
173 const QModelIndex sourceIndex = sourceModel()->index( source_row, 0, source_parent );
174 if ( QgsHistoryEntryNode *node = qobject_cast<QgsHistoryEntryModel *>( sourceModel() )->index2node( sourceIndex ) )
175 {
176 if ( !node->matchesString( mFilter ) )
177 {
178 return false;
179 }
180 }
181 return true;
182}
QFlags< HistoryProviderBackend > HistoryProviderBackends
Definition qgis.h:3579
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition qgsgui.cpp:99
An item model representing history entries in a hierarchical tree structure.
QgsHistoryEntryNode * index2node(const QModelIndex &index) const
Returns node for given index.
Base class for nodes representing a QgsHistoryEntry.
A registry for objects which track user history (i.e.
Contains settings which reflect the context in which a history widget is shown, e....
QgsHistoryWidget(const QString &providerId=QString(), Qgis::HistoryProviderBackends backends=Qgis::HistoryProviderBackend::LocalProfile, QgsHistoryProviderRegistry *registry=nullptr, const QgsHistoryWidgetContext &context=QgsHistoryWidgetContext(), QWidget *parent=nullptr)
Constructor for QgsHistoryWidget, with the specified parent widget.
QgsPanelWidget(QWidget *parent=nullptr)
Base class for any widget that can be shown as an inline panel.
Stores settings for use within QGIS.
Definition qgssettings.h:68
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.