~ubuntu-branches/ubuntu/raring/monodevelop/raring

« back to all changes in this revision

Viewing changes to src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DocumentSwitcher.cs

  • Committer: Bazaar Package Importer
  • Author(s): Andrew Mitchell
  • Date: 2011-06-29 06:56:25 UTC
  • mfrom: (1.8.1 upstream) (1.3.11 experimental)
  • Revision ID: james.westby@ubuntu.com-20110629065625-7xx19c4vb95j65pl
Tags: 2.5.92+dfsg-1ubuntu1
* Merge from Debian experimental:
 - Dropped patches & changes to debian/control for Moonlight
   + debian/patches/remove_support_for_moonlight.patch,
   + debian/patches/dont_add_moonlight_to_core_addins.patch,
 - Remaining patches:
   + debian/patches/no_appmenu:

Show diffs side-by-side

added added

removed removed

Lines of Context:
34
34
using MonoDevelop.Ide.Gui;
35
35
using MonoDevelop.Components.Commands;
36
36
using MonoDevelop.Ide.Commands;
37
 
 
 
37
using MonoDevelop.Core;
 
38
using Mono.TextEditor;
38
39
 
39
40
namespace MonoDevelop.Ide
40
41
{
41
 
        
42
 
        internal partial class DocumentSwitcher : Gtk.Window
43
 
        {
44
 
                Gtk.ListStore padListStore;
45
 
                Gtk.ListStore documentListStore;
46
 
                Gtk.TreeView  treeviewPads, treeviewDocuments;
47
 
                List<Document> documents;
48
 
                
49
 
                class MyTreeView : Gtk.TreeView
50
 
                {
51
 
                        protected override bool OnKeyPressEvent (Gdk.EventKey evnt)
52
 
                        {
53
 
                                return false;
54
 
                        }
55
 
                        protected override bool OnKeyReleaseEvent (Gdk.EventKey evnt)
56
 
                        {
57
 
                                return false;
58
 
                        }
59
 
                }
60
 
                
61
 
                void ShowSelectedPad ()
62
 
                {
63
 
                        Gtk.TreeIter iter;
64
 
                        if (treeviewPads.Selection.GetSelected (out iter)) {
65
 
                                MonoDevelop.Ide.Gui.Pad pad = padListStore.GetValue (iter, 2) as MonoDevelop.Ide.Gui.Pad;
66
 
                                ShowType (ImageService.GetPixbuf (!pad.Icon.IsNull ? pad.Icon : MonoDevelop.Ide.Gui.Stock.MiscFiles, Gtk.IconSize.Dialog),
67
 
                                          pad.Title,
68
 
                                          "",
69
 
                                          "");
70
 
                        }
71
 
                }
72
 
                
73
 
                Pixbuf GetIconForDocument (MonoDevelop.Ide.Gui.Document document, Gtk.IconSize iconSize)
74
 
                {
75
 
                        if (!string.IsNullOrEmpty (document.Window.ViewContent.StockIconId))
76
 
                                return ImageService.GetPixbuf (document.Window.ViewContent.StockIconId, iconSize);
77
 
                        if (string.IsNullOrEmpty (document.FileName)) 
78
 
                                return ImageService.GetPixbuf (MonoDevelop.Ide.Gui.Stock.MiscFiles, iconSize);
79
 
                        
80
 
                        return DesktopService.GetPixbufForFile (document.FileName, iconSize);
81
 
                }
82
 
                
83
 
                void ShowSelectedDocument ()
84
 
                {
85
 
                        MonoDevelop.Ide.Gui.Document document = SelectedDocument;
86
 
                        if (document != null) {
87
 
                                ShowType (GetIconForDocument (document, IconSize.Dialog),
88
 
                                          System.IO.Path.GetFileName (document.Name),
89
 
                                          document.Window.DocumentType,
90
 
                                          document.FileName);
91
 
                        }
92
 
                }
93
 
                
94
 
                public DocumentSwitcher (Gtk.Window parent, bool startWithNext) : base(Gtk.WindowType.Popup)
95
 
                {
96
 
                        this.documents = new List<Document> (IdeApp.Workbench.Documents.OrderByDescending (d => d.LastTimeActive));
97
 
                        this.TransientFor = parent;
 
42
        class DocumentList : Gtk.DrawingArea
 
43
        { 
 
44
                List<Category> categories = new List<Category> ();
 
45
                int maxLength = 15;
 
46
                const int maxItems = 20;
 
47
                const int padding = 6;
 
48
                const int headerDistance = 4;
 
49
                const int maxRows = 2;
 
50
                
 
51
                Item activeItem;
 
52
                public Item ActiveItem {
 
53
                        get { return activeItem; }
 
54
                        set {
 
55
                                activeItem = value;
 
56
                                OnActiveItemChanged (EventArgs.Empty);
 
57
                                QueueDraw ();
 
58
                        }
 
59
                }
 
60
                
 
61
                Item hoverItem;
 
62
 
 
63
                protected virtual void OnActiveItemChanged (EventArgs e)
 
64
                {
 
65
                        EventHandler handler = this.ActiveItemChanged;
 
66
                        if (handler != null)
 
67
                                handler (this, e);
 
68
                }
 
69
 
 
70
                public event EventHandler ActiveItemChanged;
 
71
                
 
72
                public DocumentList ()
 
73
                {
98
74
                        this.CanFocus = true;
99
 
                        this.Decorated = false;
100
 
                        this.DestroyWithParent = true;
101
 
                        //the following are specified using stetic, but documenting them here too
102
 
                        //this.Modal = true;
103
 
                        //this.WindowPosition = Gtk.WindowPosition.CenterOnParent;
104
 
                        //this.TypeHint = WindowTypeHint.Menu;
105
 
                        
106
 
                        this.Build ();
107
 
                        
108
 
                        treeviewPads = new MyTreeView ();
109
 
                        scrolledwindow1.Child = treeviewPads;
110
 
                        
111
 
                        treeviewDocuments = new MyTreeView ();
112
 
                        scrolledwindow2.Child = treeviewDocuments;
113
 
                        
114
 
                        padListStore = new Gtk.ListStore (typeof (Gdk.Pixbuf), typeof (string), typeof (Pad));
115
 
                        treeviewPads.Model = padListStore;
116
 
                        treeviewPads.AppendColumn ("icon", new Gtk.CellRendererPixbuf (), "pixbuf", 0);
117
 
                        treeviewPads.AppendColumn ("text", new Gtk.CellRendererText (), "text", 1);
118
 
                        treeviewPads.HeadersVisible = false;
119
 
                        
120
 
                        treeviewPads.Selection.Changed += TreeviewPadsSelectionChanged;
121
 
                        documentListStore = new Gtk.ListStore (typeof (Gdk.Pixbuf), typeof (string), typeof (Document));
122
 
                        treeviewDocuments.Model = documentListStore;
123
 
                        treeviewDocuments.AppendColumn ("icon", new Gtk.CellRendererPixbuf (), "pixbuf", 0);
124
 
                        treeviewDocuments.AppendColumn ("text", new Gtk.CellRendererText (), "text", 1);
125
 
                        treeviewDocuments.HeadersVisible = false;
126
 
                        treeviewDocuments.Selection.Changed += TreeviewDocumentsSelectionChanged;
127
 
                        
128
 
                        FillLists ();
129
 
                        this.labelFileName.Ellipsize = Pango.EllipsizeMode.Start;
130
 
                        if (IdeApp.Workbench.ActiveDocument != null) {
131
 
                                SwitchToDocument ();
132
 
                                SelectDocument (startWithNext ? GetNextDocument (IdeApp.Workbench.ActiveDocument) : GetPrevDocument (IdeApp.Workbench.ActiveDocument));
133
 
                        } else {
134
 
                                SwitchToPad ();
135
 
                        }
136
 
                }
137
 
 
138
 
                void TreeviewPadsSelectionChanged (object sender, EventArgs e)
139
 
                {
140
 
                        ShowSelectedPad ();
141
 
                }
142
 
 
143
 
                void TreeviewDocumentsSelectionChanged (object sender, EventArgs e)
144
 
                {
145
 
                        ShowSelectedDocument ();
146
 
                }
147
 
                
148
 
                bool documentFocus = true;
149
 
                Gtk.TreeIter selectedPadIter, selectedDocumentIter;
150
 
                
151
 
                void SwitchToDocument ()
152
 
                {
153
 
                        this.treeviewPads.Selection.GetSelected (out selectedPadIter);
154
 
                        this.treeviewPads.Selection.UnselectAll ();
155
 
                        if (documentListStore.IterIsValid (selectedDocumentIter))
156
 
                                this.treeviewDocuments.Selection.SelectIter (selectedDocumentIter);
157
 
                        else
158
 
                                this.treeviewDocuments.Selection.SelectPath (new TreePath ("0"));
159
 
                        
160
 
//                      this.treeviewPads.Sensitive = false;
161
 
//                      this.treeviewDocuments.Sensitive = true;
162
 
                        documentFocus = true;
163
 
                        treeviewDocuments.GrabFocus ();
164
 
                        ShowSelectedDocument ();
165
 
                }
166
 
                
167
 
                void SwitchToPad ()
168
 
                {
169
 
                        this.treeviewDocuments.Selection.GetSelected (out selectedDocumentIter);
170
 
                        this.treeviewDocuments.Selection.UnselectAll ();
171
 
                        if (padListStore.IterIsValid (selectedPadIter))
172
 
                                this.treeviewPads.Selection.SelectIter (selectedPadIter);
173
 
                        else
174
 
                                this.treeviewPads.Selection.SelectPath (new TreePath ("0"));
175
 
                        
176
 
//                      this.treeviewPads.Sensitive = true;
177
 
//                      this.treeviewDocuments.Sensitive = false;
178
 
                        documentFocus = false;
179
 
                        treeviewPads.GrabFocus ();
180
 
                        ShowSelectedPad ();
181
 
                }
182
 
                
183
 
                Document GetNextDocument (Document doc)
184
 
                {
185
 
                        if (documents.Count == 0)
186
 
                                return null;
187
 
                        int index = documents.IndexOf (doc);
188
 
                        return documents [(index + 1) % documents.Count];
189
 
                }
190
 
                
191
 
                Document GetPrevDocument (Document doc)
192
 
                {
193
 
                        if (documents.Count == 0)
194
 
                                return null;
195
 
                        int index = documents.IndexOf (doc);
196
 
                        return documents [(index + documents.Count - 1) % documents.Count];
197
 
                }
198
 
                
199
 
                Document SelectedDocument {
200
 
                        get {
201
 
                                if (!documentFocus)
202
 
                                        return null;
203
 
                                TreeIter iter;
204
 
                                if (treeviewDocuments.Selection.GetSelected (out iter)) {
205
 
                                        return documentListStore.GetValue (iter, 2) as Document;
206
 
                                }
207
 
                                return null;
208
 
                        }
209
 
                }
210
 
                
211
 
                Pad GetNextPad (Pad pad)
212
 
                {
213
 
                        if (this.padListStore.NColumns == 0)
214
 
                                return null;
215
 
                        int index = IdeApp.Workbench.Pads.IndexOf (pad);
216
 
                        Pad result = IdeApp.Workbench.Pads [(index + 1) % IdeApp.Workbench.Pads.Count];
217
 
                        if (!result.Visible)
218
 
                                return GetNextPad (result);
219
 
                        return result;
220
 
                }
221
 
                                
222
 
                Pad GetPrevPad (Pad pad)
223
 
                {
224
 
                        if (this.padListStore.NColumns == 0)
225
 
                                return null;
226
 
                        int index = IdeApp.Workbench.Pads.IndexOf (pad);
227
 
                        Pad result = IdeApp.Workbench.Pads [(index + IdeApp.Workbench.Pads.Count - 1) % IdeApp.Workbench.Pads.Count];
228
 
                        if (!result.Visible)
229
 
                                return GetPrevPad (result);
230
 
                        return result;
231
 
                }
232
 
                
233
 
                Pad SelectedPad {
234
 
                        get {
235
 
                                if (documentFocus)
236
 
                                        return null;
237
 
                                TreeIter iter;
238
 
                                if (this.treeviewPads.Selection.GetSelected (out iter)) {
239
 
                                        return padListStore.GetValue (iter, 2) as Pad;
240
 
                                }
241
 
                                return null;
242
 
                        }
243
 
                }
244
 
                
245
 
                void SelectDocument (Document doc)
246
 
                {
247
 
                        Gtk.TreeIter iter;
248
 
                        if (documentListStore.GetIterFirst (out iter)) {
249
 
                                do {
250
 
                                        Document curDocument = documentListStore.GetValue (iter, 2) as Document;
251
 
                                        if (doc == curDocument) {
252
 
                                                treeviewDocuments.Selection.SelectIter (iter);
253
 
                                                return;
254
 
                                        }
255
 
                                } while (documentListStore.IterNext (ref iter));
256
 
                        }
257
 
                }
258
 
                
259
 
                void SelectPad (Pad pad)
260
 
                {
261
 
                        Gtk.TreeIter iter;
262
 
                        if (padListStore.GetIterFirst (out iter)) {
263
 
                                do {
264
 
                                        Pad curPad = padListStore.GetValue (iter, 2) as Pad;
265
 
                                        if (pad == curPad) {
266
 
                                                treeviewPads.Selection.SelectIter (iter);
267
 
                                                return;
268
 
                                        }
269
 
                                } while (padListStore.IterNext (ref iter));
270
 
                        }
271
 
                }
272
 
                
273
 
                void ShowType (Gdk.Pixbuf image, string title, string type, string fileName)
274
 
                {
275
 
//                      this.imageType.Pixbuf  = image;
276
 
                        this.labelTitle.Markup = "<span size=\"xx-large\" weight=\"bold\">" +title + "</span>";
277
 
                        this.labelType.Markup =  "<span size=\"small\">" +type + " </span>";
278
 
                        this.labelFileName.Text = fileName;
279
 
                }
280
 
                
281
 
                void FillLists ()
282
 
                {
283
 
                        foreach (Pad pad in IdeApp.Workbench.Pads) {
284
 
                                if (!pad.Visible)
285
 
                                        continue;
286
 
                                padListStore.AppendValues (ImageService.GetPixbuf (!String.IsNullOrEmpty (pad.Icon) ? pad.Icon : MonoDevelop.Ide.Gui.Stock.MiscFiles, IconSize.Menu),
287
 
                                                           pad.Title,
288
 
                                                           pad);
289
 
                        }
290
 
                        
291
 
                        foreach (Document doc in documents) {
292
 
                                documentListStore.AppendValues (GetIconForDocument (doc, IconSize.Menu),
293
 
                                                                doc.Window.Title,
294
 
                                                                doc);
295
 
                        }
296
 
                }
297
 
                
298
 
                //FIXME: get ctrl(-shift)-tab keybindings from the Switch(Next|Previous)Document commands?
299
 
                protected override bool OnKeyPressEvent (Gdk.EventKey evnt)
 
75
                        Events |= EventMask.KeyPressMask | EventMask.KeyReleaseMask | EventMask.PointerMotionMask | EventMask.ButtonPressMask | EventMask.LeaveNotifyMask;
 
76
                }
 
77
                
 
78
                public void AddCategory (Category category)
 
79
                {
 
80
                        categories.Add (category);
 
81
                }
 
82
                
 
83
                Item GetItemAt (double x, double y)
 
84
                {
 
85
                        double xPos = padding, yPos = padding;
 
86
                        using (var layout = PangoUtil.CreateLayout (this)) {
 
87
                                int w, h;
 
88
                                        
 
89
                                foreach (Category cat in categories) {
 
90
                                        yPos = padding;
 
91
                                        layout.SetMarkup ("<b>" + cat.Title + "</b>");
 
92
                                        layout.SetMarkup ("");
 
93
                                        layout.GetPixelSize (out w, out h);
 
94
                                        yPos += h;
 
95
                                        yPos += headerDistance;
 
96
                                        var startY = yPos;
 
97
                                        int curItem = 0;
 
98
                                        layout.SetText (new string ('X', maxLength));
 
99
                                        layout.GetPixelSize (out w, out h);
 
100
                                        var iconHeight = Math.Max (h, cat.Items[0].Icon.Height + 2);
 
101
                                        if (cat.FirstVisibleItem > 0) {
 
102
                                                yPos += iconHeight;
 
103
                                                curItem++;
 
104
                                        }
 
105
                                        for (int i = cat.FirstVisibleItem; i < cat.Items.Count; i++) {
 
106
                                                var item = cat.Items[i];
 
107
                                                if (xPos <= x && yPos <= y && x < xPos + w + item.Icon.Width + 2 && y < yPos + iconHeight)
 
108
                                                        return item;
 
109
                                                yPos += iconHeight;
 
110
                                                if (++curItem >= maxItems) {
 
111
                                                        curItem = 0;
 
112
                                                        yPos = startY;
 
113
                                                        xPos += w + cat.Items[0].Icon.Width + 2 + padding;
 
114
                                                }
 
115
                                        }
 
116
                                        xPos += w + cat.Items[0].Icon.Width + 2 + padding;
 
117
                                }
 
118
                        }
 
119
                        return null;
 
120
                }
 
121
                
 
122
                protected override bool OnButtonPressEvent (EventButton evnt)
 
123
                {
 
124
                        if (evnt.Button == 1 && hoverItem != null)
 
125
                                ActiveItem = hoverItem;
 
126
                        return base.OnButtonPressEvent (evnt);
 
127
                }
 
128
                
 
129
                protected override bool OnMotionNotifyEvent (EventMotion evnt)
 
130
                {
 
131
                        var item = GetItemAt (evnt.X, evnt.Y);
 
132
                        if (item != hoverItem) {
 
133
                                hoverItem = item;
 
134
                                QueueDraw ();
 
135
                        }
 
136
                        return base.OnMotionNotifyEvent (evnt);
 
137
                }
 
138
                
 
139
                protected override bool OnLeaveNotifyEvent (EventCrossing evnt)
 
140
                {
 
141
                        if (hoverItem != null) {
 
142
                                hoverItem = null;
 
143
                                QueueDraw ();
 
144
                        }
 
145
                        return base.OnLeaveNotifyEvent (evnt);
 
146
                }
 
147
 
 
148
                
 
149
                static string Ellipsize (string str, int maxLength)
 
150
                {
 
151
                        if (str != null && str.Length > maxLength)
 
152
                                return str.Substring (0, maxLength - 3) + "...";
 
153
                        return str;
 
154
                }
 
155
                
 
156
                const int upperGradientHeight = 16;
 
157
                protected override bool OnExposeEvent (Gdk.EventExpose e)
 
158
                {
 
159
                        using (Cairo.Context cr = Gdk.CairoHelper.Create (e.Window)) {
 
160
                                cr.Rectangle (0, 0, Allocation.Width, upperGradientHeight);
 
161
                                using (var pattern = new Cairo.LinearGradient (0, 0, 0, upperGradientHeight)) {
 
162
                                        pattern.AddColorStopRgb (0, new Cairo.Color (0.6, 0.8, 0.6));
 
163
                                        pattern.AddColorStopRgb (1, new Cairo.Color (0.8, 1.0, 0.8));
 
164
                                        cr.Pattern = pattern;
 
165
                                        cr.Fill ();
 
166
                                }
 
167
                                
 
168
                                cr.Rectangle (0, upperGradientHeight, Allocation.Width, Allocation.Height - upperGradientHeight);
 
169
                                using (var pattern = new Cairo.LinearGradient (0, upperGradientHeight, 0, Allocation.Height)) {
 
170
                                        pattern.AddColorStop (0, new Cairo.Color (0.8, 1.0, 0.8));
 
171
                                        pattern.AddColorStop (1, new Cairo.Color (0.6, 0.8, 0.6));
 
172
                                        cr.Pattern = pattern;
 
173
                                        cr.Fill ();
 
174
                                }
 
175
                                
 
176
                                cr.LineWidth = 1;
 
177
                                cr.Line (0, 0, Allocation.Width, 0);
 
178
                                cr.Color = new Cairo.Color (0.4, 0.6, 0.4);
 
179
                                cr.Stroke ();
 
180
                                
 
181
                                double xPos = padding, yPos = padding;
 
182
                                var layout = PangoUtil.CreateLayout (this);
 
183
                                int w, h;
 
184
                                layout.SetText (new string ('X', maxLength));
 
185
                                layout.GetPixelSize (out w, out h);
 
186
                                
 
187
                                foreach (Category cat in categories) {
 
188
                                        yPos = padding;
 
189
                                        cr.MoveTo (xPos, yPos);
 
190
                                        layout.SetMarkup ("<b>" + cat.Title + "</b>");
 
191
                                        cr.Color = (HslColor)Style.Text (StateType.Normal);
 
192
                                        cr.ShowLayout (layout);
 
193
                                        layout.SetMarkup ("");
 
194
                                        int w2, h2;
 
195
                                        layout.GetPixelSize (out w2, out h2);
 
196
                                        yPos += h2;
 
197
                                        yPos += headerDistance;
 
198
                                        var startY = yPos;
 
199
                                        int curItem = 0;
 
200
                                        int row = 0;
 
201
                                        var iconHeight = Math.Max (h, cat.Items [0].Icon.Height + 2);
 
202
                                        if (cat.FirstVisibleItem > 0) {
 
203
                                                Gtk.Style.PaintArrow (Style, e.Window, State, ShadowType.None, 
 
204
                                                                new Rectangle ((int)xPos, (int)yPos, w, h), 
 
205
                                                                this, 
 
206
                                                                "", 
 
207
                                                                ArrowType.Up, 
 
208
                                                                true, 
 
209
                                                                (int)xPos, 
 
210
                                                                (int)yPos, 
 
211
                                                                w, 
 
212
                                                                h);
 
213
                                                yPos += iconHeight;
 
214
                                                curItem++;
 
215
                                        }
 
216
                                        
 
217
                                        for (int i = cat.FirstVisibleItem; i < cat.Items.Count; i++) {
 
218
                                                var item = cat.Items [i];
 
219
                                                
 
220
                                                if (curItem + 1 >= maxItems && row + 1 >= maxRows && i + 1 < cat.Items.Count) {
 
221
                                                        Gtk.Style.PaintArrow (Style, e.Window, State, ShadowType.None, 
 
222
                                                                new Rectangle ((int)xPos, (int)yPos, w, h), 
 
223
                                                                this, 
 
224
                                                                "", 
 
225
                                                                ArrowType.Down, 
 
226
                                                                true, 
 
227
                                                                (int)xPos, 
 
228
                                                                (int)yPos, 
 
229
                                                                w, 
 
230
                                                                h);
 
231
                                                        break;
 
232
                                                }
 
233
                                                
 
234
                                                if (item == ActiveItem) {
 
235
                                                        cr.Rectangle (xPos + 0.5, yPos + 0.5, w + item.Icon.Width + 2, iconHeight);
 
236
                                                        
 
237
                                                        using (var pattern = new Cairo.LinearGradient (xPos, yPos, xPos, yPos + iconHeight * 2)) {
 
238
                                                                pattern.AddColorStop (0, (HslColor)Style.Base (StateType.Selected));
 
239
                                                                pattern.AddColorStop (1, new Cairo.Color (0.8, 1.0, 0.8));
 
240
                                                                cr.Pattern = pattern;
 
241
                                                                cr.FillPreserve ();
 
242
                                                        }
 
243
                                                        
 
244
                                                        cr.Color = (HslColor)Style.Base (StateType.Selected);
 
245
                                                        cr.Stroke ();
 
246
                                                        cr.Color = (HslColor)Style.Text (StateType.Selected);
 
247
                                                } else if (item == hoverItem) {
 
248
                                                        cr.Rectangle (xPos + 0.5, yPos + 0.5, w + item.Icon.Width + 2, iconHeight);
 
249
                                                        using (var pattern = new Cairo.LinearGradient (xPos, yPos, xPos, yPos + iconHeight)) {
 
250
                                                                pattern.AddColorStop (0, new Cairo.Color (0.6, 0.8, 0.6));
 
251
                                                                pattern.AddColorStop (1, new Cairo.Color (0.8, 1.0, 0.8));
 
252
                                                                cr.Pattern = pattern;
 
253
                                                                cr.Fill ();
 
254
                                                        }
 
255
                                                        cr.Color = (HslColor)Style.Text (StateType.Normal);
 
256
                                                } else {
 
257
                                                        cr.Color = (HslColor)Style.Text (StateType.Normal);
 
258
                                                }
 
259
                                                cr.MoveTo (xPos + item.Icon.Width + 2, yPos + (iconHeight - h) / 2);
 
260
                                                layout.SetText (Ellipsize (item.ListTitle ?? item.Title, maxLength));
 
261
                                                cr.ShowLayout (layout);
 
262
                                                e.Window.DrawPixbuf (Style.BaseGC (StateType.Normal), item.Icon, 0, 0, (int)xPos, (int)(yPos + (iconHeight - item.Icon.Height) / 2), item.Icon.Width, item.Icon.Height, RgbDither.None, 0, 0);
 
263
                                                
 
264
                                                yPos += iconHeight;
 
265
                                                if (++curItem >= maxItems) {
 
266
                                                        curItem = 0;
 
267
                                                        yPos = startY;
 
268
                                                        xPos += w + cat.Items [0].Icon.Width + 2 + padding;
 
269
                                                        row++;
 
270
                                                }
 
271
                                        }
 
272
                                        
 
273
                                
 
274
                                        xPos += w + cat.Items [0].Icon.Width + 2 + padding;
 
275
                                }
 
276
                                layout.Dispose ();
 
277
                        }
 
278
                        return true;
 
279
                }
 
280
                
 
281
                protected override bool OnKeyPressEvent (EventKey evnt)
300
282
                {
301
283
                        Gdk.Key key;
302
284
                        Gdk.ModifierType mod;
304
286
                        
305
287
                        switch (key) {
306
288
                        case Gdk.Key.Left:
307
 
                                SwitchToPad ();
 
289
                                LeftItem ();
308
290
                                break;
309
291
                        case Gdk.Key.Right:
310
 
                                SwitchToDocument ();
 
292
                                RightItem ();
311
293
                                break;
312
294
                        case Gdk.Key.Up:
313
 
                                Previous ();
 
295
                                PrevItem ();
314
296
                                break;
315
297
                        case Gdk.Key.Down:
316
 
                                Next ();
 
298
                                NextItem ();
317
299
                                break;
318
300
                        case Gdk.Key.Tab:
319
301
                                if ((mod & ModifierType.ShiftMask) == 0)
320
 
                                        Next ();
 
302
                                        NextItem ();
321
303
                                else
322
 
                                        Previous ();
 
304
                                        PrevItem ();
323
305
                                break;
324
306
                        }
325
 
                        return true;
 
307
                        return base.OnKeyPressEvent (evnt);
326
308
                }
327
309
                
328
310
                protected override bool OnKeyReleaseEvent (Gdk.EventKey evnt)
329
311
                {
330
 
                        bool ret;
331
312
                        if (evnt.Key == Gdk.Key.Control_L || evnt.Key == Gdk.Key.Control_R) {
332
 
                                Gdk.Window focusTarget = null;
333
 
                                Document doc = SelectedDocument;
334
 
                                if (doc != null) {
335
 
                                        doc.Select ();
336
 
                                        focusTarget = doc.ActiveView.Control.Toplevel.GdkWindow;
337
 
                                } else {
338
 
                                        Pad pad = SelectedPad;
339
 
                                        if (pad != null) {
340
 
                                                pad.BringToFront (true);
341
 
                                                focusTarget = pad.Window.Content.Control.Toplevel.GdkWindow;
342
 
                                        }
343
 
                                }
344
 
                                ret = base.OnKeyReleaseEvent (evnt);
345
 
                                Gtk.Window parent = this.TransientFor;
346
 
                                this.Destroy ();
347
 
                                
348
 
                                (focusTarget ?? parent.GdkWindow).Focus (0);
349
 
                        } else {
350
 
                                ret = base.OnKeyReleaseEvent (evnt);
351
 
                        }
352
 
                        return ret;
 
313
                                OnRequestClose (EventArgs.Empty);
 
314
                        }
 
315
                        return base.OnKeyReleaseEvent (evnt);
 
316
                }
 
317
                
 
318
                protected virtual void OnRequestClose (EventArgs e)
 
319
                {
 
320
                        EventHandler handler = this.RequestClose;
 
321
                        if (handler != null)
 
322
                                handler (this, e);
 
323
                }
 
324
 
 
325
                public event EventHandler RequestClose;
 
326
                
 
327
                void LeftItem ()
 
328
                {
 
329
                        for (int i = 0; i < categories.Count; i++) {
 
330
                                var cat = categories[i];
 
331
                                int idx = cat.Items.IndexOf (ActiveItem);
 
332
                                if (idx < 0)
 
333
                                        continue;
 
334
                                int relIndex = idx - cat.FirstVisibleItem;
 
335
                                if (relIndex / maxItems == 0) {
 
336
                                        if (i > 0) {
 
337
                                                int newIndex = Math.Min (categories[i -1].Items.Count - 1, categories[i - 1].FirstVisibleItem + relIndex);
 
338
                                                ActiveItem = categories[i - 1].Items [newIndex];
 
339
                                        }
 
340
                                } else {
 
341
                                        ActiveItem = cat.Items [relIndex - maxItems];
 
342
                                }
 
343
                                
 
344
                        }
 
345
                }
 
346
                
 
347
                void RightItem ()
 
348
                {
 
349
                        for (int i = 0; i < categories.Count; i++) {
 
350
                                var cat = categories[i];
 
351
                                int idx = cat.Items.IndexOf (ActiveItem);
 
352
                                if (idx < 0)
 
353
                                        continue;
 
354
                                int relIndex = idx - cat.FirstVisibleItem;
 
355
                                if (relIndex / maxItems == maxRows - 1 || relIndex + maxItems >= cat.Items.Count) {
 
356
                                        if (i + 1 < categories.Count) {
 
357
                                                int newIndex = Math.Min (categories[i + 1].Items.Count - 1, categories[i + 1].FirstVisibleItem + relIndex);
 
358
                                                ActiveItem = categories[i + 1].Items [newIndex];
 
359
                                        }
 
360
                                } else {
 
361
                                        ActiveItem = cat.Items [relIndex + maxItems];
 
362
                                }
 
363
                        }
 
364
                }
 
365
                
 
366
                public void NextItem ()
 
367
                {
 
368
                        foreach (Category cat in categories) {
 
369
                                int idx = cat.Items.IndexOf (ActiveItem);
 
370
                                if (idx < 0)
 
371
                                        continue;
 
372
                                if (idx + 1 < cat.Items.Count) {
 
373
                                        if (idx + 1 > cat.FirstVisibleItem + maxItems * maxRows - 3)
 
374
                                                cat.FirstVisibleItem++;
 
375
                                        ActiveItem = cat.Items[idx + 1];
 
376
                                } else {
 
377
                                        cat.FirstVisibleItem = 0;
 
378
                                        ActiveItem = cat.Items[0];
 
379
                                }
 
380
                                break;
 
381
                        }
 
382
                }
 
383
                
 
384
                public void PrevItem ()
 
385
                {
 
386
                        foreach (Category cat in categories) {
 
387
                                int idx = cat.Items.IndexOf (ActiveItem);
 
388
                                if (idx < 0)
 
389
                                        continue;
 
390
                                if (idx - 1 >= 0) {
 
391
                                        if (idx - 1 < cat.FirstVisibleItem)
 
392
                                                cat.FirstVisibleItem--;
 
393
                                        ActiveItem = cat.Items[idx - 1];
 
394
                                } else {
 
395
                                        if (cat.Items.Count - 1 > cat.FirstVisibleItem + maxItems * maxRows)
 
396
                                                cat.FirstVisibleItem = cat.Items.Count - maxItems * maxRows + 1;
 
397
                                        ActiveItem = cat.Items[cat.Items.Count - 1];
 
398
                                }
 
399
                                break;
 
400
                        }
 
401
                }
 
402
                
 
403
                protected override void OnSizeRequested (ref Requisition req)
 
404
                {
 
405
                        maxLength = 15;
 
406
                        foreach (var cat in categories) {
 
407
                                foreach (var item in cat.Items) {
 
408
                                        maxLength = Math.Min (30, Math.Max (maxLength, (item.ListTitle ?? item.Title).Length));
 
409
                                }
 
410
                        }
 
411
                        
 
412
                        var layout = PangoUtil.CreateLayout (this);
 
413
                        int w, h;
 
414
                        layout.SetText (new string ('X', maxLength));
 
415
                        layout.GetPixelSize (out w, out h);
 
416
                        layout.Dispose ();
 
417
                        int totalWidth = 0;
 
418
                        int totalHeight = 0;
 
419
                                
 
420
                        foreach (var cat in categories) {
 
421
                                var iconHeight = Math.Max (h, cat.Items[0].Icon.Height + 2);
 
422
                                var iconWidth = cat.Items[0].Icon.Width + 2 + w;
 
423
                                var headerHeight = h + headerDistance;
 
424
                                totalHeight = Math.Max (totalHeight, headerHeight + (Math.Min (cat.Items.Count, maxItems)) * iconHeight);
 
425
                                totalWidth += (1 + Math.Min (maxRows - 1, cat.Items.Count / maxItems)) * iconWidth;
 
426
                        }
 
427
                        req.Width = totalWidth + padding * 2 + (categories.Count - 1) * padding;
 
428
                        req.Height = totalHeight + padding * 2;
 
429
                }
 
430
                
 
431
                public class Item
 
432
                {
 
433
                        public string Title {
 
434
                                get;
 
435
                                set;
 
436
                        }
 
437
                        
 
438
                        public string ListTitle {
 
439
                                get;
 
440
                                set;
 
441
                        }
 
442
                        
 
443
                        public Pixbuf Icon {
 
444
                                get;
 
445
                                set;
 
446
                        }
 
447
                        
 
448
                        public string Description {
 
449
                                get;
 
450
                                set;
 
451
                        }
 
452
                        
 
453
                        public string Path {
 
454
                                get;
 
455
                                set;
 
456
                        }
 
457
                        
 
458
                        public object Tag {
 
459
                                get;
 
460
                                set;
 
461
                        }
 
462
                        
 
463
                        public override string ToString ()
 
464
                        {
 
465
                                return string.Format ("[Item: Title={0}]", Title);
 
466
                        }
 
467
 
 
468
                }
 
469
                
 
470
                public class Category
 
471
                {
 
472
                        public string Title {
 
473
                                get;
 
474
                                set;
 
475
                        }
 
476
                        
 
477
                        List<Item> items = new List<Item> ();
 
478
                        public List<Item> Items {
 
479
                                get {
 
480
                                        return items;
 
481
                                }
 
482
                        }
 
483
                        
 
484
                        public int FirstVisibleItem {
 
485
                                get;
 
486
                                set;
 
487
                        }
 
488
                        
 
489
                        public Category (string title)
 
490
                        {
 
491
                                this.Title = title;
 
492
                        }
 
493
                        
 
494
                        public void AddItem (Item item)
 
495
                        {
 
496
                                items.Add (item);
 
497
                        }
 
498
                        
 
499
                        public override string ToString ()
 
500
                        {
 
501
                                return string.Format ("[Category: Title={0}]", Title);
 
502
                        }
 
503
                }
 
504
        }
 
505
        
 
506
        internal class DocumentSwitcher : Gtk.Window
 
507
        {
 
508
                List<MonoDevelop.Ide.Gui.Document> documents;
 
509
                Gtk.Image imageTitle = new Gtk.Image ();
 
510
                Label labelFileName = new Label ();
 
511
                Label labelType     = new Label ();
 
512
                Label labelTitle    = new Label ();
 
513
                DocumentList documentList = new DocumentList ();
 
514
                
 
515
                public DocumentSwitcher (Gtk.Window parent, bool startWithNext) : base(Gtk.WindowType.Toplevel)
 
516
                {
 
517
                        IdeApp.CommandService.IsEnabled = false;
 
518
                        this.documents = new List<MonoDevelop.Ide.Gui.Document> (IdeApp.Workbench.Documents.OrderByDescending (d => d.LastTimeActive));
 
519
                        this.TransientFor = parent;
 
520
                        
 
521
                        this.Decorated = false;
 
522
                        this.DestroyWithParent = true;
 
523
                        this.CanDefault = true;
 
524
                        
 
525
                        this.Modal = true;
 
526
                        this.WindowPosition = Gtk.WindowPosition.CenterOnParent;
 
527
                        this.TypeHint = WindowTypeHint.Dialog;
 
528
                        
 
529
                        this.ModifyBg (StateType.Normal, this.Style.Base (StateType.Normal));
 
530
                        
 
531
                        VBox vBox = new VBox ();
 
532
                        HBox hBox = new HBox ();
 
533
                        
 
534
                        var hBox2 = new HBox ();
 
535
                        hBox2.PackStart (hBox, false, false, 8);
 
536
                        
 
537
                        hBox.PackStart (imageTitle, true, false, 2);
 
538
                        labelTitle.Xalign = 0;
 
539
                        labelTitle.HeightRequest = 24;
 
540
                        hBox.PackStart (labelTitle, true, true, 2);
 
541
                        vBox.PackStart (hBox2, false, false, 6);
 
542
                        
 
543
                        labelType.Xalign = 0;
 
544
                        labelType.HeightRequest = 16;
 
545
                        hBox = new HBox ();
 
546
                        hBox.PackStart (labelType, false, false, 8);
 
547
                        vBox.PackStart (hBox, false, false, 2);
 
548
                        
 
549
                        hBox = new HBox ();
 
550
                        hBox.PackStart (documentList, true, true, 1);
 
551
                        vBox.PackStart (hBox, false, false, 0);
 
552
                        
 
553
                        labelFileName.Xalign = 0;
 
554
                        labelFileName.Ellipsize = Pango.EllipsizeMode.Start;
 
555
                        hBox = new HBox ();
 
556
                        hBox.PackStart (labelFileName, true, true, 8);
 
557
                        vBox.PackEnd (hBox, false, false, 6);
 
558
                        
 
559
                        Add (vBox);
 
560
                        
 
561
                        var padCategory = new  DocumentList.Category (GettextCatalog.GetString ("Pads"));
 
562
                        DocumentList.Item activeItem = null;
 
563
                        
 
564
                        foreach (Pad pad in IdeApp.Workbench.Pads) {
 
565
                                if (!pad.Visible)
 
566
                                        continue;
 
567
                                var item = new DocumentList.Item () {
 
568
                                        Icon = ImageService.GetPixbuf (pad.Icon.Name ?? MonoDevelop.Ide.Gui.Stock.MiscFiles, IconSize.Menu),
 
569
                                        Title = pad.Title,
 
570
                                        Tag = pad
 
571
                                };
 
572
                                if (pad.Window.Content.Control.HasFocus)
 
573
                                        activeItem = item;
 
574
                                padCategory.AddItem (item);
 
575
                        }
 
576
                        documentList.AddCategory (padCategory);
 
577
                        
 
578
                        var documentCategory = new  DocumentList.Category (GettextCatalog.GetString ("Documents"));
 
579
                        foreach (var doc in documents) {
 
580
                                var item = new DocumentList.Item () {
 
581
                                        Icon = GetIconForDocument (doc, IconSize.Menu),
 
582
                                        Title = System.IO.Path.GetFileName (doc.Name),
 
583
                                        ListTitle = doc.Window.Title,
 
584
                                        Description = doc.Window.DocumentType,
 
585
                                        Path = doc.Name,
 
586
                                        Tag = doc
 
587
                                };
 
588
                                if (doc.Window.ActiveViewContent.Control.HasFocus)
 
589
                                        activeItem = item;
 
590
                                documentCategory.AddItem (item);
 
591
                        }
 
592
                        documentList.AddCategory (documentCategory);
 
593
                
 
594
                        documentList.ActiveItemChanged += delegate {
 
595
                                if (documentList.ActiveItem == null) {
 
596
                                        labelFileName.Text = labelType.Text = labelTitle.Text = "";
 
597
                                        return;
 
598
                                }
 
599
                                imageTitle.Pixbuf = documentList.ActiveItem.Icon;
 
600
                                labelFileName.Text = documentList.ActiveItem.Path;
 
601
                                labelType.Markup = "<span size=\"small\">" + documentList.ActiveItem.Description + "</span>";
 
602
                                labelTitle.Markup =  "<span size=\"xx-large\" weight=\"bold\">" + documentList.ActiveItem.Title + "</span>";
 
603
                        };
 
604
                        
 
605
                        if (activeItem == null) {
 
606
                                if (documentCategory.Items.Count > 0) {
 
607
                                        activeItem = documentCategory.Items[0];
 
608
                                } else if (padCategory.Items.Count > 0) {
 
609
                                        activeItem = padCategory.Items[0];
 
610
                                } else {
 
611
                                        Destroy ();
 
612
                                        return;
 
613
                                }
 
614
                        }
 
615
                        
 
616
                        documentList.ActiveItem = activeItem;
 
617
                        documentList.NextItem ();
 
618
                        documentList.RequestClose += delegate {
 
619
                                if (documentList.ActiveItem.Tag is Pad) {
 
620
                                        ((Pad)documentList.ActiveItem.Tag).BringToFront (true);
 
621
                                } else {
 
622
                                        ((MonoDevelop.Ide.Gui.Document)documentList.ActiveItem.Tag).Select ();
 
623
                                }
 
624
                                Destroy ();
 
625
                        };
 
626
                        
 
627
                        this.ShowAll ();
 
628
                        documentList.GrabFocus ();
 
629
                        this.GrabDefault ();
 
630
                }
 
631
                
 
632
                Pixbuf GetIconForDocument (MonoDevelop.Ide.Gui.Document document, Gtk.IconSize iconSize)
 
633
                {
 
634
                        if (!string.IsNullOrEmpty (document.Window.ViewContent.StockIconId))
 
635
                                return ImageService.GetPixbuf (document.Window.ViewContent.StockIconId, iconSize);
 
636
                        if (string.IsNullOrEmpty (document.FileName)) 
 
637
                                return ImageService.GetPixbuf (MonoDevelop.Ide.Gui.Stock.MiscFiles, iconSize);
 
638
                        
 
639
                        return DesktopService.GetPixbufForFile (document.FileName, iconSize);
 
640
                }
 
641
                
 
642
                
 
643
                protected override bool OnFocusOutEvent (EventFocus evnt)
 
644
                {
 
645
                        Destroy ();
 
646
                        return base.OnFocusOutEvent (evnt);
 
647
                }
 
648
                
 
649
                protected override void OnDestroyed ()
 
650
                {
 
651
                        base.OnDestroyed ();
 
652
                        IdeApp.CommandService.IsEnabled = true;
353
653
                }
354
654
                
355
655
                protected override bool OnExposeEvent (EventExpose evnt)
358
658
                        
359
659
                        int winWidth, winHeight;
360
660
                        this.GetSize (out winWidth, out winHeight);
361
 
                        this.GdkWindow.DrawRectangle (this.Style.ForegroundGC (StateType.Insensitive), false, 0, 0, winWidth-1, winHeight-1);
 
661
                        
 
662
                        this.GdkWindow.DrawRectangle (this.Style.ForegroundGC (StateType.Insensitive), false, 0, 0, winWidth - 1, winHeight - 1);
362
663
                        return false;
363
664
                }
364
 
                
365
 
                void Next ()
366
 
                {
367
 
                        if (documentFocus) {
368
 
                                SelectDocument (GetNextDocument (SelectedDocument));
369
 
                        } else {
370
 
                                SelectPad (GetNextPad (SelectedPad));
371
 
                        }
372
 
                }
373
 
                
374
 
                void Previous ()
375
 
                {
376
 
                        if (documentFocus) {
377
 
                                SelectDocument (GetPrevDocument (SelectedDocument));
378
 
                        } else {
379
 
                                SelectPad (GetPrevPad (SelectedPad));
380
 
                        }
381
 
                }
382
665
        }
383
 
}
 
666
}
 
 
b'\\ No newline at end of file'