fix #7665 Use iterator to avoid ConcurrentModificationException
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / ui / element / AbstractFormSection.java
index 80392ad976b1cdc22358a670a02cec33aaaf2aaf..b816fe223241debc93b17d10e1297433b5f40201 100644 (file)
@@ -5,6 +5,7 @@ package eu.etaxonomy.taxeditor.ui.element;
 
 import java.util.ConcurrentModificationException;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
@@ -25,7 +26,8 @@ import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.TypedListener;
 import org.eclipse.swt.widgets.Widget;
-import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.forms.events.ExpansionEvent;
+import org.eclipse.ui.forms.events.IExpansionListener;
 import org.eclipse.ui.forms.widgets.Section;
 import org.eclipse.ui.forms.widgets.TableWrapLayout;
 import org.eclipse.ui.forms.widgets.ToggleHyperlink;
@@ -34,7 +36,8 @@ import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
 import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeMap;
 import eu.etaxonomy.taxeditor.model.AbstractUtility;
-import eu.etaxonomy.taxeditor.ui.campanula.compatibility.ICdmFormElement;
+import eu.etaxonomy.taxeditor.model.MessagingUtils;
+import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
 
 /**
  * <p>
@@ -46,17 +49,21 @@ import eu.etaxonomy.taxeditor.ui.campanula.compatibility.ICdmFormElement;
  *
  * @author n.hoffmann
  * @created Feb 22, 2010
- * @version 1.0
  * @param <T>
  */
 //TODO shouldn't ENTITY be bound with super class ICdmBase for example (AbstractFormSection<ENTITY extends ICdmBase>)?
 public abstract class AbstractFormSection<ENTITY> extends Section implements ISelectionChangedListener, IEntityElement<ENTITY>, IConversationEnabled {
 
+    /**
+     * The default number of columns in detail sections
+     */
+    public static final int DEFAULT_NUM_COLUMNS = 2;
+
        private ISelectionProvider selectionProvider;
 
        private ENTITY entity;
 
-       private final Set<ICdmFormElement> elements = new HashSet<ICdmFormElement>();
+       private final Set<ICdmFormElement> elements = new HashSet<>();
 
        protected CdmFormFactory formFactory;
 
@@ -99,10 +106,12 @@ public abstract class AbstractFormSection<ENTITY> extends Section implements ISe
                TableWrapLayout layout = LayoutConstants.LAYOUT();
                layout.bottomMargin = 10;
                layout.rightMargin = 5;
+               layout.horizontalSpacing = 5;
 
                client.setLayout(layout);
 
                this.setClient(client);
+
        }
 
            /**
@@ -158,13 +167,9 @@ public abstract class AbstractFormSection<ENTITY> extends Section implements ISe
         */
        public void setEntity(ENTITY entity) {
                this.entity = entity;
+               addExpandListener();
        }
 
-       /*
-        * (non-Javadoc)
-        *
-        * @see eu.etaxonomy.taxeditor.forms.IEntityElement#getEntity()
-        */
        /**
         * <p>
         * Getter for the field <code>entity</code>.
@@ -216,7 +221,7 @@ public abstract class AbstractFormSection<ENTITY> extends Section implements ISe
                 ((IPropertyChangeListener) listener).propertyChange(event);
             }
         } catch (ConcurrentModificationException e) {
-            AbstractUtility.warn(getClass(), "ConcurrentModificationException while handling PropertyChangeEvents."
+            MessagingUtils.warn(getClass(), "ConcurrentModificationException while handling PropertyChangeEvents."
                     + " It seems like this is not critical");
         }
        }
@@ -415,7 +420,8 @@ public abstract class AbstractFormSection<ENTITY> extends Section implements ISe
         */
        @Override
     public void removeElements() {
-               for (ICdmFormElement childElement : getElements()) {
+               for (Iterator<ICdmFormElement> formElementIterator = getElements().iterator();formElementIterator.hasNext();) {
+                   ICdmFormElement childElement = formElementIterator.next();
                        // recursion
                        childElement.removeElements();
 
@@ -432,7 +438,8 @@ public abstract class AbstractFormSection<ENTITY> extends Section implements ISe
                        formFactory.removePropertyChangeListener(childElement);
 
                        // dispose of the controls
-                       for (Control control : childElement.getControls()) {
+                       for (Iterator<Control> controlIterator = childElement.getControls().iterator();controlIterator.hasNext();) {
+                           Control control = controlIterator.next();
                                // we added the layoutComposite of the parental element as the
                                // layout composite to this formElement
                                // but we do not want to destroy it.
@@ -481,7 +488,7 @@ public abstract class AbstractFormSection<ENTITY> extends Section implements ISe
         */
        @Override
     public Set<Control> getControls() {
-               Set<Control> controls = new HashSet<Control>();
+               Set<Control> controls = new HashSet<>();
 
                for (Control control : getChildren()) {
                        controls.add(control);
@@ -532,7 +539,8 @@ public abstract class AbstractFormSection<ENTITY> extends Section implements ISe
         *
         * @return a {@link eu.etaxonomy.taxeditor.ui.element.CdmFormFactory} object.
         */
-       public CdmFormFactory getFormFactory() {
+       @Override
+    public CdmFormFactory getFormFactory() {
                return formFactory;
        }
 
@@ -541,11 +549,6 @@ public abstract class AbstractFormSection<ENTITY> extends Section implements ISe
         *
         * @see eu.etaxonomy.taxeditor.forms.ICdmFormElement#refresh()
         */
-       /**
-        * <p>
-        * refresh
-        * </p>
-        */
        @Override
     public void refresh() {
                // empty default implementation
@@ -562,18 +565,20 @@ public abstract class AbstractFormSection<ENTITY> extends Section implements ISe
         */
        @Override
     public ConversationHolder getConversationHolder() {
-               if(getParentElement() instanceof RootElement || getParentElement() == null){
-
-                       IEditorPart activeEditor = AbstractUtility.getActiveEditor();
-                       if(activeEditor instanceof IConversationEnabled){
-                               ConversationHolder conversation = ((IConversationEnabled) AbstractUtility.getActiveEditor()).getConversationHolder();
-                               return conversation;
-                       }
-               }else if(getParentElement() instanceof IConversationEnabled){
-                       return ((IConversationEnabled) getParentElement()).getConversationHolder();
-               }
-               AbstractUtility.errorDialog("Could not get conversation for AbstractFormSection",
-                               getClass(), "There is an error in the implementation. There should have been an active editor but it wasn't",
+           if(AbstractUtility.getActivePart() instanceof IConversationEnabled){
+            return ((IConversationEnabled) AbstractUtility.getActivePart()).getConversationHolder();
+        }
+           if(getParentElement() instanceof RootElement || getParentElement() == null){
+
+               Object activeEditor = AbstractUtility.getActiveEditor();
+               if(activeEditor instanceof IConversationEnabled){
+                   ConversationHolder conversation = ((IConversationEnabled) AbstractUtility.getActiveEditor()).getConversationHolder();
+                   return conversation;
+               }
+           }else if(getParentElement() instanceof IConversationEnabled){
+               return ((IConversationEnabled) getParentElement()).getConversationHolder();
+           }
+               MessagingUtils.error(getClass(), "Could not get conversation for AbstractFormSection. There is an error in the implementation. There should have been an active editor but it wasn't",
                                new IllegalArgumentException());
                return null;
 
@@ -582,6 +587,31 @@ public abstract class AbstractFormSection<ENTITY> extends Section implements ISe
        /** {@inheritDoc} */
        @Override
     public void update(CdmDataChangeMap changeEvents) {
+
+       }
+
+    public class ExpandListener implements IExpansionListener{
+               @Override
+               public void expansionStateChanging(ExpansionEvent e) {
+               }
+               @Override
+               public void expansionStateChanged(ExpansionEvent e) {
+                       PreferencesUtil.getPreferenceStore().setValue(getPrefKey(), e.getState());
+               }
+    }
+
+    /**
+     * Adds a custom implementation of IExpansionListener to this section
+     * which stores the expansion state in the preferences
+     */
+       protected void addExpandListener() {
+               PreferencesUtil.getPreferenceStore().setDefault(getPrefKey(), isExpanded());
+               setExpanded(PreferencesUtil.getPreferenceStore().getBoolean(getPrefKey()));
+               addExpansionListener(new ExpandListener());
+       }
+
+       private String getPrefKey() {
+               return this.getClass().getCanonicalName()+";"+entity.getClass().getCanonicalName();
        }