annotate java/src/uk/ac/qmul/eecs/ccmi/simpletemplate/Wizard.java @ 0:9418ab7b7f3f

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