1 //////////////////////////////////////////////////////////////////////////
2 //
3 // pgAdmin III - PostgreSQL Tools
4 //
5 // Copyright (C) 2002 - 2016, The pgAdmin Development Team
6 // This software is released under the PostgreSQL Licence
7 //
8 // ddColumnFigure.cpp - Minimal Composite Figure for a column of a table
9 //
10 //////////////////////////////////////////////////////////////////////////
11
12 #include "pgAdmin3.h"
13
14 // wxWindows headers
15 #include <wx/wx.h>
16 #include <wx/dcbuffer.h>
17 #include <wx/pen.h>
18
19 // App headers
20 #include "dd/dditems/figures/ddColumnFigure.h"
21 #include "dd/dditems/figures/ddTextTableItemFigure.h"
22 #include "dd/dditems/tools/ddColumnFigureTool.h"
23 #include "dd/dditems/figures/ddColumnKindIcon.h"
24 #include "dd/dditems/figures/ddColumnOptionIcon.h"
25 #include "dd/dditems/utilities/ddDataType.h"
26 #include "dd/dditems/figures/ddTableFigure.h"
27 #include "dd/dditems/figures/ddRelationshipItem.h"
28
Init(wxString & columnName,ddTableFigure * owner,ddRelationshipItem * sourceFk)29 void ddColumnFigure::Init(wxString &columnName, ddTableFigure *owner, ddRelationshipItem *sourceFk)
30 {
31 setKindId(DDCOLUMNFIGURE);
32 fkSource = sourceFk;
33 usedAsFkDestFor = NULL;
34 setOwnerTable(owner);
35 deactivateGenFkName(); //initializae by default at not generate auto fk name
36 columnText = new ddTextTableItemFigure(columnName, dt_null, this);
37 kindImage = new ddColumnKindIcon(this);
38 optionImage = new ddColumnOptionIcon(this);
39
40
41 //Initialize displaybox and image coords
42 basicDisplayBox.SetPosition(0, wxPoint(0, 0));
43 basicDisplayBox.SetSize( columnText->displayBox().GetSize());
44 if(kindImage && optionImage)
45 {
46 basicDisplayBox.width += kindImage->displayBox().GetSize().GetWidth() + 3;
47 basicDisplayBox.width += optionImage->displayBox().GetSize().GetWidth() + 3;
48 columnText->displayBox().x[0] += kindImage->displayBox().GetSize().GetWidth() + 2;
49 columnText->displayBox().x[0] += optionImage->displayBox().GetSize().GetWidth() + 3;
50 }
51 else
52 {
53 basicDisplayBox.width += 22; //default value = 1 + 8 + 3 + 8 + 2
54 columnText->displayBox().x[0] += 22;
55 }
56
57 //Set Value default Attributes
58 fontAttribute->font().SetPointSize(owner->fontAttribute->font().GetPointSize());
59 pgAttNumColNumber = -1;
60 }
61
ddColumnFigure(wxString & columnName,ddTableFigure * owner,ddRelationshipItem * sourceFk)62 ddColumnFigure::ddColumnFigure(wxString &columnName, ddTableFigure *owner, ddRelationshipItem *sourceFk)
63 {
64 Init(columnName, owner, sourceFk);
65 }
66
67 //Constructor for creation of existing column from storage
ddColumnFigure(wxString & columnName,ddTableFigure * owner,ddColumnOptionType option,bool isGenFk,bool isPkColumn,wxString colDataType,int p,int s,int ukIdx,ddRelationshipItem * srcFk,ddRelationshipItem * usedAsFk)68 ddColumnFigure::ddColumnFigure(wxString &columnName, ddTableFigure *owner, ddColumnOptionType option, bool isGenFk, bool isPkColumn, wxString colDataType, int p, int s, int ukIdx, ddRelationshipItem *srcFk, ddRelationshipItem *usedAsFk )
69 {
70 Init(columnName, owner, srcFk);
71 setColumnOption(option);
72 generateFkName = isGenFk;
73 kindImage->setPrimaryKey(isPkColumn);
74
75 int dtype = columnText->dataTypes().Index(colDataType, false);
76 if(dtype != wxNOT_FOUND)
77 {
78 setDataType((ddDataType)dtype);
79 }
80 else
81 {
82 wxMessageBox(wxString::Format(_("%s column has a non compatible data type (%s).\n%s will now have the default data type."),
83 columnName.c_str(), colDataType.c_str(), columnName.c_str()));
84 setDataType((ddDataType)0);
85 }
86
87 columnText->setPrecision(p);
88 columnText->setScale(s);
89 kindImage->setUkIndex(ukIdx);
90
91 usedAsFkDestFor = usedAsFk;
92 if(ownerTable)
93 ownerTable->updateTableSize();
94
95 }
96
~ddColumnFigure()97 ddColumnFigure::~ddColumnFigure()
98 {
99 if(columnText)
100 delete columnText;
101 if(kindImage)
102 delete kindImage;
103 if(optionImage)
104 delete optionImage;
105 }
106
AddPosForNewDiagram()107 void ddColumnFigure::AddPosForNewDiagram()
108 {
109 //Add position for new displaybox at new diagram
110 hdAttributeFigure::AddPosForNewDiagram();
111 //Add position to each figure inside this composite figure
112 if(kindImage)
113 kindImage->AddPosForNewDiagram();
114 if(optionImage)
115 optionImage->AddPosForNewDiagram();
116 if(columnText)
117 columnText->AddPosForNewDiagram();
118 }
119
RemovePosOfDiagram(int posIdx)120 void ddColumnFigure::RemovePosOfDiagram(int posIdx)
121 {
122 //Remove this position at displaybox of this figure
123 hdAttributeFigure::RemovePosOfDiagram(posIdx);
124 //Remove this position at each figure inside this composite figure
125 if(kindImage)
126 kindImage->RemovePosOfDiagram(posIdx);
127 if(optionImage)
128 optionImage->RemovePosOfDiagram(posIdx);
129 if(columnText)
130 columnText->RemovePosOfDiagram(posIdx);
131
132 }
133
basicMoveBy(int posIdx,int x,int y)134 void ddColumnFigure::basicMoveBy(int posIdx, int x, int y)
135 {
136 hdAbstractFigure::basicMoveBy(posIdx, x, y);
137 if(kindImage)
138 kindImage->moveBy(posIdx, x, y);
139 if(optionImage)
140 optionImage->moveBy(posIdx, x, y);
141 columnText->moveBy(posIdx, x, y);
142 }
143
moveTo(int posIdx,int x,int y)144 void ddColumnFigure::moveTo(int posIdx, int x, int y)
145 {
146 hdAbstractFigure::moveTo(posIdx, x, y);
147 int distance = 0;
148
149 if(kindImage)
150 {
151 kindImage->moveTo(posIdx, x, y);
152 distance += kindImage->displayBox().GetSize().GetWidth() + 3;
153 }
154 else
155 {
156 distance += 11; //value = 8 + 3
157 }
158
159 if(optionImage)
160 {
161 optionImage->moveTo(posIdx, x + distance, y);
162 distance += optionImage->displayBox().GetSize().GetWidth() + 3;
163 }
164 else
165 {
166 distance += 11; //value = 8 + 3
167 }
168
169 columnText->moveTo(posIdx, x + distance, y);
170 }
171
172
containsPoint(int posIdx,int x,int y)173 bool ddColumnFigure::containsPoint(int posIdx, int x, int y)
174 {
175 bool out = false;
176
177 if(columnText->containsPoint(posIdx, x, y))
178 out = true;
179 else if(kindImage->containsPoint(posIdx, x, y))
180 out = true;
181 else if(optionImage->containsPoint(posIdx, x, y))
182 out = true;
183
184 return out;
185 }
186
getBasicDisplayBox()187 hdMultiPosRect &ddColumnFigure::getBasicDisplayBox()
188 {
189 return basicDisplayBox;
190 }
191
basicDraw(wxBufferedDC & context,hdDrawingView * view)192 void ddColumnFigure::basicDraw(wxBufferedDC &context, hdDrawingView *view)
193 {
194 columnText->draw(context, view);
195 if(kindImage)
196 kindImage->draw(context, view);
197 if(optionImage)
198 optionImage->draw(context, view);
199 }
200
basicDrawSelected(wxBufferedDC & context,hdDrawingView * view)201 void ddColumnFigure::basicDrawSelected(wxBufferedDC &context, hdDrawingView *view)
202 {
203 columnText->drawSelected(context, view);
204 if(kindImage)
205 kindImage->drawSelected(context, view);
206 if(optionImage)
207 optionImage->drawSelected(context, view);
208 }
209
findFigure(int posIdx,int x,int y)210 hdIFigure *ddColumnFigure::findFigure(int posIdx, int x, int y)
211 {
212 hdIFigure *out = NULL;
213
214 if(columnText->containsPoint(posIdx, x, y))
215 out = columnText;
216
217 if(kindImage && kindImage->containsPoint(posIdx, x, y))
218 out = kindImage;
219
220 if(optionImage && optionImage->containsPoint(posIdx, x, y))
221 out = optionImage;
222
223 return out;
224 }
225
CreateFigureTool(hdDrawingView * view,hdITool * defaultTool)226 hdITool *ddColumnFigure::CreateFigureTool(hdDrawingView *view, hdITool *defaultTool)
227 {
228 return new ddColumnFigureTool(view, this, defaultTool);
229 }
230
getFigureAt(int pos)231 hdIFigure *ddColumnFigure::getFigureAt(int pos)
232 {
233 if(pos == 0)
234 return (hdIFigure *) kindImage;
235
236 if(pos == 1)
237 return (hdIFigure *) optionImage;
238
239 if(pos == 2)
240 return (hdIFigure *) columnText;
241
242 return NULL;
243 }
244
getOwnerTable()245 ddTableFigure *ddColumnFigure::getOwnerTable()
246 {
247 return ownerTable;
248 }
249
setOwnerTable(ddTableFigure * table)250 void ddColumnFigure::setOwnerTable(ddTableFigure *table)
251 {
252 ownerTable = table;
253 }
254
displayBoxUpdate()255 void ddColumnFigure::displayBoxUpdate()
256 {
257 if(kindImage && optionImage)
258 {
259 columnText->displayBoxUpdate();
260 basicDisplayBox.width = columnText->displayBox().GetSize().GetWidth();
261 basicDisplayBox.width += kindImage->displayBox().GetSize().GetWidth() + 3;
262 basicDisplayBox.width += optionImage->displayBox().GetSize().GetWidth() + 3;
263 }
264 else
265 {
266 columnText->displayBoxUpdate();
267 basicDisplayBox.width += 22; //default value = 1 + 8 + 3 + 8 +2
268 }
269 }
270
isNull()271 bool ddColumnFigure::isNull()
272 {
273 return optionImage->getOption() == null;
274 }
275
isNotNull()276 bool ddColumnFigure::isNotNull()
277 {
278 return optionImage->getOption() == notnull;
279 }
280
isNone()281 bool ddColumnFigure::isNone()
282 {
283 return kindImage->isNone();
284 }
285
isPrimaryKey()286 bool ddColumnFigure::isPrimaryKey()
287 {
288 return kindImage->isPrimaryKey();
289 }
290
disablePrimaryKey()291 void ddColumnFigure::disablePrimaryKey()
292 {
293 kindImage->disablePrimaryKey();
294 }
295
enablePrimaryKey()296 void ddColumnFigure::enablePrimaryKey()
297 {
298 kindImage->enablePrimaryKey();
299 }
300
isUniqueKey()301 bool ddColumnFigure::isUniqueKey()
302 {
303 return kindImage->isUniqueKey();
304 }
305
isUniqueKey(int uniqueIndex)306 bool ddColumnFigure::isUniqueKey(int uniqueIndex)
307 {
308 return kindImage->isUniqueKey(uniqueIndex);
309 }
310
isPlain()311 bool ddColumnFigure::isPlain()
312 {
313 return kindImage->isNone();
314 }
315
setColumnKindToNone()316 void ddColumnFigure::setColumnKindToNone()
317 {
318 kindImage->disablePrimaryKey();
319 kindImage->disableUniqueKey();
320 //Foreign key cannot be changed by set / toggle functions
321 }
322
setRightIconForColumn()323 void ddColumnFigure::setRightIconForColumn()
324 {
325 kindImage->setRightIconForColumn();
326 }
327
toggleColumnKind(ddColumnType type,hdDrawingView * view)328 void ddColumnFigure::toggleColumnKind(ddColumnType type, hdDrawingView *view)
329 {
330 kindImage->toggleColumnKind(type, view);
331 }
332
setColumnOption(ddColumnOptionType type)333 void ddColumnFigure::setColumnOption(ddColumnOptionType type)
334 {
335 optionImage->changeIcon(type);
336 }
337
getColumnName(bool datatype)338 wxString &ddColumnFigure::getColumnName(bool datatype)
339 {
340 return columnText->getText(datatype);
341 }
342
setPrecision(int n)343 void ddColumnFigure::setPrecision(int n)
344 {
345 columnText->setPrecision(n);
346 }
347
getPrecision()348 int ddColumnFigure::getPrecision()
349 {
350 return columnText->getPrecision();
351 }
352
setScale(int n)353 void ddColumnFigure::setScale(int n)
354 {
355 columnText->setScale(n);
356 }
357
getScale()358 int ddColumnFigure::getScale()
359 {
360 return columnText->getScale();
361 }
362
getUniqueConstraintIndex()363 int ddColumnFigure::getUniqueConstraintIndex()
364 {
365 return kindImage->getUniqueConstraintIndex();
366 }
367
setUniqueConstraintIndex(int i)368 void ddColumnFigure::setUniqueConstraintIndex(int i)
369 {
370 kindImage->setUniqueConstraintIndex(i);
371 }
372
getColumnOption()373 ddColumnOptionType ddColumnFigure::getColumnOption()
374 {
375 return optionImage->getOption();
376 }
377
getDataType()378 ddDataType ddColumnFigure::getDataType()
379 {
380 return columnText->getDataType();
381 }
382
setDataType(ddDataType type)383 void ddColumnFigure::setDataType(ddDataType type)
384 {
385 columnText->setDataType(type);
386 }
387
setColumnName(wxString name)388 void ddColumnFigure::setColumnName(wxString name)
389 {
390 columnText->setText(name);
391 }
392
isForeignKeyFromPk()393 bool ddColumnFigure::isForeignKeyFromPk()
394 {
395 if(fkSource)
396 {
397 return fkSource->isForeignKeyFromPk();
398 }
399 else if(usedAsFkDestFor)
400 {
401 return usedAsFkDestFor->isForeignKeyFromPk();
402 }
403 return false;
404 }
405
isForeignKey()406 bool ddColumnFigure::isForeignKey()
407 {
408 bool a = isUserCreatedForeignKey();
409 bool b = isGeneratedForeignKey();
410 return (a || b);
411 }
412
isGeneratedForeignKey()413 bool ddColumnFigure::isGeneratedForeignKey()
414 {
415 return fkSource != NULL;
416 }
417
isUserCreatedForeignKey()418 bool ddColumnFigure::isUserCreatedForeignKey()
419 {
420 return usedAsFkDestFor != NULL;
421 }
422
getRelatedFkItem()423 ddRelationshipItem *ddColumnFigure::getRelatedFkItem()
424 {
425 return usedAsFkDestFor;
426 }
427
setAsUserCreatedFk(ddRelationshipItem * relatedFkItem)428 void ddColumnFigure::setAsUserCreatedFk(ddRelationshipItem *relatedFkItem)
429 {
430 usedAsFkDestFor = relatedFkItem;
431 //Now fix icons of kind of column
432 if(relatedFkItem == NULL)
433 {
434 kindImage->setRightIconForColumn();
435 }
436 }
437
isFkNameGenerated()438 bool ddColumnFigure::isFkNameGenerated()
439 {
440 return generateFkName;
441 }
442
activateGenFkName()443 void ddColumnFigure::activateGenFkName()
444 {
445 generateFkName = true;
446 }
447
deactivateGenFkName()448 void ddColumnFigure::deactivateGenFkName()
449 {
450 generateFkName = false;
451 }
452
generateSQL(bool forAlterColumn)453 wxString ddColumnFigure::generateSQL(bool forAlterColumn)
454 {
455 wxString tmp;
456 tmp = wxT("\"") + getColumnName() + wxT("\" ");
457 if(forAlterColumn)
458 tmp += wxT("TYPE ");
459 tmp += columnText->getType();
460 return tmp;
461 }
462
getFkSource()463 ddRelationshipItem *ddColumnFigure::getFkSource()
464 {
465 return fkSource;
466 }
467
setTextColour(wxColour colour)468 void ddColumnFigure::setTextColour(wxColour colour)
469 {
470 columnText->fontColorAttribute->fontColor = colour;
471 }
472
473
474 //Validate status of column for SQL DDL generation
validateColumn(wxString & errors)475 bool ddColumnFigure::validateColumn(wxString &errors)
476 {
477 bool out = true;
478 wxString tmp;
479
480 if(usedAsFkDestFor)
481 {
482 //Validate if relationship is marked as identifying but column isn't marked as primary key
483 wxString sourceTableName = usedAsFkDestFor->sourceTableName();
484 wxString destTableName = usedAsFkDestFor->destTableName();
485 wxString fkColName = usedAsFkDestFor->fkColumn->getColumnName(false);
486 wxString sourceColName = usedAsFkDestFor->original->getColumnName(false);
487
488 if(usedAsFkDestFor->relationIsIdentifying() && !this->isPrimaryKey())
489 {
490 out = false;
491 tmp = _("relation between table: ") + sourceTableName + _(" and table: ") + destTableName;
492 tmp += _(" is marked as identifying but user created foreign key column: ") + fkColName;
493 tmp += _(" isn't set as primary key \n");
494 errors.Append(tmp);
495 }
496 //Validate if relationship is marked as optional but column is mandatory
497 if( !usedAsFkDestFor->relationIsMandatory() && this->isNotNull())
498 {
499 out = false;
500 tmp = _("relation between table:") + sourceTableName + _(" and table: ") + destTableName;
501 tmp += _("is marked as optional but user created foreign key column: ") + fkColName;
502 tmp += _("is set as mandatory \n");
503 errors.Append(tmp);
504 }
505 //Validate if relationship is marked as mandatory buy column is optional
506 if( usedAsFkDestFor->relationIsMandatory() && this->isNull())
507 {
508 out = false;
509 tmp = _("relation between table:") + sourceTableName + _(" and table: ") + destTableName +
510 tmp += _(" is marked as mandatory but user created foreign key column: ") + fkColName;
511 tmp += _("is set as optional \n");
512 errors.Append(tmp);
513 }
514
515 //Validate datatype compatibility (right now only exactly same datatype)
516 if(this->getDataType() != usedAsFkDestFor->original->getDataType())
517 {
518 out = false;
519 tmp = _("User created foreign key column: ") + fkColName + _("have different datatype from source column of relationship: ");
520 tmp += sourceColName + _(" \n");
521 errors.Append(tmp);
522 }
523 }
524
525 return out;
526 }
527
528 //Used by persistence classes
setFkSource(ddRelationshipItem * newColumn)529 void ddColumnFigure::setFkSource(ddRelationshipItem *newColumn)
530 {
531 fkSource = newColumn;
532 }
533
534 //Used by reverse engineering functions
getRawDataType()535 wxString ddColumnFigure::getRawDataType()
536 {
537 return columnText->getType(true);
538 }
539