/* * Rapid Beans Framework: EditorBean.java * * Copyright (C) 2009 Martin Bluemel * * Creation Date: 02/13/2006 * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU Lesser General Public License as published by the Free Software Foundation; * either version 3 of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * You should have received a copies of the GNU Lesser General Public License and the * GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>. */ package org.rapidbeans.presentation; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.MissingResourceException; import org.rapidbeans.core.basic.IdKeyprops; import org.rapidbeans.core.basic.IdType; import org.rapidbeans.core.basic.Property; import org.rapidbeans.core.basic.PropertyCollection; import org.rapidbeans.core.basic.RapidBean; import org.rapidbeans.core.basic.RapidBeanImplParent; import org.rapidbeans.core.basic.ThreadLocalValidationSettings; import org.rapidbeans.core.common.RapidBeansLocale; import org.rapidbeans.core.event.PropertyChangeEvent; import org.rapidbeans.core.exception.BeanDuplicateException; import org.rapidbeans.core.exception.BeanNotFoundException; import org.rapidbeans.core.exception.RapidBeansRuntimeException; import org.rapidbeans.core.exception.ValidationException; import org.rapidbeans.core.exception.ValidationInstanceAssocTwiceException; import org.rapidbeans.core.type.TypeProperty; import org.rapidbeans.core.type.TypePropertyCollection; import org.rapidbeans.datasource.Filter; import org.rapidbeans.datasource.event.AddedEvent; import org.rapidbeans.datasource.event.ChangedEvent; import org.rapidbeans.datasource.event.DocumentChangeListener; import org.rapidbeans.datasource.event.RemovedEvent; import org.rapidbeans.presentation.config.ConfigEditorBean; import org.rapidbeans.presentation.config.ConfigPropEditorBean; import org.rapidbeans.presentation.config.ConfigPropPersistencestrategy; import org.rapidbeans.presentation.swing.EditorBeanSwing; /** * the bean editor GUI. * * @author Martin Bluemel */ public abstract class EditorBean implements View, EditorPropertyListener, DocumentChangeListener { /** * @return the view's widget */ public abstract Object getWidget(); /** * @return the view's title. */ public String getTitle() { String idstring = null; if (bean.getContainer() == null) { idstring = this.locale.getStringGui("commongui.text.new") + " " + bean.toStringGuiType(this.locale); } else { try { final String key = "editor." + bean.getType().getName().toLowerCase() + ".title"; final String pattern = this.locale.getStringGui(key); idstring = bean.expandPropertyValues(pattern, this.getLocale()); idstring = bean.toStringGuiType(this.locale) + ": " + idstring; } catch (MissingResourceException e) { idstring = null; } if (idstring == null) { idstring = bean.toStringGui(this.locale); } } return idstring; } /** * update the GUI's buttons. * * @param propEditor * the property editor where an input field has been changed */ public abstract void validateAndUpdateButtons(EditorProperty propEditor); /** * update all property editor UIs (input fields). */ protected void updatePropedGUIs() { for (EditorProperty proped : this.propEditors) { proped.updateUI(); } } /** * the bean to edit. */ private RapidBean bean; /** * @return the bean currently edited */ public RapidBean getBean() { return this.bean; } /** * the bean backup before editing. */ private RapidBean bakbean; /** * @return the bean before */ public RapidBean getBakbean() { return this.bakbean; } /** * the parent bean of a new bean to create. */ private RapidBean parentBean; /** * @return the parent bean of a new bean to create.<BR> * null if in "edit only" mode.<BR> * not null if in create mode. */ public RapidBean getParentBean() { return this.parentBean; } /** * the parent bean's collection property for composition of a new bean to * create. */ private PropertyCollection parentBeanColProp; /** * the parent document view. */ private DocumentView documentView = null; /** * @return the parent document view */ public DocumentView getDocumentView() { return this.documentView; } /** * the list with all property editors. */ private List<EditorProperty> propEditors = new ArrayList<EditorProperty>(); /** * @return the list of property editors. */ public List<EditorProperty> getPropEditors() { return this.propEditors; } private List<EditorProperty> getPropEditorsSorted() { final List<EditorProperty> propEditorsSorted = new ArrayList<EditorProperty>(); for (final TypeProperty proptype : this.bean.getType().getPropertyTypes()) { final EditorProperty propEditor = this.getPropEditor(proptype.getPropName()); if (propEditor != null) { propEditorsSorted.add(propEditor); } } return propEditorsSorted; } private List<Property> getPropEditorsKeyprops() { final List<Property> editorsKeyprops = new ArrayList<Property>(); for (final Property prop : ((IdKeyprops) this.bean.getId()).getKeyprops()) { final EditorProperty propEditor = this.getPropEditor(prop.getName()); if (propEditor != null) { editorsKeyprops.add(prop); } } return editorsKeyprops; } /** * Find a property editor specified by a property name. * * @param propname * the property name * * @return the editor of the specified property or null if not found */ public EditorProperty getPropEditor(final String propname) { return this.propEdMap.get(propname); } /** * the hashmap to access a prop editor quickly. */ private HashMap<String, EditorProperty> propEdMap = new HashMap<String, EditorProperty>(); /** * adds a new property editor to the bean editor. * * @param client * the client * @param bbean * the bean * @param property * the property to edit * @param propBackup * the backup property used instead of a transaction */ private EditorProperty addPropertyEditor(final Application client, final RapidBean bbean, final Property property, final Property propBackup) { EditorProperty propEditor = EditorProperty.createInstance(client, this, property, propBackup); propEditor.addPropertyEditorListener(this); this.propEditors.add(propEditor); this.propEdMap.put(property.getType().getPropName(), propEditor); try { propEditor.validateInputField(); } catch (ValidationException e) { // ignore validation exceptions } return propEditor; } /** * the collection of registered editor listeners. */ private Collection<EditorBeanListener> listeners = new ArrayList<EditorBeanListener>(); /** * adds a listener that wants to be notified by editor events. * * @param listener * the listenr to add */ public void addEditorListener(final EditorBeanListener listener) { this.listeners.add(listener); } /** * removes a listener. * * @param listener * the listener to remove */ public void removeEditorListener(final EditorBeanListener listener) { this.listeners.remove(listener); } /** * notifies all listeners that the editor has been closed. */ protected void fireEditorClosed() { for (EditorBeanListener listener : this.listeners) { listener.editorClosed(this); } } /** * flag that indicates if in new mode the bean is already added to the * parent collection property. */ private boolean beanAdded = false; /** * @return if in new mode the bean is already added to the parent collection * property */ private boolean isBeanAdded() { // performance issue with big collections // return this.parentBeanColProp.getValue().contains(this.bean); return this.beanAdded; } /** * setter for this internal flag. * * @param added * if the biz bean has bean added */ public void setBeanAdded(final boolean added) { this.beanAdded = added; } /** * the locale. */ private RapidBeansLocale locale; /** * @return the locale */ public RapidBeansLocale getLocale() { return this.locale; } /** * The configuration of this editor. */ private ConfigEditorBean configuration = null; /** * @return the editor's configuration */ public ConfigEditorBean getConfiguration() { return this.configuration; } /** * constructor. * * @param client * the bean client * @param docView * parentView the parent document view * @param bizBean * the bean to edit * @param newBeanParentColProp * a new Bean's parent collection property. Is not null if a new * Bean is to be created Is null if an existing bean is simply * edited */ protected EditorBean(final Application client, final DocumentView docView, final RapidBean bizBean, final PropertyCollection newBeanParentColProp) { try { this.setEventLock(); this.documentView = docView; this.bean = bizBean; this.configuration = client.getConfigBeanEditor(this.bean.getType()); if (newBeanParentColProp != null) { this.parentBeanColProp = newBeanParentColProp; this.parentBean = newBeanParentColProp.getBean(); } this.locale = client.getCurrentLocale(); this.bakbean = bizBean.clone(); if (this.configuration != null) { for (final ConfigPropEditorBean cfgprop : this.configuration.getPropertycfgs()) { final Property prop = this.bean.getProperty(cfgprop.getName()); if (prop == null) { String validTypes = ""; int i = 0; for (final Property prop1 : bean.getPropertyList()) { if (i > 0) { validTypes += ", "; } validTypes += "\"" + prop1.getName() + "\""; i++; } throw new RapidBeansRuntimeException("Invalid property \"" + cfgprop.getName() + "\"" + " configured for class \"" + bean.getType().getName() + "\"\n" + "Valid types are: " + validTypes); } addPropertyEditor(client, bizBean, prop); } } else { try { ThreadLocalValidationSettings.readonlyOff(); for (final Property prop : this.bean.getPropertyList()) { addPropertyEditor(client, bizBean, prop); } } finally { ThreadLocalValidationSettings.remove(); } } } finally { this.releaseEventLock(); } } /** * add a new property editor. * * @param client * the client * @param bean * the bean * @param prop * the property edited */ private EditorProperty addPropertyEditor(final Application client, final RapidBean bean, final Property prop) { EditorProperty propEditor = null; if (prop == null) { throw new IllegalArgumentException("prop is unspecified (null)"); } if (prop instanceof PropertyCollection) { final TypePropertyCollection colPropType = (TypePropertyCollection) prop.getType(); if (!colPropType.isComposition()) { final Filter filter = this.documentView.getBeanFilter(); if (filter == null || filter.applies(colPropType.getTargetType())) { propEditor = this.addPropertyEditor(client, bean, prop, this.bakbean.getProperty(prop.getType().getPropName())); } } } else { propEditor = this.addPropertyEditor(client, bean, prop, this.bakbean.getProperty(prop.getType().getPropName())); } return propEditor; } /** * constructor arguments. */ private static final Class<?>[] BIZBEAN_EDITOR_CONSTR_ARGTYPES = { Application.class, DocumentView.class, RapidBean.class, PropertyCollection.class }; /** * create a new editor. * * @param client * the client * @param docView * the parent document view * @param bizBean * the bean to edit * @param newBeanParent * a new Bean's parent collection property. Is not null if a new * Bean is to be created Is null if an existing bean is simply * edited * * @return the editor object */ public static EditorBean createInstance(final Application client, final DocumentView docView, final RapidBean bizBean, final PropertyCollection newBeanParent) { EditorBean editor = null; final ConfigEditorBean cfg = client.getConfigBeanEditor(bizBean.getType()); if (cfg != null) { final String editorclassname = cfg.getEditorclass(); if (editorclassname != null) { Class<?> editorclass = null; try { editorclass = Class.forName(editorclassname); } catch (ClassNotFoundException e) { throw new RapidBeansRuntimeException(e); } Constructor<?> constr = null; try { constr = editorclass.getConstructor(BIZBEAN_EDITOR_CONSTR_ARGTYPES); } catch (SecurityException e) { throw new RapidBeansRuntimeException(e); } catch (NoSuchMethodException e) { throw new RapidBeansRuntimeException("No constructor with aruments classes:\n" + "Application, DocumentView, bean, PropertyCollection) found.", e); } if (constr != null) { final Object[] oa = { client, docView, bizBean, newBeanParent }; try { editor = (EditorBean) constr.newInstance(oa); } catch (IllegalArgumentException e) { throw new RapidBeansRuntimeException(e); } catch (InstantiationException e) { throw new RapidBeansRuntimeException(e); } catch (IllegalAccessException e) { throw new RapidBeansRuntimeException(e); } catch (InvocationTargetException e) { throw new RapidBeansRuntimeException(e); } } } } if (editor == null) { switch (client.getConfiguration().getGuitype()) { case swing: editor = new EditorBeanSwing(client, docView, bizBean, newBeanParent); break; case eclipsercp: // mainWindow = new BBMainWindowEclispercp(); break; default: throw new RapidBeansRuntimeException("Unknown GUI type \"" + client.getConfiguration().getGuitype().name() + "\""); } } return editor; } /** * action handler for OK button. */ public void handleActionOk() { try { this.createOrUpdateBean(false); this.fireEditorClosed(); } catch (ValidationException e) { if (this.getDocumentView().getClient().getTestMode()) { throw e; } else { // eat up that validation exception return; } } } /** * action handler for Apply button. */ public void handleActionApply() { try { this.createOrUpdateBean(true); } catch (ValidationException e) { if (this.getDocumentView().getClient().getTestMode()) { throw e; } else { // eat up that validation exception return; } } } /** * determines the way how the editor behaves after pressing the apply * button. */ private CreateNewBeansEditorApplyBehaviour createApplyMode = CreateNewBeansEditorApplyBehaviour.resetall; /** * Setter to determine the way how the editor behaves after pressing the * apply button. * * @param mode * determines the way how the editor behaves after pressing the * apply button.<br/> * <code>CREATE_APPLY_RESET_ALL</code>: all property values are * reset and have to be specified in order to create the next * bean.<br/> * <code>CREATE_APPLY_RESET_KEY</code>: only key property values * are reset. All other property values stay the same and can be * reused for creating the next bean.<br/> * <code>CREATE_APPLY_RESET_NONE</code>: no property value is * reset. Key properties have to be changed afterwards before<br/> * creating the nex bean. */ public void setCreateApplyMode(final CreateNewBeansEditorApplyBehaviour mode) { this.createApplyMode = mode; } /** * creates or updates a bean from the editor. */ private void createOrUpdateBean(final boolean reset) { this.validateInputAndUpdateBean(true, true, true, true, null); this.addBeanIfNew(false); if (this.documentView.getPersistencestrategy() == ConfigPropPersistencestrategy.oncloseeditor) { if (ApplicationManager.getApplication() != null) { ApplicationManager.getApplication().save(this.documentView.getDocument()); } else { this.documentView.getDocument().save(); } } if (reset) { reset(); } } /** * reset the editor. */ private void reset() { if (isInNewMode()) { this.resetBean(); } this.setBeanAdded(false); this.resetBackupBean(); updatePropEditors(); updatePropedGUIs(); validateAndUpdateButtons(null); } /** * action handler for Close (Cancel) button. */ public void handleActionClose() { boolean anyInputFieldChanged; try { anyInputFieldChanged = this.isAnyInputFieldChanged(); } catch (ValidationException e) { anyInputFieldChanged = true; } if (anyInputFieldChanged) { if (isInNewMode()) { if (this.isBeanAdded() && this.bean != null && this.bean.getParentProperty() != null) { this.bean.getParentProperty().removeLink(this.bean); this.setBeanAdded(false); } this.resetBean(); } else { // restore the bean (rollback the logical transaction) this.restoreBean(); } // restore the bean (rollback the logical transaction this.updatePropedGUIs(); this.validateAndUpdateButtons(null); } this.fireEditorClosed(); } /** * resets the bean dependently of the mode. */ private void resetBean() { // unregister all property editors as listeners for the old bean for (final Property prop : this.bean.getPropertyList()) { final EditorProperty ped = getPropEditor(prop.getName()); if (ped != null) { this.bean.removePropertyChangeListener(ped); } } switch (this.createApplyMode) { case resetall: this.bean = RapidBeanImplParent.createInstance(this.bean.getType().getName()); break; case resetnothing: case resetkey: final RapidBean newBean = RapidBeanImplParent.createInstance(this.bean.getType().getName()); for (Property prop : newBean.getPropertyList()) { if (!prop.getType().isKeyCandidate() || this.createApplyMode == CreateNewBeansEditorApplyBehaviour.resetnothing) { try { ThreadLocalValidationSettings.validationOff(); if (prop instanceof PropertyCollection) { ((PropertyCollection) prop).setValue(this.bean.getProperty(prop.getType().getPropName()) .getValue(), false, true); } else { prop.setValue(this.bean.getProperty(prop.getType().getPropName()).getValue()); } } finally { ThreadLocalValidationSettings.remove(); } } } this.bean = newBean; break; default: throw new RapidBeansRuntimeException("Invalid createApplyMode " + this.createApplyMode + " for bean editor."); } // register all property editors as listeners for the new bean for (final Property prop : this.bean.getPropertyList()) { final EditorProperty ped = getPropEditor(prop.getName()); if (ped != null) { this.bean.addPropertyChangeListener(ped); } } } /** * reset the bean's properties according to the edited input fields. */ private void restoreBean() { List<Property> properties = this.bean.getPropertyList(); List<Property> bakprops = this.bakbean.getPropertyList(); int size = properties.size(); try { this.setEventLock(); ThreadLocalValidationSettings.validationOff(); for (int i = 0; i < size; i++) { properties.get(i).setValue(bakprops.get(i).getValue()); } } finally { ThreadLocalValidationSettings.remove(); this.releaseEventLock(); } } /** * @return if any of the property editor's input field is changed */ public boolean isAnyInputFieldChanged() { boolean changedAny = false; for (EditorProperty propertyEditor : this.propEditors) { if (propertyEditor.isInputFieldChanged()) { changedAny = true; break; } } return changedAny; } /** * change the beans properties according to the edited input fields. * * @param showDialog * if dialogs should be shown * @param linkBack * if the bean is completely linked (with forward and inverse * linked) with another bean or not * @param updateUI * determines if the UI will be updated or not e. g. for * normalization */ protected void validateInputAndUpdateBean(final boolean showDialog, final boolean linkBack, final boolean updateUI) { for (EditorProperty ped : this.getPropEditors()) { this.validateInputAndUpdateBean(showDialog, linkBack, updateUI, true, ped); } } /** * change the beans properties according to the edited input fields. * * @param showDialog * if dialogs should be shown * @param linkBack * if the bean is completely linked (with forward and inverse * linked) with another bean or not * @param updateUI * determines if the UI will be updated or not e. g. for * normalization * @param propEditorChanged * the changed property editor. This is null if an OK button has * been pressed. */ protected void validateInputAndUpdateBean(final boolean showDialog, final boolean linkBack, final boolean updateUI, final boolean checkDocAlreadyContainsBean, final EditorProperty propEditorChanged) { EditorProperty propEditor = null; final boolean docChangedBefore = this.getDocumentView().getDocument().getChanged(); try { this.setEventLock(); // List<Property> keyprops = null; int keypropsSize = -1; final boolean idtypeKeyprops = this.bean.getType().getIdtype() == IdType.keyprops || this.bean.getType().getIdtype() == IdType.keypropswithparentscope; if (idtypeKeyprops) { final List<Property> keyprops = this.getPropEditorsKeyprops(); keypropsSize = keyprops.size(); if (propEditorChanged != null && propEditorChanged.getProperty().getType().isKeyCandidate()) { if (checkDocAlreadyContainsBean) { if (this.getDocumentView().getDocument().contains(this.getBean())) { throw new ValidationException("invalid.prop.key.already.in.document", this, "Changed key property \"" + propEditorChanged.getProperty().getName()); } } } } int i = 0; String propName; Property prop; for (EditorProperty currentPropEditor : this.getPropEditorsSorted()) { propEditor = currentPropEditor; if ((!idtypeKeyprops) || (i >= keypropsSize)) { addBeanIfNew(true); } if (currentPropEditor == propEditorChanged) { currentPropEditor.validateInputField(); } propName = currentPropEditor.getProperty().getType().getPropName(); prop = this.bean.getProperty(propName); if (prop instanceof PropertyCollection) { if (linkBack) { ((PropertyCollection) prop).setValue(currentPropEditor.getInputFieldValue(), true, false); } else { ((PropertyCollection) prop).setValue(currentPropEditor.getInputFieldValue(), false, false); } } else { if (!(prop.isDependent() || prop.getReadonly())) { prop.setValue(currentPropEditor.getInputFieldValue()); } } // show the value again in case it has been normalized. if (updateUI) { currentPropEditor.updateUI(); } i++; } if (!idtypeKeyprops || i >= keypropsSize) { addBeanIfNew(true); } } catch (ValidationInstanceAssocTwiceException e) { throw e; } catch (BeanDuplicateException e) { if (showDialog && !this.getDocumentView().getClient().getTestMode()) { showCreateFailedMessage(); propEditor.setFocus(); } throw e; } catch (ValidationException e) { if (showDialog && !this.getDocumentView().getClient().getTestMode()) { this.documentView.getClient().messageError( this.locale.getStringGui("messagedialog.input.field") + " \"" + propEditor.getProperty().getNameGui(this.locale) + "\":\n" + e.getLocalizedMessage(this.locale), this.locale.getStringGui("messagedialog.title.input.wrong")); propEditor.setFocus(); } throw e; } finally { removeBeanIfNew(docChangedBefore); this.releaseEventLock(); } } /** * if the editor is in new mode add the bean to the container. * * @param setAdded * set bean added afterwards. Usually this is exactly what you * want to do. */ public void addBeanIfNew(final boolean setAdded) { if (this.isInNewMode() && (!this.isBeanAdded())) { if (this.getBean().getType().getIdtype() == IdType.keyprops || this.getBean().getType().getIdtype() == IdType.keypropswithparentscope) { // clear the id in order to let the // "create bean" action work out this.bean.clearId(); } this.parentBeanColProp.addLink(this.bean); if (setAdded) { this.setBeanAdded(true); } } } /** * if the editor is in new mode remove the bean from the container. * * @param docChangedBefore * if false the document and it's view will be unmarked */ public void removeBeanIfNew(final boolean docChangedBefore) { if (this.isInNewMode() && this.isBeanAdded()) { try { setEventLockPropEditors(); for (int i = 0; i < 2; i++) { try { ThreadLocalValidationSettings.validationOff(); this.parentBeanColProp.removeLink(this.bean, true, true, false); break; } catch (BeanNotFoundException e) { if (i == 0) { this.parentBeanColProp.sort(); } else { throw e; } } finally { ThreadLocalValidationSettings.remove(); } } if (!docChangedBefore) { this.documentView.getDocument().resetChanged(); this.documentView.markAsChanged(false); } this.setBeanAdded(false); } finally { releaseEventLockPropEditors(); } } } /** * shows the "Create Failed" message. */ private void showCreateFailedMessage() { if (!this.getDocumentView().getClient().getTestMode()) { this.getDocumentView() .getClient() .messageError( this.getLocale().getStringMessage("messagedialog.create.duplicate", this.getBean().toStringGui(this.getLocale())), this.getLocale().getStringGui("messagedialog.title.create.duplicate")); } } /** * update the Property editors with the new bean's properties. */ private void updatePropEditors() { for (EditorProperty propEditor : this.propEditors) { propEditor.setProperty(this.bean.getProperty(propEditor.getProperty().getType().getPropName())); } } /** * for white box testing. * * @return a HashMap with button wigets. The keys are the button names ok, * apply and cancel */ public abstract HashMap<String, Object> getButtonWidgets(); /** * indicates if the editor is for creating a new bean instead of just * modifying an existing one. * * @return true if the editor is for creating a new bean<BR> * false if the editor is for modifying an existing bean. */ public boolean isInNewMode() { return this.parentBean != null; } /** * @param propEditor * the editor that notified the change. */ public void inputFieldChanged(final EditorProperty propEditor) { try { this.validateAndUpdateButtons(propEditor); } catch (ValidationException e) { throw e; } } /** * handler for added bean. * * @param e * the added event */ public void beanAddPre(final AddedEvent e) { } /** * handler for added bean. * * @param e * the added event */ public void beanAdded(final AddedEvent e) { if (this.getEventLock()) { return; } for (EditorProperty proped : this.propEditors) { if (proped.getProperty().getType() instanceof TypePropertyCollection) { proped.beanAdded(e); } } } /** * handler for change bean pre event. * * @param e * the changed event */ public void beanChangePre(final ChangedEvent e) { } /** * handler for changed bean. * * @param e * the changed event */ public void beanChanged(final ChangedEvent e) { if (this.getEventLock()) { return; } if (this.bean != e.getBean()) { return; } final EditorProperty sourcePropEditor = ThreadLocalEventLock.getSourcePropEditor(); if (sourcePropEditor != null && sourcePropEditor.getBeanEditor() == this) { return; } try { this.setEventLock(); for (final PropertyChangeEvent pce : e.getPropertyEvents()) { final Property prop = pce.getProperty(); final String propname = prop.getName(); final EditorProperty proped = this.propEdMap.get(propname); if (proped != null) { try { proped.setUIEventLock(); proped.beanChanged(e); } finally { proped.releaseUIEventLock(); } } } } finally { this.releaseEventLock(); } if (e.getBean() == this.bean && (!this.modifies)) { this.resetBackupBean(); } } /** * modifies flag. */ private boolean modifies = false; /** * @return if the editor modifies. */ public boolean getModifies() { return this.modifies; } /** * @param mod * if modifies. */ public void setModifies(final boolean mod) { this.modifies = mod; } /** * handler for bean pre remove event. * * @param e * the added event */ public void beanRemovePre(final RemovedEvent e) { if (this.getEventLock()) { return; } } /** * handler for added bean. * * @param e * the added event */ public void beanRemoved(final RemovedEvent e) { if (this.getEventLock()) { return; } if (this.getBean() == e.getBean()) { boolean close; if (ApplicationManager.getApplication().getTestMode()) { close = true; } else { close = ApplicationManager.getApplication().messageYesNo("Close that Editor?", "bean removed"); } if (close) { this.fireEditorClosed(); } else { this.handleActionClose(); } } for (EditorProperty proped : this.propEditors) { proped.beanRemoved(e); } } /** * the editor's event lock to avoid Change event feedback. */ private int eventLock = 0; /** * @return the event lock */ public boolean getEventLock() { return this.eventLock > 0; } /** * increase the event lock. */ protected void setEventLock() { this.eventLock++; } /** * increase the event lock. */ protected void releaseEventLock() { if (this.eventLock > 0) { this.eventLock--; } } /** * Lock all the property editors. */ private void setEventLockPropEditors() { for (final EditorProperty proped : getPropEditors()) { proped.setUIEventLock(); } } /** * Release all the property editor's locks */ private void releaseEventLockPropEditors() { for (final EditorProperty proped : getPropEditors()) { proped.releaseUIEventLock(); } } /** * the bean editor view's name is the document's name. * * @return the document view's name */ public String getName() { return "documentview.beaneditor." + this.bean.getIdString(); } /** * reset the document change mark. */ public void documentSaved() { } /** * reset the backup bean to the current bean. */ private void resetBackupBean() { this.bakbean = bean.clone(); for (Property bakprop : this.bakbean.getPropertyList()) { if (!(bakprop instanceof PropertyCollection && ((TypePropertyCollection) bakprop.getType()).isComposition()) && (this.propEdMap.get(bakprop.getType().getPropName()) != null)) { this.propEdMap.get(bakprop.getType().getPropName()).setPropertyBak(bakprop); } } } /** * close the bean editor. * * @return if canceling is desired */ public boolean close() { boolean cancel = false; boolean changed = false; boolean valid = true; try { changed = this.isAnyInputFieldChanged(); } catch (ValidationException e) { valid = false; } if (valid && changed) { switch (this.documentView.getPersistencestrategy()) { case oncloseeditor: if (changed) { handleActionApply(); } break; default: final String msg = this.locale.getStringMessage("messagedialog.beaneditor.close", this.getTitle()); MessageDialogResponse response = null; if (ApplicationManager.getApplication().getTestMode()) { response = MessageDialogResponse.yes; } else { response = this.documentView.getClient().messageYesNoCancel(msg, this.locale.getStringMessage("messagedialog.beaneditor.close.title")); } switch (response) { case yes: this.handleActionOk(); break; case no: this.handleActionClose(); break; default: cancel = true; break; } break; } } else { this.handleActionClose(); } return cancel; } public static int DIRECTION_UP = 0; public static int DIRECTION_DOWN = 1; public abstract void rotateFocus(final Property property, final int direction); public EditorProperty getNextEditor(final Property property) { final EditorProperty currentPed = getPropEditor(property.getName()); final int currentIndex = this.propEditors.indexOf(currentPed); EditorProperty nextEditor = null; if (currentIndex < this.propEditors.size() - 1) { nextEditor = this.propEditors.get(currentIndex + 1); } else { nextEditor = this.propEditors.get(0); } return nextEditor; } public EditorProperty getPreviousEditor(final Property property) { final EditorProperty currentPed = getPropEditor(property.getName()); final int currentIndex = this.propEditors.indexOf(currentPed); EditorProperty prevEditor = null; if (currentIndex > 0) { prevEditor = this.propEditors.get(currentIndex - 1); } else { prevEditor = this.propEditors.get(this.propEditors.size() - 1); } return prevEditor; } }