Move toolbox tree view to c++ class

This commit is contained in:
Nyall Dawson 2018-07-08 17:24:23 +10:00
parent 810cb9c0f7
commit 101c98fd17
9 changed files with 317 additions and 60 deletions

View File

@ -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
@ -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();

View File

@ -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 *
************************************************************************/

View File

@ -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

View File

@ -30,8 +30,8 @@ import os
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)
@ -40,8 +40,7 @@ from qgis.gui import (QgsGui,
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
@ -76,15 +75,13 @@ class ProcessingToolbox(QgsDockWidget, WIDGET):
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)
@ -122,33 +119,6 @@ class ProcessingToolbox(QgsDockWidget, WIDGET):
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()
@ -176,22 +146,10 @@ class ProcessingToolbox(QgsDockWidget, WIDGET):
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)
@ -224,7 +182,7 @@ class ProcessingToolbox(QgsDockWidget, WIDGET):
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_()
@ -233,14 +191,14 @@ class ProcessingToolbox(QgsDockWidget, WIDGET):
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:

View File

@ -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>
@ -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/>

View File

@ -199,6 +199,7 @@ SET(QGIS_GUI_SRCS
processing/qgsprocessingguiregistry.cpp
processing/qgsprocessingrecentalgorithmlog.cpp
processing/qgsprocessingtoolboxmodel.cpp
processing/qgsprocessingtoolboxtreeview.cpp
qgisinterface.cpp
qgsactionmenu.cpp
@ -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})

View File

@ -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
*/
@ -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,

View File

@ -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();
}

View File

@ -0,0 +1,103 @@
/***************************************************************************
qgsprocessingtoolboxtreeview.h
-----------------------------
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. *
* *
***************************************************************************/
#ifndef QGSPROCESSINGTOOLBOXTREEVIEW_H
#define QGSPROCESSINGTOOLBOXTREEVIEW_H
#include "qgis.h"
#include "qgis_gui.h"
#include <QTreeView>
#include "qgsprocessingtoolboxmodel.h"
class QgsProcessingRegistry;
class QgsProcessingRecentAlgorithmLog;
class QgsProcessingAlgorithm;
///@cond PRIVATE
/**
* Processing toolbox tree view, showing algorithms and providers in a tree structure.
* \ingroup gui
* \since QGIS 3.4
* \warning Not part of stable API and may change in future QGIS releases.
*/
class GUI_EXPORT QgsProcessingToolboxTreeView : public QTreeView
{
Q_OBJECT
public:
/**
* Constructor for QgsProcessingToolboxTreeView, with the specified \a parent widget.
*
* If \a 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.
*/
QgsProcessingToolboxTreeView( QWidget *parent SIP_TRANSFERTHIS = nullptr,
QgsProcessingRegistry *registry = nullptr,
QgsProcessingRecentAlgorithmLog *recentLog = nullptr );
/**
* Sets the processing \a 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.
*/
void setRegistry(
QgsProcessingRegistry *registry,
QgsProcessingRecentAlgorithmLog *recentLog = nullptr );
/**
* Returns the algorithm at the specified tree view \a index, or a nullptr
* if the index does not correspond to an algorithm.
*/
const QgsProcessingAlgorithm *algorithmForIndex( const QModelIndex &index );
/**
* Returns the currently selected algorithm in the tree view, or a nullptr
* if no algorithm is currently selected.
*/
const QgsProcessingAlgorithm *selectedAlgorithm();
/**
* Sets \a filters controlling the view's contents.
*/
void setFilters( QgsProcessingToolboxProxyModel::Filters filters );
public slots:
/**
* Sets a \a filter string, used to filter out the contents of the view
* to matching algorithms.
*/
void setFilterString( const QString &filter );
private:
QgsProcessingToolboxProxyModel *mModel = nullptr;
QgsProcessingToolboxModel *mToolboxModel = nullptr;
/**
* Returns the first visible algorithm in the tree.
*/
QModelIndex findFirstVisibleAlgorithm( const QModelIndex &parent );
};
#endif // QGSPROCESSINGTOOLBOXTREEVIEW_H