1 /***************************************************************************
2                            qgsgrassmoduleinput.h
3                              -------------------
4     begin                : September, 2015
5     copyright            : (C) 2015 by Radim Blazek
6     email                : radim.blazek@gmail.com
7  ***************************************************************************/
8 /***************************************************************************
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  ***************************************************************************/
16 #ifndef QGSGRASSMODULEINPUT_H
17 #define QGSGRASSMODULEINPUT_H
18 
19 #include <QAbstractProxyModel>
20 #include <QCheckBox>
21 #include <QComboBox>
22 #include <QCompleter>
23 #include <QFileSystemModel>
24 #include <QFileSystemWatcher>
25 #include <QGroupBox>
26 #include <QListView>
27 #include <QMap>
28 #include <QSortFilterProxyModel>
29 #include <QStandardItem>
30 #include <QStandardItemModel>
31 #include <QStyledItemDelegate>
32 #include <QTreeView>
33 
34 #include "qgis.h"
35 
36 #include "qgsgrass.h"
37 #include "qgsgrassmodule.h"
38 #include "qgsgrassmoduleparam.h"
39 #include "qgsgrassplugin.h"
40 #include "qgsgrassprovider.h"
41 #include "qgsgrassvector.h"
42 
43 extern "C"
44 {
45 #include <grass/vector.h>
46 }
47 
48 class QgsGrassModuleInputModel : public QStandardItemModel
49 {
50     Q_OBJECT
51 
52   public:
53     enum Role
54     {
55       MapRole = Qt::UserRole,
56       MapsetRole = Qt::UserRole + 1,
57       TypeRole = Qt::UserRole + 2 // QgsGrassObject::Type
58     };
59 
60     explicit QgsGrassModuleInputModel( QObject *parent = nullptr );
61 
62     //! Gets singleton instance of this class.
63     static QgsGrassModuleInputModel *instance();
64 
65     QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override;
66 
67 
68   public slots:
69     //! Reload current mapset
70     void reload();
71 
72     void onMapsetChanged();
73 
74     void onDirectoryChanged( const QString &path );
75     void onFileChanged( const QString &path );
76     void onMapsetSearchPathChanged();
77 
78   private:
79     void addMapset( const QString &mapset );
80     void refreshMapset( QStandardItem *mapsetItem, const QString &mapset, const QList<QgsGrassObject::Type> &types = QList<QgsGrassObject::Type>() );
81     // Add to watched paths if exists and if not yet watched
82     void watch( const QString &path );
83     QString mLocationPath;
84     // mapset watched dirs
watchedDirs()85     QStringList watchedDirs() { QStringList l; l << QStringLiteral( "cellhd" ) << QStringLiteral( "vector" ) << QStringLiteral( "tgis" ); return l; }
86     // names of
87     QStringList locationDirNames();
88     QFileSystemWatcher *mWatcher = nullptr;
89 
90     QgsGrassModuleInputModel( const QgsGrassModuleInputModel & ) = delete;
91     QgsGrassModuleInputModel &operator = ( const QgsGrassModuleInputModel & ) = delete;
92 };
93 
94 // Filter maps by type
95 class QgsGrassModuleInputProxy : public QSortFilterProxyModel
96 {
97     Q_OBJECT
98 
99   public:
100     explicit QgsGrassModuleInputProxy( QgsGrassModuleInputModel *sourceModel, QgsGrassObject::Type type, QObject *parent = nullptr );
101 
102   protected:
103     bool filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const override;
104     bool lessThan( const QModelIndex &left, const QModelIndex &right ) const override;
105 
106   private:
107     QgsGrassModuleInputModel *mSourceModel = nullptr;
108     QgsGrassObject::Type mType;
109 };
110 
111 class QgsGrassModuleInputTreeView : public QTreeView
112 {
113     Q_OBJECT
114   public:
115     explicit QgsGrassModuleInputTreeView( QWidget *parent = nullptr );
116 
117     void resetState();
118 };
119 
120 class QgsGrassModuleInputPopup : public QTreeView
121 {
122     Q_OBJECT
123   public:
124     explicit QgsGrassModuleInputPopup( QWidget *parent = nullptr );
125 
126     void setModel( QAbstractItemModel *model ) override;
127 };
128 
129 // Flattens tree to list of maps for completer
130 class QgsGrassModuleInputCompleterProxy : public QAbstractProxyModel
131 {
132     Q_OBJECT
133   public:
134     explicit QgsGrassModuleInputCompleterProxy( QObject *parent = nullptr );
135 
136     int columnCount( const QModelIndex &parent = QModelIndex() ) const override { Q_UNUSED( parent ) return 1; }
137     int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
138     QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const override;
139     QModelIndex parent( const QModelIndex &index ) const override;
140 
141 
142     void setSourceModel( QAbstractItemModel *sourceModel ) override;
143 
144     QModelIndex mapFromSource( const QModelIndex &sourceIndex ) const override;
145     QModelIndex mapToSource( const QModelIndex &proxyIndex ) const override;
146 
147   private:
148     void refreshMapping();
149     void map( const QModelIndex &parent, int level = 0 );
150     QMap<int, QModelIndex> mIndexes;
151     QMap<QModelIndex, int> mRows;
152 };
153 
154 class QgsGrassModuleInputCompleter : public QCompleter
155 {
156     Q_OBJECT
157 
158   public:
159     explicit QgsGrassModuleInputCompleter( QAbstractItemModel *model, QWidget *parent = nullptr );
160 
161     bool eventFilter( QObject *watched, QEvent *event ) override;
162 };
163 
164 class QgsGrassModuleInputComboBox : public QComboBox
165 {
166     Q_OBJECT
167 
168   public:
169     explicit QgsGrassModuleInputComboBox( QgsGrassObject::Type type, QWidget *parent = nullptr );
170 
171     bool eventFilter( QObject *watched, QEvent *event ) override;
172     void showPopup() override;
173     void hidePopup() override;
174 
175     // set current index
176     void setCurrent( const QModelIndex &proxyIndex );
177 
178     // set current item to map/mapset if exists
179     bool setCurrent( const QString &map, const QString &mapset = QString() );
180 
181     // set to first map if exists
182     bool setFirst();
183 
184   protected:
185     QgsGrassObject::Type mType;
186     QgsGrassModuleInputModel *mModel = nullptr;
187     QgsGrassModuleInputProxy *mProxy = nullptr;
188     QgsGrassModuleInputTreeView *mTreeView = nullptr;
189     // Skip next hidePopup
190     bool mSkipHide;
191 };
192 
193 class QgsGrassModuleInputSelectedDelegate : public QStyledItemDelegate
194 {
195     Q_OBJECT
196   public:
197     explicit QgsGrassModuleInputSelectedDelegate( QObject *parent = nullptr );
198 
199     void paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const override;
200 
201   public slots:
202     void handlePressed( const QModelIndex &index );
203 
204   private:
205     mutable QModelIndex mPressedIndex;
206 };
207 
208 class QgsGrassModuleInputSelectedView : public QTreeView
209 {
210     Q_OBJECT
211   public:
212     explicit QgsGrassModuleInputSelectedView( QWidget *parent = nullptr );
213 
214     void setModel( QAbstractItemModel *model ) override;
215 
216   signals:
217     void deleteItem( const QModelIndex &index );
218 
219   protected:
220     bool eventFilter( QObject *obj, QEvent *event ) override;
221 
222   private:
223     QgsGrassModuleInputSelectedDelegate *mDelegate = nullptr;
224 };
225 
226 
227 /**
228  * \class QgsGrassModuleInput
229  *  \brief Class representing raster or vector module input
230  */
231 class QgsGrassModuleInput : public QgsGrassModuleGroupBoxItem
232 {
233     Q_OBJECT
234 
235   public:
236 
237     /**
238      * \brief Constructor
239      * \param qdesc option element in QGIS module description XML file
240      * \param gdesc GRASS module XML description file
241      */
242     QgsGrassModuleInput( QgsGrassModule *module,
243                          QgsGrassModuleStandardOptions *options, QString key,
244                          QDomElement &qdesc, QDomElement &gdesc, QDomNode &gnode,
245                          bool direct, QWidget *parent = nullptr );
246 
247     //! Returns list of options which will be passed to module
248     QStringList options() override;
249 
250     //! Return vector of attribute fields of current vector
251     QgsFields currentFields();
252 
253     //! Returns pointer to currently selected layer or null
254 
255     QgsGrassObject currentGrassObject();
256 
257     QString currentMap();
258 
259     QgsGrassVectorLayer *currentLayer();
260 
261     QStringList currentGeometryTypeNames();
262 
263     QString ready() override;
264 
265     //! Does this options causes use of region?
266     //  Raster input/output uses region by default
267     //  Use of region can be forced by 'region' attribute in qgm
usesRegion()268     bool usesRegion() { return mUsesRegion; }
269 
270     //! Should be used region of this input
271     bool useRegion();
272 
type()273     QgsGrassObject::Type type() { return mType; }
274 
setGeometryTypeOption(const QString & optionName)275     void setGeometryTypeOption( const QString &optionName ) { mGeometryTypeOption = optionName; }
geometryTypeOption()276     QString geometryTypeOption() const { return mGeometryTypeOption; }
277 
278     // list of selected layers in <field>_<type> form, used by QgsGrassModuleSelection
279     QStringList currentLayerCodes();
280 
281   public slots:
282     void onActivated( const QString &text );
283 
284     void onChanged( const QString &text );
285 
286     void onLayerChanged();
287 
288     void deleteSelectedItem( const QModelIndex &index );
289 
290   signals:
291     // emitted when value changed/selected
292     void valueChanged();
293 
294   private:
295     //! Input type
296     QgsGrassObject::Type mType;
297 
298     // Module options
299     QgsGrassModuleStandardOptions *mModuleStandardOptions = nullptr;
300 
301     //! Vector type mask read from option defined by "typeoption" tag, used for QGIS layers in combo
302     //  + type mask defined in configuration file
303     int mGeometryTypeMask;
304 
305     //! Name of vector type option associated with this input
306     QString mGeometryTypeOption;
307 
308     //! Name of vector layer option associated with this input
309     QString mVectorLayerOption;
310 
311     //! Model used in combo
312     QgsGrassModuleInputModel *mModel = nullptr;
313 
314     //! Model containing currently selected maps
315     QStandardItemModel *mSelectedModel = nullptr;
316 
317     //! Combo box with GRASS layers
318     QgsGrassModuleInputComboBox *mComboBox = nullptr;
319 
320     //! Region button
321     QPushButton *mRegionButton = nullptr;
322 
323     //! Vector sublayer label
324     QLabel *mLayerLabel = nullptr;
325 
326     //! Vector sublayer combo
327     QComboBox *mLayerComboBox = nullptr;
328 
329     //! List of multiple selected maps
330     QgsGrassModuleInputSelectedView *mSelectedTreeView = nullptr;
331 
332     // Vector type checkboxes
333     QMap<int, QCheckBox *> mTypeCheckBoxes;
334 
335     //! Optional map option id, if defined, only the layers from the
336     //  map currently selected in that option are available.
337     //  This is used by nodes layer option for networks.
338     QString mMapId;
339 
340     // Currently selected vector
341     QgsGrassVector *mVector = nullptr;
342 
343     // List of vector layers matching mGeometryTypes for currently selected vector
344     QList<QgsGrassVectorLayer *> mLayers;
345 
346     //! The input map will be updated -> must be from current mapset
347     // TODO
348     bool mUpdate;
349 
350     //! Uses region
351     bool mUsesRegion;
352 
353     QgsGrassModuleInput( const QgsGrassModuleInput & ) = delete;
354     QgsGrassModuleInput &operator = ( const QgsGrassModuleInput & ) = delete;
355 };
356 
357 
358 #endif // QGSGRASSMODULEINPUT_H
359