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 "objectsscene.h"
20
21 bool ObjectsScene::align_objs_grid=false;
22 bool ObjectsScene::show_grid=true;
23 bool ObjectsScene::show_page_delim=true;
24 unsigned ObjectsScene::grid_size=20;
25 QPrinter::PageSize ObjectsScene::paper_size=QPrinter::A4;
26 QPrinter::Orientation ObjectsScene::page_orientation=QPrinter::Landscape;
27 QRectF ObjectsScene::page_margins=QRectF(2,2,2,2);
28 QSizeF ObjectsScene::custom_paper_size=QSizeF(0,0);
29 QBrush ObjectsScene::grid;
30 bool ObjectsScene::corner_move=true;
31 bool ObjectsScene::invert_rangesel_trigger=false;
32
ObjectsScene()33 ObjectsScene::ObjectsScene()
34 {
35 layers.push_back(tr("Default layer"));
36 active_layers.push_back(layers.at(0));
37
38 moving_objs=move_scene=false;
39 enable_range_sel=true;
40 this->setBackgroundBrush(grid);
41
42 sel_ini_pnt.setX(DNaN);
43 sel_ini_pnt.setY(DNaN);
44
45 selection_rect=new QGraphicsPolygonItem;
46 selection_rect->setVisible(false);
47 selection_rect->setZValue(100);
48
49 rel_line=new QGraphicsLineItem;
50 rel_line->setVisible(false);
51 rel_line->setZValue(-1);
52 rel_line->setPen(QColor(80,80,80));
53
54 this->addItem(selection_rect);
55 this->addItem(rel_line);
56
57 scene_move_dx=scene_move_dy=0;
58
59 connect(&scene_move_timer, SIGNAL(timeout()), this, SLOT(moveObjectScene()));
60 connect(&corner_hover_timer, SIGNAL(timeout()), this, SLOT(enableSceneMove()));
61
62 connect(&object_move_timer, &QTimer::timeout, [&](){
63 //If the timer reaches its timeout we execute the procedures to finish the objects movement
64 finishObjectsMove(itemsBoundingRect(true, true).center());
65 object_move_timer.stop();
66 });
67
68 scene_move_timer.setInterval(SceneMoveTimeout);
69 corner_hover_timer.setInterval(SceneMoveTimeout * 10);
70 object_move_timer.setInterval(SceneMoveTimeout * 10);
71 }
72
~ObjectsScene()73 ObjectsScene::~ObjectsScene()
74 {
75 QGraphicsItemGroup *item=nullptr;
76 QList<QGraphicsItem *> items;
77 vector<ObjectType> obj_types={ ObjectType::Relationship, ObjectType::Textbox, ObjectType::View,
78 ObjectType::Table, ObjectType::ForeignTable, ObjectType::Schema };
79
80 this->removeItem(selection_rect);
81 this->removeItem(rel_line);
82
83 delete selection_rect;
84 delete rel_line;
85
86 //Destroy the objects in the order defined on obj_types vector
87 for(auto &type : obj_types)
88 {
89 items=this->items();
90
91 while(!items.isEmpty())
92 {
93 /* Try to convert the item to QGraphicsItemGroup because all the objects
94 used to represent database object are derived from this class */
95 item=dynamic_cast<QGraphicsItemGroup *>(items.front());
96
97 /* Case the object is converted to a item group and can be converted to database
98 objects, indicates that the object can be removed from the scene */
99 if(item && !item->parentItem() &&
100 ((dynamic_cast<RelationshipView *>(item) && type==ObjectType::Relationship) ||
101 (dynamic_cast<TextboxView *>(item) && type==ObjectType::Textbox) ||
102 (dynamic_cast<StyledTextboxView *>(item) && type==ObjectType::Textbox) ||
103 (dynamic_cast<GraphicalView *>(item) && type==ObjectType::View) ||
104 (dynamic_cast<TableView *>(item) && (type==ObjectType::Table || type==ObjectType::ForeignTable)) ||
105 (dynamic_cast<SchemaView *>(item) && type==ObjectType::Schema)))
106
107 {
108 this->removeItem(item);
109 }
110
111 items.pop_front();
112 }
113 }
114
115 //The graphical representation of db objects must be destroyed in a sorted way
116 std::sort(removed_objs.begin(), removed_objs.end());
117 while(!removed_objs.empty())
118 {
119 delete removed_objs.back();
120 removed_objs.pop_back();
121 }
122 }
123
formatLayerName(const QString & name)124 QString ObjectsScene::formatLayerName(const QString &name)
125 {
126 QString fmt_name;
127 unsigned idx = 1;
128
129 //Removing invalid chars
130 for(auto &chr : name)
131 {
132 if(chr.isLetterOrNumber() || chr == ' ' || chr == '_')
133 fmt_name.append(chr);
134 else
135 fmt_name.append('_');
136 }
137
138 //Doing the desambiguation (if needed)
139 while(layers.contains(fmt_name))
140 fmt_name = QString("%1 %2").arg(name).arg(QString::number(idx++));
141
142 return fmt_name;
143 }
144
addLayer(const QString & name)145 QString ObjectsScene::addLayer(const QString &name)
146 {
147 if(name.isEmpty())
148 return "";
149
150 QString fmt_name = formatLayerName(name);
151 layers.push_back(fmt_name);
152
153 emit s_layersChanged();
154 return fmt_name;
155 }
156
renameLayer(unsigned idx,const QString & name)157 QString ObjectsScene::renameLayer(unsigned idx, const QString &name)
158 {
159 if(name.isEmpty() || idx >= static_cast<unsigned>(layers.size()))
160 return "";
161
162 if(name != layers[idx])
163 layers[idx] = formatLayerName(name);
164
165 emit s_layersChanged();
166 return layers[idx];
167 }
168
removeLayer(const QString & name)169 void ObjectsScene::removeLayer(const QString &name)
170 {
171 int idx = layers.indexOf(name);
172
173 if(idx > 0)
174 {
175 moveObjectsToLayer(idx, DefaultLayer);
176 layers.removeAll(name);
177 active_layers.removeAll(name);
178 emit s_layersChanged();
179 }
180 }
181
removeLayers()182 void ObjectsScene::removeLayers()
183 {
184 BaseObjectView *obj_view = nullptr;
185 QString def_layer = layers[DefaultLayer];
186 bool is_active = active_layers.contains(def_layer);
187
188 layers.clear();
189 active_layers.clear();
190 layers.push_back(def_layer);
191
192 if(is_active)
193 active_layers.push_back(def_layer);
194
195 for(auto &item : this->items())
196 {
197 obj_view = dynamic_cast<BaseObjectView *>(item);
198
199 if(obj_view && !obj_view->parentItem() && obj_view->getLayer() != DefaultLayer)
200 {
201 obj_view->setLayer(DefaultLayer);
202 obj_view->setVisible(is_active);
203 }
204 }
205
206 emit s_layersChanged();
207 updateActiveLayers();
208 }
209
setActiveLayers(QStringList act_layers)210 void ObjectsScene::setActiveLayers(QStringList act_layers)
211 {
212 QList<unsigned> layers_idxs;
213 int idx = -1;
214
215 for(auto &layer : act_layers)
216 {
217 idx = layers.indexOf(layer);
218
219 if(idx >= 0)
220 layers_idxs.push_back(idx);
221 }
222
223 setActiveLayers(layers_idxs);
224 }
225
setActiveLayers(QList<unsigned> layers_idxs)226 void ObjectsScene::setActiveLayers(QList<unsigned> layers_idxs)
227 {
228 BaseObjectView *obj_view = nullptr;
229 active_layers.clear();
230
231 if(!layers_idxs.isEmpty())
232 {
233 bool is_in_layer = false;
234 unsigned layer_cnt = static_cast<unsigned>(layers.size());
235 SchemaView *sch_view = nullptr;
236
237 for(auto &item : this->items())
238 {
239 obj_view = dynamic_cast<BaseObjectView *>(item);
240
241 if(obj_view && !obj_view->parentItem() && obj_view->getLayer() < layer_cnt)
242 {
243 sch_view = dynamic_cast<SchemaView *>(obj_view);
244 is_in_layer = layers_idxs.contains(obj_view->getLayer());
245
246 if(!obj_view->isVisible() && is_in_layer)
247 {
248 if(!sch_view ||
249 (sch_view && dynamic_cast<Schema *>(sch_view->getUnderlyingObject())->isRectVisible()))
250 obj_view->setVisible(true);
251 }
252 else if(obj_view->isVisible() && !is_in_layer)
253 obj_view->setVisible(false);
254 }
255 }
256
257 for(auto &idx : layers_idxs)
258 {
259 if(idx < layer_cnt)
260 active_layers.push_back(layers[idx]);
261 }
262 }
263 else
264 {
265 for(auto &item : this->items())
266 {
267 obj_view = dynamic_cast<BaseObjectView *>(item);
268
269 if(obj_view && !obj_view->parentItem())
270 obj_view->setVisible(false);
271 }
272 }
273
274 emit s_activeLayersChanged();
275 }
276
moveObjectsToLayer(unsigned old_layer,unsigned new_layer)277 void ObjectsScene::moveObjectsToLayer(unsigned old_layer, unsigned new_layer)
278 {
279 BaseObjectView *obj_view = nullptr;
280 unsigned total_layers = layers.size();
281
282 if(old_layer == new_layer || old_layer >= total_layers || new_layer >= total_layers)
283 return;
284
285 for(auto &item : this->items())
286 {
287 obj_view = dynamic_cast<BaseObjectView *>(item);
288
289 if(obj_view && !obj_view->parentItem() && obj_view->getLayer() == old_layer)
290 {
291 obj_view->setLayer(new_layer);
292 obj_view->setVisible(isLayerActive(layers[new_layer]));
293 }
294 }
295
296 emit s_objectsMovedLayer();
297 }
298
isLayerActive(const QString & name)299 bool ObjectsScene::isLayerActive(const QString &name)
300 {
301 return active_layers.contains(name);
302 }
303
isLayerActive(unsigned layer_id)304 bool ObjectsScene::isLayerActive(unsigned layer_id)
305 {
306 if(layer_id >= static_cast<unsigned>(layers.size()))
307 return false;
308
309 return active_layers.contains(layers[layer_id]);
310 }
311
getActiveLayers()312 QStringList ObjectsScene::getActiveLayers()
313 {
314 return active_layers;
315 }
316
getActiveLayersIds()317 QList<unsigned> ObjectsScene::getActiveLayersIds()
318 {
319 QList<unsigned> list;
320
321 for(auto &layer : active_layers)
322 list.push_back(layers.indexOf(layer));
323
324 return list;
325 }
326
getLayers()327 QStringList ObjectsScene::getLayers()
328 {
329 return layers;
330 }
331
getLayerId(const QString & name)332 unsigned ObjectsScene::getLayerId(const QString &name)
333 {
334 int idx = layers.contains(name);
335 return idx < 0 ? InvalidLayer : static_cast<unsigned>(idx);
336 }
337
updateActiveLayers()338 void ObjectsScene::updateActiveLayers()
339 {
340 setActiveLayers(active_layers);
341 }
342
setEnableCornerMove(bool enable)343 void ObjectsScene::setEnableCornerMove(bool enable)
344 {
345 ObjectsScene::corner_move=enable;
346 }
347
setInvertRangeSelectionTrigger(bool invert)348 void ObjectsScene::setInvertRangeSelectionTrigger(bool invert)
349 {
350 ObjectsScene::invert_rangesel_trigger=invert;
351 }
352
isCornerMoveEnabled()353 bool ObjectsScene::isCornerMoveEnabled()
354 {
355 return ObjectsScene::corner_move;
356 }
357
alignPointToGrid(const QPointF & pnt)358 QPointF ObjectsScene::alignPointToGrid(const QPointF &pnt)
359 {
360 int px = static_cast<int>(round(pnt.x()/static_cast<double>(grid_size))) * grid_size,
361 py = static_cast<int>(round(pnt.y()/static_cast<double>(grid_size))) * grid_size;
362
363 if(px < 0) px = 0;
364 if(py < 0) py = 0;
365
366 return QPointF(px, py);
367 }
368
setSceneRect(const QRectF & rect)369 void ObjectsScene::setSceneRect(const QRectF &rect)
370 {
371 QGraphicsScene::setSceneRect(0, 0, rect.width(), rect.height());
372 }
373
itemsBoundingRect(bool seek_only_db_objs,bool selected_only)374 QRectF ObjectsScene::itemsBoundingRect(bool seek_only_db_objs, bool selected_only)
375 {
376 if(!seek_only_db_objs)
377 return QGraphicsScene::itemsBoundingRect();
378 else
379 {
380 QRectF rect=QGraphicsScene::itemsBoundingRect();
381 QList<QGraphicsItem *> items= (selected_only ? this->selectedItems() : this->items());
382 double x=rect.width(), y=rect.height(), x2 = -10000, y2 = -10000;
383 BaseObjectView *obj_view=nullptr;
384 QPointF pnt;
385 BaseGraphicObject *graph_obj=nullptr;
386
387 for(auto &item : items)
388 {
389 obj_view=dynamic_cast<BaseObjectView *>(item);
390
391 if(obj_view && obj_view->isVisible())
392 {
393 graph_obj=dynamic_cast<BaseGraphicObject *>(obj_view->getUnderlyingObject());
394
395 if(graph_obj)
396 {
397 if(graph_obj->getObjectType()!=ObjectType::Relationship &&
398 graph_obj->getObjectType()!=ObjectType::BaseRelationship)
399 pnt=graph_obj->getPosition();
400 else
401 pnt=dynamic_cast<RelationshipView *>(obj_view)->__boundingRect().topLeft();
402
403 if(pnt.x() < x)
404 x=pnt.x();
405
406 if(pnt.y() < y)
407 y=pnt.y();
408
409 if(selected_only)
410 {
411 if(graph_obj->getObjectType()!=ObjectType::Relationship &&
412 graph_obj->getObjectType()!=ObjectType::BaseRelationship)
413 pnt = pnt + dynamic_cast<BaseObjectView *>(obj_view)->boundingRect().bottomRight();
414 else
415 pnt = pnt + dynamic_cast<RelationshipView *>(obj_view)->__boundingRect().bottomRight();
416
417 if(pnt.x() > x2)
418 x2 = pnt.x();
419
420 if(pnt.y() > y2)
421 y2 = pnt.y();
422 }
423 }
424 }
425 }
426
427 if(selected_only)
428 return QRectF(QPointF(x, y), QPointF(x2, y2));
429 else
430 return QRectF(QPointF(x, y), rect.bottomRight());
431 }
432 }
433
setGridSize(unsigned size)434 void ObjectsScene::setGridSize(unsigned size)
435 {
436 if(size >= 20 || grid.style()==Qt::NoBrush)
437 {
438 QImage grid_img;
439 double width, height, x, y;
440 int img_w, img_h;
441 QSizeF aux_size;
442 QPrinter printer;
443 QPainter painter;
444 QPen pen;
445
446 configurePrinter(&printer);
447 aux_size=printer.paperSize(QPrinter::Point);
448 aux_size-=page_margins.size();
449
450 //Calculates where the extreme width and height where delimiter lines will be drawn
451 width=aux_size.width()/static_cast<double>(size) * size;
452 height=aux_size.height()/static_cast<double>(size) * size;
453
454 //Calculates the grid pixmpa size
455 img_w=ceil(width/size) * size;
456 img_h=ceil(height/size) * size;
457
458 grid_size=size;
459 grid_img=QImage(img_w, img_h, QImage::Format_ARGB32);
460 grid_img.fill(Qt::white);
461 painter.begin(&grid_img);
462
463 if(show_grid)
464 {
465 pen.setColor(QColor(225, 225, 225));
466 painter.setPen(pen);
467
468 //Draws the grid
469 for(x=0; x < width; x+=size)
470 for(y=0; y < height; y+=size)
471 painter.drawRect(QRectF(QPointF(x,y),QPointF(x + size,y + size)));
472 }
473
474 //Creates the page delimiter lines
475 if(show_page_delim)
476 {
477 pen.setColor(QColor(75,115,195));
478 pen.setStyle(Qt::DashLine);
479 pen.setWidthF(1.0);
480 painter.setPen(pen);
481 painter.drawLine(width-1, 0,width-1,img_h-1);
482 painter.drawLine(0, height-1,img_w-1,height-1);
483 }
484
485 painter.end();
486 grid.setTextureImage(grid_img);
487 }
488 }
489
showRelationshipLine(bool value,const QPointF & p_start)490 void ObjectsScene::showRelationshipLine(bool value, const QPointF &p_start)
491 {
492 QList<QGraphicsItem *> items=this->items();
493 QGraphicsItem::GraphicsItemFlags flags;
494 BaseObjectView *object=nullptr;
495 TableObjectView *tab_obj_view=nullptr;
496 BaseGraphicObject *base_obj=nullptr;
497
498 if(!std::isnan(p_start.x()) && !std::isnan(p_start.y()))
499 rel_line->setLine(QLineF(p_start,p_start));
500
501 rel_line->setVisible(value);
502
503 while(!items.isEmpty())
504 {
505 //When showing the relationship line all the objects cannot be moved
506 flags=QGraphicsItem::ItemIsSelectable |
507 QGraphicsItem::ItemSendsGeometryChanges;
508
509 object = dynamic_cast<BaseObjectView *>(items.front());
510 tab_obj_view = dynamic_cast<TableObjectView *>(object);
511
512 // Discarding table objects views from checking since they can't be normally be selected by a single click
513 if(object && !tab_obj_view && object->getUnderlyingObject())
514 {
515 BaseObject *ul_object = object->getUnderlyingObject();
516 base_obj=dynamic_cast<BaseGraphicObject *>(ul_object);
517
518 if(!value && base_obj &&
519 base_obj->getObjectType()!=ObjectType::Relationship &&
520 base_obj->getObjectType()!=ObjectType::BaseRelationship &&
521 !base_obj->isProtected())
522 flags=QGraphicsItem::ItemIsMovable |
523 QGraphicsItem::ItemIsSelectable |
524 QGraphicsItem::ItemSendsGeometryChanges;
525 else
526 flags=QGraphicsItem::ItemIsSelectable |
527 QGraphicsItem::ItemSendsGeometryChanges;
528 }
529
530 items.front()->setFlags(flags);
531 items.pop_front();
532 }
533 }
534
setGridOptions(bool show_grd,bool align_objs_grd,bool show_pag_dlm)535 void ObjectsScene::setGridOptions(bool show_grd, bool align_objs_grd, bool show_pag_dlm)
536 {
537 bool redef_grid=(ObjectsScene::show_grid!=show_grd ||
538 ObjectsScene::show_page_delim!=show_pag_dlm ||
539 grid.style()==Qt::NoBrush);
540
541 ObjectsScene::show_grid=show_grd;
542 ObjectsScene::show_page_delim=show_pag_dlm;
543 ObjectsScene::align_objs_grid=align_objs_grd;
544
545 if(redef_grid)
546 {
547 grid.setStyle(Qt::NoBrush);
548 setGridSize(ObjectsScene::grid_size);
549 }
550 }
551
isAlignObjectsToGrid()552 bool ObjectsScene::isAlignObjectsToGrid()
553 {
554 return align_objs_grid;
555 }
556
isShowGrid()557 bool ObjectsScene::isShowGrid()
558 {
559 return show_grid;
560 }
561
isShowPageDelimiters()562 bool ObjectsScene::isShowPageDelimiters()
563 {
564 return show_page_delim;
565 }
566
setPaperConfiguration(QPrinter::PaperSize paper_sz,QPrinter::Orientation orient,QRectF margins,QSizeF custom_size)567 void ObjectsScene::setPaperConfiguration(QPrinter::PaperSize paper_sz, QPrinter::Orientation orient, QRectF margins, QSizeF custom_size)
568 {
569 ObjectsScene::paper_size=paper_sz;
570 ObjectsScene::page_orientation=orient;
571 ObjectsScene::page_margins=margins;
572 ObjectsScene::custom_paper_size=custom_size;
573 }
574
getPaperConfiguration(QPrinter::PaperSize & paper_sz,QPrinter::Orientation & orient,QRectF & margins,QSizeF & custom_size)575 void ObjectsScene::getPaperConfiguration(QPrinter::PaperSize &paper_sz, QPrinter::Orientation &orient, QRectF &margins, QSizeF &custom_size)
576 {
577 paper_sz=ObjectsScene::paper_size;
578 orient=ObjectsScene::page_orientation;
579 margins=ObjectsScene::page_margins;
580 custom_size=ObjectsScene::custom_paper_size;
581 }
582
configurePrinter(QPrinter * printer)583 void ObjectsScene::configurePrinter(QPrinter *printer)
584 {
585 if(!printer)
586 throw Exception(ErrorCode::OprNotAllocatedObject ,__PRETTY_FUNCTION__,__FILE__,__LINE__);
587
588 if(paper_size!=QPrinter::Custom)
589 printer->setPaperSize(paper_size);
590 else
591 {
592 QPageLayout pl;
593 QPageSize ps;
594 ps=QPageSize(QSizeF(custom_paper_size.width(), custom_paper_size.height()), QPageSize::Point, "", QPageSize::ExactMatch);
595 pl.setPageSize(ps);
596 pl.setOrientation(page_orientation==QPrinter::Landscape ? QPageLayout::Landscape : QPageLayout::Portrait);
597 printer->setPageSize(pl.pageSize());
598 }
599
600 if(paper_size==QPrinter::Custom)
601 {
602 if(custom_paper_size.width() > custom_paper_size.height())
603 ObjectsScene::page_orientation=QPrinter::Landscape;
604 else
605 ObjectsScene::page_orientation=QPrinter::Portrait;
606 }
607 else
608 printer->setOrientation(page_orientation);
609
610 printer->setPageMargins(page_margins.left(), page_margins.top(), page_margins.width(), page_margins.height(), QPrinter::Millimeter);
611 }
612
configurePrinter(QPrinter * printer,const QSizeF & custom_size,QPrinter::Orientation orient)613 void ObjectsScene::configurePrinter(QPrinter *printer, const QSizeF &custom_size, QPrinter::Orientation orient)
614 {
615 QPrinter::PaperSize orig_page_sz=paper_size;
616 QPrinter::Orientation orig_orient=page_orientation;
617 QSizeF orig_custom_sz=custom_paper_size;
618
619 paper_size=QPrinter::Custom;
620 page_orientation=orient;
621 custom_paper_size=custom_size;
622
623 configurePrinter(printer);
624
625 paper_size=orig_page_sz;
626 page_orientation=orig_orient;
627 custom_paper_size=orig_custom_sz;
628 }
629
handlePopupMenuRequested(TableObject * child_obj)630 void ObjectsScene::handlePopupMenuRequested(TableObject *child_obj)
631 {
632 emit s_popupMenuRequested(child_obj);
633 }
634
handleObjectSelection(BaseGraphicObject * object,bool selected)635 void ObjectsScene::handleObjectSelection(BaseGraphicObject *object, bool selected)
636 {
637 if(object)
638 emit s_objectSelected(object, selected);
639 }
640
handleChildrenSelectionChanged()641 void ObjectsScene::handleChildrenSelectionChanged()
642 {
643 BaseTableView *tab_view = dynamic_cast<BaseTableView *>(sender());
644
645 if(!tab_view)
646 return;
647
648 if(tab_view->getSelectedChidren().empty())
649 tabs_sel_children.removeAll(tab_view);
650 else if(!tabs_sel_children.contains(tab_view))
651 tabs_sel_children.append(tab_view);
652
653 emit s_childrenSelectionChanged();
654 }
655
addItem(QGraphicsItem * item)656 void ObjectsScene::addItem(QGraphicsItem *item)
657 {
658 if(item)
659 {
660 RelationshipView *rel=dynamic_cast<RelationshipView *>(item);
661 BaseTableView *tab=dynamic_cast<BaseTableView *>(item);
662 BaseObjectView *obj=dynamic_cast<BaseObjectView *>(item);
663
664 if(rel)
665 connect(rel, SIGNAL(s_relationshipModified(BaseGraphicObject*)), this, SIGNAL(s_objectModified(BaseGraphicObject*)));
666 else if(tab)
667 {
668 connect(tab, SIGNAL(s_popupMenuRequested(TableObject*)), this, SLOT(handlePopupMenuRequested(TableObject*)));
669 connect(tab, SIGNAL(s_childrenSelectionChanged()), this, SLOT(handleChildrenSelectionChanged()));
670 connect(tab, SIGNAL(s_collapseModeChanged()), this, SIGNAL(s_collapseModeChanged()));
671 connect(tab, SIGNAL(s_paginationToggled()), this, SIGNAL(s_paginationToggled()));
672 connect(tab, SIGNAL(s_currentPageChanged()), this, SIGNAL(s_currentPageChanged()));
673 connect(tab, SIGNAL(s_sceneClearRequested()), this, SLOT(clearSelection()));
674 }
675
676 if(obj)
677 {
678 obj->setVisible(isLayerActive(obj->getLayer()));
679
680 // Relationships and schemas don't have their z value changed
681 if(!rel && !dynamic_cast<SchemaView *>(item))
682 obj->setZValue(dynamic_cast<BaseGraphicObject *>(obj->getUnderlyingObject())->getZValue());
683
684 connect(obj, SIGNAL(s_objectSelected(BaseGraphicObject*,bool)), this, SLOT(handleObjectSelection(BaseGraphicObject*,bool)));
685 }
686
687 QGraphicsScene::addItem(item);
688 }
689 }
690
removeItem(QGraphicsItem * item)691 void ObjectsScene::removeItem(QGraphicsItem *item)
692 {
693 if(item)
694 {
695 BaseObjectView *object=dynamic_cast<BaseObjectView *>(item);
696 RelationshipView *rel=dynamic_cast<RelationshipView *>(item);
697
698 if(rel)
699 rel->disconnectTables();
700
701 item->setVisible(false);
702 item->setActive(false);
703 QGraphicsScene::removeItem(item);
704
705 if(object)
706 {
707 disconnect(object, nullptr, this, nullptr);
708 disconnect(object, nullptr, dynamic_cast<BaseGraphicObject*>(object->getUnderlyingObject()), nullptr);
709 disconnect(dynamic_cast<BaseGraphicObject*>(object->getUnderlyingObject()), nullptr, object, nullptr);
710 removed_objs.push_back(object);
711 }
712 }
713 }
714
blockItemsSignals(bool block)715 void ObjectsScene::blockItemsSignals(bool block)
716 {
717 BaseObjectView *obj_view = nullptr;
718
719 for(auto &item : this->items())
720 {
721 obj_view = dynamic_cast<BaseObjectView *>(item);
722 if(obj_view)
723 obj_view->blockSignals(block);
724 }
725 }
726
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)727 void ObjectsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
728 {
729 QGraphicsScene::mouseDoubleClickEvent(event);
730
731 if(this->selectedItems().size()==1 && event->buttons()==Qt::LeftButton && !rel_line->isVisible())
732 {
733 //Gets the selected graphical object
734 BaseObjectView *obj=dynamic_cast<BaseObjectView *>(this->selectedItems().at(0));
735
736 if(obj)
737 emit s_objectDoubleClicked(dynamic_cast<BaseGraphicObject *>(obj->getUnderlyingObject()));
738 }
739 else
740 //Emit a signal indicating that no object was selected
741 emit s_objectDoubleClicked(nullptr);
742 }
743
mousePressEvent(QGraphicsSceneMouseEvent * event)744 void ObjectsScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
745 {
746 //Gets the item at mouse position
747 QGraphicsItem* item=this->itemAt(event->scenePos(), QTransform());
748 bool is_deselection = !this->selectedItems().isEmpty() && !item;
749
750 if(selectedItems().empty())
751 emit s_objectsScenePressed(event->buttons());
752
753 /* If the relationship line is visible, indicates that the user is in the middle of
754 a relationship creation, thus is needed to inform to the scene to activate the
755 the multiselection to be able to select two tables and link them. By default,
756 the multiselection modifier is the Control key */
757 if(rel_line->isVisible())
758 event->setModifiers(Qt::ControlModifier);
759
760 if(is_deselection)
761 this->blockItemsSignals(true);
762
763 /* If we're handling a deselection of the user selected another object whitout being holding Control
764 * we need to deselect the tables' children objects too */
765 if(is_deselection || (event->buttons()==Qt::LeftButton && (event->modifiers() & Qt::ControlModifier) != Qt::ControlModifier))
766 //Forcing the clear on all selected table children object
767 clearTablesChildrenSelection();
768
769 QGraphicsScene::mousePressEvent(event);
770
771 if(is_deselection)
772 {
773 this->blockItemsSignals(false);
774 emit s_objectSelected(nullptr, false);
775 }
776
777 if(event->buttons()==Qt::LeftButton)
778 {
779 sel_ini_pnt=event->scenePos();
780
781 if((!invert_rangesel_trigger && event->modifiers()==Qt::ShiftModifier) ||
782 (invert_rangesel_trigger && event->modifiers()==Qt::NoModifier))
783 {
784 if(enable_range_sel && this->selectedItems().isEmpty())
785 {
786 selection_rect->setVisible(true);
787 emit s_objectSelected(nullptr,false);
788 }
789 }
790 else
791 {
792 //Selects the object (without press control) if the user is creating a relationship
793 if(item && item->isEnabled() && !item->isSelected() && rel_line->isVisible())
794 item->setSelected(true);
795 }
796 }
797 else if(event->buttons()==Qt::RightButton)
798 {
799 //Case there is no item at the mouse position clears the selection on the scene
800 if(!item)
801 {
802 this->clearSelection();
803 emit s_objectSelected(nullptr,false);
804 }
805
806 emit s_popupMenuRequested();
807 }
808 }
809
mouseIsAtCorner()810 bool ObjectsScene::mouseIsAtCorner()
811 {
812 QGraphicsView *view=getActiveViewport();
813
814 if(view)
815 {
816 QPoint pos=view->mapFromGlobal(QCursor::pos());
817 QRect rect=view->rect();
818
819 if(rect.contains(pos))
820 {
821 if(pos.x() <= SceneMoveThreshold)
822 scene_move_dx=-SceneMoveStep;
823 else if(pos.x() >= (view->width() - view->verticalScrollBar()->width() - SceneMoveThreshold))
824 scene_move_dx=SceneMoveStep;
825 else
826 scene_move_dx=0;
827
828 if(pos.y() <= SceneMoveThreshold)
829 scene_move_dy=-SceneMoveStep;
830 else if(pos.y() >= (view->height() - view->horizontalScrollBar()->height() - SceneMoveThreshold))
831 scene_move_dy=SceneMoveStep;
832 else
833 scene_move_dy=0;
834
835 return scene_move_dx!=0 || scene_move_dy!=0;
836 }
837 else
838 return false;
839 }
840 else
841 return false;
842 }
843
getActiveViewport()844 QGraphicsView *ObjectsScene::getActiveViewport()
845 {
846 QGraphicsView *view_p=nullptr;
847
848 for(auto &view : this->views())
849 {
850 if(view && view->isActiveWindow())
851 {
852 view_p=view;
853 break;
854 }
855 }
856
857 return view_p;
858 }
859
moveObjectScene()860 void ObjectsScene::moveObjectScene()
861 {
862 if(scene_move_dx!=0 || scene_move_dy!=0)
863 {
864 QGraphicsView *view=getActiveViewport();
865
866 if(view && mouseIsAtCorner())
867 {
868 view->horizontalScrollBar()->setValue(view->horizontalScrollBar()->value() + scene_move_dx);
869 view->verticalScrollBar()->setValue(view->verticalScrollBar()->value() + scene_move_dy);
870 move_scene=true;
871 }
872 else
873 {
874 move_scene=false;
875 scene_move_timer.stop();
876 }
877 }
878 }
879
enableSceneMove(bool value)880 void ObjectsScene::enableSceneMove(bool value)
881 {
882 if(value)
883 {
884 scene_move_timer.start();
885 corner_hover_timer.stop();
886 }
887 else
888 {
889 corner_hover_timer.stop();
890 scene_move_timer.stop();
891 }
892
893 move_scene=value;
894 }
895
enableRangeSelection(bool value)896 void ObjectsScene::enableRangeSelection(bool value)
897 {
898 enable_range_sel=value;
899
900 if(!value && selection_rect->isVisible())
901 selection_rect->setVisible(value);
902 }
903
adjustScenePositionOnKeyEvent(int key)904 void ObjectsScene::adjustScenePositionOnKeyEvent(int key)
905 {
906 QGraphicsView *view = getActiveViewport();
907
908 if(view)
909 {
910 QRectF brect = itemsBoundingRect(true, true);
911 QRectF view_rect = QRectF(view->mapToScene(view->rect().topLeft()),
912 view->mapToScene(view->rect().bottomRight())),
913 scene_rect = sceneRect();
914
915 if(view_rect.right() < brect.right() && key == Qt::Key_Right)
916 {
917 /* If the objects are being moved right and the scene width is lesser than the items bounding rect's width
918 we need to resize the scene prior the position adjustment */
919 scene_rect.setRight(brect.right());
920 setSceneRect(scene_rect);
921 view->horizontalScrollBar()->setValue(view->horizontalScrollBar()->value() + ((brect.right() - view_rect.right()) * 2));
922 }
923 else if(view_rect.left() > brect.left() && key == Qt::Key_Left)
924 view->horizontalScrollBar()->setValue(view->horizontalScrollBar()->value() - ((view_rect.left() - brect.left()) * 2));
925
926 if(view_rect.bottom() < brect.bottom() && key == Qt::Key_Down)
927 {
928 /* If the objects are being moved down and the scene hight is lesser than the items bounding rect's height
929 we need to resize the scene prior the position adjustment */
930 scene_rect.setBottom(brect.bottom());
931 setSceneRect(scene_rect);
932 view->verticalScrollBar()->setValue(view->verticalScrollBar()->value() + ((brect.bottom() - view_rect.bottom()) * 2));
933 }
934 else if(view_rect.top() > brect.top() && key == Qt::Key_Up)
935 view->verticalScrollBar()->setValue(view->verticalScrollBar()->value() - ((view_rect.top() - brect.top()) * 2));
936 }
937 }
938
keyPressEvent(QKeyEvent * event)939 void ObjectsScene::keyPressEvent(QKeyEvent *event)
940 {
941 if((event->key() == Qt::Key_Up || event->key() == Qt::Key_Down ||
942 event->key() == Qt::Key_Left || event->key() == Qt::Key_Right) &&
943 !selectedItems().isEmpty())
944 {
945 double dx = 0, dy = 0;
946 BaseObjectView *obj_view=nullptr;
947 QRectF brect = itemsBoundingRect(true, true);
948
949 if(!moving_objs)
950 {
951 sel_ini_pnt = brect.center();
952 moving_objs = true;
953
954 /* If the object move timer is not active we need to send the
955 s_objectsMoved() signal in order to alert the classes like ModelWidget to
956 save the current objects' position in the operation history */
957 if(!object_move_timer.isActive())
958 emit s_objectsMoved(false);
959
960 for(auto item : selectedItems())
961 {
962 obj_view=dynamic_cast<BaseObjectView *>(item);
963
964 if(obj_view && BaseObjectView::isPlaceholderEnabled())
965 obj_view->togglePlaceholder(true);
966 }
967 }
968
969 if(event->key() == Qt::Key_Up)
970 dy = -1;
971 else if(event->key() == Qt::Key_Down)
972 dy = 1;
973
974 if(event->key() == Qt::Key_Left)
975 dx = -1;
976 else if(event->key() == Qt::Key_Right)
977 dx = 1;
978
979 if(event->modifiers() == Qt::ControlModifier)
980 {
981 dx *= 10;
982 dy *= 10;
983 }
984 else if(event->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier))
985 {
986 dx *= 100;
987 dy *= 100;
988 }
989
990 for(auto item : selectedItems())
991 {
992 obj_view=dynamic_cast<BaseObjectView *>(item);
993
994 if(obj_view && !dynamic_cast<RelationshipView *>(obj_view))
995 obj_view->moveBy(dx, dy);
996 }
997
998 adjustScenePositionOnKeyEvent(event->key());
999 }
1000 else
1001 QGraphicsScene::keyPressEvent(event);
1002 }
1003
keyReleaseEvent(QKeyEvent * event)1004 void ObjectsScene::keyReleaseEvent(QKeyEvent *event)
1005 {
1006 if((event->key() == Qt::Key_Up || event->key() == Qt::Key_Down ||
1007 event->key() == Qt::Key_Left || event->key() == Qt::Key_Right) &&
1008 !event->isAutoRepeat() && !selectedItems().isEmpty())
1009 {
1010 if(moving_objs)
1011 {
1012 object_move_timer.start();
1013 adjustScenePositionOnKeyEvent(event->key());
1014 }
1015 }
1016 else
1017 QGraphicsScene::keyReleaseEvent(event);
1018 }
1019
mouseMoveEvent(QGraphicsSceneMouseEvent * event)1020 void ObjectsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1021 {
1022 if(event->buttons()==Qt::LeftButton || rel_line->isVisible())
1023 {
1024 if(corner_move)
1025 {
1026 if(mouseIsAtCorner())
1027 {
1028 if(move_scene)
1029 scene_move_timer.start();
1030 else
1031 corner_hover_timer.start();
1032 }
1033 else
1034 enableSceneMove(false);
1035 }
1036
1037 if(!rel_line->isVisible())
1038 {
1039 int sel_items_count = this->selectedItems().size();
1040
1041 //Case the user starts a object moviment
1042 if(sel_items_count != 0 && !moving_objs)
1043 {
1044 if(BaseObjectView::isPlaceholderEnabled())
1045 {
1046 QList<QGraphicsItem *> items=this->selectedItems();
1047 BaseObjectView *obj_view=nullptr;
1048
1049 for(QGraphicsItem *item : items)
1050 {
1051 obj_view=dynamic_cast<BaseObjectView *>(item);
1052 obj_view->togglePlaceholder(true);
1053 }
1054 }
1055
1056 emit s_objectsMoved(false);
1057 moving_objs=true;
1058 }
1059
1060 //If the alignment to grid is active, adjust the event scene position
1061 if(align_objs_grid && !selection_rect->isVisible() && sel_items_count <= 1)
1062 event->setScenePos(this->alignPointToGrid(event->scenePos()));
1063 else if(selection_rect->isVisible())
1064 {
1065 QPolygonF pol;
1066 pol.append(sel_ini_pnt);
1067 pol.append(QPointF(event->scenePos().x(), sel_ini_pnt.y()));
1068 pol.append(QPointF(event->scenePos().x(), event->scenePos().y()));
1069 pol.append(QPointF(sel_ini_pnt.x(), event->scenePos().y()));
1070 selection_rect->setPolygon(pol);
1071 selection_rect->setBrush(BaseObjectView::getFillStyle(Attributes::ObjSelection));
1072 selection_rect->setPen(BaseObjectView::getBorderStyle(Attributes::ObjSelection));
1073 }
1074 }
1075 }
1076
1077 if(rel_line->isVisible())
1078 rel_line->setLine(QLineF(rel_line->line().p1(), event->scenePos()));
1079
1080 QGraphicsScene::mouseMoveEvent(event);
1081 }
1082
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)1083 void ObjectsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1084 {
1085 QGraphicsScene::mouseReleaseEvent(event);
1086
1087 if(event->button()==Qt::LeftButton && corner_move)
1088 enableSceneMove(false);
1089
1090 //If there is selected object and the user ends the object moviment
1091 if(!this->selectedItems().isEmpty() && moving_objs && event->button()==Qt::LeftButton/* && event->modifiers()==Qt::NoModifier */)
1092 {
1093 finishObjectsMove(event->scenePos());
1094 }
1095 else if(selection_rect->isVisible() && event->button()==Qt::LeftButton)
1096 {
1097 QPolygonF pol;
1098 QPainterPath sel_area;
1099
1100 sel_area.addRect(selection_rect->polygon().boundingRect());
1101
1102 this->blockItemsSignals(true);
1103 this->setSelectionArea(sel_area, Qt::IntersectsItemShape);
1104 this->blockItemsSignals(false);
1105
1106 selection_rect->setVisible(false);
1107 selection_rect->setPolygon(pol);
1108 sel_ini_pnt.setX(DNaN);
1109 sel_ini_pnt.setY(DNaN);
1110
1111 if(!this->selectedItems().isEmpty())
1112 emit s_objectsSelectedInRange();
1113 }
1114 }
1115
finishObjectsMove(const QPointF & pnt_end)1116 void ObjectsScene::finishObjectsMove(const QPointF &pnt_end)
1117 {
1118 QList<QGraphicsItem *> items=this->selectedItems(), rel_list;
1119 double x1,y1,x2,y2, dx, dy;
1120 QRectF rect;
1121 SchemaView *sch_view=nullptr;
1122 vector<QPointF> points;
1123 vector<QPointF>::iterator itr;
1124 vector<BaseObject *> rels, base_rels;
1125 QSet<Schema *> schemas;
1126 BaseRelationship *base_rel=nullptr;
1127 RelationshipView *rel=nullptr;
1128 BaseObjectView *obj_view=nullptr;
1129 BaseTableView *tab_view=nullptr;
1130 TableObjectView *tab_obj_view=nullptr;
1131 QSet<BaseObjectView *> tables;
1132
1133 //Gathering the relationships inside the selected schemsa in order to move their points too
1134 for(auto &item : items)
1135 {
1136 obj_view=dynamic_cast<BaseObjectView *>(item);
1137 sch_view=dynamic_cast<SchemaView *>(item);
1138 tab_view=dynamic_cast<BaseTableView *>(item);
1139 tab_obj_view=dynamic_cast<TableObjectView *>(item);
1140
1141 // Ignoring table objects items
1142 if(tab_obj_view)
1143 continue;
1144
1145 if(obj_view)
1146 obj_view->togglePlaceholder(false);
1147
1148 if(tab_view)
1149 tables.insert(tab_view);
1150 else if(sch_view)
1151 {
1152 //Get the schema object
1153 Schema *schema=dynamic_cast<Schema *>(sch_view->getUnderlyingObject());
1154
1155 if(!schema->isProtected())
1156 {
1157 //Get the table-table and table-view relationships
1158 rels=dynamic_cast<DatabaseModel *>(schema->getDatabase())->getObjects(ObjectType::Relationship, schema);
1159 base_rels=dynamic_cast<DatabaseModel *>(schema->getDatabase())->getObjects(ObjectType::BaseRelationship, schema);
1160 rels.insert(rels.end(), base_rels.begin(), base_rels.end());
1161
1162 for(auto &rel : rels)
1163 {
1164 base_rel=dynamic_cast<BaseRelationship *>(rel);
1165
1166 /* If the relationship contains points and it is not selected then it will be included on the list
1167 in order to move their custom line points */
1168 if(!dynamic_cast<RelationshipView *>(base_rel->getOverlyingObject())->isSelected() &&
1169 !base_rel->getPoints().empty())
1170 rel_list.push_back(dynamic_cast<QGraphicsItem *>(base_rel->getOverlyingObject()));
1171 }
1172
1173 #if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
1174 tables.unite(sch_view->getChildren().toSet());
1175 #else
1176 QList<BaseObjectView *> list = sch_view->getChildren();
1177 tables.unite(QSet<BaseObjectView *>(list.begin(), list.end()));
1178 #endif
1179 }
1180 }
1181 }
1182
1183 items.append(rel_list);
1184
1185 /* Get the extreme points of the scene to check if some objects are out the area
1186 forcing the scene to be resized */
1187 x1=this->sceneRect().left();
1188 y1=this->sceneRect().top();
1189 x2=this->sceneRect().right();
1190 y2=this->sceneRect().bottom();
1191 dx=pnt_end.x() - sel_ini_pnt.x();
1192 dy=pnt_end.y() - sel_ini_pnt.y();
1193
1194 for(auto &item : items)
1195 {
1196 // Ignoring table objects items
1197 tab_obj_view=dynamic_cast<TableObjectView *>(item);
1198 if(tab_obj_view) continue;
1199
1200 rel=dynamic_cast<RelationshipView *>(item);
1201
1202 if(!rel)
1203 {
1204 if(align_objs_grid)
1205 item->setPos(alignPointToGrid(item->pos()));
1206 else
1207 {
1208 QPointF p=item->pos();
1209 if(p.x() < 0) p.setX(0);
1210 if(p.y() < 0) p.setY(0);
1211 item->setPos(p);
1212 }
1213
1214 rect.setTopLeft(item->pos());
1215 rect.setSize(item->boundingRect().size());
1216 }
1217 else
1218 {
1219 /* If the relationship has points added to the line is necessary to move the points
1220 too. Since relationships cannot be moved naturally (by user) this will be done
1221 by the scene. NOTE: this operation is done ONLY WHEN there is more than one object selected! */
1222 points=rel->getUnderlyingObject()->getPoints();
1223 if(items.size() > 1 && !points.empty())
1224 {
1225 itr=points.begin();
1226 while(itr!=points.end())
1227 {
1228 //Translate the points
1229 itr->setX(itr->x() + dx);
1230 itr->setY(itr->y() + dy);
1231
1232 //Align to grid if the flag is set
1233 if(align_objs_grid)
1234 (*itr)=alignPointToGrid(*itr);
1235
1236 itr++;
1237 }
1238
1239 //Assing the new points to relationship and reconfigure its line
1240 rel->getUnderlyingObject()->setPoints(points);
1241 rel->configureLine();
1242 }
1243
1244 rect=rel->__boundingRect();
1245 }
1246
1247 //Made the comparisson between the scene extremity and the object's bounding rect
1248 if(rect.left() < x1) x1=rect.left();
1249 if(rect.top() < y1) y1=rect.top();
1250 if(rect.right() > x2) x2=rect.right();
1251 if(rect.bottom() > y2) y2=rect.bottom();
1252 }
1253
1254 //Reconfigures the rectangle with the most extreme points
1255 rect.setCoords(x1, y1, x2, y2);
1256
1257 //If the new rect is greater than the scene bounding rect, this latter is resized
1258 if(rect!=this->sceneRect())
1259 {
1260 rect=this->itemsBoundingRect();
1261 rect.setTopLeft(QPointF(0,0));
1262 rect.setWidth(rect.width() * 1.05);
1263 rect.setHeight(rect.height() * 1.05);
1264 this->setSceneRect(rect);
1265 }
1266
1267 for(auto &obj : tables)
1268 {
1269 tab_view=dynamic_cast<BaseTableView *>(obj);
1270
1271 //Realign tables if the parent schema had the position adjusted too
1272 if(align_objs_grid)
1273 {
1274 tab_view->setPos(alignPointToGrid(tab_view->pos()));
1275 schemas.insert(dynamic_cast<Schema *>(tab_view->getUnderlyingObject()->getSchema()));
1276 }
1277
1278 if(BaseObjectView::isPlaceholderEnabled())
1279 tab_view->requestRelationshipsUpdate();
1280 }
1281
1282 //Updating schemas bounding rects after moving objects
1283 for(auto &obj : schemas)
1284 obj->setModified(true);
1285
1286 emit s_objectsMoved(true);
1287 moving_objs=false;
1288 sel_ini_pnt.setX(DNaN);
1289 sel_ini_pnt.setY(DNaN);
1290 }
1291
alignObjectsToGrid()1292 void ObjectsScene::alignObjectsToGrid()
1293 {
1294 QList<QGraphicsItem *> items=this->items();
1295 RelationshipView *rel=nullptr;
1296 BaseTableView *tab=nullptr;
1297 TextboxView *lab=nullptr;
1298 vector<QPointF> points;
1299 vector<Schema *> schemas;
1300 unsigned i, count, i1, count1;
1301
1302 count=items.size();
1303 for(i=0; i < count; i++)
1304 {
1305 if(dynamic_cast<QGraphicsItemGroup *>(items[i]) && !items[i]->parentItem())
1306 {
1307 tab=dynamic_cast<BaseTableView *>(items[i]);
1308 rel=dynamic_cast<RelationshipView *>(items[i]);
1309
1310 if(tab)
1311 tab->setPos(this->alignPointToGrid(tab->pos()));
1312 else if(rel)
1313 {
1314 //Align the relationship points
1315 points=rel->getUnderlyingObject()->getPoints();
1316 count1=points.size();
1317 for(i1=0; i1 < count1; i1++)
1318 points[i1]=this->alignPointToGrid(points[i1]);
1319
1320 if(count1 > 0)
1321 {
1322 rel->getUnderlyingObject()->setPoints(points);
1323 rel->configureLine();
1324 }
1325
1326 //Align the labels
1327 for(i1=BaseRelationship::SrcCardLabel;
1328 i1<=BaseRelationship::RelNameLabel; i1++)
1329 {
1330 lab=rel->getLabel(i1);
1331 if(lab)
1332 lab->setPos(this->alignPointToGrid(lab->pos()));
1333 }
1334 }
1335 else if(!dynamic_cast<SchemaView *>(items[i]))
1336 items[i]->setPos(this->alignPointToGrid(items[i]->pos()));
1337 else
1338 schemas.push_back(dynamic_cast<Schema *>(dynamic_cast<BaseObjectView *>(items[i])->getUnderlyingObject()));
1339 }
1340 }
1341
1342 //Updating schemas dimensions
1343 while(!schemas.empty())
1344 {
1345 schemas.back()->setModified(true);
1346 schemas.pop_back();
1347 }
1348 }
1349
update()1350 void ObjectsScene::update()
1351 {
1352 this->setBackgroundBrush(grid);
1353 QGraphicsScene::update(this->sceneRect());
1354 }
1355
clearTablesChildrenSelection()1356 void ObjectsScene::clearTablesChildrenSelection()
1357 {
1358 for(auto &tab_obj_view : tabs_sel_children)
1359 tab_obj_view->clearChildrenSelection();
1360
1361 tabs_sel_children.clear();
1362 }
1363
clearSelection()1364 void ObjectsScene::clearSelection()
1365 {
1366 clearTablesChildrenSelection();
1367 QGraphicsScene::clearSelection();
1368 }
1369
getPagesForPrinting(const QSizeF & paper_size,const QSizeF & margin,unsigned & h_page_cnt,unsigned & v_page_cnt)1370 vector<QRectF> ObjectsScene::getPagesForPrinting(const QSizeF &paper_size, const QSizeF &margin, unsigned &h_page_cnt, unsigned &v_page_cnt)
1371 {
1372 vector<QRectF> pages;
1373 QRectF page_rect, max_rect;
1374 double width, height, page_width, page_height;
1375 unsigned h_page=0, v_page=0, start_h=99999, start_v=99999;
1376 QList<QGraphicsItem *> list;
1377
1378 page_width=ceil(paper_size.width() - margin.width()-1);
1379 page_height=ceil(paper_size.height() - margin.height()-1);
1380
1381 //Calculates the horizontal and vertical page count based upon the passed paper size
1382 h_page_cnt=round(this->sceneRect().width()/page_width) + 1;
1383 v_page_cnt=round(this->sceneRect().height()/page_height) + 1;
1384
1385 //Calculates the maximum count of horizontal and vertical pages
1386 for(v_page=0; v_page < v_page_cnt; v_page++)
1387 {
1388 for(h_page=0; h_page < h_page_cnt; h_page++)
1389 {
1390 //Calculates the current page rectangle
1391 page_rect=QRectF(QPointF(h_page * page_width, v_page * page_height), QSizeF(page_width, page_height));
1392
1393 //Case there is selected items recalculates the maximum page size
1394 list=this->items(page_rect, Qt::IntersectsItemShape);
1395 if(!list.isEmpty())
1396 {
1397 if(start_h > h_page) start_h=h_page;
1398 if(start_v > v_page) start_v=v_page;
1399
1400 width=page_rect.left() + page_rect.width();
1401 height=page_rect.top() + page_rect.height();
1402
1403 if(width > max_rect.width())
1404 max_rect.setWidth(width);
1405
1406 if(height > max_rect.height())
1407 max_rect.setHeight(height);
1408 }
1409 }
1410 }
1411
1412 //Re calculates the maximum page count based upon the maximum page size
1413 h_page_cnt=round(max_rect.width()/page_width);
1414 v_page_cnt=round(max_rect.height()/page_height);
1415
1416 //Inserts the page rectangles on the list
1417 for(v_page=static_cast<unsigned>(start_v); v_page < v_page_cnt; v_page++)
1418 for(h_page=static_cast<unsigned>(start_h); h_page < h_page_cnt; h_page++)
1419 pages.push_back(QRectF(QPointF(h_page * page_width, v_page * page_height), QSizeF(page_width, page_height)));
1420
1421 return pages;
1422 }
1423
isRangeSelectionEnabled()1424 bool ObjectsScene::isRangeSelectionEnabled()
1425 {
1426 return enable_range_sel;
1427 }
1428
isRangeSelectionTriggerInverted()1429 bool ObjectsScene::isRangeSelectionTriggerInverted()
1430 {
1431 return invert_rangesel_trigger;
1432 }
1433
isRelationshipLineVisible()1434 bool ObjectsScene::isRelationshipLineVisible()
1435 {
1436 return rel_line->isVisible();
1437 }
1438
isMovingObjects()1439 bool ObjectsScene::isMovingObjects()
1440 {
1441 return moving_objs;
1442 }
1443
selectedItems() const1444 QList<QGraphicsItem *> ObjectsScene::selectedItems() const
1445 {
1446 if(tabs_sel_children.empty())
1447 return QGraphicsScene::selectedItems();
1448
1449 QList<QGraphicsItem *> items = QGraphicsScene::selectedItems();
1450
1451 for(auto &tab_view :tabs_sel_children)
1452 {
1453 for(auto &tab_obj : tab_view->getSelectedChidren())
1454 items.append(tab_obj);
1455 }
1456
1457 return items;
1458 }
1459
hasOnlyTableChildrenSelection() const1460 bool ObjectsScene::hasOnlyTableChildrenSelection() const
1461 {
1462 return QGraphicsScene::selectedItems().isEmpty() && !tabs_sel_children.isEmpty();
1463 }
1464