1   /****************************************************************************
2    * This demo file is part of yFiles for Java 2.14.
3    * Copyright (c) 2000-2017 by yWorks GmbH, Vor dem Kreuzberg 28,
4    * 72070 Tuebingen, Germany. All rights reserved.
5    * 
6    * yFiles demo files exhibit yFiles for Java functionalities. Any redistribution
7    * of demo files in source code or binary form, with or without
8    * modification, is not permitted.
9    * 
10   * Owners of a valid software license for a yFiles for Java version that this
11   * demo is shipped with are allowed to use the demo source code as basis
12   * for their own yFiles for Java powered applications. Use of such programs is
13   * governed by the rights and conditions as set out in the yFiles for Java
14   * license agreement.
15   * 
16   * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED
17   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19   * NO EVENT SHALL yWorks BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21   * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   *
27   ***************************************************************************/
28  package demo.layout.hierarchic;
29  
30  import demo.layout.hierarchic.CellSpanLayoutDemo.CellColorManager;
31  
32  import y.geom.YInsets;
33  import y.view.GenericNodeRealizer;
34  import y.view.MultiplexingNodeEditor;
35  import y.view.NodeRealizer;
36  import y.view.tabular.TableGroupNodeRealizer;
37  import y.view.tabular.TableGroupNodeRealizer.Column;
38  import y.view.tabular.TableGroupNodeRealizer.Row;
39  import y.view.tabular.TableGroupNodeRealizer.Table;
40  import y.view.tabular.TableNodePainter;
41  import y.view.tabular.TableSizeEditor;
42  
43  import java.awt.Color;
44  import java.awt.Graphics2D;
45  import java.awt.geom.Rectangle2D;
46  import java.io.IOException;
47  import java.io.ObjectInputStream;
48  import java.io.ObjectOutputStream;
49  import java.util.Map;
50  
51  /**
52   * Provides the visualization for cell designer table nodes.
53   * This visualization supports individual background colors for each table cell.
54   *
55   */
56  class CellSpanRealizerFactory {
57    /** Configuration ID for cell span designer table nodes. */
58    private static final String GRID_CONFIGURATION = "GRID_CONFIGURATION";
59  
60  
61    /**
62     * Prevents instantiation of factory class.
63     */
64    private CellSpanRealizerFactory() {
65    }
66  
67  
68    /**
69     * Registers the configuration used for cell designer table nodes.
70     */
71    static void initConfigurations() {
72      // configure the visualization of cell designer table nodes
73      final TableNodePainter painter = TableNodePainter.newDefaultInstance();
74      painter.setSubPainter(TableNodePainter.PAINTER_COLUMN_FOREGROUND, null);
75      painter.setSubPainter(TableNodePainter.PAINTER_COLUMN_BACKGROUND, null);
76      painter.setSubPainter(TableNodePainter.PAINTER_ROW_FOREGROUND, new CellPainter(true));
77      painter.setSubPainter(TableNodePainter.PAINTER_ROW_BACKGROUND, new CellPainter(false));
78      painter.setSubPainter(TableNodePainter.PAINTER_TABLE_BACKGROUND, new Background());
79  
80      final Map map = TableGroupNodeRealizer.createDefaultConfigurationMap();
81      map.put(GenericNodeRealizer.Painter.class, painter);
82      map.put(GenericNodeRealizer.UserDataHandler.class, new CellColorsDataHandler());
83  
84      // restrict interactive editing of cell designer table nodes to resizing
85      // the table's columns and rows
86      // especially re-ordering columns and rows is not supported preventing
87      // the possibility to nest columns in columns and/or rows in rows
88      final TableSizeEditor tableSizeEditor = new TableSizeEditor();
89      tableSizeEditor.setResizePolicy(TableSizeEditor.RESIZE_POLICY_IGNORE_CONTENT);
90      final MultiplexingNodeEditor editor = new MultiplexingNodeEditor();
91      editor.addNodeEditor(tableSizeEditor);
92      map.put(GenericNodeRealizer.GenericMouseInputEditorProvider.class, editor);
93  
94  
95      // register the configuration
96      GenericNodeRealizer.getFactory().addConfiguration(GRID_CONFIGURATION, map);
97    }
98  
99  
100   /**
101    * Paints the background of a cell designer table node.
102    * The main cell area, i.e. the intersection of the union of all columns and
103    * the union of all rows, is filled with the node's main fill color.
104    * The border area, i.e. column top and bottom insets and row left and right
105    * insets, is fill with the node's secondary fill color.
106    */
107   private static final class Background implements GenericNodeRealizer.Painter {
108     /**
109      * Paints the table area represented by the given node realizer in
110      * high-detail mode. Delegates painting to
111      * {@link #paintImpl(y.view.NodeRealizer, java.awt.Graphics2D)}.
112      */
113     public void paint(final NodeRealizer dummy, final Graphics2D gfx) {
114       paintImpl(dummy, gfx);
115     }
116 
117     /**
118      * Paints the table area represented by the given node realizer in
119      * low-detail mode. Delegates painting to
120      * {@link #paintImpl(y.view.NodeRealizer, java.awt.Graphics2D)}.
121      */
122     public void paintSloppy(final NodeRealizer dummy, final Graphics2D gfx) {
123       paintImpl(dummy, gfx);
124     }
125 
126     /**
127      * Paints the table area represented by the given node realizer.
128      */
129     private void paintImpl(final NodeRealizer dummy, final Graphics2D gfx) {
130       final Color oldColor = gfx.getColor();
131 
132       final Rectangle2D.Double bnds = new Rectangle2D.Double(
133               dummy.getX(), dummy.getY(), dummy.getWidth(), dummy.getHeight());
134 
135       // at this point, the dummy geometry should match the whole table
136       // node geometry
137       final Color fc2 = dummy.getFillColor2();
138       if (fc2 != null) {
139         gfx.setColor(fc2);
140         gfx.fill(bnds);
141       }
142 
143       // paint the main cell area
144       final Color fc = dummy.getFillColor();
145       if (fc != null) {
146         final Table table = TableNodePainter.getTable(dummy);
147 
148         // all the sample diagrams that can be used in CellSpanLayoutDemo
149         // used uniform insets (i.e. all columns and all rows have the same
150         // inset on all sides)
151         // moreover, there are no columns in columns or rows in rows in the
152         // aforementioned samples
153         // therefore, the main cell area is simply the bounds of the table
154         // node minus those insets
155         final YInsets cInsets = table.getColumn(0).getInsets();
156         final YInsets rInsets = table.getRow(0).getInsets();
157 
158         bnds.setFrame(
159                 bnds.getX() + rInsets.left,
160                 bnds.getY() + cInsets.top,
161                 bnds.getWidth() - rInsets.left - rInsets.right,
162                 bnds.getHeight() - cInsets.top - cInsets.bottom);
163         gfx.setColor(fc);
164         gfx.fill(bnds);
165       }
166 
167       gfx.setColor(oldColor);
168     }
169   }
170 
171   /**
172    * Paints individual cells in a cell designer table node.
173    * This painter has to be used as {@link TableNodePainter} subordinate
174    * painter for rows.
175    */
176   private static final class CellPainter implements GenericNodeRealizer.Painter {
177     /**
178      * Determines whether to paint cell foregrounds or colored cell background.
179      */
180     private final boolean foreground;
181 
182     /**
183      * Initializes a new <code>CellPainter</code> instance.
184      */
185     CellPainter( final boolean foreground ) {
186       this.foreground = foreground;
187     }
188 
189     /**
190      * Paints table cells in high-detail mode. Delegates painting to
191      * {@link #paintImpl(y.view.NodeRealizer, java.awt.Graphics2D)}.
192      */
193     public void paint(final NodeRealizer dummy, final Graphics2D gfx) {
194       paintImpl(dummy, gfx);
195     }
196 
197     /**
198      * Paints table cells in low-detail mode. Delegates painting to
199      * {@link #paintImpl(y.view.NodeRealizer, java.awt.Graphics2D)}.
200      */
201     public void paintSloppy(final NodeRealizer dummy, final Graphics2D gfx) {
202       paintImpl(dummy, gfx);
203     }
204 
205     /**
206      * Paints table cells. This method assumes to be used as a
207      * {@link TableNodePainter} subordinate painter for rows.
208      */
209     private void paintImpl(final NodeRealizer dummy, final Graphics2D gfx) {
210       final Row row = TableNodePainter.getRow(dummy);
211 
212       double x = dummy.getX();
213       final double y = dummy.getY();
214       final double h = dummy.getHeight();
215       final Rectangle2D.Double bnds = new Rectangle2D.Double(
216               x, y, dummy.getWidth(), h);
217       final YInsets insets = row.getInsets();
218       x += insets.left;
219 
220       final Color oldColor = gfx.getColor();
221 
222       final Table table = TableNodePainter.getTable(dummy);
223       final Color fg = dummy.getLineColor();
224       final CellColorManager manager = CellColorManager.getInstance(table);
225       for (int i = 0, n = table.columnCount(); i < n; ++i) {
226         final Column col = table.getColumn(i);
227         final Color color = foreground ? fg : manager.getCellColor(col, row);
228         final double w = col.getWidth();
229         if (color != null) {
230           bnds.setFrame(x, y, w, h);
231           gfx.setColor(color);
232           if (foreground) {
233             gfx.draw(bnds);
234           } else {
235             gfx.fill(bnds);
236           }
237         }
238         x += w;
239       }
240 
241       gfx.setColor(oldColor);
242     }
243   }
244 
245   /**
246    * Copies user data of type {@link CellColorManager} from one
247    * realizer to another.
248    */
249   private static final class CellColorsDataHandler
250           implements GenericNodeRealizer.UserDataHandler {
251     /**
252      * Writes user data in <code>YGF</code> file format.
253      * @throws UnsupportedOperationException <code>YGF</code> is not supported. 
254      */
255     public void storeUserData(
256             final NodeRealizer context, final Object userData, final ObjectOutputStream oos
257     ) throws IOException {
258       throw new UnsupportedOperationException();
259     }
260 
261     /**
262      * Reads user data from <code>YGF</code> file format.
263      * @throws UnsupportedOperationException <code>YGF</code> is not supported. 
264      */
265     public Object readUserData(
266             final NodeRealizer context, final ObjectInputStream ois
267     ) throws IOException {
268       throw new UnsupportedOperationException();
269     }
270 
271     /**
272      * Copies user data of type {@link CellColorManager} from one
273      * realizer to another.
274      */
275     public Object copyUserData(
276             final NodeRealizer srcContext,
277             final Object srcData,
278             final NodeRealizer targetContext
279     ) {
280       return new CellColorManager((CellColorManager) srcData);
281     }
282   }
283 }
284