001: /*
002: * Copyright (c) 2004 JETA Software, Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without modification,
005: * are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JETA Software nor the names of its contributors may
015: * be used to endorse or promote products derived from this software without
016: * specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
021: * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
022: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
023: * INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
024: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
025: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026: * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: */
029:
030: package com.jeta.forms.gui.form;
031:
032: import java.util.Iterator;
033:
034: import com.jeta.forms.gui.common.FormUtils;
035:
036: /**
037: * This class maintains an array of GridComponents for a given view. It is used
038: * to quickly find a component at a given cell row/column position.
039: * Additionally, it can find out any components that overlap a given row/column
040: * position of those componenents have rowspan/columnspans greater than 1. We
041: * need this class because the current FormLayout does not fully provide this
042: * information, and the information it does provide is a copy. This makes it
043: * terribly inefficient to use when repainting, so we need this cache mainly for
044: * performance.
045: *
046: * @author Jeff Tassin
047: */
048: public class CellAssignmentCache {
049: /**
050: * The view which we are caching cell assignments
051: */
052: private GridView m_view;
053:
054: /**
055: * An array of row/col assignment objects.
056: */
057: private CellAssignment[][] m_grid;
058:
059: /**
060: * Creates a <code>CellAssignmentCache</code> that is associated with the
061: * specified view.
062: *
063: * @param view
064: * the GridView that this cache maintains information for.
065: */
066: public CellAssignmentCache(GridView view) {
067: m_view = view;
068: }
069:
070: /**
071: * Adds the specified component to this cache.
072: *
073: * @param gc
074: * the component to add to the cache.
075: */
076: void addComponent(GridComponent gc) {
077: checkGrid();
078:
079: if (gc == null) {
080: FormUtils.safeAssert(false);
081: return;
082: }
083:
084: CellAssignment ca = m_grid[gc.getRow() - 1][gc.getColumn() - 1];
085: if (ca == null) {
086: ca = new CellAssignment();
087: ca.m_comp = gc;
088: m_grid[gc.getRow() - 1][gc.getColumn() - 1] = ca;
089: } else {
090: ca.m_comp = gc;
091: }
092:
093: int rowstart = gc.getRow();
094: int colstart = gc.getColumn();
095: int rowspan = gc.getRowSpan();
096: int colspan = gc.getColumnSpan();
097: if (rowspan > 1 || colspan > 1) {
098: for (int row = rowstart; row <= (rowstart + rowspan - 1); row++) {
099: for (int col = colstart; col <= (colstart + colspan - 1); col++) {
100: if (row != rowstart || col != colstart) {
101: CellAssignment ova = m_grid[row - 1][col - 1];
102: if (ova == null) {
103: ova = new CellAssignment();
104: m_grid[row - 1][col - 1] = ova;
105: }
106: ova.m_overlap = gc;
107: }
108: }
109: }
110: }
111: }
112:
113: /**
114: * Checks that the grid size matches the view settings.
115: */
116: private void checkGrid() {
117: int columncount = m_view.getColumnCount();
118: int rowcount = m_view.getRowCount();
119: if (m_grid == null || m_grid[0].length != columncount
120: || m_grid.length != rowcount) {
121: resync();
122: }
123: }
124:
125: /**
126: * Returns the GridComponent object that is located at the give column and
127: * row.
128: *
129: * @return the component that occupies the cell at the given row/column.
130: * Null is returned if the specified cell does not have a
131: * GridComponent.
132: */
133: public GridComponent getGridComponent(int col, int row) {
134: checkGrid();
135: try {
136: CellAssignment ca = m_grid[row - 1][col - 1];
137: if (ca == null)
138: return null;
139: return ca.m_comp;
140: } catch (Exception e) {
141: resync();
142: return null;
143: }
144: }
145:
146: /**
147: * Returns the component, if any, that overlaps the given cell.
148: *
149: * @param col
150: * the column for the specified cell
151: * @param row
152: * the row for the specified cell.
153: * @return the component that overlaps the cell at the given column and row.
154: * If no component overlaps, then null is returned.
155: */
156: public GridComponent getOverlappingComponent(int col, int row) {
157: checkGrid();
158:
159: CellAssignment ca = m_grid[row - 1][col - 1];
160: FormUtils.safeAssert(ca != null);
161: FormUtils.safeAssert(ca.m_comp.getRow() == row);
162: FormUtils.safeAssert(ca.m_comp.getColumn() == col);
163: if (ca != null) {
164: return ca.m_overlap;
165: }
166: return null;
167: }
168:
169: /**
170: * Marks the cache as invalid.
171: */
172: void sync() {
173: m_grid = null;
174: }
175:
176: /**
177: * Updates the cell assignments array if anything on the view or the view
178: * itself has changed.
179: */
180: private void resync() {
181: int columncount = m_view.getColumnCount();
182: int rowcount = m_view.getRowCount();
183: if (m_grid == null || m_grid[0].length != columncount
184: || m_grid.length != rowcount) {
185: m_grid = new CellAssignment[rowcount][columncount];
186: } else {
187: for (int row = 0; row < rowcount; row++) {
188: for (int col = 0; col < columncount; col++) {
189: m_grid[row][col] = null;
190: }
191: }
192: }
193:
194: Iterator iter = m_view.gridIterator();
195: while (iter.hasNext()) {
196: Object obj = iter.next();
197: if (!(obj instanceof GridComponent)) {
198: continue;
199: }
200: GridComponent gc = (GridComponent) obj;
201: if (gc.getColumn() > columncount || gc.getRow() > rowcount) {
202: FormUtils.safeAssert(false);
203: }
204: addComponent(gc);
205: }
206: }
207:
208: /**
209: * This class is used to hold a GridComponet and is used to associate a
210: * component that might overlap a component at a given cell.
211: */
212: private static class CellAssignment {
213: /**
214: * A grid component at a given column,row in the grid.
215: */
216: GridComponent m_comp;
217:
218: /**
219: * A compnent that overlaps the above grid component ( m_comp ). This is
220: * null if m_comp does not have an overlapping component.
221: */
222: GridComponent m_overlap;
223: }
224: }
|