1 /* 2 * Copyright (c) 2012, 2014, Oracle and/or its affiliates. 3 * All rights reserved. Use is subject to license terms. 4 * 5 * This file is available and licensed under the following license: 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the distribution. 16 * - Neither the name of Oracle Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package com.oracle.javafx.scenebuilder.kit.editor.panel.library; 33 34 import com.oracle.javafx.scenebuilder.kit.editor.i18n.I18N; 35 import com.oracle.javafx.scenebuilder.kit.editor.panel.util.dialog.AbstractModalDialog; 36 import com.oracle.javafx.scenebuilder.kit.editor.panel.util.dialog.ErrorDialog; 37 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument; 38 import com.oracle.javafx.scenebuilder.kit.library.user.UserLibrary; 39 import com.oracle.javafx.scenebuilder.kit.library.util.JarExplorer; 40 import com.oracle.javafx.scenebuilder.kit.library.util.JarReport; 41 import com.oracle.javafx.scenebuilder.kit.library.util.JarReportEntry; 42 43 import java.io.File; 44 import java.io.IOException; 45 import java.net.MalformedURLException; 46 import java.net.URL; 47 import java.net.URLClassLoader; 48 import java.nio.file.Files; 49 import java.nio.file.Path; 50 import java.nio.file.Paths; 51 import java.util.ArrayList; 52 import java.util.Collections; 53 import java.util.Iterator; 54 import java.util.List; 55 import java.util.concurrent.ExecutionException; 56 import java.util.stream.Stream; 57 58 import javafx.application.Platform; 59 import javafx.beans.value.ChangeListener; 60 import javafx.beans.value.ObservableValue; 61 import javafx.concurrent.Task; 62 import javafx.event.ActionEvent; 63 import javafx.fxml.FXML; 64 import javafx.geometry.Bounds; 65 import javafx.scene.Group; 66 import javafx.scene.Node; 67 import javafx.scene.Scene; 68 import javafx.scene.control.ChoiceBox; 69 import javafx.scene.control.Label; 70 import javafx.scene.control.ListView; 71 import javafx.scene.control.ProgressIndicator; 72 import javafx.scene.control.SplitPane; 73 import javafx.scene.control.ToggleButton; 74 import javafx.scene.control.cell.CheckBoxListCell; 75 import javafx.scene.layout.Region; 76 import javafx.scene.layout.VBox; 77 import javafx.stage.Modality; 78 import javafx.stage.Stage; 79 import javafx.stage.Window; 80 import javafx.stage.WindowEvent; 81 import javafx.util.Callback; 82 83 /** 84 * 85 */ 86 public class ImportWindowController extends AbstractModalDialog { 87 88 final List<File> importFiles; 89 private final LibraryPanelController libPanelController; 90 Task<List<JarReport>> exploringTask = null; 91 URLClassLoader importClassLoader; 92 Node zeNode = new Label(I18N.getString("import.preview.unable")); 93 double builtinPrefWidth; 94 double builtinPrefHeight; 95 private int numOfImportedJar; 96 97 // At first we put in this collection the items which are already excluded, 98 // basically all which are listed in the filter file. 99 // When constructing the list of items discovered in new jar file being imported 100 // we uncheck already excluded items and remove them from the collection. 101 // When the user clicks the Import button the collection might contain the 102 // items we retain from older import actions. 103 private List<String> alreadyExcludedItems = new ArrayList<>(); 104 105 public enum PrefSize { 106 107 DEFAULT, TWO_HUNDRED_BY_ONE_HUNDRED, TWO_HUNDRED_BY_TWO_HUNDRED 108 }; 109 110 @FXML 111 private VBox leftHandSidePart; 112 113 @FXML 114 private Label processingLabel; 115 116 @FXML 117 ProgressIndicator processingProgressIndicator; 118 119 @FXML 120 ListView<ImportRow> importList = new ListView<>(); 121 122 @FXML 123 ChoiceBox<String> defSizeChoice; 124 125 @FXML 126 private Label sizeLabel; 127 128 @FXML 129 private SplitPane topSplitPane; 130 131 @FXML 132 Group previewGroup; 133 134 @FXML 135 Label numOfItemsLabel; 136 137 @FXML 138 Label classNameLabel; 139 140 @FXML 141 Label previewHintLabel; 142 143 @FXML 144 ToggleButton checkAllUncheckAllToggle; 145 146 public ImportWindowController(LibraryPanelController lpc, List<File> files, Window owner) { 147 super(ImportWindowController.class.getResource("ImportDialog.fxml"), I18N.getBundle(), owner); //NOI18N 148 libPanelController = lpc; 149 importFiles = new ArrayList<>(files); 150 } 151 152 /* 153 * Event handlers 154 */ 155 /* TO BE SOLVED 156 We have an issue with the exploration of SOME jar files. 157 If e.g. you use sa-jdi.jar (take it in the JRE or JDK tree) then a NPE as 158 the one below will be printed but cannot be caught in the code of this class. 159 And from there we won't be able to exit from SB, whatever the action we take 160 on the import window (Cancel or Import). 161 Yes the window goes away but some thread refuse to give up. 162 I noticed two non daemon threads: 163 AWT-EventQueue-0 164 AWT-Shutdown 165 166 java.lang.NullPointerException 167 at java.util.StringTokenizer.<init>(StringTokenizer.java:199) 168 at java.util.StringTokenizer.<init>(StringTokenizer.java:221) 169 at sun.jvm.hotspot.tools.jcore.PackageNameFilter.<init>(PackageNameFilter.java:41) 170 at sun.jvm.hotspot.tools.jcore.PackageNameFilter.<init>(PackageNameFilter.java:36) 171 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 172 at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) 173 at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 174 at java.lang.reflect.Constructor.newInstance(Constructor.java:414) 175 at java.lang.Class.newInstance(Class.java:444) 176 at sun.reflect.misc.ReflectUtil.newInstance(ReflectUtil.java:47) 177 at javafx.fxml.FXMLLoader$InstanceDeclarationElement.constructValue(FXMLLoader.java:883) 178 at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:614) 179 at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2491) 180 at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2300) 181 at com.oracle.javafx.scenebuilder.kit.library.util.JarExplorer.instantiateWithFXMLLoader(JarExplorer.java:83) 182 at com.oracle.javafx.scenebuilder.kit.library.util.JarExplorer.exploreEntry(JarExplorer.java:117) 183 at com.oracle.javafx.scenebuilder.kit.library.util.JarExplorer.explore(JarExplorer.java:43) 184 at com.oracle.javafx.scenebuilder.kit.editor.panel.library.ImportWindowController$2.call(ImportWindowController.java:155) 185 at com.oracle.javafx.scenebuilder.kit.editor.panel.library.ImportWindowController$2.call(ImportWindowController.java:138) 186 at javafx.concurrent.Task$TaskCallable.call(Task.java:1376) 187 at java.util.concurrent.FutureTask.run(FutureTask.java:262) 188 at java.lang.Thread.run(Thread.java:724) 189 */ 190 @Override 191 protected void cancelButtonPressed(ActionEvent e) { 192 if (exploringTask != null && exploringTask.isRunning()) { 193 exploringTask.setOnCancelled(t -> getStage().close()); 194 exploringTask.cancel(true); 195 } else { 196 getStage().close(); 197 } 198 199 exploringTask = null; 200 201 try { 202 closeClassLoader(); 203 } catch (IOException ex) { 204 showErrorDialog(ex); 205 } 206 } 207 208 @Override 209 protected void okButtonPressed(ActionEvent e) { 210 exploringTask = null; 211 getStage().close(); 212 213 try { 214 closeClassLoader(); 215 libPanelController.copyFilesToUserLibraryDir(importFiles); 216 UserLibrary userLib = ((UserLibrary) libPanelController.getEditorController().getLibrary()); 217 userLib.setFilter(getExcludedItems()); 218 } catch (IOException ex) { 219 showErrorDialog(ex); 220 } finally { 221 alreadyExcludedItems.clear(); 222 } 223 } 224 225 @Override 226 protected void actionButtonPressed(ActionEvent e) { 227 // NOTHING TO DO (no ACTION button) 228 } 229 230 /* 231 * AbstractFxmlWindowController 232 */ 233 @Override 234 public void onCloseRequest(WindowEvent event) { 235 cancelButtonPressed(null); 236 } 237 238 @Override 239 public void controllerDidLoadContentFxml() { 240 assert topSplitPane != null; 241 // The SplitPane should not be visible from the beginning: only the progressing bar is initially visible. 242 assert topSplitPane.isVisible() == false; 243 assert processingLabel != null; 244 assert processingProgressIndicator != null; 245 assert sizeLabel != null; 246 assert previewGroup != null; 247 assert importList != null; 248 assert defSizeChoice != null; 249 assert numOfItemsLabel != null; 250 assert leftHandSidePart != null; 251 assert classNameLabel != null; 252 assert previewHintLabel != null; 253 assert checkAllUncheckAllToggle != null; 254 255 // Setup dialog buttons 256 setOKButtonVisible(true); 257 setDefaultButtonID(ButtonID.OK); 258 setShowDefaultButton(true); 259 260 // Setup size choice box 261 defSizeChoice.getItems().clear(); 262 // Care to have values in sync with definition of PrefSize 263 defSizeChoice.getItems().addAll(I18N.getString("import.choice.builtin"), 264 "200 x 100", "200 x 200"); //NOI18N 265 defSizeChoice.getSelectionModel().selectFirst(); 266 defSizeChoice.getSelectionModel().selectedIndexProperty().addListener((ChangeListener<Number>) (ov, t, t1) -> { 267 assert t1 instanceof Integer; 268 updateSize((Integer)t1); 269 }); 270 271 // Setup Select All / Unselect All toggle 272 // Initially all items are Selected. 273 checkAllUncheckAllToggle.selectedProperty().addListener((ChangeListener<Boolean>) (ov, t, t1) -> { 274 if (t1) { 275 for (ImportRow row1 : importList.getItems()) { 276 row1.setImportRequired(false); 277 } 278 checkAllUncheckAllToggle.setText(I18N.getString("import.toggle.checkall")); 279 } else { 280 for (ImportRow row2 : importList.getItems()) { 281 row2.setImportRequired(true); 282 } 283 checkAllUncheckAllToggle.setText(I18N.getString("import.toggle.uncheckall")); 284 } 285 }); 286 287 setProcessing(); 288 289 // We do not want the list becomes larger when the window is made larger. 290 // The way to make the list larger is to use the splitter. 291 SplitPane.setResizableWithParent(leftHandSidePart, false); 292 293 work(); 294 } 295 296 /* 297 * AbstractWindowController 298 */ 299 @Override 300 protected void controllerDidCreateStage() { 301 getStage().setTitle(I18N.getString("import.window.title")); 302 getStage().initModality(Modality.APPLICATION_MODAL); 303 } 304 305 /* 306 * Private 307 */ 308 309 private void closeClassLoader() throws IOException { 310 if (importClassLoader != null) { 311 importClassLoader.close(); 312 } 313 } 314 315 // This method returns a new list of File made of the union of the provided 316 // one and jar files found in the user library dir. 317 List<File> buildListOfAllFiles(List<File> importFiles) throws IOException { 318 final List<File> res = new ArrayList<>(importFiles); 319 String userLibraryDir = ((UserLibrary) libPanelController.getEditorController().getLibrary()).getPath(); 320 Path userLibraryPath = new File(userLibraryDir).toPath(); 321 322 try (Stream<Path> pathStream = Files.list(userLibraryPath)) { 323 Iterator<Path> pathIterator = pathStream.iterator(); 324 while (pathIterator.hasNext()) { 325 Path element = pathIterator.next(); 326 if (element.toString().endsWith(".jar")) { //NOI18N 327 // System.out.println("ImportWindowController::buildListOfAllFiles: Adding " + element); //NOI18N 328 res.add(element.toFile()); 329 } 330 } 331 } 332 333 return res; 334 } 335 336 private void work() { 337 exploringTask = new Task<List<JarReport>>() { 338 339 @Override 340 protected List<JarReport> call() throws Exception { 341 final List<JarReport> res = new ArrayList<>(); 342 numOfImportedJar = importFiles.size(); 343 // The classloader takes in addition all already existing 344 // jar files stored in the user lib dir. 345 final List<File> allFiles = buildListOfAllFiles(importFiles); 346 final URLClassLoader classLoader = getClassLoaderForFiles(allFiles); 347 int index = 1; 348 for (File file : importFiles) { 349 if (isCancelled()) { 350 updateMessage(I18N.getString("import.work.cancelled")); 351 break; 352 } 353 updateMessage(I18N.getString("import.work.exploring", file.getName())); 354 // System.out.println("[" + index + "/" + max + "] Exploring file " + file.getName()); //NOI18N 355 final JarExplorer explorer = new JarExplorer(Paths.get(file.getAbsolutePath())); 356 final JarReport jarReport = explorer.explore(classLoader); 357 res.add(jarReport); 358 updateProgress(index, numOfImportedJar); 359 index++; 360 } 361 362 updateProgress(numOfImportedJar, numOfImportedJar); 363 updateImportClassLoader(classLoader); 364 return res; 365 } 366 }; 367 368 Thread th = new Thread(exploringTask); 369 th.setDaemon(true); 370 processingProgressIndicator.progressProperty().bind(exploringTask.progressProperty()); 371 372 // We typically enter this handler when dropping jar files such as 373 // rt.jar from Java Runtime. 374 exploringTask.setOnFailed(t -> { 375 // See in setOnSucceeded the explanation for the toFront below. 376 getStage().toFront(); 377 updateNumOfItemsLabelAndSelectionToggleState(); 378 }); 379 380 // We construct the import list only if exploration of jar files does well. 381 // If Cancel is called during the construction of the list then the import 382 // window is closed but the construction itself will continue up to the 383 // end. Do we want to make it interruptible ? 384 exploringTask.setOnSucceeded(t -> { 385 assert Platform.isFxApplicationThread(); 386 // This toFront() might not be necessary because import window is modal 387 // and is chained to the document window. Anyway experience showed 388 // we need it (FX 8 b106). This is suspicious, to be investigated ... 389 // But more tricky is why toFront() is called here. Mind that when toFront() 390 // is called while isShowing() returns false isn't effective: that's 391 // why toFront called at the end of controllerDidCreateStage() or 392 // controllerDidLoadContentFxml() wasn't an option. Below is the 393 // earliest place it has been proven effective, at least on my machine. 394 getStage().toFront(); 395 396 try { 397 // We get the set of items which are already excluded prior to the current import. 398 UserLibrary userLib = ((UserLibrary) libPanelController.getEditorController().getLibrary()); 399 alreadyExcludedItems = userLib.getFilter(); 400 401 List<JarReport> jarReportList = exploringTask.get(); // blocking call 402 final Callback<ImportRow, ObservableValue<Boolean>> importRequired 403 = row -> row.importRequired(); 404 importList.setCellFactory(CheckBoxListCell.forListView(importRequired)); 405 406 for (JarReport jarReport : jarReportList) { 407 for (JarReportEntry e : jarReport.getEntries()) { 408 if ((e.getStatus() == JarReportEntry.Status.OK) && e.isNode()) { 409 boolean checked = true; 410 // If the class we import is already listed as an excluded one 411 // then it must appear unchecked in the list. 412 if (alreadyExcludedItems.contains(e.getKlass().getCanonicalName())) { 413 checked = false; 414 alreadyExcludedItems.remove(e.getKlass().getCanonicalName()); 415 } 416 final ImportRow importRow = new ImportRow(checked, e, null); 417 importList.getItems().add(importRow); 418 importRow.importRequired().addListener((ChangeListener<Boolean>) (ov, oldValue, 419 newValue) -> { 420 final int numOfComponentToImport = getNumOfComponentToImport(importList); 421 updateOKButtonTitle(numOfComponentToImport); 422 updateSelectionToggleText(numOfComponentToImport); 423 }); 424 } 425 } 426 } 427 428 // Sort based on the simple class name. 429 Collections.sort(importList.getItems(), new ImportRowComparator()); 430 431 final int numOfComponentToImport = getNumOfComponentToImport(importList); 432 updateOKButtonTitle(numOfComponentToImport); 433 updateSelectionToggleText(numOfComponentToImport); 434 updateNumOfItemsLabelAndSelectionToggleState(); 435 } catch (InterruptedException | ExecutionException | IOException ex) { 436 getStage().close(); 437 showErrorDialog(ex); 438 } 439 440 unsetProcessing(); 441 }); 442 443 th.start(); 444 } 445 446 private void showErrorDialog(Exception exception) { 447 final ErrorDialog errorDialog = new ErrorDialog(null); 448 errorDialog.setTitle(I18N.getString("import.error.title")); 449 errorDialog.setMessage(I18N.getString("import.error.message")); 450 errorDialog.setDetails(I18N.getString("import.error.details")); 451 errorDialog.setDebugInfoWithThrowable(exception); 452 errorDialog.showAndWait(); 453 } 454 455 void updateImportClassLoader(URLClassLoader cl) { 456 this.importClassLoader = cl; 457 } 458 459 void unsetProcessing() { 460 processingProgressIndicator.setVisible(false); 461 processingLabel.setVisible(false); 462 topSplitPane.setVisible(true); 463 464 importList.getSelectionModel().selectedItemProperty().addListener((ChangeListener<ImportRow>) (ov, t, t1) -> { 465 previewGroup.getChildren().clear(); 466 final String fxmlText = JarExplorer.makeFxmlText(t1.getJarReportEntry().getKlass()); 467 try { 468 FXOMDocument fxomDoc = new FXOMDocument(fxmlText, null, importClassLoader, null); 469 zeNode = (Node) fxomDoc.getSceneGraphRoot(); 470 } catch (IOException ioe) { 471 showErrorDialog(ioe); 472 } 473 474 // In order to get valid bounds I need to put the node into a 475 // scene and ask for full layout. 476 try { 477 final Group visualGroup = new Group(zeNode); 478 final Scene hiddenScene = new Scene(visualGroup); 479 Stage hiddenStage = new Stage(); 480 hiddenStage.setScene(hiddenScene); 481 visualGroup.applyCss(); 482 visualGroup.layout(); 483 final Bounds zeBounds = zeNode.getLayoutBounds(); 484 builtinPrefWidth = zeBounds.getWidth(); 485 builtinPrefHeight = zeBounds.getHeight(); 486 // Detach the scene ! 487 hiddenScene.setRoot(new Group()); 488 hiddenStage.close(); 489 } catch (Error e) { 490 // Experience shows that with rogue jar files (a jar file 491 // unlikely to contain FX controls) we can enter here. 492 // Anything better to do than setting pref size to 0 ? 493 builtinPrefWidth = 0; 494 builtinPrefHeight = 0; 495 } 496 497 if (builtinPrefWidth == 0 || builtinPrefHeight == 0) { 498 ((Region) zeNode).setPrefSize(200, 200); 499 setSizeLabel(PrefSize.TWO_HUNDRED_BY_TWO_HUNDRED); 500 defSizeChoice.getSelectionModel().select(2); 501 } else { 502 setSizeLabel(PrefSize.DEFAULT); 503 defSizeChoice.getSelectionModel().selectFirst(); 504 } 505 previewGroup.getChildren().add(zeNode); 506 defSizeChoice.setDisable(false); 507 classNameLabel.setText(t1.getJarReportEntry().getKlass().getName()); 508 }); 509 510 // We avoid to get an empty Preview area at first. 511 if (importList.getItems().size() > 0) { 512 importList.getSelectionModel().selectFirst(); 513 } 514 } 515 516 private URLClassLoader getClassLoaderForFiles(List<File> files) { 517 return new URLClassLoader(makeURLArrayFromFiles(files)); 518 } 519 520 private URL[] makeURLArrayFromFiles(List<File> files) { 521 final URL[] result = new URL[files.size()]; 522 try { 523 int index = 0; 524 for (File file : files) { 525 result[index] = file.toURI().toURL(); 526 index++; 527 } 528 } catch (MalformedURLException x) { 529 throw new RuntimeException("Bug in " + getClass().getSimpleName(), x); //NOI18N 530 } 531 532 return result; 533 } 534 535 private void setProcessing() { 536 cancelButton.setDefaultButton(true); 537 } 538 539 private int getNumOfComponentToImport(final ListView<ImportRow> list) { 540 int res = 0; 541 542 for (final ImportRow row : list.getItems()) { 543 if (row.isImportRequired()) { 544 res++; 545 } 546 } 547 548 return res; 549 } 550 551 private List<String> getExcludedItems() { 552 List<String> res = new ArrayList<>(alreadyExcludedItems); 553 554 for (ImportRow row : importList.getItems()) { 555 if (! row.isImportRequired()) { 556 res.add(row.getCanonicalClassName()); 557 } 558 } 559 return res; 560 } 561 562 // The title of the button is important in the sense it says to the user 563 // what action will be taken. 564 // In the most common case one or more component are selected in the list, 565 // but it is also possible to get an empty list, in which case the user may 566 // want to import the jar file anyway; it makes sense in ooder to resolve 567 // dependencies other jars have onto it. 568 // See DTL-6531 for details. 569 private void updateOKButtonTitle(int numOfComponentToImport) { 570 if (numOfComponentToImport == 0) { 571 if (numOfImportedJar == 1) { 572 setOKButtonTitle(I18N.getString("import.button.import.jar")); 573 } else { 574 setOKButtonTitle(I18N.getString("import.button.import.jars")); 575 } 576 } else if (numOfComponentToImport == 1) { 577 setOKButtonTitle(I18N.getString("import.button.import.component")); 578 } else { 579 setOKButtonTitle(I18N.getString("import.button.import.components")); 580 } 581 } 582 583 void updateNumOfItemsLabelAndSelectionToggleState() { 584 final int num = importList.getItems().size(); 585 if (num == 0 || num == 1) { 586 numOfItemsLabel.setText(num + " " //NOI18N 587 + I18N.getString("import.num.item")); 588 } else { 589 numOfItemsLabel.setText(num + " " //NOI18N 590 + I18N.getString("import.num.items")); 591 } 592 593 if (num >= 1) { 594 checkAllUncheckAllToggle.setDisable(false); 595 } 596 } 597 598 private void updateSelectionToggleText(int numOfComponentToImport) { 599 if (numOfComponentToImport == 0) { 600 checkAllUncheckAllToggle.setText(I18N.getString("import.toggle.checkall")); 601 } else { 602 checkAllUncheckAllToggle.setText(I18N.getString("import.toggle.uncheckall")); 603 } 604 } 605 606 // NOTE At the end of the day some tooling in metadata will supersedes the 607 // use of this method that is only able to deal with a Region, ignoring all 608 // other cases. 609 private void updateSize(Integer choice) { 610 if (zeNode instanceof Region) { 611 PrefSize prefSize = PrefSize.values()[choice]; 612 switch (prefSize) { 613 case DEFAULT: 614 ((Region) zeNode).setPrefSize(builtinPrefWidth, builtinPrefHeight); 615 setSizeLabel(prefSize); 616 break; 617 case TWO_HUNDRED_BY_ONE_HUNDRED: 618 ((Region) zeNode).setPrefSize(200, 100); 619 setSizeLabel(prefSize); 620 break; 621 case TWO_HUNDRED_BY_TWO_HUNDRED: 622 ((Region) zeNode).setPrefSize(200, 200); 623 setSizeLabel(prefSize); 624 break; 625 default: 626 break; 627 } 628 629 defSizeChoice.getSelectionModel().select(choice); 630 } 631 } 632 633 private void setSizeLabel(PrefSize ps) { 634 switch (ps) { 635 case DEFAULT: 636 sizeLabel.setText(builtinPrefWidth + " x " + builtinPrefHeight); //NOI18N 637 break; 638 case TWO_HUNDRED_BY_ONE_HUNDRED: 639 sizeLabel.setText("200 x 100"); //NOI18N 640 break; 641 case TWO_HUNDRED_BY_TWO_HUNDRED: 642 sizeLabel.setText("200 x 200"); //NOI18N 643 break; 644 default: 645 break; 646 } 647 } 648 }