blob: b1ef43ddb029cba8a6e3feb96fd56b34e5c0939e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010-2015 BSI Business Systems Integration AG.
* 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:
* BSI Business Systems Integration AG - initial API and implementation
******************************************************************************/
package org.eclipse.scout.rt.client.ui.form;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.io.Writer;
import java.lang.reflect.Modifier;
import java.nio.charset.StandardCharsets;
import java.security.Permission;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import org.eclipse.scout.rt.client.ModelContextProxy;
import org.eclipse.scout.rt.client.ModelContextProxy.ModelContext;
import org.eclipse.scout.rt.client.context.ClientRunContext;
import org.eclipse.scout.rt.client.context.ClientRunContexts;
import org.eclipse.scout.rt.client.dto.Data;
import org.eclipse.scout.rt.client.dto.FormData;
import org.eclipse.scout.rt.client.dto.FormData.SdkCommand;
import org.eclipse.scout.rt.client.extension.ui.form.AbstractFormExtension;
import org.eclipse.scout.rt.client.extension.ui.form.FormChains.FormAddSearchTermsChain;
import org.eclipse.scout.rt.client.extension.ui.form.FormChains.FormCheckFieldsChain;
import org.eclipse.scout.rt.client.extension.ui.form.FormChains.FormCloseTimerChain;
import org.eclipse.scout.rt.client.extension.ui.form.FormChains.FormCreateFormDataChain;
import org.eclipse.scout.rt.client.extension.ui.form.FormChains.FormDataChangedChain;
import org.eclipse.scout.rt.client.extension.ui.form.FormChains.FormDisposeFormChain;
import org.eclipse.scout.rt.client.extension.ui.form.FormChains.FormFormActivatedChain;
import org.eclipse.scout.rt.client.extension.ui.form.FormChains.FormInactivityTimerChain;
import org.eclipse.scout.rt.client.extension.ui.form.FormChains.FormInitFormChain;
import org.eclipse.scout.rt.client.extension.ui.form.FormChains.FormOnCloseRequestChain;
import org.eclipse.scout.rt.client.extension.ui.form.FormChains.FormOnVetoExceptionChain;
import org.eclipse.scout.rt.client.extension.ui.form.FormChains.FormResetSearchFilterChain;
import org.eclipse.scout.rt.client.extension.ui.form.FormChains.FormStoredChain;
import org.eclipse.scout.rt.client.extension.ui.form.FormChains.FormTimerChain;
import org.eclipse.scout.rt.client.extension.ui.form.FormChains.FormValidateChain;
import org.eclipse.scout.rt.client.extension.ui.form.FormChains.IsSaveNeededFieldsChain;
import org.eclipse.scout.rt.client.extension.ui.form.IFormExtension;
import org.eclipse.scout.rt.client.extension.ui.form.MoveFormFieldsHandler;
import org.eclipse.scout.rt.client.job.ModelJobs;
import org.eclipse.scout.rt.client.services.common.search.ISearchFilterService;
import org.eclipse.scout.rt.client.ui.DataChangeListener;
import org.eclipse.scout.rt.client.ui.IDisplayParent;
import org.eclipse.scout.rt.client.ui.IEventHistory;
import org.eclipse.scout.rt.client.ui.WeakDataChangeListener;
import org.eclipse.scout.rt.client.ui.basic.filechooser.FileChooser;
import org.eclipse.scout.rt.client.ui.desktop.AbstractDesktop;
import org.eclipse.scout.rt.client.ui.desktop.IDesktop;
import org.eclipse.scout.rt.client.ui.desktop.OpenUriAction;
import org.eclipse.scout.rt.client.ui.desktop.outline.IOutline;
import org.eclipse.scout.rt.client.ui.form.fields.AbstractFormField;
import org.eclipse.scout.rt.client.ui.form.fields.IFormField;
import org.eclipse.scout.rt.client.ui.form.fields.IFormFieldFilter;
import org.eclipse.scout.rt.client.ui.form.fields.IValidateContentDescriptor;
import org.eclipse.scout.rt.client.ui.form.fields.IValueField;
import org.eclipse.scout.rt.client.ui.form.fields.button.AbstractCancelButton;
import org.eclipse.scout.rt.client.ui.form.fields.button.AbstractCloseButton;
import org.eclipse.scout.rt.client.ui.form.fields.button.ButtonEvent;
import org.eclipse.scout.rt.client.ui.form.fields.button.ButtonListener;
import org.eclipse.scout.rt.client.ui.form.fields.button.IButton;
import org.eclipse.scout.rt.client.ui.form.fields.composer.IComposerField;
import org.eclipse.scout.rt.client.ui.form.fields.groupbox.IGroupBox;
import org.eclipse.scout.rt.client.ui.form.fields.tabbox.ITabBox;
import org.eclipse.scout.rt.client.ui.form.fields.wrappedform.IWrappedFormField;
import org.eclipse.scout.rt.client.ui.form.internal.FindFieldByFormDataIdVisitor;
import org.eclipse.scout.rt.client.ui.form.internal.FindFieldByXmlIdsVisitor;
import org.eclipse.scout.rt.client.ui.form.internal.FormDataPropertyFilter;
import org.eclipse.scout.rt.client.ui.messagebox.IMessageBox;
import org.eclipse.scout.rt.client.ui.messagebox.MessageBoxes;
import org.eclipse.scout.rt.client.ui.wizard.IWizard;
import org.eclipse.scout.rt.client.ui.wizard.IWizardStep;
import org.eclipse.scout.rt.platform.BEANS;
import org.eclipse.scout.rt.platform.Order;
import org.eclipse.scout.rt.platform.annotations.ConfigOperation;
import org.eclipse.scout.rt.platform.annotations.ConfigProperty;
import org.eclipse.scout.rt.platform.classid.ClassId;
import org.eclipse.scout.rt.platform.exception.ExceptionHandler;
import org.eclipse.scout.rt.platform.exception.PlatformError;
import org.eclipse.scout.rt.platform.exception.PlatformException;
import org.eclipse.scout.rt.platform.exception.PlatformExceptionTranslator;
import org.eclipse.scout.rt.platform.exception.ProcessingException;
import org.eclipse.scout.rt.platform.exception.VetoException;
import org.eclipse.scout.rt.platform.holders.Holder;
import org.eclipse.scout.rt.platform.holders.IHolder;
import org.eclipse.scout.rt.platform.html.HTML;
import org.eclipse.scout.rt.platform.html.IHtmlContent;
import org.eclipse.scout.rt.platform.html.IHtmlListElement;
import org.eclipse.scout.rt.platform.job.IBlockingCondition;
import org.eclipse.scout.rt.platform.job.IFuture;
import org.eclipse.scout.rt.platform.job.Jobs;
import org.eclipse.scout.rt.platform.reflect.AbstractPropertyObserver;
import org.eclipse.scout.rt.platform.reflect.ConfigurationUtility;
import org.eclipse.scout.rt.platform.reflect.FastPropertyDescriptor;
import org.eclipse.scout.rt.platform.reflect.IPropertyFilter;
import org.eclipse.scout.rt.platform.resource.BinaryResource;
import org.eclipse.scout.rt.platform.status.IMultiStatus;
import org.eclipse.scout.rt.platform.status.IStatus;
import org.eclipse.scout.rt.platform.status.MultiStatus;
import org.eclipse.scout.rt.platform.util.Assertions;
import org.eclipse.scout.rt.platform.util.BeanUtility;
import org.eclipse.scout.rt.platform.util.CollectionUtility;
import org.eclipse.scout.rt.platform.util.EventListenerList;
import org.eclipse.scout.rt.platform.util.PreferredValue;
import org.eclipse.scout.rt.platform.util.XmlUtility;
import org.eclipse.scout.rt.platform.util.concurrent.IRunnable;
import org.eclipse.scout.rt.shared.TEXTS;
import org.eclipse.scout.rt.shared.data.basic.NamedBitMaskHelper;
import org.eclipse.scout.rt.shared.data.form.AbstractFormData;
import org.eclipse.scout.rt.shared.data.form.IPropertyHolder;
import org.eclipse.scout.rt.shared.data.form.fields.AbstractFormFieldData;
import org.eclipse.scout.rt.shared.data.form.properties.AbstractPropertyData;
import org.eclipse.scout.rt.shared.extension.AbstractExtension;
import org.eclipse.scout.rt.shared.extension.ContributionComposite;
import org.eclipse.scout.rt.shared.extension.IContributionOwner;
import org.eclipse.scout.rt.shared.extension.IExtensibleObject;
import org.eclipse.scout.rt.shared.extension.IExtension;
import org.eclipse.scout.rt.shared.extension.ObjectExtensions;
import org.eclipse.scout.rt.shared.services.common.jdbc.SearchFilter;
import org.eclipse.scout.rt.shared.services.common.security.IAccessControlService;
import org.quartz.SimpleScheduleBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@ClassId("cec05259-9e6f-480c-94fa-f02f56e777f7")
@FormData(value = AbstractFormData.class, sdkCommand = SdkCommand.USE)
public abstract class AbstractForm extends AbstractPropertyObserver implements IForm, IExtensibleObject, IContributionOwner {
private static final String INITIALIZED = "INITIALIZED";
private static final String CACHE_BOUNDS = "CACHE_BOUNDS";
private static final String ASK_IF_NEED_SAVE = "ASK_IF_NEED_SAVE";
private static final String BUTTONS_ARMED = "BUTTONS_ARMED";
private static final String CLOSE_TIMER_ARMED = "CLOSE_TIMER_ARMED";
private static final String SHOW_ON_START = "SHOW_ON_START";
private static final String FORM_STORED = "FORM_STORED";
private static final String FORM_LOADING = "FORM_LOADING";
private static final String FORM_STARTED = "FORM_STARTED";
private static final Logger LOG = LoggerFactory.getLogger(AbstractForm.class);
private static final NamedBitMaskHelper FLAGS_BIT_HELPER = new NamedBitMaskHelper(INITIALIZED, CACHE_BOUNDS, ASK_IF_NEED_SAVE,
BUTTONS_ARMED, CLOSE_TIMER_ARMED, SHOW_ON_START);
private static final NamedBitMaskHelper STATE_BIT_HELPER = new NamedBitMaskHelper(FORM_STORED, FORM_LOADING, FORM_STARTED);
private final PreferredValue<IDisplayParent> m_displayParent;
private final EventListenerList m_listenerList;
private final PreferredValue<Boolean> m_modal; // no property, is fixed
private final IBlockingCondition m_blockingCondition;
private final ObjectExtensions<AbstractForm, IFormExtension<? extends AbstractForm>> m_objectExtensions;
private final IEventHistory<FormEvent> m_eventHistory;
/**
* Provides 8 boolean flags.<br>
* Currently used: {@link #INITIALIZED}, {@link #CACHE_BOUNDS}, {@link #ASK_IF_NEED_SAVE}, {@link #BUTTONS_ARMED} ,
* {@link #CLOSE_TIMER_ARMED}, {@link #SHOW_ON_START}
*/
private byte m_flags;
/**
* Provides 8 boolean flags.<br>
* Currently used: {@link #FORM_STORED}, {@link #FORM_LOADING}, {@link #FORM_STARTED}
*/
private byte m_states;
private IFormUIFacade m_uiFacade;
private IWizardStep m_wizardStep;
private int m_displayHint;// no property, is fixed
private String m_displayViewId;// no property, is fixed
private int m_closeType;
private String m_cancelVerificationText;
private IGroupBox m_mainBox;
private IWrappedFormField m_wrappedFormField;
private ButtonListener m_systemButtonListener;
private String m_classId;
private ClientRunContext m_initialClientRunContext; // ClientRunContext of the calling context during initialization.
private IFormHandler m_handler; // never null (ensured by setHandler())
private SearchFilter m_searchFilter;
// current timers
private IFuture<?> m_closeTimerFuture;
private Map<String, IFuture<Void>> m_timerFutureMap;
private DataChangeListener m_internalDataChangeListener;
// field replacement support
private Map<Class<?>, Class<? extends IFormField>> m_fieldReplacements;
private IContributionOwner m_contributionHolder;
public AbstractForm() {
this(true);
}
public AbstractForm(boolean callInitializer) {
m_listenerList = new EventListenerList();
m_modal = new PreferredValue<Boolean>(false, false);
m_closeType = IButton.SYSTEM_TYPE_NONE;
m_displayParent = new PreferredValue<>(null, false);
m_eventHistory = createEventHistory();
setHandler(new NullFormHandler());
setFormLoading(true);
m_blockingCondition = Jobs.newBlockingCondition(false);
m_objectExtensions = new ObjectExtensions<AbstractForm, IFormExtension<? extends AbstractForm>>(this, true);
if (callInitializer) {
callInitializer();
}
}
@Override
public final List<? extends IFormExtension<? extends AbstractForm>> getAllExtensions() {
return m_objectExtensions.getAllExtensions();
}
@Override
public <T extends IExtension<?>> T getExtension(Class<T> c) {
return m_objectExtensions.getExtension(c);
}
@Override
public final List<Object> getAllContributions() {
return m_contributionHolder.getAllContributions();
}
@Override
public final <T> List<T> getContributionsByClass(Class<T> type) {
return m_contributionHolder.getContributionsByClass(type);
}
@Override
public final <T> T getContribution(Class<T> contribution) {
return m_contributionHolder.getContribution(contribution);
}
@Override
public final <T> T optContribution(Class<T> contribution) {
return m_contributionHolder.optContribution(contribution);
}
protected void callInitializer() {
if (isInitialized()) {
return;
}
// Remember the initial ClientRunContext to not loose the Form from current calling context.
m_initialClientRunContext = ClientRunContexts.copyCurrent();
// Run the initialization on behalf of this Form.
ClientRunContexts.copyCurrent().withForm(this).run(new IRunnable() {
@Override
public void run() throws Exception {
interceptInitConfig();
postInitConfig();
setInitialized();
}
});
}
protected IFormExtension<? extends AbstractForm> createLocalExtension() {
return new LocalFormExtension<AbstractForm>(this);
}
/*
* Configuration
*/
/**
* @return the localized title property of the form. Use {@link TEXTS}.
*/
@ConfigProperty(ConfigProperty.TEXT)
@Order(10)
protected String getConfiguredTitle() {
return null;
}
/**
* @return the localized sub-title property of the form. Use {@link TEXTS}.
*/
@ConfigProperty(ConfigProperty.TEXT)
@Order(20)
protected String getConfiguredSubTitle() {
return null;
}
@ConfigProperty(ConfigProperty.TEXT)
@Order(30)
protected String getConfiguredCancelVerificationText() {
return TEXTS.get("FormSaveChangesQuestion");
}
/**
* Overwrite to set the display hint for this {@link IForm}. By default, {@link #DISPLAY_HINT_DIALOG} is configured.
* <ul>
* <li>{@link #DISPLAY_HINT_VIEW}</li>
* <li>{@link #DISPLAY_HINT_DIALOG}</li>
* <li>{@link #DISPLAY_HINT_POPUP_WINDOW}</li>
* </ul>
*/
@ConfigProperty(ConfigProperty.FORM_DISPLAY_HINT)
@Order(40)
protected int getConfiguredDisplayHint() {
return DISPLAY_HINT_DIALOG;
}
/**
* Overwrite to set the display parent for this {@link IForm}. By default, this method returns <code>null</code>,
* meaning that it is derived from the current calling context, or is {@link IDesktop} for views.
* <p>
* A display parent is the anchor to attach this {@link IForm} to, and affects its accessibility and modality scope.
* Possible parents are {@link IDesktop}, {@link IOutline}, or {@link IForm}:
* <ul>
* <li>Desktop: Form is always accessible; blocks the entire desktop if modal;</li>
* <li>Outline: Form is only accessible when the given outline is active; blocks only the outline if modal;</li>
* <li>Form: Form is only accessible when the given Form is active; blocks only the Form if modal;</li>
* </ul>
*
* @return like {@link IDesktop}, {@link IOutline} or {@link IForm}, or <code>null</code> to derive from the calling
* context.
*/
@ConfigProperty(ConfigProperty.OBJECT)
@Order(50)
protected IDisplayParent getConfiguredDisplayParent() {
return null;
}
@ConfigProperty(ConfigProperty.FORM_VIEW_ID)
@Order(60)
protected String getConfiguredDisplayViewId() {
return null;
}
/**
* @return if the form can be minimized.
*/
@ConfigProperty(ConfigProperty.BOOLEAN)
@Order(70)
protected boolean getConfiguredMinimizeEnabled() {
return false;
}
/**
* @return if the form can be maximized.
*/
@ConfigProperty(ConfigProperty.BOOLEAN)
@Order(80)
protected boolean getConfiguredMaximizeEnabled() {
return false;
}
/**
* @return defines if the form is initially minimized
*/
@ConfigProperty(ConfigProperty.BOOLEAN)
@Order(90)
protected boolean getConfiguredMinimized() {
return false;
}
@ConfigProperty(ConfigProperty.BOOLEAN)
@Order(100)
protected boolean getConfiguredMaximized() {
return false;
}
/**
* Overwrite to set the modality hint for this {@link IForm}. By default, this method returns
* {@link #MODALITY_HINT_AUTO}, meaning that modality is derived from the configured <code>display-hint</code>. For
* dialogs, it is <code>true</code>, for views <code>false</code>.
*
* @return {@link #MODALITY_HINT_MODAL} to make this {@link IForm} modal in respect to its {@link IDisplayParent}, or
* {@link #MODALITY_HINT_MODELESS} otherwise, or {@link #MODALITY_HINT_AUTO} to derive modality from the
* <code>display-hint</code>.
* @see #MODALITY_HINT_MODAL
* @see #MODALITY_HINT_MODELESS
* @see #MODALITY_HINT_AUTO
* @see #getConfiguredDisplayHint()
*/
@ConfigProperty(ConfigProperty.BOOLEAN)
@Order(110)
protected int getConfiguredModalityHint() {
return MODALITY_HINT_AUTO;
}
/**
* Configure whether to show this {@link IForm} once started.
* <p>
* If set to <code>true</code> and this {@link IForm} is started, it is added to the {@link IDesktop} in order to be
* displayed. By default, this property is set to <code>true</code>.
*/
@ConfigProperty(ConfigProperty.BOOLEAN)
@Order(120)
protected boolean getConfiguredShowOnStart() {
return true;
}
@ConfigProperty(ConfigProperty.BOOLEAN)
@Order(130)
protected boolean getConfiguredCacheBounds() {
return false;
}
/**
* AskIfNeedSave defines if a message box with yes, no and cancel option is shown to the user for confirmation after
* having made at least one change in the form and then having pressed the cancel button.
*
* @return <code>true</code> if message box is shown for confirmation, <code>false</code> otherwise.
*/
@ConfigProperty(ConfigProperty.BOOLEAN)
@Order(140)
protected boolean getConfiguredAskIfNeedSave() {
return true;
}
/**
* @return configured icon ID for this form
*/
@ConfigProperty(ConfigProperty.ICON_ID)
@Order(150)
protected String getConfiguredIconId() {
return null;
}
/**
* Configures the css class(es) of this form.
* <p>
* Subclasses can override this method. Default is {@code null}.
*
* @return a string containing one or more classes separated by space, or null if no class should be set.
*/
@ConfigProperty(ConfigProperty.STRING)
@Order(160)
protected String getConfiguredCssClass() {
return null;
}
@ConfigProperty(ConfigProperty.INTEGER)
@Order(170)
protected int/* seconds */ getConfiguredCloseTimer() {
return 0;
}
@ConfigProperty(ConfigProperty.INTEGER)
@Order(180)
protected int/* seconds */ getConfiguredCustomTimer() {
return 0;
}
/**
* Override this method to mark a form as closable. In case of closable the close button [X] is displayed either in
* the form or the view header. The default implementations says a form displayed as a dialog containing a
* {@link AbstractCloseButton} or a {@link AbstractCancelButton} is closable.
*
* @return
*/
@ConfigProperty(ConfigProperty.BOOLEAN)
@Order(190)
protected boolean getConfiguredClosable() {
// legacy support if not overwritten
return getDisplayHint() == DISPLAY_HINT_DIALOG && hasCloseOrCancelButton();
}
/**
* Whether or not a changed form should display the save needed state (dirty) in the dialog or view header.
*
* @return true to display the save needed state, false otherwise.
*/
@ConfigProperty(ConfigProperty.BOOLEAN)
@Order(200)
protected boolean getConfiguredSaveNeededVisible() {
return false;
}
/**
* This method is called to get an exclusive key of the form. The key is used to open the same form with the same
* handler only once. Obviously this behavior can only be used for view forms.
*
* @see AbstractDesktop#getSimilarViewForms(IForm)
* @return null for exclusive form behavior an exclusive key to ensure similar handling.
*/
@Override
public Object computeExclusiveKey() {
return null;
}
/**
* Initialize the form and all of its fields. By default any of the #start* methods of the form call this method
* <p>
* This method is called in the process of the initialization. The UI is not ready yet.
*/
@ConfigOperation
@Order(10)
protected void execInitForm() {
}
/**
* This method is called when UI is ready.
*/
@ConfigOperation
@Order(11)
protected void execFormActivated() {
}
/**
* see {@link IDesktop#dataChanged(Object...)}
*/
@ConfigOperation
@Order(13)
protected void execDataChanged(Object... dataTypes) {
}
/**
* This method is called in order to check field validity.<br>
* This method is called before {@link IFormHandler#interceptCheckFields()} and before the form is validated and
* stored.<br>
* After this method, the form is checking fields itself and displaying a dialog with missing and invalid fields.
*
* @return true when this check is done and further checks can continue, false to silently cancel the current process
* @throws ProcessingException
* to cancel the current process with error handling and user notification such as a dialog
*/
@ConfigOperation
@Order(13)
protected boolean execCheckFields() {
return true;
}
/**
* This method is called in order to update derived states like button enablings.<br>
* This method is called before {@link IFormHandler#interceptValidate()} and before the form is stored.
*
* @return true when validate is successful, false to silently cancel the current process
* @throws ProcessingException
* to cancel the current process with error handling and user notification such as a dialog
*/
@ConfigOperation
@Order(14)
protected boolean execValidate() {
return true;
}
/**
* This method is called in order to update pages on the desktop after the form stored data.<br>
* This method is called after {@link IFormHandler#execStore()}.
*/
@ConfigOperation
@Order(16)
protected void execStored() {
}
@ConfigOperation
@Order(50)
protected boolean execIsSaveNeeded() {
return getRootGroupBox().isSaveNeeded();
}
/**
* @throws ProcessingException
* / {@link VetoException} if the exception should produce further info messages (default)
*/
@ConfigOperation
@Order(17)
protected void execOnVetoException(VetoException e, int code) {
throw e;
}
/**
* @param kill
* true if a widget close icon (normally the X on the titlebar) was pressed or ESC was pressed
* @param enabledButtonSystemTypes
* set of all <code>IButton#SYSTEM_TYPE_*</code> of all enabled and visible buttons of this form (never
* <code>null</code>)
*/
@ConfigOperation
@Order(18)
protected void execOnCloseRequest(boolean kill, Set<Integer> enabledButtonSystemTypes) {
if (enabledButtonSystemTypes.contains(IButton.SYSTEM_TYPE_CLOSE)) {
doClose();
}
else {
doCancel();
}
}
@ConfigOperation
@Order(19)
protected void execDisposeForm() {
}
@ConfigOperation
@Order(20)
protected void execCloseTimer() {
doClose();
}
@ConfigOperation
@Order(30)
protected void execInactivityTimer() {
doClose();
}
@ConfigOperation
@Order(40)
protected void execTimer(String timerId) {
LOG.info("execTimer {}", timerId);
}
/**
* add verbose information to the search filter
*/
@ConfigOperation
@Order(50)
protected void execAddSearchTerms(SearchFilter search) {
}
protected boolean hasCloseOrCancelButton() {
for (IFormField f : getAllFields()) {
if (f.isEnabled() && f.isVisible() && (f instanceof IButton)) {
switch (((IButton) f).getSystemType()) {
case IButton.SYSTEM_TYPE_CLOSE:
case IButton.SYSTEM_TYPE_CANCEL: {
return true;
}
}
}
}
return false;
}
private Class<? extends IGroupBox> getConfiguredMainBox() {
Class[] dca = ConfigurationUtility.getDeclaredPublicClasses(getClass());
return ConfigurationUtility.filterClassIgnoringInjectFieldAnnotation(dca, IGroupBox.class);
}
private List<Class<IFormField>> getConfiguredInjectedFields() {
Class[] dca = ConfigurationUtility.getDeclaredPublicClasses(getClass());
return ConfigurationUtility.filterClassesWithInjectFieldAnnotation(dca, IFormField.class);
}
protected final void interceptInitConfig() {
final Holder<RuntimeException> exceptionHolder = new Holder<>(RuntimeException.class, null);
final Holder<PlatformError> errorHolder = new Holder<>(PlatformError.class, null);
m_objectExtensions.initConfig(createLocalExtension(), new Runnable() {
@Override
public void run() {
try {
initConfig();
}
catch (RuntimeException e) {
exceptionHolder.setValue(e);
}
catch (PlatformError e) {
errorHolder.setValue(e);
}
}
});
if (exceptionHolder.getValue() != null) {
throw exceptionHolder.getValue();
}
else if (errorHolder.getValue() != null) {
throw errorHolder.getValue();
}
}
protected void initConfig() {
m_uiFacade = BEANS.get(ModelContextProxy.class).newProxy(new P_UIFacade(), ModelContext.copyCurrent().withForm(this));
m_timerFutureMap = new HashMap<>();
setShowOnStart(getConfiguredShowOnStart());
m_contributionHolder = new ContributionComposite(this);
// prepare injected fields
List<Class<IFormField>> fieldArray = getConfiguredInjectedFields();
DefaultFormFieldInjection injectedFields = null;
IGroupBox rootBox = getRootGroupBox();
try {
if (fieldArray.size() > 0) {
injectedFields = new DefaultFormFieldInjection(this);
injectedFields.addFields(fieldArray);
FormFieldInjectionThreadLocal.push(injectedFields);
}
// add mainbox if getter returns null
if (rootBox == null) {
List<IGroupBox> contributedFields = m_contributionHolder.getContributionsByClass(IGroupBox.class);
rootBox = CollectionUtility.firstElement(contributedFields);
if (rootBox == null) {
Class<? extends IGroupBox> mainBoxClass = getConfiguredMainBox();
if (mainBoxClass != null) {
rootBox = ConfigurationUtility.newInnerInstance(this, mainBoxClass);
}
}
m_mainBox = rootBox;
}
}
finally {
if (injectedFields != null) {
m_fieldReplacements = injectedFields.getReplacementMapping();
FormFieldInjectionThreadLocal.pop(injectedFields);
}
}
if (rootBox != null) {
rootBox.setFormInternal(this);
rootBox.setMainBox(true);
rootBox.updateKeyStrokes();
if (rootBox.isScrollable().isUndefined()) {
rootBox.setScrollable(true);
}
}
// move form fields
new MoveFormFieldsHandler(this).moveFields();
//
if (getConfiguredCloseTimer() > 0) {
setCloseTimer(getConfiguredCloseTimer());
}
if (getConfiguredCustomTimer() > 0) {
setTimer("custom", getConfiguredCustomTimer());
}
if (getConfiguredCancelVerificationText() != null) {
setCancelVerificationText(getConfiguredCancelVerificationText());
}
if (getConfiguredTitle() != null) {
setTitle(getConfiguredTitle());
}
if (getConfiguredSubTitle() != null) {
setSubTitle(getConfiguredSubTitle());
}
setMinimizeEnabled(getConfiguredMinimizeEnabled());
setMaximizeEnabled(getConfiguredMaximizeEnabled());
setMinimized(getConfiguredMinimized());
setMaximized(getConfiguredMaximized());
setCacheBounds(getConfiguredCacheBounds());
setAskIfNeedSave(getConfiguredAskIfNeedSave());
setIconId(getConfiguredIconId());
setCssClass((getConfiguredCssClass()));
// Set 'modality' as preferred value if not 'auto'.
int modalityHint = getConfiguredModalityHint();
if (modalityHint != MODALITY_HINT_AUTO) {
m_modal.set(modalityHint == MODALITY_HINT_MODAL, true);
}
// Set 'displayParent' as preferred value if not null; must precede setting of the 'displayHint'.
IDisplayParent displayParent = getConfiguredDisplayParent();
if (displayParent != null) {
m_displayParent.set(displayParent, true);
}
else {
m_displayParent.set(getDesktop(), false);
}
setDisplayHint(getConfiguredDisplayHint());
setDisplayViewId(getConfiguredDisplayViewId());
setClosable(getConfiguredClosable());
setSaveNeededVisible(getConfiguredSaveNeededVisible());
// visit all system buttons and attach observer
m_systemButtonListener = new P_SystemButtonListener();// is auto-detaching
IFormFieldVisitor v2 = new IFormFieldVisitor() {
@Override
public boolean visitField(IFormField field, int level, int fieldIndex) {
if (field instanceof IButton) {
final IButton button = (IButton) field;
if (button.getSystemType() != IButton.SYSTEM_TYPE_NONE) {
button.addButtonListener(m_systemButtonListener);
}
}
return true;
}
};
visitFields(v2);
getRootGroupBox().addPropertyChangeListener(new P_MainBoxPropertyChangeProxy());
setButtonsArmed(true);
}
private boolean isInitialized() {
return FLAGS_BIT_HELPER.isBitSet(INITIALIZED, m_flags);
}
private void setInitialized() {
m_flags = FLAGS_BIT_HELPER.setBit(INITIALIZED, m_flags);
}
@Override
public void setEnabledPermission(Permission p) {
boolean b = true;
if (p != null) {
b = BEANS.get(IAccessControlService.class).checkPermission(p);
}
setEnabledGranted(b);
}
@Override
public boolean isEnabledGranted() {
IGroupBox box = getRootGroupBox();
if (box == null) {
return false;
}
return box.isEnabledGranted();
}
@Override
public void setEnabledGranted(boolean b) {
IGroupBox box = getRootGroupBox();
if (box != null) {
box.setEnabledGranted(b);
}
}
@Override
public void setVisiblePermission(Permission p) {
boolean b = true;
if (p != null) {
b = BEANS.get(IAccessControlService.class).checkPermission(p);
}
setVisibleGranted(b);
}
@Override
public boolean isVisibleGranted() {
IGroupBox box = getRootGroupBox();
if (box == null) {
return false;
}
return box.isVisibleGranted();
}
@Override
public void setVisibleGranted(boolean visible) {
IGroupBox box = getRootGroupBox();
if (box != null) {
box.setVisibleGranted(visible);
}
}
@Override
public String getIconId() {
return propertySupport.getPropertyString(PROP_ICON_ID);
}
@Override
public void setIconId(String iconId) {
propertySupport.setPropertyString(PROP_ICON_ID, iconId);
}
@Override
public String getCssClass() {
return propertySupport.getPropertyString(PROP_CSS_CLASS);
}
@Override
public void setCssClass(String cssClass) {
propertySupport.setPropertyString(PROP_CSS_CLASS, cssClass);
}
@Override
public boolean isClosable() {
return propertySupport.getPropertyBool(PROP_CLOSABLE);
}
@Override
public void setClosable(boolean closable) {
propertySupport.setPropertyBool(PROP_CLOSABLE, closable);
}
@Override
public boolean isSaveNeededVisible() {
return propertySupport.getPropertyBool(PROP_SAVE_NEEDED_VISIBLE);
}
@Override
public void setSaveNeededVisible(boolean saveNeededVisible) {
propertySupport.setPropertyBool(PROP_SAVE_NEEDED_VISIBLE, saveNeededVisible);
}
@Override
public IMultiStatus getStatus() {
final IMultiStatus ms = getStatusInternal();
return (ms == null) ? null : new MultiStatus(ms);
}
@Override
public boolean hasStatus(IStatus status) {
final IMultiStatus ms = getStatusInternal();
if (ms != null) {
return ms.equals(status) || ms.containsStatus(status);
}
return false;
}
/**
* @return the live error status
*/
protected MultiStatus getStatusInternal() {
return (MultiStatus) propertySupport.getProperty(PROP_STATUS);
}
@Override
public void setStatus(IMultiStatus status) {
setStatusInternal(new MultiStatus(status));
}
protected void setStatusInternal(MultiStatus status) {
propertySupport.setProperty(PROP_STATUS, status);
}
@Override
public void clearStatus() {
propertySupport.setProperty(PROP_STATUS, null);
}
/**
* Adds an error status
*/
@Override
public void addStatus(IStatus newStatus) {
final MultiStatus status = ensureMultiStatus(getStatusInternal());
// Create a copy, otherwise no PropertyChange event is fired
final MultiStatus copy = new MultiStatus(status);
copy.add(newStatus);
setStatus(copy);
}
@Override
public void removeStatus(IStatus status) {
final MultiStatus ms = getStatusInternal();
if (ms != null) {
if (ms.equals(status)) {
clearStatus();
}
else if (ms.containsStatus(status)) {
// Create a copy, otherwise no PropertyChange event is fired
final MultiStatus copy = new MultiStatus(ms);
copy.removeAll(status);
if (copy.getChildren().isEmpty()) {
clearStatus();
}
else {
setStatusInternal(copy);
}
}
}
}
private MultiStatus ensureMultiStatus(IStatus s) {
if (s instanceof MultiStatus) {
return (MultiStatus) s;
}
final MultiStatus ms = new MultiStatus();
if (s != null) {
ms.add(s);
}
return ms;
}
/**
* Register a {@link DataChangeListener} on the desktop for these dataTypes<br>
* Example:
*
* <pre>
* registerDataChangeListener(CRMEnum.Company, CRMEnum.Project, CRMEnum.Task);
* </pre>
*/
public void registerDataChangeListener(Object... dataTypes) {
if (m_internalDataChangeListener == null) {
m_internalDataChangeListener = new WeakDataChangeListener() {
@Override
public void dataChanged(Object... innerDataTypes) {
interceptDataChanged(innerDataTypes);
}
};
}
getDesktop().addDataChangeListener(m_internalDataChangeListener, dataTypes);
}
/**
* Unregister the {@link DataChangeListener} from the desktop for these dataTypes<br>
* Example:
*
* <pre>
* unregisterDataChangeListener(CRMEnum.Company, CRMEnum.Project, CRMEnum.Task);
* </pre>
*/
public void unregisterDataChangeListener(Object... dataTypes) {
if (m_internalDataChangeListener != null) {
getDesktop().removeDataChangeListener(m_internalDataChangeListener, dataTypes);
}
}
protected IForm startInternalExclusive(IFormHandler handler) {
if (m_blockingCondition.isBlocking()) {
throw new ProcessingException("The form " + getFormId() + " has already been started");
}
for (IForm simCandidate : getDesktop().getSimilarViewForms(this)) {
if (handler != null
&& simCandidate.getHandler() != null
&& handler.getClass().getName() == simCandidate.getHandler().getClass().getName()
&& simCandidate.getHandler().isOpenExclusive()
&& handler.isOpenExclusive()) {
getDesktop().activateForm(simCandidate);
return simCandidate;
}
}
return startInternal(handler);
}
@Override
public void start() {
startInternal(getHandler());
}
/**
* This method is called from the implemented handler methods in a explicit form subclass
*/
protected IForm startInternal(final IFormHandler handler) {
ClientRunContexts.copyCurrent().withForm(this).run(new IRunnable() {
@Override
public void run() throws Exception {
if (isBlockingInternal()) {
throw new IllegalStateException("The form " + getFormId() + " has already been started");
}
// Ensure that boolean is set not only once by the constructor
setFormLoading(true);
setHandler(handler);
m_closeType = IButton.SYSTEM_TYPE_NONE;
m_blockingCondition.setBlocking(true);
try {
initForm();
loadStateInternal();
// if form was disposed during initForm() or loadStateInternal()
if (!isBlockingInternal()) {
return;
}
if (getHandler().isGuiLess()) {
// make sure the form is storing since it is not showing
storeStateInternal();
markSaved();
doFinally();
disposeFormInternal();
return;
}
}
catch (RuntimeException | PlatformError e) {
disposeFormInternal();
PlatformException pe = BEANS.get(PlatformExceptionTranslator.class).translate(e)
.withContextInfo("form", AbstractForm.this.getClass().getName());
if (pe instanceof VetoException) {
VetoException ve = (VetoException) pe;
interceptOnVetoException(ve, ve.getStatus().getCode());
}
throw pe;
}
setButtonsArmed(true);
setCloseTimerArmed(true);
setFormStarted(true);
// Notify the UI to display this form.
if (isShowOnStart()) {
IDesktop desktop = getDesktop();
if (desktop == null || !desktop.isOpened()) {
throw new ProcessingException("There is no desktop or it is not open in the UI.");
}
else {
desktop.showForm(AbstractForm.this);
}
}
}
});
return this;
}
@Override
public void startWizardStep(IWizardStep wizardStep, Class<? extends IFormHandler> handlerType) {
if (handlerType != null) {
IFormHandler formHandler = ConfigurationUtility.newInnerInstance(this, handlerType);
setHandler(formHandler);
}
m_wizardStep = wizardStep;
setShowOnStart(false);
setAskIfNeedSave(false);
final String systemButtonHiddenInWizard = "systemButtonHiddenInWizard";
// hide top level process buttons with a system type
for (IFormField f : getRootGroupBox().getFields()) {
if (f instanceof IButton) {
IButton b = (IButton) f;
if (b.getSystemType() != IButton.SYSTEM_TYPE_NONE) {
// hide
b.setVisible(false, systemButtonHiddenInWizard);
}
}
}
// start
start();
}
@Override
public void startWizardStep(IWizardStep<?> wizardStep) {
startWizardStep(wizardStep, null);
}
@Override
public void waitFor() {
// Do not exit upon interruption.
m_blockingCondition.waitForUninterruptibly(ModelJobs.EXECUTION_HINT_UI_INTERACTION_REQUIRED);
}
protected static Class<?> getDataAnnotationValue(Class<?> clazz) {
while (clazz != null && !Object.class.equals(clazz)) {
Data annotation = clazz.getAnnotation(Data.class);
if (annotation != null) {
Class<?> value = annotation.value();
if (value != null && !Object.class.equals(value)) {
return value;
}
}
clazz = clazz.getSuperclass();
}
return null;
}
private void exportExtensionProperties(Object o, IPropertyHolder target) {
if (!(o instanceof IExtensibleObject)) {
return;
}
for (IExtension<?> ex : ((IExtensibleObject) o).getAllExtensions()) {
Class<?> dto = getDataAnnotationValue(ex.getClass());
if (dto != null && !Object.class.equals(dto)) {
Object propertyTarget = target.getContribution(dto);
Map<String, Object> fieldProperties = BeanUtility.getProperties(ex, AbstractFormField.class, new FormDataPropertyFilter());
BeanUtility.setProperties(propertyTarget, fieldProperties, false, null);
}
}
}
@Override
public AbstractFormData createFormData() {
return interceptCreateFormData();
}
@Override
public void exportFormData(final AbstractFormData target) {
// locally declared form properties
Map<String, Object> properties = BeanUtility.getProperties(this, AbstractForm.class, new FormDataPropertyFilter());
BeanUtility.setProperties(target, properties, false, null);
// properties in extensions of form
exportExtensionProperties(this, target);
final Set<IFormField> exportedFields = new HashSet<IFormField>();
// all fields
Map<Integer, Map<String/* qualified field id */, AbstractFormFieldData>> breadthFirstMap = target.getAllFieldsRec();
for (Map<String/* qualified field id */, AbstractFormFieldData> targetMap : breadthFirstMap.values()) {
for (Map.Entry<String, AbstractFormFieldData> e : targetMap.entrySet()) {
String fieldQId = e.getKey();
AbstractFormFieldData data = e.getValue();
FindFieldByFormDataIdVisitor v = new FindFieldByFormDataIdVisitor(fieldQId, this);
visitFields(v);
IFormField f = v.getField();
if (f != null) {
// field properties
properties = BeanUtility.getProperties(f, AbstractFormField.class, new FormDataPropertyFilter());
BeanUtility.setProperties(data, properties, false, null);
exportExtensionProperties(f, data);
// field state
f.exportFormFieldData(data);
// remember exported fields
exportedFields.add(f);
}
else {
LOG.warn("Cannot find field with id '{}' in form '{}' for DTO '{}'.", fieldQId, getClass().getName(), data.getClass().getName());
}
}
}
// visit remaining fields (there could be an extension with properties e.g. on a groupbox)
final Holder<RuntimeException> exHolder = new Holder<>(RuntimeException.class);
final Holder<PlatformError> errorHolder = new Holder<>(PlatformError.class);
visitFields(new IFormFieldVisitor() {
@Override
public boolean visitField(IFormField field, int level, int fieldIndex) {
if (exportedFields.contains(field)) {
// already exported -> skip
return true;
}
final IForm formOfField = field.getForm();
if (formOfField == null) {
// either form has not been initialized or the field is part of a composite field, that does not override setForminternal -> skip
LOG.info("Extension properties are not exported for fields on which getForm() returns null. "
+ "Ensure that the form is initialized and that the field's parent invokes field.setFormInternal(IForm) [exportingForm={}, field={}]",
AbstractForm.this.getClass().getName(), field.getClass().getName());
return true;
}
if (formOfField != AbstractForm.this) {
// field belongs to another form -> skip
return true;
}
try {
exportExtensionProperties(field, target);
}
catch (RuntimeException e) {
exHolder.setValue(e);
}
catch (PlatformError e) {
errorHolder.setValue(e);
}
return exHolder.getValue() == null && errorHolder.getValue() == null;
}
});
if (exHolder.getValue() != null) {
throw exHolder.getValue();
}
else if (errorHolder.getValue() != null) {
throw errorHolder.getValue();
}
}
@Override
public void importFormData(AbstractFormData source) {
importFormData(source, false, null);
}
@Override
public void importFormData(AbstractFormData source, boolean valueChangeTriggersEnabled) {
importFormData(source, valueChangeTriggersEnabled, null);
}
@Override
public void importFormData(AbstractFormData source, boolean valueChangeTriggersEnabled, IPropertyFilter filter) {
importFormData(source, valueChangeTriggersEnabled, filter, null);
}
private void removeNotSetProperties(IPropertyHolder dto, Map<String, Object> properties) {
for (Iterator<String> it = properties.keySet().iterator(); it.hasNext();) {
String propertyId = it.next();
AbstractPropertyData pd = dto.getPropertyById(propertyId);
if (pd != null && !pd.isValueSet()) {
it.remove();
}
}
}
private void importProperties(IPropertyHolder source, Object target, Class<?> stopClass, IPropertyFilter filter) {
// local properties
Map<String, Object> properties = BeanUtility.getProperties(source, stopClass, filter);
if (!properties.isEmpty()) {
removeNotSetProperties(source, properties);
BeanUtility.setProperties(target, properties, false, null);
}
// properties of the extensions
List<Object> allContributions = source.getAllContributions();
if (!allContributions.isEmpty()) {
for (Object con : allContributions) {
if (con instanceof IPropertyHolder) {
IPropertyHolder data = (IPropertyHolder) con;
Map<String, Object> extensionProperties = BeanUtility.getProperties(data, stopClass, filter);
if (!extensionProperties.isEmpty()) {
Object clientPart = getClientPartOfExtensionOrContributionRec(data, target);
if (clientPart != null) {
removeNotSetProperties(data, extensionProperties);
BeanUtility.setProperties(clientPart, extensionProperties, false, null);
}
else {
LOG.warn("cannot find extension for property data '{}' in form '{}'.", data.getClass().getName(), this.getClass().getName());
}
}
}
}
}
}
private Object getClientPartOfExtensionOrContribution(Object extToSearch, Object owner) {
if (owner instanceof IExtensibleObject) {
IExtensibleObject exOwner = (IExtensibleObject) owner;
for (IExtension<?> ex : exOwner.getAllExtensions()) {
Class<?> dto = getDataAnnotationValue(ex.getClass());
if (extToSearch.getClass().equals(dto)) {
return ex;
}
}
}
if (owner instanceof IContributionOwner) {
IContributionOwner compOwner = (IContributionOwner) owner;
for (Object o : compOwner.getAllContributions()) {
FormData annotation = o.getClass().getAnnotation(FormData.class);
if (annotation != null && annotation.value().equals(extToSearch.getClass())) {
return o;
}
}
}
return null;
}
private Object getClientPartOfExtensionOrContributionRec(final Object extToSearch, Object owner) {
Object ext = getClientPartOfExtensionOrContribution(extToSearch, owner);
if (ext != null) {
return ext;
}
// search for the extension in the children
final IHolder<Object> result = new Holder<Object>(Object.class);
IFormFieldVisitor visitor = new IFormFieldVisitor() {
@Override
public boolean visitField(IFormField field, int level, int fieldIndex) {
result.setValue(getClientPartOfExtensionOrContribution(extToSearch, field));
return result.getValue() == null;
}
};
if (owner instanceof IForm) {
((IForm) owner).visitFields(visitor);
}
else if (owner instanceof IFormField) {
((IFormField) owner).acceptVisitor(visitor, 0, 0, true);
}
return result.getValue();
}
private static Class<?> getFieldStopClass(Object data) {
if (data instanceof AbstractFormFieldData) {
return ((AbstractFormFieldData) data).getFieldStopClass();
}
return AbstractFormFieldData.class;
}
@Override
public void importFormData(AbstractFormData source, boolean valueChangeTriggersEnabled, IPropertyFilter filter, IFormFieldFilter formFieldFilter) {
Assertions.assertNotNull(source, "source form data must not be null");
if (filter == null) {
filter = new FormDataPropertyFilter();
}
// form properties
importProperties(source, this, AbstractFormData.class, filter);
// sort fields, first non-slave fields, then slave fields in transitive order
LinkedList<IFormField> masterList = new LinkedList<IFormField>();
LinkedList<IFormField> slaveList = new LinkedList<IFormField>();
HashMap<IFormField, AbstractFormFieldData> dataMap = new HashMap<IFormField, AbstractFormFieldData>();
// collect fields and split them into masters/slaves
Map<Integer, Map<String/* qualified field id */, AbstractFormFieldData>> breadthFirstMap = source.getAllFieldsRec();
for (Map<String/* qualified field id */, AbstractFormFieldData> sourceMap : breadthFirstMap.values()) {
for (Map.Entry<String, AbstractFormFieldData> e : sourceMap.entrySet()) {
String fieldQId = e.getKey();
AbstractFormFieldData data = e.getValue();
FindFieldByFormDataIdVisitor v = new FindFieldByFormDataIdVisitor(fieldQId, this);
visitFields(v);
IFormField f = v.getField();
if (f != null) {
if (formFieldFilter == null || formFieldFilter.accept(f)) {
dataMap.put(f, data);
if (f.getMasterField() != null) {
int index = slaveList.indexOf(f.getMasterField());
if (index >= 0) {
slaveList.add(index + 1, f);
}
else {
slaveList.addFirst(f);
}
}
else {
masterList.add(f);
}
}
}
else {
LOG.warn("cannot find field data for '{}' in form '{}'.", fieldQId, getClass().getName());
}
}
}
for (IFormField f : masterList) {
importFormField(f, dataMap, valueChangeTriggersEnabled, filter);
}
for (IFormField f : slaveList) {
importFormField(f, dataMap, valueChangeTriggersEnabled, filter);
}
}
private void importFormField(IFormField f, Map<IFormField, AbstractFormFieldData> dataMap, boolean valueChangeTriggersEnabled, IPropertyFilter filter) {
AbstractFormFieldData data = dataMap.get(f);
// form field properties
importProperties(data, f, getFieldStopClass(data), filter);
// field state
f.importFormFieldData(data, valueChangeTriggersEnabled);
}
public static String parseFormId(String className) {
String s = className;
int i = Math.max(s.lastIndexOf('$'), s.lastIndexOf('.'));
s = s.substring(i + 1);
return s;
}
@Override
public String getFormId() {
return parseFormId(getClass().getName());
}
/**
* <p>
* <ul>
* <li>If a classId was set with {@link #setClassId(String)} this value is returned.
* <li>Else if the class is annotated with {@link ClassId}, the annotation value is returned.
* <li>Otherwise the class name is returned.
* </ul>
*/
@Override
public String classId() {
if (m_classId != null) {
return m_classId;
}
String simpleClassId = ConfigurationUtility.getAnnotatedClassIdWithFallback(getClass());
if (getOuterFormField() != null) {
return simpleClassId + ID_CONCAT_SYMBOL + getOuterFormField().classId();
}
return simpleClassId;
}
@Override
public void setClassId(String classId) {
m_classId = classId;
}
@Override
public IFormHandler getHandler() {
return m_handler;
}
@Override
public void setHandler(IFormHandler handler) {
if (handler != m_handler) {
if (m_handler != null) {
m_handler.setFormInternal(null);
}
if (handler == null) {
handler = new NullFormHandler();
}
m_handler = handler;
m_handler.setFormInternal(this);
}
}
@Override
public IWizard getWizard() {
return (getWizardStep() != null) ? getWizardStep().getWizard() : null;
}
@Override
public IWizardStep getWizardStep() {
return m_wizardStep;
}
@Override
public List<IFormField> getAllFields() {
P_AbstractCollectingFieldVisitor<IFormField> v = new P_AbstractCollectingFieldVisitor<IFormField>() {
@Override
public boolean visitField(IFormField field, int level, int fieldIndex) {
collect(field);
return true;
}
};
visitFields(v);
return v.getCollection();
}
@Override
public boolean visitFields(IFormFieldVisitor visitor) {
return getRootGroupBox().visitFields(visitor);
}
/**
* @return {@link IDesktop} from current calling context.
*/
protected IDesktop getDesktop() {
return IDesktop.CURRENT.get();
}
@Override
public final SearchFilter getSearchFilter() {
if (m_searchFilter == null) {
resetSearchFilter();
}
return m_searchFilter;
}
@Override
public final void setSearchFilter(SearchFilter searchFilter) {
m_searchFilter = searchFilter;
}
/**
* Alias for {@link #resetSearchFilter()}
*/
public void rebuildSearchFilter() {
resetSearchFilter();
}
@Override
public void resetSearchFilter() {
if (m_searchFilter == null) {
SearchFilter filter;
ISearchFilterService sfs = BEANS.get(ISearchFilterService.class);
if (sfs != null) {
filter = sfs.createNewSearchFilter();
}
else {
filter = new SearchFilter();
}
m_searchFilter = filter;
}
try {
interceptResetSearchFilter(m_searchFilter);
}
catch (Exception e) {
BEANS.get(ExceptionHandler.class).handle(e);
}
}
/**
* Called when saving the form via {@link #resetSearchFilter()}.
* <p>
* This operation fills up the search filter and subclass override sets the formData property of the
* {@link SearchFilter#setFormData(AbstractFormData)} and adds verbose texts with
* {@link SearchFilter#addDisplayText(String)}
* <p>
* May call {@link #setSearchFilter(SearchFilter)}
* <p>
* Attaches a filled form data to the search filter if {@link #execCreateFormData()} returns a value.
*
* @param searchFilter
* is never null
*/
@ConfigOperation
@Order(10)
protected void execResetSearchFilter(final SearchFilter searchFilter) {
searchFilter.clear();
// add verbose field texts
// do not use visitor, so children can block traversal on whole subtrees
getRootGroupBox().applySearch(searchFilter);
// add verbose form texts
interceptAddSearchTerms(searchFilter);
// override may add form data
AbstractFormData data = createFormData();
if (data != null) {
exportFormData(data);
getSearchFilter().setFormData(data);
}
}
/**
* Creates an empty form data that can be used for example by {@link #interceptResetSearchFilter(SearchFilter)}.
* <p>
* The default creates a new instance based on the {@link FormData} annotation.
*
* @since 3.8
*/
@ConfigOperation
@Order(11)
protected AbstractFormData execCreateFormData() {
Class<? extends AbstractFormData> formDataClass = getFormDataClass();
if (formDataClass == null) {
return null;
}
try {
return formDataClass.newInstance();
}
catch (InstantiationException | IllegalAccessException e) {
BEANS.get(ExceptionHandler.class).handle(new ProcessingException("error creating instance of class '" + formDataClass.getName() + "'.", e));
return null;
}
}
protected Class<? extends AbstractFormData> getFormDataClass() {
FormData formDataAnnotation = getClass().getAnnotation(FormData.class);
//look in superclasses for annotation
Class<?> superclazz = getClass().getSuperclass();
while (formDataAnnotation == null && superclazz != null) {
formDataAnnotation = superclazz.getAnnotation(FormData.class);
superclazz = superclazz.getSuperclass();
}
if (formDataAnnotation == null) {
//no annotation found..
return null;
}
@SuppressWarnings("unchecked")
Class<? extends AbstractFormData> formDataClass = formDataAnnotation.value();
if (formDataClass == null) {
return null;
}
if (AbstractFormData.class.isAssignableFrom(formDataClass) && !Modifier.isAbstract(formDataClass.getModifiers())) {
return formDataClass;
}
return null;
}
@Override
public boolean isFormStored() {
return STATE_BIT_HELPER.isBitSet(FORM_STORED, m_states);
}
@Override
public void setFormStored(boolean b) {
m_states = STATE_BIT_HELPER.changeBit(FORM_STORED, b, m_states);
}
@Override
public boolean isFormLoading() {
return STATE_BIT_HELPER.isBitSet(FORM_LOADING, m_states);
}
private void setFormLoading(boolean b) {
m_states = STATE_BIT_HELPER.changeBit(FORM_LOADING, b, m_states);
}
/**
* Mainbox getter
*/
@Override
public IGroupBox getRootGroupBox() {
return m_mainBox;
}
@Override
public IForm getOuterForm() {
return m_wrappedFormField != null ? m_wrappedFormField.getForm() : null;
}
@Override
public IWrappedFormField getOuterFormField() {
return m_wrappedFormField;
}
@Override
public void setWrapperFieldInternal(IWrappedFormField w) {
m_wrappedFormField = w;
}
@Override
public IFormField getFieldById(final String id) {
return getRootGroupBox().getFieldById(id);
}
@Override
public <T extends IFormField> T getFieldById(String id, Class<T> type) {
return getRootGroupBox().getFieldById(id, type);
}
@Override
public <T extends IFormField> T getFieldByClass(Class<T> c) {
return getRootGroupBox().getFieldByClass(c);
}
/**
* override in subclasses to perform form initialization before handler starts
*/
protected void postInitConfig() {
FormUtility.postInitConfig(this);
FormUtility.rebuildFieldGrid(this, true);
}
@Override
public void initForm() {
// form
initFormInternal();
// fields
FormUtility.initFormFields(this);
// custom
interceptInitForm();
}
protected void initFormInternal() {
calculateSaveNeeded();
}
@Override
public int getCloseSystemType() {
return m_closeType;
}
@Override
public void setCloseSystemType(int type) {
m_closeType = type;
}
/**
* do not use or override this internal method
*/
protected void loadStateInternal() {
fireFormLoadBefore();
if (!isBlockingInternal()) {
return;
}
getHandler().onLoad();
if (!isBlockingInternal()) {
return;
}
fireFormLoadAfter();
if (!isBlockingInternal()) {
return;
}
// set all values to 'unchanged'
markSaved();
rebuildSearchFilter();
setFormLoading(false);
getHandler().onPostLoad();
if (!isBlockingInternal()) {
return;
}
// if not visible mode, mark form changed
if (getHandler().isGuiLess()) {
touch();
}
fireFormLoadComplete();
}
/**
* Store state of form, regardless of validity and completeness do not use or override this internal method directly
*/
protected void storeStateInternal() {
if (!m_blockingCondition.isBlocking()) {
String msg = TEXTS.get("FormDisposedMessage", getTitle());
LOG.error(msg);
throw new VetoException(msg);
}
fireFormStoreBefore();
setFormStored(true);
try {
rebuildSearchFilter();
m_searchFilter.setCompleted(true);
getHandler().onStore();
interceptStored();
if (!isFormStored()) {
//the form was marked as not stored in AbstractFormHandler#execStore() or AbstractForm#execStored().
ProcessingException e = new ProcessingException("Form was marked as not stored.");
e.consume();
throw e;
}
}
catch (RuntimeException | PlatformError e) {
// clear search
if (m_searchFilter != null) {
m_searchFilter.clear();
}
// store was not successfully stored
setFormStored(false);
if (e instanceof RuntimeException) { // NOSONAR
throwVetoExceptionInternal((RuntimeException) e);
}
else if (e instanceof PlatformError) { // NOSONAR
throw e;
}
// if exception was caught and suppressed, this form was after all successfully stored
// normally this code is not reached since the exception will be passed out
setFormStored(true);
}
fireFormStoreAfter();
}
/**
* do not use or override this internal method
*/
protected void discardStateInternal() {
fireFormDiscarded();
getHandler().onDiscard();
}
@Override
public void setCloseTimer(int seconds) {
removeCloseTimer();
if (seconds > 0) {
setCloseTimerArmed(true);
m_closeTimerFuture = installFormCloseTimer(seconds);
}
}
/**
* do not use or override this internal method
*/
protected void throwVetoExceptionInternal(final RuntimeException e) {
PlatformException pe = BEANS.get(PlatformExceptionTranslator.class).translate(e)
.withContextInfo("form", getClass().getName());
if (pe instanceof VetoException && !pe.isConsumed()) {
VetoException ve = (VetoException) pe;
interceptOnVetoException(ve, ve.getStatus().getCode());
ve.consume(); // if it was not re-thrown it is assumed to be consumed
}
throw e;
}
@Override
public void removeCloseTimer() {
setCloseTimerArmed(false);
setSubTitle(null);
}
@Override
public void validateForm() {
if (!interceptCheckFields()) {
VetoException veto = new VetoException("Validate " + getClass().getSimpleName());
veto.consume();
throw veto;
}
if (!getHandler().onCheckFields()) {
VetoException veto = new VetoException("Validate " + getClass().getSimpleName());
veto.consume();
throw veto;
}
// check all fields that might be invalid
final ArrayList<String> invalidTexts = new ArrayList<String>();
final ArrayList<String> mandatoryTexts = new ArrayList<String>();
P_AbstractCollectingFieldVisitor<IValidateContentDescriptor> v = new P_AbstractCollectingFieldVisitor<IValidateContentDescriptor>() {
@Override
public boolean visitField(IFormField f, int level, int fieldIndex) {
IValidateContentDescriptor desc = f.validateContent();
if (desc != null) {
if (desc.getErrorStatus() != null) {
invalidTexts.add(desc.getDisplayText() + ": " + desc.getErrorStatus().getMessage());
}
else {
mandatoryTexts.add(desc.getDisplayText());
}
if (getCollectionCount() == 0) {
collect(desc);
}
}
return true;
}
};
visitFields(v);
if (v.getCollectionCount() > 0) {
IValidateContentDescriptor firstProblem = v.getCollection().get(0);
if (LOG.isInfoEnabled()) {
LOG.info("there are fields with errors");
}
if (firstProblem != null) {
firstProblem.activateProblemLocation();
}
throw new VetoException().withHtmlMessage(createValidationMessageBoxHtml(invalidTexts, mandatoryTexts));
}
if (!interceptValidate()) {
VetoException veto = new VetoException("Validate " + getClass().getSimpleName());
veto.consume();
throw veto;
}
if (!getHandler().onValidate()) {
VetoException veto = new VetoException("Validate " + getClass().getSimpleName());
veto.consume();
throw veto;
}
}
protected IHtmlContent createValidationMessageBoxHtml(final List<String> invalidTexts, final List<String> mandatoryTexts) {
List<CharSequence> content = new ArrayList<>();
if (mandatoryTexts.size() > 0) {
content.add(HTML.bold(TEXTS.get("FormEmptyMandatoryFieldsMessage")));
List<IHtmlListElement> mandatoryTextElements = new ArrayList<>();
for (String e : mandatoryTexts) {
mandatoryTextElements.add(HTML.li(e));
}
content.add(HTML.ul(mandatoryTextElements));
content.add(HTML.br());
}
if (invalidTexts.size() > 0) {
content.add(HTML.bold(TEXTS.get("FormInvalidFieldsMessage")));
List<IHtmlListElement> invalidTextElements = new ArrayList<>();
for (String e : invalidTexts) {
invalidTextElements.add(HTML.li(e));
}
content.add(HTML.ul(invalidTextElements));
}
return HTML.fragment(content);
}
/**
* attach a statement (mode) that is executed every interval
*
* @since Build 195 09.02.2005, imo
*/
@Override
public void setTimer(String timerId, int seconds) {
removeTimer(timerId);
if (seconds > 0) {
IFuture<Void> future = startTimer(seconds, timerId);
m_timerFutureMap.put(timerId, future);
}
}
/**
* remove a statement (mode) that is executed every interval
*
* @since Build 195 09.02.2005, imo
*/
@Override
public void removeTimer(String timerId) {
IFuture<Void> future = m_timerFutureMap.remove(timerId);
if (future != null) {
future.cancel(false);
}
}
@Override
public void doClose() {
if (!isBlockingInternal()) {
return;
}
try {
m_closeType = IButton.SYSTEM_TYPE_CLOSE;
discardStateInternal();
doFinally();
disposeFormInternal();
}
catch (RuntimeException | PlatformError e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e)
.withContextInfo("form", getClass().getName());
}
}
@Override
public void doCancel() {
if (!isBlockingInternal()) {
return;
}
m_closeType = IButton.SYSTEM_TYPE_CANCEL;
try {
// ensure all fields have the right save-needed-state
checkSaveNeeded();
// find any fields that needs save
P_AbstractCollectingFieldVisitor<IFormField> collector = new P_AbstractCollectingFieldVisitor<IFormField>() {
@Override
public boolean visitField(IFormField field, int level, int fieldIndex) {
if (field.isSaveNeeded()) {
collect(field);
return false;
}
else {
return true;
}
}
};
visitFields(collector);
if (collector.getCollectionCount() > 0 && isAskIfNeedSave()) {
int result = MessageBoxes.createYesNoCancel().withDisplayParent(this).withHeader(getCancelVerificationText()).withSeverity(IStatus.INFO).show();
if (result == IMessageBox.YES_OPTION) {
doOk();
return;
}
else if (result == IMessageBox.NO_OPTION) {
doClose();
return;
}
else {
VetoException e = new VetoException(TEXTS.get("UserCancelledOperation"));
e.consume();
throw e;
}
}
discardStateInternal();
doFinally();
disposeFormInternal();
}
catch (RuntimeException | PlatformError e) {
m_closeType = IButton.SYSTEM_TYPE_NONE;
throw BEANS.get(PlatformExceptionTranslator.class).translate(e)
.withContextInfo("form", getClass().getName());
}
}
@Override
public void doReset() {
setFormLoading(true);
// reset values
P_AbstractCollectingFieldVisitor v = new P_AbstractCollectingFieldVisitor() {
@Override
public boolean visitField(IFormField field, int level, int fieldIndex) {
if (field instanceof IValueField) {
IValueField f = (IValueField) field;
f.resetValue();
}
else if (field instanceof IComposerField) {
IComposerField f = (IComposerField) field;
f.resetValue();
}
return true;
}
};
try {
visitFields(v);
// init again
initForm();
// load again
loadStateInternal();
}
catch (RuntimeException | PlatformError e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e)
.withContextInfo("form", getClass().getName());
}
}
/**
* Save data and close the form. It will make this decision based on {@link #isSaveNeeded}. Saving usually involves
* calling the <code>execStore</code> method of the current form handler.
*
* @see AbstractFormHandler#execStore()
*/
@Override
public void doOk() {
if (!isBlockingInternal()) {
return;
}
try {
m_closeType = IButton.SYSTEM_TYPE_NONE;
checkSaveNeeded();
validateForm();
m_closeType = IButton.SYSTEM_TYPE_OK;
if (isSaveNeeded()) {
storeStateInternal();
markSaved();
}
doFinally();
disposeFormInternal();
}
catch (RuntimeException e) {
m_closeType = IButton.SYSTEM_TYPE_NONE;
throwVetoExceptionInternal(e);
}
catch (PlatformError e) {
m_closeType = IButton.SYSTEM_TYPE_NONE;
throw e;
}
}
@Override
public void doSaveWithoutMarkerChange() {
if (!isBlockingInternal()) {
return;
}
try {
m_closeType = IButton.SYSTEM_TYPE_NONE;
// ensure all fields have the right save-needed-state
checkSaveNeeded();
validateForm();
m_closeType = IButton.SYSTEM_TYPE_SAVE_WITHOUT_MARKER_CHANGE;
storeStateInternal();
// do not set to "markSaved"
}
catch (RuntimeException e) {
m_closeType = IButton.SYSTEM_TYPE_NONE;
throwVetoExceptionInternal(e);
}
catch (PlatformError e) {
m_closeType = IButton.SYSTEM_TYPE_NONE;
throw e;
}
}
@Override
public void doSave() {
if (!isBlockingInternal()) {
return;
}
try {
m_closeType = IButton.SYSTEM_TYPE_NONE;
// ensure all fields have the right save-needed-state
checkSaveNeeded();
validateForm();
m_closeType = IButton.SYSTEM_TYPE_SAVE;
if (isSaveNeeded()) {
storeStateInternal();
markSaved();
}
}
catch (RuntimeException e) {
m_closeType = IButton.SYSTEM_TYPE_NONE;
throwVetoExceptionInternal(e);
}
catch (PlatformError e) {
m_closeType = IButton.SYSTEM_TYPE_NONE;
throw e;
}
}
@Override
public void setAllEnabled(final boolean b) {
IGroupBox box = getRootGroupBox();
if (box != null) {
box.setEnabled(b, false, true);
}
}
@Override
public void doFinally() {
try {
getHandler().onFinally();
}
catch (RuntimeException | PlatformError e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e)
.withContextInfo("form", getClass().getName());
}
}
@Override
public String getCancelVerificationText() {
return m_cancelVerificationText;
}
@Override
public void setCancelVerificationText(String text) {
m_cancelVerificationText = text;
}
@Override
public List<? extends IFormField> getInvalidFields() {
// check all fields that might be invalid
P_AbstractCollectingFieldVisitor<IFormField> v = new P_AbstractCollectingFieldVisitor<IFormField>() {
@Override
public boolean visitField(IFormField f, int level, int fieldIndex) {
if (!f.isContentValid()) {
collect(f);
}
return true;
}
};
visitFields(v);
return v.getCollection();
}
@Override
public final void checkSaveNeeded() {
// call checkSaveNeeded on all fields
P_AbstractCollectingFieldVisitor<IFormField> v = new P_AbstractCollectingFieldVisitor<IFormField>() {
@Override
public boolean visitField(IFormField f, int level, int fieldIndex) {
f.checkSaveNeeded();
return true;
}
};
visitFields(v);
calculateSaveNeeded();
}
private boolean/* ok */ checkForVerifyingFields() {
// check all fields that might be invalid
P_AbstractCollectingFieldVisitor v = new P_AbstractCollectingFieldVisitor() {
@Override
public boolean visitField(IFormField field, int level, int fieldIndex) {
if (field instanceof IValueField) {
IValueField f = (IValueField) field;
if (f.isValueChanging() || f.isValueParsing()) {
return false;
}
}
return true;
}
};
return visitFields(v);
}
private void closeFormInternal(boolean kill) {
if (isBlockingInternal()) {
try {
// check if there is an active close, cancel or finish button
final Set<Integer> enabledSystemTypes = new HashSet<Integer>();
final Set<IButton> enabledSystemButtons = new HashSet<IButton>();
IFormFieldVisitor v = new IFormFieldVisitor() {
@Override
public boolean visitField(IFormField field, int level, int fieldIndex) {
if (field instanceof IButton) {
IButton b = (IButton) field;
if (b.isEnabled() && b.isVisible()) {
enabledSystemTypes.add(b.getSystemType());
enabledSystemButtons.add(b);
}
}
return true;
}
};
visitFields(v);
interceptOnCloseRequest(kill, enabledSystemTypes);
}
catch (RuntimeException | PlatformError e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e)
.withContextInfo("form", getClass().getName());
}
}
}
@Override
public void touch() {
getRootGroupBox().touch();
}
protected void calculateSaveNeeded() {
propertySupport.setPropertyBool(PROP_SAVE_NEEDED, interceptIsSaveNeeded());
}
@Override
public boolean isSaveNeeded() {
return propertySupport.getPropertyBool(PROP_SAVE_NEEDED);
}
@Override
public void markSaved() {
getRootGroupBox().markSaved();
}
@Override
public boolean isEmpty() {
return getRootGroupBox().isEmpty();
}
/**
* do not use or override this internal method
*/
protected void disposeFormInternal() {
if (!isBlockingInternal()) {
return;
}
try {
setButtonsArmed(false);
setCloseTimerArmed(false);
setFormStarted(false);
// Cancel and remove timers
Iterator<IFuture<Void>> iterator = m_timerFutureMap.values().iterator();
while (iterator.hasNext()) {
iterator.next().cancel(false);
iterator.remove();
}
// Dispose Fields and Form
try {
FormUtility.disposeFormFields(this);
interceptDisposeForm();
unregisterDataChangeListener((Object[]) null);
}
catch (Exception t) {
LOG.warn("Failed to dispose Form {}", getClass().getName(), t);
}
// Detach Form from Desktop.
getDesktop().hideForm(this);
// Link all Forms which have this Form as 'displayParent' with the Desktop.
List<IForm> forms = getDesktop().getForms(this);
for (IForm childForm : forms) {
childForm.setDisplayParent(getDesktop());
}
}
finally {
m_blockingCondition.setBlocking(false);
fireFormClosed();
}
}
@Override
public boolean isShowing() {
return getDesktop().isShowing(this);
}
@Override
public boolean isFormClosed() {
return !isBlockingInternal();
}
@Override
public boolean isFormStartable() {
return !isFormStarted() && !isBlockingInternal();
}
@Override
public boolean isFormStarted() {
return STATE_BIT_HELPER.isBitSet(FORM_STARTED, m_states);
}
private void setFormStarted(boolean started) {
m_states = STATE_BIT_HELPER.changeBit(FORM_STARTED, started, m_states);
}
protected boolean isBlockingInternal() {
return m_blockingCondition.isBlocking();
}
@Override
public Object getProperty(String name) {
return propertySupport.getProperty(name);
}
@Override
public void setProperty(String name, Object value) {
propertySupport.setProperty(name, value);
}
@Override
public boolean hasProperty(String name) {
return propertySupport.hasProperty(name);
}
@Override
public void loadFromXmlString(String xml) {
if (xml == null) {
return;
}
Document xmlDocument = XmlUtility.getXmlDocument(xml);
loadFromXml(xmlDocument.getDocumentElement());
}
@Override
public String storeToXmlString() {
try {
Document e = storeToXml();
return XmlUtility.wellformDocument(e);
}
catch (RuntimeException e) {
throw BEANS.get(PlatformExceptionTranslator.class)
.translate(e)
.withContextInfo("form", getClass().getName());
}
}
@Override
public Document storeToXml() {
Document doc = XmlUtility.createNewXmlDocument("form-state");
storeToXml(doc.getDocumentElement());
return doc;
}
@Override
public void storeToXml(Element root) {
root.setAttribute("formId", getFormId());
root.setAttribute("formQname", getClass().getName());
// add custom properties
Element xProps = root.getOwnerDocument().createElement("properties");
root.appendChild(xProps);
IPropertyFilter filter = new IPropertyFilter() {
@Override
public boolean accept(FastPropertyDescriptor descriptor) {
if (descriptor.getPropertyType().isInstance(IFormField.class)) {
return false;
}
if (!descriptor.getPropertyType().isPrimitive() && !Serializable.class.isAssignableFrom(descriptor.getPropertyType())) {
return false;
}
if (descriptor.getReadMethod() == null || descriptor.getWriteMethod() == null) {
return false;
}
return true;
}
};
Map<String, Object> props = BeanUtility.getProperties(this, AbstractForm.class, filter);
storePropertiesToXml(xProps, props);
// add extension properties
for (IExtension<?> ex : getAllExtensions()) {
Map<String, Object> extensionProps = BeanUtility.getProperties(ex, AbstractFormExtension.class, filter);
if (extensionProps.isEmpty()) {
continue;
}
Element xExtension = root.getOwnerDocument().createElement("extension");
xProps.appendChild(xExtension);
xExtension.setAttribute("extensionId", ex.getClass().getSimpleName());
xExtension.setAttribute("extensionQname", ex.getClass().getName());
storePropertiesToXml(xExtension, extensionProps);
}
// add fields
final Element xFields = root.getOwnerDocument().createElement("fields");
root.appendChild(xFields);
final Holder<RuntimeException> exceptionHolder = new Holder<>(RuntimeException.class);
final Holder<PlatformError> errorHolder = new Holder<>(PlatformError.class);
P_AbstractCollectingFieldVisitor v = new P_AbstractCollectingFieldVisitor() {
@Override
public boolean visitField(IFormField field, int level, int fieldIndex) {
if (field.getForm() != AbstractForm.this) {
// field is part of a wrapped form and is handled by the AbstractWrappedFormField
return true;
}
Element xField = xFields.getOwnerDocument().createElement("field");
try {
field.storeToXml(xField);
xFields.appendChild(xField);
}
catch (RuntimeException e) {
exceptionHolder.setValue(e);
return false;
}
catch (PlatformError e) {
errorHolder.setValue(e);
return false;
}
return true;
}
};
visitFields(v);
if (exceptionHolder.getValue() != null) {
throw exceptionHolder.getValue();
}
else if (errorHolder.getValue() != null) {
throw errorHolder.getValue();
}
}
/**
* Adds a &lt;property&gt; element for every given property to the parent element.
*
* @see #loadPropertiesFromXml(Element)
*/
protected void storePropertiesToXml(Element parent, Map<String, Object> props) {
for (Entry<String, Object> entry : props.entrySet()) {
try {
Element xProp = parent.getOwnerDocument().createElement("property");
parent.appendChild(xProp);
xProp.setAttribute("name", entry.getKey());
XmlUtility.setObjectAttribute(xProp, "value", entry.getValue());
}
catch (Exception e) {
throw new ProcessingException("property " + entry.getKey() + " with value " + entry.getValue(), e);
}
}
}
@Override
public void loadFromXml(Element root) {
String formId = getFormId();
String xmlId = root.getAttribute("formId");
if (!formId.equals(xmlId)) {
throw new ProcessingException("xml id='{}' does not match form id='{}'", xmlId, formId);
}
// load properties
Element xProps = XmlUtility.getFirstChildElement(root, "properties");
if (xProps != null) {
Map<String, Object> props = loadPropertiesFromXml(xProps);
BeanUtility.setProperties(this, props, true, null);
// load extension properties
for (Element xExtension : XmlUtility.getChildElements(xProps, "extension")) {
String extensionId = xExtension.getAttribute("extensionId");
String extensionQname = xExtension.getAttribute("extensionQname");
IFormExtension<? extends AbstractForm> extension = findFormExtensionById(extensionQname, extensionId);
if (extension == null) {
continue;
}
Map<String, Object> extensionProps = loadPropertiesFromXml(xExtension);
BeanUtility.setProperties(extension, extensionProps, true, null);
}
}
// load fields
Element xFields = XmlUtility.getFirstChildElement(root, "fields");
if (xFields != null) {
for (Element xField : XmlUtility.getChildElements(xFields, "field")) {
List<String> xmlFieldIds = new LinkedList<String>();
// add enclosing field path to xml field IDs
for (Element element : XmlUtility.getChildElements(xField, "enclosingField")) {
xmlFieldIds.add(element.getAttribute("fieldId"));
}
xmlFieldIds.add(xField.getAttribute("fieldId"));
FindFieldByXmlIdsVisitor v = new FindFieldByXmlIdsVisitor(xmlFieldIds.toArray(new String[xmlFieldIds.size()]));
visitFields(v);
IFormField f = v.getField();
if (f != null) {
f.loadFromXml(xField);
}
}
}
// in all tabboxes select the first tab that contains data, iff the current
// tab has no values set
getRootGroupBox().visitFields(new IFormFieldVisitor() {
@Override
public boolean visitField(IFormField field, int level, int fieldIndex) {
if (field instanceof ITabBox) {
ITabBox tabBox = (ITabBox) field;
IGroupBox selbox = tabBox.getSelectedTab();
if (selbox == null || !selbox.isSaveNeeded()) {
for (IGroupBox g : tabBox.getGroupBoxes()) {
if (g.isSaveNeeded()) {
tabBox.setSelectedTab(g);
break;
}
}
}
}
return true;
}
});
}
/**
* Looks for an {@link IFormExtension} available on this form with the given extensionQname or extensionId (in this
* order).
*
* @return the form extension with the given qualified name, id or <code>null</code>, if no extension has been found.
*/
protected IFormExtension<? extends AbstractForm> findFormExtensionById(String extensionQname, String extensionId) {
IFormExtension<?> candidate = null;
for (IFormExtension<? extends AbstractForm> extension : getAllExtensions()) {
if (extension.getClass().getName().equals(extensionQname)) {
return extension;
}
else if (candidate == null && extension.getClass().getSimpleName().equals(extensionId)) {
candidate = extension;
}
}
return candidate;
}
/**
* Extracts properties from &lt;property&gt; child elements in the given parent element.
*
* @return Map of property name to property value
* @see #storePropertiesToXml(Element, Map)
*/
protected Map<String, Object> loadPropertiesFromXml(Element xProps) {
Map<String, Object> props = new HashMap<String, Object>();
for (Element xProp : XmlUtility.getChildElements(xProps, "property")) {
String name = xProp.getAttribute("name");
try {
Object o = XmlUtility.getObjectAttribute(xProp, "value");
props.put(name, o);
}
catch (Exception e) {
LOG.warn("Could not load XML property {}", name, e);
}
}
return props;
}
@Override
public void doExportXml(boolean saveAs) {
// export search parameters
try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); Writer w = new OutputStreamWriter(bos, StandardCharsets.UTF_8)) {
XmlUtility.wellformDocument(storeToXml(), w);
BinaryResource res = new BinaryResource("form.xml", bos.toByteArray());
getDesktop().openUri(res, OpenUriAction.DOWNLOAD);
}
catch (Exception e) {
BEANS.get(ExceptionHandler.class).handle(new ProcessingException(TEXTS.get("FormExportXml") + " " + getTitle(), e));
}
}
@Override
public void doImportXml() {
try {
List<BinaryResource> a = new FileChooser(Collections.singletonList("xml"), false).startChooser();
if (a.size() == 1) {
BinaryResource newPath = a.get(0);
try (InputStream in = new ByteArrayInputStream(newPath.getContent())) { // NOSONAR
Document doc = XmlUtility.getXmlDocument(in);
// load xml to search
loadFromXml(doc.getDocumentElement());
}
catch (Exception e) {
LOG.warn("Could not load XML from file: {}", newPath, e);
MessageBoxes.createOk().withDisplayParent(this).withHeader(TEXTS.get("LoadFormXmlFailedText")).show();
}
}
}
catch (Exception e) {
BEANS.get(ExceptionHandler.class).handle(e);
}
}
@Override
public void activate() {
getDesktop().activateForm(this);
}
@Override
public void requestFocus(IFormField f) {
if (f == null || f.getForm() != this) {
return;
}
fireRequestEvent(FormEvent.TYPE_REQUEST_FOCUS, f);
}
@Override
public void requestInput(IFormField f) {
if (f == null || f.getForm() != this) {
return;
}
fireRequestEvent(FormEvent.TYPE_REQUEST_INPUT, f);
}
/**
* @return Returns a map having old field classes as keys and replacement field classes as values. <code>null</code>
* is returned if no form fields are replaced. Do not use this internal method.
* @since 3.8.2
*/
public Map<Class<?>, Class<? extends IFormField>> getFormFieldReplacementsInternal() {
return m_fieldReplacements;
}
/**
* Registers the given form field replacements on this form. Do not use this internal method.
*
* @param replacements
* Map having old field classes as key and replacing field classes as values.
* @since 3.8.2
*/
public void registerFormFieldReplacementsInternal(Map<Class<?>, Class<? extends IFormField>> replacements) {
if (replacements == null || replacements.isEmpty()) {
return;
}
if (m_fieldReplacements == null) {
m_fieldReplacements = new HashMap<Class<?>, Class<? extends IFormField>>();
}
m_fieldReplacements.putAll(replacements);
}
/**
* Model Observer.
*/
@Override
public void addFormListener(FormListener listener) {
m_listenerList.add(FormListener.class, listener);
}
@Override
public void removeFormListener(FormListener listener) {
m_listenerList.remove(FormListener.class, listener);
}
protected IEventHistory<FormEvent> createEventHistory() {
return new DefaultFormEventHistory(5000L);
}
@Override
public IEventHistory<FormEvent> getEventHistory() {
return m_eventHistory;
}
private void fireFormLoadBefore() {
fireFormEvent(new FormEvent(this, FormEvent.TYPE_LOAD_BEFORE));
}
private void fireFormLoadAfter() {
fireFormEvent(new FormEvent(this, FormEvent.TYPE_LOAD_AFTER));
}
private void fireFormLoadComplete() {
fireFormEvent(new FormEvent(this, FormEvent.TYPE_LOAD_COMPLETE));
}
private void fireFormStoreBefore() {
fireFormEvent(new FormEvent(this, FormEvent.TYPE_STORE_BEFORE));
}
private void fireFormDiscarded() {
try {
fireFormEvent(new FormEvent(this, FormEvent.TYPE_DISCARDED));
}
catch (RuntimeException | PlatformError e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e)
.withContextInfo("form", getClass().getName());
}
}
private void fireFormStoreAfter() {
fireFormEvent(new FormEvent(this, FormEvent.TYPE_STORE_AFTER));
}
/**
* send request that form was activated by gui
*/
private void fireFormActivated() {
try {
interceptFormActivated();
fireFormEvent(new FormEvent(this, FormEvent.TYPE_ACTIVATED));
}
catch (RuntimeException | PlatformError e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e)
.withContextInfo("form", getClass().getName());
}
}
/**
* send request that form was closed by gui
*/
private void fireFormClosed() {
try {
fireFormEvent(new FormEvent(this, FormEvent.TYPE_CLOSED));
}
catch (RuntimeException | PlatformError e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e)
.withContextInfo("form", getClass().getName());
}
}
protected void fireFormEvent(FormEvent e) {
EventListener[] listeners = m_listenerList.getListeners(FormListener.class);
if (listeners != null && listeners.length > 0) {
RuntimeException pe = null;
for (int i = 0; i < listeners.length; i++) {
try {
((FormListener) listeners[i]).formChanged(e);
}
catch (RuntimeException ex) {
if (pe == null) {
pe = ex;
}
}
}
if (pe != null) {
throw pe;
}
}
IEventHistory<FormEvent> h = getEventHistory();
if (h != null) {
h.notifyEvent(e);
}
}
@Override
public void structureChanged(IFormField causingField) {
fireFormStructureChanged(causingField);
}
@SuppressWarnings("bsiRulesDefinition:htmlInString")
private void fireFormStructureChanged(IFormField causingField) {
try {
fireFormEvent(new FormEvent(this, FormEvent.TYPE_STRUCTURE_CHANGED, causingField));
}
catch (RuntimeException | PlatformError e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e)
.withContextInfo("form", getClass().getName())
.withContextInfo("field", (causingField == null ? "<null>" : causingField.getClass().getName()));
}
}
private void fireFormToFront() {
try {
fireFormEvent(new FormEvent(this, FormEvent.TYPE_TO_FRONT));
}
catch (RuntimeException | PlatformError e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e)
.withContextInfo("form", getClass().getName());
}
}
private void fireFormToBack() {
try {
fireFormEvent(new FormEvent(this, FormEvent.TYPE_TO_BACK));
}
catch (RuntimeException | PlatformError e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e)
.withContextInfo("form", getClass().getName());
}
}
@SuppressWarnings("bsiRulesDefinition:htmlInString")
private void fireRequestEvent(int eventType, IFormField f) {
try {
fireFormEvent(new FormEvent(this, eventType, f));
}
catch (RuntimeException | PlatformError e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e)
.withContextInfo("form", getClass().getName())
.withContextInfo("field", (f == null ? "<null>" : f.getClass().getName()));
}
}
@Override
public String getTitle() {
return propertySupport.getPropertyString(PROP_TITLE);
}
@Override
public void setTitle(String title) {
propertySupport.setPropertyString(PROP_TITLE, title);
}
@Override
public String getSubTitle() {
return propertySupport.getPropertyString(PROP_SUB_TITLE);
}
@Override
public void setSubTitle(String subTitle) {
propertySupport.setPropertyString(PROP_SUB_TITLE, subTitle);
}
@Override
public boolean isMaximizeEnabled() {
return propertySupport.getPropertyBool(PROP_MAXIMIZE_ENABLED);
}
@Override
public void setMaximizeEnabled(boolean b) {
propertySupport.setPropertyBool(PROP_MAXIMIZE_ENABLED, b);
}
@Override
public boolean isMinimizeEnabled() {
return propertySupport.getPropertyBool(PROP_MINIMIZE_ENABLED);
}
@Override
public void setMinimizeEnabled(boolean b) {
propertySupport.setPropertyBool(PROP_MINIMIZE_ENABLED, b);
}
@Override
public boolean isMaximized() {
return propertySupport.getPropertyBool(PROP_MAXIMIZED);
}
@Override
public void setMaximized(boolean b) {
if (isMaximizeEnabled()) {
if (b) {
propertySupport.setPropertyBool(PROP_MINIMIZED, false);
}
// maximized state of ui could be out of sync, fire always
propertySupport.setPropertyAlwaysFire(PROP_MAXIMIZED, b);
}
}
@Override
public boolean isMinimized() {
return propertySupport.getPropertyBool(PROP_MINIMIZED);
}
@Override
public void setMinimized(boolean b) {
if (isMinimizeEnabled()) {
if (b) {
propertySupport.setPropertyBool(PROP_MAXIMIZED, false);
}
// minimized state of ui could be out of sync, fire always
propertySupport.setPropertyAlwaysFire(PROP_MINIMIZED, b);
}
}
@Override
public boolean isShowOnStart() {
return FLAGS_BIT_HELPER.isBitSet(SHOW_ON_START, m_flags);
}
@Override
public void setShowOnStart(boolean showOnStart) {
m_flags = FLAGS_BIT_HELPER.changeBit(SHOW_ON_START, showOnStart, m_flags);
}
@Override
public boolean isModal() {
return m_modal.get();
}
@Override
public void setModal(boolean modal) {
Assertions.assertFalse(getDesktop().isShowing(this), "Property 'modal' cannot be changed because Form is already showing [form={}]", this);
m_modal.set(modal, true);
}
@Override
public void setCacheBounds(boolean cacheBounds) {
m_flags = FLAGS_BIT_HELPER.changeBit(CACHE_BOUNDS, cacheBounds, m_flags);
}
@Override
public boolean isCacheBounds() {
return FLAGS_BIT_HELPER.isBitSet(CACHE_BOUNDS, m_flags);
}
@Override
public String computeCacheBoundsKey() {
return getClass().getName();
}
@Override
public int getDisplayHint() {
return m_displayHint;
}
@Override
public void setDisplayHint(int displayHint) {
Assertions.assertFalse(getDesktop().isShowing(this), "Property 'displayHint' cannot be changed because Form is already showing [form={}]", this);
switch (displayHint) {
case DISPLAY_HINT_DIALOG:
case DISPLAY_HINT_POPUP_WINDOW:
case DISPLAY_HINT_VIEW: {
m_displayHint = displayHint;
break;
}
default: {
throw new IllegalArgumentException("Unsupported displayHint " + displayHint);
}
}
// Update modality hint if not explicitly set yet.
boolean modal = (displayHint == IForm.DISPLAY_HINT_DIALOG);
m_modal.set(modal, false);
m_displayParent.set(resolveDisplayParent(), false);
}
@Override
public IDisplayParent getDisplayParent() {
return m_displayParent.get();
}
@Override
public void setDisplayParent(IDisplayParent displayParent) {
if (displayParent == null) {
displayParent = resolveDisplayParent();
}
displayParent = Assertions.assertNotNull(displayParent, "'displayParent' must not be null");
if (m_displayParent.get() == displayParent) {
m_displayParent.markAsPreferredValue();
return;
}
if (!getDesktop().isShowing(this)) {
m_displayParent.set(displayParent, true); // If not showing yet, the 'displayParent' can be changed without detach/attach.
}
else {
// This Form is already showing and must be attached to the new 'displayParent'.
getDesktop().hideForm(this);
m_displayParent.set(displayParent, true);
getDesktop().showForm(this);
}
}
@Override
public String getDisplayViewId() {
return m_displayViewId;
}
@Override
public void setDisplayViewId(String viewId) {
m_displayViewId = viewId;
}
@Override
public boolean isAskIfNeedSave() {
return FLAGS_BIT_HELPER.isBitSet(ASK_IF_NEED_SAVE, m_flags);
}
@Override
public void setAskIfNeedSave(boolean b) {
m_flags = FLAGS_BIT_HELPER.changeBit(ASK_IF_NEED_SAVE, b, m_flags);
}
@Override
public void toFront() {
fireFormToFront();
}
@Override
public void toBack() {
fireFormToBack();
}
@Override
public boolean isButtonsArmed() {
return FLAGS_BIT_HELPER.isBitSet(BUTTONS_ARMED, m_flags);
}
@Override
public void setButtonsArmed(boolean b) {
m_flags = FLAGS_BIT_HELPER.changeBit(BUTTONS_ARMED, b, m_flags);
}
@Override
public boolean isCloseTimerArmed() {
return FLAGS_BIT_HELPER.isBitSet(CLOSE_TIMER_ARMED, m_flags);
}
@Override
public void setCloseTimerArmed(boolean closeTimerArmed) {
m_flags = FLAGS_BIT_HELPER.changeBit(CLOSE_TIMER_ARMED, closeTimerArmed, m_flags);
if (!closeTimerArmed && m_closeTimerFuture != null) {
m_closeTimerFuture.cancel(false);
m_closeTimerFuture = null;
}
}
@Override
public String toString() {
return "Form " + getFormId();
}
@Override
public IFormUIFacade getUIFacade() {
return m_uiFacade;
}
protected void handleSystemButtonEventInternal(ButtonEvent e) {
switch (e.getType()) {
case ButtonEvent.TYPE_CLICKED: {
// disable close timer
setCloseTimerArmed(false);
if (isButtonsArmed() && checkForVerifyingFields()) {
try {
IButton src = (IButton) e.getSource();
switch (src.getSystemType()) {
case IButton.SYSTEM_TYPE_CANCEL: {
doCancel();
break;
}
case IButton.SYSTEM_TYPE_CLOSE: {
doClose();
break;
}
case IButton.SYSTEM_TYPE_OK: {
doOk();
break;
}
case IButton.SYSTEM_TYPE_RESET: {
doReset();
break;
}
case IButton.SYSTEM_TYPE_SAVE: {
doSave();
break;
}
case IButton.SYSTEM_TYPE_SAVE_WITHOUT_MARKER_CHANGE: {
doSaveWithoutMarkerChange();
break;
}
}
}
catch (RuntimeException | PlatformError ex) {
BEANS.get(ExceptionHandler.class).handle(BEANS.get(PlatformExceptionTranslator.class).translate(ex)
.withContextInfo("button", e.getButton().getClass().getName()));
}
}
break;
}
}
}
protected IDisplayParent resolveDisplayParent() {
return m_initialClientRunContext.call(new Callable<IDisplayParent>() {
@Override
public IDisplayParent call() throws Exception {
return BEANS.get(DisplayParentResolver.class).resolve(AbstractForm.this);
}
});
}
/**
* Button controller for ok,cancel, save etc.
*/
private class P_SystemButtonListener implements ButtonListener {
@Override
public void buttonChanged(ButtonEvent e) {
// auto-detaching
if (m_systemButtonListener != this) {
((IButton) e.getSource()).removeButtonListener(this);
return;
}
handleSystemButtonEventInternal(e);
}
}// end private class
private class P_MainBoxPropertyChangeProxy implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent e) {
if (IFormField.PROP_SAVE_NEEDED.equals(e.getPropertyName())) {
calculateSaveNeeded();
}
else if (IFormField.PROP_EMPTY.equals(e.getPropertyName())) {
propertySupport.firePropertyChange(PROP_EMPTY, e.getOldValue(), e.getNewValue());
}
}
}
/**
* Starts the timer that periodically invokes {@link AbstractForm#interceptTimer(String).
*/
protected IFuture<Void> startTimer(int intervalSeconds, final String timerId) {
return ModelJobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
try {
LOG.info("timer {}", timerId);
interceptTimer(timerId);
}
catch (RuntimeException | PlatformError e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e)
.withContextInfo("form", getClass().getName())
.withContextInfo("timerId", timerId);
}
}
}, ModelJobs.newInput(ClientRunContexts.copyCurrent())
.withName("Form timer")
.withExecutionTrigger(Jobs.newExecutionTrigger()
.withStartIn(intervalSeconds, TimeUnit.SECONDS)
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(intervalSeconds))));
}
/**
* Installs the timer to close the Form once the given seconds elapse
*/
private IFuture<?> installFormCloseTimer(final long seconds) {
final long startMillis = System.currentTimeMillis();
final long delayMillis = TimeUnit.SECONDS.toMillis(seconds);
return ModelJobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
final long elapsedMillis = System.currentTimeMillis() - startMillis;
final long remainingSeconds = TimeUnit.MILLISECONDS.toSeconds(delayMillis - elapsedMillis);
if (!isCloseTimerArmed()) {
setSubTitle(null);
}
else if (remainingSeconds > 0) {
setSubTitle("" + remainingSeconds);
}
else {
setCloseTimerArmed(false); // cancel the periodic action
try {
interceptCloseTimer();
}
catch (RuntimeException | PlatformError e) {
throw BEANS.get(PlatformExceptionTranslator.class).translate(e)
.withContextInfo("form", getClass().getName());
}
}
}
}, ModelJobs.newInput(ClientRunContexts.copyCurrent())
.withName("Close timer")
.withExceptionHandling(null, false)
.withExecutionTrigger(Jobs.newExecutionTrigger()
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever())));
}
private abstract static class P_AbstractCollectingFieldVisitor<T> implements IFormFieldVisitor {
private final ArrayList<T> m_list = new ArrayList<T>();
public void collect(T o) {
m_list.add(o);
}
public int getCollectionCount() {
return m_list.size();
}
public List<T> getCollection() {
return m_list;
}
}
protected class P_UIFacade implements IFormUIFacade {
@Override
public void fireFormActivatedFromUI() {
fireFormActivated();
}
@Override
public void fireFormClosingFromUI() {
// check if some field is verifying input. In this case cancel ui call
if (!checkForVerifyingFields()) {
return;
}
closeFormInternal(false);
}
@Override
public void fireFormKilledFromUI() {
closeFormInternal(true);
}
}// end private class
/**
* The extension delegating to the local methods. This Extension is always at the end of the chain and will not call
* any further chain elements.
*/
protected static class LocalFormExtension<FORM extends AbstractForm> extends AbstractExtension<FORM> implements IFormExtension<FORM> {
/**
* @param owner
*/
public LocalFormExtension(FORM owner) {
super(owner);
}
@Override
public void execCloseTimer(FormCloseTimerChain chain) {
getOwner().execCloseTimer();
}
@Override
public void execInactivityTimer(FormInactivityTimerChain chain) {
getOwner().execInactivityTimer();
}
@Override
public void execStored(FormStoredChain chain) {
getOwner().execStored();
}
@Override
public boolean execIsSaveNeeded(IsSaveNeededFieldsChain chain) {
return getOwner().execIsSaveNeeded();
}
@Override
public boolean execCheckFields(FormCheckFieldsChain chain) {
return getOwner().execCheckFields();
}
@Override
public void execResetSearchFilter(FormResetSearchFilterChain chain, SearchFilter searchFilter) {
getOwner().execResetSearchFilter(searchFilter);
}
@Override
public void execAddSearchTerms(FormAddSearchTermsChain chain, SearchFilter search) {
getOwner().execAddSearchTerms(search);
}
@Override
public void execOnVetoException(FormOnVetoExceptionChain chain, VetoException e, int code) {
getOwner().execOnVetoException(e, code);
}
@Override
public void execFormActivated(FormFormActivatedChain chain) {
getOwner().execFormActivated();
}
@Override
public void execDisposeForm(FormDisposeFormChain chain) {
getOwner().execDisposeForm();
}
@Override
public void execTimer(FormTimerChain chain, String timerId) {
getOwner().execTimer(timerId);
}
@Override
public AbstractFormData execCreateFormData(FormCreateFormDataChain chain) {
return getOwner().execCreateFormData();
}
@Override
public void execInitForm(FormInitFormChain chain) {
getOwner().execInitForm();
}
@Override
public boolean execValidate(FormValidateChain chain) {
return getOwner().execValidate();
}
@Override
public void execOnCloseRequest(FormOnCloseRequestChain chain, boolean kill, Set<Integer> enabledButtonSystemTypes) {
getOwner().execOnCloseRequest(kill, enabledButtonSystemTypes);
}
@Override
public void execDataChanged(FormDataChangedChain chain, Object... dataTypes) {
getOwner().execDataChanged(dataTypes);
}
}
protected final void interceptCloseTimer() {
List<? extends IFormExtension<? extends AbstractForm>> extensions = getAllExtensions();
FormCloseTimerChain chain = new FormCloseTimerChain(extensions);
chain.execCloseTimer();
}
protected final void interceptInactivityTimer() {
List<? extends IFormExtension<? extends AbstractForm>> extensions = getAllExtensions();
FormInactivityTimerChain chain = new FormInactivityTimerChain(extensions);
chain.execInactivityTimer();
}
protected final void interceptStored() {
List<? extends IFormExtension<? extends AbstractForm>> extensions = getAllExtensions();
FormStoredChain chain = new FormStoredChain(extensions);
chain.execStored();
}
protected final boolean interceptIsSaveNeeded() {
List<? extends IFormExtension<? extends AbstractForm>> extensions = getAllExtensions();
IsSaveNeededFieldsChain chain = new IsSaveNeededFieldsChain(extensions);
return chain.execIsSaveNeeded();
}
protected final boolean interceptCheckFields() {
List<? extends IFormExtension<? extends AbstractForm>> extensions = getAllExtensions();
FormCheckFieldsChain chain = new FormCheckFieldsChain(extensions);
return chain.execCheckFields();
}
protected final void interceptResetSearchFilter(SearchFilter searchFilter) {
List<? extends IFormExtension<? extends AbstractForm>> extensions = getAllExtensions();
FormResetSearchFilterChain chain = new FormResetSearchFilterChain(extensions);
chain.execResetSearchFilter(searchFilter);
}
protected final void interceptAddSearchTerms(SearchFilter search) {
List<? extends IFormExtension<? extends AbstractForm>> extensions = getAllExtensions();
FormAddSearchTermsChain chain = new FormAddSearchTermsChain(extensions);
chain.execAddSearchTerms(search);
}
protected final void interceptOnVetoException(VetoException e, int code) {
List<? extends IFormExtension<? extends AbstractForm>> extensions = getAllExtensions();
FormOnVetoExceptionChain chain = new FormOnVetoExceptionChain(extensions);
chain.execOnVetoException(e, code);
}
protected final void interceptFormActivated() {
List<? extends IFormExtension<? extends AbstractForm>> extensions = getAllExtensions();
FormFormActivatedChain chain = new FormFormActivatedChain(extensions);
chain.execFormActivated();
}
protected final void interceptDisposeForm() {
List<? extends IFormExtension<? extends AbstractForm>> extensions = getAllExtensions();
FormDisposeFormChain chain = new FormDisposeFormChain(extensions);
chain.execDisposeForm();
}
protected final void interceptTimer(String timerId) {
List<? extends IFormExtension<? extends AbstractForm>> extensions = getAllExtensions();
FormTimerChain chain = new FormTimerChain(extensions);
chain.execTimer(timerId);
}
protected final AbstractFormData interceptCreateFormData() {
List<? extends IFormExtension<? extends AbstractForm>> extensions = getAllExtensions();
FormCreateFormDataChain chain = new FormCreateFormDataChain(extensions);
return chain.execCreateFormData();
}
protected final void interceptInitForm() {
List<? extends IFormExtension<? extends AbstractForm>> extensions = getAllExtensions();
FormInitFormChain chain = new FormInitFormChain(extensions);
chain.execInitForm();
}
protected final boolean interceptValidate() {
List<? extends IFormExtension<? extends AbstractForm>> extensions = getAllExtensions();
FormValidateChain chain = new FormValidateChain(extensions);
return chain.execValidate();
}
protected final void interceptOnCloseRequest(boolean kill, Set<Integer> enabledButtonSystemTypes) {
List<? extends IFormExtension<? extends AbstractForm>> extensions = getAllExtensions();
FormOnCloseRequestChain chain = new FormOnCloseRequestChain(extensions);
chain.execOnCloseRequest(kill, enabledButtonSystemTypes);
}
protected final void interceptDataChanged(Object... dataTypes) {
List<? extends IFormExtension<? extends AbstractForm>> extensions = getAllExtensions();
FormDataChangedChain chain = new FormDataChangedChain(extensions);
chain.execDataChanged(dataTypes);
}
}