001: /*
002: * Copyright (C) 2005 Jeff Tassin
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018:
019: package com.jeta.swingbuilder.gui.editor;
020:
021: import java.awt.Color;
022: import java.awt.Graphics;
023: import java.awt.Point;
024: import java.awt.Rectangle;
025:
026: import javax.swing.ImageIcon;
027: import javax.swing.JPanel;
028:
029: import com.jeta.forms.gui.form.FormComponent;
030: import com.jeta.forms.gui.form.GridCellEvent;
031: import com.jeta.forms.gui.form.GridCellListener;
032: import com.jeta.forms.gui.form.GridComponent;
033: import com.jeta.forms.gui.form.GridOverlay;
034: import com.jeta.forms.gui.form.GridView;
035: import com.jeta.open.registry.JETARegistry;
036: import com.jeta.open.resources.ResourceLoader;
037:
038: /**
039: * This component renders the grid lines on a form in the designer. This class
040: * is also responsible for drawing the blue selection rectangle for a selected
041: * component in the designer.
042: *
043: * @author Jeff Tassin
044: */
045: public class DesignGridOverlay extends JPanel implements
046: GridCellListener, GridOverlay {
047: /**
048: * The view associated with this overlay
049: */
050: private GridView m_view;
051:
052: /**
053: * The color of the grid lines
054: */
055: private Color m_grid_color;
056:
057: /**
058: * Line used to indicate resize of row or column
059: */
060: private ResizeIndicator m_resize_indicator;
061:
062: /**
063: * The selection rectangle inner color
064: */
065: private static Color m_sel_inner_color = new Color(241, 240, 227);
066:
067: /**
068: * The selection rectangle color
069: */
070: private static Color m_sel_color = Color.blue;
071:
072: /**
073: * Flag that indicates if the grid is visible or not. We don't use the
074: * setVisible/isVisible method of Component because the selected cell won't
075: * be repainted.
076: */
077: private boolean m_grid_visible = true;
078:
079: /**
080: * Icon for showing if a component is valid or not
081: */
082: private static ImageIcon m_invalid_image;
083:
084: static {
085: try {
086: ResourceLoader loader = (ResourceLoader) JETARegistry
087: .lookup(ResourceLoader.COMPONENT_ID);
088: m_invalid_image = loader
089: .loadImage("jeta.resources/images/forms/invalid_comp.gif");
090: } catch (Exception e) {
091: e.printStackTrace();
092: }
093: }
094:
095: /**
096: * Creates a <code>GridOverlay</code> instance.
097: *
098: * @param view
099: * the GridView that contains this overlay.
100: */
101: public DesignGridOverlay(GridView view) {
102: m_view = view;
103: m_grid_color = javax.swing.UIManager.getColor("control")
104: .darker();
105: setOpaque(false);
106: }
107:
108: /** GridCellListener implementation */
109: public void cellChanged(GridCellEvent evt) {
110: }
111:
112: public FormComponent getForm() {
113: return m_view.getParentForm();
114: }
115:
116: /**
117: * @return the grid cell that contains the given mouse point
118: */
119: public GridComponent getCell(Point mousePt) {
120: // @todo change to faster algorigthm if possible
121: for (int index = 0; index < m_view.getGridComponentCount(); index++) {
122: GridComponent gc = (GridComponent) m_view
123: .getGridComponent(index);
124: if (mousePt.x >= gc.getCellX()
125: && (mousePt.x < gc.getCellX() + gc.getCellWidth())
126: && mousePt.y >= gc.getCellY()
127: && (mousePt.y < gc.getCellY() + gc.getCellHeight())) {
128: return gc;
129: }
130: }
131: return null;
132: }
133:
134: /**
135: * @return the flag that indicates if the grid is visible or not.
136: */
137: public boolean isGridVisible() {
138: return m_grid_visible;
139: }
140:
141: /**
142: * Paints a small icon on the grid cell if the GridComponent is too small to
143: * be seen
144: */
145: private void paintInvalidIcon(Graphics g, GridComponent gc) {
146: java.awt.Graphics2D g2 = (java.awt.Graphics2D) g;
147: g2.drawImage(m_invalid_image.getImage(), gc.getCellX() + 2, gc
148: .getCellY() + 2, gc);
149: }
150:
151: /**
152: * Repaints the region occupied by the given component
153: */
154: public void repaint(GridComponent gc) {
155: repaint(gc.getCellX(), gc.getCellY(), gc.getCellWidth() + 1, gc
156: .getCellHeight() + 1);
157: }
158:
159: /**
160: * Shows/hides the grid
161: */
162: public void setGridVisible(boolean bvis) {
163: m_grid_visible = bvis;
164: repaint();
165: }
166:
167: void setResizeIndicator(ResizeIndicator indicator) {
168: m_resize_indicator = indicator;
169: }
170:
171: /**
172: * Override updateUI so we can update the grid lines color. It should be one
173: * shade darker than the current component background color. This method is
174: * invoked when the look and feel changes in the designer.
175: */
176: public void updateUI() {
177: super .updateUI();
178: if (m_grid_color != null) {
179: m_grid_color = javax.swing.UIManager.getColor("control")
180: .darker();
181: }
182: setBackground(javax.swing.UIManager.getColor("control"));
183: }
184:
185: private Rectangle m_gc_rect = new Rectangle();
186: private Rectangle m_clip_rect = new Rectangle();
187:
188: /**
189: * Paint routine that renders the grid lines. Only renders the grid lines
190: * that are contained in the clipping rectangle.
191: */
192: public void paintComponent(Graphics g) {
193: Color old_c = g.getColor();
194: g.setColor(m_grid_color);
195:
196: /**
197: * we need to increase the height of the clip rectangle by 2 pixels
198: * because the bottom line of the grid overlay is not painted for
199: * composite child views in some cases
200: */
201: Rectangle clip_rect = g.getClipBounds();
202:
203: m_clip_rect.setBounds(clip_rect.x - 1, clip_rect.y - 1,
204: clip_rect.width + 2, clip_rect.height + 2);
205: g.setClip(m_clip_rect.x, m_clip_rect.y, m_clip_rect.width,
206: m_clip_rect.height);
207: int clip_x1 = (int) m_clip_rect.x;
208: int clip_x2 = (int) m_clip_rect.x + m_clip_rect.width;
209: int clip_y1 = (int) m_clip_rect.y;
210: int clip_y2 = (int) m_clip_rect.y + m_clip_rect.height;
211:
212: /** now find the cells that need to be repainted */
213: int min_row = -1;
214: int max_row = -1;
215:
216: int min_col = -1;
217: int max_col = -1;
218:
219: for (int row = 1; row <= m_view.getRowCount(); row++) {
220: int row_y1 = m_view.getRowOrgY(row);
221: int row_y2 = row_y1 + m_view.getRowHeight(row);
222: if (clip_y1 >= row_y1 && clip_y1 <= row_y2) {
223: if (min_row < 0)
224: min_row = row;
225: else
226: max_row = row;
227: } else if (clip_y2 >= row_y1 && clip_y2 <= row_y2) {
228: if (min_row < 0)
229: min_row = row;
230: else
231: max_row = row;
232:
233: } else if (row_y1 >= clip_y1 && row_y2 <= clip_y2) {
234: // here, the row is contained entirely in the clip
235: if (min_row < 0)
236: min_row = row;
237: else
238: max_row = row;
239: }
240: }
241:
242: for (int col = 1; col <= m_view.getColumnCount(); col++) {
243: int col_x1 = m_view.getColumnOrgX(col);
244: int col_x2 = col_x1 + m_view.getColumnWidth(col);
245: if (clip_x1 >= col_x1 && clip_x1 <= col_x2) {
246: if (min_col < 0)
247: min_col = col;
248: else
249: max_col = col;
250: } else if (clip_x2 >= col_x1 && clip_x2 <= col_x2) {
251: if (min_col < 0)
252: min_col = col;
253: else
254: max_col = col;
255:
256: } else if (col_x1 >= clip_x1 && col_x2 <= clip_x2) {
257: // here, the col is contained entirely in the clip
258: if (min_col < 0)
259: min_col = col;
260: else
261: max_col = col;
262: }
263: }
264:
265: if (min_row < 0 || min_col < 0)
266: return;
267:
268: if (max_row < 0)
269: max_row = min_row;
270: if (max_col < 0)
271: max_col = min_col;
272:
273: if (isGridVisible()) {
274: for (int row = min_row; row <= max_row; row++) {
275: for (int col = min_col; col <= max_col; col++) {
276: GridComponent gc = (GridComponent) m_view
277: .getGridComponent(col, row);
278: if (gc != null && !gc.isSelected()) {
279: GridComponent overlap = m_view
280: .getOverlappingComponent(
281: gc.getColumn(), gc.getRow());
282: if (overlap == null) {
283: m_gc_rect.setBounds(gc.getCellX() - 1, gc
284: .getCellY() - 1,
285: gc.getCellWidth() + 2, gc
286: .getCellHeight() + 2);
287: if (m_gc_rect.intersects(m_clip_rect)) {
288: g.drawRect(gc.getCellX(),
289: gc.getCellY(), gc
290: .getCellWidth(), gc
291: .getCellHeight());
292: }
293: }
294: }
295: }
296: }
297: }
298:
299: /**
300: * Now draw the selection rectangle.
301: */
302: for (int row = min_row; row <= max_row; row++) {
303: for (int col = min_col; col <= max_col; col++) {
304: GridComponent gc = (GridComponent) m_view
305: .getGridComponent(col, row);
306: if (gc == null || !gc.isSelected())
307: gc = m_view.getOverlappingComponent(col, row);
308:
309: if (gc != null) {
310: if (gc.isSelected()) {
311: int gx = gc.getCellX();
312: int gy = gc.getCellY();
313: int gwidth = gc.getCellWidth();
314: int gheight = gc.getCellHeight();
315:
316: m_gc_rect.setBounds(gx, gy, gwidth, gheight);
317: if (m_gc_rect.intersects(m_clip_rect)) {
318: g.setColor(m_sel_color);
319: g.drawRect(gx, gy, gwidth, gheight);
320: g.setColor(m_sel_inner_color);
321: if ((gwidth > 2) && (gheight > 2)) {
322: g.drawRect(gx + 1, gy + 1, gwidth - 2,
323: gheight - 2);
324: }
325: }
326: }
327: if (!gc.isShowing()) {
328: paintInvalidIcon(g, gc);
329: }
330: }
331: }
332: }
333: g.setColor(old_c);
334: g.setClip(clip_rect.x, clip_rect.y, clip_rect.width,
335: clip_rect.height);
336:
337: if (m_resize_indicator != null) {
338: m_resize_indicator.paint(g);
339: }
340: }
341:
342: }
|