~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to src/addins/MonoDevelop.XmlEditor/MonoDevelop.XmlEditor.XPath/XPathQueryWidget.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// MonoDevelop XML Editor
 
3
//
 
4
// Copyright (C) 2006-2007 Matthew Ward
 
5
//
 
6
// Permission is hereby granted, free of charge, to any person obtaining
 
7
// a copy of this software and associated documentation files (the
 
8
// "Software"), to deal in the Software without restriction, including
 
9
// without limitation the rights to use, copy, modify, merge, publish,
 
10
// distribute, sublicense, and/or sell copies of the Software, and to
 
11
// permit persons to whom the Software is furnished to do so, subject to
 
12
// the following conditions:
 
13
// 
 
14
// The above copyright notice and this permission notice shall be
 
15
// included in all copies or substantial portions of the Software.
 
16
// 
 
17
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
18
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
19
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
20
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
21
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
22
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
23
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
24
 
 
25
using Glade;
 
26
using Gtk;
 
27
using GtkSourceView;
 
28
using MonoDevelop.Components;
 
29
using MonoDevelop.Core;
 
30
using MonoDevelop.Core.Gui.Components;
 
31
using MonoDevelop.Core.Gui.Dialogs;
 
32
using System;
 
33
using System.Collections;
 
34
using System.Collections.Generic;
 
35
using System.Collections.ObjectModel;
 
36
using System.Collections.Specialized;
 
37
using System.Xml;
 
38
using System.Xml.XPath;
 
39
 
 
40
/*
 
41
 
 
42
namespace MonoDevelop.XmlEditor
 
43
{
 
44
        /// <summary>
 
45
        /// The XPathQueryWidget uses this interface to
 
46
        /// access the currently active XmlEditorViewContent and
 
47
        /// jump to a particular file.
 
48
        /// </summary>
 
49
        public interface IXmlEditorViewContentProvider
 
50
        {
 
51
                XmlEditorViewContent View {get;}
 
52
                
 
53
                void JumpTo(string fileName, int line, int column);
 
54
        }
 
55
        
 
56
        public class XPathQueryWidget : GladeWidgetExtract
 
57
        {               
 
58
                /// <summary>
 
59
                /// The filename that the last query was executed on.
 
60
                /// </summary>
 
61
                string fileName = String.Empty;
 
62
                
 
63
                /// <summary>
 
64
                /// The total number of xpath queries to remember.
 
65
                /// </summary>
 
66
                const int xpathQueryHistoryLimit = 20;
 
67
                int xpathHistoryListCount;
 
68
                
 
69
                /// <summary>
 
70
                /// The number of namespaces we have added to the
 
71
                /// grid.
 
72
                /// </summary>
 
73
                int namespaceCount;
 
74
 
 
75
                enum MoveCaret {
 
76
                        ByJumping = 1,
 
77
                        ByScrolling = 2
 
78
                }
 
79
        
 
80
                [Widget] TreeView resultsTreeView;
 
81
                [Widget] TreeView namespacesTreeView;
 
82
                [Widget] Button queryButton;
 
83
                [Widget] ComboBoxEntry xpathComboBoxEntry;
 
84
                [Widget] Notebook notebook;
 
85
                
 
86
                // Results List: xpath result, line number, XPathNodeMatch or Exception.
 
87
                const int xpathMatchColumnNumber = 0;
 
88
                const int xpathMatchLineColumnNumber = 1;
 
89
                const int xpathNodeMatchColumnNumber = 2;
 
90
                ListStore resultsList = new ListStore(typeof(string), typeof(string), typeof(object));
 
91
                
 
92
                // Namespace list: prefix, namespace.
 
93
                const int prefixColumnNumber = 0;
 
94
                const int namespaceColumnNumber = 1;
 
95
                ListStore namespacesList = new ListStore(typeof(string), typeof(string));
 
96
                
 
97
                // XPath query history: xpath query
 
98
                ListStore xpathHistoryList = new ListStore(typeof(string));
 
99
                
 
100
                IXmlEditorViewContentProvider viewProvider;
 
101
                
 
102
                public XPathQueryWidget(IXmlEditorViewContentProvider viewProvider)
 
103
                        : base ("XmlEditor.glade", "XPathQueryPad")
 
104
                {
 
105
                        this.viewProvider = viewProvider;
 
106
                        InitResultsList();
 
107
                        InitNamespaceList();
 
108
                                        
 
109
                        queryButton.Clicked += QueryButtonClicked;
 
110
 
 
111
                        EntryCompletion completion = new EntryCompletion();
 
112
                        completion.Model = xpathHistoryList;
 
113
                        completion.TextColumn = 0;
 
114
                        
 
115
                        xpathComboBoxEntry.Model = xpathHistoryList;
 
116
                        xpathComboBoxEntry.TextColumn = 0;
 
117
                        xpathComboBoxEntry.Entry.Completion = completion;
 
118
                        xpathComboBoxEntry.Entry.Changed += XPathComboBoxEntryChanged;
 
119
                        xpathComboBoxEntry.Entry.Activated += XPathComboBoxEntryActivated;
 
120
                }
 
121
                                
 
122
                /// <summary>
 
123
                /// Adds a namespace to the namespace list.
 
124
                /// </summary>
 
125
                public void AddNamespace(string prefix, string uri)
 
126
                {
 
127
                        TreeIter iter = namespacesList.Insert(namespaceCount);
 
128
                        namespacesList.SetValue(iter, prefixColumnNumber, prefix);
 
129
                        namespacesList.SetValue(iter, namespaceColumnNumber, uri);
 
130
                        namespaceCount++;
 
131
                }
 
132
                
 
133
                /// <summary>
 
134
                /// Gets the list of namespaces in the namespace list.
 
135
                /// </summary>
 
136
                public ReadOnlyCollection<XmlNamespace> GetNamespaces()
 
137
                {
 
138
                        List<XmlNamespace> namespaces = new List<XmlNamespace>();               
 
139
                        TreeIter iter;
 
140
                        bool addNamespaces = namespacesList.GetIterFirst(out iter);
 
141
                        while (addNamespaces) {
 
142
                                string prefix = GetNamespacePrefix(iter);
 
143
                                string uri = GetNamespaceUri(iter);
 
144
                                if (prefix.Length == 0 && uri.Length == 0) {
 
145
                                        // Ignore.
 
146
                                } else {
 
147
                                        namespaces.Add(new XmlNamespace(prefix, uri));
 
148
                                }
 
149
                                addNamespaces = namespacesList.IterNext(ref iter);
 
150
                        }
 
151
                        return new ReadOnlyCollection<XmlNamespace>(namespaces);
 
152
                }
 
153
                        
 
154
                /// <summary>
 
155
                /// Gets the previously used XPath queries from the combo box drop down list.
 
156
                /// </summary>
 
157
                public string [] GetXPathHistory()
 
158
                {
 
159
                        List<string> xpaths = new List<string>();
 
160
                        TreeIter iter;
 
161
                        bool add = xpathHistoryList.GetIterFirst(out iter);
 
162
                        while (add) {
 
163
                                string xpath = (string)xpathHistoryList.GetValue(iter, 0);
 
164
                                xpaths.Add(xpath);
 
165
                                add = xpathHistoryList.IterNext(ref iter);
 
166
                        }
 
167
                        return xpaths.ToArray();
 
168
                }
 
169
                
 
170
                /// <summary>
 
171
                /// Adds the xpath into the combo box drop down list.
 
172
                /// </summary>
 
173
                public void AddXPath(string xpath)
 
174
                {
 
175
                        xpathHistoryList.AppendValues(xpath);
 
176
                }
 
177
                
 
178
                /// <summary>
 
179
                /// Gets or sets the active xpath query.
 
180
                /// </summary>
 
181
                public string Query {
 
182
                        get {
 
183
                                return xpathComboBoxEntry.Entry.Text;
 
184
                        }
 
185
                        set {
 
186
                                xpathComboBoxEntry.Entry.Text = value;
 
187
                        }
 
188
                }
 
189
                
 
190
                public void UpdateQueryButtonState()
 
191
                {
 
192
                        queryButton.Sensitive = IsXPathQueryEntered && IsXmlEditorViewContentActive;
 
193
                }
 
194
                
 
195
                void InitResultsList()
 
196
                {
 
197
                        resultsTreeView.Model = resultsList;
 
198
                        resultsTreeView.Selection.Mode = SelectionMode.Single;
 
199
                        resultsTreeView.RowActivated += ResultsTreeViewRowActivated;
 
200
                        resultsTreeView.Selection.Changed += ResultsTreeViewSelectionChanged;
 
201
                                
 
202
                        // Match column.
 
203
                        CellRendererText renderer = new CellRendererText();
 
204
                        resultsTreeView.AppendColumn("Match", renderer, "text", xpathMatchColumnNumber);
 
205
 
 
206
                        // Line number column.
 
207
                        renderer = new CellRendererText();
 
208
                        resultsTreeView.AppendColumn("Line", renderer, "text", xpathMatchLineColumnNumber);
 
209
                }
 
210
                
 
211
                void InitNamespaceList()
 
212
                {
 
213
                        namespacesTreeView.Model = namespacesList;
 
214
                        namespacesTreeView.Selection.Mode = SelectionMode.Single;
 
215
                        
 
216
                        // Prefix column.
 
217
                        CellRendererText renderer = new CellRendererText();
 
218
                        renderer.Edited += PrefixEdited;
 
219
                        renderer.Editable = true;
 
220
                        namespacesTreeView.AppendColumn("Prefix", renderer, "text", prefixColumnNumber);
 
221
 
 
222
                        // Namespace column.
 
223
                        renderer = new CellRendererText();
 
224
                        renderer.Edited += NamespaceEdited;
 
225
                        renderer.Editable = true;
 
226
                        namespacesTreeView.AppendColumn("Namespace", renderer, "text", namespaceColumnNumber);
 
227
                
 
228
                        // Add a few blank rows.
 
229
                        for (int i = 0; i < 20; ++i) {
 
230
                                namespacesList.Append();
 
231
                        }
 
232
                }
 
233
                
 
234
                void PrefixEdited(object source, EditedArgs e)
 
235
                {
 
236
                        ListItemEdited(e, namespacesList, prefixColumnNumber);
 
237
                }
 
238
 
 
239
                void NamespaceEdited(object source, EditedArgs e)
 
240
                {       
 
241
                        ListItemEdited(e, namespacesList, namespaceColumnNumber);
 
242
                }
 
243
                
 
244
                /// <summary>
 
245
                /// Updates the list store item's text that has been 
 
246
                /// edited by the user.
 
247
                /// </summary>
 
248
                void ListItemEdited(EditedArgs e, ListStore list, int column)
 
249
                {
 
250
                        TreePath path = new TreePath(e.Path);
 
251
                        TreeIter iter;
 
252
                        if (list.GetIter(out iter, path)) {
 
253
                                list.SetValue(iter, column, e.NewText);
 
254
                        }
 
255
                }
 
256
                
 
257
                void XPathComboBoxEntryChanged(object sender, EventArgs e)
 
258
                {
 
259
                        UpdateQueryButtonState();
 
260
                }
 
261
                                
 
262
                bool IsXPathQueryEntered {
 
263
                        get {
 
264
                                return xpathComboBoxEntry.Entry.Text.Length > 0;
 
265
                        }
 
266
                }
 
267
                
 
268
                bool IsXmlEditorViewContentActive {
 
269
                        get {
 
270
                                return viewProvider.View != null;
 
271
                        }
 
272
                }
 
273
                
 
274
                void QueryButtonClicked(object sender, EventArgs e)
 
275
                {
 
276
                        RunXPathQuery();
 
277
                }
 
278
                
 
279
                void RunXPathQuery()
 
280
                {
 
281
                        XmlEditorViewContent view = viewProvider.View;
 
282
                        if (view == null) {
 
283
                                return;
 
284
                        }
 
285
                        
 
286
                        try {
 
287
                                fileName = view.FileName;
 
 
b'\t\t'
 
288
                                // Clear previous XPath results.
 
289
                                ClearResults();
 
290
                                view.Select(0, 0);
 
291
                                XmlEditorView xmlEditor = view.XmlEditorView;
 
292
                                xmlEditor.RemoveXPathMarkers();
 
293
 
 
294
                                // Run XPath query.
 
295
                                XPathNodeMatch[] nodes = xmlEditor.SelectNodes(Query, GetNamespaces());
 
296
                                if (nodes.Length > 0) {
 
297
                                        AddXPathResults(nodes);
 
298
                                        xmlEditor.AddXPathMarkers(nodes);
 
299
                                } else {
 
300
                                        AddNoXPathResult();
 
301
                                }
 
302
                                AddXPathToHistory();
 
303
                        } catch (XPathException xpathEx) {
 
304
                                AddErrorResult(xpathEx);
 
305
                        } catch (XmlException xmlEx) {
 
306
                                AddErrorResult(xmlEx);
 
307
                        } finally {
 
308
                                notebook.CurrentPage = 0;
 
309
                        }
 
310
                }
 
311
        
 
312
                void ClearResults()
 
313
                {
 
314
                        resultsList.Clear();
 
315
                }
 
316
                
 
317
                void AddXPathResults(XPathNodeMatch[] nodes)
 
318
                {
 
319
                        foreach (XPathNodeMatch node in nodes) {
 
320
                                string line = String.Empty;
 
321
                                if (node.HasLineInfo()) {
 
322
                                        int lineNumber = node.LineNumber + 1;
 
323
                                        line = lineNumber.ToString();
 
324
                                }
 
325
                                resultsList.AppendValues(node.DisplayValue, line, node);
 
326
                        }
 
327
                }
 
328
                
 
329
                void AddNoXPathResult()
 
330
                {
 
331
                        resultsList.AppendValues("XPath query found 0 items.");
 
332
                }
 
333
                
 
334
                void AddErrorResult(XmlException ex)
 
335
                {
 
336
                        resultsList.AppendValues(ex.Message, ex.LineNumber.ToString(), ex);
 
337
                }
 
338
                
 
339
                void AddErrorResult(XPathException ex)
 
340
                {
 
341
                        resultsList.AppendValues(String.Concat("XPath: ", ex.Message), String.Empty, ex);
 
342
                }
 
343
                
 
344
                void ResultsTreeViewRowActivated(object sender, EventArgs e)
 
345
                {
 
346
                        JumpToResultLocation();
 
347
                }
 
 
b'\t\t'
 
348
                /// <summary>
 
349
                /// Switches focus to the location of the XPath query result.
 
350
                /// </summary>
 
351
                void JumpToResultLocation()
 
352
                {
 
353
                        MoveCaretToResultLocation(MoveCaret.ByJumping);
 
354
                }
 
355
                
 
356
                /// <summary>
 
357
                /// Scrolls the text editor so the location of the XPath query results is visible.
 
358
                /// </summary>
 
359
                void ScrollToResultLocation()
 
360
                {
 
361
                        MoveCaretToResultLocation(MoveCaret.ByScrolling);
 
362
                }
 
363
                
 
364
                void MoveCaretToResultLocation(MoveCaret moveCaret)
 
365
                {
 
366
                        TreeIter iter;
 
367
                        if (resultsTreeView.Selection.GetSelected(out iter)) {
 
368
                                object tag = resultsList.GetValue(iter, xpathNodeMatchColumnNumber);
 
369
                                XPathNodeMatch xpathNodeMatch = tag as XPathNodeMatch;
 
370
                                XPathException xpathException = tag as XPathException;
 
371
                                XmlException xmlException = tag as XmlException;
 
372
                                if (xpathNodeMatch != null) {
 
373
                                        MoveCaretToXPathNodeMatch(moveCaret, xpathNodeMatch);
 
374
                                } else if (xmlException != null) {
 
375
                                        MoveCaretToXmlException(moveCaret, xmlException);
 
376
                                } else if (xpathException != null && moveCaret == MoveCaret.ByJumping) {
 
 
b'\t\t\t\t\txpathComboBoxEntry.Entry.HasFocus = true;'
 
377
                                }
 
378
                        }
 
379
                }
 
380
                
 
381
                void MoveCaretToXPathNodeMatch(MoveCaret moveCaret, XPathNodeMatch node)
 
382
                {
 
383
                        if (moveCaret == MoveCaret.ByJumping) {
 
384
                                viewProvider.JumpTo(fileName, node.LineNumber, node.LinePosition);
 
385
                        } else {
 
386
                                ScrollTo(fileName, node.LineNumber, node.LinePosition, node.Value.Length);
 
387
                        }
 
388
                }
 
389
                
 
390
                void MoveCaretToXmlException(MoveCaret moveCaret, XmlException ex)
 
391
                {
 
392
                        int line =  ex.LineNumber - 1;
 
393
                        int column = ex.LinePosition - 1;
 
394
                        if (moveCaret == MoveCaret.ByJumping) {
 
395
                                viewProvider.JumpTo(fileName, line, column);
 
396
                        } else {
 
397
                                ScrollTo(fileName, line, column);
 
398
                        }
 
399
                }
 
400
                
 
401
                void ScrollTo(string fileName, int line, int column, int length)
 
402
                {
 
403
                        XmlEditorViewContent view = viewProvider.View;
 
404
                        if (view != null && IsFileNameMatch(view)) {
 
405
                                view.SetCaretTo(line, column);
 
406
                                SourceBuffer buffer = (SourceBuffer)view.XmlEditorView.Buffer;
 
407
                                if (length > 0 && line < buffer.LineCount) {
 
408
                                        TextIter lineIter = buffer.GetIterAtLine(line);
 
409
                                        int startOffset = lineIter.Offset + column;
 
410
                                        int endOffset = startOffset + length;
 
411
                                        view.Select(startOffset, endOffset);
 
412
                                }
 
413
                        }
 
414
                }
 
415
                
 
416
                /// <summary>
 
417
                /// Tests whether the specified view matches the filename the XPath
 
 
b'\t\t/// results were found in.'
 
418
                /// </summary>
 
419
                bool IsFileNameMatch(XmlEditorViewContent view)
 
420
                {
 
421
                        return fileName == view.FileName;
 
422
                }
 
423
                
 
424
                /// <summary>
 
425
                /// Adds the text in the combo box to the combo box drop down list.
 
426
                /// </summary>
 
427
                void AddXPathToHistory()
 
428
                {
 
429
                        string newXPath = Query;
 
430
                        if (!XPathHistoryListContains(newXPath)) {
 
431
                                TreeIter iter = xpathHistoryList.Prepend();
 
432
                                xpathHistoryList.SetValue(iter, 0, newXPath);
 
433
                                xpathHistoryListCount++;
 
434
                                if (xpathHistoryListCount > xpathQueryHistoryLimit) {   
 
435
                                        iter = GetLastIter(xpathHistoryList);
 
436
                                        xpathHistoryList.Remove(ref iter);
 
437
                                }
 
438
                        }
 
439
                }
 
440
                
 
441
                /// <summary>
 
442
                /// Brute force approach to get last list item.
 
443
                /// </summary>
 
444
                TreeIter GetLastIter(ListStore list)
 
445
                {
 
446
                        TreeIter iter = TreeIter.Zero;
 
447
                        TreeIter lastIter = iter;
 
448
                        bool success = list.GetIterFirst(out iter);
 
449
                        while (success) {
 
450
                                lastIter = iter;
 
451
                                success = list.IterNext(ref iter);
 
452
                        }
 
453
                        return lastIter;
 
454
                }
 
455
                
 
456
                /// <summary>
 
457
                /// Returns true if the xpath already exists.
 
458
                /// </summary>
 
459
                bool XPathHistoryListContains(string xpath)
 
460
                {
 
461
                        TreeIter iter;
 
462
                        bool success = xpathHistoryList.GetIterFirst(out iter);
 
463
                        while (success) {
 
464
                                string existingXPath = (string)xpathHistoryList.GetValue(iter, 0);
 
465
                                if (xpath.Equals(existingXPath, StringComparison.InvariantCultureIgnoreCase)) { 
 
466
                                        return true;
 
467
                                }
 
468
                                success = xpathHistoryList.IterNext(ref iter);
 
469
                        }
 
470
                        return false;
 
471
                }
 
472
                void ResultsTreeViewSelectionChanged(object sender, EventArgs e)
 
473
                {
 
474
                        ScrollToResultLocation();
 
475
                }
 
476
                
 
477
                /// <summary>
 
478
                /// Gets the namespace prefix from the specified
 
479
                /// list store row.
 
480
                /// </summary>
 
481
                string GetNamespacePrefix(TreeIter iter)
 
482
                {
 
483
                        string prefix = (string)namespacesList.GetValue(iter, prefixColumnNumber);
 
484
                        if (prefix != null) {
 
485
                                return prefix;
 
486
                        }
 
487
                        return String.Empty;
 
488
                }
 
489
                
 
490
                /// <summary>
 
491
                /// Gets the namespace uri from the specified
 
492
                /// list store row.
 
493
                /// </summary>
 
494
                string GetNamespaceUri(TreeIter iter)
 
495
                {
 
496
                        string uri = (string)namespacesList.GetValue(iter, namespaceColumnNumber);
 
497
                        if (uri != null) {
 
498
                                return uri;
 
499
                        }
 
500
                        return String.Empty;
 
501
                }
 
502
                
 
503
                void ScrollTo(string fileName, int line, int column)
 
504
                {
 
505
                        ScrollTo(fileName, line, column, 0);
 
506
                }       
 
507
                
 
508
                void XPathComboBoxEntryActivated(object source, EventArgs e)
 
509
                {
 
510
                        RunXPathQuery();
 
511
                }
 
512
        }
 
513
}
 
514
 
 
515
*/
 
 
b'\\ No newline at end of file'