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