1 /* 2 * Copyright (c) 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 airportapp; 33 34 import javafx.animation.KeyFrame; 35 import javafx.animation.KeyValue; 36 import javafx.animation.Timeline; 37 import javafx.collections.FXCollections; 38 import javafx.collections.ObservableList; 39 import javafx.event.ActionEvent; 40 import javafx.fxml.FXML; 41 import javafx.scene.Group; 42 import javafx.scene.control.*; 43 import javafx.scene.input.MouseEvent; 44 import javafx.scene.layout.VBox; 45 import javafx.util.Duration; 46 47 import java.util.*; 48 import java.util.Map.Entry; 49 50 import javafx.application.ConditionalFeature; 51 import javafx.application.Platform; 52 import javafx.geometry.Rectangle2D; 53 import javafx.stage.Screen; 54 55 public class Controller { 56 57 @FXML 58 private VBox root_vbox; 59 @FXML 60 private ListView<String> map_listview; 61 @FXML 62 private ScrollPane map_scrollpane; 63 @FXML 64 private Slider zoom_slider; 65 @FXML 66 private MenuButton map_pin; 67 @FXML 68 private MenuItem pin_info; 69 @FXML 70 private ToggleButton contrast_togglebutton; 71 @FXML 72 private ToggleButton size_togglebutton; 73 74 private final HashMap<String, ArrayList<Comparable<?>>> hm = new HashMap<>(); 75 Group zoomGroup; 76 77 @FXML 78 void initialize() { 79 System.out.println("airportapp.Controller.initialize"); 80 81 assert map_listview != null : "fx:id=\"map_listview\" was not injected: check your FXML file 'airportapp.fxml'."; 82 assert root_vbox != null : "fx:id=\"root_vbox\" was not injected: check your FXML file 'airportapp.fxml'."; 83 assert contrast_togglebutton != null : "fx:id=\"contrast_togglebutton\" was not injected: check your FXML file 'airportapp.fxml'."; 84 assert size_togglebutton != null : "fx:id=\"size_togglebutton\" was not injected: check your FXML file 'airportapp.fxml'."; 85 assert map_scrollpane != null : "fx:id=\"map_scrollpane\" was not injected: check your FXML file 'airportapp.fxml'."; 86 assert map_pin != null : "fx:id=\"map_pin\" was not injected: check your FXML file 'airportapp.fxml'."; 87 assert pin_info != null : "fx:id=\"pin_info\" was not injected: check your FXML file 'airportapp.fxml'."; 88 assert zoom_slider != null : "fx:id=\"zoom_slider\" was not injected: check your FXML file 'airportapp.fxml'."; 89 90 hm.put("Byron", new ArrayList<>(Arrays.asList(1849.0, 623.0, "Code: C83\nElevation:"))); 91 hm.put("Gnoss Field", new ArrayList<>(Arrays.asList(558.0, 79.0, "Code: KDVO\nElevation: 2ft"))); 92 hm.put("Half Moon Bay", new ArrayList<>(Arrays.asList(627.0, 1172.0, "Code: KHAF\nElevation: 66ft"))); 93 hm.put("Hayward Executive", new ArrayList<>(Arrays.asList(1010.0, 807.0, "Code: KHWD\nElevation: 52ft"))); 94 hm.put("Livermore Muni", new ArrayList<>(Arrays.asList(1582.0, 863.0, "Code: KLVK\nElevation: 400ft"))); 95 hm.put("Metropolitan Oakland Intl", new ArrayList<>(Arrays.asList(1009.0, 807.0, "Code: KOAK\nElevation: 9ft"))); 96 hm.put("Moffet Federal Airfield", new ArrayList<>(Arrays.asList(1265.0, 1351.0, "Code: KNUQ\nElevation: 32ft"))); 97 hm.put("Palo Alto", new ArrayList<>(Arrays.asList(1164.0, 1271.0, "Code: KPAO\nElevation: 7ft"))); 98 hm.put("Reid-Hillview", new ArrayList<>(Arrays.asList(1578.0, 1494.0, "Code: KRHV\nElevation: 135ft"))); 99 hm.put("San Carlos", new ArrayList<>(Arrays.asList(977.0, 1156.0, "Code: KSQL\nElevation: 52ft"))); 100 hm.put("San Francisco Intl", new ArrayList<>(Arrays.asList(808.0, 992.0, "Code: KSFO\nElevation: 13ft"))); 101 hm.put("San Jose Intl", new ArrayList<>(Arrays.asList(1425.0, 1438.0, "Code: KSJC\nElevation: 62ft"))); 102 hm.put("San Martin", new ArrayList<>(Arrays.asList(1879.0, 1925.0, "Code: E16\nElevation: 281ft"))); 103 104 ObservableList<String> names = FXCollections.observableArrayList(); 105 Set<Entry<String, ArrayList<Comparable<?>>>> set = hm.entrySet(); 106 Iterator<Entry<String, ArrayList<Comparable<?>>>> i = set.iterator(); 107 while (i.hasNext()) { 108 Map.Entry<String, ArrayList<Comparable<?>>> me = i.next(); 109 names.add((String) me.getKey()); 110 } 111 Collections.sort(names); 112 113 map_listview.setItems(names); 114 map_pin.setVisible(false); 115 116 zoom_slider.setMin(0.5); 117 zoom_slider.setMax(1.5); 118 zoom_slider.setValue(1.0); 119 zoom_slider.valueProperty().addListener((o, oldVal, newVal) -> zoom((Double) newVal)); 120 121 // Wrap scroll content in a Group so ScrollPane re-computes scroll bars 122 Group contentGroup = new Group(); 123 zoomGroup = new Group(); 124 contentGroup.getChildren().add(zoomGroup); 125 zoomGroup.getChildren().add(map_scrollpane.getContent()); 126 map_scrollpane.setContent(contentGroup); 127 128 // Add large UI styling and make full screen if we are on device 129 if (Platform.isSupported(ConditionalFeature.INPUT_TOUCH)) { 130 System.out.println("airportapp.Controller.initialize, device detected"); 131 size_togglebutton.setSelected(true); 132 root_vbox.getStyleClass().add("touch-sizes"); 133 Screen screen = Screen.getPrimary(); 134 Rectangle2D bounds = screen.getVisualBounds(); 135 root_vbox.setPrefSize(bounds.getWidth(), bounds.getHeight()); 136 } 137 } 138 139 @FXML 140 void listClicked(MouseEvent event) { 141 String item = map_listview.getSelectionModel().getSelectedItem(); 142 List<Comparable<?>> list = hm.get(item); 143 144 // animation scroll to new position 145 double mapWidth = zoomGroup.getBoundsInLocal().getWidth(); 146 double mapHeight = zoomGroup.getBoundsInLocal().getHeight(); 147 double scrollH = (Double) list.get(0) / mapWidth; 148 double scrollV = (Double) list.get(1) / mapHeight; 149 final Timeline timeline = new Timeline(); 150 final KeyValue kv1 = new KeyValue(map_scrollpane.hvalueProperty(), scrollH); 151 final KeyValue kv2 = new KeyValue(map_scrollpane.vvalueProperty(), scrollV); 152 final KeyFrame kf = new KeyFrame(Duration.millis(500), kv1, kv2); 153 timeline.getKeyFrames().add(kf); 154 timeline.play(); 155 156 // move the pin and set it's info 157 double pinW = map_pin.getBoundsInLocal().getWidth(); 158 double pinH = map_pin.getBoundsInLocal().getHeight(); 159 map_pin.setLayoutX((Double) list.get(0) - (pinW / 2)); 160 map_pin.setLayoutY((Double) list.get(1) - (pinH)); 161 pin_info.setText((String) list.get(2)); 162 map_pin.setVisible(true); 163 } 164 165 @FXML 166 void zoomIn(ActionEvent event) { 167 // System.out.println("airportapp.Controller.zoomIn"); 168 double sliderVal = zoom_slider.getValue(); 169 zoom_slider.setValue(sliderVal += 0.1); 170 } 171 172 @FXML 173 void zoomOut(ActionEvent event) { 174 // System.out.println("airportapp.Controller.zoomOut"); 175 double sliderVal = zoom_slider.getValue(); 176 zoom_slider.setValue(sliderVal + -0.1); 177 } 178 179 private void zoom(double scaleValue) { 180 // System.out.println("airportapp.Controller.zoom, scaleValue: " + scaleValue); 181 double scrollH = map_scrollpane.getHvalue(); 182 double scrollV = map_scrollpane.getVvalue(); 183 zoomGroup.setScaleX(scaleValue); 184 zoomGroup.setScaleY(scaleValue); 185 map_scrollpane.setHvalue(scrollH); 186 map_scrollpane.setVvalue(scrollV); 187 } 188 189 @FXML 190 void stylingContrast(ActionEvent event) { 191 // System.out.println("airportapp.Controller.stylingContrast"); 192 if (contrast_togglebutton.isSelected() == true) { 193 root_vbox.getStyleClass().add("contrast"); 194 } else { 195 root_vbox.getStyleClass().remove("contrast"); 196 } 197 } 198 199 @FXML 200 void stylingSizing(ActionEvent event) { 201 // System.out.println("airportapp.Controller.stylingSizing"); 202 if (size_togglebutton.isSelected() == true) { 203 root_vbox.getStyleClass().add("touch-sizes"); 204 } else { 205 root_vbox.getStyleClass().remove("touch-sizes"); 206 } 207 } 208 209 } 210