~ubuntu-branches/ubuntu/saucy/monodevelop/saucy-proposed

« back to all changes in this revision

Viewing changes to src/core/MonoDevelop.Core.Gui/MonoDevelop.Core.Gui.Dialogs/OptionsDialog.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2010-09-10 16:54:48 UTC
  • mfrom: (19.1.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20100910165448-0rybfk25zd4o9431
Tags: 2.4+dfsg-2
* debian/patches/inject_Mono.Debugger.Soft_source.patch,
  debian/patches/use_system_Mono.Debugger.Soft.patch,
  debian/control:
  + Build against system Soft Debugger, since we now have a new
    enough Mono to match MonoDevelop's required API

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// OptionsDialog.cs
2
 
//
3
 
// Author:
4
 
//   Lluis Sanchez Gual <lluis@novell.com>
5
 
//
6
 
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
7
 
//
8
 
// Permission is hereby granted, free of charge, to any person obtaining a copy
9
 
// of this software and associated documentation files (the "Software"), to deal
10
 
// in the Software without restriction, including without limitation the rights
11
 
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
 
// copies of the Software, and to permit persons to whom the Software is
13
 
// furnished to do so, subject to the following conditions:
14
 
//
15
 
// The above copyright notice and this permission notice shall be included in
16
 
// all copies or substantial portions of the Software.
17
 
//
18
 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
 
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
 
// THE SOFTWARE.
25
 
//
26
 
//
27
 
 
28
 
using System;
29
 
using System.Collections.Generic;
30
 
using Gtk;
31
 
using Mono.Addins;
32
 
using MonoDevelop.Core.Gui.Codons;
33
 
 
34
 
namespace MonoDevelop.Core.Gui.Dialogs
35
 
{
36
 
        public partial class OptionsDialog : Gtk.Dialog
37
 
        {
38
 
                protected TreeStore store;
39
 
                Dictionary<OptionsDialogSection, SectionPage> pages = new Dictionary<OptionsDialogSection, SectionPage> ();
40
 
                Dictionary<OptionsPanelNode, PanelInstance> panels = new Dictionary<OptionsPanelNode,PanelInstance> ();
41
 
                object mainDataObject;
42
 
                string extensionPath;
43
 
                ExtensionContext extensionContext;
44
 
                HashSet<object> modifiedObjects = new HashSet<object> ();
45
 
                bool removeEmptySections;
46
 
                
47
 
                public object DataObject {
48
 
                        get {
49
 
                                return mainDataObject;
50
 
                        }
51
 
                }
52
 
 
53
 
                public ExtensionContext ExtensionContext {
54
 
                        get {
55
 
                                return extensionContext;
56
 
                        }
57
 
                }
58
 
                
59
 
                public HashSet<object> ModifiedObjects {
60
 
                        get { return modifiedObjects; }
61
 
                }
62
 
                
63
 
                public OptionsDialog (string extensionPath): this (null, null, extensionPath)
64
 
                {
65
 
                }
66
 
                
67
 
                public OptionsDialog (Gtk.Window parentWindow, object dataObject, string extensionPath) : this (parentWindow, dataObject, extensionPath, true)
68
 
                {}
69
 
                
70
 
                public OptionsDialog (Gtk.Window parentWindow, object dataObject, string extensionPath, bool removeEmptySections)
71
 
                {
72
 
                        this.Build();
73
 
                        this.removeEmptySections = removeEmptySections;
74
 
                        extensionContext = AddinManager.CreateExtensionContext ();
75
 
                        
76
 
                        this.mainDataObject = dataObject;
77
 
                        this.extensionPath = extensionPath;
78
 
                        
79
 
                        if (parentWindow != null)
80
 
                                TransientFor = parentWindow;
81
 
                        
82
 
                        store = new TreeStore (typeof(OptionsDialogSection), typeof(string), typeof(string), typeof(bool), typeof(string));
83
 
                        tree.Model = store;
84
 
                        tree.HeadersVisible = false;
85
 
                        
86
 
                        TreeViewColumn col = new TreeViewColumn ();
87
 
                        CellRendererPixbuf crp = new CellRendererPixbuf ();
88
 
                        crp.StockSize = (uint) IconSize.Menu;
89
 
                        col.PackStart (crp, false);
90
 
                        col.AddAttribute (crp, "stock-id", 1);
91
 
                        col.AddAttribute (crp, "visible", 3);
92
 
                        col.AddAttribute (crp, "cell-background", 4);
93
 
                        CellRendererText crt = new CellRendererText ();
94
 
                        col.PackStart (crt, true);
95
 
                        col.AddAttribute (crt, "markup", 2);
96
 
                        col.AddAttribute (crt, "cell-background", 4);
97
 
                        tree.AppendColumn (col);
98
 
                        
99
 
                        tree.Selection.Changed += OnSelectionChanged;
100
 
                        
101
 
                        InitializeContext (extensionContext);
102
 
                        
103
 
                        FillTree ();
104
 
                        ExpandCategories ();
105
 
                        this.DefaultResponse = Gtk.ResponseType.Ok;
106
 
                }
107
 
                
108
 
                protected void ExpandCategories ()
109
 
                {
110
 
                        TreeIter it;
111
 
                        if (store.GetIterFirst (out it)) {
112
 
                                tree.Selection.SelectIter (it);
113
 
                                do {
114
 
                                        tree.ExpandRow (store.GetPath (it), false);
115
 
                                } while (store.IterNext (ref it));
116
 
                        }
117
 
                }
118
 
                
119
 
                public void FillTree ()
120
 
                {
121
 
                        DetachWidgets ();
122
 
                        pages.Clear ();
123
 
                        store.Clear ();
124
 
                        foreach (OptionsDialogSection section in extensionContext.GetExtensionNodes (extensionPath)) {
125
 
                                AddSection (section, mainDataObject);
126
 
                        }
127
 
                }
128
 
                
129
 
                protected virtual void InitializeContext (ExtensionContext extensionContext)
130
 
                {
131
 
                }
132
 
 
133
 
                protected override void OnDestroyed()
134
 
                {
135
 
                        foreach (PanelInstance pi in panels.Values)
136
 
                                if (pi.Widget != null)
137
 
                                        pi.Widget.Destroy ();
138
 
                        base.OnDestroyed ();
139
 
                }
140
 
                
141
 
                public void SelectPanel (string id)
142
 
                {
143
 
                        foreach (OptionsDialogSection section in pages.Keys) {
144
 
                                if (section.Id == id) {
145
 
                                        ShowPage (section);
146
 
                                        return;
147
 
                                }
148
 
                        }
149
 
                }
150
 
                
151
 
                public void AddChildSection (IOptionsPanel parent, OptionsDialogSection section, object dataObject)
152
 
                {
153
 
                        foreach (SectionPage page in pages.Values) {
154
 
                                foreach (PanelInstance pi in page.Panels) {
155
 
                                        if (pi.Panel == parent) {
156
 
                                                AddSection (page.Iter, section, dataObject);
157
 
                                                return;
158
 
                                        }
159
 
                                }
160
 
                        }
161
 
                        throw new InvalidOperationException ("Parent options panel not found in the dialog.");
162
 
                }
163
 
                
164
 
                public void RemoveSection (OptionsDialogSection section)
165
 
                {
166
 
                        SectionPage page;
167
 
                        if (pages.TryGetValue (section, out page))
168
 
                                RemoveSection (page.Iter);
169
 
                }
170
 
                
171
 
                void RemoveSection (Gtk.TreeIter it)
172
 
                {
173
 
                        Gtk.TreeIter ci;
174
 
                        if (store.IterChildren (out ci, it)) {
175
 
                                do {
176
 
                                        RemoveSection (ci);
177
 
                                } while (store.IterNext (ref ci));
178
 
                        }
179
 
                        
180
 
                        // If the this panel is the selection, select the parent before removing
181
 
                        Gtk.TreeIter itsel;
182
 
                        if (tree.Selection.GetSelected (out itsel)) {
183
 
                                if (store.GetPath (itsel).Equals (store.GetPath (it))) {
184
 
                                        Gtk.TreeIter pi;
185
 
                                        if (store.IterParent (out pi, it))
186
 
                                                tree.Selection.SelectIter (pi);
187
 
                                }
188
 
                        }
189
 
                        OptionsDialogSection section = (OptionsDialogSection) store.GetValue (it, 0);
190
 
                        if (section != null) {
191
 
                                SectionPage page;
192
 
                                if (pages.TryGetValue (section, out page)) {
193
 
                                        foreach (PanelInstance pi in page.Panels)
194
 
                                                panels.Remove (pi.Node);
195
 
                                        pages.Remove (section);
196
 
                                        if (page.Widget != null)
197
 
                                                page.Widget.Destroy ();
198
 
                                }
199
 
                        }
200
 
                        store.Remove (ref it);
201
 
                }
202
 
                
203
 
                protected TreeIter AddSection (OptionsDialogSection section, object dataObject)
204
 
                {
205
 
                        return AddSection (TreeIter.Zero, section, dataObject);
206
 
                }
207
 
                
208
 
                protected TreeIter AddSection (TreeIter parentIter, OptionsDialogSection section, object dataObject)
209
 
                {
210
 
                        TreeIter it;
211
 
                        if (parentIter.Equals (TreeIter.Zero)) {
212
 
                                string sectionLabel = "<b>" + GLib.Markup.EscapeText (section.Label) + "</b>";
213
 
                                it = store.AppendValues (section, null, sectionLabel, false, null);
214
 
                        }
215
 
                        else {
216
 
                                string icon = string.IsNullOrEmpty (section.Icon) ? "md-empty-category" : section.Icon;
217
 
                                it = store.AppendValues (parentIter, section, icon, section.Label, true, null);
218
 
                        }
219
 
                        
220
 
                        if (!section.CustomNode)
221
 
                                AddChildSections (it, section, dataObject);
222
 
                        
223
 
                        // Remove the section if it doesn't have children nor panels
224
 
                        SectionPage page = CreatePage (it, section, dataObject);
225
 
                        TreeIter cit;
226
 
                        if (removeEmptySections && page.Panels.Count == 0 && !store.IterChildren (out cit, it))
227
 
                                store.Remove (ref it);
228
 
                        return it;
229
 
                }
230
 
                
231
 
                protected virtual void AddChildSections (TreeIter parentIter, OptionsDialogSection section, object dataObject)
232
 
                {
233
 
                        foreach (ExtensionNode nod in section.ChildNodes) {
234
 
                                if (nod is OptionsDialogSection)
235
 
                                        AddSection (parentIter, (OptionsDialogSection) nod, dataObject);
236
 
                        }
237
 
                }
238
 
                
239
 
                void DetachWidgets ()
240
 
                {
241
 
                        foreach (Gtk.Widget w in pageFrame.Children)
242
 
                                pageFrame.Remove (w);
243
 
 
244
 
                        foreach (SectionPage sp in pages.Values) {
245
 
                                foreach (PanelInstance pi in sp.Panels) {
246
 
                                        if (pi.Widget != null && pi.Widget.Parent != null)
247
 
                                                ((Gtk.Container)pi.Widget.Parent).Remove (pi.Widget);
248
 
                                }
249
 
                                if (sp.Widget != null) {
250
 
                                        sp.Widget.Destroy ();
251
 
                                        sp.Widget = null;
252
 
                                }
253
 
                        }
254
 
                }
255
 
                
256
 
                protected override void OnResponse (ResponseType resp)
257
 
                {
258
 
                        base.OnResponse (resp);
259
 
                        DetachWidgets ();
260
 
                }
261
 
                
262
 
                protected virtual bool ValidateChanges ()
263
 
                {
264
 
                        foreach (SectionPage sp in pages.Values) {
265
 
                                if (sp.Widget == null)
266
 
                                        continue;
267
 
                                foreach (PanelInstance pi in sp.Panels) {
268
 
                                        if (!pi.Panel.ValidateChanges ())
269
 
                                                return false; // Not valid
270
 
                                }
271
 
                        }
272
 
                        return true;
273
 
                }
274
 
                
275
 
                protected virtual void ApplyChanges ()
276
 
                {
277
 
                        foreach (SectionPage sp in pages.Values) {
278
 
                                if (sp.Widget == null)
279
 
                                        continue;
280
 
                                foreach (PanelInstance pi in sp.Panels)
281
 
                                        pi.Panel.ApplyChanges ();
282
 
                        }
283
 
                }
284
 
                
285
 
                
286
 
                void OnSelectionChanged (object s, EventArgs a)
287
 
                {
288
 
                        TreeIter it;
289
 
                        if (tree.Selection.GetSelected (out it)) {
290
 
                                OptionsDialogSection section = (OptionsDialogSection) store.GetValue (it, 0);
291
 
                                ShowPage (section);
292
 
                        }
293
 
                }
294
 
                
295
 
                public void ShowPage (OptionsDialogSection section)
296
 
                {
297
 
                        SectionPage page;
298
 
                        if (!pages.TryGetValue (section, out page))
299
 
                                return;
300
 
                        
301
 
                        if (page.Panels.Count == 0) {
302
 
                                foreach (ExtensionNode node in section.ChildNodes) {
303
 
                                        if (node is OptionsDialogSection) {
304
 
                                                ShowPage ((OptionsDialogSection) node);
305
 
                                                return;
306
 
                                        }
307
 
                                }
308
 
                        }
309
 
                        
310
 
                        foreach (Gtk.Widget w in pageFrame.Children) {
311
 
                                Container cc = w as Gtk.Container;
312
 
                                if (cc != null) {
313
 
                                        foreach (Gtk.Widget cw in cc)
314
 
                                                cw.Hide ();
315
 
                                }
316
 
                                pageFrame.Remove (w);
317
 
                        }
318
 
                        
319
 
                        if (page.Widget == null)
320
 
                                CreatePageWidget (page);
321
 
                        
322
 
                        labelTitle.Markup = "<span weight=\"bold\" size=\"x-large\">" + GLib.Markup.EscapeText (section.Label) + "</span>";
323
 
                        if (!string.IsNullOrEmpty (section.Icon))
324
 
                                image.Stock = section.Icon;
325
 
                        else
326
 
                                image.Stock = "md-empty-category";
327
 
                        pageFrame.PackStart (page.Widget, true, true, 0);
328
 
                        
329
 
                        // Ensures that the Shown event is fired for each panel
330
 
                        Container c = page.Widget as Gtk.Container;
331
 
                        if (c != null) {
332
 
                                foreach (Gtk.Widget cw in c)
333
 
                                        cw.Show ();
334
 
                        }
335
 
                        
336
 
                        tree.ExpandToPath (store.GetPath (page.Iter));
337
 
                        tree.Selection.SelectIter (page.Iter);
338
 
                }
339
 
                
340
 
                SectionPage CreatePage (TreeIter it, OptionsDialogSection section, object dataObject)
341
 
                {
342
 
                        SectionPage page;
343
 
                        if (pages.TryGetValue (section, out page))
344
 
                                return page;
345
 
                        
346
 
                        page = new SectionPage ();
347
 
                        page.Iter = it;
348
 
                        page.Panels = new List<PanelInstance> ();
349
 
                        pages [section] = page;
350
 
                        
351
 
                        List<OptionsPanelNode> nodes = new List<OptionsPanelNode> ();
352
 
                        if (!string.IsNullOrEmpty (section.TypeName) || section.CustomNode)
353
 
                                nodes.Add (section);
354
 
                        
355
 
                        if (!section.CustomNode) {
356
 
                                foreach (ExtensionNode nod in section.ChildNodes) {
357
 
                                        OptionsPanelNode node = nod as OptionsPanelNode;
358
 
                                        if (node != null && !(node is OptionsDialogSection))
359
 
                                                nodes.Add (node);
360
 
                                }
361
 
                        }
362
 
                        
363
 
                        foreach (OptionsPanelNode node in nodes)
364
 
                        {
365
 
                                PanelInstance pi = null;
366
 
                                if (panels.TryGetValue (node, out pi)) {
367
 
                                        if (pi.DataObject == dataObject) {
368
 
                                                // The panel can be reused
369
 
                                                if (!pi.Panel.IsVisible ())
370
 
                                                        continue;
371
 
                                        } else {
372
 
                                                // If the data object has changed, this panel instance can't be
373
 
                                                // reused anymore. Destroy it.
374
 
                                                panels.Remove (node);
375
 
                                                if (pi.Widget != null)
376
 
                                                        pi.Widget.Destroy ();
377
 
                                                pi = null;
378
 
                                        }
379
 
                                }
380
 
                                if (pi == null) {
381
 
                                        IOptionsPanel panel = node.CreatePanel ();
382
 
                                        pi = new PanelInstance ();
383
 
                                        pi.Panel = panel;
384
 
                                        pi.Node = node;
385
 
                                        pi.DataObject = dataObject;
386
 
                                        page.Panels.Add (pi);
387
 
                                        panel.Initialize (this, dataObject);
388
 
                                        if (!panel.IsVisible ()) {
389
 
                                                page.Panels.Remove (pi);
390
 
                                                continue;
391
 
                                        }
392
 
                                        panels [node] = pi;
393
 
                                } else
394
 
                                        page.Panels.Add (pi);
395
 
                        }
396
 
                        return page;
397
 
                }
398
 
                
399
 
                void CreatePageWidget (SectionPage page)
400
 
                {
401
 
                        List<PanelInstance> boxPanels = new List<PanelInstance> ();
402
 
                        List<PanelInstance> tabPanels = new List<PanelInstance> ();
403
 
                        
404
 
                        foreach (PanelInstance pi in page.Panels) {
405
 
                                if (pi.Widget == null) {
406
 
                                        pi.Widget = pi.Panel.CreatePanelWidget ();
407
 
                                        //HACK: work around bug 469427 - broken themes match on widget names
408
 
                                        if (pi.Widget.Name.IndexOf ("Panel") > 0)
409
 
                                                pi.Widget.Name = pi.Widget.Name.Replace ("Panel", "_");
410
 
                                }
411
 
                                else if (pi.Widget.Parent != null)
412
 
                                        ((Gtk.Container) pi.Widget.Parent).Remove (pi.Widget);
413
 
                                        
414
 
                                if (pi.Node.Grouping == PanelGrouping.Tab)
415
 
                                        tabPanels.Add (pi);
416
 
                                else
417
 
                                        boxPanels.Add (pi);
418
 
                        }
419
 
                        
420
 
                        // Try to fit panels with grouping=box or auto in the main page.
421
 
                        // If they don't fit. Move auto panels to its own tab page.
422
 
                        
423
 
                        int mainPageSize;
424
 
                        bool fits;
425
 
                        do {
426
 
                                PanelInstance lastAuto = null;
427
 
                                mainPageSize = 0;
428
 
                                foreach (PanelInstance pi in boxPanels) {
429
 
                                        if (pi.Node.Grouping == PanelGrouping.Auto)
430
 
                                                lastAuto = pi;
431
 
                                        mainPageSize += pi.Widget.SizeRequest ().Height + 6;
432
 
                                }
433
 
                                fits = mainPageSize <= pageFrame.Allocation.Height;
434
 
                                if (!fits) {
435
 
                                        if (lastAuto != null && boxPanels.Count > 1) {
436
 
                                                boxPanels.Remove (lastAuto);
437
 
                                                tabPanels.Insert (0, lastAuto);
438
 
                                        } else {
439
 
                                                fits = true;
440
 
                                        }
441
 
                                }
442
 
                        } while (!fits);
443
 
                        
444
 
                        Gtk.VBox box = new VBox (false, 12);
445
 
                        box.Show ();
446
 
                        for (int n=0; n<boxPanels.Count; n++) {
447
 
                                if (n != 0) {
448
 
                                        HSeparator sep = new HSeparator ();
449
 
                                        sep.Show ();
450
 
                                        box.PackStart (sep, false, false, 0);
451
 
                                }
452
 
                                PanelInstance pi = boxPanels [n];
453
 
                                box.PackStart (pi.Widget, pi.Node.Fill, pi.Node.Fill, 0);
454
 
                                pi.Widget.Show ();
455
 
                        }
456
 
                        
457
 
                        if (tabPanels.Count > 0) {
458
 
                                Gtk.Notebook nb = new Notebook ();
459
 
                                nb.Show ();
460
 
                                Gtk.Label blab = new Gtk.Label (GettextCatalog.GetString ("General"));
461
 
                                blab.Show ();
462
 
                                box.BorderWidth = 9;
463
 
                                nb.InsertPage (box, blab, -1);
464
 
                                foreach (PanelInstance pi in tabPanels) {
465
 
                                        Gtk.Label lab = new Gtk.Label (GettextCatalog.GetString (pi.Node.Label));
466
 
                                        lab.Show ();
467
 
                                        Gtk.Alignment a = new Alignment (0, 0, 1, 1);
468
 
                                        a.BorderWidth = 9;
469
 
                                        a.Show ();
470
 
                                        a.Add (pi.Widget);
471
 
                                        nb.InsertPage (a, lab, -1);
472
 
                                        pi.Widget.Show ();
473
 
                                }
474
 
                                page.Widget = nb;
475
 
                        } else {
476
 
                                page.Widget = box;
477
 
                        }
478
 
                }
479
 
 
480
 
                protected virtual void OnButtonOkClicked (object sender, System.EventArgs e)
481
 
                {
482
 
                        // Validate changes before saving
483
 
                        if (!ValidateChanges ())
484
 
                                return;
485
 
                        
486
 
                        // Now save
487
 
                        ApplyChanges ();
488
 
                        
489
 
                        if (DataObject != null)
490
 
                                modifiedObjects.Add (DataObject);
491
 
                        
492
 
                        this.Respond (ResponseType.Ok);
493
 
                }
494
 
                
495
 
                class PanelInstance
496
 
                {
497
 
                        public IOptionsPanel Panel;
498
 
                        public Gtk.Widget Widget;
499
 
                        public OptionsPanelNode Node;
500
 
                        public object DataObject;
501
 
                }
502
 
                
503
 
                class SectionPage
504
 
                {
505
 
                        public List<PanelInstance> Panels;
506
 
                        public Gtk.Widget Widget;
507
 
                        public Gtk.TreeIter Iter;
508
 
                }
509
 
        }
510
 
}