3 // Ben Motmans <ben.motmans@gmail.com>
5 // Copyright (c) 2007 Ben Motmans
7 // Permission is hereby granted, free of charge, to any person obtaining
8 // a copy of this software and associated documentation files (the
9 // "Software"), to deal in the Software without restriction, including
10 // without limitation the rights to use, copy, modify, merge, publish,
11 // distribute, sublicense, and/or sell copies of the Software, and to
12 // permit persons to whom the Software is furnished to do so, subject to
13 // the following conditions:
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System
.Threading
;
30 using System
.Collections
.Generic
;
31 using MonoDevelop
.Core
;
32 using MonoDevelop
.Core
.Gui
;
33 using MonoDevelop
.Database
.Sql
;
34 using MonoDevelop
.Database
.Components
;
36 namespace MonoDevelop
.Database
.Designer
38 [System
.ComponentModel
.Category("widget")]
39 [System
.ComponentModel
.ToolboxItem(true)]
40 public partial class ColumnsEditorWidget
: Gtk
.Bin
42 public event EventHandler ContentChanged
;
44 private ListStore storeColumns
;
45 private ListStore storeTypes
;
47 private const int colPKIndex
= 0;
48 private const int colNameIndex
= 1;
49 private const int colTypeIndex
= 2;
50 private const int colLengthIndex
= 3;
51 private const int colNullableIndex
= 4;
52 private const int colCommentIndex
= 5;
53 private const int colObjIndex
= 6;
55 private ColumnSchemaCollection columns
;
56 private ConstraintSchemaCollection constraints
;
57 private DataTypeSchemaCollection dataTypes
;
58 private ISchemaProvider schemaProvider
;
59 private TableSchema table
;
61 private SchemaActions action
;
62 private ColumnEditorSettings settings
;
64 public ColumnsEditorWidget (ISchemaProvider schemaProvider
, SchemaActions action
, ColumnEditorSettings settings
)
66 if (schemaProvider
== null)
67 throw new ArgumentNullException ("schemaProvider");
69 throw new ArgumentNullException ("settings");
71 this.schemaProvider
= schemaProvider
;
73 this.settings
= settings
;
77 storeTypes
= new ListStore (typeof (string), typeof (object));
78 storeColumns
= new ListStore (typeof (bool), typeof (string), typeof (string), typeof (string), typeof (bool), typeof (string), typeof (object));
79 treeColumns
.Model
= storeColumns
;
80 treeColumns
.Selection
.Changed
+= new EventHandler (OnSelectionChanged
);
82 //TODO: cols for scale, precision, ... ?
83 TreeViewColumn colPK
= new TreeViewColumn ();
84 TreeViewColumn colName
= new TreeViewColumn ();
85 TreeViewColumn colType
= new TreeViewColumn ();
86 TreeViewColumn colLength
= new TreeViewColumn ();
87 TreeViewColumn colNullable
= new TreeViewColumn ();
88 TreeViewColumn colComment
= new TreeViewColumn ();
90 colPK
.Title
= AddinCatalog
.GetString ("PK");
91 colName
.Title
= AddinCatalog
.GetString ("Name");
92 colType
.Title
= AddinCatalog
.GetString ("Type");
93 colLength
.Title
= AddinCatalog
.GetString ("Length");
94 colNullable
.Title
= AddinCatalog
.GetString ("Nullable");
95 colComment
.Title
= AddinCatalog
.GetString ("Comment");
97 colType
.MinWidth
= 120; //request a bigger width
99 CellRendererToggle pkRenderer
= new CellRendererToggle ();
100 CellRendererText nameRenderer
= new CellRendererText ();
101 CellRendererCombo typeRenderer
= new CellRendererCombo ();
102 CellRendererText lengthRenderer
= new CellRendererText ();
103 CellRendererToggle nullableRenderer
= new CellRendererToggle ();
104 CellRendererText commentRenderer
= new CellRendererText ();
106 nameRenderer
.Editable
= true;
107 nameRenderer
.Edited
+= new EditedHandler (NameEdited
);
109 typeRenderer
.Model
= storeTypes
;
110 typeRenderer
.TextColumn
= 0;
111 typeRenderer
.Editable
= true;
112 typeRenderer
.Edited
+= new EditedHandler (TypeEdited
);
114 lengthRenderer
.Editable
= true;
115 lengthRenderer
.Edited
+= new EditedHandler (LengthEdited
);
117 pkRenderer
.Activatable
= true;
118 pkRenderer
.Toggled
+= new ToggledHandler (PkToggled
);
120 nullableRenderer
.Activatable
= true;
121 nullableRenderer
.Toggled
+= new ToggledHandler (NullableToggled
);
123 commentRenderer
.Editable
= true;
124 commentRenderer
.Edited
+= new EditedHandler (CommentEdited
);
126 colPK
.PackStart (pkRenderer
, true);
127 colName
.PackStart (nameRenderer
, true);
128 colType
.PackStart (typeRenderer
, true);
129 colLength
.PackStart (lengthRenderer
, true);
130 colNullable
.PackStart (nullableRenderer
, true);
131 colComment
.PackStart (commentRenderer
, true);
133 colPK
.AddAttribute (pkRenderer
, "active", colPKIndex
);
134 colName
.AddAttribute (nameRenderer
, "text", colNameIndex
);
135 colType
.AddAttribute (typeRenderer
, "text", colTypeIndex
);
136 colLength
.AddAttribute (lengthRenderer
, "text", colLengthIndex
);
137 colNullable
.AddAttribute (nullableRenderer
, "active", colNullableIndex
);
138 colComment
.AddAttribute (commentRenderer
, "text", colCommentIndex
);
140 if (settings
.ShowPrimaryKeyColumn
)
141 treeColumns
.AppendColumn (colPK
);
142 if (settings
.ShowNameColumn
)
143 treeColumns
.AppendColumn (colName
);
144 if (settings
.ShowTypeColumn
)
145 treeColumns
.AppendColumn (colType
);
146 if (settings
.ShowLengthColumn
)
147 treeColumns
.AppendColumn (colLength
);
148 if (settings
.ShowNullableColumn
)
149 treeColumns
.AppendColumn (colNullable
);
150 if (settings
.ShowCommentColumn
)
151 treeColumns
.AppendColumn (colComment
);
153 treeColumns
.Reorderable
= false;
154 treeColumns
.HeadersClickable
= false;
155 treeColumns
.HeadersVisible
= true;
156 //Gtk# 2.10:treeColumns.EnableGridLines = TreeViewGridLines.Both;
157 treeColumns
.EnableSearch
= false;
159 if (action
== SchemaActions
.Alter
) {
160 buttonAdd
.Sensitive
= settings
.ShowAddButton
;
161 buttonRemove
.Sensitive
= settings
.ShowRemoveButton
;
162 buttonUp
.Sensitive
= settings
.AllowReorder
;
168 public void Initialize (TableSchema table
, ColumnSchemaCollection columns
, ConstraintSchemaCollection constraints
, DataTypeSchemaCollection dataTypes
)
171 throw new ArgumentNullException ("columns");
172 if (constraints
== null)
173 throw new ArgumentNullException ("constraints");
175 throw new ArgumentNullException ("table");
176 if (dataTypes
== null)
177 throw new ArgumentNullException ("dataTypes");
180 this.columns
= columns
;
181 this.constraints
= constraints
;
182 this.dataTypes
= dataTypes
;
184 foreach (ColumnSchema column
in columns
)
185 AppendColumnSchema (column
);
187 foreach (DataTypeSchema dataType
in dataTypes
)
188 storeTypes
.AppendValues (dataType
.Name
, storeTypes
);
191 private void AppendColumnSchema (ColumnSchema column
)
193 bool pk
= column
.Constraints
.GetConstraint (ConstraintType
.PrimaryKey
) != null;
194 storeColumns
.AppendValues (pk
, column
.Name
, column
.DataType
.Name
, column
.DataType
.LengthRange
.Default
.ToString (), column
.IsNullable
, column
.Comment
, column
);
197 protected virtual void AddClicked (object sender
, EventArgs e
)
202 name
= "column" + index
;
204 } while (columns
.Contains (name
));
206 // ColumnSchema column = schemaProvider.GetNewColumnSchema (name, table);
209 // if (storeTypes.GetIterFirst (out iter))
210 // column.DataTypeName = storeTypes.GetValue (iter, 0) as string;
212 // columns.Add (column);
213 // AppendColumnSchema (column);
214 // EmitContentChanged ();
217 protected virtual void RemoveClicked (object sender
, EventArgs e
)
220 if (treeColumns
.Selection
.GetSelected (out iter
)) {
221 ColumnSchema column
= storeColumns
.GetValue (iter
, colObjIndex
) as ColumnSchema
;
223 //TODO: also check for attached constraints
225 bool result
= MessageService
.Confirm (
226 AddinCatalog
.GetString ("Are you sure you want to remove column '{0}'", column
.Name
),
231 storeColumns
.Remove (ref iter
);
232 EmitContentChanged ();
237 private void PkToggled (object sender
, ToggledArgs args
)
240 if (storeColumns
.GetIterFromString (out iter
, args
.Path
)) {
241 bool val
= (bool) storeColumns
.GetValue (iter
, colPKIndex
);
242 storeColumns
.SetValue (iter
, colPKIndex
, !val
);
243 EmitContentChanged ();
247 private void NullableToggled (object sender
, ToggledArgs args
)
250 if (storeColumns
.GetIterFromString (out iter
, args
.Path
)) {
251 bool val
= (bool) storeColumns
.GetValue (iter
, colNullableIndex
);
252 ColumnSchema column
= storeColumns
.GetValue (iter
, colObjIndex
) as ColumnSchema
;
253 storeColumns
.SetValue (iter
, colNullableIndex
, !val
);
254 column
.IsNullable
= !val
;
255 EmitContentChanged ();
259 private void NameEdited (object sender
, EditedArgs args
)
262 if (storeColumns
.GetIterFromString (out iter
, args
.Path
)) {
263 if (!string.IsNullOrEmpty (args
.NewText
)) {
264 storeColumns
.SetValue (iter
, colNameIndex
, args
.NewText
);
265 ColumnSchema column
= storeColumns
.GetValue (iter
, colObjIndex
) as ColumnSchema
;
266 column
.Name
= args
.NewText
;
267 EmitContentChanged ();
269 string oldText
= storeColumns
.GetValue (iter
, colNameIndex
) as string;
270 (sender
as CellRendererText
).Text
= oldText
;
275 private void TypeEdited (object sender
, EditedArgs args
)
278 if (storeColumns
.GetIterFromString (out iter
, args
.Path
)) {
279 if (!string.IsNullOrEmpty (args
.NewText
)) {
280 ColumnSchema column
= storeColumns
.GetValue (iter
, colObjIndex
) as ColumnSchema
;
282 int len
= int.Parse (storeColumns
.GetValue (iter
, colLengthIndex
) as string);
283 if (column
.DataType
.LengthRange
.Default
== len
) {
284 //change the length if it is still the default length
285 DataTypeSchema dtNew
= schemaProvider
.GetDataType (args
.NewText
);
286 storeColumns
.SetValue (iter
, colLengthIndex
, dtNew
.LengthRange
.Default
.ToString ());
289 storeColumns
.SetValue (iter
, colTypeIndex
, args
.NewText
);
290 column
.DataTypeName
= args
.NewText
;
291 EmitContentChanged ();
293 string oldText
= storeColumns
.GetValue (iter
, colTypeIndex
) as string;
294 (sender
as CellRendererText
).Text
= oldText
;
299 private void LengthEdited (object sender
, EditedArgs args
)
302 if (storeColumns
.GetIterFromString (out iter
, args
.Path
)) {
304 if (!string.IsNullOrEmpty (args
.NewText
) && int.TryParse (args
.NewText
, out len
)) {
305 storeColumns
.SetValue (iter
, colLengthIndex
, args
.NewText
);
306 ColumnSchema column
= storeColumns
.GetValue (iter
, colObjIndex
) as ColumnSchema
;
307 column
.DataType
.LengthRange
.Default
= int.Parse (args
.NewText
);
308 EmitContentChanged ();
310 string oldText
= storeColumns
.GetValue (iter
, colLengthIndex
) as string;
311 (sender
as CellRendererText
).Text
= oldText
;
316 private void CommentEdited (object sender
, EditedArgs args
)
319 if (storeColumns
.GetIterFromString (out iter
, args
.Path
)) {
320 storeColumns
.SetValue (iter
, colCommentIndex
, args
.NewText
);
321 ColumnSchema column
= storeColumns
.GetValue (iter
, colObjIndex
) as ColumnSchema
;
322 column
.Comment
= args
.NewText
;
323 EmitContentChanged ();
327 protected virtual void DownClicked (object sender
, EventArgs e
)
330 if (treeColumns
.Selection
.GetSelected (out iter
)) {
331 TreePath path
= storeColumns
.GetPath (iter
);
332 int x
= path
.Indices
[0];
333 columns
.Swap (x
, x
+ 1);
337 protected virtual void UpClicked (object sender
, EventArgs e
)
340 if (treeColumns
.Selection
.GetSelected (out iter
)) {
341 TreePath path
= storeColumns
.GetPath (iter
);
342 int x
= path
.Indices
[0];
343 columns
.Swap (x
, x
- 1);
347 private void OnSelectionChanged (object sender
, EventArgs e
)
349 IDbFactory fac
= schemaProvider
.ConnectionPool
.DbFactory
;
350 //TODO: check Append if "next" is the last row
352 bool sel
= settings
.ShowRemoveButton
;
353 bool next
= settings
.AllowReorder
;
356 if (treeColumns
.Selection
.GetSelected (out iter
)) {
357 TreePath path
= storeColumns
.GetPath (iter
);
358 int index
= path
.Indices
[0];
362 next
&= storeColumns
.IterNext (ref iter
);
365 buttonUp
.Sensitive
= prev
;
366 buttonDown
.Sensitive
= next
;
367 buttonRemove
.Sensitive
= sel
;
370 protected virtual void EmitContentChanged ()
372 if (ContentChanged
!= null)
373 ContentChanged (this, EventArgs
.Empty
);
376 public virtual bool ValidateSchemaObjects (out string msg
)
379 if (storeColumns
.GetIterFirst (out iter
)) {
380 bool isPk
= constraints
.GetConstraint (ConstraintType
.PrimaryKey
) != null;
382 string name
= storeColumns
.GetValue (iter
, colNameIndex
) as string;
383 string type
= storeColumns
.GetValue (iter
, colTypeIndex
) as string;
384 int len
= int.Parse (storeColumns
.GetValue (iter
, colLengthIndex
) as string);
386 isPk
= (bool)storeColumns
.GetValue (iter
, colPKIndex
);
388 DataTypeSchema dt
= schemaProvider
.GetDataType (type
);
390 msg
= AddinCatalog
.GetString ("Unknown data type '{0}' applied to column '{1}'.", type
, name
);
394 //TODO: enable when all providers have good datatype info
395 // if (!dt.LengthRange.IsInRange (len)) {
396 // msg = AddinCatalog.GetString ("Invalid length for '{0}'.", name);
399 } while (storeColumns
.IterNext (ref iter
));
402 msg
= AddinCatalog
.GetString ("Table '{0}' must contain at least one primary key.", table
.Name
);
409 msg
= AddinCatalog
.GetString ("Table '{0}' must contain at least 1 column.", table
.Name
);
413 public virtual void FillSchemaObjects ()
416 if (storeColumns
.GetIterFirst (out iter
)) {
418 ColumnSchema column
= storeColumns
.GetValue (iter
, colObjIndex
) as ColumnSchema
;
420 column
.Name
= storeColumns
.GetValue (iter
, colNameIndex
) as string;
421 column
.DataTypeName
= storeColumns
.GetValue (iter
, colTypeIndex
) as string;
422 column
.DataType
.LengthRange
.Default
= int.Parse (storeColumns
.GetValue (iter
, colLengthIndex
) as string);
423 column
.IsNullable
= (bool)storeColumns
.GetValue (iter
, colNullableIndex
);
424 column
.Comment
= storeColumns
.GetValue (iter
, colCommentIndex
) as string;
426 if ((bool)storeColumns
.GetValue (iter
, colPKIndex
)) {
427 PrimaryKeyConstraintSchema pk
= schemaProvider
.CreatePrimaryKeyConstraintSchema ("pk_" + column
.Name
);
428 column
.Constraints
.Add (pk
);
430 } while (storeColumns
.IterNext (ref iter
));
435 public class ColumnEditorSettings
437 private bool showAddButton
= true;
438 private bool showRemoveButton
= true;
439 private bool allowReorder
= true;
441 private bool showPrimaryKeyColumn
= true;
442 private bool showNameColumn
= true;
443 private bool showTypeColumn
= true;
444 private bool showLengthColumn
= true;
445 private bool showNullableColumn
= true;
446 private bool showCommentColumn
= true;
448 public bool ShowAddButton
{
449 get { return showAddButton; }
450 set { showAddButton = value; }
453 public bool ShowRemoveButton
{
454 get { return showRemoveButton; }
455 set { showRemoveButton = value; }
458 public bool AllowReorder
{
459 get { return allowReorder; }
460 set { allowReorder = value; }
463 public bool ShowPrimaryKeyColumn
{
464 get { return showPrimaryKeyColumn; }
465 set { showPrimaryKeyColumn = value; }
467 public bool ShowNameColumn
{
468 get { return showNameColumn; }
469 set { showNameColumn = value; }
471 public bool ShowTypeColumn
{
472 get { return showTypeColumn; }
473 set { showTypeColumn = value; }
475 public bool ShowLengthColumn
{
476 get { return showLengthColumn; }
477 set { showLengthColumn = value; }
479 public bool ShowNullableColumn
{
480 get { return showNullableColumn; }
481 set { showNullableColumn = value; }
484 public bool ShowCommentColumn
{
485 get { return showCommentColumn; }
486 set { showCommentColumn = value; }