Coverage Report - org.openpermis.editor.policy.gui.dock.DockControl
 
Classes in this File Line Coverage Branch Coverage Complexity
DockControl
0%
0/102
0%
0/42
1.868
DockControl$1
0%
0/3
N/A
1.868
DockControl$2
0%
0/3
N/A
1.868
DockControl$3
0%
0/3
N/A
1.868
DockControl$4
0%
0/3
N/A
1.868
DockControl$5
0%
0/9
N/A
1.868
DockControl$6
0%
0/8
N/A
1.868
DockControl$ViewMonitor
0%
0/61
0%
0/18
1.868
DockControl$ViewMonitor$1
0%
0/5
0%
0/2
1.868
DockControl$ViewMonitor$2
0%
0/4
N/A
1.868
 
 1  
 /*
 2  
  * Copyright (c) 2009, Swiss Federal Department of Defence Civil Protection and Sport
 3  
  *                     (http://www.vbs.admin.ch)
 4  
  * Copyright (c) 2009, Ergon Informatik AG (http://www.ergon.ch)
 5  
  * All rights reserved.
 6  
  *
 7  
  * Licensed under the Open Permis License which accompanies this distribution,
 8  
  * and is available at http://www.openpermis.org/BSDlicenceKent.txt
 9  
  */
 10  
 package org.openpermis.editor.policy.gui.dock;
 11  
 
 12  
 import static java.awt.KeyboardFocusManager.getCurrentKeyboardFocusManager;
 13  
 
 14  
 import java.awt.Component;
 15  
 import java.awt.Container;
 16  
 import java.awt.FocusTraversalPolicy;
 17  
 import java.util.Collections;
 18  
 import java.util.HashMap;
 19  
 import java.util.HashSet;
 20  
 import java.util.Map;
 21  
 import java.util.Set;
 22  
 
 23  
 import javax.swing.JComponent;
 24  
 import javax.swing.JFrame;
 25  
 import javax.swing.SwingUtilities;
 26  
 
 27  
 import org.jabuki.dock.theme.mercury.theme.CMercuryControl;
 28  
 import org.jabuki.dock.theme.mercury.theme.CMercuryTheme;
 29  
 import org.jabuki.dock.theme.mercury.theme.MercuryResources;
 30  
 
 31  
 import bibliothek.gui.dock.common.CControl;
 32  
 import bibliothek.gui.dock.common.CLocation;
 33  
 import bibliothek.gui.dock.common.CWorkingArea;
 34  
 import bibliothek.gui.dock.common.action.predefined.CCloseAction;
 35  
 import bibliothek.gui.dock.common.event.CDockableStateListener;
 36  
 import bibliothek.gui.dock.common.event.CFocusListener;
 37  
 import bibliothek.gui.dock.common.intern.CDockable;
 38  
 import bibliothek.gui.dock.common.intern.DefaultCDockable;
 39  
 
 40  
 import org.openpermis.editor.policy.gui.event.EventDispatcher;
 41  
 import org.openpermis.editor.policy.gui.event.EventSupport;
 42  
 import org.openpermis.editor.policy.view.Editor;
 43  
 import org.openpermis.editor.policy.view.Tool;
 44  
 import org.openpermis.editor.policy.view.View;
 45  
 
 46  
 /**
 47  
  * Control that manages all dockables and the swing components of the main frame.
 48  
  * @since 0.1.0
 49  
  */
 50  0
 public class DockControl {
 51  
 
 52  
         //---- Static
 53  
         
 54  
         /**
 55  
          * Unique string identifier for the working area.
 56  
          * @see CWorkingArea
 57  
          * @since 0.1.0
 58  
          */
 59  
         private static final String WORKING_AREA = "WorkingArea";
 60  
 
 61  
         //---- State
 62  
         
 63  
         /**
 64  
          * The common control of the docking framework wrapped by this class.
 65  
          * @since 0.1.0
 66  
          */
 67  
         private final CControl control;
 68  
         
 69  
         /**
 70  
          * Factory used to create new editor dockables.
 71  
          * @since 0.1.0
 72  
          */
 73  
         private final EditorFactory factory;
 74  
         
 75  
         /**
 76  
          * The working area used by this dock control.
 77  
          * @since 0.1.0
 78  
          */
 79  
         private final CWorkingArea workingArea;
 80  
         
 81  
         /**
 82  
          * The event support of this dock control.
 83  
          * @since 0.1.0
 84  
          */
 85  
         private final EventSupport<DockControlListener> eventSupport;
 86  
         
 87  
         /**
 88  
          * The editors managed by this control.
 89  
          * @since 0.1.0
 90  
          */
 91  
         private final Map<Editor, ViewMonitor<EditorDockable>> editors;
 92  
         
 93  
         /**
 94  
          * The tools managed by this control.
 95  
          * @since 0.1.0
 96  
          */
 97  
         private final Map<Tool, ViewMonitor<ToolDockable>> tools;
 98  
         
 99  
         //---- Constructors
 100  
         
 101  
         /**
 102  
          * Creates a new dock control for the specified owner frame.
 103  
          * @param frame the frame used as owner for externally opened views.
 104  
          * @since 0.1.0
 105  
          */
 106  0
         public DockControl (JFrame frame) {
 107  0
                 this.editors = new HashMap<Editor, ViewMonitor<EditorDockable>>();
 108  0
                 this.tools = new HashMap<Tool, ViewMonitor<ToolDockable>>();
 109  0
                 this.eventSupport = new EventSupport<DockControlListener>();
 110  0
                 this.factory = createFactory();
 111  0
                 this.control = createControl(frame);
 112  0
                 this.workingArea = createWorkingArea(this.control, this.factory);
 113  0
         }
 114  
         
 115  
         //---- Methods
 116  
         
 117  
         /**
 118  
          * Adds a listener for dock control events.
 119  
          * <p>The same {@code listener} object may be added more than once, and will be called as many 
 120  
          * times as it is added.</p>
 121  
          * <p>If the {@code listener} is {@code null}, no action is taken.</p>
 122  
          * @param listener the listener to add, may be {@code null}.
 123  
          * @since 0.1.0
 124  
          */
 125  
         public void addDockControlListener (DockControlListener listener) {
 126  0
                 this.eventSupport.addListener(listener);
 127  0
         }
 128  
         
 129  
         /**
 130  
          * Removes a listener from this dock control.
 131  
          * <p>If the same {@code listener} was added more than once, it will be notified one less
 132  
          * time after being removed.</p>
 133  
          * <p>If the {@code listener} is {@code null}, or was never added, no action is taken.</p>
 134  
          * @param listener the listener to be removed, may be {@code null}.
 135  
          */
 136  
         public void removeDockControlListener (DockControlListener listener) {
 137  0
                 this.eventSupport.removeListener(listener);
 138  0
         }
 139  
         
 140  
         /**
 141  
          * Fires an event that the specified view has been opened.
 142  
          * @param view the view that has been opened.
 143  
          * @since 0.1.0
 144  
          */
 145  
         private void fireViewOpened (final View view) {
 146  0
                 this.eventSupport.dispatchEvent(
 147  
                         new EventDispatcher<DockControlListener>() {
 148  0
                                 public void dispatch (DockControlListener listener) {
 149  0
                                         listener.viewOpened(view);
 150  0
                                 }
 151  
                         }
 152  
                 );
 153  0
         }
 154  
         
 155  
         /**
 156  
          * Fires an event that the specified view has been closed.
 157  
          * @param view the view that has been closed.
 158  
          * @since 0.1.0
 159  
          */
 160  
         private void fireViewClosed (final View view) {
 161  0
                 this.eventSupport.dispatchEvent(
 162  
                         new EventDispatcher<DockControlListener>() {
 163  0
                                 public void dispatch (DockControlListener listener) {
 164  0
                                         listener.viewClosed(view);
 165  0
                                 }
 166  
                         }
 167  
                 );
 168  0
         }
 169  
         
 170  
         /**
 171  
          * Fires an event that the specified view has been activated.
 172  
          * @param view the view that has been activated.
 173  
          * @since 0.1.0
 174  
          */
 175  
         private void fireViewActivated (final View view) {
 176  0
                 this.eventSupport.dispatchEvent(
 177  
                         new EventDispatcher<DockControlListener>() {
 178  0
                                 public void dispatch (DockControlListener listener) {
 179  0
                                         listener.viewActivated(view);
 180  0
                                 }
 181  
                         }
 182  
                 );
 183  0
         }
 184  
         
 185  
         /**
 186  
          * Fires an event that the specified view has been deactivated.
 187  
          * @param view the view that has been deactivated.
 188  
          * @since 0.1.0
 189  
          */
 190  
         private void fireViewDeactivated (final View view) {
 191  0
                 this.eventSupport.dispatchEvent(
 192  
                         new EventDispatcher<DockControlListener>() {
 193  0
                                 public void dispatch (DockControlListener listener) {
 194  0
                                         listener.viewDeactivated(view);
 195  0
                                 }
 196  
                         }
 197  
                 );
 198  0
         }
 199  
         
 200  
         /**
 201  
          * Creates the factory used to create new editor dockables.
 202  
          * @return the factory requested.
 203  
          * @since 0.1.0
 204  
          */
 205  
         private EditorFactory createFactory () {
 206  0
                 return new EditorFactory();
 207  
         }
 208  
         
 209  
         /**
 210  
          * Creates a new control that is used internally to manage dockables.
 211  
          * @param frame the frame used as owner for externally opened views.
 212  
          * @return the control requested.
 213  
          * @since 0.1.0
 214  
          */
 215  
         private CControl createControl (JFrame frame) {
 216  0
                 final CControl ccontrol = new CMercuryControl(frame, false);
 217  0
                 CMercuryTheme.addTheme(ccontrol);
 218  0
                 ccontrol.setTheme(MercuryResources.THEME_NAME);
 219  
                 // final CControl ccontrol = new CControl(frame, new ControlFactory());
 220  
                 //ccontrol.setTheme(ThemeMap.KEY_ECLIPSE_THEME);
 221  
                 //ccontrol.setTheme(ThemeMap.KEY_BASIC_THEME);
 222  
                 //ccontrol.putProperty(EclipseTheme.PAINT_ICONS_WHEN_DESELECTED, Boolean.TRUE);
 223  
                 // It is imperative to get the content area of the control before any dockables
 224  
                 // are attached otherwise they will not be contained in the content area.
 225  
                 // This is an undocumented implementation detail of the docking framework. 
 226  0
                 ccontrol.getContentArea();
 227  0
                 return ccontrol;
 228  
         }
 229  
         
 230  
         /**
 231  
          * Creates a new working area at the specified control for the given factory.
 232  
          * @param ccontrol the control at which to create the working area.
 233  
          * @param editorFactory the editor factory to use.
 234  
          * @return the working area requested.
 235  
          * @since 0.1.0
 236  
          */
 237  
         private CWorkingArea createWorkingArea (CControl ccontrol, EditorFactory editorFactory) {
 238  0
                 final CWorkingArea cworkingArea = ccontrol.createWorkingArea(WORKING_AREA);
 239  0
                 cworkingArea.setLocation(CLocation.base().normalRectangle(0, 0, 1, 1));
 240  0
                 cworkingArea.setVisible(true);
 241  0
                 ccontrol.addMultipleDockableFactory(WORKING_AREA, editorFactory);
 242  0
                 return cworkingArea;
 243  
         }
 244  
         
 245  
         /**
 246  
          * Returns the content area of this dock control.
 247  
          * <p>The content area contains all tool and editor dockables and serves
 248  
          * as the main content of the editor window.</p>
 249  
          * @return the content area requested.
 250  
          * @since 0.1.0
 251  
          */
 252  
         public JComponent getContentArea () {
 253  0
                 return this.control.getContentArea();
 254  
         }
 255  
         
 256  
         /**
 257  
          * Updates the title of the dockable this view is attached to.
 258  
          * @param view the view for which to update the title.
 259  
          * @since 0.1.0
 260  
          */
 261  
         public void updateViewTitle (View view) {
 262  0
                 if (view instanceof Editor) {
 263  0
                         final ViewMonitor<EditorDockable> editor = this.editors.get(view);
 264  0
                         if (editor != null && editor.getDockable() != null) {
 265  0
                                 editor.getDockable().updateTitle();
 266  
                         }
 267  0
                 } else if (view instanceof Tool) {
 268  0
                         final ViewMonitor<ToolDockable> tool = this.tools.get(view);
 269  0
                         if (tool != null && tool.getDockable() != null) {
 270  0
                                 tool.getDockable().updateTitle();
 271  
                         }
 272  
                 }
 273  0
         }
 274  
         
 275  
         /**
 276  
          * Creates a dockable of appropriate type for the specified view and displays it.
 277  
          * <p>If the view is already open it is activated.</p>
 278  
          * <p>Supports {@link Tool} and {@link Editor} views.</p>
 279  
          * @param view the view to display.
 280  
          * @throws IllegalArgumentException if the view type is not supported.
 281  
          * @since 0.1.0
 282  
          */
 283  
         public void openView (View view) {
 284  0
                 if (view instanceof Tool) {
 285  0
                         openToolView((Tool) view);
 286  0
                         return;
 287  0
                 } else if (view instanceof Editor) {
 288  0
                         openEditorView((Editor) view);
 289  0
                         return;
 290  
                 }
 291  0
                 final String viewType = view == null ? "null" : view.getClass().getSimpleName();
 292  0
                 throw new IllegalArgumentException("Unsupported view type [" + viewType + "].");
 293  
         }
 294  
         
 295  
         /**
 296  
          * Creates a new editor dockable for the specified view and displays the view
 297  
          * in the center of the working area.
 298  
          * @param view the view for which to create the editor dockable.
 299  
          * @since 0.1.0
 300  
          */
 301  
         private void openEditorView (final Editor view) {
 302  0
                 if (this.editors.get(view) != null) {
 303  
                         // View is already visible, this will cause to focus it.
 304  0
                         this.editors.get(view).openDockable();
 305  
                 } else {
 306  0
                         final EditorDockable editor = new EditorDockable(this.factory, view);
 307  0
                         final ViewMonitor<EditorDockable> monitor = 
 308  
                                 new ViewMonitor<EditorDockable>(editor, view) {
 309  
                                         @Override
 310  
                                         protected void viewDestroyed () {
 311  0
                                                 super.viewDestroyed();
 312  0
                                                 DockControl.this.editors.remove(view);
 313  0
                                         }
 314  
                                         @Override
 315  
                                         protected void viewClosed () {
 316  
                                                 // The docking framework destroys editors internally, sic!
 317  0
                                                 viewDestroyed();
 318  0
                                         }
 319  
                                         @Override
 320  0
                                         public void closeDockable () {
 321  0
                                                 super.closeDockable();
 322  
                                                 // The docking framework destroys editors internally, sic!
 323  0
                                                 viewDestroyed();
 324  0
                                         }
 325  
                                 };
 326  0
                         editor.setLocation(CLocation.working(this.workingArea).rectangle(0, 0, 1, 1));
 327  0
                         this.workingArea.add(editor);
 328  0
                         this.editors.put(view, monitor);
 329  0
                         monitor.openDockable();
 330  
                 }
 331  0
         }
 332  
         
 333  
         /**
 334  
          * Creates a new tool dockable for the specified view and displays the view
 335  
          * at the given location.
 336  
          * @param view the view to display as a tool dockable.
 337  
          * @since 0.1.0
 338  
          */
 339  
         private void openToolView (final Tool view) {
 340  0
                 if (this.tools.get(view) != null) {
 341  
                         // View has been hidden, reopen.
 342  0
                         this.tools.get(view).openDockable();
 343  
                 } else {
 344  0
                         final ToolDockable tool = new ToolDockable(view);
 345  0
                         final ViewMonitor<ToolDockable> monitor = 
 346  
                                 new ViewMonitor<ToolDockable>(tool, view) {
 347  
                                         @Override
 348  
                                         public void destroyDockable () {
 349  
                                                 // Destroy completely different for tools.
 350  0
                                                 DockControl.this.control.remove(getDockable());
 351  0
                                                 viewDestroyed();
 352  0
                                         }
 353  
                                         @Override
 354  
                                         protected void viewDestroyed () {
 355  0
                                                 super.viewDestroyed();
 356  0
                                                 DockControl.this.tools.remove(view);
 357  0
                                         }
 358  
                                         @Override
 359  0
                                         protected boolean canCloseView () {
 360  
                                                 // Tool views do not get asked.
 361  0
                                                 return true;
 362  
                                         }
 363  
                                 };
 364  0
                         this.control.add(tool);
 365  0
                         tool.setLocation(view.getDefaultLocation());
 366  0
                         this.tools.put(view, monitor);
 367  0
                         monitor.openDockable();
 368  
                 }
 369  0
         }
 370  
         
 371  
         /**
 372  
          * Returns all view currently attached to this dock control.
 373  
          * @return the set of views requested, never {@code null}.
 374  
          * @since 0.1.0
 375  
          */
 376  
         public Set<View> getViews () {
 377  0
                 final Set<View> views = new HashSet<View>();
 378  0
                 views.addAll(this.tools.keySet());
 379  0
                 views.addAll(this.editors.keySet());
 380  0
                 return Collections.unmodifiableSet(views);
 381  
         }
 382  
         
 383  
         /**
 384  
          * Checks if a view is open.
 385  
          * @param view the view to check.
 386  
          * @return {@code true} if the view is open.
 387  
          * @since 0.1.0
 388  
          */
 389  
         public boolean isViewOpen (View view) {
 390  0
                 if (view instanceof Tool) {
 391  0
                         final ViewMonitor<ToolDockable> manager = this.tools.get(view);
 392  
                         // Tool views may be hidden.
 393  0
                         return manager.getDockable().isVisible();
 394  0
                 } else if (view instanceof Editor) {
 395  0
                         return this.editors.get(view) != null;
 396  
                 }
 397  0
                 return false;
 398  
         }
 399  
         
 400  
         /**
 401  
          * Returns a set of all tool views currently attached to this dock control.
 402  
          * @return the set requested, never {@code null}.
 403  
          * @since 0.1.0
 404  
          */
 405  
         public Set<Tool> getToolViews () {
 406  0
                 return Collections.unmodifiableSet(new HashSet<Tool>(this.tools.keySet()));
 407  
         }
 408  
         
 409  
         /**
 410  
          * Returns a set of all editor views currently attached to this dock control.
 411  
          * @return the set requested, never {@code null}.
 412  
          * @since 0.1.0
 413  
          */
 414  
         public Set<Editor> getEditorViews () {
 415  0
                 return Collections.unmodifiableSet(new HashSet<Editor>(this.editors.keySet()));
 416  
         }
 417  
         
 418  
         /**
 419  
          * Removes the dockable responsible for the view specified.
 420  
          * @param view the view to remove.
 421  
          * @param force {@code true} to force closing the view.
 422  
          * @return {@code true} if the dockable was removed.
 423  
          * @since 0.1.0
 424  
          */
 425  
         public boolean closeView (View view, boolean force) {
 426  0
                 if (view instanceof Tool) {
 427  0
                         return closeToolView((Tool) view, force);
 428  0
                 } else if (view instanceof Editor) {
 429  0
                         return closeEditorView((Editor) view, force);
 430  
                 }
 431  0
                 final String viewType = view == null ? "null" : view.getClass().getSimpleName();
 432  0
                 throw new IllegalArgumentException("Unsupported view type [" + viewType + "].");
 433  
         }
 434  
         
 435  
         /**
 436  
          * Removes the dockable responsible for the view specified.
 437  
          * @param view the view to remove.
 438  
          * @param force {@code true} to force closing the view.
 439  
          * @return {@code true} if the dockable was removed.
 440  
          * @since 0.1.0
 441  
          */
 442  
         private boolean closeEditorView (Editor view, boolean force) {
 443  0
                 final ViewMonitor<EditorDockable> monitor = this.editors.get(view);
 444  0
                 if (monitor != null) {
 445  0
                         if (force) {
 446  0
                                 monitor.destroyDockable();
 447  0
                                 return true;
 448  
                         }
 449  0
                         monitor.closeDockable();
 450  0
                         return monitor.getDockable().isVisible();
 451  
                 }
 452  0
                 return false;
 453  
         }
 454  
         
 455  
         /**
 456  
          * Removes the dockable responsible for the view specified.
 457  
          * @param view the view to remove.
 458  
          * @param force {@code true} to force closing the view.
 459  
          * @return {@code true} if the dockable was removed.
 460  
          * @since 0.1.0
 461  
          */
 462  
         private boolean closeToolView (Tool view, boolean force) {
 463  0
                 final ViewMonitor<ToolDockable> monitor = this.tools.get(view);
 464  0
                 if (monitor != null) {
 465  0
                         if (force) {
 466  0
                                 monitor.destroyDockable();
 467  0
                                 return true;
 468  
                         }
 469  0
                         monitor.closeDockable();
 470  0
                         return true;
 471  
                 }
 472  0
                 return false;
 473  
         }
 474  
         
 475  
         //---- ViewMonitor
 476  
         
 477  
         /**
 478  
          * Monitor for views and dockables.
 479  
          * <p>Since the underlying dockable framework fires open/close and focus events out of
 480  
          * sync this monitor asserts that the events get fired in proper order.</p>
 481  
          * @param <T> the type of dockable of this monitor.
 482  
          * @since 0.1.0
 483  
          */
 484  
         private class ViewMonitor<T extends DefaultCDockable>
 485  
                 implements CFocusListener, CDockableStateListener
 486  
         {
 487  
                 
 488  
                 //---- State
 489  
                 
 490  
                 /**
 491  
                  * The view being monitored.
 492  
                  * @since 0.1.0
 493  
                  */
 494  
                 private final View view;
 495  
                 
 496  
                 /**
 497  
                  * The dockable monitored.
 498  
                  * @since 0.1.0
 499  
                  */
 500  
                 private final T dockable;
 501  
                 
 502  
                 /**
 503  
                  * Indicates if the opened event has already been fired.
 504  
                  * @since 0.1.0
 505  
                  */
 506  
                 private volatile boolean openedEventFired;
 507  
                 
 508  
                 /**
 509  
                  * Indicates if the clsed event has already been fired.
 510  
                  * @since 0.1.0
 511  
                  */
 512  
                 private volatile boolean closedEventFired;
 513  
                 
 514  
                 //---- Constructors
 515  
                 
 516  
                 /**
 517  
                  * Creates a focus listener to monitors activation and deactivation of a view.
 518  
                  * @param dockable the dockable monitored.
 519  
                  * @param view the view to monitor.
 520  
                  * @since 0.1.0
 521  
                  */
 522  0
                 public ViewMonitor (T dockable, View view) {
 523  0
                         this.view = view;
 524  0
                         this.dockable = dockable;
 525  0
                         this.dockable.putAction(
 526  
                                 CDockable.ACTION_KEY_CLOSE, 
 527  
                                 new CCloseAction(DockControl.this.control) {
 528  
                                         @Override
 529  0
                                         public void close (CDockable target) {
 530  0
                                                 if (ViewMonitor.this.canCloseView()) {
 531  0
                                                         super.close(target);
 532  0
                                                         ViewMonitor.this.viewClosed();
 533  
                                                 }
 534  0
                                         }
 535  
                                 }
 536  
                         );
 537  0
                         this.dockable.addFocusListener(this);
 538  0
                         this.dockable.addCDockableStateListener(this);
 539  0
                 }
 540  
                 
 541  
                 //---- Methods
 542  
 
 543  
                 /**
 544  
                  * Destroys the dockable.
 545  
                  * <p>This will not ask the view.</p>
 546  
                  * @since 0.1.0
 547  
                  */
 548  
                 public void destroyDockable () {
 549  0
                         this.dockable.setVisible(false);
 550  0
                         viewDestroyed();
 551  0
                 }
 552  
                 
 553  
                 /**
 554  
                  * Closes the dockable.
 555  
                  * @since 0.1.0
 556  
                  */
 557  
                 public void closeDockable () {
 558  0
                         this.dockable.setVisible(false);
 559  0
                 }
 560  
                 
 561  
                 /**
 562  
                  * Check if the view can be closed.
 563  
                  * @return {@code true} if the view can be closed.
 564  
                  * @since 0.1.0
 565  
                  */
 566  
                 protected boolean canCloseView () {
 567  0
                         return this.view.canClose();
 568  
                 }
 569  
                 
 570  
                 /**
 571  
                  * Called once a view has been destroyed.
 572  
                  * <p>Fires a view close event.</p>
 573  
                  * @since 0.1.0
 574  
                  */
 575  
                 protected void viewDestroyed () {
 576  0
                         fireViewClosed(false);
 577  0
                 }
 578  
                 
 579  
                 /**
 580  
                  * Called once a view has been closed.
 581  
                  * <p>Fires a view close event.</p>
 582  
                  * @since 0.1.0
 583  
                  */
 584  
                 protected void viewClosed () {
 585  0
                         fireViewClosed(false);
 586  0
                 }
 587  
                 
 588  
                 /**
 589  
                  * Returns the dockable monitored.
 590  
                  * @return the dockable monitored.
 591  
                  * @since 0.1.0
 592  
                  */
 593  
                 public T getDockable () {
 594  0
                         return this.dockable;
 595  
                 }
 596  
                 
 597  
                 /**
 598  
                  * Resets the state of this monitor and makes the dockable visible.
 599  
                  * @since 0.1.0
 600  
                  */
 601  
                 public void openDockable () {
 602  0
                         if (getDockable().isVisible()) {
 603  0
                                 requestFocus();
 604  
                         } else {
 605  0
                                 this.openedEventFired = false;
 606  
                                 // The docking framework may throw an exception, if a dockable is made visible
 607  
                                 // in a dock container that has the focus, therefore we transfer the focus 
 608  
                                 // somewhere save first before making the dockable visible.
 609  0
                                 DockControl.this.getContentArea().requestFocus();
 610  0
                                 SwingUtilities.invokeLater(
 611  
                                         new Runnable() {
 612  0
                                                 public void run () {
 613  0
                                                         getDockable().setVisible(true);
 614  0
                                                         fireViewOpened();
 615  0
                                                 }
 616  
                                         }
 617  
                                 );
 618  
                         }
 619  0
                 }
 620  
                 
 621  
                 /**
 622  
                  * Searches a suitable focus root starting at the given container.
 623  
                  * @param container the container to search.
 624  
                  * @return the focus candidate or {@code null}.
 625  
                  * @since 0.1.0
 626  
                  */
 627  
                 protected Component findDefaultFocusComponent (Container container) {
 628  0
                         if (container == null || !container.isShowing()) {
 629  0
                                 return null;
 630  
                         }
 631  0
                         FocusTraversalPolicy policy = container.getFocusTraversalPolicy();
 632  0
                         if (policy == null) {
 633  
                                 // Container is not a focus cycle root, use default policy.
 634  0
                                 policy = getCurrentKeyboardFocusManager().getDefaultFocusTraversalPolicy();
 635  
                         }
 636  0
                         return policy.getDefaultComponent(container);
 637  
                 }
 638  
                 
 639  
                 /**
 640  
                  * Requests the focus for the dockable.
 641  
                  * @since 0.1.0
 642  
                  */
 643  
                 public void requestFocus () {
 644  0
                         if (!this.openedEventFired) {
 645  0
                                 return;
 646  
                         }
 647  0
                         getDockable().toFront();
 648  0
                 }
 649  
                 
 650  
                 /**
 651  
                  * Fires a view opened event.
 652  
                  * <p>This event will only be fired once.</p>
 653  
                  * @since 0.1.0
 654  
                  */
 655  
                 public void fireViewOpened () {
 656  0
                         if (this.openedEventFired) {
 657  0
                                 return;
 658  
                         }
 659  0
                         this.closedEventFired = false;
 660  0
                         this.openedEventFired = true;
 661  0
                         DockControl.this.fireViewOpened(this.view);
 662  0
                 }
 663  
                 
 664  
                 /**
 665  
                  * Fires a view closed event.
 666  
                  * @param reopen {@code true} to assert that a view opened event has been fired first.
 667  
                  * @since 0.1.0
 668  
                  */
 669  
                 public void fireViewClosed (boolean reopen) {
 670  0
                         if (reopen) {
 671  0
                                 fireViewOpened();
 672  
                         }
 673  0
                         if (this.closedEventFired) {
 674  0
                                 return;
 675  
                         }
 676  0
                         this.closedEventFired = true;
 677  0
                         this.openedEventFired = false;
 678  0
                         DockControl.this.fireViewClosed(this.view);
 679  0
                 }
 680  
                 
 681  
                 //---- CFocusListener
 682  
                 
 683  
                 /**
 684  
                  * @since 0.1.0
 685  
                  */
 686  
                 public void focusGained (CDockable target) {
 687  0
                         fireViewOpened();
 688  0
                         DockControl.this.fireViewActivated(this.view);
 689  0
                 }
 690  
                 
 691  
                 /**
 692  
                  * @since 0.1.0
 693  
                  */
 694  
                 public void focusLost (CDockable target) {
 695  0
                         DockControl.this.fireViewDeactivated(this.view);
 696  0
                 }
 697  
                 
 698  
                 //---- CDockableStateListener
 699  
                 
 700  
                 /**
 701  
                  * @since 0.1.0
 702  
                  */
 703  
                 public void visibilityChanged (CDockable target) {
 704  0
                         if (this.dockable.isVisible()) {
 705  0
                                 fireViewOpened();
 706  
                         } else {
 707  0
                                 fireViewClosed(true);
 708  
                         }
 709  0
                 }
 710  
                 
 711  
                 /**
 712  
                  * @since 0.1.0
 713  
                  */
 714  
                 public void externalized (CDockable target) {
 715  
                         // Nop.
 716  0
                 }
 717  
                 
 718  
                 /**
 719  
                  * @since 0.1.0
 720  
                  */
 721  
                 public void maximized (CDockable target) {
 722  
                         // Nop.
 723  0
                 }
 724  
                 
 725  
                 /**
 726  
                  * @since 0.1.0
 727  
                  */
 728  
                 public void minimized (CDockable target) {
 729  
                         // Nop.
 730  0
                 }
 731  
                 
 732  
                 /**
 733  
                  * @since 0.1.0
 734  
                  */
 735  
                 public void normalized (CDockable target) {
 736  
                         // Nop.
 737  0
                 }
 738  
                 
 739  
         }
 740  
         
 741  
 }