* Makefile.am:
[monodevelop.git] / extras / MonoDevelop.Database / MonoDevelop.Database.Designer / Widgets / ForeignKeyConstraintEditorWidget.cs
blobb0969db907cd52223a911ef08db9485e4ce8ee9e
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 a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
14 // The above copyright notice and this permission notice shall be included in
15 // all copies or substantial portions of the Software.
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 // THE SOFTWARE.
26 using Gtk;
27 using System;
28 using System.Text;
29 using System.Collections.Generic;
30 using MonoDevelop.Core;
31 using MonoDevelop.Core.Gui;
32 using MonoDevelop.Components;
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 ForeignKeyConstraintEditorWidget : Gtk.Bin
42 public event EventHandler ContentChanged;
44 private ISchemaProvider schemaProvider;
45 private TableSchema table;
46 private TableSchemaCollection tables;
47 private ColumnSchemaCollection columns;
48 private ConstraintSchemaCollection constraints;
50 private const int colNameIndex = 0;
51 private const int colReferenceTableIndex = 1;
52 private const int colIsColumnConstraintIndex = 2;
53 private const int colColumnsIndex = 3;
54 private const int colReferenceColumnsIndex = 4;
55 private const int colDeleteActionIndex = 5;
56 private const int colUpdateActionIndex = 6;
57 private const int colObjIndex = 7;
59 private ListStore store;
60 private ListStore storeActions;
61 private ListStore storeTables;
63 private SchemaActions action;
64 private ForeignKeyConstraintEditorSettings settings;
66 //TODO: difference between columns and reference columns + combo events
67 public ForeignKeyConstraintEditorWidget (ISchemaProvider schemaProvider, SchemaActions action, ForeignKeyConstraintEditorSettings settings)
69 if (schemaProvider == null)
70 throw new ArgumentNullException ("schemaProvider");
71 if (settings == null)
72 throw new ArgumentNullException ("settings");
74 this.schemaProvider = schemaProvider;
75 this.action = action;
76 this.settings = settings;
78 this.Build();
80 store = new ListStore (typeof (string), typeof (string), typeof (bool), typeof (string), typeof (string), typeof (string), typeof (string), typeof (object));
81 listFK.Model = store;
83 storeActions = new ListStore (typeof (string), typeof (int));
84 storeTables = new ListStore (typeof (string));
86 if (settings.SupportsCascade)
87 storeActions.AppendValues ("Cascade", ForeignKeyAction.Cascade);
88 if (settings.SupportsRestrict)
89 storeActions.AppendValues ("Restrict", ForeignKeyAction.Restrict);
90 if (settings.SupportsNoAction)
91 storeActions.AppendValues ("No Action", ForeignKeyAction.NoAction);
92 if (settings.SupportsSetNull)
93 storeActions.AppendValues ("Set Null", ForeignKeyAction.SetNull);
94 if (settings.SupportsSetDefault)
95 storeActions.AppendValues ("Set Default", ForeignKeyAction.SetDefault);
97 foreach (TableSchema tbl in tables)
98 if (tbl.Name != table.Name)
99 storeTables.AppendValues (tbl.Name);
101 TreeViewColumn colName = new TreeViewColumn ();
102 TreeViewColumn colRefTable = new TreeViewColumn ();
103 TreeViewColumn colIsColumnConstraint = new TreeViewColumn ();
104 TreeViewColumn colDeleteAction = new TreeViewColumn ();
105 TreeViewColumn colUpdateAction = new TreeViewColumn ();
107 colName.Title = AddinCatalog.GetString ("Name");
108 colRefTable.Title = AddinCatalog.GetString ("Reference Table");
109 colIsColumnConstraint.Title = AddinCatalog.GetString ("Column Constraint");
110 colDeleteAction.Title = AddinCatalog.GetString ("Delete Action");
111 colUpdateAction.Title = AddinCatalog.GetString ("Update Action");
113 colRefTable.MinWidth = 120;
115 CellRendererText nameRenderer = new CellRendererText ();
116 CellRendererCombo refTableRenderer = new CellRendererCombo ();
117 CellRendererToggle isColumnConstraintRenderer = new CellRendererToggle ();
118 CellRendererCombo deleteActionRenderer = new CellRendererCombo ();
119 CellRendererCombo updateActionRenderer = new CellRendererCombo ();
121 nameRenderer.Editable = true;
122 nameRenderer.Edited += new EditedHandler (NameEdited);
124 refTableRenderer.Model = storeTables;
125 refTableRenderer.TextColumn = 0;
126 refTableRenderer.Editable = true;
127 refTableRenderer.Edited += new EditedHandler (RefTableEdited);
129 isColumnConstraintRenderer.Activatable = true;
130 isColumnConstraintRenderer.Toggled += new ToggledHandler (IsColumnConstraintToggled);
132 deleteActionRenderer.Model = storeActions;
133 deleteActionRenderer.TextColumn = 0;
134 deleteActionRenderer.Editable = true;
135 deleteActionRenderer.Edited += new EditedHandler (DeleteActionEdited);
137 updateActionRenderer.Model = storeActions;
138 updateActionRenderer.TextColumn = 0;
139 updateActionRenderer.Editable = true;
140 updateActionRenderer.Edited += new EditedHandler (UpdateActionEdited);
142 colName.PackStart (nameRenderer, true);
143 colRefTable.PackStart (refTableRenderer, true);
144 colIsColumnConstraint.PackStart (isColumnConstraintRenderer, true);
145 colDeleteAction.PackStart (deleteActionRenderer, true);
146 colUpdateAction.PackStart (updateActionRenderer, true);
148 colName.AddAttribute (nameRenderer, "text", colNameIndex);
149 colRefTable.AddAttribute (refTableRenderer, "text", colReferenceTableIndex);
150 colIsColumnConstraint.AddAttribute (isColumnConstraintRenderer, "active", colIsColumnConstraintIndex);
151 colDeleteAction.AddAttribute (deleteActionRenderer, "text", colDeleteActionIndex);
152 colUpdateAction.AddAttribute (updateActionRenderer, "text", colUpdateActionIndex);
154 listFK.AppendColumn (colName);
155 listFK.AppendColumn (colRefTable);
156 listFK.AppendColumn (colIsColumnConstraint);
157 listFK.AppendColumn (colDeleteAction);
158 listFK.AppendColumn (colUpdateAction);
160 columnSelecter.ColumnToggled += new EventHandler (ColumnToggled);
161 referenceColumnSelecter.ColumnToggled += new EventHandler (ReferenceColumnToggled);
162 listFK.Selection.Changed += new EventHandler (SelectionChanged);
164 ShowAll ();
167 public void Initialize (TableSchemaCollection tables, TableSchema table, ColumnSchemaCollection columns, ConstraintSchemaCollection constraints)
169 if (columns == null)
170 throw new ArgumentNullException ("columns");
171 if (table == null)
172 throw new ArgumentNullException ("table");
173 if (constraints == null)
174 throw new ArgumentNullException ("constraints");
175 if (tables == null)
176 throw new ArgumentNullException ("tables");
178 this.table = table;
179 this.tables = tables;
180 this.columns = columns;
181 this.constraints = constraints;
184 protected virtual void AddClicked (object sender, EventArgs e)
186 ForeignKeyConstraintSchema fk = schemaProvider.CreateForeignKeyConstraintSchema ("fk_new");
187 int index = 1;
188 while (constraints.Contains (fk.Name))
189 fk.Name = "fk_new" + (index++);
190 constraints.Add (fk);
191 AddConstraint (fk);
192 EmitContentChanged ();
195 protected virtual void RemoveClicked (object sender, EventArgs e)
197 TreeIter iter;
198 if (listFK.Selection.GetSelected (out iter)) {
199 ForeignKeyConstraintSchema fk = store.GetValue (iter, colObjIndex) as ForeignKeyConstraintSchema;
201 if (MessageService.Confirm (
202 AddinCatalog.GetString ("Are you sure you want to remove constraint '{0}'?", fk.Name),
203 AlertButton.Remove
204 )) {
205 store.Remove (ref iter);
206 constraints.Remove (fk);
207 EmitContentChanged ();
212 private void SelectionChanged (object sender, EventArgs args)
214 columnSelecter.DeselectAll ();
216 TreeIter iter;
217 if (listFK.Selection.GetSelected (out iter)) {
218 columnSelecter.Sensitive = true;
219 SetSelectionFromIter (iter);
220 } else {
221 columnSelecter.Sensitive = false;
225 private void SetSelectionFromIter (TreeIter iter)
227 bool iscolc = (bool)store.GetValue (iter, colIsColumnConstraintIndex);
228 columnSelecter.SingleCheck = iscolc;
230 string colstr = store.GetValue (iter, colColumnsIndex) as string;
231 string[] cols = colstr.Split (',');
232 foreach (string col in cols)
233 columnSelecter.Select (col);
235 colstr = store.GetValue (iter, colReferenceColumnsIndex) as string;
236 cols = colstr.Split (',');
237 foreach (string col in cols)
238 referenceColumnSelecter.Select (col);
241 private void RefTableEdited (object sender, EditedArgs args)
243 TreeIter iter;
244 if (store.GetIterFromString (out iter, args.Path)) {
245 if (tables.Contains (args.NewText)) {
246 store.SetValue (iter, colReferenceTableIndex, args.NewText);
247 SetSelectionFromIter (iter);
248 EmitContentChanged ();
249 } else {
250 string oldText = store.GetValue (iter, colReferenceTableIndex) as string;
251 (sender as CellRendererText).Text = oldText;
256 private void ColumnToggled (object sender, EventArgs args)
258 TreeIter iter;
259 if (listFK.Selection.GetSelected (out iter)) {
260 store.SetValue (iter, colColumnsIndex, GetColumnsString (columnSelecter.CheckedColumns));
261 EmitContentChanged ();
265 private void ReferenceColumnToggled (object sender, EventArgs args)
267 TreeIter iter;
268 if (listFK.Selection.GetSelected (out iter)) {
269 store.SetValue (iter, colReferenceColumnsIndex, GetColumnsString (referenceColumnSelecter.CheckedColumns));
270 EmitContentChanged ();
274 private void IsColumnConstraintToggled (object sender, ToggledArgs args)
276 TreeIter iter;
277 if (store.GetIterFromString (out iter, args.Path)) {
278 bool val = (bool) store.GetValue (iter, colIsColumnConstraintIndex);
279 store.SetValue (iter, colIsColumnConstraintIndex, !val);
280 EmitContentChanged ();
284 private void NameEdited (object sender, EditedArgs args)
286 TreeIter iter;
287 if (store.GetIterFromString (out iter, args.Path)) {
288 if (!string.IsNullOrEmpty (args.NewText)) {
289 store.SetValue (iter, colNameIndex, args.NewText);
290 EmitContentChanged ();
291 } else {
292 string oldText = store.GetValue (iter, colNameIndex) as string;
293 (sender as CellRendererText).Text = oldText;
298 private void UpdateActionEdited (object sender, EditedArgs args)
300 TreeIter iter;
301 if (store.GetIterFromString (out iter, args.Path)) {
302 if (IsValidForeignKeyAction (args.NewText)) {
303 store.SetValue (iter, colUpdateActionIndex, args.NewText);
304 EmitContentChanged ();
305 } else {
306 string oldText = store.GetValue (iter, colUpdateActionIndex) as string;
307 (sender as CellRendererText).Text = oldText;
312 private void DeleteActionEdited (object sender, EditedArgs args)
314 TreeIter iter;
315 if (store.GetIterFromString (out iter, args.Path)) {
316 if (IsValidForeignKeyAction (args.NewText)) {
317 store.SetValue (iter, colDeleteActionIndex, args.NewText);
318 EmitContentChanged ();
319 } else {
320 string oldText = store.GetValue (iter, colDeleteActionIndex) as string;
321 (sender as CellRendererText).Text = oldText;
326 private bool IsValidForeignKeyAction (string name)
328 foreach (string item in Enum.GetNames (typeof (ForeignKeyAction))) {
329 if (item == name)
330 return true;
332 return false;
335 private void AddConstraint (ForeignKeyConstraintSchema fk)
337 store.AppendValues (fk.Name, String.Empty, false, String.Empty, String.Empty,
338 fk.DeleteAction.ToString (), fk.UpdateAction.ToString (), fk
342 protected virtual void EmitContentChanged ()
344 if (ContentChanged != null)
345 ContentChanged (this, EventArgs.Empty);
348 public virtual bool ValidateSchemaObjects (out string msg)
350 TreeIter iter;
351 if (store.GetIterFirst (out iter)) {
352 do {
353 string name = store.GetValue (iter, colNameIndex) as string;
354 string columns = store.GetValue (iter, colColumnsIndex) as string;
356 if (String.IsNullOrEmpty (columns)) {
357 msg = AddinCatalog.GetString ("Unique Key constraint '{0}' must be applied to one or more columns.", name);
358 return false;
360 } while (store.IterNext (ref iter));
362 msg = null;
363 return true;
366 public virtual void FillSchemaObjects ()
368 TreeIter iter;
369 if (store.GetIterFirst (out iter)) {
370 do {
371 ForeignKeyConstraintSchema fk = store.GetValue (iter, colObjIndex) as ForeignKeyConstraintSchema;
373 fk.Name = store.GetValue (iter, colNameIndex) as string;
374 fk.IsColumnConstraint = (bool)store.GetValue (iter, colIsColumnConstraintIndex);
375 fk.ReferenceTableName = store.GetValue (iter, colReferenceTableIndex) as string;
377 fk.DeleteAction = GetForeignKeyAction (iter, colDeleteActionIndex);
378 fk.UpdateAction = GetForeignKeyAction (iter, colUpdateActionIndex);
380 string colstr = store.GetValue (iter, colColumnsIndex) as string;
381 string[] cols = colstr.Split (',');
382 foreach (string col in cols) {
383 ColumnSchema column = columns.Search (col);
384 fk.Columns.Add (column);
387 colstr = store.GetValue (iter, colReferenceColumnsIndex) as string;
388 cols = colstr.Split (',');
389 foreach (string col in cols) {
390 ColumnSchema column = columns.Search (col);
391 fk.ReferenceColumns.Add (column);
394 table.Constraints.Add (fk);
395 } while (store.IterNext (ref iter));
399 private string GetColumnsString (IEnumerable<ColumnSchema> collection)
401 bool first = true;
402 StringBuilder sb = new StringBuilder ();
403 foreach (ColumnSchema column in collection) {
404 if (first)
405 first = false;
406 else
407 sb.Append (',');
409 sb.Append (column.Name);
411 return sb.ToString ();
414 private ForeignKeyAction GetForeignKeyAction (TreeIter colIter, int colIndex)
416 string name = store.GetValue (colIter, colIndex) as string;
418 TreeIter iter;
419 if (storeActions.GetIterFirst (out iter)) {
420 do {
421 string actionName = storeActions.GetValue (iter, 0) as string;
422 if (actionName == name)
423 return (ForeignKeyAction)storeActions.GetValue (iter, 1);
424 } while (storeActions.IterNext (ref iter));
426 return ForeignKeyAction.None;
430 public class ForeignKeyConstraintEditorSettings
432 private bool supportsCascade = true;
433 private bool supportsRestrict = true;
434 private bool supportsNoAction = true;
435 private bool supportsSetNull = true;
436 private bool supportsSetDefault = true;
438 public bool SupportsCascade {
439 get { return supportsCascade; }
440 set { supportsCascade = value; }
443 public bool SupportsRestrict {
444 get { return supportsRestrict; }
445 set { supportsRestrict = value; }
448 public bool SupportsNoAction {
449 get { return supportsNoAction; }
450 set { supportsNoAction = value; }
453 public bool SupportsSetNull {
454 get { return supportsSetNull; }
455 set { supportsSetNull = value; }
458 public bool SupportsSetDefault {
459 get { return supportsSetDefault; }
460 set { supportsSetDefault = value; }