1 /*
   2  * Copyright (c) 2012, 2015, 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.content.driver;
  33 
  34 import com.oracle.javafx.scenebuilder.kit.util.Deprecation;
  35 import javafx.scene.control.skin.TableColumnHeader;
  36 import java.util.ArrayList;
  37 import java.util.Collections;
  38 import java.util.Iterator;
  39 import java.util.List;
  40 import java.util.Set;
  41 import javafx.geometry.BoundingBox;
  42 import javafx.geometry.Bounds;
  43 import javafx.geometry.Point2D;
  44 import javafx.scene.Node;
  45 import javafx.scene.control.TableColumnBase;
  46 import javafx.scene.control.TreeTableColumn;
  47 import javafx.scene.control.TreeTableView;
  48 
  49 /**
  50  * A temporary class that should extend TableViewDesignInfo and adds
  51  * some additional verbs for managing TableView at design time.
  52  * This could potentially move to TabDesignInfo some day.
  53  *
  54  */
  55 public class TreeTableViewDesignInfoX {
  56 
  57 
  58     public Bounds getColumnBounds(TreeTableColumn<?,?> treeTableColumn) {
  59         final TreeTableView<?> tv = treeTableColumn.getTreeTableView();
  60         final Bounds tb = tv.getLayoutBounds();
  61         final Bounds hb = getColumnHeaderBounds(treeTableColumn);
  62 
  63         //
  64         //           x0             x1
  65         //
  66         //     +--------------------------------------+
  67         // y0  |     +--------------+                 |
  68         //     |     |    header    |                 |
  69         //     |     +--------------+                 |
  70         //     +--------------------------------------+
  71         //     |                                      |
  72         //     |          table view content          |
  73         //     |                                      |
  74         // y1  +--------------------------------------+
  75         //
  76 
  77         final double x0 = hb.getMinX();
  78         final double x1 = hb.getMaxX();
  79         final double y0 = hb.getMinY();
  80         final double y1 = tb.getMaxY();
  81 
  82         return new BoundingBox(x0, y0, x1 - x0, y1 - y0);
  83     }
  84 
  85 
  86     public Bounds getColumnHeaderBounds(TreeTableColumn<?,?> treeTableColumn) {
  87         final TreeTableView<?> tv = treeTableColumn.getTreeTableView();
  88         final Node hn = getColumnNode(treeTableColumn);
  89         return Deprecation.localToLocal(hn, hn.getLayoutBounds(), tv);
  90     }
  91 
  92 
  93     public Node getColumnNode(TreeTableColumn<?,?> tableColumn) {
  94         assert tableColumn != null;
  95         assert tableColumn.getTreeTableView() != null;
  96 
  97 
  98         // Looks for the sub nodes which match the .column-header CSS selector
  99         final TreeTableView<?> tableView = tableColumn.getTreeTableView();
 100         final Set<Node> set = tableView.lookupAll(".column-header"); //NOI18N
 101 
 102         // Searches the result for the node associated to 'tableColumn'.
 103         // This item has (TableColumn.class, tableColumn) in its property list.
 104         Node result = null;
 105         final Iterator<Node> it = set.iterator();
 106         while ((result == null) && it.hasNext()) {
 107             Node n = it.next();
 108             assert n instanceof TableColumnHeader;
 109             final TableColumnBase<?,?> tc = ((TableColumnHeader)n).getTableColumn();
 110             if (tc == tableColumn) {
 111                 result = n;
 112             }
 113         }
 114 
 115         return result;
 116     }
 117 
 118 
 119     public <T> TreeTableColumn<T,?> lookupColumn(TreeTableView<T>  tableView, double sceneX, double sceneY) {
 120         TreeTableColumn<T,?> result = null;
 121 
 122         //
 123         //                     x
 124         //          +--------------------------------------+
 125         //          |    +----------------------------+    |
 126         // #1    y  |    |            header          |    |
 127         //          |    +----------------------------+    |
 128         //          |    +--------------+-------------+    |
 129         // #2    y  |    |    header    |    header   |    |
 130         //          |    +--------------+-------------+    |
 131         //          +--------------------------------------+
 132         //          |                                      |
 133         // #3    y  |          table view content          |
 134         //          |                                      |
 135         //          +--------------------------------------+
 136         //
 137 
 138         // Walk through the column to see if one contains 'x' vertical
 139         List<TreeTableColumn<T,?>> tableColumns = tableView.getColumns();
 140         List<TreeTableColumn<T,?>> columnPath = new ArrayList<>();
 141         while (tableColumns.isEmpty() == false) {
 142             final TreeTableColumn<T,?> tc = lookupColumn(tableColumns, sceneX);
 143             if (tc != null) {
 144                 columnPath.add(0, tc);
 145                 tableColumns = tc.getColumns();
 146             } else {
 147                 tableColumns = Collections.emptyList(); // To stop the loop
 148             }
 149         }
 150 
 151         if (columnPath.isEmpty()) {
 152             // No column contains sceneX
 153             result = null;
 154         } else {
 155             // Check if one column in columnPath contains (sceneX, sceneY)
 156             // => case #1 or #2
 157             for (TreeTableColumn<T,?> tc : columnPath) {
 158                 final Node headerNode = getColumnNode(tc);
 159                 final Bounds headerBounds = headerNode.getLayoutBounds();
 160                 final Point2D p = headerNode.sceneToLocal(sceneX, sceneY, true /* rootScene */);
 161                 if (headerBounds.contains(p)) {
 162                     result = tc;
 163                     break;
 164                 }
 165             }
 166 
 167             if (result == null) {
 168                 // No column in columnPath contains sceneX => case #3
 169                 result = columnPath.get(0);
 170             }
 171         }
 172 
 173         return result;
 174     }
 175 
 176 
 177     private <T> TreeTableColumn<T,?> lookupColumn(
 178             List<TreeTableColumn<T,?>> tableColumns, double sceneX) {
 179         TreeTableColumn<T,?> result = null;
 180 
 181         // Walk through the columns to see if one contains 'x' vertical
 182         for (TreeTableColumn<T,?> tc : tableColumns) {
 183             final Node headerNode = getColumnNode(tc);
 184             if (headerNode != null) {
 185                 final Bounds headerBounds = headerNode.getLayoutBounds();
 186                 final Point2D p = headerNode.sceneToLocal(sceneX, 0, true /* rootScene */);
 187                 if ((headerBounds.getMinX() <= p.getX())
 188                         && (p.getX() < headerBounds.getMaxX())) {
 189                     result = tc;
 190                     break;
 191                 }
 192             }
 193         }
 194 
 195         return result;
 196     }
 197 }