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

at.spardat.xma.page.PageClient Maven / Gradle / Ivy

/*******************************************************************************
 * 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
 *******************************************************************************/

package at.spardat.xma.page;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Properties;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.HelpEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.TypedEvent;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;

import at.spardat.enterprise.exc.AppException;
import at.spardat.enterprise.exc.INotification;
import at.spardat.enterprise.exc.SysException;
import at.spardat.enterprise.fmt.FmtFactory;
import at.spardat.enterprise.fmt.IFmt;
import at.spardat.enterprise.util.Types;
import at.spardat.xma.appshell.IAppShell;
import at.spardat.xma.boot.component.IComponent;
import at.spardat.xma.boot.component.IDialog;
import at.spardat.xma.boot.component.IXMAControl;
import at.spardat.xma.boot.logger.LogLevel;
import at.spardat.xma.component.ComponentClient;
import at.spardat.xma.component.EmbeddableComponent;
import at.spardat.xma.exception.Codes;
import at.spardat.xma.help.HelpView;
import at.spardat.xma.mdl.AttachmentExceptionClient;
import at.spardat.xma.mdl.IWModelClient;
import at.spardat.xma.mdl.NewModelEvent;
import at.spardat.xma.mdl.NewModelEventParams;
import at.spardat.xma.mdl.UIDelegateClient;
import at.spardat.xma.mdl.ValidationErrorClient;
import at.spardat.xma.mdl.WModel;
import at.spardat.xma.mdl.list.IListWMClient;
import at.spardat.xma.mdl.simple.ISimpleWMClient;
import at.spardat.xma.mdl.tree.TreeUIDelegateClient;
import at.spardat.xma.page.messagebox.DetailedMessageBox;
import at.spardat.xma.rpc.RemoteCallClient;
import at.spardat.xma.rpc.RemoteReply;
import at.spardat.xma.security.XMAContext;
import at.spardat.xma.session.XMASession;



/**
 * Base class of all client side pages. A PageClient contains Widgets and Models.
 *
 * @author s2877
 */
public abstract class PageClient extends Page implements IEmbeddable {

    /** The parent PageClient of this PageClient, if any. */
    PageClient parent;


    /**
     * Collection of all Subpages or Notebooks on the PageClient
     * Technically all elements of the Collection must implement IXMAControl
     */
    private ArrayList children;


    /** The SWT-Composite corresponding to this PageClient. */
    protected Composite composite;


    /**
     * The component this page belongs to.
     */
    private ComponentClient  component_;

    /**
     * Specifies if the WidgetModels of this PageClient have UIDelegates attached.
     */
    private boolean          uiAttached_;


    /**
     * Indicates that this Page has been newly created, i.e., did not
     * exist since the last server side event.
     */
    private boolean          isNew_ = true;

    /**
     * Indicates if the page is visible.
     * This flag is toggled by enterBase() and leaveBase().
     */
    private boolean visible = false;

    /**
     * The Dialog containing this page. null if this page is not embedded.
     */
    IDialog dialog;

    /**
     * Additional object which extends the behavior of the page.
     */
    IPageExtender extend;


    private String contextString;

    /**
     * respond to UI-Events
     */
    private boolean eventsEnabled=false;

    /**
     * during the execution of widgetEvent() and the event methods of the
     * application code, this field holds the current SWT-Event
     */
    private TypedEvent currentEvent;

    /** stores DynamicModelSets containing dynamic models and their corresponding widgets  */
    private List dynamicModels;

    /**
     * Constructor of the PageClient.
     *
     * @param component the component containing this page.
     * @param stateless indicating if this page is stateless on the server.
     */
    public PageClient (ComponentClient component, boolean stateless) {
        super (stateless, false);
        component_ = component;
    }

    /**
     * Constructor of the PageClient.
     *
     * @param parent the parentpage of this page. parent must not be null.
     * @param stateless indicating if this page is stateless on the server.
     */
    public PageClient (PageClient parent, boolean stateless) {
        super (stateless, false);
        this.parent = parent;
        component_ = parent.getComponent();
    }

    /**
     * Adds a Subpage to this PageClient. This may be a Notebook with its NotebookPages, an EmbeddableComponent,
     * or an AssistentPage in an Assistent. Any Object implementing the IXMAControl-Interface
     * my be added. The methods createWidgets() and enter() will be called on the Subpage at the right time.
     *
     * @param child the IXMAControl to add.
     */
    public void addChild(IXMAControl child) {
        if (children == null) children = new ArrayList();
        children.add(child);
        if(child instanceof IEmbeddable) {
            ((IEmbeddable)child).setDialog(getDialog());
            if(eventsEnabled) {
                ((IEmbeddable)child).setEventsEnabled(true);
            }
        }

        if(getWidgets()!=null) {
            child.initGUI();
            child.getComposite().getParent().layout();
        }
        if(visible) {
            child.enterBase();
            getDialog().stateChangedBase();
            getDialog().updateErrorStatus(getDialog().getFocusControl());
        }
    }

    /**
     * Removes a Subpage of this PageClient.
     * The methods leave() and removeWidgets() will be called on the
     * Subpage if not allready called.
     *
     * @param child the IXMAControl to remove.
     */
    public void removeChild(IXMAControl child) {
        if(children!=null) {
            if(children.remove(child)) {
                if(visible) {
                    child.leaveBase();
                }
                if(getWidgets()!=null) {
                    Composite comp = child.getComposite();
                    child.removeWidgetsBase();
                    comp.dispose();
                }
            }
        }
        if(child instanceof IEmbeddable) {
            ((IEmbeddable)child).setDialog(null);
            if(eventsEnabled) {
                ((IEmbeddable)child).setEventsEnabled(false);
            }
        }
    }

    /**
     * Get the SWT-Composite of the PageClient. All SWT-Widgets of this PageClient
     * are children of this Composite (directly or indirectly).
     *
     * @return the SWT-Composite corresponding to this PageClient
     */
    public Composite getComposite() {
        return composite;
    }

    /**
     * Get the Parent of the PageClient, if any.
     *
     * @return the Parent of this PageClient or null if it is a top-level DialogPage.
     */
    public PageClient getParent() {
        return parent;
    }

    /**
     * Sets the containing dialog of the PageClient.
     * @param dialog
     */
    public void setDialog(IDialog dialog) {
        this.dialog=dialog;
        if(children!=null) {
            for (Iterator it = children.iterator(); it.hasNext();) {
                IXMAControl child = (IXMAControl) it.next();
                if(child instanceof IEmbeddable) { ((IEmbeddable)child).setDialog(dialog); }
            }
        }
    }

    /**
     * Get the DialogPage of the PageClient.
     *
     * @return the DialogPage containing this page or this if this page is a DialogPage.
     */
    public IDialog getDialog() {
        return dialog;
    }

    /**
     * Get the DialogPage of the PageClient.
     *
     * @return the DialogPage containing this page or this if this page is a DialogPage.
     */
    public IDialogPage getDialogPage() {
        return (IDialogPage) getDialog();
    }

    /**
     * Returns an array of all Widgets of this page.
     * @return array of Widgets or null if the widgets are not allready created.
     */
    abstract public Control[] getWidgets();

    /**
     * Creates the Widgets of the PageClient and all Subpages by calling
     * {@link #createWidgets()} on the PageClient and all Subpages.
     */
    public void initGUI() {
        createWidgets();
        if(dynamicModels!=null) {
            for(Iterator it=dynamicModels.iterator();it.hasNext();) {
                DynamicModelSet dynSet = (DynamicModelSet)it.next();
                integrateNewWidgets(dynSet);
            }
        }
        if (children != null) {
            for (Iterator it = children.iterator(); it.hasNext();) {
                ((IXMAControl) it.next()).initGUI();
            }
        }
        //make sure the composite is layouted after all controls are created
        composite.layout(false);
    }

    /**
     * This Method will be implemented in the generated Class for each PageClient, to
     * create the WidgetModels. It will also create all Subpages which are not lazy.
     *
     */
    abstract protected void createModels ();

    /**
     * This Method will be implemented in the generated Class for each PageClient, to
     * indicate if the WidgetModels are allready created.
     *
     * @return true if the WidgetModels exist.
     */
    public abstract boolean hasModels();


    /**
     * This Method will be implemented in the generated Class for each PageClient, to
     * create and initialize all SWT-Widgets of the PageClient.
     * It will 
*
    *
  • instantiate the Widgets
  • *
  • define the Layout (Attachements, Distances, Sizes)
  • *
  • set constant texts (Title, Labels, Tooltips)
  • *
  • define the Taborder
  • *
  • set the focus
  • *
*/ abstract protected void createWidgets(); /** * Notify the PageClient and all Subpages, that the PageClient is becoming visible * by calling {@link #enter()} on the PageClient and all Subpages. */ public void enterBase() { try { if(extend!=null) { extend.enter(); } enter(); visible=true; } catch (Exception exc) { showException(exc); } if (children != null) { for (Iterator it = children.iterator(); it.hasNext();) { ((IXMAControl) it.next()).enterBase(); } } // eventsEnabled=true; } /** * This method will be called every time the PageClient becomes visible. * For DialogPages this method is called exactly once. * For NotebookPages and WizardPages this method is called every time the * user navigates to this PageClient.
* It is intended to be implemented by the application programmer if he * wants to react on this event. */ protected void enter() { } /** * Notify the PageClient and all Subpages, that the PageClient no longer is visible * by calling {@link #leave()} on all Subpages and the PageClient. */ public void leaveBase() { if (children != null) { for (Iterator it = children.iterator(); it.hasNext();) { ((IXMAControl) it.next()).leaveBase(); } } try { visible=false; leave(); } catch (Exception exc) { showException(exc); } } /** * This method will be called every time the PageClient becomes invisible. * For DialogPages this method is called exactly once. * For NotebookPages and WizardPages this method is called every time the * user navigates off this PageClient.
* It is intended to be implemented by the application programmer if he * wants to react on this event. */ protected void leave() { } /** * Notify the PageClient and all Subpages, to remove alle WidgetModles * by calling {@link #removeWidgetModels()} on all Subpages and the PageClient. */ public void removeModel() { if(hasModels()) { if (children != null) { for (Iterator it = children.iterator(); it.hasNext();) { ((IXMAControl) it.next()).removeModel(); } } if(composite!=null) detachUI(); getComponent().freePageModel(getId()); removeWidgetModels(); dynamicModels=null; } } /** * This Method will be implemented in the generated Class for each PageClient, to * remove alle WidgetModels. */ abstract protected void removeWidgetModels(); /** * Notify the PageClient and all Subpages, that the Widgets are disposed * by calling {@link #removeWidgets()} on all Subpages and the PageClient. */ public void removeWidgetsBase() { if (children != null) { for (Iterator it = children.iterator(); it.hasNext();) { ((IXMAControl) it.next()).removeWidgetsBase(); } } if(uiAttached_) detachUI(); if(dynamicModels!=null) { for(Iterator it=dynamicModels.iterator();it.hasNext();) { DynamicModelSet set = ((DynamicModelSet)it.next()); set.setControls(null); } } removeWidgets(); composite=null; } /** * This Method will be implemented in the generated Class for each PageClient, to * remove all Widgets after the Widgets have been disposed. */ abstract protected void removeWidgets(); /** * Notify the PageClient and all Subpages of a possible Change in the PageModels * by calling {@link #determineState()} and {@link #stateChanged()} on the PageClient * and all Subpages. */ public void stateChangedBase() { determineStateBase(); stateChangedExtend(); stateChangedBaseImpl(); } /** * Calls {@link #determineState()} on the PageClient and all subpages */ public void determineStateBase() { determineState(); if (children != null) { for (Iterator it = children.iterator(); it.hasNext();) { ((IEmbeddable) it.next()).determineStateBase(); } } } /** * This method is called every time the content of any WizardModel of the * Page may have been changed.
* It is intended to be implemented by the application programmer, to set * some state variables to simplify the implementation of {@link #stateChanged()}. * This method is called imidiatly befor {@link #stateChanged()}. */ public void determineState() { } /** * Calls {@link IPageExtender#stateChanged()} on the IPageExtender of the PageClient and all subpages */ public void stateChangedExtend() { if(extend!=null) { extend.stateChanged(); } if (children != null) { for (Iterator it = children.iterator(); it.hasNext();) { ((IEmbeddable) it.next()).stateChangedExtend(); } } } /** * Calls {@link #stateChanged()} on the PageClient and all subpages */ public void stateChangedBaseImpl() { stateChanged(); if (children != null) { for (Iterator it = children.iterator(); it.hasNext();) { ((IEmbeddable) it.next()).stateChangedBaseImpl(); } } } /** * This method is called every time the content of any WizardModel of the * Page may have been changed.
* It is intended to be implemented by the application programmer, to enable * or disable Controls. * This method is called emediatly after {@link #determineState()}. */ public void stateChanged() { } /** * Enables/disables GUI-events on the page and all its subpages. * @param enabled */ public void setEventsEnabled(boolean enabled) { eventsEnabled=enabled; if (children != null) { for (Iterator it = children.iterator(); it.hasNext();) { ((IEmbeddable) it.next()).setEventsEnabled(enabled); } } } /** * Determine if this page currently responds to UI-Events * @return true if UI-Events are enabled. */ public boolean isEventsEnabled() { return eventsEnabled; } /** * Implementation of the focus events. * The focusControl on the dialog and the error message in the status bar are updated. * The focus lost event is propagated via {@link #widgetEvent()}. * * @param event the SWT-Event that happened. * @param type the type of the Event, as defined by the event type constants in class SWT. */ void focusEvent(FocusEvent event, int type) { if(type==SWT.FocusIn) { getDialog().setFocusControl((Control)event.widget); getDialog().updateErrorStatus(event.widget); if(event.widget instanceof Text) { // select single line texts on focus in Text text = (Text) event.widget; // caused by keystroke-navigation if((text.getStyle()&SWT.MULTI)==0) { // it does not select the text on mouse-click text.setSelection(0,text.getText().length()+1); } } } else if(type==SWT.FocusOut) { getDialog().setFocusControl(null); widgetEvent(event,SWT.FocusOut); } } /** * Implementation of the Eventhandlers.
* The event is propagated to the WidgetModel of the Widget on which the * event ocured. Then {@link #stateChanged()} is called and at last an eventuelly happended * error ist displayed in the statusBar. * * @param event the SWT-Event that happened. * @param type the type of the Event, as defined by the event type constants in class SWT. */ void widgetEvent(TypedEvent event,int type) { // if(event instanceof KeyEvent) { // if(((((KeyEvent)event).stateMask & (SWT.CONTROL|SWT.SHIFT))!=0) && ((KeyEvent)event).keyCode == 4) { // printData(); // return; // } // } if(!eventsEnabled) return; IDialogPage dialog = getDialogPage(); try { dialog.setEventsEnabled(false); currentEvent=event; UIDelegateClient delegate = (UIDelegateClient) event.widget.getData(); if(delegate!=null) { delegate.handleUIEvent(event, type); } try { if(event instanceof SelectionEvent) { clientEventBase((SelectionEvent)event,type); //TreeEvents (dymamic trees): manipulated Nodes have to be expanded and be collapsed explicit. if(delegate!=null && delegate instanceof TreeUIDelegateClient) { ((TreeUIDelegateClient)delegate).postClientEvent(event, type); } } else if(event.widget instanceof Combo && event instanceof ModifyEvent && ((Combo)event.widget).getSelectionIndex()==-1) { // Selections on Combos caused by direct typing and prefixsearch do not lead to SWT-SelectionEvents, only to ModifyEvents. // ModifyEvents with valid selection index are followed by SelectionEvents and can be ignored here. // ModifyEvents without selection index are not followed by SelectionEvents. We have to simulate them. Event sel = new Event(); sel.widget=event.widget; clientEventBase(new SelectionEvent(sel),SWT.Selection); } } catch (Exception exc) { showException(exc); } // if(dialog instanceof IAppShell) { // try { // ((IAppShell)dialog).refreshClientArea(); // } catch (Exception exc) { // showException(exc); // } // } if(composite!=null && !composite.isDisposed()) { //TODO stateChanged f?r embedded components filtern? getDialog().stateChangedBase(); getDialog().updateErrorStatus(event.widget); } } catch (Exception exc) { showException(exc); } finally { currentEvent=null; dialog.setEventsEnabled(true); } } /** * Shows an Exception in a MessageBox. This method is called every time the xma-runtime * catches an Exception from an clientevent-method of this page. It can be overriden to customize the * exception-handling. * @param exc the catched Exception */ public void showException(Exception exc) { showExceptionImpl(exc,this,getComponent()); } /** * Implementation method used by {@link #showException(Exception)} and {@link ComponentClient} * to show the given exception. * @param exc Exception to show * @param page PageClient, that cached the exception. * @param component ComponentClient of the page, that cached the exception. * @since 2.2.0 */ static public void showExceptionImpl(Exception exc,PageClient page,ComponentClient component) { boolean disposeShell = false; Shell shell = null; IDialog dialog = page!=null?page.getDialog():null; if(dialog!=null) { shell=dialog.getShell(); } // find a suitable shell if an exception occurred before the shell has been created. if(shell==null) shell = component.getDisplay().getActiveShell(); if(shell==null) { shell = new Shell(component.getDisplay()); disposeShell = true; } boolean autoExit = "true".equalsIgnoreCase(component.getSession().getRuntimeProperty("autoExit")); if(autoExit && exc instanceof SysException) { if(((SysException)exc).getCode() == Codes.SERVER_INVALID_SESSION) { ((SysException)exc).setMessage(Codes.getText(Codes.SERVER_INVALID_SESSION_AUTOEXIT)); ((SysException)exc).setCode(Codes.SERVER_INVALID_SESSION_AUTOEXIT); } else if(((SysException)exc).getCode() == Codes.SERVER_UNREACHABLE) { ((SysException)exc).setMessage(Codes.getText(Codes.SERVER_UNREACHABLE_AUTOEXIT)); ((SysException)exc).setCode(Codes.SERVER_UNREACHABLE_AUTOEXIT); ((SysException)exc).setType(INotification.T_QUESTION); ((SysException)exc).setReaction(INotification.R_YES_NO); } } if(!(exc instanceof AppException)) { component.getSession().getLogger().log(LogLevel.WARNING, "exception:", exc); } else if (component.getContext().isLocal()) { component.getSession().getLogger().log(LogLevel.WARNING, "exception:", exc); } int result = NotificationBox.show(exc, shell, component.getContext(), component.getSession(), page); if(disposeShell) { shell.dispose();} if(autoExit && exc instanceof SysException) { if(((SysException)exc).getCode() == Codes.SERVER_INVALID_SESSION_AUTOEXIT) { component.getSession().logout(); System.exit(-1); } else if(((SysException)exc).getCode() == Codes.SERVER_UNREACHABLE_AUTOEXIT) { if(result==INotification.R_YES) { component.getSession().logout(); System.exit(-1); } } } } /** * Displays the provided notification in a modal message box. * * @return A reaction constant of the class INotification, this is one of the constants * starting with praefix R_ and indicates the pressed push button on the * message dialogue. */ public int showMessage (INotification notification) { boolean disposeShell = false; Shell shell = null; if(getDialog()!=null) { shell=getDialog().getShell(); } try { // find a suitable shell if (shell==null) shell = getComponent().getDisplay().getActiveShell(); if (shell==null) { shell = new Shell (getComponent().getDisplay()); disposeShell = true; } // show the box return NotificationBox.show (notification, shell, getComponent().getContext(), getComponent().getSession(), this); } finally { if(disposeShell) { shell.dispose();} } } /** * Adds information (time, user, mandant, envrionment) into the details part of the * given {@link DetailedMessageBox}. This method can be overwritten to add some more * information there. * @since 2.1.2 */ public void addContextInformation(DetailedMessageBox box) { XMAContext context = getSession().getContext(); box.addAdditionalInformation("Time: "+new Date(System.currentTimeMillis())); box.addAdditionalInformation("User: "+context.getName()); box.addAdditionalInformation("Mandant: "+context.getMandant()); box.addAdditionalInformation("Environment: "+context.getEnvironment()); } /** * Implementation of the help event. * Shows the help-uri of the page in a browser window. * * @param event the SWT-Event that happened. * @param type the type of the Event, as defined by the event type constants in class SWT. */ void helpEvent(HelpEvent event,int type) { if(eventsEnabled){ helpEvent(); } } /** * Shows the help-uri of the page in a browser window. */ public void helpEvent() { String helpUri = getHelpUriBase(); if(helpUri!=null) { String uri; try { URL baseUrl = getComponent().getSession().getUri().getHTTP_URI(); if(!baseUrl.getFile().endsWith("/")) baseUrl=new URL(baseUrl.toString()+"/"); uri = new URL(baseUrl,helpUri).toString(); } catch (MalformedURLException e) { throw new SysException(e,"error in help uri"); } HelpView helpView = (HelpView)getComponent().getDisplay().getData("help"); if (helpView == null) { helpView = new HelpView(); getComponent().getDisplay().setData("help",helpView); Shell shell = helpView.open(getComponent().getDisplay()); } if (helpView.isActivated()){ helpView.Navigate(uri); } } } /** * Gets the URI to the help page explaining this page. If there is none, * first the enclosing pages within the same component and at last the * component are searched for a help URI. * * @return the help URI of this page or an enclosing page or component. */ public String getHelpUriBase() { String helpUri = getHelpUri(); helpUri = toLocalizedHelpUri(helpUri,getComponent().getSession().getContext().getLocale()); if(helpUri!=null) return helpUri; else { if(parent!=null) return parent.getHelpUriBase(); else return getComponent().getHelpUri(); } } /** * Gets the URI to the help page explaining this page. The help page must be * showable inside a web browser. * This method is implemented in the generated Class for each PageClient. * * @return the uri of the help page or null if none is defined. */ public String getHelpUri() { return null; } /** * Overwrite this method to convert the given helpUri to the uri of the tranlation * of the help page to the language given in the locale. * The default implementation just returns the helpUri unchanged. * @param helpUri as returned by {@link #getHelpUri()} * @param locale the locale from the XMAContext * @return the uri of the localized help page */ public String toLocalizedHelpUri(String helpUri,Locale locale) { return helpUri; } /** * Places the language code of the given locale into the file-part of the given * uri just before the extention. If the file-part has no extention, * the language code is appended at the end.
* E.g. insertLangInFilename("http://server.lan.at/help/Help.html",Locale.US) * returns http://server.lan.at/help/Help_en.html
* If the parameter uri is null, null is returned. */ public static String insertLangInFilename(String uri,Locale locale) { if(uri==null) return null; int lastSlash = uri.lastIndexOf('/'); int pos = uri.lastIndexOf('.'); int end = uri.length(); if(pos<=lastSlash) pos = end; String result = uri.substring(0,pos)+"_"+locale.getLanguage()+uri.substring(pos!isUIAttached holds * after this method returns. * @exception IllegalStateException if already attached. */ public void attachUI () throws AttachmentExceptionClient { if (isUIAttached()) throw new IllegalStateException("already attached"); try { attachUIImpl(); if(dynamicModels!=null) { for(Iterator it=dynamicModels.iterator();it.hasNext();) { DynamicModelSet set = (DynamicModelSet) it.next(); if(set!=null&&(set.getModel()instanceof IWModelClient)&&set.getControls()!=null&&set.getControls().getControl()!=null) { attach(((IWModelClient)set.getModel()).getUIDelegate(), set.getControls().getControl(), set.getControls().getLabel()); } } } uiAttached_ = true; } catch (AttachmentExceptionClient ex) { detachUI(); throw ex; } } /** * Must be implemented by subclass. The subclass must call * attachUI on every WidgetModels UIDelegateClient of this page. It * must not catch the AttachmentException if it gets * attachement errors from IWModelC.attach. */ public abstract void attachUIImpl () throws AttachmentExceptionClient; /** * Detaches the UI-page from this Page. All UI-controls are reset to an * empty status. This method does nothing if !isUIAttached(). */ public void detachUI() { if (!isUIAttached()) return; WModel[] wModels = getWModels(); for (int i=wModels.length-1; i>=0; i--) { ((IWModelClient)wModels[i]).getUIDelegate().detachUI(); } uiAttached_ = false; } /** * Removes the error for the given widget. * * @param widget the widget where to clear the error state. */ public void clearError (Widget widget) { getDialogPage().clearError(widget); } /** * Sets an error for the given widget. The error is shown in the status line. * Only one error can be shown at a time. The precedence rules are: * 1) the validation error of the widget owning the focus * 2) the error of the widget owning the focus set with this method * 3) the error of the next widget in the tab order containing an error * 4) the error set for the null-widget. */ public void setError (ValidationErrorClient error) { getDialogPage().setError((Widget)error.getControl(),error.getErrorText(getComponent().getContext().getLocale())); } /** * Removes a validation error for a particular widget model. This method * is for internal use only. Calling it causes undefined behaviour! * * @param widget the widget where to clear the error state. */ public void clearValidationErrorImpl (Widget widget) { getDialogPage().clearValidationErrorImpl(widget); } /** * Sets a validation error for a particular widget model. This method * is for internal use only. Calling it causes undefined behaviour! * * @param error indicates the error */ public void setValidationErrorImpl (ValidationErrorClient error) { getDialogPage().setValidationErrorImpl((Widget)error.getControl(),error.getErrorText(getComponent().getContext().getLocale())); } /** * Determines if a validation error currently exists for a given widget. * Note that validation is disabled automatically for readonly widgets, so * readonly widgets never have validation errors. * @param widget to search for validation errors * @return true if the validator reported an error for the given widget. false otherwise. */ public boolean hasValidationError(Widget widget) { return getDialogPage().hasValidationError(widget); } /** * Yields true if this Page has been created since the last server side * event. * * @return true if new. */ public boolean isNew() { return isNew_; } /** * Sets the new state. * * @param what true if this should be marked as new. */ public void setNew(boolean what) { isNew_ = what; } /** * Assigns an id to this Page. This method may only be called by * the Component. * * @param id the assigned id for this Page */ public void setId(short id) { super.setId(id); isNew_=true; } /** * Constructs a {@link at.spardat.xma.rpc.RemoteCall RemoteCall} object to execute a * server side method with the provided name. The corresponding server side Page * class must have a method with the signature *
     * void <namEvent> (RemoteCall call, RemoteReply reply)
     * 
* This method will be called if you call execute on the RemoteCall * object returned by this. * * @param namEvent the name of the server side method to call * @return a RemoteCall object */ public RemoteCallClient newRemoteCall (String namEvent) { return new RemoteCallClient (this, namEvent); } /** * Sets the editable-state of all model's widgets. May be used to move the * whole page into (or out of) a read-only mode. * * @param what the value to set. */ public void setEditable (boolean what) { WModel[] wModels = getWModels(); for (int i=wModels.length-1; i>=0; i--) { ((IWModelClient)wModels[i]).setEditable(what); } } /** * Calls a modal component of the same application. If this page is directly or * indirectly embedded in an {@link IAppShell}, * the called component is pushed on the client area of the IAppShell. * In all other cases, the component is called as a dialog. * * @param componentName name of the component within the application * @param input input properties for the component * @return Properties output properties of the component */ public Properties launchRelative(String componentName, Properties input) { if(getDialog()!=this && getDialog() instanceof IAppShell) { IComponent comp = getComponent().getSession().getComponent(componentName); comp.setProperties(input); ((IAppShell)getDialog()).pushClientComponent((IXMAControl)comp,true); return comp.getProperties(); } else { return getComponent().getSession().launchRelative(componentName, input, getDialog().getShell()); } } /** * Calls a modal component of an other application. If this page is directly or * indirectly embedded in an {@link IAppShell}, * the called component is pushed on the client area of the IAppShell. * In all other cases, the component is called as a dialog. * * @param componentUri absolute URI of the component * @param input input properties for the component * @return Properties output properties of the component */ public Properties launchExtern(String componentUri, Properties input) { if(getDialog()!=this && getDialog() instanceof IAppShell) { IComponent comp = getComponent().getSession().getComponentExtern(componentUri); comp.setProperties(input); ((IAppShell)getDialog()).pushClientComponent((IXMAControl)comp,true); return comp.getProperties(); } else { return getComponent().getSession().launchExtern(componentUri, input, getDialog().getShell()); } } /** * Calls a modal component. If this page is directly or * indirectly embedded in an {@link IAppShell}, * the called component is pushed on the client area of the IAppShell. * In all other cases, the component is called as a dialog. * @param comp the component to call. */ public void launch(EmbeddableComponent comp) { if(getDialog()!=this && getDialog() instanceof IAppShell) { ((IAppShell)getDialog()).pushClientComponent(comp,true); } else { try { comp.invoke(getDialog().getShell()); } finally { if( comp!=null) comp.dispose(); } } } /** * Sets an extention object, which can add behavior to the page. * The event-methods defined in IPageExtender are called on the extend-object * before they are called on the page itself. */ public void setExtend(IPageExtender extend) { this.extend = extend; } /** * Gets the extention object of the page. * The event-methods defined in IPageExtender are called on the extend-object * before they are called on the page itself. * @return the extention object. It may be null. */ public IPageExtender getExtend() { return extend; } /* (non-Javadoc) * @see at.spardat.xma.boot.component.IXMAControl#getContextString() */ public String getContextString() { return contextString; } /** * Sets the context String and notifies the containing AppShell or dialog * if there exists one. * @param text the new contextString */ public void setContextString(String text) { contextString = text; if(getDialog() instanceof IAppShell) { ((IAppShell)getDialog()).contextStringChanged(this,text); } } /** * Brings the window representing this page to the foreground. * * @since version_number * @author s3460 */ public void activatePage(){ Shell shell = getDialog().getShell(); if(shell.getDisplay().getActiveShell() != shell){ shell.forceActive(); //shell.setMinimized(true); //shell.setMinimized(false); } } /** * Is called at the end of RemoteCallClient.execute(). May be overwritten * by subclasses to implement some RPC-post processing. Is not called, * if the RPC terminates with exceptions. * * @param rc the RemoteCallClient whose execute method is about to end * @param reply the RemoteReply object that execute will return */ public void rpcFinished (RemoteCallClient rc, RemoteReply reply) { } /** * Get the current SWT-Event. This Event only exists vor the duration of the event execution. * @return the current SWT-Event or null if called outside an event method. * @since 1.7.1 */ public final TypedEvent getCurrentEvent() { return currentEvent; } /** * Creates the widgets for the new widget model. This will include the widget itself * and eventually needed additionally widgets like a label. * This method must be overwritten, if widget models are added dynamically at runtime. * @param model created using {@link Page#addWModel(WModel)} * @param params parameter map passed to {@link Page#addWModel(WModel, NewModelEventParams)} * @since 2.1.0 */ public ControlSet createWidgetForModel(IWModelClient model, NewModelEventParams params) { return null; } /** * Replaces the widget array generated by guidesigner. * May only be called by the runtime. Do not call this method! * @since 2.1.0 */ protected void setWidgets(Control[] widgets) { throw new SysException("not supported"); } /** * Adds a new widget model at runtime. A corresponding widget model is created automatically * on the other side and this new widget model on the other side is automatically synchronized * with the widgetModel passed as parameter. * On client side the method {@link #createWidgetForModel(IWModelClient, NewModelEventParams)} * is called to create a corresponding SWT widget, too. * @param widgetModel the new widget model which shall be integrated in automatically synchronizations. * @param params to be passed to {@link #createWidgetForModel(IWModelClient, NewModelEventParams)} * @since 2.1.0 */ public void addWModel(WModel widgetModel,NewModelEventParams params) { if(!(widgetModel instanceof IWModelClient)) throw new IllegalArgumentException("only IWModelClients my be used on cliet side"); super.addWModel(widgetModel,params); integrateNewModel((IWModelClient)widgetModel,params); } /** * Creates a new widget model corresponding to the given event and * integrates it into synchronization mechanism. * @param event sent from the other side * @return the new widget model * @since 2.1.0 */ WModel handle(NewModelEvent event) { WModel widgetModel = super.handle(event); integrateNewModel((IWModelClient)widgetModel,event.getParams()); return widgetModel; } /** * Does the additional integration work for widget model on client side. * Creates the formatter. Depending on page state creates and attaches the * corresponding widget or just prepares this so it can be done later by * {@link #initGUI()} and {@link #attachUI()}. * @since 2.1.0 */ private void integrateNewModel(IWModelClient widgetModel,NewModelEventParams params) { DynamicModelSet dynSet = new DynamicModelSet(widgetModel); dynSet.setParams(params); if(dynamicModels==null) dynamicModels = new ArrayList(); dynamicModels.add(dynSet); if(params!=null) { String format = (String) params.getParameter(NewModelEventParams.PARAM_FORMAT); if(format!=null) { try { setFormatter(widgetModel, format); } catch(Exception exc) { showException(exc); } } } if(getWidgets()!=null) { integrateNewWidgets(dynSet); } } /** * Creates and sets the formatter/validator for the given widget model. * The format string must be understandable by at.spardat.enterprise.fmt.FmtFactory. * If you use an other format string format in {@link NewModelEventParams}, you have to * overwrite this method and create the formatter/validator yourself. * @since 2.1.0 */ public void setFormatter(IWModelClient widgetModel,String format) { IFmt formatter = FmtFactory.create(format,getComponent().getSession().getContext().getLocale()); if(widgetModel instanceof ISimpleWMClient) { ((ISimpleWMClient)widgetModel).setFmt(formatter); } else if(widgetModel instanceof IListWMClient) { ((IListWMClient)widgetModel).setFmt(formatter); } } /** * Creates and integrates the widgets corresponding to the model in dynSet. * @since 2.1.0 */ private void integrateNewWidgets(DynamicModelSet dynSet) { if(dynSet.getModel()==null) throw new IllegalStateException("dynamic model must not be null"); try { NewModelEventParams params = dynSet.getParams(); ControlSet created = createWidgetForModel(dynSet.getModel(),params!=null?params:new NewModelEventParams()); if(created!=null) { Control[] oldWidgets = getWidgets(); Control[] newWidgets = created.toArray(); Control[] widgets = new Control[oldWidgets.length+newWidgets.length]; for(int i=0;i0) { lastControl=tabList[tabList.length-1]; } Label label = null; if(labelText!=null && !(model instanceof ISimpleWMClient &&((ISimpleWMClient)model).getType()==Types.T_BOOLEAN)) { label = new Label(parent,SWT.LEFT); label.setText(labelText); } control = (Control) model.getUIDelegate().createControl(parent); if(labelText!=null && model instanceof ISimpleWMClient &&((ISimpleWMClient)model).getType()==Types.T_BOOLEAN) { ((Button)control).setText(labelText); } FormData data = new FormData(); if(seperator!=null) { data.left = new FormAttachment(seperator,scaler.convertXToCurrent(3),SWT.RIGHT); } else if(label!=null) { data.left = new FormAttachment(label,scaler.convertXToCurrent(3),SWT.RIGHT); } else { data.left = new FormAttachment(0,100,0); } data.right = new FormAttachment(100,100,0); if(lastControl==null) { data.top = new FormAttachment(0,100,0); } else { data.top = new FormAttachment(lastControl,scaler.convertYToCurrent(3),SWT.BOTTOM); } control.setLayoutData(data); if(label!=null) { data = new FormData(); data.left = new FormAttachment(0,100,0); if(seperator!=null) { data.right = new FormAttachment(seperator,scaler.convertXToCurrent(-3),SWT.LEFT); } data.top = new FormAttachment(control,0,SWT.CENTER); label.setLayoutData(data); } Control[] newTabList = new Control[tabList.length+1]; System.arraycopy(tabList,0,newTabList,0,tabList.length); newTabList[tabList.length]=control; parent.setTabList(newTabList); parent.layout(); return new ControlSet(control,label); } /** * Attaches the given UIDelegate to the given Control. * Used for integration of dynamically created widget models. * @since 2.1.0 */ private void attach(UIDelegateClient delegate,Control control,Label label) { control.setData(delegate); delegate.attachUI(control,label); if(control instanceof Table) { TableColumn[] cols = ((Table)control).getColumns(); for(int i=0;i=0; i--) { // ((IWModelClient)wModels[i]).setEnabled(what); // } // } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy