Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*******************************************************************************
* 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.effects.DefaultPageEffects;
import at.spardat.xma.page.effects.IPageEffects;
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;
/**
* Indicates that the state of the page has been determined.
*
* This flag has been introduced to be able to produce a exception in case
* the generated method determineState has not been called. (This
* is usually the case in older openXMA projects which have been upgraded
* to a version 5.0.0 or newer.)
*/
private boolean stateHasBeenDetermined = 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;
/**
* A helper object to which the execution of page effects is delegated.
*/
private IPageEffects pageEffects;
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() {
if (pageEffects == null) {
pageEffects = createPageEffects();
}
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();
/**
* This method creates the layout of the widgets of the page.
*/
public void createWidgetsLayout() {
}
/**
* 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();
initializePageEffectsBaseImpl();
stateChangedExtend();
stateChangedBaseImpl();
layoutStateChangedBaseImpl();
applyPageEffectsBaseImpl();
resetLayoutStateBaseImpl();
}
/**
* 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() {
stateHasBeenDetermined=true;
}
/**
* 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();
}
}
}
public void initializePageEffectsBaseImpl() {
initializePageEffects();
if (children != null) {
for (Iterator it = children.iterator(); it.hasNext();) {
((IEmbeddable) it.next()).initializePageEffectsBaseImpl();
}
}
}
/**
* 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();
}
}
}
public void applyPageEffectsBaseImpl() {
applyPageEffects();
if (children != null) {
for (Iterator it = children.iterator(); it.hasNext();) {
((IEmbeddable) it.next()).applyPageEffectsBaseImpl();
}
}
}
public void layoutStateChangedBaseImpl() {
if (hasLayoutStateChanged()) {
layoutStateChanged();
}
if (children != null) {
for (Iterator it = children.iterator(); it.hasNext();) {
((IEmbeddable) it.next()).layoutStateChangedBaseImpl();
}
}
}
public void resetLayoutStateBaseImpl() {
if (hasLayoutStateChanged()) {
resetLayoutState();
}
if (children != null) {
for (Iterator it = children.iterator(); it.hasNext();) {
((IEmbeddable) it.next()).resetLayoutStateBaseImpl();
}
}
}
/**
* This method initializes the page effects
*/
public void initializePageEffects() {
getPageEffects().initializePageEffects();
}
/**
* This method applies the page effects.
*/
public void applyPageEffects() {
getPageEffects().applyPageEffects();
}
/**
* This method is asked before the layout of a page is changed. When
* the method returns true the method layoutStateChanged is called.
* @return true in case the layout is affected by a state change.
*/
protected boolean hasLayoutStateChanged() {
return false;
}
/**
* This method resets the layout state in order to allow to determine
* changes of the layout state. This method is called after the method
* layoutStateChanged.
*/
public void resetLayoutState() {
}
/**
* 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() {
if (!stateHasBeenDetermined) {
throw new RuntimeException("The state of the page has not be determined yet. Most probably 'super.determineState()' is not called in your implementation.");
}
}
/**
* This method is called every time the content of any WizardModel of the
* Page may have been changed and affects the layout.
* It is called after of stateChanged
*/
public void layoutStateChanged() {
}
/**
* 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);
}
}
}
/**
* This method is called by the method createWidgetsLayout.
* @param control
* @param data
* @param condition
*/
protected void setCollapsed(Control control, boolean condition) {
pageEffects.setCollapsed(control,condition);
}
/**
* 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
*
* 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);
// }
// }
}