001package ca.bc.webarts.javaFX; 002 003import javafx.application.Application; 004import javafx.beans.property.*; 005import javafx.beans.value.*; 006import javafx.collections.*; 007import javafx.event.*; 008import javafx.scene.*; 009import javafx.scene.control.*; 010import javafx.scene.layout.*; 011import javafx.stage.Stage; 012 013import java.util.Stack; 014 015/** This class displays a survey using a wizard */ 016public class Survey extends Application 017{ 018 public static void main(String[] args) throws Exception 019 { launch(args); } 020 021 @Override 022 public void start(Stage stage) throws Exception 023 { 024 // configure and display the scene and stage. 025 stage.setScene(new Scene(new SurveyWizard(stage), 400, 250)); 026 stage.show(); 027 } 028} 029 030/** basic wizard infrastructure class */ 031abstract class Wizard extends StackPane 032{ 033 private static final int UNDEFINED = -1; 034 private ObservableList<WizardPage> pages = FXCollections.observableArrayList(); 035 private Stack<Integer> history = new Stack<>(); 036 private int curPageIdx = UNDEFINED; 037 038 Wizard(WizardPage... nodes) 039 { 040 pages.addAll(nodes); 041 navTo(0); 042 setStyle("-fx-padding: 10; -fx-background-color: cornsilk;"); 043 } 044 045 void nextPage() 046 { 047 if (hasNextPage()) 048 { 049 navTo(curPageIdx + 1); 050 } 051 } 052 053 void priorPage() 054 { 055 if (hasPriorPage()) 056 { 057 navTo(history.pop(), false); 058 } 059 } 060 061 boolean hasNextPage() 062 { 063 return (curPageIdx < pages.size() - 1); 064 } 065 066 boolean hasPriorPage() 067 { 068 return !history.isEmpty(); 069 } 070 071 void navTo(int nextPageIdx, boolean pushHistory) 072 { 073 if (nextPageIdx < 0 || nextPageIdx >= pages.size()) 074 { 075 return; 076 } 077 if (curPageIdx != UNDEFINED) 078 { 079 if (pushHistory) 080 { 081 history.push(curPageIdx); 082 } 083 } 084 085 WizardPage nextPage = pages.get(nextPageIdx); 086 curPageIdx = nextPageIdx; 087 getChildren().clear(); 088 getChildren().add(nextPage); 089 nextPage.manageButtons(); 090 } 091 092 void navTo(int nextPageIdx) 093 { 094 navTo(nextPageIdx, true); 095 } 096 097 void navTo(String id) 098 { 099 Node page = lookup("#" + id); 100 if (page != null) 101 { 102 int nextPageIdx = pages.indexOf(page); 103 if (nextPageIdx != UNDEFINED) 104 { 105 navTo(nextPageIdx); 106 } 107 } 108 } 109 110 public void finish() 111 { } 112 public void cancel() 113 { } 114} 115 116/** This class shows a satisfaction survey */ 117class SurveyWizard extends Wizard 118{ 119 Stage owner; 120 public SurveyWizard(Stage owner) 121 { 122 super(new ComplaintsPage(), new MoreInformationPage(), new ThanksPage()); 123 this.owner = owner; 124 } 125 public void finish() 126 { 127 System.out.println("Had complaint? " + SurveyData.instance.hasComplaints.get()); 128 if (SurveyData.instance.hasComplaints.get()) 129 { 130 System.out.println("Complaints: " + (SurveyData.instance.complaints.get().isEmpty() ? "No Details" : "\n" + SurveyData.instance.complaints.get())); 131 } 132 owner.close(); 133 } 134 public void cancel() 135 { 136 System.out.println("Cancelled"); 137 owner.close(); 138 } 139} 140 141/** Simple placeholder class for the customer entered survey response. */ 142class SurveyData 143{ 144 BooleanProperty hasComplaints = new SimpleBooleanProperty(); 145 StringProperty complaints = new SimpleStringProperty(); 146 static SurveyData instance = new SurveyData(); 147} 148 149 150/** basic wizard page class */ 151abstract class WizardPage extends VBox 152{ 153 Button priorButton = new Button("_Previous"); 154 Button nextButton = new Button("N_ext"); 155 Button cancelButton = new Button("Cancel"); 156 Button finishButton = new Button("_Finish"); 157 158 WizardPage(String title) 159 { 160 getChildren().add(LabelBuilder.create().text(title).style("-fx-font-weight: bold; -fx-padding: 0 0 5 0;").build()); 161 setId(title); 162 setSpacing(5); 163 setStyle("-fx-padding:10; -fx-background-color: honeydew; -fx-border-color: derive(honeydew, -30%); -fx-border-width: 3;"); 164 165 Region spring = new Region(); 166 VBox.setVgrow(spring, Priority.ALWAYS); 167 getChildren().addAll(getContent(), spring, getButtons()); 168 169 priorButton.setOnAction(new EventHandler<ActionEvent>() 170 { 171 @Override 172 public void handle(ActionEvent actionEvent) 173 { 174 priorPage(); 175 } 176 } ); 177 nextButton.setOnAction(new EventHandler<ActionEvent>() 178 { 179 @Override 180 public void handle(ActionEvent actionEvent) 181 { 182 nextPage(); 183 } 184 } ); 185 cancelButton.setOnAction(new EventHandler<ActionEvent>() 186 { 187 @Override 188 public void handle(ActionEvent actionEvent) 189 { 190 getWizard().cancel(); 191 } 192 } ); 193 finishButton.setOnAction(new EventHandler<ActionEvent>() 194 { 195 @Override 196 public void handle(ActionEvent actionEvent) 197 { 198 getWizard().finish(); 199 } 200 } ); 201 } 202 203 HBox getButtons() 204 { 205 Region spring = new Region(); 206 HBox.setHgrow(spring, Priority.ALWAYS); 207 HBox buttonBar = new HBox(5); 208 cancelButton.setCancelButton(true); 209 finishButton.setDefaultButton(true); 210 buttonBar.getChildren().addAll(spring, priorButton, nextButton, cancelButton, finishButton); 211 return buttonBar; 212 } 213 214 abstract Parent getContent(); 215 216 boolean hasNextPage() 217 { 218 return getWizard().hasNextPage(); 219 } 220 221 boolean hasPriorPage() 222 { 223 return getWizard().hasPriorPage(); 224 } 225 226 void nextPage() 227 { 228 getWizard().nextPage(); 229 } 230 231 void priorPage() 232 { 233 getWizard().priorPage(); 234 } 235 236 void navTo(String id) 237 { 238 getWizard().navTo(id); 239 } 240 241 Wizard getWizard() 242 { 243 return (Wizard) getParent(); 244 } 245 246 public void manageButtons() 247 { 248 if (!hasPriorPage()) 249 { 250 priorButton.setDisable(true); 251 } 252 253 if (!hasNextPage()) 254 { 255 nextButton.setDisable(true); 256 } 257 } 258} 259 260/** 261 * This class determines if the user has complaints. 262 * If not, it jumps to the last page of the wizard. 263 */ 264class ComplaintsPage extends WizardPage 265{ 266 private RadioButton yes; 267 private RadioButton no; 268 private ToggleGroup options = new ToggleGroup(); 269 270 public ComplaintsPage() 271 { 272 super("Complaints"); 273 274 nextButton.setDisable(true); 275 finishButton.setDisable(true); 276 yes.setToggleGroup(options); 277 no.setToggleGroup(options); 278 options.selectedToggleProperty().addListener(new ChangeListener<Toggle>() 279 { @Override 280 public void changed(ObservableValue<? extends Toggle> observableValue, Toggle oldToggle, Toggle newToggle) 281 { 282 nextButton.setDisable(false); 283 finishButton.setDisable(false); 284 } 285 } ); 286 } 287 288 Parent getContent() 289 { 290 yes = new RadioButton("Yes"); 291 no = new RadioButton("No"); 292 SurveyData.instance.hasComplaints.bind(yes.selectedProperty()); 293 return VBoxBuilder.create().spacing(5).children (new Label("Do you have complaints?"), yes, no).build(); 294 } 295 296 void nextPage() 297 { 298 // If they have complaints, go to the normal next page 299 if (options.getSelectedToggle().equals(yes)) 300 { 301 super.nextPage(); 302 } 303 else 304 { 305 // No complaints? Short-circuit the rest of the pages 306 navTo("Thanks"); 307 } 308 } 309} 310 311/** This page gathers more information about the complaint */ 312class MoreInformationPage extends WizardPage 313{ 314 public MoreInformationPage() 315 { 316 super("More Info"); 317 } 318 319 Parent getContent() 320 { 321 TextArea textArea = TextAreaBuilder.create() 322 .wrapText(true) 323 .text("Tell me what's wrong Dave...") 324 .build(); 325 nextButton.setDisable(true); 326 textArea.textProperty().addListener(new ChangeListener<String>() 327 { @Override 328 public void changed(ObservableValue<? extends String> observableValue, String oldValue, String newValue) 329 { 330 nextButton.setDisable(newValue.isEmpty()); 331 } 332 } ); 333 SurveyData.instance.complaints.bind(textArea.textProperty()); 334 return VBoxBuilder.create() 335 .spacing(5) 336 .children 337 ( 338 new Label("Please enter your complaints."), 339 textArea 340 ) 341 .build(); 342 } 343} 344 345/** This page thanks the user for taking the survey */ 346class ThanksPage extends WizardPage 347{ 348 public ThanksPage() 349 { 350 super("Thanks"); 351 } 352 353 Parent getContent() 354 { 355 StackPane stack = StackPaneBuilder.create().children (new Label("Thanks!") ).build(); 356 VBox.setVgrow(stack, Priority.ALWAYS); 357 return stack; 358 } 359}