Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
DockControl |
|
| 1.8679245283018868;1.868 | ||||
DockControl$1 |
|
| 1.8679245283018868;1.868 | ||||
DockControl$2 |
|
| 1.8679245283018868;1.868 | ||||
DockControl$3 |
|
| 1.8679245283018868;1.868 | ||||
DockControl$4 |
|
| 1.8679245283018868;1.868 | ||||
DockControl$5 |
|
| 1.8679245283018868;1.868 | ||||
DockControl$6 |
|
| 1.8679245283018868;1.868 | ||||
DockControl$ViewMonitor |
|
| 1.8679245283018868;1.868 | ||||
DockControl$ViewMonitor$1 |
|
| 1.8679245283018868;1.868 | ||||
DockControl$ViewMonitor$2 |
|
| 1.8679245283018868;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 | } |