Free cookie consent management tool by TermsFeed Policy Generator

source: branches/Async/HeuristicLab.ExtLibs/HeuristicLab.WinFormsUI/2.7.0/WinFormsUI-2.7.0/Docking/DockPanel.FocusManager.cs @ 13329

Last change on this file since 13329 was 8616, checked in by mkommend, 12 years ago

#1939: Added DockPanelSuite 2.7.0 to ExtLibs.

File size: 21.0 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.ComponentModel;
5using System.Runtime.InteropServices;
6using System.Windows.Forms;
7using System.Diagnostics.CodeAnalysis;
8
9namespace WeifenLuo.WinFormsUI.Docking
10{
11    internal interface IContentFocusManager
12    {
13        void Activate(IDockContent content);
14        void GiveUpFocus(IDockContent content);
15        void AddToList(IDockContent content);
16        void RemoveFromList(IDockContent content);
17    }
18
19    partial class DockPanel
20    {
21        private interface IFocusManager
22        {
23            void SuspendFocusTracking();
24            void ResumeFocusTracking();
25            bool IsFocusTrackingSuspended { get; }
26            IDockContent ActiveContent { get; }
27            DockPane ActivePane { get; }
28            IDockContent ActiveDocument { get; }
29            DockPane ActiveDocumentPane { get; }
30        }
31
32        private class FocusManagerImpl : Component, IContentFocusManager, IFocusManager
33        {
34            private class HookEventArgs : EventArgs
35            {
36                [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
37                public int HookCode;
38                [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
39                public IntPtr wParam;
40                public IntPtr lParam;
41            }
42
43            private class LocalWindowsHook : IDisposable
44            {
45                // Internal properties
46                private IntPtr m_hHook = IntPtr.Zero;
47                private NativeMethods.HookProc m_filterFunc = null;
48                private Win32.HookType m_hookType;
49
50                // Event delegate
51                public delegate void HookEventHandler(object sender, HookEventArgs e);
52
53                // Event: HookInvoked
54                public event HookEventHandler HookInvoked;
55                protected void OnHookInvoked(HookEventArgs e)
56                {
57                    if (HookInvoked != null)
58                        HookInvoked(this, e);
59                }
60
61                public LocalWindowsHook(Win32.HookType hook)
62                {
63                    m_hookType = hook;
64                    m_filterFunc = new NativeMethods.HookProc(this.CoreHookProc);
65                }
66
67                // Default filter function
68                public IntPtr CoreHookProc(int code, IntPtr wParam, IntPtr lParam)
69                {
70                    if (code < 0)
71                        return NativeMethods.CallNextHookEx(m_hHook, code, wParam, lParam);
72
73                    // Let clients determine what to do
74                    HookEventArgs e = new HookEventArgs();
75                    e.HookCode = code;
76                    e.wParam = wParam;
77                    e.lParam = lParam;
78                    OnHookInvoked(e);
79
80                    // Yield to the next hook in the chain
81                    return NativeMethods.CallNextHookEx(m_hHook, code, wParam, lParam);
82                }
83
84                // Install the hook
85                public void Install()
86                {
87                    if (m_hHook != IntPtr.Zero)
88                        Uninstall();
89
90                    int threadId = NativeMethods.GetCurrentThreadId();
91                    m_hHook = NativeMethods.SetWindowsHookEx(m_hookType, m_filterFunc, IntPtr.Zero, threadId);
92                }
93
94                // Uninstall the hook
95                public void Uninstall()
96                {
97                    if (m_hHook != IntPtr.Zero)
98                    {
99                        NativeMethods.UnhookWindowsHookEx(m_hHook);
100                        m_hHook = IntPtr.Zero;
101                    }
102                }
103
104                ~LocalWindowsHook()
105                {
106                    Dispose(false);
107                }
108
109                public void Dispose()
110                {
111                    Dispose(true);
112                    GC.SuppressFinalize(this);
113                }
114
115                protected virtual void Dispose(bool disposing)
116                {
117                    Uninstall();
118                }
119            }
120
121            private static LocalWindowsHook sm_localWindowsHook;
122            private LocalWindowsHook.HookEventHandler m_hookEventHandler;
123
124            // Use a static instance of the windows hook to prevent stack overflows in the windows kernel.
125            static FocusManagerImpl()
126            {
127                if (Win32Helper.IsRunningOnMono)
128                    return;
129
130                sm_localWindowsHook = new LocalWindowsHook(Win32.HookType.WH_CALLWNDPROCRET);
131                sm_localWindowsHook.Install();
132            }
133
134            public FocusManagerImpl(DockPanel dockPanel)
135            {
136                m_dockPanel = dockPanel;
137                if (Win32Helper.IsRunningOnMono)
138                    return;               
139                m_hookEventHandler = new LocalWindowsHook.HookEventHandler(HookEventHandler);
140                sm_localWindowsHook.HookInvoked += m_hookEventHandler;
141            }
142
143            private DockPanel m_dockPanel;
144            public DockPanel DockPanel
145            {
146                get { return m_dockPanel; }
147            }
148
149            private bool m_disposed = false;
150            protected override void Dispose(bool disposing)
151            {
152                lock (this)
153                {
154                    if (!m_disposed && disposing)
155                    {
156                        if (!Win32Helper.IsRunningOnMono)
157                        sm_localWindowsHook.HookInvoked -= m_hookEventHandler;
158                        m_disposed = true;
159                    }
160
161                    base.Dispose(disposing);
162                }
163            }
164
165            private IDockContent m_contentActivating = null;
166            private IDockContent ContentActivating
167            {
168                get { return m_contentActivating; }
169                set { m_contentActivating = value; }
170            }
171
172            public void Activate(IDockContent content)
173            {
174                if (IsFocusTrackingSuspended)
175                {
176                    ContentActivating = content;
177                    return;
178                }
179
180                if (content == null)
181                    return;
182                DockContentHandler handler = content.DockHandler;
183                if (handler.Form.IsDisposed)
184                    return; // Should not reach here, but better than throwing an exception
185                if (ContentContains(content, handler.ActiveWindowHandle))
186                    if (!Win32Helper.IsRunningOnMono)
187                        NativeMethods.SetFocus(handler.ActiveWindowHandle);
188                if (!handler.Form.ContainsFocus)
189                {
190                    if (!handler.Form.SelectNextControl(handler.Form.ActiveControl, true, true, true, true))
191                        // Since DockContent Form is not selectalbe, use Win32 SetFocus instead
192                        if (!Win32Helper.IsRunningOnMono)
193                            NativeMethods.SetFocus(handler.Form.Handle);
194                }
195            }
196
197            private List<IDockContent> m_listContent = new List<IDockContent>();
198            private List<IDockContent> ListContent
199            {
200                get { return m_listContent; }
201            }
202            public void AddToList(IDockContent content)
203            {
204                if (ListContent.Contains(content) || IsInActiveList(content))
205                    return;
206
207                ListContent.Add(content);
208            }
209
210            public void RemoveFromList(IDockContent content)
211            {
212                if (IsInActiveList(content))
213                    RemoveFromActiveList(content);
214                if (ListContent.Contains(content))
215                    ListContent.Remove(content);
216            }
217
218            private IDockContent m_lastActiveContent = null;
219            private IDockContent LastActiveContent
220            {
221                get { return m_lastActiveContent; }
222                set { m_lastActiveContent = value; }
223            }
224
225            private bool IsInActiveList(IDockContent content)
226            {
227                return !(content.DockHandler.NextActive == null && LastActiveContent != content);
228            }
229
230            private void AddLastToActiveList(IDockContent content)
231            {
232                IDockContent last = LastActiveContent;
233                if (last == content)
234                    return;
235
236                DockContentHandler handler = content.DockHandler;
237
238                if (IsInActiveList(content))
239                    RemoveFromActiveList(content);
240
241                handler.PreviousActive = last;
242                handler.NextActive = null;
243                LastActiveContent = content;
244                if (last != null)
245                    last.DockHandler.NextActive = LastActiveContent;
246            }
247
248            private void RemoveFromActiveList(IDockContent content)
249            {
250                if (LastActiveContent == content)
251                    LastActiveContent = content.DockHandler.PreviousActive;
252
253                IDockContent prev = content.DockHandler.PreviousActive;
254                IDockContent next = content.DockHandler.NextActive;
255                if (prev != null)
256                    prev.DockHandler.NextActive = next;
257                if (next != null)
258                    next.DockHandler.PreviousActive = prev;
259
260                content.DockHandler.PreviousActive = null;
261                content.DockHandler.NextActive = null;
262            }
263
264            public void GiveUpFocus(IDockContent content)
265            {
266                DockContentHandler handler = content.DockHandler;
267                if (!handler.Form.ContainsFocus)
268                    return;
269
270                if (IsFocusTrackingSuspended)
271                    DockPanel.DummyControl.Focus();
272
273                if (LastActiveContent == content)
274                {
275                    IDockContent prev = handler.PreviousActive;
276                    if (prev != null)
277                        Activate(prev);
278                    else if (ListContent.Count > 0)
279                        Activate(ListContent[ListContent.Count - 1]);
280                }
281                else if (LastActiveContent != null)
282                    Activate(LastActiveContent);
283                else if (ListContent.Count > 0)
284                    Activate(ListContent[ListContent.Count - 1]);
285            }
286
287            private static bool ContentContains(IDockContent content, IntPtr hWnd)
288            {
289                Control control = Control.FromChildHandle(hWnd);
290                for (Control parent = control; parent != null; parent = parent.Parent)
291                    if (parent == content.DockHandler.Form)
292                        return true;
293
294                return false;
295            }
296
297            private int m_countSuspendFocusTracking = 0;
298            public void SuspendFocusTracking()
299            {
300                m_countSuspendFocusTracking++;
301                if (!Win32Helper.IsRunningOnMono)
302                    sm_localWindowsHook.HookInvoked -= m_hookEventHandler;
303            }
304
305            public void ResumeFocusTracking()
306            {
307                if (m_countSuspendFocusTracking > 0)
308                    m_countSuspendFocusTracking--;
309
310                if (m_countSuspendFocusTracking == 0)
311                {
312                    if (ContentActivating != null)
313                    {
314                        Activate(ContentActivating);
315                        ContentActivating = null;
316                    }
317                    if (!Win32Helper.IsRunningOnMono)
318                        sm_localWindowsHook.HookInvoked += m_hookEventHandler;
319                    if (!InRefreshActiveWindow)
320                        RefreshActiveWindow();
321                }
322            }
323
324            public bool IsFocusTrackingSuspended
325            {
326                get { return m_countSuspendFocusTracking != 0; }
327            }
328
329            // Windows hook event handler
330            private void HookEventHandler(object sender, HookEventArgs e)
331            {
332                Win32.Msgs msg = (Win32.Msgs)Marshal.ReadInt32(e.lParam, IntPtr.Size * 3);
333
334                if (msg == Win32.Msgs.WM_KILLFOCUS)
335                {
336                    IntPtr wParam = Marshal.ReadIntPtr(e.lParam, IntPtr.Size * 2);
337                    DockPane pane = GetPaneFromHandle(wParam);
338                    if (pane == null)
339                        RefreshActiveWindow();
340                }
341                else if (msg == Win32.Msgs.WM_SETFOCUS)
342                    RefreshActiveWindow();
343            }
344
345            private DockPane GetPaneFromHandle(IntPtr hWnd)
346            {
347                Control control = Control.FromChildHandle(hWnd);
348
349                IDockContent content = null;
350                DockPane pane = null;
351                for (; control != null; control = control.Parent)
352                {
353                    content = control as IDockContent;
354                    if (content != null)
355                        content.DockHandler.ActiveWindowHandle = hWnd;
356
357                    if (content != null && content.DockHandler.DockPanel == DockPanel)
358                        return content.DockHandler.Pane;
359
360                    pane = control as DockPane;
361                    if (pane != null && pane.DockPanel == DockPanel)
362                        break;
363                }
364
365                return pane;
366            }
367
368            private bool m_inRefreshActiveWindow = false;
369            private bool InRefreshActiveWindow
370            {
371                get { return m_inRefreshActiveWindow; }
372            }
373
374            private void RefreshActiveWindow()
375            {
376                SuspendFocusTracking();
377                m_inRefreshActiveWindow = true;
378
379                DockPane oldActivePane = ActivePane;
380                IDockContent oldActiveContent = ActiveContent;
381                IDockContent oldActiveDocument = ActiveDocument;
382
383                SetActivePane();
384                SetActiveContent();
385                SetActiveDocumentPane();
386                SetActiveDocument();
387                DockPanel.AutoHideWindow.RefreshActivePane();
388
389                ResumeFocusTracking();
390                m_inRefreshActiveWindow = false;
391
392                if (oldActiveContent != ActiveContent)
393                    DockPanel.OnActiveContentChanged(EventArgs.Empty);
394                if (oldActiveDocument != ActiveDocument)
395                    DockPanel.OnActiveDocumentChanged(EventArgs.Empty);
396                if (oldActivePane != ActivePane)
397                    DockPanel.OnActivePaneChanged(EventArgs.Empty);
398            }
399
400            private DockPane m_activePane = null;
401            public DockPane ActivePane
402            {
403                get { return m_activePane; }
404            }
405
406            private void SetActivePane()
407            {
408                DockPane value = Win32Helper.IsRunningOnMono ? null : GetPaneFromHandle(NativeMethods.GetFocus());
409                if (m_activePane == value)
410                    return;
411
412                if (m_activePane != null)
413                    m_activePane.SetIsActivated(false);
414
415                m_activePane = value;
416
417                if (m_activePane != null)
418                    m_activePane.SetIsActivated(true);
419            }
420
421            private IDockContent m_activeContent = null;
422            public IDockContent ActiveContent
423            {
424                get { return m_activeContent; }
425            }
426
427            internal void SetActiveContent()
428            {
429                IDockContent value = ActivePane == null ? null : ActivePane.ActiveContent;
430
431                if (m_activeContent == value)
432                    return;
433
434                if (m_activeContent != null)
435                    m_activeContent.DockHandler.IsActivated = false;
436
437                m_activeContent = value;
438
439                if (m_activeContent != null)
440                {
441                    m_activeContent.DockHandler.IsActivated = true;
442                    if (!DockHelper.IsDockStateAutoHide((m_activeContent.DockHandler.DockState)))
443                        AddLastToActiveList(m_activeContent);
444                }
445            }
446
447            private DockPane m_activeDocumentPane = null;
448            public DockPane ActiveDocumentPane
449            {
450                get { return m_activeDocumentPane; }
451            }
452
453            private void SetActiveDocumentPane()
454            {
455                DockPane value = null;
456
457                if (ActivePane != null && ActivePane.DockState == DockState.Document)
458                    value = ActivePane;
459
460                if (value == null && DockPanel.DockWindows != null)
461                {
462                    if (ActiveDocumentPane == null)
463                        value = DockPanel.DockWindows[DockState.Document].DefaultPane;
464                    else if (ActiveDocumentPane.DockPanel != DockPanel || ActiveDocumentPane.DockState != DockState.Document)
465                        value = DockPanel.DockWindows[DockState.Document].DefaultPane;
466                    else
467                        value = ActiveDocumentPane;
468                }
469
470                if (m_activeDocumentPane == value)
471                    return;
472
473                if (m_activeDocumentPane != null)
474                    m_activeDocumentPane.SetIsActiveDocumentPane(false);
475
476                m_activeDocumentPane = value;
477
478                if (m_activeDocumentPane != null)
479                    m_activeDocumentPane.SetIsActiveDocumentPane(true);
480            }
481
482            private IDockContent m_activeDocument = null;
483            public IDockContent ActiveDocument
484            {
485                get { return m_activeDocument; }
486            }
487
488            private void SetActiveDocument()
489            {
490                IDockContent value = ActiveDocumentPane == null ? null : ActiveDocumentPane.ActiveContent;
491
492                if (m_activeDocument == value)
493                    return;
494
495                m_activeDocument = value;
496            }
497        }
498
499        private IFocusManager FocusManager
500        {
501            get { return m_focusManager; }
502        }
503
504        internal IContentFocusManager ContentFocusManager
505        {
506            get { return m_focusManager; }
507        }
508
509        internal void SaveFocus()
510        {
511            DummyControl.Focus();
512        }
513
514        [Browsable(false)]
515        public IDockContent ActiveContent
516        {
517            get { return FocusManager.ActiveContent; }
518        }
519
520        [Browsable(false)]
521        public DockPane ActivePane
522        {
523            get { return FocusManager.ActivePane; }
524        }
525
526        [Browsable(false)]
527        public IDockContent ActiveDocument
528        {
529            get { return FocusManager.ActiveDocument; }
530        }
531
532        [Browsable(false)]
533        public DockPane ActiveDocumentPane
534        {
535            get { return FocusManager.ActiveDocumentPane; }
536        }
537
538        private static readonly object ActiveDocumentChangedEvent = new object();
539        [LocalizedCategory("Category_PropertyChanged")]
540        [LocalizedDescription("DockPanel_ActiveDocumentChanged_Description")]
541        public event EventHandler ActiveDocumentChanged
542        {
543            add { Events.AddHandler(ActiveDocumentChangedEvent, value); }
544            remove { Events.RemoveHandler(ActiveDocumentChangedEvent, value); }
545        }
546        protected virtual void OnActiveDocumentChanged(EventArgs e)
547        {
548            EventHandler handler = (EventHandler)Events[ActiveDocumentChangedEvent];
549            if (handler != null)
550                handler(this, e);
551        }
552
553        private static readonly object ActiveContentChangedEvent = new object();
554        [LocalizedCategory("Category_PropertyChanged")]
555        [LocalizedDescription("DockPanel_ActiveContentChanged_Description")]
556        public event EventHandler ActiveContentChanged
557        {
558            add { Events.AddHandler(ActiveContentChangedEvent, value); }
559            remove { Events.RemoveHandler(ActiveContentChangedEvent, value); }
560        }
561        protected void OnActiveContentChanged(EventArgs e)
562        {
563            EventHandler handler = (EventHandler)Events[ActiveContentChangedEvent];
564            if (handler != null)
565                handler(this, e);
566        }
567
568        private static readonly object ActivePaneChangedEvent = new object();
569        [LocalizedCategory("Category_PropertyChanged")]
570        [LocalizedDescription("DockPanel_ActivePaneChanged_Description")]
571        public event EventHandler ActivePaneChanged
572        {
573            add { Events.AddHandler(ActivePaneChangedEvent, value); }
574            remove { Events.RemoveHandler(ActivePaneChangedEvent, value); }
575        }
576        protected virtual void OnActivePaneChanged(EventArgs e)
577        {
578            EventHandler handler = (EventHandler)Events[ActivePaneChangedEvent];
579            if (handler != null)
580                handler(this, e);
581        }
582    }
583}
Note: See TracBrowser for help on using the repository browser.