1 /*
2 # PostgreSQL Database Modeler (pgModeler)
3 #
4 # Copyright 2006-2020 - Raphael Araújo e Silva <raphael@pgmodeler.io>
5 #
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation version 3.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # The complete text of GPLv3 is at LICENSE file on source code root directory.
16 # Also, you can get the complete GNU General Public License at <http://www.gnu.org/licenses/>
17 */
18
19 /**
20 \ingroup libpgmodeler_ui
21 \class BaseObjectWidget
22 \brief Implements the basic operations to create/edit database objects via form.
23 */
24
25 #ifndef BASE_OBJECT_WIDGET_H
26 #define BASE_OBJECT_WIDGET_H
27
28 #include <QtWidgets>
29 #include "databasemodel.h"
30 #include "operationlist.h"
31 #include "modelobjectswidget.h"
32 #include "objectselectorwidget.h"
33 #include "ui_baseobjectwidget.h"
34 #include "pgsqltypewidget.h"
35 #include "pgmodeleruins.h"
36
37 /* Declaring the PgSQLType class as a Qt metatype in order to permit
38 that instances of the class be used as data of QVariant and QMetaType */
39 #include <QMetaType>
Q_DECLARE_METATYPE(PgSqlType)40 Q_DECLARE_METATYPE(PgSqlType)
41
42 class BaseObjectWidget: public QWidget, public Ui::BaseObjectWidget {
43 private:
44 Q_OBJECT
45
46 protected:
47 static constexpr int MaxObjectSize=16777215;
48
49 static const QColor ProtRowBgColor,
50 ProtRowFgColor,
51 RelAddedRowBgColor,
52 RelAddedRowFgColor;
53
54 bool object_protected;
55
56 QHBoxLayout *misc_btns_lt;
57
58 //! \brief Store the kind of object being handled by the widget (configured in the constructor)
59 ObjectType handled_obj_type;
60
61 /*! \brief Operation list element count before editing an object. This attribute
62 is used to know, in case of cancel the edition, the operation (count) that is needed to
63 be removed. This attribute applies only if the object creation is chained (like in tables, views or relationships)
64 See: cancelChainedConfiguration() */
65 unsigned operation_count;
66
67 //! \brief Reference database model
68 DatabaseModel *model;
69
70 //! \brief Reference table/view (used only when editing table objects)
71 BaseTable *table;
72
73 //! \brief Stores the object previous name (used to validate schema renaming)
74 QString prev_name;
75
76 //! \brief Store the object previous schema (used to update the schemas when moving tables/views from one to another)
77 Schema *prev_schema;
78
79 //! \brief Reference relationship (used only when editing relationship attributes)
80 Relationship *relationship;
81
82 //! \brief Reference operation list where all modifications in the form are registered
83 OperationList *op_list;
84
85 //! \brief Object that is being edited / created
86 BaseObject *object;
87
88 /*! \brief Stores the object position (generally the mouse position) when the dialog was called
89 (used only when creating graphical objects) */
90 double object_px, object_py;
91
92 //! \brief Grid layout used to organize the widgets over the form
93 QGridLayout *baseobject_grid;
94
95 //! \brief Indicates if the object is a new one or is being edited
96 bool new_object;
97
98 //! \brief Object selectors for schema, owner, tablespace and collation
99 ObjectSelectorWidget *schema_sel,
100 *owner_sel,
101 *tablespace_sel,
102 *collation_sel;
103
104 /*! \brief Merges the specified grid layout with the 'baseobject_grid' creating a single form.
105 The obj_type parameter must be specified to show the object type icon */
106 void configureFormLayout(QGridLayout *grid=nullptr, ObjectType obj_type=ObjectType::BaseObject);
107
108 /*! \brief Starts a object configuration, alocating a new one if necessary, registering
109 the object on the operation list. This method doens't applies to database model edition */
110 template<class Class>
111 void startConfiguration();
112
113 /*! \brief Finishes the edition / creation of object, registering it on the operation list
114 and inserts is on the parent object */
115 void finishConfiguration();
116
117 //! \brief Apply the basic configurations to the object (name, schema, comment, owner, tablespace)
118 virtual void applyConfiguration();
119
120 void showEvent(QShowEvent *);
121
122 void setAttributes(DatabaseModel *model, OperationList *op_list,
123 BaseObject *object, BaseObject *parent_obj=nullptr,
124 double obj_px=DNaN, double obj_py=DNaN, bool uses_op_list=true);
125
126 /*! \brief This method is a simplification of the original setAttributes. This method must be used
127 only on forms that does not make use of operaton list and not treat graphical objects, since it calls
128 this original one whit the op_list=nullptr and obj_px=DoubleNaN, obj_py=DoubleNaN */
129 void setAttributes(DatabaseModel *model, BaseObject *object, BaseObject *parent_obj);
130
131 //! \brief Disable the object's refereces SQL code
132 void disableReferencesSQL(BaseObject *object);
133
134 void configureTabOrder(vector<QWidget *> widgets={});
135
136 BaseObject *getHandledObject();
137
138 public:
139 //! \brief Constants used to generate version intervals for version alert frame
140 static constexpr unsigned UntilVersion=0,
141 VersionsInterval=1,
142 AfterVersion=2;
143
144 BaseObjectWidget(QWidget * parent = nullptr, ObjectType obj_type=ObjectType::BaseObject);
145
146 virtual ~BaseObjectWidget();
147
148 //! \brief Generates a string containing the specified version interval
149 static QString generateVersionsInterval(unsigned ver_interv_id, const QString &ini_ver, const QString &end_ver="");
150
151 /*! \brief Generates a alert frame highlighting the fields of exclusive use on the specified
152 PostgreSQL versions. On the first map (fields) the key is the PostgreSQL versions and
153 the values are the reference to the widget. The second map is used to specify the values
154 of widgets specific for each version. */
155 static QFrame *generateVersionWarningFrame(map<QString, vector<QWidget *> > &fields, map<QWidget *, vector<QString> > *values=nullptr);
156
157 //! \brief Generates a informative frame containing the specified message
158 static QFrame *generateInformationFrame(const QString &msg);
159
160 static void highlightVersionSpecificFields(map<QString, vector<QWidget *> > &fields, map<QWidget *, vector<QString> > *values=nullptr);
161
162 //! \brief Highlights the specified widget as a required field
163 static void setRequiredField(QWidget *widget);
164
165 //! \brief Filters the ENTER/RETURN key press forcing the button "Apply" to be clicked
166 bool eventFilter(QObject *obj, QEvent *event);
167
168 //! \brief Returns the kind of database object handled
169 ObjectType getHandledObjectType();
170
171 virtual bool isHandledObjectProtected();
172
173 protected slots:
174 void editPermissions();
175 void editCustomSQL();
176
177 //! \brief Register the new object in the operation history if it is not registered already
178 void registerNewObject();
179
180 /*! \brief Aborts the object configuration, deallocation it if necessary or restoring it to
181 its previous configuration */
182 virtual void cancelConfiguration();
183
184 //! \brief Executes the proper actions to cancel chained operations.
185 virtual void cancelChainedOperation();
186
187 signals:
188 //! \brief Signal emitted whenever a object is created / edited using the form
189 void s_objectManipulated();
190
191 //! \brief Signal emitted whenever the object editing was successful and the form need to be closed
192 void s_closeRequested();
193
194 friend class BaseForm;
195 friend class ModelWidget;
196 };
197
198 template<class Class>
startConfiguration(void)199 void BaseObjectWidget::startConfiguration(void)
200 {
201 try
202 {
203 Class *new_tmpl_obj=nullptr;
204
205 //! \brief If the object is already allocated
206 if(this->object && op_list &&
207 this->object->getObjectType()!=ObjectType::Database)
208 {
209 if(this->table)
210 op_list->registerObject(this->object, Operation::ObjectModified, -1, this->table);
211 else
212 op_list->registerObject(this->object, Operation::ObjectModified, -1, this->relationship);
213 new_object=false;
214 }
215 //! \brief If there is need to allocate the object
216 else if(!this->object)
217 {
218 new_tmpl_obj=new Class;
219 this->object=new_tmpl_obj;
220 new_object=true;
221 }
222 }
223 catch(Exception &e)
224 {
225 throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e);
226 }
227 }
228
229 #endif
230