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