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