annotate java/src/uk/ac/qmul/eecs/ccmi/simpletemplate/Wizard.java @ 1:e3935c01cde2 tip

moved license of PdPersistenceManager to the beginning of the file
author Fiore Martin <f.martin@qmul.ac.uk>
date Tue, 08 Jul 2014 19:52:03 +0100
parents 78b7fc5391a2
children
rev   line source
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 }