1 /*
   2  * Copyright (c) 2008, 2018, 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 
  33 package ensemble.samples.language.swing;
  34 
  35 import java.awt.BorderLayout;
  36 import java.awt.Color;
  37 import java.awt.Component;
  38 import java.awt.Dimension;
  39 import java.text.DecimalFormat;
  40 import javafx.application.Platform;
  41 import javafx.beans.value.ChangeListener;
  42 import javafx.beans.value.ObservableValue;
  43 import javafx.collections.FXCollections;
  44 import javafx.collections.ObservableList;
  45 import javafx.embed.swing.JFXPanel;
  46 import javafx.event.ActionEvent;
  47 import javafx.event.EventHandler;
  48 import javafx.geometry.HPos;
  49 import javafx.geometry.Insets;
  50 import javafx.geometry.VPos;
  51 import javafx.scene.Scene;
  52 import javafx.scene.chart.BarChart;
  53 import javafx.scene.chart.CategoryAxis;
  54 import javafx.scene.chart.Chart;
  55 import javafx.scene.chart.NumberAxis;
  56 import javafx.scene.chart.XYChart;
  57 import javafx.scene.control.Button;
  58 import javafx.scene.control.Label;
  59 import javafx.scene.control.TextField;
  60 import javafx.scene.layout.ColumnConstraints;
  61 import javafx.scene.layout.GridPane;
  62 import javafx.scene.layout.Pane;
  63 import javafx.scene.layout.Priority;
  64 import javafx.scene.web.WebEngine;
  65 import javafx.scene.web.WebView;
  66 
  67 import javax.swing.JFrame;
  68 import javax.swing.JLabel;
  69 import javax.swing.JPanel;
  70 import javax.swing.JScrollPane;
  71 import javax.swing.JSplitPane;
  72 import javax.swing.JTable;
  73 import javax.swing.JTabbedPane;
  74 import javax.swing.SwingUtilities;
  75 import javax.swing.UIManager;
  76 import javax.swing.event.TableModelEvent;
  77 import javax.swing.event.TableModelListener;
  78 import javax.swing.table.DefaultTableCellRenderer;
  79 
  80 /**
  81  * SwingInterop
  82  *
  83  * Note using the browser might require setting the properties
  84  *  - http.proxyHost
  85  *  - http.proxyPort
  86  *
  87  * e.g. -Dhttp.proxyHost=webcache.mydomain.com -Dhttp.proxyPort=8080
  88  *
  89  */
  90 public class SwingInterop extends JPanel {
  91 
  92     private static final int PANEL_WIDTH = 675;
  93     private static final int PANEL_HEIGHT = 400;
  94     private static final int TABLE_PANEL_HEIGHT = 100;
  95     private static JFXPanel chartFxPanel;
  96     private static JFXPanel browserFxPanel;
  97     private static SampleTableModel tableModel;
  98     private Chart chart;
  99     private Pane browser;
 100 
 101     void initUI() {
 102         tableModel = new SampleTableModel();
 103         // create javafx panel for charts
 104         chartFxPanel = new JFXPanel();
 105         chartFxPanel.setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
 106 
 107         // create javafx panel for browser
 108         browserFxPanel = new JFXPanel();
 109 
 110         //create tabbed pane
 111         JTabbedPane tabbedPane = new JTabbedPane();
 112 
 113         //JTable
 114         JTable table = new JTable(tableModel);
 115         table.setAutoCreateRowSorter(true);
 116         table.setGridColor(Color.DARK_GRAY);
 117         DecimalFormatRenderer renderer = new DecimalFormatRenderer();
 118         renderer.setHorizontalAlignment(JLabel.RIGHT);
 119         for (int i = 0; i < table.getColumnCount(); i++) {
 120             table.getColumnModel().getColumn(i).setCellRenderer(renderer);
 121         }
 122         JScrollPane tablePanel = new JScrollPane(table);
 123         tablePanel.setPreferredSize(new Dimension(PANEL_WIDTH,
 124                                                   TABLE_PANEL_HEIGHT));
 125 
 126         JPanel chartTablePanel = new JPanel();
 127         chartTablePanel.setLayout(new BorderLayout());
 128 
 129         //Split pane that holds both chart and table
 130         JSplitPane jsplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
 131         jsplitPane.setTopComponent(chartTablePanel);
 132         jsplitPane.setBottomComponent(tablePanel);
 133         jsplitPane.setDividerLocation(410);
 134         chartTablePanel.add(chartFxPanel, BorderLayout.CENTER);
 135 
 136         tabbedPane.addTab("JavaFX Chart and Swing JTable", jsplitPane);
 137         tabbedPane.addTab("Web Browser", browserFxPanel);
 138 
 139         add(tabbedPane, BorderLayout.CENTER);
 140 
 141         // create JavaFX scene
 142         Platform.runLater(new Runnable() {
 143             public void run() {
 144                 createScene();
 145             }
 146         });
 147     }
 148 
 149     public static void main(String[] args) {
 150         SwingUtilities.invokeLater(new Runnable() {
 151 
 152             @Override
 153             public void run() {
 154                 try {
 155                     final String ui =
 156                         "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel";
 157                     UIManager.setLookAndFeel(ui);
 158                 } catch (Exception e) {}
 159 
 160                 JFrame frame = new JFrame("JavaFX in Swing");
 161                 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 162 
 163                 SwingInterop app = new SwingInterop();
 164                 app.initUI();
 165 
 166                 frame.setContentPane(app);
 167 
 168                 frame.pack();
 169                 frame.setLocationRelativeTo(null);
 170                 frame.setVisible(true);
 171             }
 172         });
 173     }
 174 
 175     private void createScene() {
 176         chart = createBarChart();
 177         chartFxPanel.setScene(new Scene(chart));
 178         browser = createBrowser();
 179         browserFxPanel.setScene(new Scene(browser));
 180     }
 181 
 182     private BarChart createBarChart() {
 183         CategoryAxis xAxis = new CategoryAxis();
 184         ObservableList<String> xCategories =
 185             FXCollections.observableArrayList(tableModel.getColumnNames());
 186         xAxis.setCategories(xCategories);
 187         xAxis.setLabel("Year");
 188 
 189         double tickUnit = tableModel.getTickUnit();
 190 
 191         NumberAxis yAxis = new NumberAxis();
 192         yAxis.setTickUnit(tickUnit);
 193         yAxis.setLabel("Units Sold");
 194 
 195         final BarChart bChart = new BarChart(xAxis, yAxis,
 196                                              tableModel.getBarChartData());
 197         final TableModelListener tableListener = (TableModelEvent e) -> {
 198                 if (e.getType() == TableModelEvent.UPDATE) {
 199                     final int row = e.getFirstRow();
 200                     final int column = e.getColumn();
 201                     final Object value =
 202                         ((SampleTableModel) e.getSource()).getValueAt(row,
 203                                                                       column);
 204                     Platform.runLater(new Runnable() {
 205                         @Override
 206                         public void run() {
 207                             XYChart.Series<String, Number> s =
 208                                 (XYChart.Series<String, Number>)
 209                                     bChart.getData().get(row);
 210                             BarChart.Data data = s.getData().get(column);
 211                             data.setYValue(value);
 212                         }
 213                     });
 214                 }
 215             };
 216         tableModel.addTableModelListener(tableListener);
 217         return bChart;
 218     }
 219 
 220     private Pane createBrowser() {
 221         Double widthDouble = new Integer(PANEL_WIDTH).doubleValue();
 222         Double heightDouble = new Integer(PANEL_HEIGHT).doubleValue();
 223         WebView view = new WebView();
 224         view.setMinSize(widthDouble, heightDouble);
 225         view.setPrefSize(widthDouble, heightDouble);
 226         final WebEngine eng = view.getEngine();
 227         final String message = "Do you need to specify web proxy information?";
 228         final Label warningLabel = new Label(message);
 229         eng.load("http://www.oracle.com/us/index.html");
 230 
 231         final ChangeListener<Number> handler =
 232             (ObservableValue<? extends Number> observable,
 233              Number oldValue, Number newValue) -> {
 234                 if (warningLabel.isVisible()) {
 235                     warningLabel.setVisible(false);
 236                 }
 237             };
 238         eng.getLoadWorker().progressProperty().addListener(handler);
 239 
 240         final String url = "http://www.oracle.com/us/index.html";
 241         final TextField locationField = new TextField(url);
 242         locationField.setMaxHeight(Double.MAX_VALUE);
 243         Button goButton = new Button("Go");
 244         goButton.setMinWidth(Button.USE_PREF_SIZE);
 245         goButton.setDefaultButton(true);
 246         EventHandler<ActionEvent> goAction = (ActionEvent event) -> {
 247                 eng.load(locationField.getText().startsWith("http://") ?
 248                          locationField.getText() :
 249                          "http://" + locationField.getText());
 250             };
 251         goButton.setOnAction(goAction);
 252         locationField.setOnAction(goAction);
 253         final ChangeListener<String> webListener =
 254             (ObservableValue<? extends String> observable,
 255              String oldValue, String newValue) -> {
 256                 locationField.setText(newValue);
 257             };
 258         eng.locationProperty().addListener(webListener);
 259         GridPane grid = new GridPane();
 260         grid.setPadding(new Insets(5));
 261         grid.setVgap(5);
 262         grid.setHgap(5);
 263         GridPane.setConstraints(locationField, 0, 0, 1, 1,
 264                                 HPos.CENTER, VPos.CENTER,
 265                                 Priority.ALWAYS, Priority.SOMETIMES);
 266         GridPane.setConstraints(goButton, 1, 0);
 267         GridPane.setConstraints(view, 0, 1, 2, 1,
 268                                 HPos.CENTER, VPos.CENTER,
 269                                 Priority.ALWAYS, Priority.ALWAYS);
 270         GridPane.setConstraints(warningLabel, 0, 2, 2, 1,
 271                                 HPos.CENTER, VPos.CENTER,
 272                                 Priority.ALWAYS, Priority.SOMETIMES);
 273         grid.getColumnConstraints().addAll(
 274                 new ColumnConstraints(widthDouble - 200, widthDouble - 200,
 275                                       Double.MAX_VALUE, Priority.ALWAYS,
 276                                       HPos.CENTER, true),
 277                 new ColumnConstraints(40, 40, 40,
 278                                       Priority.NEVER, HPos.CENTER, true));
 279         grid.getChildren().addAll(locationField, goButton, warningLabel, view);
 280         return grid;
 281     }
 282 
 283     private static class DecimalFormatRenderer extends DefaultTableCellRenderer {
 284         private static final DecimalFormat formatter = new DecimalFormat("#.0");
 285 
 286         @Override
 287         public Component getTableCellRendererComponent(JTable table, Object value,
 288                                                        boolean isSelected,
 289                                                        boolean hasFocus,
 290                                                        int row, int column) {
 291             value = formatter.format((Number) value);
 292             return super.getTableCellRendererComponent(table, value, isSelected,
 293                                                        hasFocus, row, column);
 294         }
 295     }
 296 }