f@0
|
1 /*
|
f@0
|
2 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
|
f@0
|
3
|
f@0
|
4 Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
|
f@0
|
5
|
f@0
|
6 This program is free software: you can redistribute it and/or modify
|
f@0
|
7 it under the terms of the GNU General Public License as published by
|
f@0
|
8 the Free Software Foundation, either version 3 of the License, or
|
f@0
|
9 (at your option) any later version.
|
f@0
|
10
|
f@0
|
11 This program is distributed in the hope that it will be useful,
|
f@0
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
f@0
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
f@0
|
14 GNU General Public License for more details.
|
f@0
|
15
|
f@0
|
16 You should have received a copy of the GNU General Public License
|
f@0
|
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
f@0
|
18 */
|
f@0
|
19
|
f@0
|
20 package uk.ac.qmul.eecs.ccmi.simpletemplate;
|
f@0
|
21
|
f@0
|
22 import java.awt.Component;
|
f@0
|
23 import java.awt.Dimension;
|
f@0
|
24 import java.awt.FlowLayout;
|
f@0
|
25 import java.awt.Frame;
|
f@0
|
26 import java.awt.GridBagLayout;
|
f@0
|
27 import java.awt.GridLayout;
|
f@0
|
28 import java.awt.event.ActionEvent;
|
f@0
|
29 import java.awt.event.KeyEvent;
|
f@0
|
30 import java.io.IOException;
|
f@0
|
31 import java.text.MessageFormat;
|
f@0
|
32 import java.util.ArrayList;
|
f@0
|
33 import java.util.Arrays;
|
f@0
|
34 import java.util.Collection;
|
f@0
|
35 import java.util.LinkedHashMap;
|
f@0
|
36 import java.util.LinkedHashSet;
|
f@0
|
37 import java.util.ResourceBundle;
|
f@0
|
38 import java.util.Set;
|
f@0
|
39
|
f@0
|
40 import javax.swing.AbstractAction;
|
f@0
|
41 import javax.swing.DefaultComboBoxModel;
|
f@0
|
42 import javax.swing.JCheckBox;
|
f@0
|
43 import javax.swing.JComboBox;
|
f@0
|
44 import javax.swing.JComponent;
|
f@0
|
45 import javax.swing.JPanel;
|
f@0
|
46 import javax.swing.JScrollPane;
|
f@0
|
47 import javax.swing.JTextField;
|
f@0
|
48 import javax.swing.KeyStroke;
|
f@0
|
49 import javax.swing.SpinnerModel;
|
f@0
|
50
|
f@0
|
51 import jwizardcomponent.FinishAction;
|
f@0
|
52 import jwizardcomponent.JWizardComponents;
|
f@0
|
53 import jwizardcomponent.JWizardPanel;
|
f@0
|
54 import uk.ac.qmul.eecs.ccmi.diagrammodel.NodeProperties;
|
f@0
|
55 import uk.ac.qmul.eecs.ccmi.diagrammodel.NodeProperties.Modifiers;
|
f@0
|
56 import uk.ac.qmul.eecs.ccmi.gui.Diagram;
|
f@0
|
57 import uk.ac.qmul.eecs.ccmi.gui.Edge;
|
f@0
|
58 import uk.ac.qmul.eecs.ccmi.gui.LineStyle;
|
f@0
|
59 import uk.ac.qmul.eecs.ccmi.gui.LoopComboBox;
|
f@0
|
60 import uk.ac.qmul.eecs.ccmi.gui.LoopSpinnerNumberModel;
|
f@0
|
61 import uk.ac.qmul.eecs.ccmi.gui.Node;
|
f@0
|
62 import uk.ac.qmul.eecs.ccmi.gui.SpeechSummaryPane;
|
f@0
|
63 import uk.ac.qmul.eecs.ccmi.simpletemplate.SimpleShapeNode.ShapeType;
|
f@0
|
64 import uk.ac.qmul.eecs.ccmi.sound.SoundEvent;
|
f@0
|
65 import uk.ac.qmul.eecs.ccmi.sound.SoundFactory;
|
f@0
|
66 import uk.ac.qmul.eecs.ccmi.speech.NarratorFactory;
|
f@0
|
67 import uk.ac.qmul.eecs.ccmi.speech.SpeechUtilities;
|
f@0
|
68 import uk.ac.qmul.eecs.ccmi.utils.GridBagUtilities;
|
f@0
|
69
|
f@0
|
70 /**
|
f@0
|
71 *
|
f@0
|
72 * A Wizard-like sequence of screens prompted to the user to let they input (e.g. which shape a node will have or how many nodes an edge can connect at most)
|
f@0
|
73 * how to build a template diagram. A template diagram is a prototype diagram
|
f@0
|
74 * (containing prototype nodes and edges) which can later on be used for creating instances
|
f@0
|
75 * of that type of diagram through clonation. The wizard is completely accessible via audio
|
f@0
|
76 * as all the content and all focused components names are spoken out by the {@code Narrator} through a text to speech synthesizer.
|
f@0
|
77 *
|
f@0
|
78 */
|
f@0
|
79 public class Wizard {
|
f@0
|
80 public Wizard(Frame frame, Collection<String> existingDiagrams, Diagram diagramToEdit){
|
f@0
|
81 dialog = new SpeechWizardDialog(frame);
|
f@0
|
82 resources = ResourceBundle.getBundle(SpeechWizardDialog.class.getName());
|
f@0
|
83
|
f@0
|
84 model = createModel(diagramToEdit);
|
f@0
|
85 node = new Model.Node();
|
f@0
|
86 edge = new Model.Edge();
|
f@0
|
87 property = new Model.Property();
|
f@0
|
88 modifier = new Model.Modifier();
|
f@0
|
89
|
f@0
|
90 initWizardComponents(existingDiagrams,diagramToEdit);
|
f@0
|
91
|
f@0
|
92 /* if the user is editing from an existing diagram, they have to choose a new name. They're switched *
|
f@0
|
93 * directly to the diagram name panel so they have to enter a new name as they would otherwise *
|
f@0
|
94 * not be allowed to proceed. */
|
f@0
|
95 if(diagramToEdit != null)
|
f@0
|
96 dialog.getWizardComponents().setCurrentIndex(DIAGRAM_NAME);
|
f@0
|
97
|
f@0
|
98 /* when the user clicks on the finish button they'll be prompted with a summary text area dialog *
|
f@0
|
99 * describing what they have created so far and asking for a confirmation to proceed with the actual *
|
f@0
|
100 * creation of the template. */
|
f@0
|
101 dialog.getWizardComponents().setFinishAction(new FinishAction(dialog.getWizardComponents()){
|
f@0
|
102 @Override
|
f@0
|
103 public void performAction(){
|
f@0
|
104 String[] options = {
|
f@0
|
105 resources.getString("dialog.summary.ok_button_label"),
|
f@0
|
106 resources.getString("dialog.summary.cancel_button_label")};
|
f@0
|
107 int result = SpeechSummaryPane.showDialog(
|
f@0
|
108 dialog,
|
f@0
|
109 resources.getString("dialog.summary.title"),
|
f@0
|
110 model.toString(),
|
f@0
|
111 SpeechSummaryPane.OK_CANCEL_OPTION,
|
f@0
|
112 options);
|
f@0
|
113
|
f@0
|
114 if(result == SpeechSummaryPane.CANCEL){ // user wants to continue editing
|
f@0
|
115 /* null arg will avoid default playerListener which speaks out the focused component */
|
f@0
|
116 SoundFactory.getInstance().play(SoundEvent.CANCEL,null);
|
f@0
|
117 return;
|
f@0
|
118 }
|
f@0
|
119 /* create the actual diagram (it will be return to the client class by execute()) */
|
f@0
|
120 diagram = createDiagram(model);
|
f@0
|
121 dialog.dispose();
|
f@0
|
122 }
|
f@0
|
123 });
|
f@0
|
124 }
|
f@0
|
125
|
f@0
|
126 public Wizard(Frame frame, Collection<String> existingDiagrams){
|
f@0
|
127 this(frame,existingDiagrams,null);
|
f@0
|
128 }
|
f@0
|
129
|
f@0
|
130 public Diagram execute(){
|
f@0
|
131 diagram = null;
|
f@0
|
132 dialog.show();
|
f@0
|
133 if(diagram == null)
|
f@0
|
134 SoundFactory.getInstance().play(SoundEvent.CANCEL);
|
f@0
|
135 return diagram;
|
f@0
|
136 }
|
f@0
|
137
|
f@0
|
138 @SuppressWarnings("serial")
|
f@0
|
139 private void initWizardComponents(Collection<String> existingDiagrams, final Diagram diagramToEdit){
|
f@0
|
140 /* --- MAIN PANEL --- */
|
f@0
|
141 String[] choices = {
|
f@0
|
142 resources.getString("panel.home.choice.diagram_name"),
|
f@0
|
143 resources.getString("panel.home.choice.nodes"),
|
f@0
|
144 resources.getString("panel.home.choice.edges"),
|
f@0
|
145 };
|
f@0
|
146 int[] nexts = {DIAGRAM_NAME,NODES,EDGES};
|
f@0
|
147
|
f@0
|
148 /* panel for the selection of main tasks when creating the diagram: enter diagram name, create node and *
|
f@0
|
149 * create edge. When a name is assigned an item is added to the selection which allows the user to finish *
|
f@0
|
150 * the template creation, much as they would do by pressing the finish button. If the user edits an existing *
|
f@0
|
151 * diagram they're prompted with a message to enter a new diagram name (as there cannot be two diagrams *
|
f@0
|
152 * with the same name. When the user enters the name the message goes away */
|
f@0
|
153 add(HOME,new SelectWizardPanel(
|
f@0
|
154 dialog.getWizardComponents(),
|
f@0
|
155 resources.getString("panel.home.title.new"),
|
f@0
|
156 Arrays.asList(choices),
|
f@0
|
157 nexts,
|
f@0
|
158 SpeechWizardPanel.DISABLE_SWITCH
|
f@0
|
159 ){
|
f@0
|
160 @Override
|
f@0
|
161 public void update(){
|
f@0
|
162 if(!model.diagramName.value.isEmpty()){
|
f@0
|
163 dialog.setFinishButtonEnabled(true);
|
f@0
|
164 /* if the diagram has a name the template creation can finish. So add a selection item to the *
|
f@0
|
165 * comboBox unless it's already there from a previous update (item count < 4 ) */
|
f@0
|
166 if(comboBox.getItemCount() < 4)
|
f@0
|
167 ((DefaultComboBoxModel)comboBox.getModel()).addElement(resources.getString("panel.home.choice.finish"));
|
f@0
|
168 }
|
f@0
|
169 super.update();
|
f@0
|
170 }
|
f@0
|
171 @Override
|
f@0
|
172 public void next(){
|
f@0
|
173 if(comboBox.getSelectedIndex() == 3)
|
f@0
|
174 dialog.getWizardComponents().getFinishButton().doClick();
|
f@0
|
175 else
|
f@0
|
176 super.next();
|
f@0
|
177 }
|
f@0
|
178 });
|
f@0
|
179
|
f@0
|
180 /* --- DIAGRAM NAME INPUT PANEL --- */
|
f@0
|
181 add(DIAGRAM_NAME, new TextWizardPanel(
|
f@0
|
182 dialog.getWizardComponents(),
|
f@0
|
183 resources.getString(diagramToEdit == null ? "panel.diagram_name.title" : "panel.diagram_name.title.editing_existing_diagram"),
|
f@0
|
184 existingDiagrams,
|
f@0
|
185 HOME,
|
f@0
|
186 HOME,
|
f@0
|
187 model.diagramName
|
f@0
|
188 ){
|
f@0
|
189 @Override
|
f@0
|
190 public void update(){
|
f@0
|
191 /* this is a little nasty trick to achieve the following: when the user creates a new diagram out of an already existing
|
f@0
|
192 * one they're directly prompted with this panel. We want the name of the diagram to be there for awareness
|
f@0
|
193 * but at the same time it must not be accepted by the program as it would otherwise clash with
|
f@0
|
194 * with the starting diagam's. As the program accepts it when the text entered in the text field is equal to
|
f@0
|
195 * model.diagramName.value (for when the user wants to re-edit the name of a diagram they're creating) we must
|
f@0
|
196 * fill model.DiagramName.value with the name of the starting diagram to get it shown and spoken out but then
|
f@0
|
197 * it's assigned the empty string not to let the user to go forward */
|
f@0
|
198 if(diagramToEdit != null && model.diagramName.value.isEmpty()){
|
f@0
|
199 model.diagramName.value = diagramToEdit.getName();
|
f@0
|
200 super.update();
|
f@0
|
201 model.diagramName.value = "";
|
f@0
|
202 }else{
|
f@0
|
203 super.update();
|
f@0
|
204 }
|
f@0
|
205 }
|
f@0
|
206 });
|
f@0
|
207
|
f@0
|
208 /* --- NODE ACTION SELECTION PANEL --- */
|
f@0
|
209 /* decide whether to add a new node or to edit/delete an existing node */
|
f@0
|
210 String[] nodeOptions = {
|
f@0
|
211 resources.getString("panel.nodes.actions.add"),
|
f@0
|
212 resources.getString("panel.nodes.actions.edit"),
|
f@0
|
213 resources.getString("panel.nodes.actions.del"),
|
f@0
|
214 resources.getString("panel.nodes.actions.finish")};
|
f@0
|
215 int[] nodeNexts = {NODE_TYPE,NODE_EDIT,NODE_DEL,HOME};
|
f@0
|
216 add(NODES, new ActionChooserPanel(
|
f@0
|
217 dialog.getWizardComponents(),
|
f@0
|
218 model.nodes.getNames(),
|
f@0
|
219 resources.getString("panel.nodes.title"),
|
f@0
|
220 nodeOptions,
|
f@0
|
221 nodeNexts,
|
f@0
|
222 HOME,
|
f@0
|
223 node
|
f@0
|
224 ));
|
f@0
|
225
|
f@0
|
226 /* --- NODE TYPE NAME INPUT PANEL --- */
|
f@0
|
227 add(NODE_TYPE,new TextWizardPanel(
|
f@0
|
228 dialog.getWizardComponents(),
|
f@0
|
229 resources.getString("panel.node_name.title"),
|
f@0
|
230 model.nodes.getNames(),
|
f@0
|
231 NODE_SHAPE,
|
f@0
|
232 NODES,
|
f@0
|
233 node.type
|
f@0
|
234 ));
|
f@0
|
235
|
f@0
|
236 /* --- NODE TO DELETE SELECTION PANEL*/
|
f@0
|
237 add(NODE_DEL, new DeletePanel(
|
f@0
|
238 dialog.getWizardComponents(),
|
f@0
|
239 resources.getString("panel.node_del.title"),
|
f@0
|
240 NODES,
|
f@0
|
241 NODES,
|
f@0
|
242 model.nodes));
|
f@0
|
243
|
f@0
|
244 /* -- NODE TO EDIT SELECTION PANEL */
|
f@0
|
245 add(NODE_EDIT, new EditPanel(
|
f@0
|
246 dialog.getWizardComponents(),
|
f@0
|
247 resources.getString("panel.node_edit.title"),
|
f@0
|
248 NODE_TYPE,
|
f@0
|
249 NODES,
|
f@0
|
250 model.nodes,
|
f@0
|
251 node
|
f@0
|
252 ));
|
f@0
|
253
|
f@0
|
254 ShapeType[] shapeTypes = ShapeType.values();
|
f@0
|
255 ArrayList<String> shapeTypeNames = new ArrayList<String>(shapeTypes.length);
|
f@0
|
256 for(int i=0; i<shapeTypes.length;i++)
|
f@0
|
257 if(shapeTypes[i] != ShapeType.Transparent)
|
f@0
|
258 shapeTypeNames.add(shapeTypes[i].toString());
|
f@0
|
259
|
f@0
|
260 /* -- NODE SHAPE SELECTION PANEL --- */
|
f@0
|
261 add(NODE_SHAPE, new SelectWizardPanel(
|
f@0
|
262 dialog.getWizardComponents(),
|
f@0
|
263 resources.getString("panel.node_shape.title"),
|
f@0
|
264 shapeTypeNames,
|
f@0
|
265 NODE_YESNO_PROPERTIES,
|
f@0
|
266 NODE_TYPE,
|
f@0
|
267 node.shape
|
f@0
|
268 ));
|
f@0
|
269
|
f@0
|
270 /* --- SELECT WHETHER THE THE NODE HAS TO HAVE PROPERTIES --- */
|
f@0
|
271 String[] yesnoPropertyOptions = {
|
f@0
|
272 resources.getString("panel.yesno_properties.add"),
|
f@0
|
273 resources.getString("panel.yesno_properties.finish")
|
f@0
|
274 };
|
f@0
|
275 int[] yesnoPropertyNexts = {PROPERTIES,NODES};
|
f@0
|
276
|
f@0
|
277 add(NODE_YESNO_PROPERTIES,new SelectWizardPanel(
|
f@0
|
278 dialog.getWizardComponents(),
|
f@0
|
279 resources.getString("panel.yesno_properties.title"),
|
f@0
|
280 Arrays.asList(yesnoPropertyOptions),
|
f@0
|
281 yesnoPropertyNexts,
|
f@0
|
282 NODE_SHAPE
|
f@0
|
283 ){
|
f@0
|
284 @Override
|
f@0
|
285 public void next(){
|
f@0
|
286 if(comboBox.getSelectedIndex() == 1){
|
f@0
|
287 Model.Node newNode = new Model.Node();
|
f@0
|
288 Model.copy(node, newNode);
|
f@0
|
289 model.nodes.put(newNode.id,newNode);
|
f@0
|
290 }
|
f@0
|
291 super.next();
|
f@0
|
292 }
|
f@0
|
293 });
|
f@0
|
294
|
f@0
|
295 /* --- PROPERTIES ACTION SELECTION PANEL --- */
|
f@0
|
296 String[] propertyOptions = {
|
f@0
|
297 resources.getString("panel.properties.actions.add"),
|
f@0
|
298 resources.getString("panel.properties.actions.edit"),
|
f@0
|
299 resources.getString("panel.properties.actions.del"),
|
f@0
|
300 resources.getString("panel.properties.action.finish")};
|
f@0
|
301 int[] propertyNexts = {PROPERTY_TYPE,PROPERTY_EDIT,PROPERTY_DEL,NODES};
|
f@0
|
302
|
f@0
|
303 add(PROPERTIES, new ActionChooserPanel(
|
f@0
|
304 dialog.getWizardComponents(),
|
f@0
|
305 node.properties.getNames(),
|
f@0
|
306 resources.getString("panel.properties.title"),
|
f@0
|
307 propertyOptions,
|
f@0
|
308 propertyNexts,
|
f@0
|
309 NODE_SHAPE,
|
f@0
|
310 property
|
f@0
|
311 ){
|
f@0
|
312 @Override
|
f@0
|
313 public void next(){
|
f@0
|
314 /* if the user selects finish, create a new node put in it the values of */
|
f@0
|
315 /* the temporary property and store it in the model */
|
f@0
|
316 if( (comboBox.getSelectedIndex() == 1 && comboBox.getItemCount() == 2)||
|
f@0
|
317 (comboBox.getSelectedIndex() == 3 && comboBox.getItemCount() == 4)){
|
f@0
|
318 Model.Node newNode = new Model.Node();
|
f@0
|
319 Model.copy(node, newNode);
|
f@0
|
320 model.nodes.put(newNode.id,newNode);
|
f@0
|
321 }
|
f@0
|
322 super.next();
|
f@0
|
323 }
|
f@0
|
324 });
|
f@0
|
325
|
f@0
|
326 /* --- PROPERTY TYPE NAME INPUT PANEL --- */
|
f@0
|
327 add(PROPERTY_TYPE,new TextWizardPanel(
|
f@0
|
328 dialog.getWizardComponents(),
|
f@0
|
329 resources.getString("panel.property_name.title"),
|
f@0
|
330 node.properties.getNames(),
|
f@0
|
331 PROPERTY_POSITION,
|
f@0
|
332 PROPERTIES,
|
f@0
|
333 property.type
|
f@0
|
334 ));
|
f@0
|
335
|
f@0
|
336 /* --- PROPERTY TO DELETE SELECTION PANEL --- */
|
f@0
|
337 add(PROPERTY_DEL, new DeletePanel(
|
f@0
|
338 dialog.getWizardComponents(),
|
f@0
|
339 resources.getString("panel.property_del.title"),
|
f@0
|
340 PROPERTIES,
|
f@0
|
341 PROPERTIES,
|
f@0
|
342 node.properties
|
f@0
|
343 ));
|
f@0
|
344
|
f@0
|
345 /* --- PROPERTY TO EDIT SELECTION PANEL --- */
|
f@0
|
346 add(PROPERTY_EDIT, new EditPanel(
|
f@0
|
347 dialog.getWizardComponents(),
|
f@0
|
348 resources.getString("panel.property_edit.title"),
|
f@0
|
349 PROPERTY_TYPE,
|
f@0
|
350 PROPERTIES,
|
f@0
|
351 node.properties,
|
f@0
|
352 property
|
f@0
|
353 ));
|
f@0
|
354
|
f@0
|
355 /* --- PROPERTY POSITION SELECTION DIALOG --- */
|
f@0
|
356 SimpleShapeNode.Position positions[] = SimpleShapeNode.Position.values();
|
f@0
|
357 ArrayList<String> positionNames = new ArrayList<String>(positions.length);
|
f@0
|
358 for(int i=0; i<positions.length;i++)
|
f@0
|
359 positionNames.add(positions[i].toString());
|
f@0
|
360 int[] positionNexts = {PROPERTY_YESNO_MODIFIER,PROPERTY_SHAPE};
|
f@0
|
361
|
f@0
|
362
|
f@0
|
363 add(PROPERTY_POSITION, new SelectWizardPanel(
|
f@0
|
364 dialog.getWizardComponents(),
|
f@0
|
365 resources.getString("panel.property_position.title"),
|
f@0
|
366 positionNames,
|
f@0
|
367 positionNexts,
|
f@0
|
368 PROPERTY_TYPE,
|
f@0
|
369 property.position
|
f@0
|
370 ));
|
f@0
|
371
|
f@0
|
372 /* --- PROPERTY SHAPE SELECTION DIALOG --- */
|
f@0
|
373 shapeTypeNames.add(ShapeType.Transparent.toString());
|
f@0
|
374 add(PROPERTY_SHAPE, new SelectWizardPanel(
|
f@0
|
375 dialog.getWizardComponents(),
|
f@0
|
376 resources.getString("panel.property_shape.title"),
|
f@0
|
377 shapeTypeNames,
|
f@0
|
378 PROPERTY_YESNO_MODIFIER,
|
f@0
|
379 PROPERTY_POSITION,
|
f@0
|
380 property.shape
|
f@0
|
381 ));
|
f@0
|
382
|
f@0
|
383 /* --- SELECT WHETHER THE THE PROPERTY HAS TO HAVE MODIFIERS --- */
|
f@0
|
384 String[] yesnoModifierOptions = {
|
f@0
|
385 resources.getString("panel.yesno_modifiers.add"),
|
f@0
|
386 resources.getString("panel.yesno_modifiers.finish")
|
f@0
|
387 };
|
f@0
|
388 int[] yesnoModifierNexts = {MODIFIERS,PROPERTIES};
|
f@0
|
389
|
f@0
|
390 add(PROPERTY_YESNO_MODIFIER,new SelectWizardPanel(
|
f@0
|
391 dialog.getWizardComponents(),
|
f@0
|
392 resources.getString("panel.yesno_modifiers.title"),
|
f@0
|
393 Arrays.asList(yesnoModifierOptions),
|
f@0
|
394 yesnoModifierNexts,
|
f@0
|
395 PROPERTY_POSITION
|
f@0
|
396 ){
|
f@0
|
397 @Override
|
f@0
|
398 public void next(){
|
f@0
|
399 if(comboBox.getSelectedIndex() == 1){
|
f@0
|
400 Model.Property newProperty = new Model.Property();
|
f@0
|
401 Model.copy(property, newProperty);
|
f@0
|
402 node.properties.put(newProperty.id,newProperty);
|
f@0
|
403 }
|
f@0
|
404 super.next();
|
f@0
|
405 }
|
f@0
|
406 });
|
f@0
|
407 /* --- MODIFIERS ACTION SELECTION PANE --- */
|
f@0
|
408 String[] modifierOptions = {
|
f@0
|
409 resources.getString("panel.modifiers.actions.add"),
|
f@0
|
410 resources.getString("panel.modifiers.actions.edit"),
|
f@0
|
411 resources.getString("panel.modifiers.actions.del"),
|
f@0
|
412 resources.getString("panel.modifiers.actions.finish")
|
f@0
|
413 };
|
f@0
|
414 int[] modifiersNexts = {MODIFIER_TYPE,MODIFIER_EDIT,MODIFIER_DEL,PROPERTIES};
|
f@0
|
415
|
f@0
|
416 add(MODIFIERS, new ActionChooserPanel(
|
f@0
|
417 dialog.getWizardComponents(),
|
f@0
|
418 property.modifiers.getNames(),
|
f@0
|
419 resources.getString("panel.modifiers.title"),
|
f@0
|
420 modifierOptions,
|
f@0
|
421 modifiersNexts,
|
f@0
|
422 PROPERTY_POSITION,
|
f@0
|
423 modifier){
|
f@0
|
424
|
f@0
|
425 @Override
|
f@0
|
426 public void next(){
|
f@0
|
427 /* if the user selects finish, create a new property put in it the values of */
|
f@0
|
428 /* the temporary property and store it in the model */
|
f@0
|
429 if( (comboBox.getSelectedIndex() == 1 && comboBox.getItemCount() == 2)||
|
f@0
|
430 (comboBox.getSelectedIndex() == 3 && comboBox.getItemCount() == 4)){
|
f@0
|
431 Model.Property newProperty = new Model.Property();
|
f@0
|
432 Model.copy(property, newProperty);
|
f@0
|
433 node.properties.put(newProperty.id,newProperty);
|
f@0
|
434 }
|
f@0
|
435 super.next();
|
f@0
|
436 }
|
f@0
|
437 });
|
f@0
|
438
|
f@0
|
439 /* --- MODIFIER TYPE PANEL --- */
|
f@0
|
440 add(MODIFIER_TYPE, new TextWizardPanel(
|
f@0
|
441 dialog.getWizardComponents(),
|
f@0
|
442 resources.getString("panel.modifier_type.title"),
|
f@0
|
443 property.modifiers.getNames(),
|
f@0
|
444 MODIFIER_FORMAT,
|
f@0
|
445 MODIFIERS,
|
f@0
|
446 modifier.type
|
f@0
|
447 ));
|
f@0
|
448
|
f@0
|
449 add(MODIFIER_DEL, new DeletePanel(
|
f@0
|
450 dialog.getWizardComponents(),
|
f@0
|
451 resources.getString("panel.modifier_del.title"),
|
f@0
|
452 MODIFIERS,
|
f@0
|
453 MODIFIERS,
|
f@0
|
454 property.modifiers));
|
f@0
|
455
|
f@0
|
456 add(MODIFIER_EDIT, new EditPanel(
|
f@0
|
457 dialog.getWizardComponents(),
|
f@0
|
458 resources.getString("panel.modifier_edit.title"),
|
f@0
|
459 MODIFIER_TYPE,
|
f@0
|
460 MODIFIERS,
|
f@0
|
461 property.modifiers,
|
f@0
|
462 modifier
|
f@0
|
463 ));
|
f@0
|
464
|
f@0
|
465 add(MODIFIER_FORMAT, new FormatWizardPanel());
|
f@0
|
466 /* --- EDGE ACTION SELECTION PANEL --- */
|
f@0
|
467 /* decide whether to add a new edge or to edit/delete an existing edge */
|
f@0
|
468 String[] edgeOptions = {
|
f@0
|
469 resources.getString("panel.edges.actions.add"),
|
f@0
|
470 resources.getString("panel.edges.actions.edit"),
|
f@0
|
471 resources.getString("panel.edges.actions.del"),
|
f@0
|
472 resources.getString("panel.edges.actions.finish")};
|
f@0
|
473 int[] edgeNexts = {EDGE_TYPE,EDGE_EDIT,EDGE_DEL,HOME};
|
f@0
|
474 add(EDGES, new ActionChooserPanel(
|
f@0
|
475 dialog.getWizardComponents(),
|
f@0
|
476 model.edges.getNames(),
|
f@0
|
477 resources.getString("panel.edges.title"),
|
f@0
|
478 edgeOptions,
|
f@0
|
479 edgeNexts,
|
f@0
|
480 HOME,
|
f@0
|
481 edge
|
f@0
|
482 ));
|
f@0
|
483
|
f@0
|
484 /* --- EDGE TYPE NAME INPUT PANEL --- */
|
f@0
|
485 add(EDGE_TYPE,new TextWizardPanel(
|
f@0
|
486 dialog.getWizardComponents(),
|
f@0
|
487 resources.getString("panel.edge_name.title"),
|
f@0
|
488 model.edges.getNames(),
|
f@0
|
489 EDGE_LINE_STYLE,
|
f@0
|
490 EDGES,
|
f@0
|
491 edge.type
|
f@0
|
492 ));
|
f@0
|
493
|
f@0
|
494 /* --- EDGE TO DELETE SELECTION PANEL --- */
|
f@0
|
495 add(EDGE_DEL, new DeletePanel(
|
f@0
|
496 dialog.getWizardComponents(),
|
f@0
|
497 resources.getString("panel.edge_del.title"),
|
f@0
|
498 EDGES,
|
f@0
|
499 EDGES,
|
f@0
|
500 model.edges));
|
f@0
|
501
|
f@0
|
502 /* --- EDGE TO EDIT SELECTION PANEL --- */
|
f@0
|
503 add(EDGE_EDIT, new EditPanel(
|
f@0
|
504 dialog.getWizardComponents(),
|
f@0
|
505 resources.getString("panel.edge_edit.title"),
|
f@0
|
506 EDGE_TYPE,
|
f@0
|
507 EDGES,
|
f@0
|
508 model.edges,
|
f@0
|
509 edge
|
f@0
|
510 ));
|
f@0
|
511
|
f@0
|
512 /* --- LINE STYLE SELECTION PANEL --- */
|
f@0
|
513 LineStyle[] lineStyles = LineStyle.values();
|
f@0
|
514 String[] lineStyleNames = new String[lineStyles.length];
|
f@0
|
515 for(int i=0; i<lineStyles.length;i++)
|
f@0
|
516 lineStyleNames[i] = lineStyles[i].toString();
|
f@0
|
517
|
f@0
|
518 add(EDGE_LINE_STYLE, new SelectWizardPanel(
|
f@0
|
519 dialog.getWizardComponents(),
|
f@0
|
520 resources.getString("panel.edge_linestyle.title"),
|
f@0
|
521 Arrays.asList(lineStyleNames),
|
f@0
|
522 EDGE_MIN_NODES,
|
f@0
|
523 EDGE_TYPE,
|
f@0
|
524 edge.lineStyle
|
f@0
|
525 ));
|
f@0
|
526
|
f@0
|
527 /* --- MIN NODES SELECTION PANEL --- */
|
f@0
|
528 SpinnerModel minNodesSpinnerModel = new LoopSpinnerNumberModel(2,2,4);
|
f@0
|
529 add(EDGE_MIN_NODES,new SpinnerWizardPanel(
|
f@0
|
530 dialog.getWizardComponents(),
|
f@0
|
531 resources.getString("panel.edge_min_nodes.title"),
|
f@0
|
532 minNodesSpinnerModel,
|
f@0
|
533 EDGE_MAX_NODES,
|
f@0
|
534 EDGE_LINE_STYLE,
|
f@0
|
535 edge.minNodes
|
f@0
|
536 ));
|
f@0
|
537
|
f@0
|
538 /* --- MAX NODES SELECTION PANEL --- */
|
f@0
|
539 SpinnerModel maxNodesSpinnerModel = new LoopSpinnerNumberModel(2,2,4);
|
f@0
|
540 add(EDGE_MAX_NODES, new SpinnerWizardPanel(
|
f@0
|
541 dialog.getWizardComponents(),
|
f@0
|
542 resources.getString("panel.edge_max_nodes.title"),
|
f@0
|
543 maxNodesSpinnerModel,
|
f@0
|
544 EDGE_YESNO_ARROW_HEAD,
|
f@0
|
545 EDGE_MIN_NODES,
|
f@0
|
546 edge.maxNodes
|
f@0
|
547 ){
|
f@0
|
548 @Override
|
f@0
|
549 public void next(){
|
f@0
|
550 int min = Integer.parseInt(edge.minNodes.value);
|
f@0
|
551 int max = Integer.parseInt(spinner.getValue().toString());
|
f@0
|
552 if(min > max){
|
f@0
|
553 NarratorFactory.getInstance().speak(resources.getString("dialog.error.min_max"));
|
f@0
|
554 }else{
|
f@0
|
555 super.next();
|
f@0
|
556 }
|
f@0
|
557 }
|
f@0
|
558
|
f@0
|
559 });
|
f@0
|
560
|
f@0
|
561 /* --- SELECT WHETHER THE EDGE MUST HAVE ARROW HEADS OR NOT --- */
|
f@0
|
562 String[] arrowHeadOptions = {
|
f@0
|
563 resources.getString("panel.edge_yesno_arrow_head.actions.add"),
|
f@0
|
564 resources.getString("panel.edge_yesno_arrow_head.actions.finish")
|
f@0
|
565 };
|
f@0
|
566 int[] arrowHeadNexts = {EDGE_ARROW_HEAD,EDGES};
|
f@0
|
567 add(EDGE_YESNO_ARROW_HEAD,new SelectWizardPanel(
|
f@0
|
568 dialog.getWizardComponents(),
|
f@0
|
569 resources.getString("panel.edge_yesno_arrow_head.title"),
|
f@0
|
570 Arrays.asList(arrowHeadOptions),
|
f@0
|
571 arrowHeadNexts,
|
f@0
|
572 EDGE_MAX_NODES
|
f@0
|
573 ){
|
f@0
|
574 @Override
|
f@0
|
575 public void next(){
|
f@0
|
576 if(comboBox.getSelectedIndex() == 1){
|
f@0
|
577 Model.Edge newEdge = new Model.Edge();
|
f@0
|
578 Model.copy(edge, newEdge);
|
f@0
|
579 model.edges.put(newEdge.id,newEdge);
|
f@0
|
580 }
|
f@0
|
581 super.next();
|
f@0
|
582 }
|
f@0
|
583 });
|
f@0
|
584
|
f@0
|
585 /* --- ARROW HEAD SELECTION PANEL --- */
|
f@0
|
586 add(EDGE_ARROW_HEAD, new ArrowHeadPanel());
|
f@0
|
587
|
f@0
|
588 add(LAST_PANEL, new DummyWizardPanel(dialog.getWizardComponents()));
|
f@0
|
589
|
f@0
|
590 SpeechUtilities.changeTabListener((JComponent)dialog.getContentPane(), dialog);
|
f@0
|
591 }
|
f@0
|
592
|
f@0
|
593 private void add(int index, JWizardPanel panel){
|
f@0
|
594 dialog.getWizardComponents().addWizardPanel(index,panel);
|
f@0
|
595 }
|
f@0
|
596
|
f@0
|
597 private Diagram createDiagram(Model model){
|
f@0
|
598 /* create the node prototypes */
|
f@0
|
599 Node[] nodes = new Node[model.nodes.size()];
|
f@0
|
600 int i = 0;
|
f@0
|
601 for(Model.Node n : model.nodes.values()){
|
f@0
|
602 nodes[i] = createDiagramNode(n);
|
f@0
|
603 i++;
|
f@0
|
604 }
|
f@0
|
605 /* create the edge prototypes */
|
f@0
|
606 Edge[] edges = new Edge[model.edges.size()];
|
f@0
|
607 i = 0;
|
f@0
|
608 for(Model.Edge e : model.edges.values()){
|
f@0
|
609 edges[i] = createDiagramEdge(e);
|
f@0
|
610 i++;
|
f@0
|
611 }
|
f@0
|
612 return Diagram.newInstance(model.diagramName.value, nodes, edges, new SimpleShapePrototypePersistenceDelegate());
|
f@0
|
613 }
|
f@0
|
614
|
f@0
|
615 private Node createDiagramNode(Model.Node n){
|
f@0
|
616 /* set up the properties */
|
f@0
|
617 LinkedHashMap<String,Set<String>> propertiesTypeDefinition = new LinkedHashMap<String,Set<String>>();
|
f@0
|
618 /* create the property type definition */
|
f@0
|
619 for(Model.Property modelProperty : n.properties.values()){
|
f@0
|
620 Set<String> modifiersTypeDefinition = new LinkedHashSet<String>();
|
f@0
|
621 for(Model.Modifier modifier : modelProperty.modifiers.values())
|
f@0
|
622 modifiersTypeDefinition.add(modifier.type.value);
|
f@0
|
623 propertiesTypeDefinition.put(modelProperty.type.value, modifiersTypeDefinition);
|
f@0
|
624 }
|
f@0
|
625 NodeProperties properties = new NodeProperties(propertiesTypeDefinition);
|
f@0
|
626 /* now that properties object is created attach the views on it */
|
f@0
|
627 for(Model.Property modelProperty : n.properties.values()){
|
f@0
|
628 PropertyView propertyView = new PropertyView(
|
f@0
|
629 SimpleShapeNode.Position.valueOf(modelProperty.position.value),
|
f@0
|
630 modelProperty.shape.value.isEmpty() ?
|
f@0
|
631 /* doesn't really matter as position is inside and shape won't be taken into account */
|
f@0
|
632 SimpleShapeNode.ShapeType.Rectangle :
|
f@0
|
633 SimpleShapeNode.ShapeType.valueOf(modelProperty.shape.value)
|
f@0
|
634 );
|
f@0
|
635 properties.setView(modelProperty.type.value, propertyView);
|
f@0
|
636 /* modifier view */
|
f@0
|
637 for(Model.Modifier modelModifier : modelProperty.modifiers.values()){
|
f@0
|
638 boolean bold = false;
|
f@0
|
639 boolean italic = false;
|
f@0
|
640 boolean underline = false;
|
f@0
|
641 String prefix = "";
|
f@0
|
642 String suffix = "";
|
f@0
|
643 for(String value : modelModifier.format.values){
|
f@0
|
644 if(value.equals(resources.getString("modifier.format.bold"))){
|
f@0
|
645 bold = true;
|
f@0
|
646 }else if(value.equals(resources.getString("modifier.format.underline"))){
|
f@0
|
647 underline = true;
|
f@0
|
648 }else if(value.equals(resources.getString("modifier.format.italic"))){
|
f@0
|
649 italic = true;
|
f@0
|
650 }else if(value.equals(resources.getString("modifier.format.prefix"))){
|
f@0
|
651 prefix = modelModifier.affix.values[PREFIX_INDEX];
|
f@0
|
652 }else if(value.equals(resources.getString("modifier.format.suffix"))){
|
f@0
|
653 suffix = modelModifier.affix.values[SUFFIX_INDEX];
|
f@0
|
654 }
|
f@0
|
655 }
|
f@0
|
656 ModifierView modifierView = new ModifierView(underline,bold,italic,prefix,suffix);
|
f@0
|
657 properties.getModifiers(modelProperty.type.value).setView(modelModifier.type.value, modifierView);
|
f@0
|
658 }
|
f@0
|
659 }
|
f@0
|
660 return SimpleShapeNode.getInstance(
|
f@0
|
661 SimpleShapeNode.ShapeType.valueOf(n.shape.value),
|
f@0
|
662 n.type.value,
|
f@0
|
663 properties);
|
f@0
|
664 }
|
f@0
|
665
|
f@0
|
666 private Edge createDiagramEdge(Model.Edge e){
|
f@0
|
667 /* create the arrow head array out of the string stored in the model */
|
f@0
|
668 ArrowHead[] arrowHeads = new ArrowHead[e.arrowHeads.values.length];
|
f@0
|
669 for(int i=0; i<e.arrowHeads.values.length;i++){
|
f@0
|
670 try {
|
f@0
|
671 arrowHeads[i] = ArrowHead.getArrowHeadFromString(e.arrowHeads.values[i]);
|
f@0
|
672 } catch (IOException ioe) {
|
f@0
|
673 throw new RuntimeException(ioe);// the wizard mustn't allow the user to enter different strings
|
f@0
|
674 }
|
f@0
|
675 }
|
f@0
|
676 return new SimpleShapeEdge(
|
f@0
|
677 e.type.value,
|
f@0
|
678 LineStyle.valueOf(e.lineStyle.value),
|
f@0
|
679 arrowHeads,
|
f@0
|
680 e.arrowHeadsDescriptions.values,
|
f@0
|
681 Integer.parseInt(e.minNodes.value),
|
f@0
|
682 Integer.parseInt(e.maxNodes.value)
|
f@0
|
683 );
|
f@0
|
684 }
|
f@0
|
685
|
f@0
|
686 private Model createModel(Diagram diagram) {
|
f@0
|
687 Model model = new Model();
|
f@0
|
688 if(diagram == null)
|
f@0
|
689 return model;
|
f@0
|
690
|
f@0
|
691 /* the name isn't copied as the user as to find a new one */
|
f@0
|
692 /* model.diagramName.value = diagram.getName();*/
|
f@0
|
693
|
f@0
|
694 /* nodes */
|
f@0
|
695 for(Node n : diagram.getNodePrototypes()){
|
f@0
|
696 if(!(n instanceof SimpleShapeNode))
|
f@0
|
697 continue;
|
f@0
|
698 Model.Node modelNode = createModelNode((SimpleShapeNode)n);
|
f@0
|
699 model.nodes.put(modelNode.id,modelNode);
|
f@0
|
700 }
|
f@0
|
701 /* edges */
|
f@0
|
702 for(Edge e : diagram.getEdgePrototypes()){
|
f@0
|
703 if(!(e instanceof SimpleShapeEdge))
|
f@0
|
704 continue;
|
f@0
|
705 Model.Edge modelEdge = createModelEdge((SimpleShapeEdge)e);
|
f@0
|
706 model.edges.put(modelEdge.id, modelEdge);
|
f@0
|
707 }
|
f@0
|
708 return model;
|
f@0
|
709 }
|
f@0
|
710
|
f@0
|
711 /**
|
f@0
|
712 * fills up the model node object with informations from the real diagram node
|
f@0
|
713 * @param n
|
f@0
|
714 * @return
|
f@0
|
715 */
|
f@0
|
716 private Model.Node createModelNode(SimpleShapeNode n){
|
f@0
|
717 Model.Node modelNode = new Model.Node();
|
f@0
|
718 modelNode.type.value = n.getType();
|
f@0
|
719 modelNode.shape.value = n.getShapeType().toString();
|
f@0
|
720
|
f@0
|
721 NodeProperties properties = n.getProperties();
|
f@0
|
722 for(String propertyType : properties.getTypes()){
|
f@0
|
723 Model.Property modelProperty = new Model.Property();
|
f@0
|
724 modelProperty.type.value = propertyType;
|
f@0
|
725 /* if the view is not a PropertyView or is null then assign a default value */
|
f@0
|
726 /* it should never happen but it's just to keep it safer and more forward compliant */
|
f@0
|
727 if(! (properties.getView(propertyType) instanceof PropertyView)){
|
f@0
|
728 modelProperty.position.value = SimpleShapeNode.Position.Inside.toString();
|
f@0
|
729 }else{
|
f@0
|
730 PropertyView propertyView = (PropertyView)properties.getView(propertyType);
|
f@0
|
731 modelProperty.position.value = propertyView.getPosition().toString();
|
f@0
|
732 modelProperty.shape.value = propertyView.getShapeType().toString();
|
f@0
|
733 }
|
f@0
|
734 Modifiers modifiers = properties.getModifiers(propertyType);
|
f@0
|
735 for(String modifierType : modifiers.getTypes()){
|
f@0
|
736 Model.Modifier modelModifier = new Model.Modifier();
|
f@0
|
737 modelModifier.type.value = modifierType;
|
f@0
|
738 if(modifiers.getView(modifierType) instanceof ModifierView){
|
f@0
|
739 ModifierView modifierView = (ModifierView)modifiers.getView(modifierType);
|
f@0
|
740 /* the string array with the modifier values must be created, so the size must be known before */
|
f@0
|
741 int numModifierValues = 0;
|
f@0
|
742 if(modifierView.isBold())
|
f@0
|
743 numModifierValues++;
|
f@0
|
744 if(modifierView.isItalic())
|
f@0
|
745 numModifierValues++;
|
f@0
|
746 if(modifierView.isUnderline())
|
f@0
|
747 numModifierValues++;
|
f@0
|
748 if(!modifierView.getPrefix().isEmpty())
|
f@0
|
749 numModifierValues++;
|
f@0
|
750 if(!modifierView.getSuffix().isEmpty())
|
f@0
|
751 numModifierValues++;
|
f@0
|
752 /* create the string array and fill it up with values */
|
f@0
|
753 modelModifier.format.values = new String[numModifierValues];
|
f@0
|
754 numModifierValues = 0;
|
f@0
|
755 if(modifierView.isBold())
|
f@0
|
756 modelModifier.format.values[numModifierValues++] = resources.getString("modifier.format.bold");
|
f@0
|
757 if(modifierView.isItalic())
|
f@0
|
758 modelModifier.format.values[numModifierValues++] = resources.getString("modifier.format.italic");
|
f@0
|
759 if(modifierView.isUnderline())
|
f@0
|
760 modelModifier.format.values[numModifierValues++] = resources.getString("modifier.format.underline");
|
f@0
|
761 if(!modifierView.getPrefix().isEmpty()){
|
f@0
|
762 modelModifier.format.values[numModifierValues++] = resources.getString("modifier.format.prefix");
|
f@0
|
763 modelModifier.affix.values[PREFIX_INDEX] = modifierView.getPrefix();
|
f@0
|
764 }
|
f@0
|
765
|
f@0
|
766 if(!modifierView.getSuffix().isEmpty()){
|
f@0
|
767 modelModifier.format.values[numModifierValues++] = resources.getString("modifier.format.suffix");
|
f@0
|
768 modelModifier.affix.values[SUFFIX_INDEX] = modifierView.getSuffix();
|
f@0
|
769 }
|
f@0
|
770 }
|
f@0
|
771 modelProperty.modifiers.put(modelModifier.id, modelModifier);
|
f@0
|
772 }
|
f@0
|
773 modelNode.properties.put(modelProperty.id, modelProperty);
|
f@0
|
774 }
|
f@0
|
775 return modelNode;
|
f@0
|
776 }
|
f@0
|
777
|
f@0
|
778 private Model.Edge createModelEdge(SimpleShapeEdge e){
|
f@0
|
779 Model.Edge modelEdge = new Model.Edge();
|
f@0
|
780 modelEdge.type.value = e.getType();
|
f@0
|
781 modelEdge.lineStyle.value = e.getStyle().toString();
|
f@0
|
782 modelEdge.maxNodes.value = Integer.toString(e.getMaxAttachedNodes());
|
f@0
|
783 modelEdge.minNodes.value = Integer.toString(e.getMinAttachedNodes());
|
f@0
|
784
|
f@0
|
785 /* arrow heads and arrowheads descriptions */
|
f@0
|
786 modelEdge.arrowHeadsDescriptions.values = e.getAvailableEndDescriptions();
|
f@0
|
787 modelEdge.arrowHeads.values = new String[e.getHeads().length];
|
f@0
|
788 for(int i =0; i<e.getHeads().length;i++){
|
f@0
|
789 modelEdge.arrowHeads.values[i] = e.getHeads()[i].toString();
|
f@0
|
790 }
|
f@0
|
791
|
f@0
|
792 return modelEdge;
|
f@0
|
793 }
|
f@0
|
794
|
f@0
|
795 private SpeechWizardDialog dialog;
|
f@0
|
796 private Diagram diagram;
|
f@0
|
797 private ResourceBundle resources;
|
f@0
|
798 private Model model;
|
f@0
|
799 /* these are the temporary variables where the data are stored during the wizard *
|
f@0
|
800 * when a sub task is completed ( node creation, edge creation, property creation)*
|
f@0
|
801 * the data stored in the temporary variables are saved in the model */
|
f@0
|
802 private Model.Node node;
|
f@0
|
803 private Model.Property property;
|
f@0
|
804 private Model.Modifier modifier;
|
f@0
|
805 private Model.Edge edge;
|
f@0
|
806
|
f@0
|
807 static int HOME = 0;
|
f@0
|
808 static int DIAGRAM_NAME = 1;
|
f@0
|
809 static int NODES = 2;
|
f@0
|
810 static int NODE_TYPE = 3;
|
f@0
|
811 static int NODE_DEL = 4;
|
f@0
|
812 static int NODE_EDIT = 5;
|
f@0
|
813 static int NODE_SHAPE = 6;
|
f@0
|
814 static int NODE_YESNO_PROPERTIES = 7;
|
f@0
|
815 static int PROPERTIES = 8;
|
f@0
|
816 static int PROPERTY_TYPE = 9;
|
f@0
|
817 static int PROPERTY_DEL = 10;
|
f@0
|
818 static int PROPERTY_EDIT = 11;
|
f@0
|
819 static int PROPERTY_POSITION = 12;
|
f@0
|
820 static int PROPERTY_SHAPE = 13;
|
f@0
|
821 static int PROPERTY_YESNO_MODIFIER = 14;
|
f@0
|
822 static int MODIFIERS = 15;
|
f@0
|
823 static int MODIFIER_TYPE = 16;
|
f@0
|
824 static int MODIFIER_DEL = 17;
|
f@0
|
825 static int MODIFIER_EDIT = 18;
|
f@0
|
826 static int MODIFIER_FORMAT = 19;
|
f@0
|
827 static int EDGES = 20;
|
f@0
|
828 static int EDGE_TYPE = 21;
|
f@0
|
829 static int EDGE_DEL = 22;
|
f@0
|
830 static int EDGE_EDIT = 23;
|
f@0
|
831 static int EDGE_LINE_STYLE = 24;
|
f@0
|
832 static int EDGE_MIN_NODES = 25;
|
f@0
|
833 static int EDGE_MAX_NODES = 26;
|
f@0
|
834 static int EDGE_YESNO_ARROW_HEAD = 27;
|
f@0
|
835 static int EDGE_ARROW_HEAD = 28;
|
f@0
|
836 static int LAST_PANEL = 29;
|
f@0
|
837
|
f@0
|
838 private static int PREFIX_INDEX = 0;
|
f@0
|
839 private static int SUFFIX_INDEX = 1;
|
f@0
|
840
|
f@0
|
841 /* the abstract class from which the panels for Nodes, edges and Modifiers inherit
|
f@0
|
842 * It displays the actions (add,edit,delete,finish) on a comboBox. if elementNames is empty
|
f@0
|
843 * it means that no element has been created yet and therefore edit and delete actions are disabled
|
f@0
|
844 */
|
f@0
|
845 @SuppressWarnings("serial")
|
f@0
|
846 private static class ActionChooserPanel extends SpeechWizardPanel{
|
f@0
|
847 ActionChooserPanel(JWizardComponents wizardComponents,Collection<String> elementNames, String title, String[] options, int[] nexts, int previous, Model.Element temporaryElement){
|
f@0
|
848 super(wizardComponents,title,OWN_SWITCH, previous);
|
f@0
|
849 this.options = options;
|
f@0
|
850 comboBoxModel = new DefaultComboBoxModel();
|
f@0
|
851 comboBoxModel.addElement(options[0]);
|
f@0
|
852 comboBoxModel.addElement(options[3]);
|
f@0
|
853 comboBox = new LoopComboBox(comboBoxModel);
|
f@0
|
854 comboBox.addItemListener(SpeechUtilities.getSpeechComboBoxItemListener());
|
f@0
|
855 layoutComponents(comboBox);
|
f@0
|
856 this.elementNames = elementNames;
|
f@0
|
857 this.temporaryElement = temporaryElement;
|
f@0
|
858 this.nexts = nexts;
|
f@0
|
859 }
|
f@0
|
860
|
f@0
|
861 @Override
|
f@0
|
862 public void update(){
|
f@0
|
863 if(elementNames.isEmpty() && comboBoxModel.getSize() == 4){
|
f@0
|
864 comboBoxModel.removeElement(options[1]);
|
f@0
|
865 comboBoxModel.removeElement(options[2]);
|
f@0
|
866 }else if(!elementNames.isEmpty() && comboBoxModel.getSize() == 2){
|
f@0
|
867 comboBoxModel.insertElementAt(options[1],1);
|
f@0
|
868 comboBoxModel.insertElementAt(options[2],2);
|
f@0
|
869 }
|
f@0
|
870 super.update();
|
f@0
|
871 }
|
f@0
|
872
|
f@0
|
873 @Override
|
f@0
|
874 public void next(){
|
f@0
|
875 /* if the selection was add element, then we clear the temporary holder */
|
f@0
|
876 if(comboBox.getSelectedIndex() == 0)
|
f@0
|
877 temporaryElement.clear();
|
f@0
|
878 /* jump to the selected next step, works both when it's only add/finish and when it's add/delete/edit/finish */
|
f@0
|
879 for(int i=0; i<options.length; i++)
|
f@0
|
880 if(comboBox.getSelectedItem().equals(options[i])){
|
f@0
|
881 switchPanel(nexts[i]);
|
f@0
|
882 return;
|
f@0
|
883 }
|
f@0
|
884 }
|
f@0
|
885
|
f@0
|
886 JComboBox comboBox;
|
f@0
|
887 Collection<String> elementNames;
|
f@0
|
888 DefaultComboBoxModel comboBoxModel;
|
f@0
|
889 String[] options;
|
f@0
|
890 Model.Element temporaryElement;
|
f@0
|
891 int[] nexts;
|
f@0
|
892 }
|
f@0
|
893
|
f@0
|
894 @SuppressWarnings("serial")
|
f@0
|
895 private static class DeletePanel extends SpeechWizardPanel {
|
f@0
|
896 DeletePanel(JWizardComponents wizardComponents,String title, int next, int previous, ModelMap<? extends Model.Element> elements){
|
f@0
|
897 super(wizardComponents,title,next, previous);
|
f@0
|
898 this.elements = elements;
|
f@0
|
899 comboBox = new LoopComboBox();
|
f@0
|
900 comboBox.addItemListener(SpeechUtilities.getSpeechComboBoxItemListener());
|
f@0
|
901 layoutComponents(comboBox);
|
f@0
|
902 }
|
f@0
|
903
|
f@0
|
904 @Override
|
f@0
|
905 public void update(){
|
f@0
|
906 String[] options = new String[elements.values().size()];
|
f@0
|
907 options = elements.getNames().toArray(options);
|
f@0
|
908 comboBox.setModel(new DefaultComboBoxModel(options));
|
f@0
|
909 super.update();
|
f@0
|
910 }
|
f@0
|
911
|
f@0
|
912 /**
|
f@0
|
913 * the default behaviour is to delete the selected element
|
f@0
|
914 */
|
f@0
|
915 @Override
|
f@0
|
916 public void next(){
|
f@0
|
917 Model.Element elementToDelete = null;
|
f@0
|
918 for(Model.Element element : elements.values()){
|
f@0
|
919 if(element.type.value.equals(comboBox.getSelectedItem())){
|
f@0
|
920 elementToDelete = element;
|
f@0
|
921 break;
|
f@0
|
922 }
|
f@0
|
923 }
|
f@0
|
924 Object o = elements.remove(elementToDelete.id);
|
f@0
|
925 assert(o != null);
|
f@0
|
926 super.next();
|
f@0
|
927 }
|
f@0
|
928
|
f@0
|
929 JComboBox comboBox;
|
f@0
|
930 ModelMap<? extends Model.Element> elements;
|
f@0
|
931 }
|
f@0
|
932
|
f@0
|
933 @SuppressWarnings("serial")
|
f@0
|
934 private static class EditPanel extends DeletePanel {
|
f@0
|
935 EditPanel(JWizardComponents wizardComponents,
|
f@0
|
936 String title,
|
f@0
|
937 int next,
|
f@0
|
938 int previous,
|
f@0
|
939 ModelMap<? extends Model.Element> elements,
|
f@0
|
940 Model.Element temporaryHolder){
|
f@0
|
941 super(wizardComponents, title,next, previous,elements);
|
f@0
|
942 this.temporaryHolder = temporaryHolder;
|
f@0
|
943 this.next = next;
|
f@0
|
944 }
|
f@0
|
945
|
f@0
|
946 @Override
|
f@0
|
947 public void next(){
|
f@0
|
948 Model.Element selected = null;
|
f@0
|
949 for(Model.Element e : elements.values()){
|
f@0
|
950 if(e.type.value.equals(comboBox.getSelectedItem())){
|
f@0
|
951 selected = e;
|
f@0
|
952 break;
|
f@0
|
953 }
|
f@0
|
954 }
|
f@0
|
955
|
f@0
|
956 Model.copy(selected, temporaryHolder);
|
f@0
|
957 switchPanel(next);
|
f@0
|
958 }
|
f@0
|
959
|
f@0
|
960 int next;
|
f@0
|
961 Model.Element temporaryHolder;
|
f@0
|
962 }
|
f@0
|
963
|
f@0
|
964 @SuppressWarnings("serial")
|
f@0
|
965 private class FormatWizardPanel extends SpeechWizardPanel{
|
f@0
|
966 FormatWizardPanel(){
|
f@0
|
967 super(dialog.getWizardComponents(),resources.getString("panel.modifier_format.title"),MODIFIERS,MODIFIER_TYPE);
|
f@0
|
968 String values[] = {
|
f@0
|
969 resources.getString("modifier.format.bold"),
|
f@0
|
970 resources.getString("modifier.format.underline"),
|
f@0
|
971 resources.getString("modifier.format.italic"),
|
f@0
|
972 resources.getString("modifier.format.prefix"),
|
f@0
|
973 resources.getString("modifier.format.suffix"),
|
f@0
|
974 };
|
f@0
|
975
|
f@0
|
976 checkBoxes = new JCheckBox[values.length];
|
f@0
|
977 checkBoxPanel = new JPanel(new GridLayout(0, 1));
|
f@0
|
978 for(int i=0; i<values.length;i++){
|
f@0
|
979 String value = values[i];
|
f@0
|
980 checkBoxes[i] = new JCheckBox(value);
|
f@0
|
981 checkBoxes[i].getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), "enter");
|
f@0
|
982 checkBoxes[i].getActionMap().put("enter", new AbstractAction(){
|
f@0
|
983 @Override
|
f@0
|
984 public void actionPerformed(ActionEvent arg0) {
|
f@0
|
985 getWizardComponents().getNextButton().doClick();
|
f@0
|
986 }
|
f@0
|
987 });
|
f@0
|
988 checkBoxes[i].addItemListener(SpeechUtilities.getCheckBoxSpeechItemListener());
|
f@0
|
989 /* prefix and suffix check boxes must have a JText area for the user to enter the String */
|
f@0
|
990 if(i == 3 || i == 4){
|
f@0
|
991 JPanel panel = new JPanel();
|
f@0
|
992 panel.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
|
f@0
|
993 panel.add(checkBoxes[i]);
|
f@0
|
994 if(i == 3){
|
f@0
|
995 prefixTextField = new JTextField();
|
f@0
|
996 prefixTextField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), "enter");
|
f@0
|
997 prefixTextField.getActionMap().put("enter", new AbstractAction(){
|
f@0
|
998 @Override
|
f@0
|
999 public void actionPerformed(ActionEvent arg0) {
|
f@0
|
1000 getWizardComponents().getNextButton().doClick();
|
f@0
|
1001 }
|
f@0
|
1002 });
|
f@0
|
1003 prefixTextField.getAccessibleContext().setAccessibleName(checkBoxes[i].getText());
|
f@0
|
1004 prefixTextField.setColumns(5);
|
f@0
|
1005 prefixTextField.addKeyListener(SpeechUtilities.getSpeechKeyListener(true));
|
f@0
|
1006 panel.add(prefixTextField);
|
f@0
|
1007 }else{
|
f@0
|
1008 suffixTextField = new JTextField();
|
f@0
|
1009 suffixTextField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), "enter");
|
f@0
|
1010 suffixTextField.getActionMap().put("enter", new AbstractAction(){
|
f@0
|
1011 @Override
|
f@0
|
1012 public void actionPerformed(ActionEvent arg0) {
|
f@0
|
1013 getWizardComponents().getNextButton().doClick();
|
f@0
|
1014 }
|
f@0
|
1015 });
|
f@0
|
1016 suffixTextField.getAccessibleContext().setAccessibleName(checkBoxes[i].getText());
|
f@0
|
1017 suffixTextField.setColumns(5);
|
f@0
|
1018 suffixTextField.addKeyListener(SpeechUtilities.getSpeechKeyListener(true));
|
f@0
|
1019 panel.add(suffixTextField);
|
f@0
|
1020 }
|
f@0
|
1021 checkBoxPanel.add(panel);
|
f@0
|
1022 }else{
|
f@0
|
1023 checkBoxPanel.add(checkBoxes[i]);
|
f@0
|
1024 }
|
f@0
|
1025 }
|
f@0
|
1026 JScrollPane scrollPane = new JScrollPane(checkBoxPanel);
|
f@0
|
1027 scrollPane.setFocusable(false);
|
f@0
|
1028 layoutComponents(scrollPane);
|
f@0
|
1029 dialog.getWizardComponents().getFinishButton().setEnabled(true);
|
f@0
|
1030 }
|
f@0
|
1031
|
f@0
|
1032 /* store the checks into the StrArrayRecord, it doesn't call super.next thus */
|
f@0
|
1033 /* sub classes have to implement call the switch panel on their own */
|
f@0
|
1034 public void next(){
|
f@0
|
1035 int numCheckedBoxes = 0;
|
f@0
|
1036 for(JCheckBox check : checkBoxes){
|
f@0
|
1037 if(check.isSelected())
|
f@0
|
1038 numCheckedBoxes++;
|
f@0
|
1039 }
|
f@0
|
1040 String[] result = new String[numCheckedBoxes];
|
f@0
|
1041 numCheckedBoxes = 0;
|
f@0
|
1042 for(int i=0; i<checkBoxes.length;i++){
|
f@0
|
1043 /* store the text value of the check boxes, if it's the prefix or suffix */
|
f@0
|
1044 /* append the text entered by the user in the text areas */
|
f@0
|
1045 if(checkBoxes[i].isSelected()){
|
f@0
|
1046 String text = checkBoxes[i].getText();
|
f@0
|
1047 if(i == 3)
|
f@0
|
1048 modifier.affix.values[PREFIX_INDEX] = prefixTextField.getText();
|
f@0
|
1049 else if(i == 4)
|
f@0
|
1050 modifier.affix.values[SUFFIX_INDEX] = suffixTextField.getText();
|
f@0
|
1051 result[numCheckedBoxes++] = text;
|
f@0
|
1052 }
|
f@0
|
1053 }
|
f@0
|
1054 modifier.format.values = result;
|
f@0
|
1055 Model.Modifier newModifier = new Model.Modifier();
|
f@0
|
1056 Model.copy(modifier,newModifier);
|
f@0
|
1057 property.modifiers.put(newModifier.id,newModifier);
|
f@0
|
1058 super.next();
|
f@0
|
1059 }
|
f@0
|
1060
|
f@0
|
1061 @Override
|
f@0
|
1062 public void update(){
|
f@0
|
1063 /* set the check boxes and text field according to the modifier.format. so if we are editing an existing *
|
f@0
|
1064 * modifier we find the old values, else if it's a new modifier we find everything blank */
|
f@0
|
1065 if(modifier.format != null){
|
f@0
|
1066 prefixTextField.setText("");
|
f@0
|
1067 suffixTextField.setText("");
|
f@0
|
1068 for(JCheckBox check : checkBoxes){
|
f@0
|
1069 /* temporarily remove the speech Item listener in order to avoid bla bla bla not triggered by user */
|
f@0
|
1070 check.removeItemListener(SpeechUtilities.getCheckBoxSpeechItemListener());
|
f@0
|
1071 check.setSelected(false);
|
f@0
|
1072 for(String checkedValue : modifier.format.values){
|
f@0
|
1073 if(checkedValue.equals(check.getText())){//for bold,italic,underline
|
f@0
|
1074 check.setSelected(true);
|
f@0
|
1075 if(checkedValue.equals(resources.getString("modifier.format.prefix"))){
|
f@0
|
1076 prefixTextField.setText(modifier.affix.values[PREFIX_INDEX]);
|
f@0
|
1077 }else if(checkedValue.equals(resources.getString("modifier.format.suffix"))){
|
f@0
|
1078 suffixTextField.setText(modifier.affix.values[SUFFIX_INDEX]);
|
f@0
|
1079 }
|
f@0
|
1080 break;
|
f@0
|
1081 }
|
f@0
|
1082 }
|
f@0
|
1083 check.addItemListener(SpeechUtilities.getCheckBoxSpeechItemListener());
|
f@0
|
1084 }
|
f@0
|
1085 }
|
f@0
|
1086 super.update();
|
f@0
|
1087 }
|
f@0
|
1088
|
f@0
|
1089 @Override
|
f@0
|
1090 protected Component assignFocus(){
|
f@0
|
1091 /* focus on the first item */
|
f@0
|
1092 checkBoxes[0].requestFocus();
|
f@0
|
1093 return checkBoxes[0];
|
f@0
|
1094 }
|
f@0
|
1095
|
f@0
|
1096 JTextField prefixTextField;
|
f@0
|
1097 JTextField suffixTextField;
|
f@0
|
1098 JPanel checkBoxPanel;
|
f@0
|
1099 JCheckBox checkBoxes[];
|
f@0
|
1100 }
|
f@0
|
1101
|
f@0
|
1102 @SuppressWarnings("serial")
|
f@0
|
1103 private class ArrowHeadPanel extends SpeechWizardPanel {
|
f@0
|
1104 ArrowHeadPanel(){
|
f@0
|
1105 super(dialog.getWizardComponents(),resources.getString("panel.edge_arrow_head.title"),EDGES,EDGE_YESNO_ARROW_HEAD);
|
f@0
|
1106 JPanel panel = new JPanel(new GridBagLayout());
|
f@0
|
1107 final JScrollPane scrollPane = new JScrollPane(panel);
|
f@0
|
1108 scrollPane.setFocusable(false);
|
f@0
|
1109 GridBagUtilities gridBagUtils = new GridBagUtilities();
|
f@0
|
1110 int numArrowHeads = ArrowHead.values().length;
|
f@0
|
1111 arrowsCheckBoxes = new JCheckBox[numArrowHeads];
|
f@0
|
1112 arrowsTextDescriptions = new JTextField[numArrowHeads];
|
f@0
|
1113 for(int i=0; i<numArrowHeads; i++){
|
f@0
|
1114 /* set up the key bindings for all the check boxes and text fields */
|
f@0
|
1115 /* by pressing enter the wizard switches the next panel */
|
f@0
|
1116 arrowsCheckBoxes[i] = new JCheckBox(ArrowHead.values()[i].toString());
|
f@0
|
1117 arrowsCheckBoxes[i].getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), "enter");
|
f@0
|
1118 arrowsCheckBoxes[i].getActionMap().put("enter", new AbstractAction(){
|
f@0
|
1119 @Override
|
f@0
|
1120 public void actionPerformed(ActionEvent arg0) {
|
f@0
|
1121 getWizardComponents().getNextButton().doClick();
|
f@0
|
1122 }
|
f@0
|
1123 });
|
f@0
|
1124 arrowsTextDescriptions[i] = new JTextField();
|
f@0
|
1125 arrowsTextDescriptions[i].getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), "enter");
|
f@0
|
1126 arrowsTextDescriptions[i].getActionMap().put("enter", new AbstractAction(){
|
f@0
|
1127 @Override
|
f@0
|
1128 public void actionPerformed(ActionEvent arg0) {
|
f@0
|
1129 getWizardComponents().getNextButton().doClick();
|
f@0
|
1130 }
|
f@0
|
1131 });
|
f@0
|
1132 /* add the speech to the check boxes */
|
f@0
|
1133 arrowsCheckBoxes[i].addItemListener(SpeechUtilities.getCheckBoxSpeechItemListener());
|
f@0
|
1134
|
f@0
|
1135 arrowsTextDescriptions[i].setPreferredSize(new Dimension(TEXTFIELD_SIZE, arrowsTextDescriptions[i].getPreferredSize().height));
|
f@0
|
1136 arrowsTextDescriptions[i].getAccessibleContext().setAccessibleName(arrowsCheckBoxes[i].getText());
|
f@0
|
1137 arrowsTextDescriptions[i].addKeyListener(SpeechUtilities.getSpeechKeyListener(true));
|
f@0
|
1138 panel.add(arrowsCheckBoxes[i], gridBagUtils.label());
|
f@0
|
1139 panel.add(arrowsTextDescriptions[i],gridBagUtils.field());
|
f@0
|
1140 }
|
f@0
|
1141 layoutComponents(scrollPane);
|
f@0
|
1142 }
|
f@0
|
1143
|
f@0
|
1144 @Override
|
f@0
|
1145 public void update(){
|
f@0
|
1146 /* restore the values (checkbox + text) currently in edge.arrowHeads into the panel components */
|
f@0
|
1147 if(edge.arrowHeads != null){
|
f@0
|
1148 for(int i=0; i<arrowsCheckBoxes.length;i++){
|
f@0
|
1149 arrowsCheckBoxes[i].setSelected(false);
|
f@0
|
1150 arrowsTextDescriptions[i].setText("");
|
f@0
|
1151 for(int j=0; j< edge.arrowHeads.values.length; j++){
|
f@0
|
1152 if(arrowsCheckBoxes[i].getText().equals(edge.arrowHeads.values[j])){
|
f@0
|
1153 arrowsCheckBoxes[i].setSelected(true);
|
f@0
|
1154 arrowsTextDescriptions[i].setText(edge.arrowHeadsDescriptions.values[j]);
|
f@0
|
1155 break;
|
f@0
|
1156 }
|
f@0
|
1157 }
|
f@0
|
1158 }
|
f@0
|
1159 }
|
f@0
|
1160 super.update();
|
f@0
|
1161 }
|
f@0
|
1162 @Override
|
f@0
|
1163 public void next(){
|
f@0
|
1164 /* check that the user has entered a text for all of the selected check boxes */
|
f@0
|
1165 int numChecked = 0;//this is to keep count of the checked boxes, used after the check
|
f@0
|
1166 for(int i=0; i<arrowsCheckBoxes.length;i++){
|
f@0
|
1167 JCheckBox checkBox = arrowsCheckBoxes[i];
|
f@0
|
1168 if(checkBox.isSelected()){
|
f@0
|
1169 numChecked++;
|
f@0
|
1170 /* there cannot be a checked check box without the related textField filled in */
|
f@0
|
1171 if(arrowsTextDescriptions[i].getText().trim().isEmpty()){
|
f@0
|
1172 NarratorFactory.getInstance().speak(
|
f@0
|
1173 MessageFormat.format(
|
f@0
|
1174 resources.getString("dialog.error.empty_desc"),
|
f@0
|
1175 checkBox.getText())
|
f@0
|
1176 );
|
f@0
|
1177 return;
|
f@0
|
1178 }
|
f@0
|
1179 }
|
f@0
|
1180 }
|
f@0
|
1181 /* copy the label of the checked boxes and the text of the JTextField into the edge fields */
|
f@0
|
1182 edge.arrowHeads.values = new String[numChecked];
|
f@0
|
1183 edge.arrowHeadsDescriptions.values = new String[numChecked];
|
f@0
|
1184 numChecked = 0;
|
f@0
|
1185 for(int i=0; i<arrowsCheckBoxes.length;i++){
|
f@0
|
1186 if(arrowsCheckBoxes[i].isSelected()){
|
f@0
|
1187 edge.arrowHeads.values[numChecked] = arrowsCheckBoxes[i].getText();
|
f@0
|
1188 edge.arrowHeadsDescriptions.values[numChecked] = arrowsTextDescriptions[i].getText().trim();
|
f@0
|
1189 numChecked++;
|
f@0
|
1190 }
|
f@0
|
1191 }
|
f@0
|
1192 /* put the edge (copy of) into the model */
|
f@0
|
1193 Model.Edge newEdge = new Model.Edge();
|
f@0
|
1194 Model.copy(edge, newEdge);
|
f@0
|
1195 model.edges.put(newEdge.id,newEdge);
|
f@0
|
1196 super.next();
|
f@0
|
1197 }
|
f@0
|
1198
|
f@0
|
1199 @Override
|
f@0
|
1200 protected Component assignFocus(){
|
f@0
|
1201 /* focus on the first item */
|
f@0
|
1202 arrowsCheckBoxes[0].requestFocus();
|
f@0
|
1203 return arrowsCheckBoxes[0];
|
f@0
|
1204 }
|
f@0
|
1205
|
f@0
|
1206 JCheckBox arrowsCheckBoxes[];
|
f@0
|
1207 JTextField arrowsTextDescriptions[];
|
f@0
|
1208 final int TEXTFIELD_SIZE = 100;
|
f@0
|
1209 }
|
f@0
|
1210 }
|