Files
Brainstorm/Foundation/src/com/foundation/controller/AbstractViewController.java
2014-05-30 10:31:51 -07:00

797 lines
32 KiB
Java

/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.controller;
import com.common.debug.Debug;
import com.common.thread.IRunnable;
import com.foundation.attribute.ReflectionContext;
import com.foundation.view.IView;
import com.foundation.view.IViewContext;
import com.foundation.view.ViewSystemMetadata;
/**
* The base class for the RemoteViewController and the ViewController providing functionality common to both the remote and local views.
*/
public abstract class AbstractViewController extends Controller {
public static final int OPTION_MODELESS = 0;
public static final int OPTION_MODAL = 1;
public static final int OPTION_APPLICATION_MODAL = 2;
public static final int OPTION_SYSTEM_MODAL = 3;
/** The view controller's current view. */
private IView view = null;
/** Whether the view has been opened yet. This will stay true indefinately once the view has been opened. */
private boolean isOpen = false;
/** Whether the view has been closed. This will stay true indefinately once the view is closed. This is not true before the view is opened. */
private boolean isClosed = false;
/** The view context for the current view. This will be null if the view is null. */
private IViewContext context = null;
/** Prevents an opening view from being opened twice. */
private boolean isOpening = false;
/** The parent view's controller. This will only be set for modal views. */
private AbstractViewController parent = null;
/** Whether the view is actively in the process of closing. */
private volatile boolean isClosing = false;
/** The handler called prior to closing the view and which is capable of canceling the closure. */
private IVetoableRunnable preCloseHandler = null;
/** The handler called when the view closes (before control is returned to the parent view). */
private Runnable onCloseHandler = null;
/** The handler called when the view disposes (before control is returned to the parent view). */
private Runnable onDisposeHandler = null;
/** The reflection context for this view. All internal reflections should use this context since the context will be released when the view is closed. */
private ReflectionManager reflectionManager = null;
/** The options for this view. Currently this is either OPTION_MODAL or OPTION_MODELESS. */
private int options = OPTION_MODAL;
/** The parent component assigned when the view controller is controlling only part of a view. */
private IView parentComponent = null;
/** The manager used to control the decorations. */
private DecorationManager decorationManager = new DecorationManager();
/** Whether to validate the view upon opening it. */
private boolean validateOnOpen = false;
/**
* AbstractViewController constructor.
* @param context The context underwhich the view is being created. This context manages the threading, resources, and request handling for the view as well as ties together related views.
*/
AbstractViewController(IViewContext context) {
this(context, false);
}//AbstractViewController()//
/**
* AbstractViewController constructor.
* @param context The context underwhich the view is being created. This context manages the threading, resources, and request handling for the view as well as ties together related views.
* @param reflectionContext The reflection context to be used by the view.
*/
AbstractViewController(IViewContext context, ReflectionContext reflectionContext) {
this(context, reflectionContext, false);
}//AbstractViewController()//
/**
* AbstractViewController constructor.
* @param context The context underwhich the view is being created. This context manages the threading, resources, and request handling for the view as well as ties together related views.
* @param validateOnOpen Whether the view should perform validation immediately after opening. This is false by default.
*/
AbstractViewController(IViewContext context, boolean validateOnOpen) {
this.validateOnOpen = validateOnOpen;
if(context == null) {
throw new IllegalArgumentException("A view context must be provided to the view.");
}//if//
this.context = context;
this.reflectionManager = new ReflectionManager(this, new ReflectionContext(context.getRequestHandler(), getViewClass(), new Runnable() {
public void run() {
validate();
}//run()//
}));
}//AbstractViewController()//
/**
* AbstractViewController constructor.
* @param context The context underwhich the view is being created. This context manages the threading, resources, and request handling for the view as well as ties together related views.
* @param reflectionContext The reflection context to be used by the view.
* @param validateOnOpen Whether the view should perform validation immediately after opening. This is false by default.
*/
AbstractViewController(IViewContext context, ReflectionContext reflectionContext, boolean validateOnOpen) {
this.validateOnOpen = validateOnOpen;
if(context == null) {
throw new IllegalArgumentException("A view context must be provided to the view.");
}//if//
if((reflectionContext != null) && (reflectionContext.getRequestHandler() != context.getRequestHandler())) {
Debug.log(new RuntimeException(), "Error: Can't use the reflection context since it uses a different request handler from the view context.");
reflectionContext = null;
}//if//
this.context = context;
if(reflectionContext == null) {
this.reflectionManager = new ReflectionManager(this, new ReflectionContext(context.getRequestHandler(), getViewClass(), new Runnable() {
public void run() {
validate();
}//run()//
}));
}//if//
else {
this.reflectionManager = new ReflectionManager(this, reflectionContext);
}//else//
}//AbstractViewController()//
/**
* Gets the decoration manager for this view.
* @return The view's decoration manager.
*/
public DecorationManager getDecorationManager() {
return decorationManager;
}//getDecorationManager()//
/**
* Closes the view if it is open.
* All waiting threads will be notified after the view has been destroyed.
* <p> This method may be called by any thread. </p>
* @return Whether the close was actually performed.
*/
public final boolean close() {
boolean result = false;
boolean isOpened;
boolean isClosed;
boolean isClosing;
synchronized(this) {
isOpened = this.isOpen;
isClosed = this.isClosed;
isClosing = this.isClosing;
if(isOpened && !isClosing && !isClosed) {
this.isClosing = true;
}//if//
}//synchronized//
//Prevent closing twice or calling it recursively.//
if(isOpened && !isClosed && !isClosing) {
final IView view;
final Runnable onCloseHandler;
final Runnable onDisposeHandler;
boolean doClose = true;
try {
if(preCloseHandler != null) {
doClose = preCloseHandler.run();
}//if//
if(doClose) {
result = true;
preClose();
synchronized(this) {
if(this.view != null) {
onCloseHandler = getOnCloseHandler();
onDisposeHandler = getOnDisposeHandler();
view = this.view;
setOnCloseHandler(null);
this.view = null;
this.isClosed = true;
}//if//
else {
view = null;
onCloseHandler = null;
onDisposeHandler = null;
}//else//
//Unregister all reflections. Failure to do so will result in memory leaks, perticularly if the data is accessed over a network.//
getReflectionManager().release();
}//synchronized//
if(view != null) {
//Note: Moved this out of the threaded code since we should always be calling this on the SWT event thread.//
internalClose(view, onCloseHandler, onDisposeHandler);
synchronized(this) {
context = null;
notifyAll();
}//synchronized//
}//if//
}//if//
}//try//
finally {
synchronized(this) {
this.isClosing = false;
}//synchronized//
}//finally//
}//if//
return result;
}//close()//
/*
* TODO: The problem with this idea (to allow reusable partial view's) is that the reflection manager must be released sometime, but can't be released now, so when?
* Closes the view if it is open.
* All waiting threads will be notified after the view has been destroyed.
* <p> This method is only to be called by the caller of openPartial. </p>
*
public final void closePartial(IView view) {
//final IView view;
final Runnable onCloseHandler;
synchronized(this) {
if(this.view != null) {
onCloseHandler = getOnCloseHandler();
//view = this.view;
//setOnCloseHandler(null);
this.view = null;
}//if//
else {
view = null;
//onCloseHandler = null;
}//else//
//Unregister all reflections. Failure to do so will result in memory leaks, perticularly if the data is accessed over a network.//
getReflectionManager().release();
getReflectionManager().getReflectionContext().release();
}//synchronized//
if(view != null) {
//Ensure that the close occurs on the proper thread.//
//Note: Don't call the execute method since the view reference is no longer valid.//
view.execute(new IRunnable() {
public Object run() {
internalClose(view, onCloseHandler);
return null;
}//run()//
});
synchronized(this) {
context = null;
notifyAll();
}//synchronized//
}//if//
}//close()//
*/
/**
* Creates the controller's primary view component.
* @return This view controller's new view object.
*/
protected abstract IView createView();
/**
* Gets the controller's view's class.
* @return The class identifying the view code for this controller.
*/
protected abstract Class getViewClass();
/**
* Requests that the view validate all the data (perticularly the altered reflection data when using reflections).
* <p>Note: This method is automatically called when synchronizing one or more altered reflections without passing a validation handler.</p>
* @return Whether the data was validated.
*/
public abstract boolean validate();
/**
* Disables the view associated with this controller.
* <p>NOTE: This does not close the view.
* @see #close()
*/
public synchronized void disable() {
IView view = getView();
if(view != null) {
view.setIsEnabled(false);
}//if//
}//disable()//
/**
* Enables the view associated with this controller so that it is usable by the user.
*/
public synchronized void enable() {
IView view = getView();
if(view != null) {
view.setIsEnabled(true);
}//if//
}//enable()//
/**
* Executes the runnable synchronously.
* <p>This is a thread safe call.</p>
* @param runnable The code block to execute.
* @return The runnable's result.
* @throws ViewClosedException If the view was closed prior to the call executing.
*/
public Object execute(IRunnable runnable) throws ViewClosedException {
IView view = null;
synchronized(this) {
view = getView();
}//synchronized//
if(view == null) {
throw new ViewClosedException();
}//if//
return getView().execute(runnable);
}//execute()//
/**
* @deprecated Use executeAsync(IRunnable) instead.
* Do not use this method any more since it is not thead safe.
*/
public void executeAsynch(IRunnable runnable) {
getView().executeAsync(runnable);
}//executeAsynch()//
/**
* Executes the runnable asynchronously.
* <p>This is a thread safe call.</p>
* @param runnable The code block to execute.
* @throws ViewClosedException If the view was closed prior to the call executing.
*/
public void executeAsync(IRunnable runnable) throws ViewClosedException {
synchronized(this) {
if(getView() != null) {
getView().executeAsync(runnable);
}//if//
else {
throw new ViewClosedException();
}//else//
}//synchronized//
}//executeAsynch()//
/**
* Called by the GC thread upon destroying this object.
*/
protected void finalize() throws Throwable {
//Just in case we will unregister all reflections one more time. This should have already occured when the view closed.//
getReflectionManager().release();
}//finalize()//
/**
* Gets the view context provided when the view was opened.
* Each view should have a context (view framework dependant) which can be created from any other view controller's context.
* <p>Note: Views exist under the same context for the same client (or in the case of the thick client views, they all exist under the same context).
* This is not a view specific context, but rather a view system context, one for each view system.</p>
* @return The view framework dependant view context.
*/
public final IViewContext getContext() {
return context;
}//getContext()//
/**
* Gets the handler run before the view is closed.
* @return The handler to be run just after before hiding or closing the view.
*/
public IVetoableRunnable getPreCloseHandler() {
return preCloseHandler;
}//getPreCloseHandler()//
/**
* Gets the handler run just before the view is closed.
* @return The handler to be run just after hiding the view and before closing the view.
*/
public Runnable getOnCloseHandler() {
return onCloseHandler;
}//getOnCloseHandler()//
/**
* Gets the handler run just after the view is disposed.
* @return The handler to be run just after the view has been completely destroyed.
*/
public Runnable getOnDisposeHandler() {
return onDisposeHandler;
}//getOnDisposeHandler()//
/**
* Gets the options specified when opening the view.
* @return The options given when the view's controller was opened.
* @see #OPTION_MODELESS
* @see #OPTION_MODAL
* @see #OPTION_APPLICATION_MODAL
* @see #OPTION_SYSTEM_MODAL
*/
public final int getOptions() {
return options;
}//getOptions()//
/**
* Gets the parent view controller if one was supplied durring the opening of the view controller.
* @return This view's parent view's controller object. This value will be null for partial views (embedded in another view), or for modeless views.
*/
public final AbstractViewController getParent() {
return parent;
}//getParent()//
/**
* Gets the view's parent view component. This will only be available if the view is an integrated component in another view.
* @return The view component that this view controller's view is part of. For standalone view's, this value will be null.
*/
public final IView getParentComponent() {
return parentComponent;
}//getParentComponent()//
/**
* Sets the view's parent view component. This will only be available if the view is an integrated component in another view.
* @param parentComponent The view component that this view controller's view is part of. For standalone view's, this value will be null.
*/
public final void setParentComponent(IView parentComponent) {
this.parentComponent = parentComponent;
}//setParentComponent()//
/**
* Gets the reflection manager for this view.
* Each view has its own reflection manager which can be called upon to create, synchronize, and release reflections.
* <p>Note: Currently the reflection manager is not usable after the view closes. Subsiquently all reflections are also may be unusable (will still be useable if the reflection context was shared and is still accessed by other views). They still exist, but are no longer connected to their reflections. Using them may cause problems since they may be missing unloaded attribute data.</p>
* @return The view's reflection manager.
*/
public final ReflectionManager getReflectionManager() {
return reflectionManager;
}//getReflectionManager()//
/**
* Gets the associated view for this view controller. If there isn't yet a view (or the close() method was called and the view was disposed) then this method will return null.
* @return Will be the view associated with the controller if the controller has been opened (and not subsquently closed), or getView(true) has been called.
* @see #open()
* @see #close()
*/
public final IView getView() {
return view;
}//getView()//
/**
* Hides the view associated with this controller.
* <p>NOTE: This does not close the view.</p>
* @see #close()
*/
public synchronized void hide() {
IView view = getView();
if(view != null) {
view.setIsVisible(false);
}//if//
}//hide()//
/**
* Closes the view and releases all components.
* <p>Subclasses should override the preClose() and postClose() methods, or set the on close handler.</p>
* @param view The view associated with the view controller.
* @param onCloseHandler The handler to be called right before closing the view. This is normally set by the opener of the view to handle post processing of the view data.
* @param onDisposeHandler The handler to be called right after disposing the view.
* @see #preClose()
* @see #postClose()
* @see #setOnCloseHandler(Runnable)
*/
protected void internalClose(IView view, Runnable onCloseHandler, Runnable onDispose) {
if(view != null) {
view.setIsVisible(false);
//Run the on close handler.//
if(onCloseHandler != null) {
onCloseHandler.run();
}//if//
view.viewReleaseAll();
postClose();
//Run the on dispose handler.//
if(onDispose != null) {
onDispose.run();
}//if//
}//if//
}//internalClose()//
/**
* Opens the view either by displaying the existing view, or by creating a new view.
* <p>This method allows subclasses to override the way the newly created view is initialized.</p>
* @return The open and visible view.
*/
protected IView internalInitialize() {
return createView();
}//internalInitialize()//
/**
* Initializes the view context.
* <p>Note: This must get called immediatly AFTER the view has been created & initialized.
* @param viewContext The context the view is being opened under.
* @return The view context to be used by this view controller.
*/
protected void internalInitializeContext(IViewContext viewContext) {
}//internalInitializeContext()//
/**
* Opens the view either by displaying the existing view, or by creating a new view.
* <p>This method allows subclasses to override the way the newly created view is initialized.</p>
* @return The open and visible view.
*/
protected void internalOpen(final IView view) {
view.suspendLayouts();
view.viewInitializeAll();
view.resumeLayouts();
view.layout();
view.pack();
postOpenInitialization(view);
if(validateOnOpen) {
validate();
}//if//
}//internalOpen()//
/**
* Determines whether the view should validate upon opening. This is normally false.
* @return Whether the view validates as soon as it is displayed.
*/
protected boolean validateOnOpen() {
return validateOnOpen;
}//validateOnOpen()//
/**
* Determines whether the view is open.
* Note that this is different than isClosed since it reports whether the view has been opened, though it could be subsiquently closed and this method will still report true.
* @return Whether the view is currently open (not necessarily visible or enabled).
*/
public synchronized boolean isOpen() {
return isOpen;
}//isOpen()//
/**
* Determines whether the view is open.
* Note that this is different than isClosed since it reports whether the view has been opened, though it could be subsiquently closed and this method will still report true.
* <p>Note: Not synchronized since it is generally set only while opening the view and synchronization is not necessary.</p>
* @param isOpen Whether the view is currently open (not necessarily visible or enabled).
*/
protected void isOpen(boolean isOpen) {
this.isOpen = isOpen;
}//isOpen()//
/**
* Determines whether the view has been closed.
* Note that this is different than isOpen since the view must be first opened to be then closed.
* @return Whether the view is currently closed.
*/
public synchronized boolean isClosed() {
return isClosed;
}//isClosed()//
/**
* Creates and displays the modal view associated with this controller. A modal view is one which must be closed before the user may interact with any parent view.
* The user should close the view by calling the close method.
* <p>Note: The thread calling this method will return immediatly and will NOT block until the view is closed.</p>
* @param parent The view controller associated with the parent view.
* @see #show()
* @see #close()
*/
public void open(AbstractViewController parent) {
open(parent, -1, parent != null ? OPTION_MODAL : OPTION_MODELESS);
}//open()//
/**
* Creates and displays the view associated with this controller.
* The user should close the view by calling the close method.
* <p><b>Warning: The caller should not block unless it is certain that the calling thread is not the message handler in a single threaded view environment. In such a case a handler should be provided to handle the view closure.</b></p>
* @param parent The optional parent view controller.
* @param timeout The amount of time to wait for the view to close before returning control. This should be zero if the thread should wait for ever. This should be less than zero if there should be no wait.
* @param options The options used to open the view. Currently you can pass OPTION_MODELESS or OPTION_MODAL.
* @see #show()
* @see #close()
*/
protected final void open(AbstractViewController parent, long timeout, int options) {
this.parent = parent;
open(timeout, options);
}//open()//
/**
* Creates and displays the modeless view associated with this controller. A modeless view is one that does not exist within the life of a parent view. Any parent may close without affecting this view.
* The user should close the view by calling the close method.
* <p>Note: The thread calling this method will return immediatly and will NOT block until the view is closed.</p>
* @see #show()
* @see #close()
*/
public void open() {
open(-1, OPTION_MODELESS);
}//open()//
/**
* Creates and displays the view associated with this controller.
* The user should close the view by calling the close method.
* <p><b>Warning: The caller should not block unless it is certain that the calling thread is not the message handler in a single threaded view environment. In such a case a handler should be provided to handle the view closure.</b></p>
* @param timeout The amount of time to wait for the view to close before returning control. This should be zero if the thread should wait for ever. This should be less than zero if there should be no wait.
* @param options The options used to open the view. Currently you can pass OPTION_MODELESS or OPTION_MODAL.
* @see #show()
* @see #close()
*/
protected final void open(long timeout, int options) {
try {
//Since we don't want to be synchronized on the view controller while we are opening, we will just synchronize to check the open status.//
synchronized(this) {
if(view != null) {
show();
return;
}//if//
else if(isOpening) {
return;
}//else if//
else {
isOpening = true;
}//else//
}//synchronized//
this.parentComponent = null;
this.options = options;
internalInitializeContext(context);
this.view = internalInitialize();
decorationManager.initialize(view);
this.isOpen = true;
internalOpen(this.view);
//Warning: This should not be called if this is the one and only view event handler thread!//
if(timeout >= 0) {
waitForViewClosure(timeout);
}//if//
}//try//
finally {
synchronized(this) {
isOpening = false;
}//synchronized//
}//finally//
}//open()//
/**
* Opens a partial view given the view's parent view component reference and an optional view context.
* <p>This is intended only to be called by the containing view when it requires the sub-component to be created.</p>
* <p><b>Warning: This method is not thread safe. It is assumed that the view will be owned by one parent component and will be opened only by that component.</b></p>
* @param parent The non-null parent view component passed by the view.
* @param context The context for the view. The actual value is dependant upon the view framework being used. In a remote view this value may be the session context for example.
* @return A view associated with this view controller that is a part of another view.
*/
public IView openPartial(IView parent, Object context) {
IView result = null;
if(parent == null) {
throw new RuntimeException("Error: Cannot open a partial view without a parent view part.");
}//if//
else if(context != this.context) {
throw new RuntimeException("Error: Invalid view context. This view was initialized with a different context than it is being used under.");
}//else if//
if(view == null) {
this.options = 0;
this.parentComponent = parent;
this.view = createView();
decorationManager.initialize(view);
this.isOpen = true;
this.view.setController(this);
this.view.viewInitializeAll();
this.view.layout();
this.view.pack();
postOpenInitialization(this.view);
if(validateOnOpen) {
validate();
}//if//
}//if//
result = view;
return result;
}//openPartialView()//
/**
* Called just after closing the view. Note that the reflection context will have been released and any reflections will not be useable (they won't return the correct hashCode, won't be able to load attributes, and will behave as non-reflected objects).
* <p><b>Warning: If using a ModelListener, do not release it in this method. Instead use preClose() to release the model listener.</b></p>
* <p>Note: This method will always be called by the view thread and can access non-multi-thread safe objects.</p>
* @see #preClose()
* @see #setOnCloseHandler(Runnable)
*/
protected void postClose() {
}//postClose()//
/**
* Called after the view is opened but not yet visible to the user.
* <p>This method allows the view controller an opportunity to modify how or whether the view is made visible to the user. The default behavior is to make the view visible and to give it the focus. Subclasses can also overload this to position the view.</p>
* @param view The newly opened but not yet visible view.
*/
protected void postOpenInitialization(IView view) {
view.setIsVisible(true);
view.setFocus();
}//postOpenInitialization()//
/**
* Called just prior to releasing the reflection context and calling the onCloseHandler and closing the view. This is called after calling the preCloseHandler which can veto the closure.
* <p><b>Note: This is a good place to release any ModelListeners or other custom listeners that were setup by the view controller.</b></p>
* <p>Warning: This method may not be called by the view thread. Implementations should consider this when affecting objects not in a multi-thread safe context. The postClose method is called on the view thread.</p>
* @see #postClose()
* @see #setOnCloseHandler(Runnable)
*/
protected void preClose() {
}//preClose()//
/**
* Forces a resfresh of the view (pushing data from the model to the view).
*/
public synchronized void refresh() {
IView view = getView();
if(view != null) {
view.viewRefreshAll();
}//if//
}//refresh()//
/**
* Sets the handler run before the view is closed and is intended to allow the view creator to setup post processing of the view data external to the view logic with the ability to cancel the closure if there is a problem.
* To setup internal post processing of the view data, the view should override the preClose() or postClose() methods.
* Note that only one pre-close handler may be assigned to a view controller. Assigning a second will mean that the first assigned pre-close handler will not be called.
* <p><b>Warning: This handler will never be called if the view is opened inside another view (openPartial versus a call to open) since the close cannot be cancelled.</b></p>
* <p>This handler can be used to process the view results, interact with the view's reflections before they are disposed, and cancel the closing the view if processing the results fails.</p>
* <p><b>Warning: In a single threaded view environment (most of them), the handler will be called by the view's event thread, and thus the handler should do nothing that blocks or takes a long time.</b></p>
* @param preCloseHandler The handler to be run before any other close functionality. This handler is can veto the closure process.
* @see #preClose()
* @see #setOnCloseHandler()
* @see #postClose()
*/
public void setPreCloseHandler(IVetoableRunnable preCloseHandler) {
this.preCloseHandler = preCloseHandler;
}//setPreCloseHandler()//
/**
* Sets the handler run just before the view is closed and is intended to allow the view creator to setup post processing of the view data external to the view logic.
* To setup internal post processing of the view data, the view should override the preClose() or postClose() methods.
* Note that only one on-close handler may be assigned to a view controller. Assigning a second will mean that the first assigned on-close handler will not be called.
* <p>This handler can be used to cleanup after the view, and to process the view results if the opening thread is not able to wait for the view to be closed.</p>
* <p><b>Warning: In a single threaded view environment (most of them), the handler will be called by the view's event thread, and thus the handler should do nothing that blocks or takes a long time.</b></p>
* @param onCloseHandler The handler to be run just after hiding the view and before closing the view. This handler is run between the execution of the preClose() method and the actual view closing.
* @see #setPreCloseHandler()
* @see #preClose()
* @see #postClose()
*/
public void setOnCloseHandler(Runnable onCloseHandler) {
this.onCloseHandler = onCloseHandler;
}//setOnCloseHandler()//
/**
* Sets the handler run just after the view is disposed.
* To setup internal post processing of the view data, the view should override the preClose() or postClose() methods.
* Note that only one on-dispose handler may be assigned to a view controller. Assigning a second will mean that the first assigned on-dispose handler will not be called.
* <p>This handler can be used to cleanup after the view, and to process the view results if the opening thread is not able to wait for the view to be closed.</p>
* <p><b>Warning: In a single threaded view environment (most of them), the handler will be called by the view's event thread, and thus the handler should do nothing that blocks or takes a long time.</b></p>
* @param onDisposeHandler The handler to be run just after the view is completely disposed.
* @see #preClose()
* @see #postClose()
*/
public void setOnDisposeHandler(Runnable onDisposeHandler) {
this.onDisposeHandler = onDisposeHandler;
}//setOnDisposeHandler()//
/**
* Sets the options specified when opening the view.
* @param options The options given when the view's controller was opened.
* @see #OPTION_MODAL
* @see #OPTION_MODELESS
*/
protected void setOptions(int options) {
this.options = options;
}//setOptions()//
/**
* Sets the view reference.
* @param view The current view for this view controller.
*/
protected void setView(IView view) {
this.view = view;
decorationManager.initialize(view);
}//setView()//
/**
* Shows the view associated with this controller so that it is visible to the user.
* <p>Note: This does not open the view. The view must first be open.</p>
*/
public synchronized void show() {
IView view = getView();
if(view != null) {
//Set visible and bring to top.//
view.show();
}//if//
}//show()//
/**
* Forces a synchronize of the view (pushing data from the view to the model).
*/
public synchronized void synchronize() {
IView view = getView();
if(view != null) {
view.viewSynchronizeAll();
}//if//
}//synchronize()//
/**
* Waits for the view to be closed before returning.
*/
public void waitForViewClosure() {
waitForViewClosure(0);
}//waitForViewClosure()//
/**
* Waits for the view to be closed or the time to run out before returning.
* @param timeout The number of milliseconds to wait before giving up. If this value is zero then the thread may wait forever.
*/
public synchronized void waitForViewClosure(long timeout) {
if(isOpen()) {
try {
wait(timeout);
}//try//
catch(InterruptedException e) {
Debug.handle(e);
}//catch//
}//if//
}//waitForViewClosure()//
/**
* Gets the display metadata which describes the view system such as information about the display locations and sizes.
* @return The metadata describing the view system.
*/
public ViewSystemMetadata getViewSystemMetadata() {
return getView().getViewContext().getViewSystemMetadata();
}//getViewSystemMetadata()//
/**
* Verifies that the calling thread is allowed access to the view components.
* <p>Note: This is really a debug only operation and should be turned off for production applications.</p>
*/
protected void verifyThread() {
if((getView() != null) && (!getView().isViewThread())) {
Debug.log(new RuntimeException("Error: Invalid thread."));
}//if//
}//verifyThread()//
}//AbstractViewController()//