Skip to content

Commit

Permalink
Merge pull request #5221 from nyalldawson/browser_awesome
Browse files Browse the repository at this point in the history
Add QLR, processing models to browser
  • Loading branch information
nyalldawson committed Sep 20, 2017
2 parents d34fd9f + a67dab5 commit 15e650d
Show file tree
Hide file tree
Showing 11 changed files with 277 additions and 21 deletions.
12 changes: 11 additions & 1 deletion python/core/qgsdataitem.sip
Expand Up @@ -49,7 +49,8 @@ class QgsDataItem : QObject
Layer,
Error,
Favorites,
Project
Project,
Custom,
};


Expand Down Expand Up @@ -153,6 +154,15 @@ Create new data item.
:rtype: bool
%End

virtual bool handleDoubleClick();
%Docstring
Called when a user double clicks on the item. Subclasses should return true
if they have implemented a double-click handler and do not want the default
double-click behavior for items.
.. versionadded:: 3.0
:rtype: bool
%End

virtual bool hasDragEnabled() const;
%Docstring
Returns true if the item may be dragged.
Expand Down
81 changes: 79 additions & 2 deletions python/plugins/processing/ProcessingPlugin.py
Expand Up @@ -33,10 +33,14 @@

from qgis.core import (QgsApplication,
QgsProcessingUtils,
QgsProcessingModelAlgorithm)
QgsProcessingModelAlgorithm,
QgsDataItemProvider,
QgsDataProvider,
QgsDataItem,
QgsMimeDataUtils)
from qgis.gui import (QgsOptionsWidgetFactory,
QgsCustomDropHandler)
from qgis.PyQt.QtCore import Qt, QCoreApplication, QDir
from qgis.PyQt.QtCore import Qt, QCoreApplication, QDir, QFileInfo
from qgis.PyQt.QtWidgets import QMenu, QAction
from qgis.PyQt.QtGui import QIcon

Expand Down Expand Up @@ -74,7 +78,10 @@ class ProcessingDropHandler(QgsCustomDropHandler):
def handleFileDrop(self, file):
if not file.lower().endswith('.model3'):
return False
self.runAlg(file)

@staticmethod
def runAlg(file):
alg = QgsProcessingModelAlgorithm()
if not alg.fromFile(file):
return False
Expand All @@ -85,6 +92,73 @@ def handleFileDrop(self, file):
dlg.show()
return True

def customUriProviderKey(self):
return 'processing'

def handleCustomUriDrop(self, uri):
path = uri.uri
self.runAlg(path)


class ProcessingModelItem(QgsDataItem):

def __init__(self, parent, name, path):
super(ProcessingModelItem, self).__init__(QgsDataItem.Custom, parent, name, path)
self.setState(QgsDataItem.Populated) # no children
self.setIconName(":/images/themes/default/processingModel.svg")
self.setToolTip(QDir.toNativeSeparators(path))

def hasDragEnabled(self):
return True

def handleDoubleClick(self):
self.runModel()
return True

def mimeUri(self):
u = QgsMimeDataUtils.Uri()
u.layerType = "custom"
u.providerKey = "processing"
u.name = self.name()
u.uri = self.path()
return u

def runModel(self):
ProcessingDropHandler.runAlg(self.path())

def editModel(self):
dlg = ModelerDialog()
dlg.loadModel(self.path())
dlg.show()

def actions(self):
run_model_action = QAction(self.tr('&Run Model…'), self)
run_model_action.triggered.connect(self.runModel)
edit_model_action = QAction(self.tr('&Edit Model…'), self)
edit_model_action.triggered.connect(self.editModel)
return [run_model_action, edit_model_action]


class ProcessingDataItemProvider(QgsDataItemProvider):

def __init__(self):
super(ProcessingDataItemProvider, self).__init__()

def name(self):
return 'processing'

def capabilities(self):
return QgsDataProvider.File

def createDataItem(self, path, parentItem):
file_info = QFileInfo(path)

if file_info.suffix().lower() == 'model3':
alg = QgsProcessingModelAlgorithm()
if alg.fromFile(path):
return ProcessingModelItem(parentItem, alg.name(), path)
return None


class ProcessingPlugin(object):

Expand All @@ -95,6 +169,8 @@ def __init__(self, iface):
iface.registerOptionsWidgetFactory(self.options_factory)
self.drop_handler = ProcessingDropHandler()
iface.registerCustomDropHandler(self.drop_handler)
self.item_provider = ProcessingDataItemProvider()
QgsApplication.dataItemProviderRegistry().addProvider(self.item_provider)
self.locator_filter = AlgorithmLocatorFilter()
iface.registerLocatorFilter(self.locator_filter)
Processing.initialize()
Expand Down Expand Up @@ -182,6 +258,7 @@ def unload(self):
self.iface.unregisterOptionsWidgetFactory(self.options_factory)
self.iface.deregisterLocatorFilter(self.locator_filter)
self.iface.unregisterCustomDropHandler(self.drop_handler)
QgsApplication.dataItemProviderRegistry().removeProvider(self.item_provider)

removeMenus()
Processing.deinitialize()
Expand Down
35 changes: 19 additions & 16 deletions python/plugins/processing/modeler/ModelerDialog.py
Expand Up @@ -503,23 +503,26 @@ def openModel(self):
ModelerUtils.modelsFolders()[0],
self.tr('Processing models (*.model3 *.MODEL3)'))
if filename:
alg = QgsProcessingModelAlgorithm()
if alg.fromFile(filename):
self.model = alg
self.model.setProvider(QgsApplication.processingRegistry().providerById('model'))
self.textGroup.setText(alg.group())
self.textName.setText(alg.name())
self.repaintModel()
self.loadModel(filename)

self.view.centerOn(0, 0)
self.hasChanged = False
else:
QgsMessageLog.logMessage(self.tr('Could not load model {0}').format(filename),
self.tr('Processing'),
QgsMessageLog.CRITICAL)
QMessageBox.critical(self, self.tr('Could not open model'),
self.tr('The selected model could not be loaded.\n'
'See the log for more information.'))
def loadModel(self, filename):
alg = QgsProcessingModelAlgorithm()
if alg.fromFile(filename):
self.model = alg
self.model.setProvider(QgsApplication.processingRegistry().providerById('model'))
self.textGroup.setText(alg.group())
self.textName.setText(alg.name())
self.repaintModel()

self.view.centerOn(0, 0)
self.hasChanged = False
else:
QgsMessageLog.logMessage(self.tr('Could not load model {0}').format(filename),
self.tr('Processing'),
QgsMessageLog.CRITICAL)
QMessageBox.critical(self, self.tr('Could not open model'),
self.tr('The selected model could not be loaded.\n'
'See the log for more information.'))

def repaintModel(self, controls=True):
self.scene = ModelerScene(self, dialog=self)
Expand Down
2 changes: 2 additions & 0 deletions src/app/CMakeLists.txt
Expand Up @@ -6,6 +6,7 @@ SET(QGIS_APP_SRCS
qgisappstylesheet.cpp
qgsabout.cpp
qgsalignrasterdialog.cpp
qgsappbrowserproviders.cpp
qgsapplayertreeviewmenuprovider.cpp
qgsaddattrdialog.cpp
qgsaddtaborgroup.cpp
Expand Down Expand Up @@ -194,6 +195,7 @@ SET (QGIS_APP_MOC_HDRS
qgsabout.h
qgsaddattrdialog.h
qgsalignrasterdialog.h
qgsappbrowserproviders.h
qgsjoindialog.h
qgsaddtaborgroup.h
qgsannotationwidget.h
Expand Down
5 changes: 5 additions & 0 deletions src/app/qgisapp.cpp
Expand Up @@ -124,6 +124,7 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
#include "qgisplugin.h"
#include "qgsabout.h"
#include "qgsalignrasterdialog.h"
#include "qgsappbrowserproviders.h"
#include "qgsapplayertreeviewmenuprovider.h"
#include "qgsapplication.h"
#include "qgsactionmanager.h"
Expand Down Expand Up @@ -153,6 +154,7 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
#include "qgscustomization.h"
#include "qgscustomlayerorderwidget.h"
#include "qgscustomprojectiondialog.h"
#include "qgsdataitemproviderregistry.h"
#include "qgsdatasourceuri.h"
#include "qgsdatumtransformdialog.h"
#include "qgsdoublespinbox.h"
Expand Down Expand Up @@ -975,6 +977,9 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh
qApp->processEvents();
QgsApplication::initQgis();

QgsApplication::dataItemProviderRegistry()->addProvider( new QgsQlrDataItemProvider() );
registerCustomDropHandler( new QgsQlrDropHandler() );

mSplash->showMessage( tr( "Starting Python" ), Qt::AlignHCenter | Qt::AlignBottom );
qApp->processEvents();
loadPythonSupport();
Expand Down
80 changes: 80 additions & 0 deletions src/app/qgsappbrowserproviders.cpp
@@ -0,0 +1,80 @@
/***************************************************************************
qgsappbrowserproviders.cpp
---------------------------
begin : September 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsappbrowserproviders.h"
#include "qgisapp.h"

//
// QgsQlrDataItem
//

QgsQlrDataItem::QgsQlrDataItem( QgsDataItem *parent, const QString &name, const QString &path )
: QgsLayerItem( parent, name, path, path, QgsLayerItem::NoType, QStringLiteral( "qlr" ) )
{
setState( QgsDataItem::Populated ); // no children
setIconName( QStringLiteral( ":/images/icons/qgis-icon-16x16.png" ) );
setToolTip( QDir::toNativeSeparators( path ) );
}

bool QgsQlrDataItem::hasDragEnabled() const
{
return true;
}

QgsMimeDataUtils::Uri QgsQlrDataItem::mimeUri() const
{
QgsMimeDataUtils::Uri u;
u.layerType = QStringLiteral( "custom" );
u.providerKey = QStringLiteral( "qlr" );
u.name = name();
u.uri = path();
return u;
}

//
// QgsQlrDataItemProvider
//

QString QgsQlrDataItemProvider::name()
{
return QStringLiteral( "QLR" );
}

int QgsQlrDataItemProvider::capabilities()
{
return QgsDataProvider::File;
}

QgsDataItem *QgsQlrDataItemProvider::createDataItem( const QString &path, QgsDataItem *parentItem )
{
QFileInfo fileInfo( path );

if ( fileInfo.suffix().compare( QStringLiteral( "qlr" ), Qt::CaseInsensitive ) == 0 )
{
return new QgsQlrDataItem( parentItem, fileInfo.fileName(), path );
}
return nullptr;
}

QString QgsQlrDropHandler::customUriProviderKey() const
{
return QStringLiteral( "qlr" );
}

void QgsQlrDropHandler::handleCustomUriDrop( const QgsMimeDataUtils::Uri &uri ) const
{
QString path = uri.uri;
QgisApp::instance()->openLayerDefinition( path );
}
50 changes: 50 additions & 0 deletions src/app/qgsappbrowserproviders.h
@@ -0,0 +1,50 @@
/***************************************************************************
qgsappbrowserproviders.h
-------------------------
begin : September 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSAPPBROWSERPROVIDERS_H
#define QGSAPPBROWSERPROVIDERS_H

#include "qgsdataitemprovider.h"
#include "qgsdataprovider.h"
#include "qgscustomdrophandler.h"

class QgsQlrDataItem : public QgsLayerItem
{
Q_OBJECT

public:

QgsQlrDataItem( QgsDataItem *parent, const QString &name, const QString &path );
bool hasDragEnabled() const override;
QgsMimeDataUtils::Uri mimeUri() const override;

};

class QgsQlrDataItemProvider : public QgsDataItemProvider
{
public:
QString name() override;
int capabilities() override;
QgsDataItem *createDataItem( const QString &path, QgsDataItem *parentItem ) override;
};

class QgsQlrDropHandler : public QgsCustomDropHandler
{
public:

QString customUriProviderKey() const override;
void handleCustomUriDrop( const QgsMimeDataUtils::Uri &uri ) const override;
};

#endif // QGSAPPBROWSERPROVIDERS_H
5 changes: 5 additions & 0 deletions src/core/qgsdataitem.cpp
Expand Up @@ -511,6 +511,11 @@ bool QgsDataItem::equal( const QgsDataItem *other )
mPath == other->path() );
}

bool QgsDataItem::handleDoubleClick()
{
return false;
}

QgsDataItem::State QgsDataItem::state() const
{
return mState;
Expand Down
11 changes: 10 additions & 1 deletion src/core/qgsdataitem.h
Expand Up @@ -79,7 +79,8 @@ class CORE_EXPORT QgsDataItem : public QObject
Layer,
Error,
Favorites, //!< Represents a favorite item
Project //!< Represents a QGIS project
Project, //!< Represents a QGIS project
Custom, //!< Custom item type
};

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

/**
* Called when a user double clicks on the item. Subclasses should return true
* if they have implemented a double-click handler and do not want the default
* double-click behavior for items.
* \since QGIS 3.0
*/
virtual bool handleDoubleClick();

/** Returns true if the item may be dragged.
* Default implementation returns false.
* A draggable item has to implement mimeUri() that will be used to pass data.
Expand Down

0 comments on commit 15e650d

Please sign in to comment.