All Downloads are FREE. Search and download functionalities are using the official Maven repository.

at.spardat.xma.appshell.AppShellDelegate Maven / Gradle / Ivy

There is a newer version: 6.0.2
Show 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;        
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy