From a7b11b7980dba2a30e92a2a58b2b0ed6e25e798c Mon Sep 17 00:00:00 2001 From: Edward Brown <edward.brown@stfc.ac.uk> Date: Wed, 9 May 2018 11:00:20 +0100 Subject: [PATCH] Renamed QtLeafNodeFilter to FilteredTreeModel + updated docs. - Reorgranised JobTreeView page. - Added documentation + example for filtering. - Moved RowPredicate into its own header. Re #22263 --- .../BatchWidget/API/CodeExamples/filtering.py | 52 +++++++++++++ .../init_with_custom_subscriber.cpp | 2 +- .../source/BatchWidget/API/JobTreeView.rst | 76 ++++++++++--------- .../QtStandardItemTreeModelAdapter.rst | 75 ++++++++++++++++++ .../Internals/StrictModelIndexing.rst | 2 +- .../mantidqtpython/mantidqtpython_def.sip | 2 +- qt/widgets/common/CMakeLists.txt | 6 +- .../Common/Batch/CellDelegate.h | 6 +- ...tFilterLeafNodes.h => FilteredTreeModel.h} | 21 ++--- .../Common/Batch/JobTreeView.h | 4 +- .../Common/Batch/RowPredicate.h | 19 +++++ qt/widgets/common/src/Batch/CellDelegate.cpp | 2 +- ...terLeafNodes.cpp => FilteredTreeModel.cpp} | 34 ++++----- qt/widgets/common/src/Batch/JobTreeView.cpp | 2 +- qt/widgets/common/src/Batch/RowPredicate.cpp | 14 ++++ 15 files changed, 235 insertions(+), 82 deletions(-) create mode 100644 dev-docs/source/BatchWidget/API/CodeExamples/filtering.py create mode 100644 dev-docs/source/BatchWidget/Internals/QtStandardItemTreeModelAdapter.rst rename qt/widgets/common/inc/MantidQtWidgets/Common/Batch/{QtFilterLeafNodes.h => FilteredTreeModel.h} (59%) create mode 100644 qt/widgets/common/inc/MantidQtWidgets/Common/Batch/RowPredicate.h rename qt/widgets/common/src/Batch/{QtFilterLeafNodes.cpp => FilteredTreeModel.cpp} (52%) create mode 100644 qt/widgets/common/src/Batch/RowPredicate.cpp diff --git a/dev-docs/source/BatchWidget/API/CodeExamples/filtering.py b/dev-docs/source/BatchWidget/API/CodeExamples/filtering.py new file mode 100644 index 00000000000..e25dfdc0b00 --- /dev/null +++ b/dev-docs/source/BatchWidget/API/CodeExamples/filtering.py @@ -0,0 +1,52 @@ +from mantidqtpython import MantidQt +import re + + +class Predicate(MantidQt.MantidWidgets.Batch.RowPredicate): + def __init__(self, meetsCriteria): + super(MantidQt.MantidWidgets.Batch.RowPredicate, self).__init__() + self.meetsCriteria = meetsCriteria + + def rowMeetsCriteria(self, location): + return bool(self.meetsCriteria(location)) + + +def make_regex_filter(table, text, col = 0): + try: + regex = re.compile(text) + return Predicate(lambda location: regex.match(table.cellAt(location, col).contentText())) + except re.error: + return Predicate(lambda location: True) + + +def row(path): + return MantidQt.MantidWidgets.Batch.RowLocation(path) + + +def empty_cell(): + return cell("") + + +def cell(cell_text): + return MantidQt.MantidWidgets.Batch.Cell(cell_text) + + +def row_from_text(*cell_texts): + return [cell(cell_text) for cell_text in cell_texts] + + +# Inside the parent view +def setup(self): + self.table = MantidQt.MantidWidgets.Batch.JobTreeView(["Column 1"], empty_cell(), self) + self.table_signals = MantidQt.MantidWidgets.Batch.JobTreeViewSignalAdapter(self.table, self) + + self.table.appendChildRowOf(row([]), [cell("DD")]) # DD + self.table.appendChildRowOf(row([0]), [cell("DC")]) # DC + self.table.appendChildRowOf(row([0]), [cell("A9")]) # A9 + self.table.appendChildRowOf(row([]), [cell("B0")]) # B0 + self.table.appendChildRowOf(row([]), [cell("C0")]) # C0 + self.table.appendChildRowOf(row([2]), [cell("A1")]) # A1 + + self.table.filterRowsBy(make_regex_filter(self.table, "A[0-9]+", col=0)) + # Applying this filter excludes B0 since neither itself not it's decendant's contents + # match the regex given. diff --git a/dev-docs/source/BatchWidget/API/CodeExamples/init_with_custom_subscriber.cpp b/dev-docs/source/BatchWidget/API/CodeExamples/init_with_custom_subscriber.cpp index c21debf00cc..b157e039778 100644 --- a/dev-docs/source/BatchWidget/API/CodeExamples/init_with_custom_subscriber.cpp +++ b/dev-docs/source/BatchWidget/API/CodeExamples/init_with_custom_subscriber.cpp @@ -14,7 +14,7 @@ public: void notifyRowInserted(RowLocation const &newRowLocation) override {} void notifyRemoveRowsRequested( std::vector<RowLocation> const &locationsOfRowsToRemove) override {} - void notifyCopyRowsRequested() overrride {} + void notifyCopyRowsRequested() override {} void notifyPasteRowsRequested() override {} void notifyFilterReset() override {} diff --git a/dev-docs/source/BatchWidget/API/JobTreeView.rst b/dev-docs/source/BatchWidget/API/JobTreeView.rst index e141dbbaae9..a3a5f1e885e 100644 --- a/dev-docs/source/BatchWidget/API/JobTreeView.rst +++ b/dev-docs/source/BatchWidget/API/JobTreeView.rst @@ -8,6 +8,14 @@ The :code:`JobTreeView` component provides an MVP style view interface for a hie with a spreadsheet-like appearance for configuring and indicating the status of multiple (batch) reduction jobs. It is currently used to implement the tree component of the Batch Widget. +It is written in C++ and exposed to python through SIP leading to similar API's as shown by the +examples below. + +.. literalinclude:: CodeExamples/init.py + +.. literalinclude:: CodeExamples/init.cpp + :language: c++ + API Concepts ############ @@ -24,7 +32,7 @@ number of children or depth of the tree, and the batch widget has mechanisms for Currently a row location is represented as a path from the root node to the row node in question, this is actualised in the :code:`RowLocation` class which contains an ordered list of integers where each element represents the index of the next node in the path relative to it's predecessor in the -path. Some example nodes, their corresponding paths, and their representations are illustrated in +path. An example table and corresponding tree structure, complete with their paths are illustrated in the diagram below. .. image:: ../../images/row_location_path.svg @@ -59,9 +67,9 @@ the code below. Dealing With Cells ------------------ -Each row in the table can have 0..N cells. When interacting with the :code:`JobTreeView` we +Each row in the table can have 0-N cells. When interacting with the :code:`JobTreeView` we sometimes need to be able to address and change the properties of an individual cell. To do this -we use both a :code:`RowLocation` and a column index, usually actualized as an :code:`int`. +we use both a :code:`RowLocation` and a column index. Cells ^^^^^ @@ -75,9 +83,11 @@ view-implementation independent format. These cell objects intentionally have no link back to the view they originated from and so mutating them does not directly update the view. In order to update the cell or cells corresponding to a row, -the methods :code:`setCellAt` or :code:`setCellsAt` should be used. +the methods :code:`setCellAt` or :code:`setCellsAt` should be used. This process is illustrated in +the example code below. + +.. literalinclude:: CodeExamples/change_color.py -This is illustrated in the `Change Cell Color Example`_ below. Subtrees ^^^^^^^^ @@ -106,15 +116,21 @@ Notification ^^^^^^^^^^^^ :code:`JobTreeViewSubscriber` is the mechanism by which the JobTreeView communicates events such as -key presses to the presenter in an MVP setup. This interface is also implemented by -:code:`JobTreeViewSignalAdapter` which makes it easy to use a signals and slots when writing a GUI -from python. +key presses to the presenter in an MVP setup. + +.. literalinclude:: CodeExamples/init_with_custom_subscriber.cpp + :language: c++ + +This interface is also implemented by :code:`JobTreeViewSignalAdapter` which makes it easy to use +signals and slots instead when writing a GUI from python. Due to the interactive nature of some events (such as row insertion, cell modification and filter resets), notification does not happen until after said event has taken place and the view has already been updated. Therefore, if a presenter determines that said action is on-reflection invalid it will be required to call a method which updates the view and rolls back the action. -This is illustrated in the `Depth Limit Example`_ below. +This is illustrated in the example below. + +.. literalinclude:: CodeExamples/depth_limit_example.py Other events (those who's notification method name ends with :code:`Requested`) require the presenter to update the view and/or model and so the notification happens before the view has been updated. @@ -123,35 +139,23 @@ to update the view and/or model and so the notification happens before the view After creating a :code:`JobTreeView` it is important to call the :code:`subscribe` method passing in the subscriber prior to calling any other methods, failure to do so may result in undefined behavior. -Usage Examples -############## +Filtering +^^^^^^^^^ -Initializing a JobTreeView -^^^^^^^^^^^^^^^^^^^^^^^^^^ +Is is possible to make the JobTreeView only show a subset of the nodes in the tree based on an +arbitrary predicate over row locations which can of course be translated to their corresponding +node in the MVP model or their corresponding cells from the view. -.. literalinclude:: CodeExamples/init.py +The header :code:`RowPredicate.h` defines the interface which must be implemented by implementations +of such predicates. The method :code:`filterRowsBy` defined in :code:`JobTreeView` can be used to set +the currently active filter as demonstrated by the code below. -.. literalinclude:: CodeExamples/init.cpp - :language: c++ - - -Initializing a JobTreeView with your own subscriber -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. literalinclude:: CodeExamples/init_with_custom_subscriber.cpp - :language: c++ +.. literalinclude:: CodeExamples/filtering.py +The method :code:`resetFilter` is used to unset the filter such that +all items are shown again and the :code:`hasFilter` method is used to determine if the filter is +currently set. -.. _Depth Limit Example: - -Limiting the depth of the tree -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. literalinclude:: CodeExamples/depth_limit_example.py - -.. _Change Cell Color Example: - -Changing the color of a cell -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. literalinclude:: CodeExamples/change_color.py +Some actions performed on the :code:`JobTreeView` can trigger the filter to be reset automatically. +This necessitates the :code:`notifyFilterReset` method in :code:`JobTreeViewSubscriber` which is +called whenever the filter is reset, even when requested explicitly. diff --git a/dev-docs/source/BatchWidget/Internals/QtStandardItemTreeModelAdapter.rst b/dev-docs/source/BatchWidget/Internals/QtStandardItemTreeModelAdapter.rst new file mode 100644 index 00000000000..1e85db66f16 --- /dev/null +++ b/dev-docs/source/BatchWidget/Internals/QtStandardItemTreeModelAdapter.rst @@ -0,0 +1,75 @@ +.. _QtStandardItemTreeModelAdapter: + +============================== +QtStandardItemTreeModelAdapter +============================== + +The :code:`QtStandardItemTreeModelAdapter` is a class used to perform +The :doc:`../API/JobTreeView` uses :code:`RowLocation` objects in it's API as an abstraction over +:code:`QModelIndex`\ s which are used internally to access :code:`QStandardItem`\ s from the 'models' +provided by Qt. As such, code which simply uses the :code:`JobTreeView` does not need to know anything +about :code:`QModelIndex`\ s. + +MVC Models +^^^^^^^^^^ + +Sections of Qt such as :code:`QTreeView` are designed as an MVC framework rather than an MVP +framework, as such working with some sections of it's API becomes difficult when using MVP. Models in +MVC are directly accessible from the view which is free to read the data directly from it. In MVP +however, data access is marshalled through the presenter, models and presenters are not supposed to +be coupled to any particular view implementation. + +The Main Model +-------------- + +The :code:`JobTreeView` solves this problem by keeping an internal instance of +:code:`QStandardItemModel` a Qt 'model' which fulfils Qt's requirements for a 'model' and which acts +as the view state. We refer to this instance as the 'main model'. + +Filtered Model +-------------- + +To take advantage of the filtering functionality offered by the :code:`QTreeView`, the +:code:`JobTreeView` also manages an instance of :code:`TreeFilterOnSelfOrDescendant`, a class derived from +:code:`QSortFilterProxyModel` which is a filtered version of the 'main model'. + +Strongly Typed Indexes +^^^^^^^^^^^^^^^^^^^^^^ + +The :code:`QModelIndex`\ s into the filtered model cannot be used to directly access items in the +main model. Likewise, the :code:`QModelIndex`\ s cannot be used to directly access items in the +filtered model. Indexes must be explicitly converted between the two spaces. + +To make this less bugprone, the header file :code:`StrictQModelIndices.h` defines two types, +:code:`QModelIndexForMainModel` and :code:`QModelIndexForFilteredModel`. Functions which wish to +constrain the indices they accept and/or return can now make that explicit and use the type system +to catch errors. + +Converting Between Index Spaces +------------------------------- + +The filtered model holds a subset of the items in the main model, therefore: + +* Conversion from a valid index into the filtered model to a valid index into the main model should + always be successful. +* Conversion from a valid index into the main model to a valid index into the main model could be + unsuccessful. + +Given a :code:`QModelIndex`, in order to convert to a strongly typed variant you must know whether +it originated from the filtered model or the main model. Conversion to the appropriate +strongly typed variant is done via assertion using the functions :code:`fromMainModel` and +:code:`fromFilteredModel` provided by :code:`StrictQModelIndices.h`. These functions attempt to +check the assertion by requiring a reference to the model you are claiming the index is from and +comparing it with the pointer returned by calling :code:`.model()` on the model index. However this +is only a heuristic since the index could refer to a cell which has since been removed from the +filtered model due to a change of filter. + +After the construction of the :code:`JobTreeView`, indices provided through :code:`QTreeView` APIs +are indices into the filtered model and must be mapped into the main model before being used to +modify it. :code:`RowLocation`\ s on the other hand always correspond with indices into the main +model. + +Asserting that an index is from one space or the other as described above is not the same as mapping +from one space into the other. This is performed using the functions :code:`mapToMainModel` and +:code:`mapToFilteredModel` defined in :code:`JobTreeView` which internally call methods of the +filtered model. diff --git a/dev-docs/source/BatchWidget/Internals/StrictModelIndexing.rst b/dev-docs/source/BatchWidget/Internals/StrictModelIndexing.rst index 3e424eda871..54634d50378 100644 --- a/dev-docs/source/BatchWidget/Internals/StrictModelIndexing.rst +++ b/dev-docs/source/BatchWidget/Internals/StrictModelIndexing.rst @@ -29,7 +29,7 @@ Filtered Model -------------- To take advantage of the filtering functionality offered by the :code:`QTreeView`, the -:code:`JobTreeView` also manages an instance of :code:`QtFilterLeafNodes`, a class derived from +:code:`JobTreeView` also manages an instance of :code:`FilteredTreeModel`, a class derived from :code:`QSortFilterProxyModel` which is a filtered version of the 'main model'. Strongly Typed Indexes diff --git a/qt/python/mantidqtpython/mantidqtpython_def.sip b/qt/python/mantidqtpython/mantidqtpython_def.sip index d636cd92fc9..b9cdaae4d19 100644 --- a/qt/python/mantidqtpython/mantidqtpython_def.sip +++ b/qt/python/mantidqtpython/mantidqtpython_def.sip @@ -1537,7 +1537,7 @@ public: class RowPredicate { %TypeHeaderCode -#include "MantidQtWidgets/Common/Batch/QtFilterLeafNodes.h" +#include "MantidQtWidgets/Common/Batch/FilteredTreeModel.h" %End protected: RowPredicate(); diff --git a/qt/widgets/common/CMakeLists.txt b/qt/widgets/common/CMakeLists.txt index 3cd5af9918e..806d17317c0 100644 --- a/qt/widgets/common/CMakeLists.txt +++ b/qt/widgets/common/CMakeLists.txt @@ -80,6 +80,7 @@ set ( SRC_FILES src/DataProcessorUI/VectorString.cpp src/Batch/RowLocation.cpp src/Batch/RowLocationAdapter.cpp + src/Batch/RowPredicate.cpp src/Batch/Row.cpp src/Batch/Cell.cpp src/Batch/CellStandardItem.cpp @@ -88,7 +89,7 @@ set ( SRC_FILES src/Batch/JobTreeView.cpp src/Batch/JobTreeViewSignalAdapter.cpp src/Batch/QtStandardItemTreeAdapter.cpp - src/Batch/QtFilterLeafNodes.cpp + src/Batch/FilteredTreeModel.cpp src/Batch/QtBasicNavigation.cpp src/Batch/QtTreeCursorNavigation.cpp src/Batch/CellDelegate.cpp @@ -407,8 +408,9 @@ set ( INC_FILES inc/MantidQtWidgets/Common/Batch/QtBasicNavigation.h inc/MantidQtWidgets/Common/Batch/QtTreeCursorNavigation.h inc/MantidQtWidgets/Common/Batch/StrictQModelIndices.h - inc/MantidQtWidgets/Common/Batch/QtFilterLeafNodes.h + inc/MantidQtWidgets/Common/Batch/FilteredTreeModel.h inc/MantidQtWidgets/Common/Batch/RowLocation.h + inc/MantidQtWidgets/Common/Batch/RowPredicate.h inc/MantidQtWidgets/Common/Batch/RowLocationAdapter.h inc/MantidQtWidgets/Common/Batch/Row.h inc/MantidQtWidgets/Common/Batch/Cell.h diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/Batch/CellDelegate.h b/qt/widgets/common/inc/MantidQtWidgets/Common/Batch/CellDelegate.h index 69cc04312f8..67bbc794512 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/Batch/CellDelegate.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/Batch/CellDelegate.h @@ -3,7 +3,7 @@ #include <QStyledItemDelegate> #include <QTreeView> #include <QStandardItemModel> -#include "MantidQtWidgets/Common/Batch/QtFilterLeafNodes.h" +#include "MantidQtWidgets/Common/Batch/FilteredTreeModel.h" namespace MantidQt { namespace MantidWidgets { @@ -11,14 +11,14 @@ namespace Batch { class CellDelegate : public QStyledItemDelegate { public: explicit CellDelegate(QObject *parent, QTreeView const &view, - QtFilterLeafNodes const &filterModel, + FilteredTreeModel const &filterModel, QStandardItemModel const &mainModel); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; private: QTreeView const &m_view; - QtFilterLeafNodes const &m_filteredModel; + FilteredTreeModel const &m_filteredModel; QStandardItemModel const &m_mainModel; }; } diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/Batch/QtFilterLeafNodes.h b/qt/widgets/common/inc/MantidQtWidgets/Common/Batch/FilteredTreeModel.h similarity index 59% rename from qt/widgets/common/inc/MantidQtWidgets/Common/Batch/QtFilterLeafNodes.h rename to qt/widgets/common/inc/MantidQtWidgets/Common/Batch/FilteredTreeModel.h index f24246c0478..f249768ffdb 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/Batch/QtFilterLeafNodes.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/Batch/FilteredTreeModel.h @@ -1,28 +1,19 @@ -#ifndef MANTIDQTMANTIDWIDGETS_FILTERLEAFNODES_H_ -#define MANTIDQTMANTIDWIDGETS_FILTERLEAFNODES_H_ +#ifndef MANTIDQTMANTIDWIDGETS_FILTEREDTREEMODEL_H_ +#define MANTIDQTMANTIDWIDGETS_FILTEREDTREEMODEL_H_ #include <QSortFilterProxyModel> -#include <functional> #include <memory> #include "MantidQtWidgets/Common/Batch/RowLocation.h" +#include "MantidQtWidgets/Common/Batch/RowPredicate.h" #include "MantidQtWidgets/Common/Batch/RowLocationAdapter.h" #include "MantidQtWidgets/Common/DllOption.h" namespace MantidQt { namespace MantidWidgets { namespace Batch { -class RowPredicate { -public: - bool operator()(RowLocation const &row) const; - virtual ~RowPredicate() = default; - -protected: - virtual bool rowMeetsCriteria(RowLocation const &row) const = 0; -}; - -class EXPORT_OPT_MANTIDQT_COMMON QtFilterLeafNodes +class EXPORT_OPT_MANTIDQT_COMMON FilteredTreeModel : public QSortFilterProxyModel { public: - QtFilterLeafNodes(RowLocationAdapter rowLocation, QObject *parent = nullptr); + FilteredTreeModel(RowLocationAdapter rowLocation, QObject *parent = nullptr); void setPredicate(std::unique_ptr<RowPredicate> predicate); void resetPredicate(); bool isReset() const; @@ -38,4 +29,4 @@ private: } } } -#endif // MANTIDQTMANTIDWIDGETS_FILTERLEAFNODES_H_ +#endif // MANTIDQTMANTIDWIDGETS_FILTEREDTREEMODEL_H_ diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/Batch/JobTreeView.h b/qt/widgets/common/inc/MantidQtWidgets/Common/Batch/JobTreeView.h index 4514586cec3..851cce8b308 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/Batch/JobTreeView.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/Batch/JobTreeView.h @@ -3,7 +3,7 @@ #include "MantidQtWidgets/Common/Batch/ExtractSubtrees.h" #include "MantidQtWidgets/Common/Batch/QtStandardItemTreeAdapter.h" #include "MantidQtWidgets/Common/Batch/QtTreeCursorNavigation.h" -#include "MantidQtWidgets/Common/Batch/QtFilterLeafNodes.h" +#include "MantidQtWidgets/Common/Batch/FilteredTreeModel.h" #include "MantidQtWidgets/Common/Batch/RowLocation.h" #include "MantidQtWidgets/Common/Batch/RowLocationAdapter.h" #include "MantidQtWidgets/Common/Batch/Cell.h" @@ -138,7 +138,7 @@ private: QStandardItemModel m_mainModel; QtStandardItemTreeModelAdapter m_adaptedMainModel; - QtFilterLeafNodes m_filteredModel; + FilteredTreeModel m_filteredModel; QModelIndexForMainModel m_lastEdited; bool m_hasEditorOpen; }; diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/Batch/RowPredicate.h b/qt/widgets/common/inc/MantidQtWidgets/Common/Batch/RowPredicate.h new file mode 100644 index 00000000000..0d22de199e8 --- /dev/null +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/Batch/RowPredicate.h @@ -0,0 +1,19 @@ +#ifndef MANTIDQTMANTIDWIDGETS_ROWPREDICATE_H_ +#define MANTIDQTMANTIDWIDGETS_ROWPREDICATE_H_ +#include "MantidQtWidgets/Common/Batch/RowLocation.h" + +namespace MantidQt { +namespace MantidWidgets { +namespace Batch { +class RowPredicate { +public: + bool operator()(RowLocation const &row) const; + virtual ~RowPredicate() = default; + +protected: + virtual bool rowMeetsCriteria(RowLocation const &row) const = 0; +}; +} +} +} +#endif // MANTIDQTMANTIDWIDGETS_ROWPREDICATE_H_ diff --git a/qt/widgets/common/src/Batch/CellDelegate.cpp b/qt/widgets/common/src/Batch/CellDelegate.cpp index f2d96cea58a..0a0f456a6f5 100644 --- a/qt/widgets/common/src/Batch/CellDelegate.cpp +++ b/qt/widgets/common/src/Batch/CellDelegate.cpp @@ -8,7 +8,7 @@ namespace MantidWidgets { namespace Batch { CellDelegate::CellDelegate(QObject *parent, QTreeView const &view, - QtFilterLeafNodes const &filteredModel, + FilteredTreeModel const &filteredModel, QStandardItemModel const &mainModel) : QStyledItemDelegate(parent), m_view(view), m_filteredModel(filteredModel), m_mainModel(mainModel) {} diff --git a/qt/widgets/common/src/Batch/QtFilterLeafNodes.cpp b/qt/widgets/common/src/Batch/FilteredTreeModel.cpp similarity index 52% rename from qt/widgets/common/src/Batch/QtFilterLeafNodes.cpp rename to qt/widgets/common/src/Batch/FilteredTreeModel.cpp index 29c9d4012f0..8aa01322e44 100644 --- a/qt/widgets/common/src/Batch/QtFilterLeafNodes.cpp +++ b/qt/widgets/common/src/Batch/FilteredTreeModel.cpp @@ -1,48 +1,44 @@ -#include "MantidQtWidgets/Common/Batch/QtFilterLeafNodes.h" +#include "MantidQtWidgets/Common/Batch/FilteredTreeModel.h" #include "MantidQtWidgets/Common/Batch/StrictQModelIndices.h" -#include <iostream> namespace MantidQt { namespace MantidWidgets { namespace Batch { -bool RowPredicate::operator()(RowLocation const &rowLocation) const { - return rowMeetsCriteria(rowLocation); -} - -QtFilterLeafNodes::QtFilterLeafNodes(RowLocationAdapter rowLocationAdapter, +FilteredTreeModel::FilteredTreeModel(RowLocationAdapter rowLocationAdapter, QObject *parent) : QSortFilterProxyModel(parent), m_rowLocation(rowLocationAdapter) { resetPredicate(); } -void QtFilterLeafNodes::resetPredicate() { +void FilteredTreeModel::resetPredicate() { m_predicate = nullptr; invalidate(); } -bool QtFilterLeafNodes::isReset() const { return m_predicate == nullptr; } +bool FilteredTreeModel::isReset() const { return m_predicate == nullptr; } -void QtFilterLeafNodes::setPredicate(std::unique_ptr<RowPredicate> predicate) { +void FilteredTreeModel::setPredicate(std::unique_ptr<RowPredicate> predicate) { m_predicate = std::move(predicate); invalidate(); } -RowLocation QtFilterLeafNodes::rowLocationAt(QModelIndex const &index) const { +RowLocation FilteredTreeModel::rowLocationAt(QModelIndex const &index) const { return m_rowLocation.atIndex(fromMainModel(index, *sourceModel())); } -bool QtFilterLeafNodes::filterAcceptsRow(int row, +bool FilteredTreeModel::filterAcceptsRow(int row, const QModelIndex &parent) const { auto index = sourceModel()->index(row, 0, parent); if (index.isValid()) { - if (m_predicate == nullptr || (*m_predicate)(rowLocationAt(index))) + if (m_predicate == nullptr || (*m_predicate)(rowLocationAt(index))) { return true; - - int rows = sourceModel()->rowCount(index); - for (auto r = 0; r < rows; r++) - if (filterAcceptsRow(r, index)) - return true; - return false; + } else { + int rows = sourceModel()->rowCount(index); + for (auto r = 0; r < rows; r++) + if (filterAcceptsRow(r, index)) + return true; + return false; + } } else { return false; } diff --git a/qt/widgets/common/src/Batch/JobTreeView.cpp b/qt/widgets/common/src/Batch/JobTreeView.cpp index 9ed1de68d78..7a3f3396c31 100644 --- a/qt/widgets/common/src/Batch/JobTreeView.cpp +++ b/qt/widgets/common/src/Batch/JobTreeView.cpp @@ -50,8 +50,8 @@ void JobTreeView::filterRowsBy(RowPredicate *predicate) { } void JobTreeView::resetFilter() { - m_notifyee->notifyFilterReset(); m_filteredModel.resetPredicate(); + m_notifyee->notifyFilterReset(); } bool JobTreeView::hasFilter() const { return m_filteredModel.isReset(); } diff --git a/qt/widgets/common/src/Batch/RowPredicate.cpp b/qt/widgets/common/src/Batch/RowPredicate.cpp new file mode 100644 index 00000000000..054c9c867f3 --- /dev/null +++ b/qt/widgets/common/src/Batch/RowPredicate.cpp @@ -0,0 +1,14 @@ +#include "MantidQtWidgets/Common/Batch/RowPredicate.h" +#include "MantidQtWidgets/Common/Batch/StrictQModelIndices.h" +#include <iostream> +namespace MantidQt { +namespace MantidWidgets { +namespace Batch { + +bool RowPredicate::operator()(RowLocation const &rowLocation) const { + return rowMeetsCriteria(rowLocation); +} + +} +} +} -- GitLab