/* * Copyright (c) 2006 Stiftung Deutsches Elektronen-Synchroton, * Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY. * * THIS SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "../AS IS" BASIS. * WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND * NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. SHOULD THE SOFTWARE PROVE DEFECTIVE * IN ANY RESPECT, THE USER ASSUMES THE COST OF ANY NECESSARY SERVICING, REPAIR OR * CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. * NO USE OF ANY SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. * DESY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. * THE FULL LICENSE SPECIFYING FOR THE SOFTWARE THE REDISTRIBUTION, MODIFICATION, * USAGE AND OTHER RIGHTS AND OBLIGATIONS IS INCLUDED WITH THE DISTRIBUTION OF THIS * PROJECT IN THE FILE LICENSE.HTML. IF THE LICENSE IS NOT INCLUDED YOU MAY FIND A COPY * AT HTTP://WWW.DESY.DE/LEGAL/LICENSE.HTM */ package org.csstudio.sds.model; import java.util.ArrayList; import java.util.List; import org.csstudio.sds.internal.model.LayerSupport; import org.eclipse.core.runtime.IAdaptable; /** * @author Sven Wende * * @version $Revision: 1.27 $ * */ public abstract class ContainerModel extends AbstractWidgetModel implements IAdaptable { /** * ID for <i>select child</i> events. */ public static final String PROP_CHILDREN_SELECTED = "PROP_CHILDREN_SELECTED"; /** * ID for <i>add children</i> events. */ public static final String PROP_CHILDREN_ADDED = "PROP_CHILDREN_ADDED"; //$NON-NLS-1$ /** * ID for <i>add child</i> events. */ public static final String PROP_CHILD_ADDED = "PROP_CHILD_ADDED"; //$NON-NLS-1$ /** * ID for <i>remove children</i> events. */ public static final String PROP_CHILDREN_REMOVED = "PROP_CHILDREN_REMOVED"; //$NON-NLS-1$ /** * ID for <i>remove child</i> events. */ public static final String PROP_CHILD_REMOVED = "PROP_CHILD_REMOVED"; //$NON-NLS-1$ /** * ID for <i>order changed</i> events. */ public static final String PROP_ORDER_CHANGED = "PROP_ORDER_CHANGED"; //$NON-NLS-1$ /** * Flag that indicates whether parent relationships of contained widgets * should be checked an maintained (is used to provide simple cloning * facility for the use in copy&paste function). */ private boolean _parentChecks = true; /** * A list that contains all widgets. */ private List<AbstractWidgetModel> _widgets = new ArrayList<AbstractWidgetModel>(); /** * The name of the default Layer. */ public static final String DEFAULT_LAYER = "DEFAULT"; /** * Flag that signals that the model is currently being loaded. */ private boolean _loading = false; /** * Encapsulates all layer information. */ private LayerSupport _layerSupport; /** * Standard constructor. */ public ContainerModel() { this(true, false); } /** * Constructor. * * @param parentChecksEnabled * true if this container should check and maintain parent * relationships for contained widgets */ public ContainerModel(boolean parentChecksEnabled) { this(parentChecksEnabled, false); } /** * Standard constructor. * * @param parentChecksEnabled * true if this container should check and maintain parent * relationships for contained widgets * @param isRotatable * true if this widget can be rotated */ public ContainerModel(boolean parentChecksEnabled, final boolean isRotatable) { super(true); _layerSupport = new LayerSupport(this); _parentChecks = parentChecksEnabled; } /** * Adds multiple widgets to the container. * * @param indices * the indices for the added images * @param widget * A widget model that is to be added. */ public void addWidgets(List<Integer> indices, List<AbstractWidgetModel> widgets) { // add all widgets for (AbstractWidgetModel w : widgets) { doAddWidget(_widgets.size(), w); } // adjust indices for (int i = 0; i < indices.size(); i++) { doChangeOrder(widgets.get(i), indices.get(i)); } // fire a single event for all added widgets at once firePropertyChangeEvent(PROP_CHILDREN_ADDED, null, widgets); } /** * Adds multiple widgets to the container. * * @param widget * A widget model that is to be added. */ public final void addWidgets(final List<AbstractWidgetModel> widgets) { assert widgets != null; // add all widgets for (AbstractWidgetModel w : widgets) { doAddWidget(_widgets.size(), w); } // fire a single event for all added widgets at once firePropertyChangeEvent(PROP_CHILDREN_ADDED, null, widgets); } /** * Add a widget model to the model. * * @param widget * A widget model that is to be added. */ public final void addWidget(final AbstractWidgetModel widget) { assert widget != null; doAddWidget(_widgets.size(), widget); firePropertyChangeEvent(PROP_CHILD_ADDED, null, widget); } /** * Add a widget model at the given index to the model. * * @param index * The index where to insert the widget. Must be >= 0 and <= * {@link #getWidgets()}.size() * @param widget * A widget model that is to be added. */ public final void addWidget(final int index, final AbstractWidgetModel widget) { assert index >= 0 : "Precondition violated: index >= 0"; //$NON-NLS-1$ assert index <= getWidgets().size() : "Precondition violated: index <= getWidgets().size()"; //$NON-NLS-1$ doAddWidget(index, widget); firePropertyChangeEvent(PROP_CHILD_ADDED, null, widget); } /** * @see #enableParentChecks() */ public void disableParentChecks() { } /** * Adds a widget model at the given index to the model. * * @param index * the index * @param widget * the widget model * @param selectWidget * Specifies if the {@link AbstractWidgetModel} should be * selected */ protected void doAddWidget(final int index, final AbstractWidgetModel widget) { // check parent relationship if (_parentChecks) { if (widget.getParent() != null) { throw new RuntimeException( "Widget already has another parent. Remove it from its parent first."); } else { widget.setParent(this); } } // add widget _widgets.add(index, widget); // inherit live state widget.setLive(isLive()); } /** * Return the widgets of this model. * * @return The widgets of this model. */ public final synchronized List<AbstractWidgetModel> getWidgets() { return new ArrayList<AbstractWidgetModel>(_widgets); } /** * Remove widgets from the container. * * @param widget * The widget model that is to be removed. */ public final void removeWidgets(final List<AbstractWidgetModel> widgets) { assert widgets != null; // remove all widgets for (AbstractWidgetModel w : widgets) { doRemoveWidget(w); } // fire a single event for all removed widgets at once firePropertyChangeEvent(PROP_CHILDREN_REMOVED, null, widgets); } /** * Remove a widget model from the model. * * @param widget * The widget model that is to be removed. */ public final void removeWidget(final AbstractWidgetModel widget) { doRemoveWidget(widget); firePropertyChangeEvent(PROP_CHILD_REMOVED, widget, null); } private void doRemoveWidget(final AbstractWidgetModel widget) { // check parent relationship if (_parentChecks) { if (widget.getParent() != this) { throw new RuntimeException("The widget�s parent is corrupted."); } else { widget.setParent(null); } } // remove _widgets.remove(widget); } /** * Gets the index of the specified widget model. * * @param widget * a widget model * @return the index of the specified widget model and -1 if the specified * widget is not part of the model */ public final int getIndexOf(final AbstractWidgetModel widget) { return _widgets.indexOf(widget); } public final int getPreviousLayerIndex(final AbstractWidgetModel widget) { int startIndex = this.getIndexOf(widget) - 1; for (int i = startIndex; i >= 0; i--) { if (_widgets.get(i).getLayer().equals(widget.getLayer())) { return i; } } return 0; } public final int getNextLayerIndex(final AbstractWidgetModel widget) { int startIndex = this.getIndexOf(widget) + 1; for (int i = startIndex; i < _widgets.size(); i++) { if (_widgets.get(i).getLayer().equals(widget.getLayer())) { return i; } } return _widgets.size() - 1; } /** * Sets the connection state for this model. * * @param isLive * true, if the model is connected to the control system, false * otherwise */ @Override public final void setLive(final boolean isLive) { super.setLive(isLive); // inform children for (AbstractWidgetModel w : getWidgets()) { w.setLive(isLive); } } /** * Returns the loading state of this model. * * @return true, if the model is currently being loaded, false otherwise */ public final boolean isLoading() { return _loading; } /** * Set the loading state of the model. * * @param loading * true, if the model is currently being loaded, false otherwise */ public final synchronized void setLoading(final boolean loading) { _loading = loading; } /** * Returns the index for the front depending on the given * {@link AbstractWidgetModel}. * * @param child * The AbstractWidgetModel * @return int The index for the front */ public final int getFrontIndex(final AbstractWidgetModel child) { for (int i = _widgets.size() - 1; i >= 0; i--) { AbstractWidgetModel widgetModel = _widgets.get(i); if (widgetModel.getLayer().equals(child.getLayer())) { return i; } } return _widgets.size() - 1; } /** * Returns the index for the back. * * @return int The index for the back */ public final int getBackIndex(final AbstractWidgetModel child) { for (int i = 0; i < _widgets.size(); i++) { if (_widgets.get(i).getLayer().equals(child.getLayer())) { return i; } } return 0; } /** * Sets the given AbstractWidgetModel to the given index in the List. * * @param child * The AbstractWidgetModel, which index should be changed * @param newIndex * The new index */ public final void changeOrder(final AbstractWidgetModel child, final int newIndex) { doChangeOrder(child, newIndex); firePropertyChangeEvent(PROP_ORDER_CHANGED, null, null); } private void doChangeOrder(final AbstractWidgetModel child, final int newIndex) { if (_widgets.contains(child) && newIndex >= 0 && newIndex < _widgets.size()) { int oldLength = _widgets.size(); if (newIndex == _widgets.indexOf(child)) { return; } _widgets.remove(child); _widgets.add(newIndex, child); assert oldLength == _widgets.size() : "List is corrupted"; } } /** * Returns the object that encapsulates all layer information for this * container. * * @return the object that encapsulates all layer information for this * container */ public final LayerSupport getLayerSupport() { return _layerSupport; } /** * Selects the specified widgets. * * @param widgetModel * the widget */ public void selectWidgets(List<AbstractWidgetModel> widgets) { firePropertyChangeEvent(PROP_CHILDREN_SELECTED, null, widgets); } }