~halega/+junk/sharpdevelop

« back to all changes in this revision

Viewing changes to src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs

  • Committer: sk
  • Date: 2011-09-10 05:17:57 UTC
  • Revision ID: halega@halega.com-20110910051757-qfouz1llya9m6boy
4.1.0.7915 Release Candidate 1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
 
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
 
3
 
 
4
using System;
 
5
using System.Collections.Generic;
 
6
using System.Collections.ObjectModel;
 
7
using System.Diagnostics;
 
8
using System.Linq;
 
9
using System.Windows;
 
10
using System.Windows.Controls;
 
11
using System.Windows.Input;
 
12
using System.Windows.Threading;
 
13
 
 
14
using AvalonDock;
 
15
using ICSharpCode.Core;
 
16
using ICSharpCode.Core.Presentation;
 
17
 
 
18
namespace ICSharpCode.SharpDevelop.Gui
 
19
{
 
20
        sealed class AvalonWorkbenchWindow : DocumentContent, IWorkbenchWindow, IOwnerState
 
21
        {
 
22
                readonly static string contextMenuPath = "/SharpDevelop/Workbench/OpenFileTab/ContextMenu";
 
23
                
 
24
                AvalonDockLayout dockLayout;
 
25
                
 
26
                public AvalonWorkbenchWindow(AvalonDockLayout dockLayout)
 
27
                {
 
28
                        if (dockLayout == null)
 
29
                                throw new ArgumentNullException("dockLayout");
 
30
                        
 
31
                        CustomFocusManager.SetRememberFocusedChild(this, true);
 
32
                        this.IsFloatingAllowed = true;
 
33
                        this.dockLayout = dockLayout;
 
34
                        viewContents = new ViewContentCollection(this);
 
35
                        
 
36
                        ResourceService.LanguageChanged += OnTabPageTextChanged;
 
37
                }
 
38
                
 
39
                protected override void FocusContent()
 
40
                {
 
41
                        WpfWorkbench.FocusDebug("{0}.FocusContent() IsActiveContent={1} IsKeyboardFocusWithin={2} Keyboard.FocusedElement={3}",
 
42
                                                Title, IsActiveContent, IsKeyboardFocusWithin, Keyboard.FocusedElement);
 
43
                        if (!(IsActiveContent && !IsKeyboardFocusWithin)) {
 
44
                                return;
 
45
                        }
 
46
                        IInputElement activeChild = CustomFocusManager.GetFocusedChild(this);
 
47
                        WpfWorkbench.FocusDebug("{0}.FocusContent() - Will move focus (activeChild={1})", this.Title, activeChild);
 
48
                        // use lambda for fetching the active child - this is necessary because the ActiveViewContent might change until the background
 
49
                        // action is called
 
50
                        AvalonWorkbenchWindow.SetFocus(this, () => activeChild ?? (ActiveViewContent != null ? ActiveViewContent.InitiallyFocusedControl as IInputElement : null));
 
51
                }
 
52
                
 
53
                internal static void SetFocus(ManagedContent m, Func<IInputElement> activeChildFunc, bool forceSetFocus = false)
 
54
                {
 
55
                        m.Dispatcher.BeginInvoke(
 
56
                                DispatcherPriority.Background,
 
57
                                new Action(
 
58
                                        delegate {
 
59
                                                // ensure that condition for FocusContent() is still fulfilled
 
60
                                                // (necessary to avoid focus switching loops when changing layouts)
 
61
                                                if (!forceSetFocus && !(m.IsActiveContent && !m.IsKeyboardFocusWithin)) {
 
62
                                                        WpfWorkbench.FocusDebug("{0} - not moving focus (IsActiveContent={1}, IsKeyboardFocusWithin={2})",
 
63
                                                                                m.Title, m.IsActiveContent, m.IsKeyboardFocusWithin);
 
64
                                                        return;
 
65
                                                }
 
66
                                                IInputElement activeChild = activeChildFunc();
 
67
                                                WpfWorkbench.FocusDebug("{0} - moving focus to: {1}", m.Title, activeChild != null ? activeChild.ToString() : "<null>");
 
68
                                                if (activeChild != null) {
 
69
                                                        Keyboard.Focus(activeChild);
 
70
                                                }
 
71
                                        }));
 
72
                }
 
73
                
 
74
                public bool IsDisposed { get { return false; } }
 
75
                
 
76
                #region IOwnerState
 
77
                [Flags]
 
78
                public enum OpenFileTabStates {
 
79
                        Nothing             = 0,
 
80
                        FileDirty           = 1,
 
81
                        FileReadOnly        = 2,
 
82
                        FileUntitled        = 4,
 
83
                        ViewContentWithoutFile = 8
 
84
                }
 
85
                
 
86
                public System.Enum InternalState {
 
87
                        get {
 
88
                                IViewContent content = this.ActiveViewContent;
 
89
                                OpenFileTabStates state = OpenFileTabStates.Nothing;
 
90
                                if (content != null) {
 
91
                                        if (content.IsDirty)
 
92
                                                state |= OpenFileTabStates.FileDirty;
 
93
                                        if (content.IsReadOnly)
 
94
                                                state |= OpenFileTabStates.FileReadOnly;
 
95
                                        if (content.PrimaryFile != null && content.PrimaryFile.IsUntitled)
 
96
                                                state |= OpenFileTabStates.FileUntitled;
 
97
                                        if (content.PrimaryFile == null)
 
98
                                                state |= OpenFileTabStates.ViewContentWithoutFile;
 
99
                                }
 
100
                                return state;
 
101
                        }
 
102
                }
 
103
                #endregion
 
104
                
 
105
                TabControl viewTabControl;
 
106
                
 
107
                /// <summary>
 
108
                /// The current view content which is shown inside this window.
 
109
                /// </summary>
 
110
                public IViewContent ActiveViewContent {
 
111
                        get {
 
112
                                WorkbenchSingleton.DebugAssertMainThread();
 
113
                                if (viewTabControl != null && viewTabControl.SelectedIndex >= 0 && viewTabControl.SelectedIndex < ViewContents.Count) {
 
114
                                        return ViewContents[viewTabControl.SelectedIndex];
 
115
                                } else if (ViewContents.Count == 1) {
 
116
                                        return ViewContents[0];
 
117
                                } else {
 
118
                                        return null;
 
119
                                }
 
120
                        }
 
121
                        set {
 
122
                                int pos = ViewContents.IndexOf(value);
 
123
                                if (pos < 0)
 
124
                                        throw new ArgumentException();
 
125
                                SwitchView(pos);
 
126
                        }
 
127
                }
 
128
                
 
129
                SDWindowsFormsHost GetActiveWinFormsHost()
 
130
                {
 
131
                        if (viewTabControl != null && viewTabControl.SelectedIndex >= 0 && viewTabControl.SelectedIndex < ViewContents.Count) {
 
132
                                TabItem page = (TabItem)viewTabControl.Items[viewTabControl.SelectedIndex];
 
133
                                return page.Content as SDWindowsFormsHost;
 
134
                        } else {
 
135
                                return this.Content as SDWindowsFormsHost;
 
136
                        }
 
137
                }
 
138
                
 
139
                public event EventHandler ActiveViewContentChanged;
 
140
                
 
141
                IViewContent oldActiveViewContent;
 
142
                
 
143
                void UpdateActiveViewContent()
 
144
                {
 
145
                        UpdateTitleAndInfoTip();
 
146
                        
 
147
                        IViewContent newActiveViewContent = this.ActiveViewContent;
 
148
                        if (newActiveViewContent != null)
 
149
                                IsLocked = newActiveViewContent.IsReadOnly;
 
150
 
 
151
                        if (oldActiveViewContent != newActiveViewContent && ActiveViewContentChanged != null) {
 
152
                                ActiveViewContentChanged(this, EventArgs.Empty);
 
153
                        }
 
154
                        oldActiveViewContent = newActiveViewContent;
 
155
                        CommandManager.InvalidateRequerySuggested();
 
156
                }
 
157
                
 
158
                sealed class ViewContentCollection : Collection<IViewContent>
 
159
                {
 
160
                        readonly AvalonWorkbenchWindow window;
 
161
                        
 
162
                        internal ViewContentCollection(AvalonWorkbenchWindow window)
 
163
                        {
 
164
                                this.window = window;
 
165
                        }
 
166
                        
 
167
                        protected override void ClearItems()
 
168
                        {
 
169
                                foreach (IViewContent vc in this) {
 
170
                                        window.UnregisterContent(vc);
 
171
                                }
 
172
                                
 
173
                                base.ClearItems();
 
174
                                window.ClearContent();
 
175
                                window.UpdateActiveViewContent();
 
176
                        }
 
177
                        
 
178
                        protected override void InsertItem(int index, IViewContent item)
 
179
                        {
 
180
                                base.InsertItem(index, item);
 
181
                                
 
182
                                window.RegisterNewContent(item);
 
183
                                
 
184
                                if (Count == 1) {
 
185
                                        window.SetContent(item.Control, item);
 
186
                                } else {
 
187
                                        if (Count == 2) {
 
188
                                                window.CreateViewTabControl();
 
189
                                                IViewContent oldItem = this[0];
 
190
                                                if (oldItem == item) oldItem = this[1];
 
191
                                                
 
192
                                                TabItem oldPage = new TabItem();
 
193
                                                oldPage.Header = StringParser.Parse(oldItem.TabPageText);
 
194
                                                oldPage.SetContent(oldItem.Control, oldItem);
 
195
                                                window.viewTabControl.Items.Add(oldPage);
 
196
                                        }
 
197
                                        
 
198
                                        TabItem newPage = new TabItem();
 
199
                                        newPage.Header = StringParser.Parse(item.TabPageText);
 
200
                                        newPage.SetContent(item.Control, item);
 
201
                                        
 
202
                                        window.viewTabControl.Items.Insert(index, newPage);
 
203
                                }
 
204
                                window.UpdateActiveViewContent();
 
205
                        }
 
206
                        
 
207
                        protected override void RemoveItem(int index)
 
208
                        {
 
209
                                window.UnregisterContent(this[index]);
 
210
                                
 
211
                                base.RemoveItem(index);
 
212
                                
 
213
                                if (Count < 2) {
 
214
                                        window.ClearContent();
 
215
                                        if (Count == 1) {
 
216
                                                window.SetContent(this[0].Control, this[0]);
 
217
                                        }
 
218
                                } else {
 
219
                                        window.viewTabControl.Items.RemoveAt(index);
 
220
                                }
 
221
                                window.UpdateActiveViewContent();
 
222
                        }
 
223
                        
 
224
                        protected override void SetItem(int index, IViewContent item)
 
225
                        {
 
226
                                window.UnregisterContent(this[index]);
 
227
                                
 
228
                                base.SetItem(index, item);
 
229
                                
 
230
                                window.RegisterNewContent(item);
 
231
                                
 
232
                                if (Count == 1) {
 
233
                                        window.ClearContent();
 
234
                                        window.SetContent(item.Control, item);
 
235
                                } else {
 
236
                                        TabItem page = (TabItem)window.viewTabControl.Items[index];
 
237
                                        page.SetContent(item.Control, item);
 
238
                                        page.Header = StringParser.Parse(item.TabPageText);
 
239
                                }
 
240
                                window.UpdateActiveViewContent();
 
241
                        }
 
242
                }
 
243
                
 
244
                readonly ViewContentCollection viewContents;
 
245
                
 
246
                public IList<IViewContent> ViewContents {
 
247
                        get { return viewContents; }
 
248
                }
 
249
                
 
250
                /// <summary>
 
251
                /// Gets whether any contained view content has changed
 
252
                /// since the last save/load operation.
 
253
                /// </summary>
 
254
                public bool IsDirty {
 
255
                        get { return this.ViewContents.Any(vc => vc.IsDirty); }
 
256
                }
 
257
                
 
258
                public void SwitchView(int viewNumber)
 
259
                {
 
260
                        if (viewTabControl != null) {
 
261
                                this.viewTabControl.SelectedIndex = viewNumber;
 
262
                        }
 
263
                }
 
264
                
 
265
                public void SelectWindow()
 
266
                {
 
267
                        Activate();//this.SetAsActive();
 
268
                }
 
269
                
 
270
                public override void OnApplyTemplate()
 
271
                {
 
272
                        base.OnApplyTemplate();
 
273
                        
 
274
                        if (this.DragEnabledArea != null) {
 
275
                                this.DragEnabledArea.ContextMenu = MenuService.CreateContextMenu(this, contextMenuPath);
 
276
                                UpdateInfoTip(); // set tooltip
 
277
                        }
 
278
                }
 
279
                
 
280
                void Dispose()
 
281
                {
 
282
                        ResourceService.LanguageChanged -= OnTabPageTextChanged;
 
283
                        // DetachContent must be called before the controls are disposed
 
284
                        List<IViewContent> viewContents = this.ViewContents.ToList();
 
285
                        this.ViewContents.Clear();
 
286
                        viewContents.ForEach(vc => vc.Dispose());
 
287
                }
 
288
                
 
289
                sealed class TabControlWithModifiedShortcuts : TabControl
 
290
                {
 
291
                        readonly AvalonWorkbenchWindow parentWindow;
 
292
                        
 
293
                        public TabControlWithModifiedShortcuts(AvalonWorkbenchWindow parentWindow)
 
294
                        {
 
295
                                this.parentWindow = parentWindow;
 
296
                        }
 
297
                        
 
298
                        protected override void OnKeyDown(KeyEventArgs e)
 
299
                        {
 
300
                                // We don't call base.KeyDown to prevent the TabControl from handling Ctrl+Tab.
 
301
                                // Instead, we let the key press bubble up to the DocumentPane.
 
302
                        }
 
303
                        
 
304
                        protected override void OnPreviewKeyDown(KeyEventArgs e)
 
305
                        {
 
306
                                base.OnPreviewKeyDown(e);
 
307
                                if (e.Handled)
 
308
                                        return;
 
309
                                
 
310
                                // However, we do want to handle Ctrl+PgUp / Ctrl+PgDown (SD-1735)
 
311
                                if ((e.Key == Key.PageUp || e.Key == Key.PageDown) && e.KeyboardDevice.Modifiers == ModifierKeys.Control) {
 
312
                                        int index = this.SelectedIndex;
 
313
                                        if (e.Key == Key.PageUp) {
 
314
                                                if (++index >= this.Items.Count)
 
315
                                                        index = 0;
 
316
                                        } else {
 
317
                                                if (--index < 0)
 
318
                                                        index = this.Items.Count - 1;
 
319
                                        }
 
320
                                        this.SelectedIndex = index;
 
321
                                        
 
322
                                        IViewContent vc = parentWindow.ActiveViewContent;
 
323
                                        if (vc != null)
 
324
                                                SetFocus(parentWindow, () => vc.InitiallyFocusedControl as IInputElement, true);
 
325
                                        
 
326
                                        e.Handled = true;
 
327
                                }
 
328
                        }
 
329
                }
 
330
                
 
331
                private void CreateViewTabControl()
 
332
                {
 
333
                        if (viewTabControl == null) {
 
334
                                viewTabControl = new TabControlWithModifiedShortcuts(this);
 
335
                                viewTabControl.TabStripPlacement = Dock.Bottom;
 
336
                                this.SetContent(viewTabControl);
 
337
                                
 
338
                                viewTabControl.SelectionChanged += delegate {
 
339
                                        UpdateActiveViewContent();
 
340
                                };
 
341
                        }
 
342
                }
 
343
                
 
344
                void ClearContent()
 
345
                {
 
346
                        this.Content = null;
 
347
                        if (viewTabControl != null) {
 
348
                                foreach (TabItem page in viewTabControl.Items) {
 
349
                                        page.SetContent(null);
 
350
                                }
 
351
                                viewTabControl = null;
 
352
                        }
 
353
                }
 
354
                
 
355
                void OnTitleNameChanged(object sender, EventArgs e)
 
356
                {
 
357
                        if (sender == ActiveViewContent) {
 
358
                                UpdateTitle();
 
359
                        }
 
360
                }
 
361
 
 
362
                void OnInfoTipChanged(object sender, EventArgs e)
 
363
                {
 
364
                        if (sender == ActiveViewContent) {
 
365
                                UpdateInfoTip();
 
366
                        }
 
367
                }
 
368
                
 
369
                void OnIsDirtyChanged(object sender, EventArgs e)
 
370
                {
 
371
                        UpdateTitle();
 
372
                        CommandManager.InvalidateRequerySuggested();
 
373
                }
 
374
                
 
375
                void UpdateTitleAndInfoTip()
 
376
                {
 
377
                        UpdateInfoTip();
 
378
                        UpdateTitle();
 
379
                }
 
380
                
 
381
                void UpdateInfoTip()
 
382
                {
 
383
                        IViewContent content = ActiveViewContent;
 
384
                        if (content != null)
 
385
                        {
 
386
                                string newInfoTip = content.InfoTip;
 
387
 
 
388
                                if (newInfoTip != this.InfoTip) {
 
389
                                        this.InfoTip = newInfoTip;
 
390
                                        if (DragEnabledArea != null)
 
391
                                                DragEnabledArea.ToolTip = this.InfoTip;
 
392
 
 
393
                                        OnInfoTipChanged();
 
394
                                }
 
395
                        }
 
396
                }
 
397
 
 
398
                void UpdateTitle()
 
399
                {
 
400
                        IViewContent content = ActiveViewContent;
 
401
                        if (content != null) {
 
402
                                string newTitle = content.TitleName;
 
403
                                if (content.IsDirty)
 
404
                                        newTitle += "*";
 
405
                                if (newTitle != Title) {
 
406
                                        Title = newTitle;
 
407
                                        OnTitleChanged();
 
408
                                }
 
409
                        }
 
410
                }
 
411
 
 
412
 
 
413
                void RegisterNewContent(IViewContent content)
 
414
                {
 
415
                        Debug.Assert(content.WorkbenchWindow == null);
 
416
                        content.WorkbenchWindow = this;
 
417
                        
 
418
                        content.TabPageTextChanged += OnTabPageTextChanged;
 
419
                        content.TitleNameChanged += OnTitleNameChanged;
 
420
                        content.InfoTipChanged += OnInfoTipChanged;
 
421
                        content.IsDirtyChanged += OnIsDirtyChanged;
 
422
 
 
423
                        this.dockLayout.Workbench.OnViewOpened(new ViewContentEventArgs(content));
 
424
                }
 
425
                
 
426
                void UnregisterContent(IViewContent content)
 
427
                {
 
428
                        content.WorkbenchWindow = null;
 
429
                        
 
430
                        content.TabPageTextChanged -= OnTabPageTextChanged;
 
431
                        content.TitleNameChanged -= OnTitleNameChanged;
 
432
                        content.InfoTipChanged -= OnInfoTipChanged;
 
433
                        content.IsDirtyChanged -= OnIsDirtyChanged;
 
434
 
 
435
                        this.dockLayout.Workbench.OnViewClosed(new ViewContentEventArgs(content));
 
436
                }
 
437
                
 
438
                void OnTabPageTextChanged(object sender, EventArgs e)
 
439
                {
 
440
                        RefreshTabPageTexts();
 
441
                }
 
442
                
 
443
                bool forceClose;
 
444
                
 
445
                public bool CloseWindow(bool force)
 
446
                {
 
447
                        WorkbenchSingleton.AssertMainThread();
 
448
                        
 
449
                        forceClose = force;
 
450
                        Close();
 
451
                        return this.ViewContents.Count == 0;
 
452
                }
 
453
                
 
454
                protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
 
455
                {
 
456
                        base.OnClosing(e);
 
457
                        if (!e.Cancel && !forceClose && this.IsDirty) {
 
458
                                MessageBoxResult dr = MessageBox.Show(
 
459
                                        ResourceService.GetString("MainWindow.SaveChangesMessage"),
 
460
                                        ResourceService.GetString("MainWindow.SaveChangesMessageHeader") + " " + Title + " ?",
 
461
                                        MessageBoxButton.YesNoCancel, MessageBoxImage.Question,
 
462
                                        MessageBoxResult.Yes);
 
463
                                switch (dr) {
 
464
                                        case MessageBoxResult.Yes:
 
465
                                                foreach (IViewContent vc in this.ViewContents) {
 
466
                                                        while (vc.IsDirty) {
 
467
                                                                ICSharpCode.SharpDevelop.Commands.SaveFile.Save(vc);
 
468
                                                                if (vc.IsDirty) {
 
469
                                                                        if (MessageService.AskQuestion("${res:MainWindow.DiscardChangesMessage}")) {
 
470
                                                                                break;
 
471
                                                                        }
 
472
                                                                }
 
473
                                                        }
 
474
                                                }
 
475
                                                break;
 
476
                                        case MessageBoxResult.No:
 
477
                                                break;
 
478
                                        case MessageBoxResult.Cancel:
 
479
                                                e.Cancel = true;
 
480
                                                break;
 
481
                                }
 
482
                        }
 
483
                        if (!e.Cancel) {
 
484
                                foreach (IViewContent vc in this.viewContents) {
 
485
                                        dockLayout.Workbench.StoreMemento(vc);
 
486
                                }
 
487
                        }
 
488
                }
 
489
                
 
490
                protected override void OnClosed()
 
491
                {
 
492
                        base.OnClosed();
 
493
                        Dispose();
 
494
                        CommandManager.InvalidateRequerySuggested();
 
495
                }
 
496
                
 
497
                void RefreshTabPageTexts()
 
498
                {
 
499
                        if (viewTabControl != null) {
 
500
                                for (int i = 0; i < viewTabControl.Items.Count; ++i) {
 
501
                                        TabItem tabPage = (TabItem)viewTabControl.Items[i];
 
502
                                        tabPage.Header = StringParser.Parse(ViewContents[i].TabPageText);
 
503
                                }
 
504
                        }
 
505
                }
 
506
 
 
507
                void OnTitleChanged()
 
508
                {
 
509
                        if (TitleChanged != null)
 
510
                        {
 
511
                                TitleChanged(this, EventArgs.Empty);
 
512
                        }
 
513
                }
 
514
 
 
515
                public event EventHandler TitleChanged;
 
516
 
 
517
                void OnInfoTipChanged()
 
518
                {
 
519
                        if (InfoTipChanged != null)
 
520
                        {
 
521
                                InfoTipChanged(this, EventArgs.Empty);
 
522
                        }
 
523
                }
 
524
 
 
525
                public event EventHandler InfoTipChanged;
 
526
 
 
527
                public override string ToString()
 
528
                {
 
529
                        return "[AvalonWorkbenchWindow: " + this.Title + "]";
 
530
                }
 
531
                
 
532
                /// <summary>
 
533
                /// Gets the target for re-routing commands to this window.
 
534
                /// </summary>
 
535
                internal IInputElement GetCommandTarget()
 
536
                {
 
537
                        return CustomFocusManager.GetFocusedChild(this) ?? GetActiveWinFormsHost();
 
538
                }
 
539
        }
 
540
}