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.app.preferences; 33 34 import com.oracle.javafx.scenebuilder.app.SceneBuilderApp.ToolTheme; 35 import com.oracle.javafx.scenebuilder.app.i18n.I18N; 36 37 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesController.ALIGNMENT_GUIDES_COLOR; 38 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesController.BACKGROUND_IMAGE; 39 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesController.CSS_TABLE_COLUMNS_ORDERING_REVERSED; 40 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesController.ROOT_CONTAINER_HEIGHT; 41 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesController.ROOT_CONTAINER_WIDTH; 42 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesController.HIERARCHY_DISPLAY_OPTION; 43 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesController.LIBRARY_DISPLAY_OPTION; 44 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesController.PARENT_RING_COLOR; 45 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesController.RECENT_ITEMS; 46 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesController.RECENT_ITEMS_SIZE; 47 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesController.TOOL_THEME; 48 49 import com.oracle.javafx.scenebuilder.app.preferences.PreferencesRecordGlobal.BackgroundImage; 50 import com.oracle.javafx.scenebuilder.app.preferences.PreferencesRecordGlobal.CSSAnalyzerColumnsOrder; 51 52 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesRecordGlobal.DEFAULT_ALIGNMENT_GUIDES_COLOR; 53 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesRecordGlobal.DEFAULT_BACKGROUND_IMAGE; 54 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesRecordGlobal.DEFAULT_HIERARCHY_DISPLAY_OPTION; 55 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesRecordGlobal.DEFAULT_LIBRARY_DISPLAY_OPTION; 56 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesRecordGlobal.DEFAULT_PARENT_RING_COLOR; 57 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesRecordGlobal.DEFAULT_RECENT_ITEMS_SIZE; 58 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesRecordGlobal.DEFAULT_ROOT_CONTAINER_HEIGHT; 59 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesRecordGlobal.DEFAULT_ROOT_CONTAINER_WIDTH; 60 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesRecordGlobal.DEFAULT_TOOL_THEME; 61 import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesRecordGlobal.recentItemsSizes; 62 63 import com.oracle.javafx.scenebuilder.kit.editor.panel.hierarchy.AbstractHierarchyPanelController.DisplayOption; 64 import com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors.DoubleField; 65 import com.oracle.javafx.scenebuilder.kit.editor.panel.library.LibraryPanelController.DISPLAY_MODE; 66 import com.oracle.javafx.scenebuilder.kit.editor.panel.util.AbstractFxmlWindowController; 67 import com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.PaintPicker; 68 import com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.PaintPicker.Mode; 69 70 import java.util.Arrays; 71 72 import javafx.beans.value.ChangeListener; 73 import javafx.beans.value.ObservableValue; 74 import javafx.event.ActionEvent; 75 import javafx.fxml.FXML; 76 import javafx.scene.control.ChoiceBox; 77 import javafx.scene.control.CustomMenuItem; 78 import javafx.scene.control.MenuButton; 79 import javafx.scene.paint.Color; 80 import javafx.scene.paint.Paint; 81 import javafx.scene.shape.Rectangle; 82 import javafx.stage.WindowEvent; 83 84 /** 85 * Preferences window controller. 86 */ 87 public class PreferencesWindowController extends AbstractFxmlWindowController { 88 89 @FXML 90 private DoubleField rootContainerHeight; 91 @FXML 92 private DoubleField rootContainerWidth; 93 @FXML 94 private ChoiceBox<BackgroundImage> backgroundImage; 95 @FXML 96 private ChoiceBox<ToolTheme> toolTheme; 97 @FXML 98 private ChoiceBox<DISPLAY_MODE> libraryDisplayOption; 99 @FXML 100 private ChoiceBox<DisplayOption> hierarchyDisplayOption; 101 @FXML 102 private ChoiceBox<CSSAnalyzerColumnsOrder> cssAnalyzerColumnsOrder; 103 @FXML 104 private MenuButton alignmentGuidesButton; 105 @FXML 106 private MenuButton parentRingButton; 107 @FXML 108 private CustomMenuItem alignmentGuidesMenuItem; 109 @FXML 110 private CustomMenuItem parentRingMenuItem; 111 @FXML 112 private Rectangle alignmentGuidesGraphic; 113 @FXML 114 private Rectangle parentRingGraphic; 115 @FXML 116 private ChoiceBox<Integer> recentItemsSize; 117 118 private PaintPicker alignmentColorPicker; 119 private PaintPicker parentRingColorPicker; 120 121 public PreferencesWindowController() { 122 super(PreferencesWindowController.class.getResource("Preferences.fxml"), //NOI18N 123 I18N.getBundle()); 124 } 125 126 /* 127 * AbstractModalDialog 128 */ 129 @Override 130 protected void controllerDidLoadFxml() { 131 super.controllerDidLoadFxml(); 132 133 final PreferencesController preferencesController 134 = PreferencesController.getSingleton(); 135 final PreferencesRecordGlobal recordGlobal 136 = preferencesController.getRecordGlobal(); 137 138 // Root container size 139 rootContainerHeight.setText(String.valueOf(recordGlobal.getRootContainerHeight())); 140 rootContainerHeight.setOnAction(t -> { 141 final String value = rootContainerHeight.getText(); 142 recordGlobal.setRootContainerHeight(Double.valueOf(value)); 143 rootContainerHeight.selectAll(); 144 // Update preferences 145 recordGlobal.writeToJavaPreferences(ROOT_CONTAINER_HEIGHT); 146 // Update UI 147 recordGlobal.refreshRootContainerHeight(); 148 }); 149 rootContainerWidth.setText(String.valueOf(recordGlobal.getRootContainerWidth())); 150 rootContainerWidth.setOnAction(t -> { 151 final String value = rootContainerWidth.getText(); 152 recordGlobal.setRootContainerWidth(Double.valueOf(value)); 153 rootContainerWidth.selectAll(); 154 // Update preferences 155 recordGlobal.writeToJavaPreferences(ROOT_CONTAINER_WIDTH); 156 // Update UI 157 recordGlobal.refreshRootContainerWidth(); 158 }); 159 160 // Background image 161 backgroundImage.getItems().setAll(Arrays.asList(BackgroundImage.class.getEnumConstants())); 162 backgroundImage.setValue(recordGlobal.getBackgroundImage()); 163 backgroundImage.getSelectionModel().selectedItemProperty().addListener(new BackgroundImageListener()); 164 165 // PaintPicker delegate shared by alignmentColorPicker and parentRingColorPicker 166 final PaintPicker.Delegate delegate = new PaintPickerDelegate(); 167 168 // Alignment guides color 169 final Color alignmentColor = recordGlobal.getAlignmentGuidesColor(); 170 alignmentColorPicker = new PaintPicker(delegate, Mode.COLOR); 171 alignmentGuidesGraphic.setFill(alignmentColor); 172 alignmentGuidesMenuItem.setContent(alignmentColorPicker); 173 alignmentColorPicker.setPaintProperty(alignmentColor); 174 alignmentColorPicker.paintProperty().addListener( 175 new AlignmentGuidesColorListener(alignmentGuidesGraphic)); 176 177 // Parent ring color 178 final Color parentRingColor = recordGlobal.getParentRingColor(); 179 parentRingColorPicker = new PaintPicker(delegate, Mode.COLOR); 180 parentRingGraphic.setFill(parentRingColor); 181 parentRingMenuItem.setContent(parentRingColorPicker); 182 parentRingColorPicker.setPaintProperty(parentRingColor); 183 parentRingColorPicker.paintProperty().addListener( 184 new ParentRingColorListener(parentRingGraphic)); 185 186 // Tool theme 187 toolTheme.getItems().setAll(Arrays.asList(ToolTheme.class.getEnumConstants())); 188 toolTheme.setValue(recordGlobal.getToolTheme()); 189 toolTheme.getSelectionModel().selectedItemProperty().addListener(new ToolThemeListener()); 190 191 // Library view option 192 final DISPLAY_MODE availableDisplayMode[] = new DISPLAY_MODE[]{ 193 DISPLAY_MODE.LIST, DISPLAY_MODE.SECTIONS}; 194 libraryDisplayOption.getItems().setAll(Arrays.asList(availableDisplayMode)); 195 libraryDisplayOption.setValue(recordGlobal.getLibraryDisplayOption()); 196 libraryDisplayOption.getSelectionModel().selectedItemProperty().addListener(new LibraryOptionListener()); 197 198 // Hierarchy display option 199 hierarchyDisplayOption.getItems().setAll(Arrays.asList(DisplayOption.class.getEnumConstants())); 200 hierarchyDisplayOption.setValue(recordGlobal.getHierarchyDisplayOption()); 201 hierarchyDisplayOption.getSelectionModel().selectedItemProperty().addListener(new DisplayOptionListener()); 202 203 // CSS analyzer column order 204 cssAnalyzerColumnsOrder.getItems().setAll(Arrays.asList(CSSAnalyzerColumnsOrder.class.getEnumConstants())); 205 cssAnalyzerColumnsOrder.setValue(recordGlobal.getCSSAnalyzerColumnsOrder()); 206 cssAnalyzerColumnsOrder.getSelectionModel().selectedItemProperty().addListener(new ColumnOrderListener()); 207 208 // Number of open recent items 209 recentItemsSize.getItems().setAll(recentItemsSizes); 210 recentItemsSize.setValue(recordGlobal.getRecentItemsSize()); 211 recentItemsSize.getSelectionModel().selectedItemProperty().addListener(new RecentItemsSizeListener()); 212 } 213 214 /* 215 * AbstractWindowController 216 */ 217 @Override 218 protected void controllerDidCreateStage() { 219 assert getRoot() != null; 220 assert getRoot().getScene() != null; 221 assert getRoot().getScene().getWindow() != null; 222 223 getStage().setTitle(I18N.getString("prefs.title")); 224 getStage().setResizable(false); 225 } 226 227 @Override 228 public void onCloseRequest(WindowEvent event) { 229 super.closeWindow(); 230 } 231 232 @FXML 233 void resetToDefaultAction(ActionEvent event) { 234 final PreferencesController preferencesController 235 = PreferencesController.getSingleton(); 236 final PreferencesRecordGlobal recordGlobal 237 = preferencesController.getRecordGlobal(); 238 239 // Root container size 240 rootContainerHeight.setText(String.valueOf(DEFAULT_ROOT_CONTAINER_HEIGHT)); 241 rootContainerHeight.getOnAction().handle(new ActionEvent()); 242 rootContainerWidth.setText(String.valueOf(DEFAULT_ROOT_CONTAINER_WIDTH)); 243 rootContainerWidth.getOnAction().handle(new ActionEvent()); 244 245 // Background image 246 backgroundImage.setValue(DEFAULT_BACKGROUND_IMAGE); 247 248 // Alignment guides color 249 alignmentColorPicker.setPaintProperty(DEFAULT_ALIGNMENT_GUIDES_COLOR); 250 251 // Parent ring color 252 parentRingColorPicker.setPaintProperty(DEFAULT_PARENT_RING_COLOR); 253 254 // Tool theme 255 toolTheme.setValue(DEFAULT_TOOL_THEME); 256 257 // Library view option 258 libraryDisplayOption.setValue(DEFAULT_LIBRARY_DISPLAY_OPTION); 259 260 // Hierarchy display option 261 hierarchyDisplayOption.setValue(DEFAULT_HIERARCHY_DISPLAY_OPTION); 262 263 // CSS analyzer column order 264 cssAnalyzerColumnsOrder.setValue(recordGlobal.getDefaultCSSAnalyzerColumnsOrder()); 265 266 // Number of open recent items 267 recentItemsSize.setValue(DEFAULT_RECENT_ITEMS_SIZE); 268 } 269 270 /** 271 * ************************************************************************* 272 * Static inner class 273 * ************************************************************************* 274 */ 275 private static class BackgroundImageListener implements ChangeListener<BackgroundImage> { 276 277 @Override 278 public void changed(ObservableValue<? extends BackgroundImage> observable, 279 BackgroundImage oldValue, BackgroundImage newValue) { 280 final PreferencesController preferencesController 281 = PreferencesController.getSingleton(); 282 final PreferencesRecordGlobal recordGlobal 283 = preferencesController.getRecordGlobal(); 284 // Update preferences 285 recordGlobal.setBackgroundImage(newValue); 286 recordGlobal.writeToJavaPreferences(BACKGROUND_IMAGE); 287 // Update UI 288 recordGlobal.refreshBackgroundImage(); 289 } 290 } 291 292 private static class ToolThemeListener implements ChangeListener<ToolTheme> { 293 294 @Override 295 public void changed(ObservableValue<? extends ToolTheme> observable, 296 ToolTheme oldValue, ToolTheme newValue) { 297 final PreferencesController preferencesController 298 = PreferencesController.getSingleton(); 299 final PreferencesRecordGlobal recordGlobal 300 = preferencesController.getRecordGlobal(); 301 // Update preferences 302 recordGlobal.setToolTheme(newValue); 303 recordGlobal.writeToJavaPreferences(TOOL_THEME); 304 // Update UI 305 recordGlobal.refreshToolTheme(); 306 } 307 } 308 309 private static class LibraryOptionListener implements ChangeListener<DISPLAY_MODE> { 310 311 @Override 312 public void changed(ObservableValue<? extends DISPLAY_MODE> ov, DISPLAY_MODE oldValue, DISPLAY_MODE newValue) { 313 final PreferencesController preferencesController 314 = PreferencesController.getSingleton(); 315 final PreferencesRecordGlobal recordGlobal 316 = preferencesController.getRecordGlobal(); 317 // Update preferences 318 recordGlobal.setLibraryDisplayOption(newValue); 319 recordGlobal.writeToJavaPreferences(LIBRARY_DISPLAY_OPTION); 320 // Update UI 321 recordGlobal.refreshLibraryDisplayOption(); 322 } 323 } 324 325 private static class DisplayOptionListener implements ChangeListener<DisplayOption> { 326 327 @Override 328 public void changed(ObservableValue<? extends DisplayOption> observable, 329 DisplayOption oldValue, DisplayOption newValue) { 330 final PreferencesController preferencesController 331 = PreferencesController.getSingleton(); 332 final PreferencesRecordGlobal recordGlobal 333 = preferencesController.getRecordGlobal(); 334 // Update preferences 335 recordGlobal.setHierarchyDisplayOption(newValue); 336 recordGlobal.writeToJavaPreferences(HIERARCHY_DISPLAY_OPTION); 337 // Update UI 338 recordGlobal.refreshHierarchyDisplayOption(); 339 } 340 } 341 342 private static class ColumnOrderListener implements ChangeListener<CSSAnalyzerColumnsOrder> { 343 344 @Override 345 public void changed(ObservableValue<? extends CSSAnalyzerColumnsOrder> observable, 346 CSSAnalyzerColumnsOrder oldValue, CSSAnalyzerColumnsOrder newValue) { 347 final PreferencesController preferencesController 348 = PreferencesController.getSingleton(); 349 final PreferencesRecordGlobal recordGlobal 350 = preferencesController.getRecordGlobal(); 351 // Update preferences 352 recordGlobal.setCSSAnalyzerColumnsOrder(newValue); 353 recordGlobal.writeToJavaPreferences(CSS_TABLE_COLUMNS_ORDERING_REVERSED); 354 // Update UI 355 recordGlobal.refreshCSSAnalyzerColumnsOrder(); 356 } 357 } 358 359 private static class RecentItemsSizeListener implements ChangeListener<Integer> { 360 361 @Override 362 public void changed(ObservableValue<? extends Integer> observable, 363 Integer oldValue, Integer newValue) { 364 final PreferencesController preferencesController 365 = PreferencesController.getSingleton(); 366 final PreferencesRecordGlobal recordGlobal 367 = preferencesController.getRecordGlobal(); 368 // Update preferences 369 recordGlobal.setRecentItemsSize(newValue); 370 recordGlobal.writeToJavaPreferences(RECENT_ITEMS_SIZE); 371 recordGlobal.writeToJavaPreferences(RECENT_ITEMS); 372 } 373 } 374 375 private static class AlignmentGuidesColorListener implements ChangeListener<Paint> { 376 377 private final Rectangle graphic; 378 379 public AlignmentGuidesColorListener(Rectangle graphic) { 380 this.graphic = graphic; 381 } 382 383 @Override 384 public void changed(ObservableValue<? extends Paint> ov, Paint oldValue, Paint newValue) { 385 assert newValue instanceof Color; 386 final PreferencesController preferencesController 387 = PreferencesController.getSingleton(); 388 final PreferencesRecordGlobal recordGlobal 389 = preferencesController.getRecordGlobal(); 390 // Update preferences 391 recordGlobal.setAlignmentGuidesColor((Color) newValue); 392 recordGlobal.writeToJavaPreferences(ALIGNMENT_GUIDES_COLOR); 393 // Update UI 394 recordGlobal.refreshAlignmentGuidesColor(); 395 graphic.setFill(newValue); 396 } 397 } 398 399 private static class ParentRingColorListener implements ChangeListener<Paint> { 400 401 private final Rectangle graphic; 402 403 public ParentRingColorListener(Rectangle graphic) { 404 this.graphic = graphic; 405 } 406 407 @Override 408 public void changed(ObservableValue<? extends Paint> ov, Paint oldValue, Paint newValue) { 409 assert newValue instanceof Color; 410 final PreferencesController preferencesController 411 = PreferencesController.getSingleton(); 412 final PreferencesRecordGlobal recordGlobal 413 = preferencesController.getRecordGlobal(); 414 // Update preferences 415 recordGlobal.setParentRingColor((Color) newValue); 416 recordGlobal.writeToJavaPreferences(PARENT_RING_COLOR); 417 // Update UI 418 recordGlobal.refreshParentRingColor(); 419 graphic.setFill(newValue); 420 } 421 } 422 423 private static class PaintPickerDelegate implements PaintPicker.Delegate { 424 425 @Override 426 public void handleError(String warningKey, Object... arguments) { 427 // Log a warning in message bar 428 } 429 } 430 }