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 #include "baseobjectwidget.h"
20 #include "permissionwidget.h"
21 #include "customsqlwidget.h"
22 #include "baseform.h"
23 #include "generalconfigwidget.h"
24 
25 const QColor BaseObjectWidget::ProtRowBgColor=QColor(255,180,180);
26 const QColor BaseObjectWidget::ProtRowFgColor=QColor(80,80,80);
27 const QColor BaseObjectWidget::RelAddedRowBgColor=QColor(164,249,176);
28 const QColor BaseObjectWidget::RelAddedRowFgColor=QColor(80,80,80);
29 
BaseObjectWidget(QWidget * parent,ObjectType obj_type)30 BaseObjectWidget::BaseObjectWidget(QWidget *parent, ObjectType obj_type): QWidget(parent)
31 {
32 	try
33 	{
34 		QSpacerItem *spacer=nullptr;
35 
36 		setWindowTitle("");
37 		setupUi(this);
38 
39 		handled_obj_type=obj_type;
40 		operation_count=0;
41 		new_object=false;
42 		model=nullptr;
43 		table=nullptr;
44 		relationship=nullptr;
45 		prev_schema=nullptr;
46 		op_list=nullptr;
47 		object=nullptr;
48 		object_px=DNaN;
49 		object_py=DNaN;
50 		schema_sel=nullptr;
51 		owner_sel=nullptr;
52 		tablespace_sel=nullptr;
53 		object_protected = false;
54 
55 		PgModelerUiNs::configureWidgetFont(protected_obj_lbl, PgModelerUiNs::MediumFontFactor);
56 
57 		connect(edt_perms_tb, SIGNAL(clicked(bool)),this, SLOT(editPermissions()));
58 		connect(append_sql_tb, SIGNAL(clicked(bool)),this, SLOT(editCustomSQL()));
59 
60 		schema_sel=new ObjectSelectorWidget(ObjectType::Schema, true, this);
61 		collation_sel=new ObjectSelectorWidget(ObjectType::Collation, true, this);
62 		tablespace_sel=new ObjectSelectorWidget(ObjectType::Tablespace, true, this);
63 		owner_sel=new ObjectSelectorWidget(ObjectType::Role, true, this);
64 
65 		baseobject_grid = new QGridLayout;
66 		baseobject_grid->setObjectName("objetobase_grid");
67 		baseobject_grid->addWidget(protected_obj_frm, 0, 0, 1, 0);
68 		baseobject_grid->addWidget(name_lbl, 1, 0, 1, 1);
69 		baseobject_grid->addWidget(name_edt, 1, 1, 1, 1);
70 		baseobject_grid->addWidget(id_ico_wgt, 1, 2, 1, 3);
71 		baseobject_grid->addWidget(logical_name_lbl, 2, 0, 1, 1);
72 		baseobject_grid->addWidget(alias_edt, 2, 1, 1, 1);
73 		baseobject_grid->addWidget(schema_lbl, 4, 0, 1, 1);
74 		baseobject_grid->addWidget(schema_sel, 4, 1, 1, 4);
75 		baseobject_grid->addWidget(collation_lbl, 5, 0, 1, 1);
76 		baseobject_grid->addWidget(collation_sel, 5, 1, 1, 4);
77 		baseobject_grid->addWidget(tablespace_lbl, 6, 0, 1, 1);
78 		baseobject_grid->addWidget(tablespace_sel, 6, 1, 1, 4);
79 		baseobject_grid->addWidget(owner_lbl, 7, 0, 1, 1);
80 		baseobject_grid->addWidget(owner_sel, 7, 1, 1, 4);
81 		baseobject_grid->addWidget(comment_lbl, 8, 0, 1, 1);
82 		baseobject_grid->addWidget(comment_edt, 8, 1, 1, 4);
83 
84 		misc_btns_lt=new QHBoxLayout;
85 		spacer=new QSpacerItem(20,1,QSizePolicy::Expanding);
86 
87 		misc_btns_lt->addItem(spacer);
88 		misc_btns_lt->addWidget(append_sql_tb);
89 		misc_btns_lt->addWidget(edt_perms_tb);
90 		misc_btns_lt->addWidget(disable_sql_chk);
91 
92 		baseobject_grid->addLayout(misc_btns_lt,9,0,1,5);
93 	}
94 	catch(Exception &e)
95 	{
96 		throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e);
97 	}
98 }
99 
~BaseObjectWidget()100 BaseObjectWidget::~BaseObjectWidget()
101 {
102 
103 }
104 
eventFilter(QObject * object,QEvent * event)105 bool BaseObjectWidget::eventFilter(QObject *object, QEvent *event)
106 {
107 	//Filters the ENTER/RETURN pressing forcing the parent form activate the "Apply" button
108 	if(event->type() == QEvent::KeyPress)
109 	{
110 		QKeyEvent *kevent=dynamic_cast<QKeyEvent *>(event);
111 
112 		// If the object is protected we avoid accepting the enter hit
113 		if(!protected_obj_frm->isVisible() &&
114 			 (kevent->key()==Qt::Key_Return || kevent->key()==Qt::Key_Enter))
115 		{
116 			applyConfiguration();
117 			return true;
118 		}
119 	}
120 
121 	return QWidget::eventFilter(object, event);
122 }
123 
getHandledObjectType()124 ObjectType BaseObjectWidget::getHandledObjectType()
125 {
126 	return handled_obj_type;
127 }
128 
isHandledObjectProtected()129 bool BaseObjectWidget::isHandledObjectProtected()
130 {
131 	return object_protected;
132 }
133 
showEvent(QShowEvent *)134 void BaseObjectWidget::showEvent(QShowEvent *)
135 {
136 	name_edt->setFocus();
137 }
138 
setRequiredField(QWidget * widget)139 void BaseObjectWidget::setRequiredField(QWidget *widget)
140 {
141 	if(widget)
142 	{
143 		QLabel *lbl=qobject_cast<QLabel *>(widget);
144 		QLineEdit *edt=qobject_cast<QLineEdit *>(widget);
145 		QTextEdit *txt=qobject_cast<QTextEdit *>(widget);
146 		QGroupBox *grp=qobject_cast<QGroupBox *>(widget);
147 		ObjectSelectorWidget *sel=dynamic_cast<ObjectSelectorWidget *>(widget);
148 		PgSQLTypeWidget *pgtype=dynamic_cast<PgSQLTypeWidget *>(widget);
149 		QString str_aux=QString(" <span style='color: #ff0000;'>*</span> ");
150 		QColor bgcolor=QColor(QString("#ffffc0"));
151 
152 		if(lbl || pgtype || grp)
153 		{
154 			if(lbl)
155 				lbl->setText(str_aux + lbl->text());
156 
157 			if(!grp)
158 				widget->setStyleSheet(QString("QWidget {	font-weight: bold; }"));
159 			else
160 				grp->setStyleSheet(QString("QGroupBox {	font-weight: bold; }"));
161 		}
162 		else if(edt || txt || sel)
163 		{
164 			if(sel)
165 			{
166 				widget=sel->obj_name_txt;
167 				widget->setStyleSheet(QString("ObjectSelectorWidget > QPlainTextEdit { background-color: %1; }").arg(bgcolor.name()));
168 			}
169 			else
170 			{
171 				QPalette pal;
172 				pal.setColor(QPalette::Base, bgcolor);
173 				pal.setColor(QPalette::Text, QColor(0,0,0));
174 				widget->setPalette(pal);
175 			}
176 		}
177 
178 		str_aux=(!widget->toolTip().isEmpty() ? QString("\n") : "");
179 		widget->setToolTip(widget->toolTip() + str_aux + tr("Required field. Leaving this empty will raise errors!"));
180 	}
181 }
182 
setAttributes(DatabaseModel * model,BaseObject * object,BaseObject * parent_obj)183 void BaseObjectWidget::setAttributes(DatabaseModel *model, BaseObject *object, BaseObject *parent_obj)
184 {
185 	setAttributes(model, nullptr, object, parent_obj, DNaN, DNaN, false);
186 }
187 
disableReferencesSQL(BaseObject * object)188 void BaseObjectWidget::disableReferencesSQL(BaseObject *object)
189 {
190 	vector<BaseObject *> refs;
191 	TableObject *tab_obj=nullptr;
192 
193 	model->getObjectReferences(object, refs);
194 
195 	while(!refs.empty())
196 	{
197 		tab_obj=dynamic_cast<TableObject *>(refs.back());
198 
199 		//If the object is a relationship added does not do anything since the relationship itself will be disabled
200 		if(!tab_obj || (tab_obj && !tab_obj->isAddedByRelationship()))
201 		{
202 			refs.back()->setSQLDisabled(disable_sql_chk->isChecked());
203 
204 			//Update the parent table graphical representation to show the disabled child object
205 			if(tab_obj)
206 				tab_obj->getParentTable()->setModified(true);
207 
208 			//Disable the references of the current object too
209 			disableReferencesSQL(refs.back());
210 		}
211 
212 		refs.pop_back();
213 	}
214 }
215 
configureTabOrder(vector<QWidget * > widgets)216 void BaseObjectWidget::configureTabOrder(vector<QWidget *> widgets)
217 {
218 	ObjectSelectorWidget *obj_sel=nullptr;
219 	PgSQLTypeWidget *type_wgt=nullptr;
220 	vector<QWidget *> children, tab_order;
221 	int idx=0, cnt=0;
222 
223 	widgets.insert(widgets.begin(),
224 	{ name_edt, alias_edt, schema_sel , collation_sel, owner_sel, tablespace_sel,
225 	  comment_edt, append_sql_tb, edt_perms_tb, disable_sql_chk });
226 
227 	for(auto &wgt : widgets)
228 	{
229 		wgt->setFocusPolicy(Qt::StrongFocus);
230 
231 		obj_sel=dynamic_cast<ObjectSelectorWidget *>(wgt);
232 		type_wgt=dynamic_cast<PgSQLTypeWidget *>(wgt);
233 
234 		if(obj_sel)
235 			children={ obj_sel->rem_object_tb, obj_sel->sel_object_tb };
236 		else if(type_wgt)
237 		{
238 			children={ type_wgt->type_cmb, type_wgt->length_sb, type_wgt->precision_sb,
239 					   type_wgt->dimension_sb, type_wgt->interval_cmb, type_wgt->spatial_cmb,
240 					   type_wgt->srid_spb, type_wgt->var_z_chk, type_wgt->var_m_chk,
241 					   type_wgt->timezone_chk };
242 		}
243 
244 		tab_order.push_back(wgt);
245 
246 		for(auto &child : children)
247 		{
248 			child->setFocusPolicy(Qt::StrongFocus);
249 			tab_order.push_back(child);
250 		}
251 	}
252 
253 	cnt=tab_order.size()-1;
254 
255 	for(idx=0; idx < cnt; idx++)
256 		QWidget::setTabOrder(tab_order[idx], tab_order[idx+1]);
257 }
258 
getHandledObject()259 BaseObject *BaseObjectWidget::getHandledObject()
260 {
261 	return object;
262 }
263 
cancelChainedOperation()264 void BaseObjectWidget::cancelChainedOperation()
265 {
266 	bool op_list_changed=false;
267 
268 	if(op_list->isOperationChainStarted())
269 		op_list->finishOperationChain();
270 
271 	if(operation_count < op_list->getCurrentSize())
272 	{
273 		op_list_changed=true;
274 		BaseObjectWidget::cancelConfiguration();
275 	}
276 
277 	if(new_object && this->object)
278 	{
279 		if(!op_list_changed)
280 			delete this->object;
281 
282 		this->object=nullptr;
283 	}
284 }
285 
setAttributes(DatabaseModel * model,OperationList * op_list,BaseObject * object,BaseObject * parent_obj,double obj_px,double obj_py,bool uses_op_list)286 void BaseObjectWidget::setAttributes(DatabaseModel *model, OperationList *op_list, BaseObject *object, BaseObject *parent_obj, double obj_px, double obj_py, bool uses_op_list)
287 {
288 	ObjectType obj_type, parent_type=ObjectType::BaseObject;
289 
290 	/* Reseting the objects attributes in order to force them to be redefined
291 	every time this method is called */
292 	this->object=nullptr;
293 	this->model=nullptr;
294 	this->op_list=nullptr;
295 	this->relationship=nullptr;
296 	this->table=nullptr;
297 
298 	if(!model || (uses_op_list && !op_list))
299 		throw Exception(ErrorCode::AsgNotAllocattedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__);
300 
301 	if(op_list)
302 	  operation_count = op_list->getCurrentSize();
303 
304 	this->model=model;
305 
306 	if(parent_obj)
307 	{
308 		parent_type=parent_obj->getObjectType();
309 
310 		if(BaseTable::isBaseTable(parent_type))
311 			this->table=dynamic_cast<BaseTable *>(parent_obj);
312 		else if(parent_type==ObjectType::Relationship)
313 			this->relationship=dynamic_cast<Relationship *>(parent_obj);
314 		else if(parent_type!=ObjectType::Database && parent_type!=ObjectType::Schema)
315 			throw Exception(ErrorCode::AsgObjectInvalidType,__PRETTY_FUNCTION__,__FILE__,__LINE__);
316 	}
317 	else
318 	{
319 		TableObject *tab_obj=dynamic_cast<TableObject *>(object);
320 
321 		if(object && object->getSchema())
322 			parent_obj=object->getSchema();
323 		else if(tab_obj && tab_obj->getParentTable())
324 			parent_obj=tab_obj->getParentTable();
325 		else
326 			parent_obj=model;
327 	}
328 
329 	if(dynamic_cast<BaseGraphicObject *>(object))
330 		dynamic_cast<BaseGraphicObject *>(object)->setModified(false);
331 
332 	this->op_list=op_list;
333 	this->object=object;
334 
335 	if(this->table)
336 	{
337 		this->object_px=this->table->getPosition().x();
338 		this->object_py=this->table->getPosition().y();
339 	}
340 	else
341 	{
342 		this->object_px=obj_px;
343 		this->object_py=obj_py;
344 	}
345 
346 	name_edt->setFocus();
347 	edt_perms_tb->setEnabled(object!=nullptr && !new_object);
348 	append_sql_tb->setEnabled(object!=nullptr && !new_object);
349 
350 	owner_sel->setModel(model);
351 	owner_sel->setSelectedObject(model->getDefaultObject(ObjectType::Role));
352 
353 	schema_sel->setModel(model);
354 	schema_sel->setSelectedObject(model->getDefaultObject(ObjectType::Schema));
355 
356 	tablespace_sel->setModel(model);
357 	tablespace_sel->setSelectedObject(model->getDefaultObject(ObjectType::Tablespace));
358 
359 	collation_sel->setModel(model);
360 	collation_sel->setSelectedObject(model->getDefaultObject(ObjectType::Collation));
361 
362 	if(object)
363 	{
364 		obj_id_lbl->setVisible(true);
365 		obj_id_lbl->setText(QString("ID: %1").arg(object->getObjectId()));
366 
367 		if(handled_obj_type != ObjectType::BaseObject)
368 			name_edt->setText(object->getName());
369 		else
370 			name_edt->setText(object->getSignature());
371 
372 		comment_edt->setPlainText(object->getComment());
373 		alias_edt->setText(object->getAlias());
374 
375 		/* When creating a new table or relationship the object is pre allocated and the flag new_object is set.
376 	   In order to avoid the selectors to have empty values, we check if the flag is false which means
377 	   that the object is not new at all */
378 		if(!new_object)
379 		{
380 			schema_sel->setSelectedObject(object->getSchema());
381 			tablespace_sel->setSelectedObject(object->getTablespace());
382 			owner_sel->setSelectedObject(object->getOwner());
383 			collation_sel->setSelectedObject(object->getCollation());
384 		}
385 		/* Some objects like tables and views came with a pre selected schema even when
386 	   they are new objects. So we need to show this selected schema instead of the default one */
387 		else if(new_object && object->getSchema())
388 			schema_sel->setSelectedObject(object->getSchema());
389 
390 		obj_type=object->getObjectType();
391 		object_protected=(parent_type!=ObjectType::Relationship &&
392 																	 (object->isProtected() ||
393 																		((obj_type==ObjectType::Column || obj_type==ObjectType::Constraint) &&
394 																		 dynamic_cast<TableObject *>(object)->isAddedByRelationship())));
395 		protected_obj_frm->setVisible(object_protected);
396 		disable_sql_chk->setChecked(object->isSQLDisabled());
397 	}
398 	else
399 	{
400 		object_protected = false;
401 		obj_id_lbl->setVisible(false);
402 		protected_obj_frm->setVisible(false);
403 
404 		if(parent_obj && parent_obj->getObjectType()==ObjectType::Schema)
405 			schema_sel->setSelectedObject(parent_obj);
406 	}
407 }
408 
configureFormLayout(QGridLayout * grid,ObjectType obj_type)409 void BaseObjectWidget::configureFormLayout(QGridLayout *grid, ObjectType obj_type)
410 {
411 	bool show_comment;
412 	QObjectList chld_list;
413 	QWidget *wgt=nullptr;
414 
415 
416 	if(grid)
417 	{
418 		QLayoutItem *item=nullptr;
419 		int lin, col, col_span,row_span, item_id, item_count;
420 
421 		/* Move all the widgets of the passed grid layout one row down,
422 		 permiting the insertion of the 'baseobject_grid' at the top
423 		 of the items */
424 		item_count=grid->count();
425 		for(item_id=item_count-1; item_id >= 0; item_id--)
426 		{
427 			item=grid->itemAt(item_id);
428 			grid->getItemPosition(item_id, &lin, &col, &row_span, &col_span);
429 			grid->removeItem(item);
430 			grid->addItem(item, lin+1, col, row_span, col_span);
431 
432 			/* Configuring QTextEdit to accept tabs as focus changes. This code
433 			only applies to widgets directly linked to the layout. If there is some
434 			QTextEdit nested in some child widget this is not applied */
435 			if(dynamic_cast<QTextEdit *>(item->widget()))
436 				dynamic_cast<QTextEdit *>(item->widget())->setTabChangesFocus(true);
437 		}
438 
439 		//Adding the base layout on the top
440 		grid->addLayout(baseobject_grid, 0,0,1,0);
441 		baseobject_grid=grid;
442 	}
443 	else
444 		this->setLayout(baseobject_grid);
445 
446 	baseobject_grid->setContentsMargins(4, 4, 4, 4);
447 	disable_sql_chk->setVisible(obj_type!=ObjectType::BaseObject && obj_type!=ObjectType::Permission &&
448 															obj_type!=ObjectType::Textbox && obj_type!=ObjectType::Tag &&
449 															obj_type!=ObjectType::Parameter);
450 
451 	alias_edt->setVisible(BaseObject::acceptsAlias(obj_type));
452 	logical_name_lbl->setVisible(BaseObject::acceptsAlias(obj_type));
453 
454 	edt_perms_tb->setVisible(Permission::acceptsPermission(obj_type));
455 	append_sql_tb->setVisible(BaseObject::acceptsCustomSQL(obj_type));
456 
457 	schema_lbl->setVisible(BaseObject::acceptsSchema(obj_type));
458 	schema_sel->setVisible(BaseObject::acceptsSchema(obj_type));
459 
460 	owner_lbl->setVisible(BaseObject::acceptsOwner(obj_type));
461 	owner_sel->setVisible(BaseObject::acceptsOwner(obj_type));
462 
463 	tablespace_lbl->setVisible(BaseObject::acceptsTablespace(obj_type));
464 	tablespace_sel->setVisible(BaseObject::acceptsTablespace(obj_type));
465 
466 	collation_lbl->setVisible(BaseObject::acceptsCollation(obj_type));
467 	collation_sel->setVisible(BaseObject::acceptsCollation(obj_type));
468 
469 	show_comment=obj_type!=ObjectType::Relationship && obj_type!=ObjectType::Textbox &&
470 							 obj_type!=ObjectType::Parameter && obj_type!=ObjectType::UserMapping &&
471 							 obj_type!=ObjectType::Permission;
472 	comment_lbl->setVisible(show_comment);
473 	comment_edt->setVisible(show_comment);
474 
475 	if(obj_type!=ObjectType::BaseObject)
476 	{
477 		obj_icon_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath(obj_type)));
478 		obj_icon_lbl->setToolTip(BaseObject::getTypeName(obj_type));
479 
480 		if(obj_type!=ObjectType::Permission && obj_type!=ObjectType::Cast && obj_type!=ObjectType::UserMapping)
481 		{
482 			setRequiredField(name_lbl);
483 			setRequiredField(name_edt);
484 		}
485 		else
486 		{
487 			QFont font=name_edt->font();
488 			name_edt->setReadOnly(true);
489 			font.setItalic(true);
490 			name_edt->setFont(font);
491 		}
492 
493 		if(obj_type!=ObjectType::Extension)
494 		{
495 			setRequiredField(schema_lbl);
496 			setRequiredField(schema_sel);
497 		}
498 	}
499 
500 	if(BaseObject::acceptsCollation(obj_type))
501 	{
502 		QFrame *frame=nullptr;
503 		map<QString, vector<QWidget *> > fields_map;
504 		fields_map[generateVersionsInterval(AfterVersion, PgSqlVersions::PgSqlVersion91)].push_back(collation_lbl);
505 		frame=generateVersionWarningFrame(fields_map);
506 		baseobject_grid->addWidget(frame, baseobject_grid->count()+1, 0, 1, 0);
507 		frame->setParent(this);
508 	}
509 
510 	//Install the event filter into all children object in order to capture key press
511 	chld_list=this->children();
512 	while(!chld_list.isEmpty())
513 	{
514 		wgt=dynamic_cast<QWidget *>(chld_list.front());
515 
516 		//Avoids install event filters in objects that are inteneded to edit multiple lines
517 		if(wgt &&
518 				wgt->metaObject()->className()!=QString("QPlainTextEdit") &&
519 				wgt->metaObject()->className()!=QString("NumberedTextEditor"))
520 			wgt->installEventFilter(this);
521 
522 		chld_list.pop_front();
523 	}
524 }
525 
generateVersionsInterval(unsigned ver_interv_id,const QString & ini_ver,const QString & end_ver)526 QString BaseObjectWidget::generateVersionsInterval(unsigned ver_interv_id, const QString &ini_ver, const QString &end_ver)
527 {
528 	if(ver_interv_id==UntilVersion && !ini_ver.isEmpty())
529 		return (XmlParser::CharLt + QString("= ") + ini_ver);
530 	else if(ver_interv_id==VersionsInterval && !ini_ver.isEmpty() && !end_ver.isEmpty())
531 		return (XmlParser::CharGt + QString("= ") + ini_ver + XmlParser::CharAmp + XmlParser::CharLt + QString("= ") + end_ver);
532 	else if(ver_interv_id==AfterVersion &&  !ini_ver.isEmpty())
533 		return (XmlParser::CharGt + QString("= ") + ini_ver);
534 	else
535 		return "";
536 }
537 
generateInformationFrame(const QString & msg)538 QFrame *BaseObjectWidget::generateInformationFrame(const QString &msg)
539 {
540 	QFrame *info_frm=nullptr;
541 	QGridLayout *grid=nullptr;
542 	QLabel *ico_lbl=nullptr, *msg_lbl=nullptr;
543 	QFont font;
544 
545 	info_frm = new QFrame;
546 
547 	font.setItalic(false);
548 	font.setBold(false);
549 	info_frm->setFont(font);
550 
551 	PgModelerUiNs::configureWidgetFont(info_frm, PgModelerUiNs::MediumFontFactor);
552 
553 	info_frm->setObjectName("info_frm");
554 	info_frm->setFrameShape(QFrame::StyledPanel);
555 	info_frm->setFrameShadow(QFrame::Raised);
556 	info_frm->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
557 
558 	grid = new QGridLayout(info_frm);
559 	grid->setContentsMargins(4, 4, 4, 4);
560 	grid->setObjectName("grid");
561 
562 	ico_lbl = new QLabel(info_frm);
563 	ico_lbl->setObjectName("icone_lbl");
564 	ico_lbl->setMinimumSize(QSize(24, 24));
565 	ico_lbl->setMaximumSize(QSize(24, 24));
566 	ico_lbl->setScaledContents(true);
567 	ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("msgbox_info")));
568 	ico_lbl->setAlignment(Qt::AlignLeft|Qt::AlignTop);
569 
570 	grid->addWidget(ico_lbl, 0, 0, 1, 1);
571 
572 	msg_lbl = new QLabel(info_frm);
573 	msg_lbl->setFont(font);
574 	msg_lbl->setObjectName("message_lbl");
575 	msg_lbl->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
576 	msg_lbl->setWordWrap(true);
577 
578 	msg_lbl->setText(msg);
579 
580 	grid->addWidget(msg_lbl, 0, 1, 1, 1);
581 	grid->setContentsMargins(4,4,4,4);
582 
583 	return info_frm;
584 }
585 
highlightVersionSpecificFields(map<QString,vector<QWidget * >> & fields,map<QWidget *,vector<QString>> * values)586 void BaseObjectWidget::highlightVersionSpecificFields(map<QString, vector<QWidget *> > &fields,
587 																											map< QWidget *, vector<QString> > *values)
588 {
589 	QString field_name;
590 	QColor color=QColor(0,0,128);
591 
592 	for(auto itr : fields)
593 	{
594 		for(auto wgt : itr.second)
595 		{
596 			if(values && values->count(wgt) > 0)
597 			{
598 				field_name+=QString("<br/>") + tr("Value(s)") + QString(": (");
599 				for(auto value : values->at(wgt))
600 				{
601 					field_name += value;
602 					field_name+=", ";
603 				}
604 
605 				field_name.remove(field_name.length() - 2, 2);
606 				field_name+=")";
607 			}
608 
609 			wgt->setStyleSheet(QString("QWidget {	font-weight: bold; font-style: italic; color: %1}").arg(color.name()));
610 			wgt->setToolTip(QString("<p>PostgreSQL") + itr.first + QString(" %1</p>").arg(field_name));
611 		}
612 	}
613 }
614 
generateVersionWarningFrame(map<QString,vector<QWidget * >> & fields,map<QWidget *,vector<QString>> * values)615 QFrame *BaseObjectWidget::generateVersionWarningFrame(map<QString, vector<QWidget *> > &fields,
616 																											map< QWidget *, vector<QString> > *values)
617 {
618 	QFrame *alert_frm=nullptr;
619 	QGridLayout *grid=nullptr;
620 	QLabel *ico_lbl=nullptr, *msg_lbl=nullptr;
621 	QFont font;
622 	QColor color=QColor(0,0,128);
623 
624 	highlightVersionSpecificFields(fields, values);
625 
626 	alert_frm = new QFrame;
627 	font.setItalic(false);
628 	font.setBold(false);
629 
630 	PgModelerUiNs::configureWidgetFont(alert_frm, PgModelerUiNs::MediumFontFactor);
631 
632 	alert_frm->setObjectName("alerta_frm");
633 	alert_frm->setFrameShape(QFrame::StyledPanel);
634 	alert_frm->setFrameShadow(QFrame::Raised);
635 	alert_frm->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
636 
637 	grid = new QGridLayout(alert_frm);
638 	grid->setObjectName("grid");
639 
640 	ico_lbl = new QLabel(alert_frm);
641 	ico_lbl->setObjectName("icone_lbl");
642 	ico_lbl->setMinimumSize(QSize(24, 24));
643 	ico_lbl->setMaximumSize(QSize(24, 24));
644 	ico_lbl->setScaledContents(true);
645 	ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta")));
646 	ico_lbl->setAlignment(Qt::AlignLeft|Qt::AlignTop);
647 
648 	grid->addWidget(ico_lbl, 0, 0, 1, 1);
649 
650 	msg_lbl = new QLabel(alert_frm);
651 	msg_lbl->setFont(font);
652 	msg_lbl->setObjectName("mensagelm_lb");
653 	msg_lbl->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
654 	msg_lbl->setWordWrap(true);
655 
656 	msg_lbl->setText(tr("The <em style='color: %1'><strong>highlighted</strong></em> fields in the form or one of their values are available only on specific PostgreSQL versions. \
657 							Generating SQL code for versions other than those specified in the fields' tooltips may create incompatible code.").arg(color.name()));
658 
659 	grid->addWidget(msg_lbl, 0, 1, 1, 1);
660 	grid->setContentsMargins(4,4,4,4);
661 
662 	alert_frm->adjustSize();
663 	return alert_frm;
664 }
665 
editPermissions()666 void BaseObjectWidget::editPermissions()
667 {
668 	BaseObject *parent_obj=nullptr;
669 	BaseForm parent_form(this);
670 	PermissionWidget *permission_wgt=new PermissionWidget;
671 
672 	if(this->relationship)
673 		parent_obj=this->relationship;
674 
675 	permission_wgt->setAttributes(this->model, parent_obj, this->object);
676 	parent_form.setMainWidget(permission_wgt);
677 	parent_form.setButtonConfiguration(Messagebox::OkButton);
678 
679 	GeneralConfigWidget::restoreWidgetGeometry(&parent_form, permission_wgt->metaObject()->className());
680 	parent_form.exec();
681 	GeneralConfigWidget::saveWidgetGeometry(&parent_form, permission_wgt->metaObject()->className());
682 }
683 
editCustomSQL()684 void BaseObjectWidget::editCustomSQL()
685 {
686 	BaseForm parent_form(this);
687 	CustomSQLWidget *customsql_wgt=new CustomSQLWidget;
688 
689 	customsql_wgt->setAttributes(this->model, this->object);
690 	parent_form.setMainWidget(customsql_wgt);
691 
692 	GeneralConfigWidget::restoreWidgetGeometry(&parent_form, customsql_wgt->metaObject()->className());
693 	parent_form.exec();
694 	GeneralConfigWidget::saveWidgetGeometry(&parent_form, customsql_wgt->metaObject()->className());
695 }
696 
applyConfiguration()697 void BaseObjectWidget::applyConfiguration()
698 {
699 	if(object)
700 	{
701 		try
702 		{
703 			BaseObject *aux_obj=nullptr, *aux_obj1=nullptr, *parent_obj=nullptr;
704 			bool new_obj;
705 			ObjectType obj_type=object->getObjectType();
706 			QString obj_name;
707 
708 			QApplication::setOverrideCursor(Qt::WaitCursor);
709 			obj_name=BaseObject::formatName(name_edt->text().toUtf8(), obj_type==ObjectType::Operator);
710 
711 			if(this->object->acceptsSchema() &&  schema_sel->getSelectedObject())
712 				obj_name=schema_sel->getSelectedObject()->getName(true) + "." + obj_name;
713 
714 			//Checking the object duplicity
715 			if(obj_type!=ObjectType::Database && obj_type!=ObjectType::Permission && obj_type!=ObjectType::Parameter)
716 			{
717 				if(table)
718 				{
719 					//Validationg the object against the siblings on parent table
720 					parent_obj=table;
721 					aux_obj=table->getObject(obj_name,obj_type);
722 					aux_obj1=table->getObject(object->getName(),obj_type);
723 					new_obj=(!aux_obj && !aux_obj1);
724 				}
725 				else if(relationship)
726 				{
727 					//Validationg the object against the siblings on parent relationship
728 					parent_obj=relationship;
729 					aux_obj=relationship->getObject(obj_name,obj_type);
730 					aux_obj1=relationship->getObject(object->getName(),obj_type);
731 					new_obj=(!aux_obj && !aux_obj1);
732 				}
733 				//Validationg the object against the other objects on model
734 				else
735 				{
736 					parent_obj=model;
737 					aux_obj=model->getObject(obj_name,obj_type);
738 
739 					/* Special case for tables and views. Its necessary to make an additional
740 					checking on table list when the configured object is a view or a checking
741 					on view list when the configured object is a table, this because PostgreSQL
742 					does not accepts tables and views have the same name on the same schema */
743 					aux_obj = model->getObject(obj_name, { ObjectType::Table, ObjectType::ForeignTable, ObjectType::View });
744 					new_obj = (aux_obj == nullptr);
745 				}
746 
747 				//Raises an error if another object is found with the same name as the editing object
748 				if(!new_obj && aux_obj && aux_obj!=object)
749 				{
750 					throw Exception(Exception::getErrorMessage(ErrorCode::AsgDuplicatedObject)
751 									.arg(obj_name)
752 									.arg(BaseObject::getTypeName(obj_type))
753 									.arg(parent_obj->getName(true))
754 									.arg(parent_obj->getTypeName()),
755 									ErrorCode::AsgDuplicatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__);
756 				}
757 			}
758 
759 			//Renames the object (only cast object aren't renamed)
760 			if(obj_type!=ObjectType::Cast)
761 			{
762 				prev_name=object->getName();
763 				object->setName(name_edt->text().trimmed().toUtf8());
764 			}
765 
766 			if(alias_edt->isVisible())
767 				object->setAlias(alias_edt->text().trimmed());
768 
769 			//Sets the object's comment
770 			if(comment_edt->isVisible())
771 				object->setComment(comment_edt->toPlainText().toUtf8());
772 
773 			//Sets the object's tablespace
774 			if(tablespace_sel->isVisible())
775 				object->setTablespace(tablespace_sel->getSelectedObject());
776 
777 			//Sets the object's owner
778 			if(owner_sel->isVisible())
779 				object->setOwner(owner_sel->getSelectedObject());
780 
781 			//Sets the object's collation
782 			if(collation_sel->isVisible())
783 				object->setCollation(collation_sel->getSelectedObject());
784 
785 			//Sets the object's schema
786 			if(schema_sel->isVisible())
787 			{
788 				Schema *esquema=dynamic_cast<Schema *>(schema_sel->getSelectedObject());
789 				this->prev_schema=dynamic_cast<Schema *>(object->getSchema());
790 				object->setSchema(esquema);
791 			}
792 
793 			if(!object->isProtected() && !object->isSystemObject())
794 				PgModelerUiNs::disableObjectSQL(object, disable_sql_chk->isChecked());
795 		}
796 		catch(Exception &e)
797 		{
798 			QApplication::restoreOverrideCursor();
799 			throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__, &e);
800 		}
801 	}
802 }
803 
finishConfiguration()804 void BaseObjectWidget::finishConfiguration()
805 {
806 	try
807 	{
808 		if(this->object)
809 		{
810 			ObjectType obj_type=this->object->getObjectType();
811 			BaseGraphicObject *graph_obj=dynamic_cast<BaseGraphicObject *>(this->object);
812 			TableObject *tab_obj=dynamic_cast<TableObject *>(this->object);
813 			vector<BaseObject *> ref_objs;
814 
815 			if(new_object)
816 			{
817 				//If the object is a table object and the parent table is specified, adds it to table
818 				if(table && TableObject::isTableObject(obj_type))
819 					table->addObject(this->object);
820 				//Adding the object on the relationship, if specified
821 				else if(relationship && (obj_type==ObjectType::Column || obj_type==ObjectType::Constraint))
822 					relationship->addObject(dynamic_cast<TableObject *>(this->object));
823 				//Adding the object on the model
824 				else if(obj_type!=ObjectType::Parameter)
825 					model->addObject(this->object);
826 
827 				registerNewObject();
828 				new_object=false;
829 			}
830 			else
831 			{
832 				//If the object is being updated, validates its SQL definition
833 				if(obj_type==ObjectType::BaseRelationship || obj_type==ObjectType::Textbox || obj_type==ObjectType::Tag)
834 					this->object->getCodeDefinition(SchemaParser::XmlDefinition);
835 				else
836 					this->object->getCodeDefinition(SchemaParser::SqlDefinition);
837 			}
838 
839 			model->getObjectReferences(object, ref_objs);
840 			for(auto &obj : ref_objs)
841 			{
842 				obj->setCodeInvalidated(true);
843 
844 				if(obj->getObjectType()==ObjectType::Column)
845 					dynamic_cast<Column *>(obj)->getParentTable()->setModified(true);
846 			}
847 
848 			object->setCodeInvalidated(true);
849 
850 			//If the object is graphical (or a table object), updates it (or its parent) on the scene
851 			if(graph_obj || tab_obj)
852 			{
853 				if(!graph_obj && tab_obj && tab_obj->getObjectType()!=ObjectType::Parameter)
854 				{
855 					if(this->table)
856 						graph_obj=dynamic_cast<BaseGraphicObject *>(this->table);
857 					else
858 						graph_obj=dynamic_cast<BaseGraphicObject *>(this->relationship);
859 
860 					graph_obj->setModified(true);
861 					graph_obj->setCodeInvalidated(true);
862 				}
863 				else if(graph_obj)
864 				{
865 					if(!std::isnan(object_px) && !std::isnan(object_py))
866 						graph_obj->setPosition(QPointF(object_px, object_py));
867 
868 					graph_obj->setModified(true);
869 				}
870 
871 				/* Updates the visual schemas when the objects is moved to another or a
872 					table object is added to a table */
873 				if(object->getSchema())
874 					dynamic_cast<Schema *>(object->getSchema())->setModified(true);
875 				else if(tab_obj && tab_obj->getParentTable() &&
876 						tab_obj->getParentTable()->getSchema())
877 					dynamic_cast<Schema *>(tab_obj->getParentTable() ->getSchema())->setModified(true);
878 
879 				if(prev_schema && object->getSchema()!=prev_schema)
880 					prev_schema->setModified(true);
881 			}
882 
883 			emit s_objectManipulated();
884 			emit s_closeRequested();
885 		}
886 
887 		QApplication::restoreOverrideCursor();
888 	}
889 	catch(Exception &e)
890 	{
891 		QApplication::restoreOverrideCursor();
892 
893 		if(e.getErrorCode()==ErrorCode::AsgObjectInvalidDefinition)
894 			throw Exception(Exception::getErrorMessage(ErrorCode::RequiredFieldsNotFilled)
895 							.arg(this->object->getName()).arg(this->object->getTypeName()),
896 							ErrorCode::RequiredFieldsNotFilled,__PRETTY_FUNCTION__,__FILE__,__LINE__,&e);
897 		else
898 			throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e);
899 	}
900 }
901 
cancelConfiguration()902 void BaseObjectWidget::cancelConfiguration()
903 {
904 	if(!object)
905 		return;
906 
907 	ObjectType obj_type;
908 	obj_type=this->object->getObjectType();
909 
910 	if(new_object)
911 	{
912 		TableObject *tab_obj=dynamic_cast<TableObject *>(this->object);
913 
914 		//Removes the object from its parent
915 		if(!table && !tab_obj && model->getObjectIndex(this->object) >= 0)
916 			model->removeObject(this->object);
917 		else if(table && table->getObjectIndex(tab_obj) >= 0)
918 			table->removeObject(tab_obj);
919 		else if(relationship && relationship->getObjectIndex(tab_obj) >= 0)
920 			relationship->removeObject(tab_obj);
921 
922 		if(!BaseTable::isBaseTable(obj_type) && obj_type != ObjectType::Relationship)
923 		{
924 			if(!op_list->isObjectRegistered(this->object, Operation::ObjectCreated))
925 				delete this->object;
926 
927 			this->object=nullptr;
928 		}
929 	}
930 
931 	//If the object is not a new one, restore its previous state
932 	if(op_list &&
933 	  ((!new_object && obj_type!=ObjectType::Database && obj_type!=ObjectType::Permission && operation_count != op_list->getCurrentSize()) ||
934 		 (new_object && (BaseTable::isBaseTable(obj_type) || obj_type==ObjectType::Relationship))))
935 	{
936 		try
937 		{
938 			op_list->undoOperation();
939 			op_list->removeLastOperation();
940 		}
941 		catch(Exception &){}
942 	}
943 
944 	QApplication::restoreOverrideCursor();
945 	emit s_objectManipulated();
946 }
947 
registerNewObject()948 void BaseObjectWidget::registerNewObject()
949 {
950 	try
951 	{
952 		if(this->new_object && op_list && !op_list->isObjectRegistered(this->object, Operation::ObjectCreated))
953 		{
954 			//If the object is a new one is necessary register it on the operation list
955 			if(this->table)
956 				op_list->registerObject(this->object, Operation::ObjectCreated, -1, this->table);
957 			else if(this->relationship)
958 				op_list->registerObject(this->object, Operation::ObjectCreated, -1, this->relationship);
959 			else
960 				op_list->registerObject(this->object, Operation::ObjectCreated);
961 		}
962 	}
963 	catch(Exception &e)
964 	{
965 		throw Exception(e.getErrorMessage(),e.getErrorCode(),__PRETTY_FUNCTION__,__FILE__,__LINE__,&e);
966 	}
967 }
968