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 "tableview.h"
20
TableView(PhysicalTable * table)21 TableView::TableView(PhysicalTable *table) : BaseTableView(table)
22 {
23 connect(table, SIGNAL(s_objectModified()), this, SLOT(configureObject()));
24 this->configureObject();
25 }
26
configureObject()27 void TableView::configureObject()
28 {
29 /* If the table isn't visible we abort the current configuration
30 * and mark its geometry update as pending so in the next call to
31 * setVisible(true) the geometry can be updated (see BaseObjectView::itemChange()) */
32 if(!this->isVisible())
33 {
34 pending_geom_update = true;
35 return;
36 }
37
38 PhysicalTable *table=dynamic_cast<PhysicalTable *>(this->getUnderlyingObject());
39 int i, count, obj_idx;
40 double width=0, px=0, cy=0, old_width=0, old_height=0;
41 unsigned start_col = 0, end_col = 0, start_ext = 0, end_ext = 0;
42 QPen pen;
43 TableObjectView *col_item=nullptr;
44 QList<QGraphicsItem *> subitems;
45 QList<TableObjectView *> col_items;
46 TableObject *tab_obj=nullptr;
47 QGraphicsItemGroup *groups[]={ columns, ext_attribs };
48 RoundedRectItem *bodies[]={ body, ext_attribs_body };
49 vector<TableObject *> tab_objs, columns, ext_tab_objs;
50 QStringList atribs, tag_attribs = { Attributes::TableBody, Attributes::TableExtBody };
51 Tag *tag=table->getTag();
52 CollapseMode collapse_mode = table->getCollapseMode();
53 vector<ObjectType> ext_types = BaseObject::getChildObjectTypes(table->getObjectType());
54 bool has_col_pag = false, has_ext_pag = false;
55
56 if(table->getObjectType() == ObjectType::Table)
57 atribs.append({ Attributes::TableBody, Attributes::TableExtBody });
58 else
59 atribs.append({ Attributes::ForeignTableBody, Attributes::ForeignTableExtBody });
60
61 // Clear the selected children objects vector since we'll (re)configure the whole table
62 sel_child_objs.clear();
63
64 //Configures the table title
65 title->configureObject(table);
66
67 // We store the columns in a separated vector in order to paginate them (if enabled)
68 columns.assign(table->getObjectList(ObjectType::Column)->begin(),
69 table->getObjectList(ObjectType::Column)->end());
70
71 // We store the extended attributes in a separated vector in order to paginate them (if enabled)
72 for(auto &type : ext_types)
73 {
74 if(type == ObjectType::Column)
75 continue;
76
77 ext_tab_objs.insert(ext_tab_objs.end(),
78 table->getObjectList(type)->begin(),
79 table->getObjectList(type)->end());
80 }
81
82 has_col_pag = configurePaginationParams(BaseTable::AttribsSection, columns.size(), start_col, end_col);
83
84 has_ext_pag = configurePaginationParams(BaseTable::ExtAttribsSection,
85 collapse_mode != CollapseMode::ExtAttribsCollapsed ? ext_tab_objs.size() : 0,
86 start_ext, end_ext);
87
88 attribs_toggler->setHasExtAttributes(!hide_ext_attribs && !ext_tab_objs.empty());
89
90 px=0;
91 old_width=this->bounding_rect.width();
92 old_height=this->bounding_rect.height();
93
94 for(obj_idx=0; obj_idx < 2; obj_idx++)
95 {
96 tab_objs.clear();
97
98 if(obj_idx==0)
99 {
100 if(collapse_mode != CollapseMode::AllAttribsCollapsed)
101 {
102 if(table->isPaginationEnabled() && has_col_pag)
103 tab_objs.assign(columns.begin() + start_col, columns.begin() + end_col);
104 else
105 tab_objs.assign(columns.begin(), columns.end());
106 }
107 }
108 else
109 {
110 if(!hide_ext_attribs && collapse_mode == CollapseMode::NotCollapsed)
111 {
112 if(table->isPaginationEnabled() && has_ext_pag)
113 tab_objs.assign(ext_tab_objs.begin() + start_ext, ext_tab_objs.begin() + end_ext);
114 else
115 tab_objs.assign(ext_tab_objs.begin(), ext_tab_objs.end());
116 }
117 }
118
119 //Gets the subitems of the current group
120 subitems=groups[obj_idx]->childItems();
121 groups[obj_idx]->moveBy(-groups[obj_idx]->scenePos().x(),
122 -groups[obj_idx]->scenePos().y());
123 count=tab_objs.size();
124 groups[obj_idx]->setVisible(count > 0);
125 bodies[obj_idx]->setVisible(count > 0);
126
127 for(i=0; i < count; i++)
128 {
129 tab_obj=tab_objs.at(i);
130
131 //Reusing the subitem if it was allocated before
132 if(!subitems.isEmpty() && i < subitems.size())
133 {
134 col_item=dynamic_cast<TableObjectView *>(subitems[i]);
135 col_item->setSourceObject(tab_obj);
136 col_item->configureObject();
137 col_item->moveBy(-col_item->scenePos().x(),-col_item->scenePos().y());
138 }
139 else
140 col_item=new TableObjectView(tab_obj);
141
142 //Configures the item and set its position
143 col_item->configureObject();
144 col_item->moveBy(HorizSpacing, (i * col_item->boundingRect().height()) + VertSpacing);
145
146 /* Calculates the width of the name + type of the object. This is used to align all
147 the constraint labels on table */
148 width=col_item->getChildObject(TableObjectView::ObjDescriptor)->boundingRect().width() +
149 col_item->getChildObject(TableObjectView::NameLabel)->boundingRect().width() + (5 * HorizSpacing);
150
151 if(px < width)
152 px=width;
153
154 col_items.push_back(col_item);
155 }
156
157 //Destroy the unused items
158 i=subitems.size()-1;
159 while(i > count-1)
160 {
161 col_item=dynamic_cast<TableObjectView *>(subitems[i]);
162 groups[obj_idx]->removeFromGroup(col_item);
163 delete col_item;
164 i--;
165 }
166
167 //Set all items position
168 while(!col_items.isEmpty())
169 {
170 col_item=dynamic_cast<TableObjectView *>(col_items.front());
171 groups[obj_idx]->removeFromGroup(col_item);
172 col_items.pop_front();
173
174 //Positioning the type label
175 col_item->setChildObjectXPos(TableObjectView::TypeLabel, px);
176
177 //Positioning the constraints label
178 col_item->setChildObjectXPos(TableObjectView::ConstrAliasLabel,
179 px + (col_item->getChildObject(TableObjectView::TypeLabel)->boundingRect().width() * 1.05));
180
181 groups[obj_idx]->addToGroup(col_item);
182 }
183 }
184
185 width = calculateWidth();
186
187 //Resizes the title using the new width
188 title->resizeTitle(width, title->boundingRect().height());
189
190 //Resizes the columns/extended attributes using the new width
191 for(obj_idx=0; obj_idx < 2; obj_idx++)
192 {
193 bodies[obj_idx]->setRect(QRectF(0,0, width, groups[obj_idx]->boundingRect().height() + (2 * VertSpacing)));
194 pen=this->getBorderStyle(atribs[obj_idx]);
195
196 if(table->isPartition())
197 pen.setStyle(Qt::DashLine);
198
199 if(!tag)
200 bodies[obj_idx]->setBrush(this->getFillStyle(atribs[obj_idx]));
201 else
202 {
203 pen.setColor(tag->getElementColor(tag_attribs[obj_idx], Tag::BorderColor));
204 bodies[obj_idx]->setBrush(tag->getFillStyle(tag_attribs[obj_idx]));
205 }
206
207 bodies[obj_idx]->setPen(pen);
208
209 if(obj_idx==0)
210 bodies[obj_idx]->setPos(title->pos().x(), title->boundingRect().height()-1);
211 else
212 {
213 if(bodies[0]->isVisible())
214 bodies[obj_idx]->setPos(title->pos().x(),
215 title->boundingRect().height() +
216 bodies[0]->boundingRect().height() - 2);
217 else
218 bodies[obj_idx]->setPos(title->pos().x(), title->boundingRect().height()-1);
219 }
220
221 groups[obj_idx]->setPos(bodies[obj_idx]->pos());
222
223 subitems=groups[obj_idx]->childItems();
224 while(!subitems.isEmpty())
225 {
226 col_item=dynamic_cast<TableObjectView *>(subitems.front());
227 subitems.pop_front();
228 col_item->setChildObjectXPos(TableObjectView::ConstrAliasLabel,
229 width - col_item->getChildObject(TableObjectView::ConstrAliasLabel)->boundingRect().width() - (2 * HorizSpacing) - 1);
230
231 //Generating the connection points of the columns
232 if(obj_idx==0)
233 {
234 tab_obj=dynamic_cast<TableObject *>(col_item->getUnderlyingObject());
235 cy=title->boundingRect().height() + col_item->pos().y() + (col_item->boundingRect().height()/2);
236 conn_points[tab_obj].resize(2);
237 conn_points[tab_obj][LeftConnPoint]=QPointF(col_item->pos().x() - 1.5, cy);
238 conn_points[tab_obj][RightConnPoint]=QPointF(col_item->pos().x() + width - 1.5 , cy);
239 }
240 }
241 }
242
243 BaseTableView::__configureObject(width);
244
245 if(table->isPartitioned())
246 table_tooltip += QString("\n%1 (%2)").arg(tr("Partitioned")).arg(~table->getPartitioningType());
247
248 if(table->isPartition())
249 table_tooltip += QString("\n%1 of %2").arg(tr("Partition")).arg(table->getPartitionedTable()->getSignature(true));
250
251 if(!table->getAlias().isEmpty())
252 table_tooltip += QString("\nAlias: %1").arg(table->getAlias());
253
254 if(!table->getComment().isEmpty())
255 table_tooltip += QString("\n---\n%1").arg(table->getComment());
256
257 BaseObjectView::__configureObject();
258 configureTag();
259 configureSQLDisabledInfo();
260
261 if((old_width!=0 && this->bounding_rect.width()!=old_width) ||
262 (old_height!=0 && this->bounding_rect.height()!=old_height))
263 emit s_objectDimensionChanged();
264 else
265 requestRelationshipsUpdate();
266 }
267
getConnectionPoints(TableObject * tab_obj,unsigned pnt_type)268 QPointF TableView::getConnectionPoints(TableObject *tab_obj, unsigned pnt_type)
269 {
270 if(!tab_obj)
271 throw Exception(ErrorCode::OprNotAllocatedObject,__PRETTY_FUNCTION__,__FILE__,__LINE__);
272 else if(pnt_type > RightConnPoint)
273 throw Exception(ErrorCode::RefElementInvalidIndex,__PRETTY_FUNCTION__,__FILE__,__LINE__);
274 else if(conn_points.count(tab_obj)==0)
275 //Returns the center point in case of the connection point of the table object wasn't calculated already
276 return this->getCenter();
277
278 return conn_points[tab_obj][pnt_type];
279 }
280