* Makefile.am:
[monodevelop.git] / extras / MonoDevelop.Database / MonoDevelop.Database.Designer / Widgets / ColumnsEditorWidget.cs
blobc29f166b740330a7a31249b975a70ebeb39f9101
1 //
2 // Authors:
3 // Ben Motmans <ben.motmans@gmail.com>
4 //
5 // Copyright (c) 2007 Ben Motmans
6 //
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:
14 //
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
17 //
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.
27 using Gtk;
28 using System;
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");
68 if (settings == null)
69 throw new ArgumentNullException ("settings");
71 this.schemaProvider = schemaProvider;
72 this.action = action;
73 this.settings = settings;
75 this.Build();
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;
165 ShowAll ();
168 public void Initialize (TableSchema table, ColumnSchemaCollection columns, ConstraintSchemaCollection constraints, DataTypeSchemaCollection dataTypes)
170 if (columns == null)
171 throw new ArgumentNullException ("columns");
172 if (constraints == null)
173 throw new ArgumentNullException ("constraints");
174 if (table == null)
175 throw new ArgumentNullException ("table");
176 if (dataTypes == null)
177 throw new ArgumentNullException ("dataTypes");
179 this.table = table;
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)
199 int index = 1;
200 string name = null;
201 do {
202 name = "column" + index;
203 index++;
204 } while (columns.Contains (name));
206 // ColumnSchema column = schemaProvider.GetNewColumnSchema (name, table);
208 // TreeIter iter;
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)
219 TreeIter iter;
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),
227 AlertButton.Remove
230 if (result) {
231 storeColumns.Remove (ref iter);
232 EmitContentChanged ();
237 private void PkToggled (object sender, ToggledArgs args)
239 TreeIter iter;
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)
249 TreeIter iter;
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)
261 TreeIter iter;
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 ();
268 } else {
269 string oldText = storeColumns.GetValue (iter, colNameIndex) as string;
270 (sender as CellRendererText).Text = oldText;
275 private void TypeEdited (object sender, EditedArgs args)
277 TreeIter iter;
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 ();
292 } else {
293 string oldText = storeColumns.GetValue (iter, colTypeIndex) as string;
294 (sender as CellRendererText).Text = oldText;
299 private void LengthEdited (object sender, EditedArgs args)
301 TreeIter iter;
302 if (storeColumns.GetIterFromString (out iter, args.Path)) {
303 int len;
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 ();
309 } else {
310 string oldText = storeColumns.GetValue (iter, colLengthIndex) as string;
311 (sender as CellRendererText).Text = oldText;
316 private void CommentEdited (object sender, EditedArgs args)
318 TreeIter iter;
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)
329 TreeIter iter;
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)
339 TreeIter iter;
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
351 TreeIter iter;
352 bool sel = settings.ShowRemoveButton;
353 bool next = settings.AllowReorder;
354 bool prev = next;
356 if (treeColumns.Selection.GetSelected (out iter)) {
357 TreePath path = storeColumns.GetPath (iter);
358 int index = path.Indices[0];
360 sel &= true;
361 prev &= index > 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)
378 TreeIter iter;
379 if (storeColumns.GetIterFirst (out iter)) {
380 bool isPk = constraints.GetConstraint (ConstraintType.PrimaryKey) != null;
381 do {
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);
385 if (!isPk)
386 isPk = (bool)storeColumns.GetValue (iter, colPKIndex);
388 DataTypeSchema dt = schemaProvider.GetDataType (type);
389 if (dt == null) {
390 msg = AddinCatalog.GetString ("Unknown data type '{0}' applied to column '{1}'.", type, name);
391 return false;
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);
397 // return false;
398 // }
399 } while (storeColumns.IterNext (ref iter));
401 if (!isPk) {
402 msg = AddinCatalog.GetString ("Table '{0}' must contain at least one primary key.", table.Name);
403 return false;
404 } else {
405 msg = null;
406 return true;
409 msg = AddinCatalog.GetString ("Table '{0}' must contain at least 1 column.", table.Name);
410 return false;
413 public virtual void FillSchemaObjects ()
415 TreeIter iter;
416 if (storeColumns.GetIterFirst (out iter)) {
417 do {
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; }