Free cookie consent management tool by TermsFeed Policy Generator

source: branches/Persistence Test/WinFormsUI/Docking/DockPanel.FocusManager.cs @ 3708

Last change on this file since 3708 was 2134, checked in by gkronber, 15 years ago

Added up to date source of Weifen Luo dock panel suit in a separate project (and added strong name key). Removed binary versions of Weifen Luo dock panel suite and references to it. #687 (Update AdvancedOptimizationFrontend to use more recent version of Weifen Luo Docking library)

File size: 20.3 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 LocalWindowsHook m_localWindowsHook;
122            private LocalWindowsHook.HookEventHandler m_hookEventHandler;
123
124            public FocusManagerImpl(DockPanel dockPanel)
125            {
126                m_dockPanel = dockPanel;
127                m_localWindowsHook = new LocalWindowsHook(Win32.HookType.WH_CALLWNDPROCRET);
128                m_hookEventHandler = new LocalWindowsHook.HookEventHandler(HookEventHandler);
129                m_localWindowsHook.HookInvoked += m_hookEventHandler;
130                m_localWindowsHook.Install();
131            }
132
133            private DockPanel m_dockPanel;
134            public DockPanel DockPanel
135            {
136                get { return m_dockPanel; }
137            }
138
139            private bool m_disposed = false;
140            protected override void Dispose(bool disposing)
141            {
142                lock (this)
143                {
144                    if (!m_disposed && disposing)
145                    {
146                        m_localWindowsHook.Dispose();
147                        m_disposed = true;
148                    }
149
150                    base.Dispose(disposing);
151                }
152            }
153
154            private IDockContent m_contentActivating = null;
155            private IDockContent ContentActivating
156            {
157                get { return m_contentActivating; }
158                set { m_contentActivating = value; }
159            }
160
161            public void Activate(IDockContent content)
162            {
163                if (IsFocusTrackingSuspended)
164                {
165                    ContentActivating = content;
166                    return;
167                }
168
169                if (content == null)
170                    return;
171                DockContentHandler handler = content.DockHandler;
172                if (handler.Form.IsDisposed)
173                    return; // Should not reach here, but better than throwing an exception
174                if (ContentContains(content, handler.ActiveWindowHandle))
175                    NativeMethods.SetFocus(handler.ActiveWindowHandle);
176                if (!handler.Form.ContainsFocus)
177                {
178                    if (!handler.Form.SelectNextControl(handler.Form.ActiveControl, true, true, true, true))
179                        // Since DockContent Form is not selectalbe, use Win32 SetFocus instead
180                        NativeMethods.SetFocus(handler.Form.Handle);
181                }
182            }
183
184            private List<IDockContent> m_listContent = new List<IDockContent>();
185            private List<IDockContent> ListContent
186            {
187                get { return m_listContent; }
188            }
189            public void AddToList(IDockContent content)
190            {
191                if (ListContent.Contains(content) || IsInActiveList(content))
192                    return;
193
194                ListContent.Add(content);
195            }
196
197            public void RemoveFromList(IDockContent content)
198            {
199                if (IsInActiveList(content))
200                    RemoveFromActiveList(content);
201                if (ListContent.Contains(content))
202                    ListContent.Remove(content);
203            }
204
205            private IDockContent m_lastActiveContent = null;
206            private IDockContent LastActiveContent
207            {
208                get { return m_lastActiveContent; }
209                set { m_lastActiveContent = value; }
210            }
211
212            private bool IsInActiveList(IDockContent content)
213            {
214                return !(content.DockHandler.NextActive == null && LastActiveContent != content);
215            }
216
217            private void AddLastToActiveList(IDockContent content)
218            {
219                IDockContent last = LastActiveContent;
220                if (last == content)
221                    return;
222
223                DockContentHandler handler = content.DockHandler;
224
225                if (IsInActiveList(content))
226                    RemoveFromActiveList(content);
227
228                handler.PreviousActive = last;
229                handler.NextActive = null;
230                LastActiveContent = content;
231                if (last != null)
232                    last.DockHandler.NextActive = LastActiveContent;
233            }
234
235            private void RemoveFromActiveList(IDockContent content)
236            {
237                if (LastActiveContent == content)
238                    LastActiveContent = content.DockHandler.PreviousActive;
239
240                IDockContent prev = content.DockHandler.PreviousActive;
241                IDockContent next = content.DockHandler.NextActive;
242                if (prev != null)
243                    prev.DockHandler.NextActive = next;
244                if (next != null)
245                    next.DockHandler.PreviousActive = prev;
246
247                content.DockHandler.PreviousActive = null;
248                content.DockHandler.NextActive = null;
249            }
250
251            public void GiveUpFocus(IDockContent content)
252            {
253                DockContentHandler handler = content.DockHandler;
254                if (!handler.Form.ContainsFocus)
255                    return;
256
257                if (IsFocusTrackingSuspended)
258                    DockPanel.DummyControl.Focus();
259
260                if (LastActiveContent == content)
261                {
262                    IDockContent prev = handler.PreviousActive;
263                    if (prev != null)
264                        Activate(prev);
265                    else if (ListContent.Count > 0)
266                        Activate(ListContent[ListContent.Count - 1]);
267                }
268                else if (LastActiveContent != null)
269                    Activate(LastActiveContent);
270                else if (ListContent.Count > 0)
271                    Activate(ListContent[ListContent.Count - 1]);
272            }
273
274            private static bool ContentContains(IDockContent content, IntPtr hWnd)
275            {
276                Control control = Control.FromChildHandle(hWnd);
277                for (Control parent = control; parent != null; parent = parent.Parent)
278                    if (parent == content.DockHandler.Form)
279                        return true;
280
281                return false;
282            }
283
284            private int m_countSuspendFocusTracking = 0;
285            public void SuspendFocusTracking()
286            {
287                m_countSuspendFocusTracking++;
288                m_localWindowsHook.HookInvoked -= m_hookEventHandler;
289            }
290
291            public void ResumeFocusTracking()
292            {
293                if (m_countSuspendFocusTracking > 0)
294                    m_countSuspendFocusTracking--;
295
296                if (m_countSuspendFocusTracking == 0)
297                {
298                    if (ContentActivating != null)
299                    {
300                        Activate(ContentActivating);
301                        ContentActivating = null;
302                    }
303                    m_localWindowsHook.HookInvoked += m_hookEventHandler;
304                    if (!InRefreshActiveWindow)
305                        RefreshActiveWindow();
306                }
307            }
308
309            public bool IsFocusTrackingSuspended
310            {
311                get { return m_countSuspendFocusTracking != 0; }
312            }
313
314            // Windows hook event handler
315            private void HookEventHandler(object sender, HookEventArgs e)
316            {
317                Win32.Msgs msg = (Win32.Msgs)Marshal.ReadInt32(e.lParam, IntPtr.Size * 3);
318
319                if (msg == Win32.Msgs.WM_KILLFOCUS)
320                {
321                    IntPtr wParam = Marshal.ReadIntPtr(e.lParam, IntPtr.Size * 2);
322                    DockPane pane = GetPaneFromHandle(wParam);
323                    if (pane == null)
324                        RefreshActiveWindow();
325                }
326                else if (msg == Win32.Msgs.WM_SETFOCUS)
327                    RefreshActiveWindow();
328            }
329
330            private DockPane GetPaneFromHandle(IntPtr hWnd)
331            {
332                Control control = Control.FromChildHandle(hWnd);
333
334                IDockContent content = null;
335                DockPane pane = null;
336                for (; control != null; control = control.Parent)
337                {
338                    content = control as IDockContent;
339                    if (content != null)
340                        content.DockHandler.ActiveWindowHandle = hWnd;
341
342                    if (content != null && content.DockHandler.DockPanel == DockPanel)
343                        return content.DockHandler.Pane;
344
345                    pane = control as DockPane;
346                    if (pane != null && pane.DockPanel == DockPanel)
347                        break;
348                }
349
350                return pane;
351            }
352
353            private bool m_inRefreshActiveWindow = false;
354            private bool InRefreshActiveWindow
355            {
356                get { return m_inRefreshActiveWindow; }
357            }
358
359            private void RefreshActiveWindow()
360            {
361                SuspendFocusTracking();
362                m_inRefreshActiveWindow = true;
363
364                DockPane oldActivePane = ActivePane;
365                IDockContent oldActiveContent = ActiveContent;
366                IDockContent oldActiveDocument = ActiveDocument;
367
368                SetActivePane();
369                SetActiveContent();
370                SetActiveDocumentPane();
371                SetActiveDocument();
372                DockPanel.AutoHideWindow.RefreshActivePane();
373
374                ResumeFocusTracking();
375                m_inRefreshActiveWindow = false;
376
377                if (oldActiveContent != ActiveContent)
378                    DockPanel.OnActiveContentChanged(EventArgs.Empty);
379                if (oldActiveDocument != ActiveDocument)
380                    DockPanel.OnActiveDocumentChanged(EventArgs.Empty);
381                if (oldActivePane != ActivePane)
382                    DockPanel.OnActivePaneChanged(EventArgs.Empty);
383            }
384
385            private DockPane m_activePane = null;
386            public DockPane ActivePane
387            {
388                get { return m_activePane; }
389            }
390
391            private void SetActivePane()
392            {
393                DockPane value = GetPaneFromHandle(NativeMethods.GetFocus());
394                if (m_activePane == value)
395                    return;
396
397                if (m_activePane != null)
398                    m_activePane.SetIsActivated(false);
399
400                m_activePane = value;
401
402                if (m_activePane != null)
403                    m_activePane.SetIsActivated(true);
404            }
405
406            private IDockContent m_activeContent = null;
407            public IDockContent ActiveContent
408            {
409                get { return m_activeContent; }
410            }
411
412            internal void SetActiveContent()
413            {
414                IDockContent value = ActivePane == null ? null : ActivePane.ActiveContent;
415
416                if (m_activeContent == value)
417                    return;
418
419                if (m_activeContent != null)
420                    m_activeContent.DockHandler.IsActivated = false;
421
422                m_activeContent = value;
423
424                if (m_activeContent != null)
425                {
426                    m_activeContent.DockHandler.IsActivated = true;
427                    if (!DockHelper.IsDockStateAutoHide((m_activeContent.DockHandler.DockState)))
428                        AddLastToActiveList(m_activeContent);
429                }
430            }
431
432            private DockPane m_activeDocumentPane = null;
433            public DockPane ActiveDocumentPane
434            {
435                get { return m_activeDocumentPane; }
436            }
437
438            private void SetActiveDocumentPane()
439            {
440                DockPane value = null;
441
442                if (ActivePane != null && ActivePane.DockState == DockState.Document)
443                    value = ActivePane;
444
445                if (value == null && DockPanel.DockWindows != null)
446                {
447                    if (ActiveDocumentPane == null)
448                        value = DockPanel.DockWindows[DockState.Document].DefaultPane;
449                    else if (ActiveDocumentPane.DockPanel != DockPanel || ActiveDocumentPane.DockState != DockState.Document)
450                        value = DockPanel.DockWindows[DockState.Document].DefaultPane;
451                    else
452                        value = ActiveDocumentPane;
453                }
454
455                if (m_activeDocumentPane == value)
456                    return;
457
458                if (m_activeDocumentPane != null)
459                    m_activeDocumentPane.SetIsActiveDocumentPane(false);
460
461                m_activeDocumentPane = value;
462
463                if (m_activeDocumentPane != null)
464                    m_activeDocumentPane.SetIsActiveDocumentPane(true);
465            }
466
467            private IDockContent m_activeDocument = null;
468            public IDockContent ActiveDocument
469            {
470                get { return m_activeDocument; }
471            }
472
473            private void SetActiveDocument()
474            {
475                IDockContent value = ActiveDocumentPane == null ? null : ActiveDocumentPane.ActiveContent;
476
477                if (m_activeDocument == value)
478                    return;
479
480                m_activeDocument = value;
481            }
482        }
483
484        private IFocusManager FocusManager
485        {
486            get { return m_focusManager; }
487        }
488
489        internal IContentFocusManager ContentFocusManager
490        {
491            get { return m_focusManager; }
492        }
493
494        internal void SaveFocus()
495        {
496            DummyControl.Focus();
497        }
498
499        [Browsable(false)]
500        public IDockContent ActiveContent
501        {
502            get { return FocusManager.ActiveContent; }
503        }
504
505        [Browsable(false)]
506        public DockPane ActivePane
507        {
508            get { return FocusManager.ActivePane; }
509        }
510
511        [Browsable(false)]
512        public IDockContent ActiveDocument
513        {
514            get { return FocusManager.ActiveDocument; }
515        }
516
517        [Browsable(false)]
518        public DockPane ActiveDocumentPane
519        {
520            get { return FocusManager.ActiveDocumentPane; }
521        }
522
523        private static readonly object ActiveDocumentChangedEvent = new object();
524        [LocalizedCategory("Category_PropertyChanged")]
525        [LocalizedDescription("DockPanel_ActiveDocumentChanged_Description")]
526        public event EventHandler ActiveDocumentChanged
527        {
528            add { Events.AddHandler(ActiveDocumentChangedEvent, value); }
529            remove { Events.RemoveHandler(ActiveDocumentChangedEvent, value); }
530        }
531        protected virtual void OnActiveDocumentChanged(EventArgs e)
532        {
533            EventHandler handler = (EventHandler)Events[ActiveDocumentChangedEvent];
534            if (handler != null)
535                handler(this, e);
536        }
537
538        private static readonly object ActiveContentChangedEvent = new object();
539        [LocalizedCategory("Category_PropertyChanged")]
540        [LocalizedDescription("DockPanel_ActiveContentChanged_Description")]
541        public event EventHandler ActiveContentChanged
542        {
543            add { Events.AddHandler(ActiveContentChangedEvent, value); }
544            remove { Events.RemoveHandler(ActiveContentChangedEvent, value); }
545        }
546        protected void OnActiveContentChanged(EventArgs e)
547        {
548            EventHandler handler = (EventHandler)Events[ActiveContentChangedEvent];
549            if (handler != null)
550                handler(this, e);
551        }
552
553        private static readonly object ActivePaneChangedEvent = new object();
554        [LocalizedCategory("Category_PropertyChanged")]
555        [LocalizedDescription("DockPanel_ActivePaneChanged_Description")]
556        public event EventHandler ActivePaneChanged
557        {
558            add { Events.AddHandler(ActivePaneChangedEvent, value); }
559            remove { Events.RemoveHandler(ActivePaneChangedEvent, value); }
560        }
561        protected virtual void OnActivePaneChanged(EventArgs e)
562        {
563            EventHandler handler = (EventHandler)Events[ActivePaneChangedEvent];
564            if (handler != null)
565                handler(this, e);
566        }
567    }
568}
Note: See TracBrowser for help on using the repository browser.