2
// XmlSchemasPanelWidget.cs
5
// Michael Hutchinson <mhutchinson@novell.com>
8
// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
9
// Copyright (C) 2005-2007 Matthew Ward
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:
19
// The above copyright notice and this permission notice shall be
20
// included in all copies or substantial portions of the Software.
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.
31
using MonoDevelop.XmlEditor;
32
using MonoDevelop.XmlEditor.Completion;
33
using MonoDevelop.Core;
34
using MonoDevelop.Core.Gui;
37
using System.Collections.Generic;
40
namespace MonoDevelop.XmlEditor.Gui
44
public partial class XmlSchemasPanelWidget : Gtk.Bin
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> ();
53
public XmlSchemasPanelWidget()
57
//set up tree view for default schemas
58
CellRendererText textRenderer = new CellRendererText ();
59
registeredSchemasStore = new ListStore (typeof (XmlSchemaCompletionData));
60
registeredSchemasView.Model = registeredSchemasStore;
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;
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");
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
82
registeredSchemasStore.SetSortColumnId (0, SortType.Ascending);
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);
89
registeredSchemasRemoveButton.Sensitive = false;
91
//set up cells for associations
92
CellRendererText extensionTextRenderer = new CellRendererText ();
93
extensionTextRenderer.Editable = true;
94
CellRendererText prefixTextRenderer = new CellRendererText ();
95
prefixTextRenderer.Editable = true;
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;
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
114
registeredSchemasComboModel.SetSortColumnId (0, Gtk.SortType.Ascending);
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);
126
extensionTextRenderer.Edited += handleExtensionSet;
127
comboEditor.Edited += delegate (object sender, EditedArgs args) {
128
setAssocValAndMarkChanged (args.Path, DACols.Namespace, args.NewText);
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?
135
setAssocValAndMarkChanged (args.Path, DACols.Prefix, args.NewText);
138
//update state of "remove" button depending on whether anything's slected
139
defaultAssociationsView.Selection.Changed += delegate {
141
defaultAssociationsRemoveButton.Sensitive =
142
defaultAssociationsView.Selection.GetSelected (out iter);
144
defaultAssociationsRemoveButton.Sensitive = false;
147
IEnumerable<object> WalkStore (TreeModel model, int column)
149
foreach (TreeIter iter in WalkStore (model))
150
yield return model.GetValue (iter, column);
153
IEnumerable<TreeIter> WalkStore (TreeModel model)
156
bool valid = model.GetIterFirst (out iter);
159
valid = model.IterNext (ref iter);
163
#region Schema accessors
165
public List<XmlSchemaCompletionData> AddedSchemas {
166
get { return addedSchemas; }
169
public List<XmlSchemaCompletionData> RemovedSchemas {
170
get { return removedSchemas; }
173
XmlSchemaCompletionData GetSelectedSchema ()
176
if (registeredSchemasView.Selection.GetSelected (out iter))
177
return (XmlSchemaCompletionData) registeredSchemasStore.GetValue (iter, 0);
181
// Checks that the schema namespace does not already exist.
182
XmlSchemaCompletionData GetRegisteredSchema (string namespaceUri)
184
foreach (XmlSchemaCompletionData schema in WalkStore (registeredSchemasStore, 0))
185
if (schema.NamespaceUri == namespaceUri)
190
XmlSchemaCompletionData GetRegisteredSchema (TreeIter iter)
192
return (XmlSchemaCompletionData) registeredSchemasStore.GetValue (iter, 0);
195
public void LoadUserSchemas (XmlSchemaCompletionDataCollection val)
198
registeredSchemasStore.Clear ();
199
foreach (XmlSchemaCompletionData schema in val)
200
AppendSchemaToStore (schema);
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);
210
public bool IsChanged {
212
if ( addedSchemas.Count > 0 || removedSchemas.Count > 0 || removedExtensions.Count > 0)
215
foreach (TreeIter iter in WalkStore (defaultAssociationsStore))
216
if ((bool)defaultAssociationsStore.GetValue (iter, (int)DACols.Changed))
223
#region File associations
225
public IEnumerable<XmlSchemaAssociation> GetChangedXmlSchemaAssociations ()
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 (
232
((string)defaultAssociationsStore.GetValue (iter, (int)DACols.Namespace)) ?? string.Empty,
233
((string)defaultAssociationsStore.GetValue (iter, (int)DACols.Prefix)) ?? string.Empty
239
public List<string> RemovedExtensions {
240
get { return removedExtensions; }
243
public void AddFileExtensions (IEnumerable<XmlSchemaAssociation> assocs)
245
foreach (XmlSchemaAssociation a in assocs)
246
defaultAssociationsStore.AppendValues (a.Extension, a.NamespaceUri, a.NamespacePrefix, false);
249
void handleExtensionSet (object sender, EditedArgs args)
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?
257
foreach (char c in newval)
258
if (!char.IsLetterOrDigit (c) && c != '.')
259
//FIXME: give an error message?
262
foreach (string s in WalkStore (defaultAssociationsStore, (int)DACols.Extension)) {
264
//FIXME: give an error message?
268
setAssocValAndMarkChanged (args.Path, DACols.Extension, newval);
271
void setAssocValAndMarkChanged (string path, DACols col, object val)
274
if (defaultAssociationsStore.GetIter (out iter, new TreePath (path))) {
275
defaultAssociationsStore.SetValue (iter, (int)col, val);
276
defaultAssociationsStore.SetValue (iter, (int)DACols.Changed, true);
278
throw new Exception ("Could not resolve edited path '" + path +"' to TreeIter at " + Environment.StackTrace);
282
protected virtual void addFileAssociation (object sender, System.EventArgs e)
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;
293
newIter = defaultAssociationsStore.Append ();
295
defaultAssociationsView.SetCursor (
296
defaultAssociationsStore.GetPath (newIter),
297
defaultAssociationsView.GetColumn ((int) DACols.Extension),
301
protected virtual void removeFileAssocation (object sender, System.EventArgs e)
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.");
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);
316
#region Adding/removing schemas
318
TreeIter AppendSchemaToStore (XmlSchemaCompletionData schema)
320
return registeredSchemasStore.AppendValues (schema);
323
TreeIter AddRegisteredSchema (XmlSchemaCompletionData schema)
325
if (removedSchemas.Contains (schema))
326
removedSchemas.Remove (schema);
328
addedSchemas.Add (schema);
330
return AppendSchemaToStore (schema);
333
void RemoveRegisteredSchema (XmlSchemaCompletionData schema)
335
if (addedSchemas.Contains (schema) && !schema.ReadOnly)
336
addedSchemas.Remove (schema);
338
removedSchemas.Add (schema);
341
bool valid = registeredSchemasStore.GetIterFirst (out iter);
343
if (GetRegisteredSchema (iter) == schema) {
344
registeredSchemasStore.Remove (ref iter);
347
valid = registeredSchemasStore.IterNext (ref iter);
350
//restore built-in schema
351
if (!schema.ReadOnly) {
352
XmlSchemaCompletionData builtin = XmlSchemaManager.BuiltinSchemas[schema.NamespaceUri];
354
AppendSchemaToStore (builtin);
358
protected virtual void removeRegisteredSchema (object sender, System.EventArgs e)
360
XmlSchemaCompletionData schema = GetSelectedSchema ();
362
throw new InvalidOperationException ("Should not be able to activate removeRegisteredSchema button while no row is selected.");
364
RemoveRegisteredSchema (schema);
367
protected virtual void addRegisteredSchema (object sender, System.EventArgs args)
369
string fileName = XmlEditorService.BrowseForSchemaFile ();
370
if (string.IsNullOrEmpty (fileName))
373
string shortName = System.IO.Path.GetFileName (fileName);
376
XmlSchemaCompletionData schema = null;
378
schema = new XmlSchemaCompletionData (fileName);
379
} catch (Exception ex) {
380
string msg = GettextCatalog.GetString ("Error loading schema '{0}'.", shortName);
381
MessageService.ShowException (ex, msg);
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));
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"))
404
//remove the old schema
405
RemoveRegisteredSchema (oldSchema);
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);
416
/// Scrolls the list so the specified item is visible.
418
void ScrollToSelection (TreeView view)
422
if (!registeredSchemasView.Selection.GetSelected (out model, out iter))
424
view.ScrollToCell (model.GetPath (iter), null, false, 0, 0);