Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Move toolbox tree view to c++ class
  • Loading branch information
nyalldawson committed Jul 16, 2018
1 parent 810cb9c commit 101c98f
Show file tree
Hide file tree
Showing 9 changed files with 317 additions and 60 deletions.
Expand Up @@ -365,9 +365,6 @@ A sort/filter proxy model for providers and algorithms shown within the Processi
which automatically sorts the toolbox in a logical fashion and supports filtering
the results.

If \recentLog is specified then it will be used to create a "Recently used" top
level group containing recently used algorithms.

.. versionadded:: 3.2
%End

Expand All @@ -394,6 +391,9 @@ If ``registry`` is specified then the model will show providers and algorithms
from the given registry. If no registry is specified, then the processing
registry attached to QgsApplication.processingRegistry() will be used
by the model.

If \recentLog is specified then it will be used to create a "Recently used" top
level group containing recently used algorithms.
%End

QgsProcessingToolboxModel *toolboxModel();
Expand Down
@@ -0,0 +1,87 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/processing/qgsprocessingtoolboxtreeview.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/





class QgsProcessingToolboxTreeView : QTreeView
{
%Docstring
Processing toolbox tree view, showing algorithms and providers in a tree structure.

.. versionadded:: 3.4

.. warning::

Not part of stable API and may change in future QGIS releases.
%End

%TypeHeaderCode
#include "qgsprocessingtoolboxtreeview.h"
%End
public:

QgsProcessingToolboxTreeView( QWidget *parent /TransferThis/ = 0,
QgsProcessingRegistry *registry = 0,
QgsProcessingRecentAlgorithmLog *recentLog = 0 );
%Docstring
Constructor for QgsProcessingToolboxTreeView, with the specified ``parent`` widget.

If ``registry`` is set, then the view will automatically be populated with algorithms
and providers from the registry. Otherwise, users must manually call setRegistry()
to associate a registry with the view.

If \recentLog is specified then it will be used to create a "Recently used" top
level group containing recently used algorithms.
%End

void setRegistry(
QgsProcessingRegistry *registry,
QgsProcessingRecentAlgorithmLog *recentLog = 0 );
%Docstring
Sets the processing ``registry`` associated with the view.

If \recentLog is specified then it will be used to create a "Recently used" top
level group containing recently used algorithms.
%End

const QgsProcessingAlgorithm *algorithmForIndex( const QModelIndex &index );
%Docstring
Returns the algorithm at the specified tree view ``index``, or a None
if the index does not correspond to an algorithm.
%End

const QgsProcessingAlgorithm *selectedAlgorithm();
%Docstring
Returns the currently selected algorithm in the tree view, or a None
if no algorithm is currently selected.
%End

void setFilters( QgsProcessingToolboxProxyModel::Filters filters );
%Docstring
Sets ``filters`` controlling the view's contents.
%End

public slots:

void setFilterString( const QString &filter );
%Docstring
Sets a ``filter`` string, used to filter out the contents of the view
to matching algorithms.
%End

};

/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/processing/qgsprocessingtoolboxtreeview.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
1 change: 1 addition & 0 deletions python/gui/gui_auto.sip
Expand Up @@ -317,4 +317,5 @@
%Include auto_generated/processing/qgsprocessingalgorithmdialogbase.sip
%Include auto_generated/processing/qgsprocessingrecentalgorithmlog.sip
%Include auto_generated/processing/qgsprocessingtoolboxmodel.sip
%Include auto_generated/processing/qgsprocessingtoolboxtreeview.sip
%Include auto_generated/qgsadvanceddigitizingcanvasitem.sip
64 changes: 11 additions & 53 deletions python/plugins/processing/gui/ProcessingToolbox.py
Expand Up @@ -30,8 +30,8 @@
import warnings

from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt, QCoreApplication, QModelIndex, QItemSelectionModel
from qgis.PyQt.QtWidgets import QToolButton, QMenu, QAction, QMessageBox
from qgis.PyQt.QtCore import Qt, QCoreApplication
from qgis.PyQt.QtWidgets import QToolButton, QMenu, QAction
from qgis.utils import iface
from qgis.core import (QgsApplication,
QgsProcessingAlgorithm)
Expand All @@ -40,8 +40,7 @@
QgsProcessingToolboxProxyModel)

from processing.gui.Postprocessing import handleAlgorithmResults
from processing.core.ProcessingLog import ProcessingLog
from processing.core.ProcessingConfig import ProcessingConfig, settingsWatcher
from processing.core.ProcessingConfig import ProcessingConfig
from processing.gui.MessageDialog import MessageDialog
from processing.gui.AlgorithmDialog import AlgorithmDialog
from processing.gui.BatchAlgorithmDialog import BatchAlgorithmDialog
Expand Down Expand Up @@ -76,15 +75,13 @@ def __init__(self):
self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
self.processingToolbar.setIconSize(iface.iconSize(True))

self.model = QgsProcessingToolboxProxyModel(self,
QgsApplication.processingRegistry(),
QgsGui.instance().processingRecentAlgorithmLog())
self.model.setFilters(QgsProcessingToolboxProxyModel.FilterToolbox)
self.algorithmTree.setModel(self.model)
self.algorithmTree.setRegistry(QgsApplication.processingRegistry(),
QgsGui.instance().processingRecentAlgorithmLog())
self.algorithmTree.setFilters(QgsProcessingToolboxProxyModel.FilterToolbox)

self.searchBox.setShowSearchIcon(True)

self.searchBox.textChanged.connect(self.textChanged)
self.searchBox.textChanged.connect(self.algorithmTree.setFilterString)
self.searchBox.returnPressed.connect(self.activateCurrent)
self.algorithmTree.customContextMenuRequested.connect(
self.showPopupMenu)
Expand Down Expand Up @@ -122,33 +119,6 @@ def disabledProviders(self):

return False

def textChanged(self):
text = self.searchBox.text().strip(' ').lower()
self.model.setFilterString(text)
if text:
self.algorithmTree.expandAll()
if not self.algorithmTree.selectionModel().hasSelection():
# if previously selected item was hidden, auto select the first visible algorithm
first_visible_index = self._findFirstVisibleAlgorithm(QModelIndex())
if first_visible_index is not None:
self.algorithmTree.selectionModel().setCurrentIndex(first_visible_index, QItemSelectionModel.ClearAndSelect)
else:
self.algorithmTree.collapseAll()

def _findFirstVisibleAlgorithm(self, parent_index):
"""
Returns the first visible algorithm in the tree widget
"""
for r in range(self.model.rowCount(parent_index)):
proxy_index = self.model.index(r, 0, parent_index)
source_index = self.model.mapToSource(proxy_index)
if self.model.toolboxModel().isAlgorithm(source_index):
return proxy_index
index = self._findFirstVisibleAlgorithm(proxy_index)
if index is not None:
return index
return None

def addProviderActions(self, provider):
if provider.id() in ProviderActions.actions:
toolbarButton = QToolButton()
Expand Down Expand Up @@ -176,22 +146,10 @@ def removeProvider(self, provider_id):
if button:
self.processingToolbar.removeChild(button)

def algorithm_for_index(self, index):
source_index = self.model.mapToSource(index)
if self.model.toolboxModel().isAlgorithm(source_index):
return self.model.toolboxModel().algorithmForIndex(source_index)
return None

def selected_algorithm(self):
if self.algorithmTree.selectionModel().hasSelection():
index = self.algorithmTree.selectionModel().selectedIndexes()[0]
return self.algorithm_for_index(index)
return None

def showPopupMenu(self, point):
index = self.algorithmTree.indexAt(point)
popupmenu = QMenu()
alg = self.algorithm_for_index(index)
alg = self.algorithmTree.algorithmForIndex(index)
if alg is not None:
executeAction = QAction(QCoreApplication.translate('ProcessingToolbox', 'Execute…'), popupmenu)
executeAction.triggered.connect(self.executeAlgorithm)
Expand Down Expand Up @@ -224,7 +182,7 @@ def showPopupMenu(self, point):
popupmenu.exec_(self.algorithmTree.mapToGlobal(point))

def editRenderingStyles(self):
alg = self.selected_algorithm()
alg = self.algorithmTree.selectedAlgorithm()
if alg is not None:
dlg = EditRenderingStylesDialog(alg)
dlg.exec_()
Expand All @@ -233,14 +191,14 @@ def activateCurrent(self):
self.executeAlgorithm()

def executeAlgorithmAsBatchProcess(self):
alg = self.selected_algorithm()
alg = self.algorithmTree.selectedAlgorithm()
if alg is not None:
dlg = BatchAlgorithmDialog(alg)
dlg.show()
dlg.exec_()

def executeAlgorithm(self):
alg = self.selected_algorithm()
alg = self.algorithmTree.selectedAlgorithm()
if alg is not None:
ok, message = alg.canExecute()
if not ok:
Expand Down
7 changes: 6 additions & 1 deletion python/plugins/processing/ui/ProcessingToolbox.ui
Expand Up @@ -51,7 +51,7 @@
</widget>
</item>
<item>
<widget class="QTreeView" name="algorithmTree">
<widget class="QgsProcessingToolboxTreeView" name="algorithmTree">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
Expand Down Expand Up @@ -96,6 +96,11 @@ color: rgb(255, 255, 255);</string>
<class>QgsFilterLineEdit</class>
<extends>QLineEdit</extends>
<header>qgis.gui</header>
</customwidget>
<customwidget>
<class>QgsProcessingToolboxTreeView</class>
<extends>QTreeView</extends>
<header>qgis.gui</header>
</customwidget>
</customwidgets>
<resources/>
Expand Down
2 changes: 2 additions & 0 deletions src/gui/CMakeLists.txt
Expand Up @@ -199,6 +199,7 @@ SET(QGIS_GUI_SRCS
processing/qgsprocessingguiregistry.cpp
processing/qgsprocessingrecentalgorithmlog.cpp
processing/qgsprocessingtoolboxmodel.cpp
processing/qgsprocessingtoolboxtreeview.cpp

qgisinterface.cpp
qgsactionmenu.cpp
Expand Down Expand Up @@ -721,6 +722,7 @@ SET(QGIS_GUI_MOC_HDRS
processing/qgsprocessingconfigurationwidgets.h
processing/qgsprocessingrecentalgorithmlog.h
processing/qgsprocessingtoolboxmodel.h
processing/qgsprocessingtoolboxtreeview.h
)
SET_PROPERTY(GLOBAL PROPERTY QGIS_GUI_MOC_HDRS ${QGIS_GUI_MOC_HDRS})

Expand Down
6 changes: 3 additions & 3 deletions src/gui/processing/qgsprocessingtoolboxmodel.h
Expand Up @@ -402,9 +402,6 @@ class GUI_EXPORT QgsProcessingToolboxModel : public QAbstractItemModel
* which automatically sorts the toolbox in a logical fashion and supports filtering
* the results.
*
* If \recentLog is specified then it will be used to create a "Recently used" top
* level group containing recently used algorithms.
*
* \ingroup gui
* \since QGIS 3.2
*/
Expand All @@ -429,6 +426,9 @@ class GUI_EXPORT QgsProcessingToolboxProxyModel: public QSortFilterProxyModel
* from the given registry. If no registry is specified, then the processing
* registry attached to QgsApplication::processingRegistry() will be used
* by the model.
*
* If \recentLog is specified then it will be used to create a "Recently used" top
* level group containing recently used algorithms.
*/
explicit QgsProcessingToolboxProxyModel( QObject *parent SIP_TRANSFERTHIS = nullptr,
QgsProcessingRegistry *registry = nullptr,
Expand Down
101 changes: 101 additions & 0 deletions src/gui/processing/qgsprocessingtoolboxtreeview.cpp
@@ -0,0 +1,101 @@
/***************************************************************************
qgsprocessingtoolboxtreeview.cpp
-------------------------------
begin : July 2018
copyright : (C) 2018 by Nyall Dawso
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 "qgsprocessingtoolboxtreeview.h"
#include "qgsprocessingtoolboxmodel.h"

QgsProcessingToolboxTreeView::QgsProcessingToolboxTreeView( QWidget *parent,
QgsProcessingRegistry *registry,
QgsProcessingRecentAlgorithmLog *recentLog )
: QTreeView( parent )
{
mModel = new QgsProcessingToolboxProxyModel( this, registry, recentLog );
mToolboxModel = mModel->toolboxModel();
setModel( mModel );
}

void QgsProcessingToolboxTreeView::setRegistry( QgsProcessingRegistry *registry, QgsProcessingRecentAlgorithmLog *recentLog )
{
QgsProcessingToolboxProxyModel *newModel = new QgsProcessingToolboxProxyModel( this, registry, recentLog );
mToolboxModel = mModel->toolboxModel();
setModel( newModel );
mModel->deleteLater();
mModel = newModel;
}

void QgsProcessingToolboxTreeView::setFilterString( const QString &filter )
{
const QString text = filter.trimmed().toLower();
mModel->setFilterString( text );
if ( !text.isEmpty() )
{
expandAll();
if ( !selectedAlgorithm() )
{
// if previously selected item was hidden, auto select the first visible algorithm
QModelIndex firstVisibleIndex = findFirstVisibleAlgorithm( QModelIndex() );
if ( firstVisibleIndex.isValid() )
selectionModel()->setCurrentIndex( firstVisibleIndex, QItemSelectionModel::ClearAndSelect );
}
}
else
{
collapseAll();
}
}

const QgsProcessingAlgorithm *QgsProcessingToolboxTreeView::algorithmForIndex( const QModelIndex &index )
{
QModelIndex sourceIndex = mModel->mapToSource( index );
if ( mToolboxModel->isAlgorithm( sourceIndex ) )
return mToolboxModel->algorithmForIndex( sourceIndex );
else
return nullptr;
}

const QgsProcessingAlgorithm *QgsProcessingToolboxTreeView::selectedAlgorithm()
{
if ( selectionModel()->hasSelection() )
{
QModelIndex index = selectionModel()->selectedIndexes().at( 0 );
return algorithmForIndex( index );
}
else
{
return nullptr;
}
}

void QgsProcessingToolboxTreeView::setFilters( QgsProcessingToolboxProxyModel::Filters filters )
{
mModel->setFilters( filters );
}

QModelIndex QgsProcessingToolboxTreeView::findFirstVisibleAlgorithm( const QModelIndex &parent )
{
for ( int r = 0; r < mModel->rowCount( parent ); ++r )
{
QModelIndex proxyIndex = mModel->index( r, 0, parent );
QModelIndex sourceIndex = mModel->mapToSource( proxyIndex );
if ( mToolboxModel->isAlgorithm( sourceIndex ) )
return proxyIndex;

QModelIndex index = findFirstVisibleAlgorithm( proxyIndex );
if ( index.isValid() )
return index;
}
return QModelIndex();
}

0 comments on commit 101c98f

Please sign in to comment.