1 /***************************************************************************
2     qgsattributesformproperties.h
3     ---------------------
4     begin                : August 2017
5     copyright            : (C) 2017 by David Signer
6     email                : david at opengis dot ch
7  ***************************************************************************
8  *                                                                         *
9  *   This program is free software; you can redistribute it and/or modify  *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  ***************************************************************************/
15 
16 #ifndef QGSATTRIBUTESFORMPROPERTIES_H
17 #define QGSATTRIBUTESFORMPROPERTIES_H
18 
19 // We don't want to expose this in the public API
20 #define SIP_NO_FILE
21 
22 #include <QMimeData>
23 #include <QPushButton>
24 #include <QTableWidget>
25 #include <QTreeWidget>
26 #include <QWidget>
27 #include <QSpinBox>
28 #include <QTreeWidgetItem>
29 #include <QDropEvent>
30 #include <QTableWidgetItem>
31 #include <QMessageBox>
32 #include <QFileDialog>
33 #include <QHBoxLayout>
34 #include <QFormLayout>
35 #include <QPlainTextEdit>
36 
37 #include "ui_qgsattributesformproperties.h"
38 #include "qgis_gui.h"
39 #include "qgsaddattrdialog.h"
40 #include "qgslogger.h"
41 #include "qgsexpressionbuilderdialog.h"
42 #include "qgsfieldcalculator.h"
43 #include "qgsfieldexpressionwidget.h"
44 #include "qgsattributesforminitcode.h"
45 #include "qgsgui.h"
46 #include "qgseditorwidgetfactory.h"
47 #include "qgseditorwidgetregistry.h"
48 #include "qgsrelationmanager.h"
49 
50 class QgsAttributesDnDTree;
51 class QgsAttributeFormContainerEdit;
52 class QgsAttributeTypeDialog;
53 class QgsAttributeWidgetEdit;
54 
55 class GUI_EXPORT QgsAttributesFormProperties : public QWidget, public QgsExpressionContextGenerator, private Ui_QgsAttributesFormProperties
56 {
57     Q_OBJECT
58 
59   public:
60 
61     enum FieldPropertiesRoles
62     {
63       DnDTreeRole = Qt::UserRole,
64       FieldConfigRole,
65       FieldNameRole
66     };
67 
68     struct RelationEditorConfiguration
69     {
70       QgsAttributeEditorRelation::Buttons buttons = QgsAttributeEditorRelation::Button::AllButtons;
71       QVariant nmRelationId;
72       bool forceSuppressFormPopup = false;
73       QString label;
74     };
75 
76     struct QmlElementEditorConfiguration
77     {
78       QString qmlCode;
79     };
80 
81     struct HtmlElementEditorConfiguration
82     {
83       QString htmlCode;
84     };
85 
86     class DnDTreeItemData : public QTreeWidgetItem
87     {
88       public:
89         enum Type
90         {
91           Field,
92           Relation,
93           Container, //!< Container for the form
94           QmlWidget,
95           HtmlWidget,
96           WidgetType //!< In the widget tree, the type of widget
97         };
98 
99         //do we need that
100         DnDTreeItemData() = default;
101 
102         DnDTreeItemData( Type type, const QString &name, const QString &displayName, const QColor &backgroundColor = QColor() )
mType(type)103           : mType( type )
104           , mName( name )
105           , mDisplayName( displayName )
106           , mBackgroundColor( backgroundColor )
107         {}
108 
name()109         QString name() const { return mName; }
setName(const QString & name)110         void setName( const QString &name ) { mName = name; }
111 
displayName()112         QString displayName() const { return mDisplayName; }
setDisplayName(const QString & displayName)113         void setDisplayName( const QString &displayName ) { mDisplayName = displayName; }
114 
type()115         Type type() const { return mType; }
setType(Type type)116         void setType( Type type ) { mType = type; }
117 
QVariant()118         operator QVariant() { return QVariant::fromValue<DnDTreeItemData>( *this ); }
119 
columnCount()120         int columnCount() const { return mColumnCount; }
setColumnCount(int count)121         void setColumnCount( int count ) { mColumnCount = count; }
122 
123         bool showAsGroupBox() const;
124         void setShowAsGroupBox( bool showAsGroupBox );
125 
126         bool showLabel() const;
127         void setShowLabel( bool showLabel );
128 
129         QgsOptionalExpression visibilityExpression() const;
130         void setVisibilityExpression( const QgsOptionalExpression &visibilityExpression );
131 
132         RelationEditorConfiguration relationEditorConfiguration() const;
133         void setRelationEditorConfiguration( RelationEditorConfiguration relationEditorConfiguration );
134 
135         QmlElementEditorConfiguration qmlElementEditorConfiguration() const;
136         void setQmlElementEditorConfiguration( QmlElementEditorConfiguration qmlElementEditorConfiguration );
137 
138         HtmlElementEditorConfiguration htmlElementEditorConfiguration() const;
139         void setHtmlElementEditorConfiguration( HtmlElementEditorConfiguration htmlElementEditorConfiguration );
140 
141         QColor backgroundColor() const;
142         void setBackgroundColor( const QColor &backgroundColor );
143 
144       private:
145         Type mType = Field;
146         QString mName;
147         QString mDisplayName;
148         int mColumnCount = 1;
149         bool mShowAsGroupBox = false;
150         bool mShowLabel = true;
151         QgsOptionalExpression mVisibilityExpression;
152         RelationEditorConfiguration mRelationEditorConfiguration;
153         QmlElementEditorConfiguration mQmlElementEditorConfiguration;
154         HtmlElementEditorConfiguration mHtmlElementEditorConfiguration;
155         QColor mBackgroundColor;
156     };
157 
158 
159     /**
160      * Holds the configuration for a field
161      */
162     struct FieldConfig
163     {
164       FieldConfig() = default;
165       FieldConfig( QgsVectorLayer *layer, int idx );
166 
167       bool mEditable =  true ;
168       bool mEditableEnabled =  true ;
169       bool mLabelOnTop =  false ;
170       QgsFieldConstraints mFieldConstraints;
171       QPushButton *mButton = nullptr;
172       QString mEditorWidgetType;
173       QMap<QString, QVariant> mEditorWidgetConfig;
174       QString mAlias;
175       QgsPropertyCollection mDataDefinedProperties;
176       QString mComment;
177 
178       operator QVariant();
179     };
180 
181   public:
182     explicit QgsAttributesFormProperties( QgsVectorLayer *layer, QWidget *parent = nullptr );
183 
184     QgsAttributeEditorElement *createAttributeEditorWidget( QTreeWidgetItem *item, QgsAttributeEditorElement *parent, bool forceGroup = true );
185 
186     void init();
187     void apply();
188 
189 
190     void loadRelations();
191 
192     void initAvailableWidgetsTree();
193     void initFormLayoutTree();
194     void initLayoutConfig();
195     void initInitPython();
196     void initSuppressCombo();
197 
198     QgsExpressionContext createExpressionContext() const override;
199 
200   protected:
201     void updateButtons();
202 
203     //QList<QgsRelation> mRelations;
204     QgsVectorLayer *mLayer = nullptr;
205 
206     QgsAttributesDnDTree *mAvailableWidgetsTree = nullptr;
207     QgsAttributesDnDTree *mFormLayoutTree = nullptr;
208 
209     QgsAttributeWidgetEdit *mAttributeWidgetEdit = nullptr;
210     QgsAttributeTypeDialog *mAttributeTypeDialog = nullptr;
211     QgsAttributeFormContainerEdit *mAttributeContainerEdit = nullptr;
212     QLabel *mInfoTextWidget = nullptr;
213 
214   private slots:
215 
216     void onInvertSelectionButtonClicked( bool checked );
217     void loadAttributeSpecificEditor( QgsAttributesDnDTree *emitter, QgsAttributesDnDTree *receiver );
218     void onAttributeSelectionChanged();
219     void onFormLayoutSelectionChanged();
220 
221   private:
222     //! this will clean the right panel
223     void clearAttributeTypeFrame();
224 
225     void loadAttributeWidgetEdit();
226     void storeAttributeWidgetEdit();
227 
228     void loadAttributeTypeDialog();
229     void storeAttributeTypeDialog( );
230 
231     void storeAttributeContainerEdit();
232     void loadAttributeContainerEdit();
233 
234     void loadInfoWidget( const QString &infoText );
235 
236     QgsEditFormConfig::PythonInitCodeSource mInitCodeSource = QgsEditFormConfig::CodeSourceNone;
237     QString mInitFunction;
238     QString mInitFilePath;
239     QString mInitCode;
240 
241     QTreeWidgetItem *loadAttributeEditorTreeItem( QgsAttributeEditorElement *widgetDef, QTreeWidgetItem *parent, QgsAttributesDnDTree *tree );
242 
243   private slots:
244     void addTabOrGroupButton();
245     void removeTabOrGroupButton();
246     void mEditorLayoutComboBox_currentIndexChanged( int index );
247     void pbnSelectEditForm_clicked();
248     void mTbInitCode_clicked();
249 };
250 
251 
252 QDataStream &operator<< ( QDataStream &stream, const QgsAttributesFormProperties::DnDTreeItemData &data );
253 QDataStream &operator>> ( QDataStream &stream, QgsAttributesFormProperties::DnDTreeItemData &data );
254 
255 
256 /**
257  * This class overrides mime type handling to be able to work with
258  * the drag and drop attribute editor.
259  *
260  * The mime type is application/x-qgsattributetablefield
261  *
262  * Graphical representation for the attribute editor drag and drop editor
263  */
264 
265 class GUI_EXPORT QgsAttributesDnDTree : public QTreeWidget
266 {
267     Q_OBJECT
268 
269   public:
270     explicit QgsAttributesDnDTree( QgsVectorLayer *layer, QWidget *parent = nullptr );
271 
272     /**
273      * Adds a new item to a \a parent. If \a index is -1, the item is added to the end of the parent's existing children.
274      * Otherwise it is inserted at the specified \a index.
275      */
276     QTreeWidgetItem *addItem( QTreeWidgetItem *parent, QgsAttributesFormProperties::DnDTreeItemData data, int index = -1, const QIcon &icon = QIcon() );
277     QTreeWidgetItem *addContainer( QTreeWidgetItem *parent, const QString &title, int columnCount );
278 
279     enum Type
280     {
281       Drag,
282       Drop
283     };
284 
285 
286     Type type() const;
287     void setType( QgsAttributesDnDTree::Type value );
288 
289   public slots:
290     void selectFirstMatchingItem( const QgsAttributesFormProperties::DnDTreeItemData &data );
291 
292   protected:
293     void dragMoveEvent( QDragMoveEvent *event ) override;
294     void dropEvent( QDropEvent *event ) override;
295     bool dropMimeData( QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action ) override;
296     /* Qt::DropActions supportedDropActions() const;*/
297 
298     // QTreeWidget interface
299   protected:
300     QStringList mimeTypes() const override;
301     QMimeData *mimeData( const QList<QTreeWidgetItem *> items ) const override;
302 
303 
304   private slots:
305     void onItemDoubleClicked( QTreeWidgetItem *item, int column );
306 
307   private:
308     QgsVectorLayer *mLayer = nullptr;
309     Type mType = QgsAttributesDnDTree::Type::Drag;
310 };
311 
312 
313 Q_DECLARE_METATYPE( QgsAttributesFormProperties::FieldConfig )
314 Q_DECLARE_METATYPE( QgsAttributesFormProperties::DnDTreeItemData )
315 
316 #endif // QGSATTRIBUTESFORMPROPERTIES_H
317