at.spardat.xma.appshell.AppShellDelegate Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* Copyright (c) 2003, 2007 s IT Solutions AT Spardat GmbH .
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* s IT Solutions AT Spardat GmbH - initial API and implementation
*******************************************************************************/
/*******************************************************************************
* Copyright (c) 2003, 2007 s IT Solutions AT Spardat GmbH .
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* s IT Solutions AT Spardat GmbH - initial API and implementation
*******************************************************************************/
/*
* @(#) $Id: AppShellDelegate.java 9060 2012-03-06 10:06:47Z hoenninger $
*
*
*
*
*/
package at.spardat.xma.appshell;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ResourceBundle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import at.spardat.xma.boot.component.IXMAControl;
// TODO: change comment
/**
* Base class for application shells in XMA. An application shell is the window opened at startup
* of the client side application. It stays open during the whole user session. It typically contains
* a header area showing some context information, a menu area containing the menu tree of the
* application and a client area showing the currently active component.
*
* @author s2877
* @since 1.4.0
*/
public abstract class AppShellDelegate implements IAppShell {
// TODO: comment me
protected AppShell appShell;
/**
* The root of the menu tree. It is not shown itself, but contains all the MenuItems
* which are shown at top level.
*/
protected MenuItem rootMenu;
/**
* The task at the very bottom of the call stack. This task is called automaticaly
* at application startup. All furter tasks are called from this task.
*/
protected ITask rootTask;
/**
* Lookup table for all MenueItems contained somewhere in the menu-tree.
* Every menu item can be found by its unique name.
*/
private HashMap menuItems = new HashMap();
/**
* Lookup table for named Tasks. see registerTask() and getTask().
*/
HashMap tasks = new HashMap();
/**
* Component or page currently shown in the client area.
*/
IXMAControl client;
/**
* Lock-counter for the menu used by lockMenu() and unlockMenu().
* If it is greater than zero, the menu is disabled.
* If it is less or equal to zero, the menu is enabled.
*/
int menuLock=0;
// TODO: change comment
/**
* Initializes the application shell.
*
* @param component the Component containing the DialogPage.
* @param stateless indicating if this page is stateless on the server.
* @param style The SWT-Style for the Shell of the DialogPage.
* @throws IllegalArgumentException if comonent is null.
*/
void setAppShell(AppShell appShell) {
this.appShell = appShell;
}
/**
* Replaces the embedded page or component in the client area. The currently embedded
* page or component is removed from this AppShell and the new one is shown in
* the client area.
* @param newClient the new page or component to embedd.
*/
public void setClientArea(IXMAControl newClient) {
setClientArea(newClient,null);
}
/**
* Replaces the embedded page or component in the client area. The currently embedded
* page or component is removed from this AppShell and the new one is shown in
* the client area.
* @param newClient the new page or component to embedd.
* @param clientCompositeW the composite to embedd into or null to use the one returned from getClientComposite()
*/
public void setClientArea(IXMAControl newClient, Composite clientCompositeW) {
Composite compW = null;
try {
if ( clientCompositeW == null ) {
clientCompositeW = getClientComposite();
}
if(client!=null ) {
appShell.removeChild(client);
}
client = newClient;
compW = newClient.createComposite(clientCompositeW);
// compW.parent = clientCompositeW
// compW.data = newClient
FormData data = new FormData();
data.left = new FormAttachment(0,0);
data.right = new FormAttachment(100,0);
data.top = new FormAttachment(0,0);
data.bottom = new FormAttachment(100,0);
compW.setLayoutData(data);
clientCompositeW.setTabList(new Control[]{compW});
compW.setVisible(false);
appShell.addChild(newClient);
} catch (Exception e) {
appShell.showException(e);
} finally {
if(compW!=null) compW.setVisible(true);
}
}
/**
* Removes the embedded page or componet form the client area.
* Nothing is embedded afterwards.
*/
/* (non-Javadoc)
* @see at.spardat.xma.appshell.IAppShell#clearClientArea()
*/
public void clearClientArea() {
if(client!=null) {
getClientComposite().setVisible(false);
appShell.removeChild(client);
client=null;
getClientComposite().setVisible(true);
}
}
/**
* Get the SWT-composite where client pages or composites
* can be embedded.
* @return the composite representing the client area.
*/
public Composite getClientComposite() {
return appShell.getClientComposite();
}
/**
* Create the MenuItem which will serve as root of all
* other MenuItems.
* @return the newly created root of the menu tree.
*/
public ITask createRootTask(IMenuItem rootMenu) {
return appShell.createRootTask(rootMenu);
}
/**
* Creates the Task with the given name. The default implementation
* takes the name as the fully qualified classname of the Task.
* @param name unique name for the task within the client side application.
*/
public ITask createTask(String name) {
return appShell.createTask(name);
}
/**
* Locks and disables the menu. Internaly increments a lock counter.
* To unlock the menu again unlockMenu() must be called as often
* as lockMenu().
*/
public void lockMenu() {
if(menuLock==0) {
setMenuEnabled(false);
}
menuLock++;
}
/**
* Unlocks the menu. Internaly decrements a lock counter.
* To unlock the menu unlockMenu() must be called as often
* as lockMenu() before.
*/
public void unlockMenu() {
if(menuLock==0) throw new IllegalStateException("menu is not locked");
menuLock--;
if(menuLock==0) {
setMenuEnabled(true);
}
}
/**
* Completely enable/disable the menu.
* @param enabled true: enable, false: disable.
*/
abstract protected void setMenuEnabled(boolean enabled);
/**
* Enables the given menu item if the argument enabled is true
,
* and disables it otherwise. A disabled menu item is
* not selectable from the user interface and
* draws with an inactive or "grayed" look.
* Disabling a menu item makes all its children not selectable, too.
* @since 2.2.0
*/
abstract protected void setMenuItemEnabled(IMenuItem item,boolean enabled);
/**
* Returns true
if the given menu item is enabled and false
* otherwise. A disabled menu item is not selectable from the user interface
* and draws with an inactive or "grayed" look. A menu item is disabled, if
* it is either directly disabled or any of its parents is disabled.
* @since 2.2.0
*/
abstract protected boolean isMenuItemEnabled(IMenuItem item);
/**
* Enables the given menu item if the argument enabled is true
,
* and disables it otherwise. A disabled menu item is
* not selectable from the user interface and
* draws with an inactive or "grayed" look.
* Disabling a menu item makes all its children not selectable, too.
* @since 2.2.0
*/
protected void setMenuItemEnabled(String menuId,boolean enabled) {
setMenuItemEnabled(getMenu(menuId), enabled);
}
/**
* Returns true
if the given menu item is enabled and false
* otherwise. A disabled menu item is not selectable from the user interface
* and draws with an inactive or "grayed" look. A menu item is disabled, if
* it is either directly disabled or any of its parents is disabled.
* @since 2.2.0
*/
protected boolean isMenuItemEnabled(String menuId) {
return isMenuItemEnabled(getMenu(menuId));
}
/**
* Attach the given MenuItem to its viusal representation.
* The visual representation can be implemented by a
* Widget Model or directly by a Widget.
* The change must be propagated to the GUI.
* @param item to attach
*/
abstract public void attachMenu(IMenuItem item);
/**
* Detach the MenuItem from its visual representation.
* The change must be propagated to the GUI.
* @param item to remove
*/
abstract public void detachMenu(IMenuItem item);
/**
* Register the given MenuItem at the AppShell.
* After this, the MenuItem will be attached to
* its visual representation. It will be visible
* and events will be delivered.
* @param item to register
*/
public void registerMenu(IMenuItem item) {
List list = (List) menuItems.get(item.getName());
if(list==null) {
list = new LinkedList();
menuItems.put(item.getName(),list);
}
list.add(item);
attachMenu(item);
}
/**
* Unregister the given MenuItem fromt the AppShell.
* After this, the MenuItem will no longer be attached
* to its visual representation. It will not be
* visible and no events will be delivered any more.
* @param item to remove
*/
public void unregisterMenu(IMenuItem item) {
List list = (List) menuItems.get(item.getName());
if(list!=null) {
list.remove(item);
if(list.isEmpty()) {
menuItems.remove(item.getName());
}
}
detachMenu(item);
}
/**
* Calls the action associated which the given MenuItem.
* Before it is actually called, all currently open Tasks
* outside the given MenuItem are closed.
* If there is no Task attached to the given MenuItem, nothing happens.
* @param item the MenuItem to call.
*/
public void callMenu(IMenuItem item) {
if (item.getTask()==null && item.hasMenuSelectionListener()==false) return; // nothing to do
if (item.isPreserveTasks() == false) {
if (closeTasks(item) == false) {
return;
}
}
item.select();
}
/**
* Calls the action associated which the named MenuItem.
* Before it is actually called, all currently open Tasks
* outside the named MenuItem are closed.
* If there is no Task attached to the named MenuItem, nothing happens.
* @param menuId the name of the MenuItem to call.
*/
public void callMenu(String menuId) {
IMenuItem item = getMenu(menuId);
if(item==null) {
throw new IllegalArgumentException("no such menu item: "+menuId);
} else {
callMenu(item);
}
}
/**
* Get the MenuItem registered under the given menuId.
* If there are more than one MenuItem registered under the same name,
* the one registered last is returned.
* @param menuId the name of the MenuItem you want.
* @return the MenuItem with the given name or null if not found.
*/
public IMenuItem getMenu(String menuId) {
LinkedList list = (LinkedList)menuItems.get(menuId);
if(list!=null && !list.isEmpty()) {
return (IMenuItem) list.getLast();
} else {
return null;
}
}
/**
* Selects the named MenuItem. This method behaves like
* the user has selected the MenuItem via the GUI.
* @param menuId the name of the MenuItem to select.
*/
abstract public void selectMenu(String menuId);
/**
* Visibly marks the named MenuItem as selected.
* @param menuId the name of the MenuItem to mark as selected.
*/
abstract public void markMenu(String menuId);
/**
* Get the ResourceBundle containing the labels for all menu items.
* @return the ResourceBundle for the menu.
*/
protected ResourceBundle getMenuResource() {
return appShell.getMenuResource();
}
// TODO: change comment
/**
* Method called to start the AppShell.
* The AppShell will be shown and executed.
* It blocks until the AppShell is closed.
* @return true
*/
void prepare() {
rootMenu = new MenuItem(this);
rootMenu.setStyle(SWT.CASCADE); //needed by MenuAppShell
rootTask = createRootTask(rootMenu);
if ( rootTask != null ) {
rootTask.setMenu(rootMenu);
rootMenu.setTask(rootTask);
}
}
/**
* Get the task on top of the call stack. This is the currently active Task.
*/
public ITask getTopTask() {
ITask top = rootTask;
for(ITask task = rootTask;task!=null;task=task.getSubTask()) {
top = task;
}
return top;
}
/**
* Pushes the given Component or Page on top of the call stack.
* It is shown embedded in the client area.
* If modal is true, this method blocks until the Component or Page is
* closed.
* @param newClient the component or page to embedd.
* @param modal if modal is true this method blocks until newClient is finished
* if modal if false this method returns immediately.
*/
public void pushClientComponent(final IXMAControl newClient, boolean modal) {
getTopTask().call(new SimpleTask(newClient,modal));
}
/**
* This method will be called every time the Shell is tried to be closed.
* It is intended to be implemented by the application programmer if he
* wants to react on this event. The application programmer my decide if
* the shell will actually be closed.
* Per default closing is permitted if the menu is enabled - no blocking Task is active.
*
* @return true means it is ok to close the Shell
* false means do not close the Shell
*/
protected boolean mayClose() {
return menuLock==0;
}
/**
* Closes all tasks on the call stack which are outside the given
* MenuItem. The call stack is rewinded until the task is on top which
* corresponds to the given MenuItem.
* @param item the menu item outside which all tasks should be closed.
* @return true if all this tasks could be successfully closed.
* false if a task refused to close.
*/
protected boolean closeTasks(IMenuItem item) {
ITask oldTop = getTopTask();
for(ITask top = getTopTask();top!=rootTask&&!top.contains(item);top=getTopTask()) {
if(!top.closeRequested(false)) {
if(top!=oldTop) {
top.showTopPage();
}
return false;
}
}
return true;
}
// TODO: comment me
public void removeWidgets() {
}
// TODO: comment me
protected void clientEvent(SelectionEvent event,int type) {
}
// TODO: comment me
public boolean hasWidgets () {
return appShell.hasWidgets();
}
public List getTaskStack() {
List taskStack = new ArrayList();
for(ITask task = rootTask;task!=null;task=task.getSubTask()) {
taskStack.add(task);
}
return taskStack;
}
}