Skip to content

Commit 15e650d

Browse files
authoredSep 20, 2017
Merge pull request #5221 from nyalldawson/browser_awesome
Add QLR, processing models to browser
2 parents d34fd9f + a67dab5 commit 15e650d

File tree

11 files changed

+277
-21
lines changed

11 files changed

+277
-21
lines changed
 

‎python/core/qgsdataitem.sip

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ class QgsDataItem : QObject
4949
Layer,
5050
Error,
5151
Favorites,
52-
Project
52+
Project,
53+
Custom,
5354
};
5455

5556

@@ -153,6 +154,15 @@ Create new data item.
153154
:rtype: bool
154155
%End
155156

157+
virtual bool handleDoubleClick();
158+
%Docstring
159+
Called when a user double clicks on the item. Subclasses should return true
160+
if they have implemented a double-click handler and do not want the default
161+
double-click behavior for items.
162+
.. versionadded:: 3.0
163+
:rtype: bool
164+
%End
165+
156166
virtual bool hasDragEnabled() const;
157167
%Docstring
158168
Returns true if the item may be dragged.

‎python/plugins/processing/ProcessingPlugin.py

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,14 @@
3333

3434
from qgis.core import (QgsApplication,
3535
QgsProcessingUtils,
36-
QgsProcessingModelAlgorithm)
36+
QgsProcessingModelAlgorithm,
37+
QgsDataItemProvider,
38+
QgsDataProvider,
39+
QgsDataItem,
40+
QgsMimeDataUtils)
3741
from qgis.gui import (QgsOptionsWidgetFactory,
3842
QgsCustomDropHandler)
39-
from qgis.PyQt.QtCore import Qt, QCoreApplication, QDir
43+
from qgis.PyQt.QtCore import Qt, QCoreApplication, QDir, QFileInfo
4044
from qgis.PyQt.QtWidgets import QMenu, QAction
4145
from qgis.PyQt.QtGui import QIcon
4246

@@ -74,7 +78,10 @@ class ProcessingDropHandler(QgsCustomDropHandler):
7478
def handleFileDrop(self, file):
7579
if not file.lower().endswith('.model3'):
7680
return False
81+
self.runAlg(file)
7782

83+
@staticmethod
84+
def runAlg(file):
7885
alg = QgsProcessingModelAlgorithm()
7986
if not alg.fromFile(file):
8087
return False
@@ -85,6 +92,73 @@ def handleFileDrop(self, file):
8592
dlg.show()
8693
return True
8794

95+
def customUriProviderKey(self):
96+
return 'processing'
97+
98+
def handleCustomUriDrop(self, uri):
99+
path = uri.uri
100+
self.runAlg(path)
101+
102+
103+
class ProcessingModelItem(QgsDataItem):
104+
105+
def __init__(self, parent, name, path):
106+
super(ProcessingModelItem, self).__init__(QgsDataItem.Custom, parent, name, path)
107+
self.setState(QgsDataItem.Populated) # no children
108+
self.setIconName(":/images/themes/default/processingModel.svg")
109+
self.setToolTip(QDir.toNativeSeparators(path))
110+
111+
def hasDragEnabled(self):
112+
return True
113+
114+
def handleDoubleClick(self):
115+
self.runModel()
116+
return True
117+
118+
def mimeUri(self):
119+
u = QgsMimeDataUtils.Uri()
120+
u.layerType = "custom"
121+
u.providerKey = "processing"
122+
u.name = self.name()
123+
u.uri = self.path()
124+
return u
125+
126+
def runModel(self):
127+
ProcessingDropHandler.runAlg(self.path())
128+
129+
def editModel(self):
130+
dlg = ModelerDialog()
131+
dlg.loadModel(self.path())
132+
dlg.show()
133+
134+
def actions(self):
135+
run_model_action = QAction(self.tr('&Run Model…'), self)
136+
run_model_action.triggered.connect(self.runModel)
137+
edit_model_action = QAction(self.tr('&Edit Model…'), self)
138+
edit_model_action.triggered.connect(self.editModel)
139+
return [run_model_action, edit_model_action]
140+
141+
142+
class ProcessingDataItemProvider(QgsDataItemProvider):
143+
144+
def __init__(self):
145+
super(ProcessingDataItemProvider, self).__init__()
146+
147+
def name(self):
148+
return 'processing'
149+
150+
def capabilities(self):
151+
return QgsDataProvider.File
152+
153+
def createDataItem(self, path, parentItem):
154+
file_info = QFileInfo(path)
155+
156+
if file_info.suffix().lower() == 'model3':
157+
alg = QgsProcessingModelAlgorithm()
158+
if alg.fromFile(path):
159+
return ProcessingModelItem(parentItem, alg.name(), path)
160+
return None
161+
88162

89163
class ProcessingPlugin(object):
90164

@@ -95,6 +169,8 @@ def __init__(self, iface):
95169
iface.registerOptionsWidgetFactory(self.options_factory)
96170
self.drop_handler = ProcessingDropHandler()
97171
iface.registerCustomDropHandler(self.drop_handler)
172+
self.item_provider = ProcessingDataItemProvider()
173+
QgsApplication.dataItemProviderRegistry().addProvider(self.item_provider)
98174
self.locator_filter = AlgorithmLocatorFilter()
99175
iface.registerLocatorFilter(self.locator_filter)
100176
Processing.initialize()
@@ -182,6 +258,7 @@ def unload(self):
182258
self.iface.unregisterOptionsWidgetFactory(self.options_factory)
183259
self.iface.deregisterLocatorFilter(self.locator_filter)
184260
self.iface.unregisterCustomDropHandler(self.drop_handler)
261+
QgsApplication.dataItemProviderRegistry().removeProvider(self.item_provider)
185262

186263
removeMenus()
187264
Processing.deinitialize()

‎python/plugins/processing/modeler/ModelerDialog.py

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -503,23 +503,26 @@ def openModel(self):
503503
ModelerUtils.modelsFolders()[0],
504504
self.tr('Processing models (*.model3 *.MODEL3)'))
505505
if filename:
506-
alg = QgsProcessingModelAlgorithm()
507-
if alg.fromFile(filename):
508-
self.model = alg
509-
self.model.setProvider(QgsApplication.processingRegistry().providerById('model'))
510-
self.textGroup.setText(alg.group())
511-
self.textName.setText(alg.name())
512-
self.repaintModel()
506+
self.loadModel(filename)
513507

514-
self.view.centerOn(0, 0)
515-
self.hasChanged = False
516-
else:
517-
QgsMessageLog.logMessage(self.tr('Could not load model {0}').format(filename),
518-
self.tr('Processing'),
519-
QgsMessageLog.CRITICAL)
520-
QMessageBox.critical(self, self.tr('Could not open model'),
521-
self.tr('The selected model could not be loaded.\n'
522-
'See the log for more information.'))
508+
def loadModel(self, filename):
509+
alg = QgsProcessingModelAlgorithm()
510+
if alg.fromFile(filename):
511+
self.model = alg
512+
self.model.setProvider(QgsApplication.processingRegistry().providerById('model'))
513+
self.textGroup.setText(alg.group())
514+
self.textName.setText(alg.name())
515+
self.repaintModel()
516+
517+
self.view.centerOn(0, 0)
518+
self.hasChanged = False
519+
else:
520+
QgsMessageLog.logMessage(self.tr('Could not load model {0}').format(filename),
521+
self.tr('Processing'),
522+
QgsMessageLog.CRITICAL)
523+
QMessageBox.critical(self, self.tr('Could not open model'),
524+
self.tr('The selected model could not be loaded.\n'
525+
'See the log for more information.'))
523526

524527
def repaintModel(self, controls=True):
525528
self.scene = ModelerScene(self, dialog=self)

‎src/app/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ SET(QGIS_APP_SRCS
66
qgisappstylesheet.cpp
77
qgsabout.cpp
88
qgsalignrasterdialog.cpp
9+
qgsappbrowserproviders.cpp
910
qgsapplayertreeviewmenuprovider.cpp
1011
qgsaddattrdialog.cpp
1112
qgsaddtaborgroup.cpp
@@ -194,6 +195,7 @@ SET (QGIS_APP_MOC_HDRS
194195
qgsabout.h
195196
qgsaddattrdialog.h
196197
qgsalignrasterdialog.h
198+
qgsappbrowserproviders.h
197199
qgsjoindialog.h
198200
qgsaddtaborgroup.h
199201
qgsannotationwidget.h

‎src/app/qgisapp.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
124124
#include "qgisplugin.h"
125125
#include "qgsabout.h"
126126
#include "qgsalignrasterdialog.h"
127+
#include "qgsappbrowserproviders.h"
127128
#include "qgsapplayertreeviewmenuprovider.h"
128129
#include "qgsapplication.h"
129130
#include "qgsactionmanager.h"
@@ -153,6 +154,7 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
153154
#include "qgscustomization.h"
154155
#include "qgscustomlayerorderwidget.h"
155156
#include "qgscustomprojectiondialog.h"
157+
#include "qgsdataitemproviderregistry.h"
156158
#include "qgsdatasourceuri.h"
157159
#include "qgsdatumtransformdialog.h"
158160
#include "qgsdoublespinbox.h"
@@ -975,6 +977,9 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh
975977
qApp->processEvents();
976978
QgsApplication::initQgis();
977979

980+
QgsApplication::dataItemProviderRegistry()->addProvider( new QgsQlrDataItemProvider() );
981+
registerCustomDropHandler( new QgsQlrDropHandler() );
982+
978983
mSplash->showMessage( tr( "Starting Python" ), Qt::AlignHCenter | Qt::AlignBottom );
979984
qApp->processEvents();
980985
loadPythonSupport();

‎src/app/qgsappbrowserproviders.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/***************************************************************************
2+
qgsappbrowserproviders.cpp
3+
---------------------------
4+
begin : September 2017
5+
copyright : (C) 2017 by 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 "qgsappbrowserproviders.h"
17+
#include "qgisapp.h"
18+
19+
//
20+
// QgsQlrDataItem
21+
//
22+
23+
QgsQlrDataItem::QgsQlrDataItem( QgsDataItem *parent, const QString &name, const QString &path )
24+
: QgsLayerItem( parent, name, path, path, QgsLayerItem::NoType, QStringLiteral( "qlr" ) )
25+
{
26+
setState( QgsDataItem::Populated ); // no children
27+
setIconName( QStringLiteral( ":/images/icons/qgis-icon-16x16.png" ) );
28+
setToolTip( QDir::toNativeSeparators( path ) );
29+
}
30+
31+
bool QgsQlrDataItem::hasDragEnabled() const
32+
{
33+
return true;
34+
}
35+
36+
QgsMimeDataUtils::Uri QgsQlrDataItem::mimeUri() const
37+
{
38+
QgsMimeDataUtils::Uri u;
39+
u.layerType = QStringLiteral( "custom" );
40+
u.providerKey = QStringLiteral( "qlr" );
41+
u.name = name();
42+
u.uri = path();
43+
return u;
44+
}
45+
46+
//
47+
// QgsQlrDataItemProvider
48+
//
49+
50+
QString QgsQlrDataItemProvider::name()
51+
{
52+
return QStringLiteral( "QLR" );
53+
}
54+
55+
int QgsQlrDataItemProvider::capabilities()
56+
{
57+
return QgsDataProvider::File;
58+
}
59+
60+
QgsDataItem *QgsQlrDataItemProvider::createDataItem( const QString &path, QgsDataItem *parentItem )
61+
{
62+
QFileInfo fileInfo( path );
63+
64+
if ( fileInfo.suffix().compare( QStringLiteral( "qlr" ), Qt::CaseInsensitive ) == 0 )
65+
{
66+
return new QgsQlrDataItem( parentItem, fileInfo.fileName(), path );
67+
}
68+
return nullptr;
69+
}
70+
71+
QString QgsQlrDropHandler::customUriProviderKey() const
72+
{
73+
return QStringLiteral( "qlr" );
74+
}
75+
76+
void QgsQlrDropHandler::handleCustomUriDrop( const QgsMimeDataUtils::Uri &uri ) const
77+
{
78+
QString path = uri.uri;
79+
QgisApp::instance()->openLayerDefinition( path );
80+
}

‎src/app/qgsappbrowserproviders.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/***************************************************************************
2+
qgsappbrowserproviders.h
3+
-------------------------
4+
begin : September 2017
5+
copyright : (C) 2017 by 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+
#ifndef QGSAPPBROWSERPROVIDERS_H
16+
#define QGSAPPBROWSERPROVIDERS_H
17+
18+
#include "qgsdataitemprovider.h"
19+
#include "qgsdataprovider.h"
20+
#include "qgscustomdrophandler.h"
21+
22+
class QgsQlrDataItem : public QgsLayerItem
23+
{
24+
Q_OBJECT
25+
26+
public:
27+
28+
QgsQlrDataItem( QgsDataItem *parent, const QString &name, const QString &path );
29+
bool hasDragEnabled() const override;
30+
QgsMimeDataUtils::Uri mimeUri() const override;
31+
32+
};
33+
34+
class QgsQlrDataItemProvider : public QgsDataItemProvider
35+
{
36+
public:
37+
QString name() override;
38+
int capabilities() override;
39+
QgsDataItem *createDataItem( const QString &path, QgsDataItem *parentItem ) override;
40+
};
41+
42+
class QgsQlrDropHandler : public QgsCustomDropHandler
43+
{
44+
public:
45+
46+
QString customUriProviderKey() const override;
47+
void handleCustomUriDrop( const QgsMimeDataUtils::Uri &uri ) const override;
48+
};
49+
50+
#endif // QGSAPPBROWSERPROVIDERS_H

‎src/core/qgsdataitem.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,11 @@ bool QgsDataItem::equal( const QgsDataItem *other )
511511
mPath == other->path() );
512512
}
513513

514+
bool QgsDataItem::handleDoubleClick()
515+
{
516+
return false;
517+
}
518+
514519
QgsDataItem::State QgsDataItem::state() const
515520
{
516521
return mState;

‎src/core/qgsdataitem.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ class CORE_EXPORT QgsDataItem : public QObject
7979
Layer,
8080
Error,
8181
Favorites, //!< Represents a favorite item
82-
Project //!< Represents a QGIS project
82+
Project, //!< Represents a QGIS project
83+
Custom, //!< Custom item type
8384
};
8485

8586
Q_ENUM( Type );
@@ -155,6 +156,14 @@ class CORE_EXPORT QgsDataItem : public QObject
155156
*/
156157
virtual bool handleDrop( const QMimeData * /*data*/, Qt::DropAction /*action*/ ) { return false; }
157158

159+
/**
160+
* Called when a user double clicks on the item. Subclasses should return true
161+
* if they have implemented a double-click handler and do not want the default
162+
* double-click behavior for items.
163+
* \since QGIS 3.0
164+
*/
165+
virtual bool handleDoubleClick();
166+
158167
/** Returns true if the item may be dragged.
159168
* Default implementation returns false.
160169
* A draggable item has to implement mimeUri() that will be used to pass data.

‎src/gui/qgsbrowserdockwidget.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ QgsBrowserDockWidget::QgsBrowserDockWidget( const QString &name, QgsBrowserModel
9797
connect( mLeFilter, &QgsFilterLineEdit::textChanged, this, &QgsBrowserDockWidget::setFilter );
9898
connect( group, &QActionGroup::triggered, this, &QgsBrowserDockWidget::setFilterSyntax );
9999
connect( mBrowserView, &QgsDockBrowserTreeView::customContextMenuRequested, this, &QgsBrowserDockWidget::showContextMenu );
100-
connect( mBrowserView, &QgsDockBrowserTreeView::doubleClicked, this, &QgsBrowserDockWidget::addLayerAtIndex );
100+
connect( mBrowserView, &QgsDockBrowserTreeView::doubleClicked, this, &QgsBrowserDockWidget::itemDoubleClicked );
101101
connect( mSplitter, &QSplitter::splitterMoved, this, &QgsBrowserDockWidget::splitterMoved );
102102
}
103103

@@ -155,6 +155,18 @@ void QgsBrowserDockWidget::showEvent( QShowEvent *e )
155155
QgsDockWidget::showEvent( e );
156156
}
157157

158+
void QgsBrowserDockWidget::itemDoubleClicked( const QModelIndex &index )
159+
{
160+
QgsDataItem *item = mModel->dataItem( mProxyModel->mapToSource( index ) );
161+
if ( !item )
162+
return;
163+
164+
if ( item->handleDoubleClick() )
165+
return;
166+
else
167+
addLayerAtIndex( index ); // default double-click handler
168+
}
169+
158170
void QgsBrowserDockWidget::showContextMenu( QPoint pt )
159171
{
160172
QModelIndex index = mProxyModel->mapToSource( mBrowserView->indexAt( pt ) );

‎src/gui/qgsbrowserdockwidget.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ class GUI_EXPORT QgsBrowserDockWidget : public QgsDockWidget, private Ui::QgsBro
110110
//! Show event override
111111
void showEvent( QShowEvent *event ) override;
112112

113+
private slots:
114+
void itemDoubleClicked( const QModelIndex &index );
115+
113116
private:
114117
//! Refresh the model
115118
void refreshModel( const QModelIndex &index );

0 commit comments

Comments
 (0)
Please sign in to comment.