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