~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric-updates

« back to all changes in this revision

Viewing changes to src/addins/MonoDevelop.XmlEditor/MonoDevelop.XmlEditor.Gui/XmlSchemasPanelWidget.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2009-02-18 08:40:51 UTC
  • mfrom: (1.2.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20090218084051-gh8m6ukvokbwj7cf
Tags: 1.9.2+dfsg-1ubuntu1
* Merge from Debian Experimental (LP: #330519), remaining Ubuntu changes:
  + debian/control:
    - Update for Gnome# 2.24
    - Add libmono-cairo1.0-cil to build-deps to fool pkg-config check

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// 
 
2
// XmlSchemasPanelWidget.cs
 
3
// 
 
4
// Author:
 
5
//   Michael Hutchinson <mhutchinson@novell.com>
 
6
//   Matthew Ward
 
7
// 
 
8
// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
 
9
// Copyright (C) 2005-2007 Matthew Ward
 
10
// 
 
11
// Permission is hereby granted, free of charge, to any person obtaining
 
12
// a copy of this software and associated documentation files (the
 
13
// "Software"), to deal in the Software without restriction, including
 
14
// without limitation the rights to use, copy, modify, merge, publish,
 
15
// distribute, sublicense, and/or sell copies of the Software, and to
 
16
// permit persons to whom the Software is furnished to do so, subject to
 
17
// the following conditions:
 
18
// 
 
19
// The above copyright notice and this permission notice shall be
 
20
// included in all copies or substantial portions of the Software.
 
21
// 
 
22
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
23
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
24
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
25
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
26
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
27
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
28
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
29
//
 
30
 
 
31
using MonoDevelop.XmlEditor;
 
32
using MonoDevelop.XmlEditor.Completion;
 
33
using MonoDevelop.Core;
 
34
using MonoDevelop.Core.Gui;
 
35
 
 
36
using System;
 
37
using System.Collections.Generic;
 
38
using Gtk;
 
39
 
 
40
namespace MonoDevelop.XmlEditor.Gui
 
41
{
 
42
        
 
43
        
 
44
        public partial class XmlSchemasPanelWidget : Gtk.Bin
 
45
        {
 
46
                ListStore registeredSchemasStore;
 
47
                ListStore defaultAssociationsStore;
 
48
                ListStore registeredSchemasComboModel;
 
49
                List<XmlSchemaCompletionData> addedSchemas = new List<XmlSchemaCompletionData> ();
 
50
                List<XmlSchemaCompletionData> removedSchemas = new List<XmlSchemaCompletionData> ();
 
51
                List<string> removedExtensions = new List<string> ();
 
52
                
 
53
                public XmlSchemasPanelWidget()
 
54
                {
 
55
                        this.Build();
 
56
                        
 
57
                        //set up tree view for default schemas
 
58
                        CellRendererText textRenderer = new CellRendererText ();
 
59
                        registeredSchemasStore = new ListStore (typeof (XmlSchemaCompletionData));
 
60
                        registeredSchemasView.Model = registeredSchemasStore;
 
61
                        
 
62
                        registeredSchemasView.AppendColumn ("Namespace", textRenderer,
 
63
                            delegate (TreeViewColumn col, CellRenderer cell, TreeModel model, TreeIter iter) {
 
64
                                ((Gtk.CellRendererText)cell).Text = ((MonoDevelop.XmlEditor.Completion.XmlSchemaCompletionData)model.GetValue (iter, 0)).NamespaceUri;
 
65
                        });
 
66
                        
 
67
                        registeredSchemasView.AppendColumn ("Type", textRenderer,
 
68
                            delegate (TreeViewColumn col, CellRenderer cell, TreeModel model, TreeIter iter) {
 
69
                                bool builtIn = ((MonoDevelop.XmlEditor.Completion.XmlSchemaCompletionData)model.GetValue (iter, 0)).ReadOnly;
 
70
                                ((Gtk.CellRendererText)cell).Text = builtIn? 
 
71
                                          MonoDevelop.Core.GettextCatalog.GetString ("Built in") 
 
72
                                        : MonoDevelop.Core.GettextCatalog.GetString ("User schema");
 
73
                        });
 
74
                        
 
75
                        registeredSchemasStore.SetSortFunc (0, 
 
76
                            delegate (TreeModel model, TreeIter a, TreeIter b) {
 
77
                                return string.Compare (
 
78
                                    ((MonoDevelop.XmlEditor.Completion.XmlSchemaCompletionData) model.GetValue (a, 0)).NamespaceUri,
 
79
                                    ((MonoDevelop.XmlEditor.Completion.XmlSchemaCompletionData) model.GetValue (b, 0)).NamespaceUri
 
80
                                );
 
81
                        });
 
82
                        registeredSchemasStore.SetSortColumnId (0, SortType.Ascending);
 
83
                        
 
84
                        //update state of "remove" button depending on whether schema is read-only and anything's slected
 
85
                        registeredSchemasView.Selection.Changed += delegate {
 
86
                                MonoDevelop.XmlEditor.Completion.XmlSchemaCompletionData data = GetSelectedSchema ();
 
87
                                registeredSchemasRemoveButton.Sensitive = (data != null && !data.ReadOnly);
 
88
                        };
 
89
                        registeredSchemasRemoveButton.Sensitive = false;
 
90
                        
 
91
                        //set up cells for associations
 
92
                        CellRendererText extensionTextRenderer = new CellRendererText ();
 
93
                        extensionTextRenderer.Editable = true;
 
94
                        CellRendererText prefixTextRenderer = new CellRendererText ();
 
95
                        prefixTextRenderer.Editable = true;
 
96
                        
 
97
                        CellRendererCombo comboEditor = new CellRendererCombo ();
 
98
                        registeredSchemasComboModel = new ListStore (typeof (string));
 
99
                        comboEditor.Model = registeredSchemasComboModel;
 
100
                        comboEditor.Mode = CellRendererMode.Editable;
 
101
                        comboEditor.TextColumn = 0;
 
102
                        comboEditor.Editable = true;
 
103
                        comboEditor.HasEntry = false;
 
104
                        
 
105
                        //rebuild combo's model from default schemas whenever editing starts
 
106
                        comboEditor.EditingStarted += delegate (object sender, EditingStartedArgs args) {
 
107
                                registeredSchemasComboModel.Clear ();
 
108
                                registeredSchemasComboModel.AppendValues (string.Empty);
 
109
                                foreach (Gtk.TreeIter iter in WalkStore (registeredSchemasStore))
 
110
                                        registeredSchemasComboModel.AppendValues (
 
111
                                            ((MonoDevelop.XmlEditor.Completion.XmlSchemaCompletionData)registeredSchemasStore.GetValue (iter, 0)).NamespaceUri
 
112
                                        );
 
113
                                args.RetVal = true;
 
114
                                registeredSchemasComboModel.SetSortColumnId (0, Gtk.SortType.Ascending);
 
115
                        };
 
116
                        
 
117
                        //set up tree view for associations
 
118
                        defaultAssociationsStore = new ListStore (typeof (string), typeof (string), typeof (string), typeof (bool));
 
119
                        defaultAssociationsView.Model = defaultAssociationsStore;
 
120
                        defaultAssociationsView.AppendColumn ("File Extension", extensionTextRenderer, "text", DACols.Extension);
 
121
                        defaultAssociationsView.AppendColumn ("Namespace", comboEditor, "text", DACols.Namespace);
 
122
                        defaultAssociationsView.AppendColumn ("Prefix", prefixTextRenderer, "text", DACols.Prefix);
 
123
                        defaultAssociationsStore.SetSortColumnId ((int)DACols.Extension, SortType.Ascending);
 
124
                        
 
125
                        //editing handlers
 
126
                        extensionTextRenderer.Edited += handleExtensionSet;
 
127
                        comboEditor.Edited += delegate (object sender, EditedArgs args) {
 
128
                                setAssocValAndMarkChanged (args.Path, DACols.Namespace, args.NewText);
 
129
                        };
 
130
                        prefixTextRenderer.Edited += delegate (object sender, EditedArgs args) {
 
131
                                foreach (char c in args.NewText)
 
132
                                        if (!char.IsLetterOrDigit (c))
 
133
                                                //FIXME: give an error message?
 
134
                                                return;
 
135
                                setAssocValAndMarkChanged (args.Path, DACols.Prefix, args.NewText);
 
136
                        };
 
137
                        
 
138
                        //update state of "remove" button depending on whether anything's slected
 
139
                        defaultAssociationsView.Selection.Changed += delegate {
 
140
                                Gtk.TreeIter iter;
 
141
                                defaultAssociationsRemoveButton.Sensitive =
 
142
                                        defaultAssociationsView.Selection.GetSelected (out iter);
 
143
                        };
 
144
                        defaultAssociationsRemoveButton.Sensitive = false;
 
145
                }
 
146
                
 
147
                IEnumerable<object> WalkStore (TreeModel model, int column)
 
148
                {
 
149
                        foreach (TreeIter iter in WalkStore (model))
 
150
                                yield return model.GetValue (iter, column);
 
151
                }
 
152
                
 
153
                IEnumerable<TreeIter> WalkStore (TreeModel model)
 
154
                {
 
155
                        TreeIter iter;
 
156
                        bool valid = model.GetIterFirst (out iter);
 
157
                        while (valid) {
 
158
                                yield return iter;
 
159
                                valid = model.IterNext (ref iter);
 
160
                        }
 
161
                }
 
162
                
 
163
                #region Schema accessors
 
164
                
 
165
                public List<XmlSchemaCompletionData> AddedSchemas {
 
166
                        get { return addedSchemas; }
 
167
                }
 
168
                
 
169
                public List<XmlSchemaCompletionData> RemovedSchemas {
 
170
                        get { return removedSchemas; }
 
171
                }
 
172
                
 
173
                XmlSchemaCompletionData GetSelectedSchema ()
 
174
                {
 
175
                        TreeIter iter;
 
176
                        if (registeredSchemasView.Selection.GetSelected (out iter))
 
177
                                return (XmlSchemaCompletionData) registeredSchemasStore.GetValue (iter, 0);
 
178
                        return null;
 
179
                }
 
180
                
 
181
                // Checks that the schema namespace does not already exist.
 
182
                XmlSchemaCompletionData GetRegisteredSchema (string namespaceUri)
 
183
                {
 
184
                        foreach (XmlSchemaCompletionData schema in WalkStore (registeredSchemasStore, 0))
 
185
                                if (schema.NamespaceUri == namespaceUri)
 
186
                                        return schema;
 
187
                        return null;
 
188
                }
 
189
                
 
190
                XmlSchemaCompletionData GetRegisteredSchema (TreeIter iter)
 
191
                {
 
192
                        return (XmlSchemaCompletionData) registeredSchemasStore.GetValue (iter, 0);
 
193
                }
 
194
                
 
195
                public void LoadUserSchemas (XmlSchemaCompletionDataCollection val)
 
196
                {
 
197
                        //add user schemas
 
198
                        registeredSchemasStore.Clear ();
 
199
                        foreach (XmlSchemaCompletionData schema in val)
 
200
                                AppendSchemaToStore (schema);
 
201
                        
 
202
                        //add built-in schemas that aren't overriden by a matching user schema
 
203
                        foreach (XmlSchemaCompletionData schema in XmlSchemaManager.BuiltinSchemas)
 
204
                                if (val[schema.NamespaceUri] == null)
 
205
                                        AppendSchemaToStore (schema);
 
206
                }
 
207
                
 
208
                #endregion
 
209
                
 
210
                public bool IsChanged {
 
211
                        get {
 
212
                                if ( addedSchemas.Count > 0 || removedSchemas.Count > 0 || removedExtensions.Count > 0)
 
213
                                        return true;
 
214
                                
 
215
                                foreach (TreeIter iter in WalkStore (defaultAssociationsStore))
 
216
                                        if ((bool)defaultAssociationsStore.GetValue (iter, (int)DACols.Changed))
 
217
                                                return true;
 
218
                                
 
219
                                return false;
 
220
                        }
 
221
                }
 
222
                
 
223
                #region File associations
 
224
                
 
225
                public IEnumerable<XmlSchemaAssociation> GetChangedXmlSchemaAssociations ()
 
226
                {
 
227
                        foreach (TreeIter iter in WalkStore (defaultAssociationsStore)) {
 
228
                                string ext = (string)defaultAssociationsStore.GetValue (iter, (int)DACols.Extension);
 
229
                                if (!string.IsNullOrEmpty (ext) && (bool)defaultAssociationsStore.GetValue (iter, (int)DACols.Changed)) {
 
230
                                        yield return new XmlSchemaAssociation (
 
231
                                                ext,
 
232
                                                ((string)defaultAssociationsStore.GetValue (iter, (int)DACols.Namespace)) ?? string.Empty,
 
233
                                                ((string)defaultAssociationsStore.GetValue (iter, (int)DACols.Prefix)) ?? string.Empty
 
234
                                        );
 
235
                                }
 
236
                        }
 
237
                }
 
238
                
 
239
                public List<string> RemovedExtensions {
 
240
                        get { return removedExtensions; }
 
241
                }
 
242
                
 
243
                public void AddFileExtensions (IEnumerable<XmlSchemaAssociation> assocs)
 
244
                {
 
245
                        foreach (XmlSchemaAssociation a in assocs)
 
246
                                defaultAssociationsStore.AppendValues (a.Extension, a.NamespaceUri, a.NamespacePrefix, false);
 
247
                }
 
248
                
 
249
                void handleExtensionSet (object sender, EditedArgs args)
 
250
                {
 
251
                        //check extension is valid and not a duplicate
 
252
                        string newval = args.NewText == null? null : args.NewText.ToLowerInvariant ().Trim ();
 
253
                        if (string.IsNullOrEmpty (newval))
 
254
                                //FIXME: give an error message?
 
255
                                return;
 
256
                        
 
257
                        foreach (char c in newval)
 
258
                                if (!char.IsLetterOrDigit (c) && c != '.')
 
259
                                        //FIXME: give an error message?
 
260
                                        return;
 
261
                        
 
262
                        foreach (string s in WalkStore (defaultAssociationsStore, (int)DACols.Extension)) {
 
263
                                if (s == newval)
 
264
                                        //FIXME: give an error message?
 
265
                                        return;
 
266
                        }
 
267
                        
 
268
                        setAssocValAndMarkChanged (args.Path, DACols.Extension, newval);
 
269
                }
 
270
                
 
271
                void setAssocValAndMarkChanged (string path, DACols col, object val)
 
272
                {
 
273
                        Gtk.TreeIter iter;
 
274
                        if (defaultAssociationsStore.GetIter (out iter, new TreePath (path))) {
 
275
                                defaultAssociationsStore.SetValue (iter, (int)col, val);
 
276
                                defaultAssociationsStore.SetValue (iter, (int)DACols.Changed, true);
 
277
                        } else {
 
278
                                throw new Exception ("Could not resolve edited path '" + path +"' to TreeIter at " + Environment.StackTrace);
 
279
                        }
 
280
                }
 
281
                
 
282
                protected virtual void addFileAssociation (object sender, System.EventArgs e)
 
283
                {
 
284
                        bool foundExisting = false;
 
285
                        TreeIter newIter = TreeIter.Zero;
 
286
                        foreach (TreeIter iter in WalkStore (defaultAssociationsStore)) {
 
287
                                if (string.IsNullOrEmpty ((string) defaultAssociationsStore.GetValue (iter, (int) DACols.Extension))) {
 
288
                                        foundExisting = true;
 
289
                                        newIter = iter;
 
290
                                }
 
291
                        }
 
292
                        if (!foundExisting)
 
293
                                newIter = defaultAssociationsStore.Append ();
 
294
                        
 
295
                        defaultAssociationsView.SetCursor (
 
296
                            defaultAssociationsStore.GetPath (newIter),
 
297
                            defaultAssociationsView.GetColumn ((int) DACols.Extension),
 
298
                            true);
 
299
                }
 
300
 
 
301
                protected virtual void removeFileAssocation (object sender, System.EventArgs e)
 
302
                {
 
303
                        TreeIter iter;
 
304
                        if (!defaultAssociationsView.Selection.GetSelected (out iter))
 
305
                                throw new InvalidOperationException
 
306
                                        ("Should not be able to activate removeFileAssocation button while no row is selected.");
 
307
                        
 
308
                        string ext = (string) defaultAssociationsStore.GetValue (iter, (int)DACols.Extension);
 
309
                        if (ext != null && ext.Trim ().Length > 0)
 
310
                                removedExtensions.Add (ext.Trim ());
 
311
                        defaultAssociationsStore.Remove (ref iter);
 
312
                }
 
313
                
 
314
                #endregion
 
315
                
 
316
                #region Adding/removing schemas
 
317
                                
 
318
                TreeIter AppendSchemaToStore (XmlSchemaCompletionData schema)
 
319
                {
 
320
                        return registeredSchemasStore.AppendValues (schema);
 
321
                }
 
322
                
 
323
                TreeIter AddRegisteredSchema (XmlSchemaCompletionData schema)
 
324
                {
 
325
                        if (removedSchemas.Contains (schema))
 
326
                                removedSchemas.Remove (schema);
 
327
                        else
 
328
                                addedSchemas.Add (schema);
 
329
                        
 
330
                        return AppendSchemaToStore (schema);
 
331
                }
 
332
                
 
333
                void RemoveRegisteredSchema (XmlSchemaCompletionData schema)
 
334
                {
 
335
                        if (addedSchemas.Contains (schema) && !schema.ReadOnly)
 
336
                                addedSchemas.Remove (schema);
 
337
                        else
 
338
                                removedSchemas.Add (schema);
 
339
                        
 
340
                        TreeIter iter;
 
341
                        bool valid = registeredSchemasStore.GetIterFirst (out iter);
 
342
                        while (valid) {
 
343
                                if (GetRegisteredSchema (iter) == schema) {
 
344
                                        registeredSchemasStore.Remove (ref iter);
 
345
                                        break;
 
346
                                }
 
347
                                valid = registeredSchemasStore.IterNext (ref iter);
 
348
                        }
 
349
                        
 
350
                        //restore built-in schema
 
351
                        if (!schema.ReadOnly) {
 
352
                                XmlSchemaCompletionData builtin = XmlSchemaManager.BuiltinSchemas[schema.NamespaceUri];
 
353
                                if (builtin != null)
 
354
                                        AppendSchemaToStore (builtin);
 
355
                        }
 
356
                }
 
357
                
 
358
                protected virtual void removeRegisteredSchema (object sender, System.EventArgs e)
 
359
                {
 
360
                        XmlSchemaCompletionData schema = GetSelectedSchema ();
 
361
                        if (schema == null)
 
362
                                throw new InvalidOperationException ("Should not be able to activate removeRegisteredSchema button while no row is selected.");
 
363
                        
 
364
                        RemoveRegisteredSchema (schema);
 
365
                }
 
366
 
 
367
                protected virtual void addRegisteredSchema (object sender, System.EventArgs args)
 
368
                {
 
369
                        string fileName = XmlEditorService.BrowseForSchemaFile ();
 
370
                        if (string.IsNullOrEmpty (fileName))
 
371
                                return;
 
372
                        
 
373
                        string shortName = System.IO.Path.GetFileName (fileName);
 
374
                        
 
375
                        //load the schema
 
376
                        XmlSchemaCompletionData schema = null;
 
377
                        try {
 
378
                                schema = new XmlSchemaCompletionData (fileName);
 
379
                        } catch (Exception ex) {
 
380
                                string msg = GettextCatalog.GetString ("Error loading schema '{0}'.", shortName);
 
381
                                MessageService.ShowException (ex, msg);
 
382
                                return;
 
383
                        }
 
384
                        
 
385
                        // Make sure the schema has a target namespace.
 
386
                        if (schema.NamespaceUri == null) {
 
387
                                MessageService.ShowError (
 
388
                                    GettextCatalog.GetString ("Schema '{0}' has no target namespace.", shortName));
 
389
                                return;
 
390
                        }
 
391
                        
 
392
                        //if namaspace conflict, ask user whether they want to replace existing schema
 
393
                        XmlSchemaCompletionData oldSchema = GetRegisteredSchema (schema.NamespaceUri);
 
394
                        if (oldSchema != null) {
 
395
                                bool replace = MessageService.Confirm (
 
396
                                    GettextCatalog.GetString (
 
397
                                        "A schema is already registered with the namespace '{0}'. Would you like to replace it?",
 
398
                                        schema.NamespaceUri),
 
399
                                    new AlertButton (GettextCatalog.GetString ("Replace"))
 
400
                                );
 
401
                                if (!replace)
 
402
                                        return;
 
403
                                
 
404
                                //remove the old schema
 
405
                                RemoveRegisteredSchema (oldSchema);
 
406
                        }
 
407
                        
 
408
                        // Store the schema so we can add it for real later, if the "ok" button's clicked
 
409
                        TreeIter newIter = AddRegisteredSchema (schema);
 
410
                        registeredSchemasView.Selection.SelectIter (newIter);
 
411
                        ScrollToSelection (registeredSchemasView);
 
412
                }
 
413
                
 
414
                
 
415
                /// <summary>
 
416
                /// Scrolls the list so the specified item is visible.
 
417
                /// </summary>
 
418
                void ScrollToSelection (TreeView view)
 
419
                {
 
420
                        TreeIter iter;
 
421
                        TreeModel model;
 
422
                        if (!registeredSchemasView.Selection.GetSelected (out model, out iter))
 
423
                                return;
 
424
                        view.ScrollToCell (model.GetPath (iter), null, false, 0, 0);
 
425
                }
 
426
                
 
427
                #endregion
 
428
                
 
429
                enum DACols {
 
430
                        Extension,
 
431
                        Namespace,
 
432
                        Prefix,
 
433
                        Changed
 
434
                }
 
435
        }
 
436
}