001: /* uDig - User Friendly Desktop Internet GIS client
002: * http://udig.refractions.net
003: * (C) 2004, Refractions Research Inc.
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation;
008: * version 2.1 of the License.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: */
015: package net.refractions.udig.tools.edit;
016:
017: import java.util.ArrayList;
018: import java.util.List;
019: import java.util.Stack;
020:
021: /**
022: * This class provides methods so that initializing an Edit tool is done declaratively.
023: *
024: * @author jones
025: * @since 1.1.0
026: */
027: public class EditToolConfigurationHelper {
028:
029: private List<EventBehaviour> behaviours;
030: private Stack<Map> lists = new Stack<Map>();
031: private List<EventBehaviour> current;
032: private ListType currentType = ListType.NONE;
033: private boolean done = false;
034: private List<EventBehaviour> elseList;
035:
036: public EditToolConfigurationHelper(List<EventBehaviour> behaviours) {
037: this .behaviours = behaviours;
038: current = behaviours;
039: }
040:
041: /**
042: * Starts building a list of behaviours that will be mutually exclusive. IE only the first behviour
043: * that is valid will run.
044: */
045: public void startMutualExclusiveList() {
046: pushCurrentList();
047: currentType = ListType.EXCLUSIVE;
048: current = new ArrayList<EventBehaviour>();
049: }
050:
051: /**
052: * Signals the end of a Mutually Exclusive list of behaviours
053: */
054: public void stopMutualExclusiveList() {
055: if (currentType != ListType.EXCLUSIVE)
056: throw new IllegalStateException(
057: "A mutual exclusive list is not the current type of list being" + //$NON-NLS-1$
058: "created: " + currentType); //$NON-NLS-1$
059:
060: MutualExclusiveEventBehavior mutualExclusiveBehavior = new MutualExclusiveEventBehavior(
061: current);
062: popLastList(mutualExclusiveBehavior);
063: }
064:
065: /**
066: * Starts building a list of behaviours that are ordered but all behaviours are run.
067: * @param processAsCommand If true then the behaviours will be processed in the command execution thread instead of the Display thread.
068: * This is sometimes necessary if a command from a previous behaviour may change the state that a later command depends on.
069: * However it depends on the implementation of the behaviour, many behaviours pre-execute their commands in the display thread so
070: * do some research before using this as is can cause a slower response to the user.
071: */
072: public void startOrderedList(boolean processAsCommand) {
073: pushCurrentList();
074: currentType = processAsCommand ? ListType.ORDERED_COMMAND
075: : ListType.ORDERED;
076: current = new ArrayList<EventBehaviour>();
077: }
078:
079: public void stopOrderedList() {
080: if (currentType != ListType.ORDERED
081: && currentType != ListType.ORDERED_COMMAND)
082: throw new IllegalStateException(
083: "A mutual exclusive list is not the current type of list being" + //$NON-NLS-1$
084: "created: " + currentType); //$NON-NLS-1$
085:
086: OrderedCompositeEventBehavior orderedCompositeBehaviour = new OrderedCompositeEventBehavior(
087: current, currentType == ListType.ORDERED_COMMAND);
088: popLastList(orderedCompositeBehaviour);
089: }
090:
091: /**
092: * Add a behaviours to the current list
093: *
094: * @param behaviour the behaviour to add
095: */
096: public void add(EventBehaviour behaviour) {
097: current.add(behaviour);
098: }
099:
100: /**
101: * Signals that the configuration is complete. It checks that all lists where correctly signalled as done.
102: * An exception will be thrown if done is not called
103: *
104: */
105: public void done() {
106: done = true;
107: if (currentType != ListType.NONE)
108: throw new IllegalStateException(
109: "There are still " + lists.size() + "lists not finished, " + //$NON-NLS-1$ //$NON-NLS-2$
110: "the current list is a " + currentType
111: + " list"); //$NON-NLS-1$//$NON-NLS-2$
112: }
113:
114: private void popLastList(EventBehaviour behavior) {
115: if (lists.isEmpty()) {
116: behaviours.add(behavior);
117: current = behaviours;
118: currentType = ListType.NONE;
119: } else {
120: Map map = lists.pop();
121:
122: map.list.add(behavior);
123: current = map.list;
124: currentType = map.type;
125: }
126: }
127:
128: private void pushCurrentList() {
129: if (current != behaviours) {
130: lists.push(new Map(currentType, current));
131: }
132: }
133:
134: enum ListType {
135: EXCLUSIVE, ORDERED, NONE, ADVANCED, ELSE, ORDERED_COMMAND
136: }
137:
138: static class Map {
139: final ListType type;
140: final List<EventBehaviour> list;
141:
142: Map(ListType type, List<EventBehaviour> list) {
143: this .type = type;
144: this .list = list;
145: }
146: }
147:
148: /**
149: * Returns true if the done() was called;
150: * @return
151: */
152: public boolean isDone() {
153: return done;
154: }
155:
156: /**
157: * Behaviours that are added after this method is called will only be active when the advanced editing
158: * is active.
159: * <p> The normal behaviour must either be outside of the Advanced list or in the Else List</p>
160: *
161: * @see #startElseFeatures()
162: */
163: public void startAdvancedFeatures() {
164: pushCurrentList();
165: currentType = ListType.ADVANCED;
166: current = new ArrayList<EventBehaviour>();
167: }
168:
169: /**
170: * Ends Advanced behaviour section
171: */
172: public void stopAdvancedFeatures() {
173: if (currentType != ListType.ADVANCED)
174: throw new IllegalStateException(
175: "A advanced behaviours list is not the current type of list being" + //$NON-NLS-1$
176: "created: " + currentType); //$NON-NLS-1$
177:
178: AdvancedFeaturesEventBehavior behavior = new AdvancedFeaturesEventBehavior(
179: current);
180: if (elseList != null) {
181: behavior.setElse(elseList);
182: elseList = null;
183: }
184: popLastList(behavior);
185: }
186:
187: /**
188: * Starts the Else Behaviours of the Advanced configuration. The Else Behaviours are the behaviours that only run when Not in advanced
189: * mode. The Advanced System has the "Advanced Behaviours", which are ran only when in advanced mode and the "Else Behaviours", which run
190: * only when not in Advanced Mode.
191: * <p>StartElseFeatures() must be called after {@link #startAdvancedFeatures()} has been called but before {@link #stopAdvancedFeatures()}
192: * is called </p>
193: */
194: public void startElseFeatures() {
195: if (currentType != ListType.ADVANCED)
196: throw new IllegalStateException(
197: "Else Features can only be added to Advanced feature list. Current" + //$NON-NLS-1$
198: " list is: " + currentType); //$NON-NLS-1$
199:
200: pushCurrentList();
201: currentType = ListType.ELSE;
202: current = new ArrayList<EventBehaviour>();
203: elseList = current;
204: }
205:
206: /**
207: * Ends the declaration of the Else Behaviours
208: */
209: public void stopElseFeatures() {
210: if (currentType != ListType.ELSE)
211: throw new IllegalStateException(
212: "Else is not the current type of list being" + //$NON-NLS-1$
213: "added. StartElseFeatures() must be called first. Current type is: "
214: + currentType); //$NON-NLS-1$
215:
216: Map map = lists.pop();
217: currentType = map.type;
218: current = map.list;
219: }
220: }
|