fiore@0
|
1 /*
|
fiore@0
|
2 CCmI Diagram Editor for Android
|
fiore@0
|
3
|
fiore@0
|
4 Copyright (C) 2012 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
|
fiore@0
|
5
|
fiore@0
|
6 This program is free software: you can redistribute it and/or modify
|
fiore@0
|
7 it under the terms of the GNU General Public License as published by
|
fiore@0
|
8 the Free Software Foundation, either version 3 of the License, or
|
fiore@0
|
9 (at your option) any later version.
|
fiore@0
|
10
|
fiore@0
|
11 This program is distributed in the hope that it will be useful,
|
fiore@0
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
fiore@0
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
fiore@0
|
14 GNU General Public License for more details.
|
fiore@0
|
15
|
fiore@0
|
16 You should have received a copy of the GNU General Public License
|
fiore@0
|
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
fiore@0
|
18 */
|
fiore@0
|
19 package uk.ac.qmul.eecs.ccmi.activities;
|
fiore@0
|
20
|
fiore@0
|
21 import java.util.ArrayList;
|
fiore@0
|
22 import java.util.LinkedHashMap;
|
fiore@0
|
23 import java.util.LinkedHashSet;
|
fiore@0
|
24 import java.util.LinkedList;
|
fiore@0
|
25 import java.util.List;
|
fiore@0
|
26 import java.util.Map;
|
fiore@0
|
27 import java.util.Set;
|
fiore@0
|
28
|
fiore@0
|
29 import uk.ac.qmul.eecs.ccmi.accessibility.AccessibilityService;
|
fiore@0
|
30 import uk.ac.qmul.eecs.ccmi.accessibility.AccessibilityService.SoundEvent;
|
fiore@0
|
31 import uk.ac.qmul.eecs.ccmi.accessibility.AccessibleCheckbox;
|
fiore@0
|
32 import uk.ac.qmul.eecs.ccmi.accessibility.AccessibleDialogBuilder;
|
fiore@1
|
33 import uk.ac.qmul.eecs.ccmi.utilities.ILogger;
|
fiore@0
|
34 import uk.ac.qmul.eecs.ccmi.utilities.Stack;
|
fiore@0
|
35 import uk.ac.qmul.eecs.ccmi.xmlparser.Diagram;
|
fiore@0
|
36 import uk.ac.qmul.eecs.ccmi.xmlparser.DiagramUpdater;
|
fiore@0
|
37 import uk.ac.qmul.eecs.ccmi.xmlparser.Edge;
|
fiore@0
|
38 import uk.ac.qmul.eecs.ccmi.xmlparser.EdgeNode;
|
fiore@0
|
39 import uk.ac.qmul.eecs.ccmi.xmlparser.EdgeType;
|
fiore@0
|
40 import uk.ac.qmul.eecs.ccmi.xmlparser.HierarchyItem;
|
fiore@0
|
41 import uk.ac.qmul.eecs.ccmi.xmlparser.LocalDiagramUpdater;
|
fiore@0
|
42 import uk.ac.qmul.eecs.ccmi.xmlparser.Modifier;
|
fiore@0
|
43 import uk.ac.qmul.eecs.ccmi.xmlparser.Node;
|
fiore@0
|
44 import uk.ac.qmul.eecs.ccmi.xmlparser.NodeProperty;
|
fiore@0
|
45 import uk.ac.qmul.eecs.ccmi.xmlparser.NodePropertyType;
|
fiore@0
|
46 import uk.ac.qmul.eecs.ccmi.xmlparser.NodeType;
|
fiore@0
|
47 import uk.ac.qmul.eecs.ccmi.xmlparser.PropertyValue;
|
fiore@0
|
48 import android.support.v4.app.DialogFragment;
|
fiore@0
|
49 import android.view.View;
|
fiore@0
|
50 import android.widget.AdapterView;
|
fiore@0
|
51 import android.widget.EditText;
|
fiore@0
|
52 import android.widget.Spinner;
|
fiore@0
|
53
|
fiore@0
|
54 /**
|
fiore@0
|
55 * Provides a navigation of the model (the diagram) based on the tree hierarchy of the
|
fiore@0
|
56 * <a href="http://ccmi.eecs.qmul.ac.uk">CCmI Diagram Editor</a>
|
fiore@0
|
57 *
|
fiore@0
|
58 */
|
fiore@0
|
59 class TreeNavigation {
|
fiore@0
|
60
|
fiore@0
|
61 private static final String RENAME_DIALOG_TAG = "Rename ";
|
fiore@0
|
62 private static final String EDIT_NODE_DIALOG_TAG = "Edit Node Dialog";
|
fiore@0
|
63 private static final String EDIT_EDGE_DIALOG_TAG = "Edit Edge Dialog";
|
fiore@0
|
64 private static final String EDIT_NODE_REF_DIALOG_TAG = "Edit Node Reference Dialog";
|
fiore@0
|
65 private static final String EDIT_LABEL_DIALOG_TAG = "Edit Label";
|
fiore@0
|
66 private static final String EDIT_ARROWHEAD_DIALOG_TAG = "Edit Arrow Head Dialog";
|
fiore@0
|
67 private static final String CONFIRMATION_DIALOG_TAG = "Are you sure you want to delete";
|
fiore@0
|
68 private static final String ADD_PROPERTY_DIALOG_TAG = "Add Property Dialog";
|
fiore@0
|
69 private static final String EDIT_PROPERTY_DIALOG_TAG = "Edit Property Dialog";
|
fiore@0
|
70 private static final String EDIT_MODIFIERS_DIALOG_TAG = "Edit Modifiers Dialog";
|
fiore@0
|
71
|
fiore@0
|
72 private Diagram diagram;
|
fiore@0
|
73 private DiagramUpdater diagramUpdater;
|
fiore@0
|
74 private Stack<HierarchyItem> path;
|
fiore@0
|
75
|
fiore@0
|
76 private List<Node> selectedNodes = new ArrayList<Node>(4);
|
fiore@0
|
77 /* cached list is filled up when next() and previous() and used to undo the navigation
|
fiore@0
|
78 * if the list created is empty. Once created, then it's returned by getCurrentList() */
|
fiore@0
|
79 private String[] cachedList;
|
fiore@0
|
80 private Stack<String> cachedHeaderTexts;
|
fiore@0
|
81
|
fiore@0
|
82 /* controller for edit actions with access to the current status of the navigation */
|
fiore@0
|
83 private Controller controller;
|
fiore@0
|
84 private Updateable updateable;
|
fiore@0
|
85
|
fiore@0
|
86 /* the level currently displayed. Level item's toString() is on the header *
|
fiore@0
|
87 * text and its children are displayed in the currentList */
|
fiore@0
|
88 private final static int PATH_MAX_LEN = 5;
|
fiore@0
|
89 public final static int DIAGRAM_LEVEL = 0;
|
fiore@0
|
90 public final static int TYPE_LEVEL = 1;
|
fiore@0
|
91 public final static int ITEM_LEVEL = 2;
|
fiore@0
|
92 public final static int REFERENCE_AND_PROPERTY_TYPE_LEVEL = 3;
|
fiore@0
|
93 public final static int PROPERTY_AND_EDGE_REFERENCE_LEVEL = 4; // neved used
|
fiore@0
|
94
|
fiore@0
|
95 public TreeNavigation(Diagram diagram, AccessibleDialogBuilder dialogBuilder, Updateable updateable){
|
fiore@0
|
96 this.diagram = diagram;
|
fiore@0
|
97 this.updateable = updateable;
|
fiore@0
|
98 diagramUpdater = new LocalDiagramUpdater(diagram);
|
fiore@0
|
99 path = new Stack<HierarchyItem>(PATH_MAX_LEN);
|
fiore@0
|
100 cachedHeaderTexts = new Stack<String>(PATH_MAX_LEN);
|
fiore@0
|
101 /* tree path starts with top node */
|
fiore@0
|
102 path.push(diagram);
|
fiore@0
|
103 cachedHeaderTexts.push(diagram.toString());
|
fiore@0
|
104 cachedList = buildCurrentChildList();
|
fiore@0
|
105 controller = new Controller(dialogBuilder);
|
fiore@0
|
106 }
|
fiore@0
|
107
|
fiore@0
|
108 public String[] getCurrentChildList(){
|
fiore@0
|
109 return cachedList;
|
fiore@0
|
110 }
|
fiore@0
|
111
|
fiore@0
|
112 public String getCurrentPath(){
|
fiore@0
|
113 StringBuilder builder = new StringBuilder();
|
fiore@0
|
114 for(HierarchyItem item : path){
|
fiore@0
|
115 builder.append('/').append(item);
|
fiore@0
|
116 }
|
fiore@0
|
117 return builder.toString();
|
fiore@0
|
118 }
|
fiore@0
|
119
|
fiore@0
|
120 /* builds the String list of items to display when getCurrentListIsCalled */
|
fiore@0
|
121 private String[] buildCurrentChildList(){
|
fiore@0
|
122 String[] currentList = null;
|
fiore@0
|
123 switch(path.level()){
|
fiore@0
|
124 case DIAGRAM_LEVEL :{
|
fiore@0
|
125 List<NodeType> nodeTypes = diagram.getPrototypes().getNodeTypes();
|
fiore@0
|
126 List<EdgeType> edgeTypes = diagram.getPrototypes().getEdgeTypes();
|
fiore@0
|
127 int numNodeTypes = nodeTypes.size();
|
fiore@0
|
128 int numEdgeTypes = edgeTypes.size();
|
fiore@0
|
129 currentList = new String[numNodeTypes+numEdgeTypes];
|
fiore@0
|
130
|
fiore@0
|
131 /* build the string for each node type */
|
fiore@0
|
132 StringBuilder builder = new StringBuilder();
|
fiore@0
|
133 for(int i=0; i<numNodeTypes;i++){
|
fiore@0
|
134 builder.setLength(0);
|
fiore@0
|
135 builder.append(nodeTypes.get(i).getType())
|
fiore@0
|
136 .append(' ')
|
fiore@0
|
137 .append('(')
|
fiore@0
|
138 .append(count(nodeTypes.get(i)))
|
fiore@0
|
139 .append(')');
|
fiore@0
|
140 currentList[i] = builder.toString();
|
fiore@0
|
141 }
|
fiore@0
|
142 /* build the string for each edge type */
|
fiore@0
|
143 for(int j=0; j<numEdgeTypes; j++){
|
fiore@0
|
144 builder.setLength(0);
|
fiore@0
|
145 builder.append(edgeTypes.get(j).getType())
|
fiore@0
|
146 .append(' ')
|
fiore@0
|
147 .append('(')
|
fiore@0
|
148 .append(count(edgeTypes.get(j)))
|
fiore@0
|
149 .append(')');
|
fiore@0
|
150 currentList[numNodeTypes+j] = builder.toString();
|
fiore@0
|
151 }
|
fiore@0
|
152
|
fiore@0
|
153 break;
|
fiore@0
|
154 }
|
fiore@0
|
155 case TYPE_LEVEL : {
|
fiore@0
|
156 /* list all objects of a certain type */
|
fiore@0
|
157 LinkedList<String> items = new LinkedList<String>();
|
fiore@0
|
158 if(path.current() instanceof NodeType){
|
fiore@0
|
159 for(Node cNode : diagram.getComponents().getNodes()){
|
fiore@0
|
160 if(path.current().toString().equals(cNode.getType()))
|
fiore@0
|
161 if(selectedNodes.contains(cNode))
|
fiore@0
|
162 items.add("<"+cNode+">"); // <selected node>
|
fiore@0
|
163 else
|
fiore@0
|
164 items.add(cNode.getName());
|
fiore@0
|
165 }
|
fiore@0
|
166 }else{
|
fiore@0
|
167 for(Edge cEdge : diagram.getComponents().getEdges()){
|
fiore@0
|
168 if(path.current().toString().equals(cEdge.getType()))
|
fiore@0
|
169 items.add(cEdge.getName());
|
fiore@0
|
170 }
|
fiore@0
|
171 }
|
fiore@0
|
172 currentList = items.toArray(new String[items.size()]);
|
fiore@0
|
173 break;
|
fiore@0
|
174 }
|
fiore@0
|
175 case ITEM_LEVEL : {
|
fiore@0
|
176 Map<String,Integer> edgeTypes = new LinkedHashMap<String,Integer>();
|
fiore@0
|
177 if(path.current() instanceof Node){
|
fiore@0
|
178 /* node displays the list of edge types connected to *
|
fiore@0
|
179 * itself + the list of property types defined for itself */
|
fiore@0
|
180 Node node = (Node)path.current();
|
fiore@0
|
181 /* add the edge types of the edges the node is attached to */
|
fiore@0
|
182 for(Edge cEdge : diagram.getComponents().getEdges()){
|
fiore@0
|
183 for(EdgeNode attachedNode : cEdge.getAttachedNodes()){
|
fiore@0
|
184 if(attachedNode.getId() == node.getId()){
|
fiore@0
|
185 if(!edgeTypes.containsKey(cEdge.getType())){
|
fiore@0
|
186 edgeTypes.put(cEdge.getType(),1);
|
fiore@0
|
187 }else{
|
fiore@0
|
188 edgeTypes.put(cEdge.getType(),edgeTypes.get(cEdge.getType())+1);
|
fiore@0
|
189 }
|
fiore@0
|
190 break;
|
fiore@0
|
191 }
|
fiore@0
|
192 }
|
fiore@0
|
193 }
|
fiore@0
|
194
|
fiore@0
|
195 /* build the array to return : first part is the edge types. second part property types /
|
fiore@0
|
196 /* now the property types this node can have */
|
fiore@0
|
197 currentList = new String[edgeTypes.size()+node.getProperties().size()];
|
fiore@0
|
198 int i = 0;
|
fiore@0
|
199 StringBuilder builder = new StringBuilder();
|
fiore@0
|
200 for(Map.Entry<String, Integer> entry : edgeTypes.entrySet()){
|
fiore@0
|
201 builder.setLength(0);
|
fiore@0
|
202 currentList[i++] = builder.append(entry.getKey())
|
fiore@0
|
203 .append(' ')
|
fiore@0
|
204 .append('(')
|
fiore@0
|
205 .append(entry.getValue())
|
fiore@0
|
206 .append(')').toString();
|
fiore@0
|
207 }
|
fiore@0
|
208
|
fiore@0
|
209 for(int j=i;j<currentList.length;j++){
|
fiore@0
|
210 builder.setLength(0);
|
fiore@0
|
211 currentList[j] = builder.append(node.getProperties().get(j-i).getType())
|
fiore@0
|
212 .append(' ')
|
fiore@0
|
213 .append('(')
|
fiore@0
|
214 .append(node.getProperties().get(j-i).getValues().size())
|
fiore@0
|
215 .append(')').toString();
|
fiore@0
|
216 }
|
fiore@0
|
217
|
fiore@0
|
218 }else{ // Edge
|
fiore@0
|
219 /* edge displays the list of nodes attached to self */
|
fiore@0
|
220 Edge cEdge = (Edge)path.current();
|
fiore@0
|
221 currentList = new String[cEdge.getAttachedNodes().size()];
|
fiore@0
|
222 int i = 0;
|
fiore@0
|
223 for(EdgeNode attachedNode : cEdge.getAttachedNodes()){
|
fiore@0
|
224 for(Node node : diagram.getComponents().getNodes()){
|
fiore@0
|
225 if(node.getId() == attachedNode.getId()){
|
fiore@0
|
226 currentList[i++] = (attachedNode.getHead()+" "+node.getName()+" "+attachedNode.getLabel()).trim();
|
fiore@0
|
227 }
|
fiore@0
|
228 }
|
fiore@0
|
229 }
|
fiore@0
|
230 }
|
fiore@0
|
231 break;
|
fiore@0
|
232 }
|
fiore@0
|
233 case REFERENCE_AND_PROPERTY_TYPE_LEVEL : {
|
fiore@0
|
234 /* display the values of the selected property types */
|
fiore@0
|
235 if(path.current() instanceof NodeProperty){ // property type is displayed on the header
|
fiore@0
|
236 NodeProperty property = (NodeProperty)path.current();
|
fiore@0
|
237 currentList = new String[property.getValues().size()];
|
fiore@0
|
238 NodeType nodeType = (NodeType)path.get(TYPE_LEVEL);
|
fiore@0
|
239
|
fiore@0
|
240 /* for each property value build the string "mod1 mod2 mod3...value" *
|
fiore@0
|
241 * where modn is the modifier type and value is the property value */
|
fiore@0
|
242 StringBuilder builder = new StringBuilder();
|
fiore@0
|
243 for(int i=0; i<currentList.length; i++){
|
fiore@0
|
244 builder.setLength(0);
|
fiore@0
|
245 List<Integer> modifierIndexes = property.getValues().get(i).getModifiersIndexes();
|
fiore@0
|
246 for(NodePropertyType propertyType : nodeType.getPropretyTypes()){
|
fiore@0
|
247 if(propertyType.getType().equals(property.getType())){
|
fiore@0
|
248 ArrayList<Modifier> modifiers = propertyType.getModifiers();
|
fiore@0
|
249 for(Integer j : modifierIndexes){
|
fiore@0
|
250 builder.append(modifiers.get(j).getType()).append(' ');
|
fiore@0
|
251 }
|
fiore@0
|
252 }
|
fiore@0
|
253 }
|
fiore@0
|
254 currentList[i] = builder.append(property.getValues().get(i).getValue()).toString();
|
fiore@0
|
255 }
|
fiore@0
|
256
|
fiore@0
|
257 // NodeProperty propertyType = (NodeProperty)path.current();
|
fiore@0
|
258 // Node node = (Node)path.get(ITEM_LEVEL);
|
fiore@0
|
259 // for(NodeProperty property : node.getProperties()){
|
fiore@0
|
260 // if(property.getType().equals(propertyType.getType())){
|
fiore@0
|
261 // currentList = new String[property.getValues().size()];
|
fiore@0
|
262 // for(int i=0; i<currentList.length; i++){
|
fiore@0
|
263 // currentList[i] = property.getValues().get(i).getValue();
|
fiore@0
|
264 // }
|
fiore@0
|
265 // break;
|
fiore@0
|
266 // }
|
fiore@0
|
267 // }
|
fiore@0
|
268 }else{ // instance of EdgeType
|
fiore@0
|
269 EdgeType edgeType = (EdgeType)path.current();
|
fiore@0
|
270 LinkedList<String> currentListItems = new LinkedList<String>();
|
fiore@0
|
271 int nodeID = ((Node)path.get(ITEM_LEVEL)).getId();
|
fiore@0
|
272 StringBuilder builder = new StringBuilder();
|
fiore@0
|
273 for(Edge edge : diagram.getComponents().getEdges()){
|
fiore@0
|
274 if(edge.getType().equals(edgeType.getType())){
|
fiore@0
|
275 for(EdgeNode attachedNode : edge.getAttachedNodes()){
|
fiore@0
|
276 if(attachedNode.getId() == nodeID){
|
fiore@0
|
277 currentListItems.add(makeEdgeReferenceString(edge,nodeID,builder));
|
fiore@0
|
278 }
|
fiore@0
|
279 }
|
fiore@0
|
280 }
|
fiore@0
|
281 }
|
fiore@0
|
282 currentList = currentListItems.toArray(new String[currentListItems.size()]);
|
fiore@0
|
283 }
|
fiore@0
|
284 break;
|
fiore@0
|
285 }
|
fiore@0
|
286 default : new IllegalStateException("Wrong path level: "+path.level());
|
fiore@0
|
287 }
|
fiore@0
|
288 return currentList;
|
fiore@0
|
289 }
|
fiore@0
|
290
|
fiore@0
|
291 /**
|
fiore@0
|
292 * Returns the label of the parent of the list currently visualized
|
fiore@0
|
293 *
|
fiore@0
|
294 * @return the label of the parent
|
fiore@0
|
295 */
|
fiore@0
|
296 public String getCurrentItemName(){
|
fiore@0
|
297 String text = cachedHeaderTexts.current();
|
fiore@0
|
298 if(text != null)
|
fiore@0
|
299 return text;
|
fiore@0
|
300 else
|
fiore@0
|
301 return path.current().toString();
|
fiore@0
|
302 }
|
fiore@0
|
303
|
fiore@0
|
304 /**
|
fiore@0
|
305 * Returns the level of the navigation at the moment the method is called.
|
fiore@0
|
306 *
|
fiore@0
|
307 * @return an {@code int} representing the current level. Possible values are
|
fiore@0
|
308 * listed as {@code static} variables of this class.
|
fiore@0
|
309 */
|
fiore@0
|
310 public int getCurrentLevel(){
|
fiore@0
|
311 return path.level();
|
fiore@0
|
312 }
|
fiore@0
|
313
|
fiore@0
|
314 /**
|
fiore@0
|
315 * Makes a child of the current {@code HierarchyItem} the current one.
|
fiore@0
|
316 *
|
fiore@0
|
317 * @param child the index of the child becoming the current
|
fiore@0
|
318 * @return {@code true} if the current position has changed after the call
|
fiore@0
|
319 **/
|
fiore@0
|
320 public boolean goNext(int child){
|
fiore@0
|
321 if(child < 0)
|
fiore@0
|
322 throw new IllegalArgumentException("Wrong child index: "+child);
|
fiore@0
|
323
|
fiore@0
|
324 HierarchyItem hierarchyItem = findNext(child);
|
fiore@0
|
325 if(hierarchyItem == null)
|
fiore@0
|
326 return false;
|
fiore@0
|
327
|
fiore@0
|
328 path.push(hierarchyItem);
|
fiore@0
|
329 /* saves the selected list item to display as a title on the next call to getCurrentHeaderText() */
|
fiore@0
|
330 cachedHeaderTexts.push(cachedList[child]);
|
fiore@0
|
331 /* make the new list to return for next calls to getCurrentList() */
|
fiore@0
|
332 cachedList = buildCurrentChildList();
|
fiore@0
|
333 /* the selected hierarchy node has no children. go back and return false */
|
fiore@0
|
334 if(cachedList.length == 0){
|
fiore@0
|
335 goPrevious();
|
fiore@0
|
336 return false;
|
fiore@0
|
337 }
|
fiore@0
|
338 updateable.update();
|
fiore@0
|
339 return true;
|
fiore@0
|
340 }
|
fiore@0
|
341
|
fiore@0
|
342 private HierarchyItem findNext(int child){
|
fiore@0
|
343 switch(path.level()){
|
fiore@0
|
344 case DIAGRAM_LEVEL :{
|
fiore@0
|
345 List<NodeType> nodeTypes = diagram.getPrototypes().getNodeTypes();
|
fiore@0
|
346 List<EdgeType> edgeTypes = diagram.getPrototypes().getEdgeTypes();
|
fiore@0
|
347 int numNodeTypes = nodeTypes.size();
|
fiore@0
|
348 int numEdgeTypes = edgeTypes.size();
|
fiore@0
|
349 if(child >= numNodeTypes+numEdgeTypes)
|
fiore@0
|
350 throw new IllegalArgumentException("Wrong child index: "+child);
|
fiore@0
|
351
|
fiore@0
|
352 if(child < numNodeTypes){
|
fiore@0
|
353 return nodeTypes.get(child);
|
fiore@0
|
354 }else{
|
fiore@0
|
355 return edgeTypes.get(child-numNodeTypes);
|
fiore@0
|
356 }
|
fiore@0
|
357 }
|
fiore@0
|
358 case TYPE_LEVEL : {
|
fiore@0
|
359 int numTypeItems = 0;// the number of nodes or edges found of the current type
|
fiore@0
|
360 if(path.current() instanceof NodeType){
|
fiore@0
|
361 /* find the child-th node of the current type */
|
fiore@0
|
362 for(Node node : diagram.getComponents().getNodes()){
|
fiore@0
|
363 if(path.current().toString().equals(node.getType())){
|
fiore@0
|
364 if(numTypeItems == child){
|
fiore@0
|
365 return node;
|
fiore@0
|
366 }else{
|
fiore@0
|
367 numTypeItems++;
|
fiore@0
|
368 }
|
fiore@0
|
369 }
|
fiore@0
|
370 }
|
fiore@0
|
371 }else{ // EdgeType
|
fiore@0
|
372 for(Edge edge : diagram.getComponents().getEdges()){
|
fiore@0
|
373 /* find the child-th edge of the current type */
|
fiore@0
|
374 if(path.current().toString().equals(edge.getType())){
|
fiore@0
|
375 if(numTypeItems == child){
|
fiore@0
|
376 return edge;
|
fiore@0
|
377 }else{
|
fiore@0
|
378 numTypeItems++;
|
fiore@0
|
379 }
|
fiore@0
|
380 }
|
fiore@0
|
381 }
|
fiore@0
|
382 }
|
fiore@0
|
383 break;
|
fiore@0
|
384 }
|
fiore@0
|
385 case ITEM_LEVEL : {
|
fiore@0
|
386 /* we can go further only for nodes */
|
fiore@0
|
387 if(path.current() instanceof Node){
|
fiore@0
|
388 Node node = (Node)path.current();
|
fiore@0
|
389 /* check if user clicked on an edge, this node is attached to */
|
fiore@0
|
390
|
fiore@0
|
391 Set<String> cNodeEdgeTypes = new LinkedHashSet<String>();
|
fiore@0
|
392 /* for each edge component */
|
fiore@0
|
393 for(Edge edge : diagram.getComponents().getEdges()){
|
fiore@0
|
394 /* for each attached node to this edge */
|
fiore@0
|
395 for(EdgeNode attachedNode : edge.getAttachedNodes()){
|
fiore@0
|
396 /* if it's this node we're looking for (cNode) */
|
fiore@0
|
397 if(attachedNode.getId() == node.getId()){
|
fiore@0
|
398 cNodeEdgeTypes.add(edge.getType());
|
fiore@0
|
399 }
|
fiore@0
|
400 }
|
fiore@0
|
401 }
|
fiore@0
|
402
|
fiore@0
|
403 if(child < cNodeEdgeTypes.size()){
|
fiore@0
|
404 String selectedType = cNodeEdgeTypes.toArray(new String[cNodeEdgeTypes.size()])[child];
|
fiore@0
|
405 for(EdgeType edge : diagram.getPrototypes().getEdgeTypes()){
|
fiore@0
|
406 if(edge.getType().equals(selectedType)){
|
fiore@0
|
407 return edge;
|
fiore@0
|
408 }
|
fiore@0
|
409 }
|
fiore@0
|
410 }else{// user selected a NodePropertyType put a NodeProperty in the path
|
fiore@0
|
411 return node.getProperties().get(child-cNodeEdgeTypes.size());
|
fiore@0
|
412 }
|
fiore@0
|
413 break;
|
fiore@0
|
414 }
|
fiore@0
|
415 }
|
fiore@0
|
416 default : return null; // don't go further than REFERENCE_AND_PROPERTY_LEVEL
|
fiore@0
|
417 }
|
fiore@0
|
418 return null;
|
fiore@0
|
419 }
|
fiore@0
|
420
|
fiore@0
|
421 /**
|
fiore@0
|
422 * Makes the father of the current {@code HierarchyItem} the current one.
|
fiore@0
|
423 * @return @code true} if the current position has changed after the call
|
fiore@0
|
424 */
|
fiore@0
|
425 public boolean goPrevious(){
|
fiore@0
|
426 if(path.level() == DIAGRAM_LEVEL) // level = DIAGRAM_LEVEL
|
fiore@0
|
427 return false;
|
fiore@0
|
428 path.pop();
|
fiore@0
|
429 cachedList = buildCurrentChildList();
|
fiore@0
|
430 cachedHeaderTexts.pop();
|
fiore@0
|
431 return true;
|
fiore@0
|
432 }
|
fiore@0
|
433
|
fiore@0
|
434 /**
|
fiore@0
|
435 * Returns a controller, that can be used to
|
fiore@0
|
436 * change the model (the diagram) in a way coherent to the tree navigation
|
fiore@0
|
437 *
|
fiore@0
|
438 * @return a controller connected to this navigation
|
fiore@0
|
439 */
|
fiore@0
|
440 public Controller getController(){
|
fiore@0
|
441 return controller;
|
fiore@0
|
442 }
|
fiore@0
|
443
|
fiore@0
|
444 /* Counts the number of nodes or edges of a given type */
|
fiore@0
|
445 private int count(HierarchyItem hItem){
|
fiore@0
|
446 int count = 0;
|
fiore@0
|
447 if(hItem instanceof NodeType){
|
fiore@0
|
448 NodeType node = (NodeType)hItem;
|
fiore@0
|
449 for(Node cNode : diagram.getComponents().getNodes())
|
fiore@0
|
450 if(cNode.getType().equals(node.getType()))
|
fiore@0
|
451 count++;
|
fiore@0
|
452 }else if(hItem instanceof EdgeType){
|
fiore@0
|
453 EdgeType edge = (EdgeType)hItem;
|
fiore@0
|
454 for(Edge cEdge : diagram.getComponents().getEdges())
|
fiore@0
|
455 if(cEdge.getType().equals(edge.getType()))
|
fiore@0
|
456 count++;
|
fiore@0
|
457 }
|
fiore@0
|
458 return count;
|
fiore@0
|
459 }
|
fiore@0
|
460
|
fiore@0
|
461 /* Creates a string for the node reference of edge related to the node N equal to ID nodeID.
|
fiore@0
|
462 * The string looks like "to N1, N2 and N3 vie E", where N1, N2 and N3 are the nodes connected
|
fiore@0
|
463 * to N via E ( they can be more than one in case of a multiple ended edge ).
|
fiore@0
|
464 */
|
fiore@0
|
465 private String makeEdgeReferenceString(Edge edge, int nodeID, StringBuilder builder) {
|
fiore@0
|
466 builder.setLength(0);
|
fiore@0
|
467 builder.append("to ");
|
fiore@0
|
468 /* attach the name of the nodes interleaved by " and " */
|
fiore@0
|
469 for(int i=0; i<edge.getAttachedNodes().size(); i++){
|
fiore@0
|
470 EdgeNode attachedNode = edge.getAttachedNodes().get(i);
|
fiore@0
|
471 if(attachedNode.getId() != nodeID){
|
fiore@0
|
472 for(Node cNode : diagram.getComponents().getNodes()){
|
fiore@0
|
473 if(cNode.getId() == attachedNode.getId()){
|
fiore@0
|
474 if(i == edge.getAttachedNodes().size()-1){
|
fiore@0
|
475 builder.append(cNode.getName());
|
fiore@0
|
476 }else if(i == edge.getAttachedNodes().size()-2){
|
fiore@0
|
477 builder.append(cNode.getName()).append(" and ");
|
fiore@0
|
478 }else{
|
fiore@0
|
479 builder.append(cNode.getName()).append(", ");
|
fiore@0
|
480 }
|
fiore@0
|
481 break;
|
fiore@0
|
482 }
|
fiore@0
|
483 }
|
fiore@0
|
484 }
|
fiore@0
|
485 }
|
fiore@0
|
486 builder.append(", via ");
|
fiore@0
|
487 builder.append(edge.getName());
|
fiore@0
|
488 return builder.toString();
|
fiore@0
|
489 }
|
fiore@0
|
490
|
fiore@0
|
491 /* A controller that changes the model (the data structures in the xml parser package) using the informations *
|
fiore@0
|
492 * given by the TreeNavigation. When commands are issued by the user (through long click) the controller pops *
|
fiore@0
|
493 * up a dialog according to what the user chose and which layer of the tree they are currently visualizing *
|
fiore@0
|
494 * if the user issues the command (doesn't cancel the dialog) the model is updated and the updater *
|
fiore@0
|
495 * is called to refresh and visualize the result */
|
fiore@0
|
496 class Controller implements AccessibleDialogBuilder.ButtonClickListener {
|
fiore@0
|
497 AccessibleDialogBuilder dialogBuilder;
|
fiore@0
|
498 HierarchyItem clickedItem;
|
fiore@0
|
499
|
fiore@0
|
500 Controller(AccessibleDialogBuilder dialogBuilder){
|
fiore@0
|
501 this.dialogBuilder = dialogBuilder;
|
fiore@0
|
502 };
|
fiore@0
|
503
|
fiore@0
|
504 /*
|
fiore@1
|
505 * Responds to the long click of the user. It acts according to the list item clicked
|
fiore@0
|
506 * by the user (and therefore according to the hierarchy level currently displayed).
|
fiore@0
|
507 * When a dialog needs to be shown, it used dialogBuilder.displayDialog() and register itself
|
fiore@0
|
508 * as buttoClickListener to handle the click of the user in the same class.
|
fiore@0
|
509 */
|
fiore@0
|
510 public boolean performEditAction(AdapterView<?> parent, View view,
|
fiore@0
|
511 int position, long id, Updateable u) {
|
fiore@0
|
512 switch(getCurrentLevel()){
|
fiore@0
|
513 case TreeNavigation.DIAGRAM_LEVEL : {
|
fiore@0
|
514 List<NodeType> nodeTypes = diagram.getPrototypes().getNodeTypes();
|
fiore@0
|
515 if(position < nodeTypes.size()){ // user clicked on a node
|
fiore@0
|
516 clickedItem = nodeTypes.get(position);
|
fiore@0
|
517 /* build the properties for node constructor using node property types */
|
fiore@0
|
518 NodeType nodeType = nodeTypes.get(position);
|
fiore@0
|
519 ArrayList<NodeProperty> properties = new ArrayList<NodeProperty>(nodeType.getPropretyTypes().size());
|
fiore@0
|
520 for(NodePropertyType pType : nodeType.getPropretyTypes()){
|
fiore@0
|
521 properties.add(new NodeProperty(pType.getType()));
|
fiore@0
|
522 }
|
fiore@0
|
523 /* construct the node and add it to the diagram */
|
fiore@0
|
524 Node node = new Node(((NodeType)clickedItem).getType(),properties);
|
fiore@0
|
525 diagramUpdater.addNode(node);
|
fiore@1
|
526 dialogBuilder.getAccessibilityService().playSound(SoundEvent.V_OK);
|
fiore@0
|
527 dialogBuilder.getAccessibilityService().speak("Node "+ node +" created");
|
fiore@1
|
528 ILogger.log("Node "+ node +" created");
|
fiore@0
|
529 }else{ // user clicked on edge
|
fiore@0
|
530 List<EdgeType> edgeTypes = diagram.getPrototypes().getEdgeTypes();
|
fiore@0
|
531 clickedItem = edgeTypes.get(position - nodeTypes.size());
|
fiore@0
|
532 /* respect min and max attached nodes */
|
fiore@0
|
533 if(selectedNodes.size() < ((EdgeType)clickedItem).getMinAttachedNodes()){
|
fiore@1
|
534 dialogBuilder.getAccessibilityService().playSound(SoundEvent.V_ERROR);
|
fiore@0
|
535 dialogBuilder.getAccessibilityService().speak("you must select at least "+
|
fiore@0
|
536 ((EdgeType)clickedItem).getMinAttachedNodes()+" nodes");
|
fiore@1
|
537 ILogger.logError("selected nodes < "+((EdgeType)clickedItem).getMinAttachedNodes());
|
fiore@0
|
538 return true;
|
fiore@0
|
539 }
|
fiore@0
|
540 if(selectedNodes.size() > ((EdgeType)clickedItem).getMaxAttachedNodes()){
|
fiore@1
|
541 dialogBuilder.getAccessibilityService().playSound(SoundEvent.V_ERROR);
|
fiore@0
|
542 dialogBuilder.getAccessibilityService().speak("you must select at most "+
|
fiore@0
|
543 ((EdgeType)clickedItem).getMaxAttachedNodes()+" nodes");
|
fiore@1
|
544 ILogger.logError("selected nodes > "+((EdgeType)clickedItem).getMaxAttachedNodes());
|
fiore@0
|
545 return true;
|
fiore@0
|
546 }
|
fiore@0
|
547
|
fiore@0
|
548 /* create the edge and add the edge nodes */
|
fiore@0
|
549 Edge edge = new Edge(((EdgeType)clickedItem).getType());
|
fiore@0
|
550 edge.getAttachedNodes().clear();
|
fiore@0
|
551 /* create all the node references (EdgeNode) for this edge */
|
fiore@0
|
552 for(Node n : diagram.getComponents().getNodes()){
|
fiore@0
|
553 if(selectedNodes.contains(n))
|
fiore@0
|
554 edge.getAttachedNodes().add(new EdgeNode(n.getId()));
|
fiore@0
|
555 }
|
fiore@0
|
556 diagramUpdater.addEdge(edge);
|
fiore@1
|
557 dialogBuilder.getAccessibilityService().playSound(SoundEvent.V_OK);
|
fiore@0
|
558 StringBuilder builder = new StringBuilder();
|
fiore@0
|
559 builder.append(edge).append(" created between ");
|
fiore@0
|
560 for(int i=0; i<selectedNodes.size(); i++){
|
fiore@0
|
561 Node sn = selectedNodes.get(i);
|
fiore@0
|
562 builder.append(sn.getName());
|
fiore@0
|
563 if(i == selectedNodes.size() - 2 ){
|
fiore@0
|
564 builder.append(", and ");
|
fiore@0
|
565 }else if (i != selectedNodes.size() - 1 ){
|
fiore@0
|
566 builder.append(", ");
|
fiore@0
|
567 }
|
fiore@0
|
568 }
|
fiore@0
|
569 selectedNodes.clear(); // when an edge is added the selected node are cleared
|
fiore@0
|
570 dialogBuilder.getAccessibilityService().speak(builder.toString());
|
fiore@1
|
571 ILogger.log(builder.toString());
|
fiore@0
|
572 }
|
fiore@0
|
573 /* update the view */
|
fiore@0
|
574 cachedList = buildCurrentChildList();
|
fiore@0
|
575 updateable.update();
|
fiore@0
|
576 return true;
|
fiore@0
|
577 }
|
fiore@0
|
578 case TreeNavigation.TYPE_LEVEL :{
|
fiore@0
|
579 clickedItem = findNext(position);
|
fiore@0
|
580 /* path.current() is what's displayed on the header */
|
fiore@0
|
581 if(path.current() instanceof NodeType){ // Node
|
fiore@0
|
582 if(selectedNodes.contains(clickedItem)){
|
fiore@0
|
583 dialogBuilder.displayDialog(R.layout.alert_dialog_edit_node_unselect, EDIT_NODE_DIALOG_TAG, this);
|
fiore@0
|
584 }else{
|
fiore@0
|
585 dialogBuilder.displayDialog(R.layout.alert_dialog_edit_node, EDIT_NODE_DIALOG_TAG, this);
|
fiore@0
|
586 }
|
fiore@0
|
587 }else{ // Edge
|
fiore@0
|
588 dialogBuilder.displayDialog(R.layout.alert_dialog_edit_edge, EDIT_EDGE_DIALOG_TAG, this);
|
fiore@0
|
589 }
|
fiore@0
|
590 return true;
|
fiore@0
|
591 }
|
fiore@0
|
592 case TreeNavigation.ITEM_LEVEL :{
|
fiore@0
|
593 if(path.current() instanceof Node){ // Node
|
fiore@0
|
594 clickedItem = findNext(position);
|
fiore@0
|
595 /* edge types inside node cannot be edited directly */
|
fiore@0
|
596 if(clickedItem instanceof EdgeType)
|
fiore@0
|
597 return false;
|
fiore@0
|
598 /* if it ain't an EdgeType then t's a PropertyType */
|
fiore@0
|
599 /* property type items can be used to add new properties */
|
fiore@0
|
600 dialogBuilder.displayDialog(R.layout.alert_dialog_add_property, ADD_PROPERTY_DIALOG_TAG, this);
|
fiore@0
|
601 }else{ // Edge
|
fiore@0
|
602 clickedItem = ((Edge)path.current()).getAttachedNodes().get(position);
|
fiore@0
|
603 dialogBuilder.displayDialog(R.layout.alert_dialog_edit_node_reference, EDIT_NODE_REF_DIALOG_TAG, this);
|
fiore@0
|
604 }
|
fiore@0
|
605 return true;
|
fiore@0
|
606 }
|
fiore@0
|
607 case TreeNavigation.REFERENCE_AND_PROPERTY_TYPE_LEVEL :{
|
fiore@0
|
608 if(path.current() instanceof NodeProperty){
|
fiore@0
|
609 NodeProperty nodeProperty = (NodeProperty)path.current();
|
fiore@0
|
610 clickedItem = nodeProperty.getValues().get(position);
|
fiore@0
|
611 dialogBuilder.displayDialog(R.layout.alert_dialog_edit_property, EDIT_PROPERTY_DIALOG_TAG, this);
|
fiore@0
|
612 return true;
|
fiore@0
|
613 }
|
fiore@0
|
614 return false;
|
fiore@0
|
615 }
|
fiore@0
|
616 case TreeNavigation.PROPERTY_AND_EDGE_REFERENCE_LEVEL :{
|
fiore@0
|
617 return false;// never happens
|
fiore@0
|
618 }
|
fiore@0
|
619 }
|
fiore@0
|
620 return false;
|
fiore@0
|
621 }
|
fiore@0
|
622
|
fiore@1
|
623 /* this is the callback triggered when the user clicks on any botton of the dialog shown. v is the button
|
fiore@0
|
624 * The method first checks for the dialog tag to understand which dialog it's handling, then it checks
|
fiore@0
|
625 * for the button tag to understand which button the user pressed. The first check though is on "CANCEL"
|
fiore@0
|
626 * button as its tag it's the same for all the dialog */
|
fiore@0
|
627 @Override
|
fiore@0
|
628 public void onClick(View v, DialogFragment dialogFragment, String dialogTag) {
|
fiore@0
|
629 Object buttonTag = v.getTag();
|
fiore@1
|
630 ILogger.logButton(buttonTag.toString());
|
fiore@0
|
631 AccessibilityService accessibility = dialogBuilder.getAccessibilityService();
|
fiore@0
|
632
|
fiore@0
|
633 if("CANCEL".equals(buttonTag)){
|
fiore@1
|
634 accessibility.playSound(SoundEvent.V_CANCEL);
|
fiore@0
|
635 accessibility.speak("Cancel");
|
fiore@0
|
636 dialogFragment.dismiss();
|
fiore@0
|
637 return;
|
fiore@0
|
638 }
|
fiore@0
|
639
|
fiore@0
|
640 if(EDIT_NODE_DIALOG_TAG.equals(dialogTag) || EDIT_EDGE_DIALOG_TAG.equals(dialogTag)){
|
fiore@0
|
641 if("SELECT".equals(buttonTag)){
|
fiore@0
|
642 selectedNodes.add((Node)clickedItem);
|
fiore@0
|
643 accessibility.playSound(SoundEvent.V_OK);
|
fiore@0
|
644 accessibility.speak(clickedItem + " selected");
|
fiore@1
|
645 ILogger.log(clickedItem + " selected");
|
fiore@0
|
646 }else if("UNSELECT".equals(buttonTag)){
|
fiore@0
|
647 selectedNodes.remove(clickedItem);
|
fiore@0
|
648 accessibility.playSound(SoundEvent.V_OK);
|
fiore@0
|
649 accessibility.speak(clickedItem + " unselected");
|
fiore@1
|
650 ILogger.log(clickedItem + " unselected");
|
fiore@0
|
651 }else if("RENAME".equals(buttonTag)){
|
fiore@0
|
652 dialogFragment.dismiss();
|
fiore@0
|
653 dialogBuilder.displayDialog(R.layout.alert_dialog_rename, RENAME_DIALOG_TAG+clickedItem, this);
|
fiore@0
|
654 }else if("DELETE".equals(buttonTag)){
|
fiore@0
|
655 dialogFragment.dismiss();
|
fiore@0
|
656 dialogBuilder.displayDialog(R.layout.alert_dialog_confirmation,
|
fiore@0
|
657 CONFIRMATION_DIALOG_TAG+
|
fiore@0
|
658 (EDIT_NODE_DIALOG_TAG.equals(dialogTag) ? " Node " : " Edge ") +
|
fiore@0
|
659 clickedItem,
|
fiore@0
|
660 this);
|
fiore@0
|
661 }
|
fiore@0
|
662 }else if(dialogTag.startsWith(RENAME_DIALOG_TAG)){
|
fiore@0
|
663 /* if it reached this point it'a "RENAME" button as "CANCEL" *
|
fiore@0
|
664 * have been matched against at the beginning of the method */
|
fiore@0
|
665 EditText editText = (EditText)dialogFragment.getDialog().findViewById(R.id.text_edit);
|
fiore@0
|
666 String text = editText.getText().toString().trim();
|
fiore@0
|
667 if(text.length() == 0){
|
fiore@0
|
668 accessibility.playSound(SoundEvent.V_ERROR);
|
fiore@0
|
669 accessibility.speak("Text cannot be empty");
|
fiore@1
|
670 ILogger.logError("text empty");
|
fiore@0
|
671 return;
|
fiore@0
|
672 }
|
fiore@0
|
673 String oldName = clickedItem.toString();
|
fiore@0
|
674 diagramUpdater.rename(clickedItem,text);
|
fiore@0
|
675 accessibility.playSound(SoundEvent.V_OK);
|
fiore@0
|
676 accessibility.speak(oldName+" renamed to "+clickedItem);
|
fiore@1
|
677 ILogger.log(oldName+" renamed to "+clickedItem);
|
fiore@0
|
678 }else if(dialogTag.startsWith(CONFIRMATION_DIALOG_TAG)){
|
fiore@0
|
679 /* if it reaches this point it's a "YES" as a "NO" button has "CANCEL" as its tag */
|
fiore@0
|
680 /* and the match against "CANCEL" match is performed first of all */
|
fiore@0
|
681 diagramUpdater.delete(clickedItem);
|
fiore@0
|
682 /* if it's a selected node, remove it from selected */
|
fiore@0
|
683 selectedNodes.remove(clickedItem);
|
fiore@1
|
684 accessibility.playSound(SoundEvent.V_OK);
|
fiore@0
|
685 accessibility.speak(clickedItem+" Deleted");
|
fiore@1
|
686 ILogger.log(clickedItem+" Deleted");
|
fiore@0
|
687 /* update the headers which show the number of children the current item contains */
|
fiore@0
|
688 if(path.current() instanceof NodeType || path.current() instanceof EdgeType){
|
fiore@0
|
689 cachedHeaderTexts.pop();
|
fiore@0
|
690 cachedHeaderTexts.push(path.current()+" ("+count(path.current())+')');
|
fiore@0
|
691 }else if(path.current() instanceof NodeProperty){
|
fiore@0
|
692 cachedHeaderTexts.pop();
|
fiore@0
|
693 cachedHeaderTexts.push(path.current()+" ("+((NodeProperty)path.current()).getValues().size()+')');
|
fiore@0
|
694 }
|
fiore@0
|
695 }else if(ADD_PROPERTY_DIALOG_TAG.equals(dialogTag)){
|
fiore@0
|
696 /* if it reaches this point it's a "CREATE" as "CANCEL" would *
|
fiore@0
|
697 * have been matched against at the beginning of the method */
|
fiore@0
|
698 EditText editText = (EditText)dialogFragment.getDialog().findViewById(R.id.text_edit);
|
fiore@0
|
699 String text = editText.getText().toString().trim();
|
fiore@0
|
700 if(text.length() == 0){
|
fiore@0
|
701 accessibility.playSound(SoundEvent.V_ERROR);
|
fiore@0
|
702 accessibility.speak("Text cannot be empty");
|
fiore@1
|
703 ILogger.logError("text empty");
|
fiore@0
|
704 return;
|
fiore@0
|
705 }
|
fiore@0
|
706 diagramUpdater.addProperty((Node)path.get(ITEM_LEVEL),((NodeProperty)clickedItem),text);
|
fiore@0
|
707 accessibility.playSound(SoundEvent.V_OK);
|
fiore@0
|
708 accessibility.speak("Property "+text+" added");
|
fiore@1
|
709 ILogger.log("Property "+text+" added");
|
fiore@0
|
710 }else if(EDIT_NODE_REF_DIALOG_TAG.equals(dialogTag)){
|
fiore@0
|
711 if("EDIT_LABEL".equals(buttonTag)){
|
fiore@0
|
712 dialogFragment.dismiss();
|
fiore@0
|
713 dialogBuilder.displayDialog(R.layout.alert_dialog_rename, EDIT_LABEL_DIALOG_TAG, this);
|
fiore@0
|
714 }else{ // EDIT_ARROWHEAD
|
fiore@0
|
715 dialogFragment.dismiss();
|
fiore@0
|
716 Edge edge = (Edge)path.current(); // get the edge this node reference belongs to
|
fiore@0
|
717 String[] heads = null;
|
fiore@0
|
718 /* build a string array with all the available head labels for this edge's type */
|
fiore@0
|
719 for(EdgeType edgeType : diagram.getPrototypes().getEdgeTypes()){
|
fiore@0
|
720 if(edgeType.getType().equals(edge.getType())){
|
fiore@0
|
721 heads = new String[edgeType.getHeads().size()];
|
fiore@0
|
722 for(int i=0; i<heads.length;i++)
|
fiore@0
|
723 heads[i] = edgeType.getHeads().get(i).getHeadLabel();
|
fiore@0
|
724 break;
|
fiore@0
|
725 }
|
fiore@0
|
726 }
|
fiore@0
|
727 if(heads == null || heads.length == 0){
|
fiore@0
|
728 accessibility.playSound(SoundEvent.V_ERROR);
|
fiore@0
|
729 accessibility.speak("There are no arrow heads defined for "+edge);
|
fiore@1
|
730 ILogger.logError("There are no arrow heads defined for "+edge);
|
fiore@0
|
731 return;
|
fiore@0
|
732 }
|
fiore@0
|
733 dialogBuilder.displaySelectionDialog(EDIT_ARROWHEAD_DIALOG_TAG, heads, this);
|
fiore@0
|
734 }
|
fiore@0
|
735 }else if(EDIT_LABEL_DIALOG_TAG.equals(dialogTag)){
|
fiore@0
|
736 EditText editText = (EditText)dialogFragment.getDialog().findViewById(R.id.text_edit);
|
fiore@0
|
737 String text = editText.getText().toString().trim();
|
fiore@0
|
738 if(text.length() == 0){
|
fiore@0
|
739 accessibility.playSound(SoundEvent.V_ERROR);
|
fiore@0
|
740 accessibility.speak("Text cannot be empty");
|
fiore@1
|
741 ILogger.logError("Text empty");
|
fiore@0
|
742 return;
|
fiore@0
|
743 }
|
fiore@0
|
744 diagramUpdater.setLabel((EdgeNode)clickedItem,text);
|
fiore@0
|
745 accessibility.playSound(SoundEvent.V_OK);
|
fiore@0
|
746 accessibility.speak("Label set to "+clickedItem);// EdgeNode.toString = EdgeNode.getLabel
|
fiore@1
|
747 ILogger.log("Label set to "+clickedItem);
|
fiore@0
|
748 }else if(EDIT_ARROWHEAD_DIALOG_TAG.equals(dialogTag)){
|
fiore@0
|
749 Spinner spinner = (Spinner)dialogFragment.getDialog().findViewById(R.id.selectionSpinner);
|
fiore@1
|
750 diagramUpdater.setArrowHead((EdgeNode)clickedItem, spinner.getSelectedItem().toString());
|
fiore@0
|
751 accessibility.playSound(SoundEvent.V_OK);
|
fiore@0
|
752 accessibility.speak("Arrow head set to "+spinner.getSelectedItem().toString());
|
fiore@1
|
753 ILogger.log("Arrow head set to "+spinner.getSelectedItem().toString());
|
fiore@0
|
754 }else if(EDIT_PROPERTY_DIALOG_TAG.equals(dialogTag)){
|
fiore@0
|
755 if("RENAME".equals(buttonTag)){
|
fiore@0
|
756 dialogFragment.dismiss();
|
fiore@0
|
757 dialogBuilder.displayDialog(R.layout.alert_dialog_rename, RENAME_DIALOG_TAG, this);
|
fiore@0
|
758 }else if("DELETE".equals(buttonTag)){
|
fiore@0
|
759 dialogFragment.dismiss();
|
fiore@0
|
760 dialogBuilder.displayDialog(R.layout.alert_dialog_confirmation,
|
fiore@0
|
761 CONFIRMATION_DIALOG_TAG+ " property "+clickedItem,
|
fiore@0
|
762 this);
|
fiore@0
|
763 }else if("MODIFIERS".equals(buttonTag)){
|
fiore@0
|
764 dialogFragment.dismiss();
|
fiore@0
|
765 /* get the modifiers from the NodePropertyType of the node where this property is */
|
fiore@0
|
766 NodeProperty property = (NodeProperty)path.current();
|
fiore@0
|
767 String[] modifiers = null;
|
fiore@0
|
768 boolean[] checks = null;
|
fiore@0
|
769 for( NodePropertyType propertyType : ((NodeType)path.get(TYPE_LEVEL)).getPropretyTypes()){
|
fiore@0
|
770 if(propertyType.getType().equals(property.getType())){
|
fiore@0
|
771 modifiers = new String[propertyType.getModifiers().size()];
|
fiore@0
|
772 checks = new boolean[modifiers.length];
|
fiore@0
|
773 for(int i=0; i< modifiers.length; i++){
|
fiore@0
|
774 modifiers[i] = propertyType.getModifiers().get(i).getType();
|
fiore@0
|
775 if(((PropertyValue)clickedItem).getModifiersIndexes().contains(i))
|
fiore@0
|
776 checks[i] = true;
|
fiore@0
|
777 }
|
fiore@0
|
778 }
|
fiore@0
|
779 }
|
fiore@0
|
780 if(modifiers == null || modifiers.length == 0){
|
fiore@0
|
781 accessibility.playSound(SoundEvent.V_ERROR);
|
fiore@0
|
782 accessibility.speak("There are no modifiers defined for "+property);
|
fiore@0
|
783 return;
|
fiore@0
|
784 }
|
fiore@0
|
785 dialogBuilder.displayCheckDialog(EDIT_MODIFIERS_DIALOG_TAG, modifiers, checks, this);
|
fiore@0
|
786 }
|
fiore@0
|
787 }else if(EDIT_MODIFIERS_DIALOG_TAG.equals(dialogTag)){
|
fiore@0
|
788 /* pressed button is OK as CANCEL would have been cought at the beginning */
|
fiore@0
|
789 AccessibleCheckbox checkbox = (AccessibleCheckbox)dialogFragment.getDialog().findViewById(R.id.checkBox);
|
fiore@0
|
790 boolean[] checks = checkbox.getChecks();
|
fiore@0
|
791 List<Integer> modifiers = new ArrayList<Integer>(checks.length);
|
fiore@1
|
792 StringBuilder modifiersString = new StringBuilder();
|
fiore@0
|
793 for(int i=0; i<checks.length; i++){
|
fiore@1
|
794 if(checks[i]){
|
fiore@0
|
795 modifiers.add(i);
|
fiore@1
|
796 modifiersString.append(i).append(' ');
|
fiore@1
|
797 }
|
fiore@0
|
798 }
|
fiore@0
|
799 diagramUpdater.setModifiers((PropertyValue)clickedItem, modifiers);
|
fiore@1
|
800 accessibility.playSound(SoundEvent.V_OK);
|
fiore@1
|
801 accessibility.speak("modifiers set for "+path.current());
|
fiore@1
|
802 if(modifiersString.length() == 0)
|
fiore@1
|
803 modifiersString.append("no modifiers");
|
fiore@1
|
804 ILogger.log("modifiers set for "+path.current()+": "+ modifiersString.toString());
|
fiore@0
|
805 }
|
fiore@0
|
806 /* update the view */
|
fiore@0
|
807 cachedList = buildCurrentChildList();
|
fiore@0
|
808 updateable.update();
|
fiore@0
|
809 dialogFragment.dismiss();
|
fiore@0
|
810 }
|
fiore@0
|
811 }
|
fiore@0
|
812
|
fiore@0
|
813 /**
|
fiore@0
|
814 *
|
fiore@0
|
815 * Simple interface to provide an update method
|
fiore@0
|
816 *
|
fiore@0
|
817 */
|
fiore@0
|
818 interface Updateable {
|
fiore@0
|
819 /**
|
fiore@0
|
820 * performs an update
|
fiore@0
|
821 */
|
fiore@0
|
822 public void update();
|
fiore@0
|
823 }
|
fiore@0
|
824 }
|