001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.sql.framework.ui.graph.impl;
042:
043: import java.awt.Color;
044: import java.awt.Dimension;
045: import java.awt.Graphics2D;
046: import java.awt.Insets;
047: import java.awt.Rectangle;
048: import java.util.ArrayList;
049: import java.util.Iterator;
050:
051: import org.netbeans.modules.sql.framework.ui.graph.IGraphInterface;
052:
053: import com.nwoods.jgo.JGoBrush;
054: import com.nwoods.jgo.JGoDrawable;
055: import com.nwoods.jgo.JGoObject;
056: import com.nwoods.jgo.JGoPen;
057: import com.nwoods.jgo.JGoRectangle;
058: import com.nwoods.jgo.JGoView;
059:
060: /**
061: * @author Ritesh Adval
062: * @version $Revision$
063: */
064: public class ColumnPortArea extends CanvasArea {
065: /**
066: * constant that describe that this area has ports on left side of it
067: */
068: public static final int LEFT_PORT_AREA = 0;
069:
070: /**
071: * constant that describe that this area has ports on right side of it
072: */
073: public static final int RIGHT_PORT_AREA = 1;
074:
075: private static final JGoPen DEFAULT_PEN = JGoPen
076: .makeStockPen(Color.WHITE);
077:
078: private ArrayList columnPorts;
079: private JGoRectangle rect;
080: //default --> a ColumnPortArea can be both source and destination of a link
081: private int columnPortAlignment = 2;
082: private int vSpace = 1;
083: private JGoPen linePen = null;
084: private boolean expanded = true;
085:
086: //constants for first , last visible row
087: private int firstVisibleRow = 0;
088: private int lastVisibleRow = -1;
089:
090: private boolean drawBoundingRect = true;
091:
092: /**
093: * Creates a new instance of ColumnPortArea
094: *
095: * @param alignment alignment
096: * @param rows number of rows
097: */
098: public ColumnPortArea(int alignment, int rows) {
099: super ();
100: this .setSelectable(false);
101: this .setResizable(false);
102:
103: this .rect = new JGoRectangle();
104: rect.setSelectable(false);
105: rect.setResizable(false);
106:
107: rect.setPen(DEFAULT_PEN);
108: rect
109: .setBrush(JGoBrush.makeStockBrush(new Color(254, 253,
110: 235)));
111: this .addObjectAtTail(rect);
112:
113: this .columnPortAlignment = alignment;
114: columnPorts = new ArrayList();
115: addPorts(rows);
116:
117: this .insets = new Insets(1, 0, 0, 0);
118:
119: }
120:
121: /**
122: * add port areas to this area
123: *
124: * @param rows number of port areas to be added
125: */
126: public void addPorts(int rows) {
127: for (int i = 0; i < rows; i++) {
128: PortArea pArea = new PortArea();
129: if (columnPortAlignment == LEFT_PORT_AREA) {
130: pArea.setValidDestination(true);
131: pArea.setValidSource(false);
132: } else if (columnPortAlignment == RIGHT_PORT_AREA) {
133: pArea.setValidSource(true);
134: pArea.setValidDestination(false);
135: }
136:
137: this .addObjectAtTail(pArea);
138: columnPorts.add(pArea);
139: layoutChildren();
140: }
141: }
142:
143: public void addPort() {
144: PortArea pArea = new PortArea();
145: pArea.setLocation(this .getLeft(), this .getTop()
146: + this .getMaximumHeight());
147: if (columnPortAlignment == LEFT_PORT_AREA) {
148: pArea.setValidDestination(true);
149: pArea.setValidSource(false);
150: } else if (columnPortAlignment == RIGHT_PORT_AREA) {
151: pArea.setValidSource(true);
152: pArea.setValidDestination(false);
153: }
154:
155: this .addObjectAtTail(pArea);
156: columnPorts.add(pArea);
157: }
158:
159: public void addPort(int row) {
160: if (row < 0 || row > columnPorts.size()) {
161: throw new IllegalArgumentException(
162: "Can not add port, specified row " + row
163: + " does not exist.");
164: }
165:
166: PortArea pArea = new PortArea();
167: pArea.setLocation(this .getLeft(), this .getTop()
168: + this .getMaximumHeight());
169: if (columnPortAlignment == LEFT_PORT_AREA) {
170: pArea.setValidDestination(true);
171: pArea.setValidSource(false);
172: } else if (columnPortAlignment == RIGHT_PORT_AREA) {
173: pArea.setValidSource(true);
174: pArea.setValidDestination(false);
175: }
176:
177: this .addObjectAtTail(pArea);
178: columnPorts.add(row, pArea);
179: }
180:
181: public void removePort(int row) {
182: if (row < 0 || row >= columnPorts.size()) {
183: throw new IllegalArgumentException(
184: "Can not remove port, specified row " + row
185: + " does not exist.");
186: }
187: PortArea pArea = (PortArea) columnPorts.get(row);
188: this .removeObject(pArea);
189: columnPorts.remove(row);
190: }
191:
192: /**
193: * get the index of a port area
194: *
195: * @param pArea port area
196: * @return port area index
197: */
198: public int getIndexOf(PortArea pArea) {
199: for (int i = 0; i < columnPorts.size(); i++) {
200: PortArea portArea = (PortArea) columnPorts.get(i);
201: if (portArea.equals(pArea)) {
202: return i;
203: }
204: }
205:
206: return -1;
207: }
208:
209: /**
210: * get the port area at an index
211: *
212: * @param row row index
213: * @return port area
214: */
215: public PortArea getPortAreaAt(int row) {
216: if (row < columnPorts.size()) {
217: return (PortArea) columnPorts.get(row);
218: }
219: return null;
220: }
221:
222: /**
223: * get the graphical bound rectangle
224: *
225: * @return graphical bound rectangle
226: */
227: public JGoRectangle getRect() {
228: return rect;
229: }
230:
231: /**
232: * get the number of rows in this column area
233: *
234: * @return number of rows in this column
235: */
236: public int getRowCount() {
237: if (columnPorts == null) {
238: return -1;
239: }
240: return columnPorts.size();
241: }
242:
243: /**
244: * get first visible row index
245: *
246: * @return first visible row index
247: */
248: public int getFirstVisibleRow() {
249: return firstVisibleRow;
250: }
251:
252: /**
253: * set the first visible row index
254: *
255: * @param rowIdx row index
256: */
257: public void setFirstVisibleRow(int rowIdx) {
258: int oldIndex = firstVisibleRow;
259:
260: if (rowIdx >= 0 && rowIdx <= getRowCount()
261: && oldIndex != rowIdx) {
262: firstVisibleRow = rowIdx;
263: layoutChildren();
264: }
265: }
266:
267: /**
268: * get the last visible row index
269: *
270: * @return last visible row index
271: */
272: public int getLastVisibleRow() {
273: return lastVisibleRow;
274: }
275:
276: /**
277: * is area expanded
278: *
279: * @return whether area is expanded
280: */
281: public boolean isExpanded() {
282: return expanded;
283: }
284:
285: /**
286: * set whether container table is expanded
287: *
288: * @param sExpanded expanded or collapsed
289: */
290: public void setExpanded(boolean sExpanded) {
291: this .expanded = sExpanded;
292: }
293:
294: /**
295: * get the line pen
296: *
297: * @return pen
298: */
299: public JGoPen getLinePen() {
300: return (linePen != null) ? linePen : DEFAULT_PEN;
301: }
302:
303: /**
304: * set the line pen for drawing border
305: *
306: * @param pen pen
307: */
308: public void setLinePen(JGoPen pen) {
309: JGoPen oldPen = linePen;
310: if (oldPen != pen) {
311: linePen = pen;
312: layoutChildren();
313: }
314: }
315:
316: public int getMaximumHeight() {
317: Iterator it = columnPorts.iterator();
318: //this is the width of widest PortArea
319: int h = 0;
320:
321: while (it.hasNext()) {
322: PortArea pArea = (PortArea) it.next();
323: int height = pArea.getHeight();
324: h += height + getVerticalSpacing();
325:
326: }
327: //remove one extra vertical space
328: if (columnPorts.size() > 0) {
329: h -= getVerticalSpacing();
330: }
331:
332: return h;
333: }
334:
335: /**
336: * get the maximum width of a PortArea in this area
337: *
338: * @return maximum PortArea width
339: */
340: public int getMaximizePortAreaWidth() {
341: Iterator it = columnPorts.iterator();
342: //this is the width of widest PortArea
343: int w = 0;
344:
345: while (it.hasNext()) {
346: PortArea pArea = (PortArea) it.next();
347: int width = pArea.getWidth();
348: if (width > w) {
349: w = width;
350: }
351: }
352:
353: return w;
354: }
355:
356: /**
357: * get the maximum height of a PortArea in this area
358: *
359: * @return maximum PortArea height
360: */
361: public int getMaximizePortAreaHeight() {
362: Iterator it = columnPorts.iterator();
363: //this is the height of tallest PortArea
364: int h = 0;
365:
366: while (it.hasNext()) {
367: PortArea pArea = (PortArea) it.next();
368:
369: int height = pArea.getHeight();
370: if (height > h) {
371: h = height;
372: }
373: }
374:
375: return h;
376: }
377:
378: /**
379: * calculate the minimum size for the columnRect , as determined by the maximum item
380: * size plus the insets
381: *
382: * @return minimum size
383: */
384: public Dimension getMinimumRectSize() {
385: int maxW = getMaximizePortAreaWidth();
386: int maxH = getMaximizePortAreaHeight();
387:
388: // now account for insets on all sides
389: Insets insets1 = getInsets();
390:
391: int minw = maxW + insets1.left + insets1.right;
392: int minh = maxH + insets1.top + insets1.bottom;
393: return new Dimension(minw, minh);
394: }
395:
396: /**
397: * get the minimum size
398: *
399: * @return minimum size
400: */
401: public Dimension getMinimumSize() {
402: // first account for the minimum ListAreaRect size
403: Dimension minRect = getMinimumRectSize();
404: return minRect;
405: }
406:
407: /**
408: * set the port area height at an index
409: *
410: * @param row row index
411: * @param height height
412: */
413: public void setPortAreaHeight(int row, int height) {
414: if (columnPorts.size() > row) {
415: PortArea pArea = (PortArea) columnPorts.get(row);
416: pArea.setHeight(height);
417: }
418: }
419:
420: /**
421: * paint this area
422: *
423: * @param g Graphics2D
424: * @param view view
425: */
426: public void paint(Graphics2D g, JGoView view) {
427: super .paint(g, view);
428:
429: int penwidth = 0;
430: if (getLinePen() != null) {
431: penwidth = getLinePen().getWidth();
432: }
433: if (penwidth == 0) {
434: return;
435: }
436: JGoObject r = getRect();
437: if (r == null) {
438: return; // not yet initialized
439: }
440: Insets insets1 = getInsets();
441:
442: int rectleft = r.getLeft();
443: int recttop = r.getTop();
444: int rectwidth = r.getWidth();
445: int rectheight = r.getHeight();
446:
447: int top = recttop + insets1.top;
448: int height = rectheight - insets1.top - insets1.bottom;
449:
450: int limit = 0;
451: limit = height;
452:
453: int s = 0; // height/width of visible items so far
454: // do not allow to draw a line for last item...
455: // it will be taken care by bounding rectangle
456: for (int i = 0; i < columnPorts.size() - 1; i++) {
457:
458: PortArea cell = (PortArea) columnPorts.get(i);
459: int h = cell.getHeight();
460: s += h;
461: int sep = Math.max(penwidth, getVerticalSpacing());
462: if (s + sep <= limit) {
463: JGoDrawable.drawLine(g, getLinePen(), rectleft, top + s
464: + sep / 2, rectleft + rectwidth, top + s + sep
465: / 2);
466: }
467: s += sep;
468: }
469:
470: }
471:
472: /**
473: * override this method to handle the changes in the geometry of this area we will lay
474: * out all the columns and headers again
475: *
476: * @param prevRect previous bounds rectangle
477: */
478: protected void geometryChange(Rectangle prevRect) {
479: // handle any size changes by repositioning all the items
480: if (prevRect.width != getWidth()
481: || prevRect.height != getHeight()) {
482: layoutChildren();
483: } else {
484: super .geometryChange(prevRect);
485: }
486: }
487:
488: /**
489: * handle child geometry change. This will ignore changes in child geometry as none if
490: * its children are resizable
491: *
492: * @param child child
493: * @param prevRect previous rectangle
494: */
495:
496: protected boolean geometryChangeChild(JGoObject child,
497: Rectangle prevRect) {
498: //do nothing as we do not want to listen to changes in children
499: return true;
500: }
501:
502: /**
503: * layout all of this children of this column area
504: */
505: public void layoutChildren() {
506: rect.setPen(getLinePen());
507:
508: if (drawBoundingRect) {
509: rect.setBoundingRect(this .getBoundingRect());
510: }
511: Insets insets1 = getInsets();
512:
513: int x = this .getLeft() + insets1.left;
514: int y = this .getTop() + insets1.top;
515: int height = this .getHeight() - insets1.top - insets1.bottom;
516:
517: // remember last visible row index
518: lastVisibleRow = getFirstVisibleRow();
519:
520: //get the cell with maximum width, this will be the width of the column
521: int cellWidth = this .getMaximizePortAreaWidth();
522:
523: //calculate the top of next cell
524: int nextCellDeltaTop = 0;
525: Iterator it = columnPorts.iterator();
526:
527: //row count
528: int cnt = 0;
529:
530: while (it.hasNext()) {
531: PortArea pArea = (PortArea) it.next();
532:
533: if (cnt < getFirstVisibleRow()) {
534: pArea.setVisible(false);
535: JGoObject parent = this .getParent();
536: if (parent != null && parent instanceof IGraphInterface) {
537: Rectangle cellBounds = ((IGraphInterface) parent)
538: .getTitleAreaBounds();
539: if (columnPortAlignment == TableConstants.LEFT_PORT_AREA) {
540: pArea.setLocation(cellBounds.x, cellBounds.y);
541: } else {
542: pArea.setLocation(cellBounds.x
543: + cellBounds.width - pArea.getWidth(),
544: cellBounds.y);
545: }
546: }
547: cnt++;
548: continue;
549: }
550:
551: //if cell is going out of the height of this area
552: //then we mark it invisible
553: if (nextCellDeltaTop + pArea.getHeight() > height) {
554: pArea.setVisible(false);
555: JGoObject parent = this .getParent();
556: if (parent != null && parent instanceof IGraphInterface) {
557: Rectangle cellBounds = ((IGraphInterface) parent)
558: .getTitleAreaBounds();
559: if (columnPortAlignment == TableConstants.LEFT_PORT_AREA) {
560: pArea.setLocation(cellBounds.x, cellBounds.y);
561: } else {
562: pArea.setLocation(cellBounds.x
563: + cellBounds.width - pArea.getWidth(),
564: cellBounds.y);
565: }
566: }
567: continue;
568: }
569:
570: pArea.setVisible(true);
571: pArea.setBoundingRect(x, y + nextCellDeltaTop, cellWidth,
572: pArea.getHeight());
573:
574: nextCellDeltaTop += pArea.getHeight()
575: + getVerticalSpacing();
576: cnt++;
577: }
578: }
579:
580: /**
581: * get the vertical space between port area of this area
582: *
583: * @return vertical space
584: */
585: int getVerticalSpacing() {
586: return vSpace;
587: }
588:
589: public void setBackgroundColor(Color c) {
590: if (this .rect != null) {
591: this .rect.setBrush(JGoBrush.makeStockBrush(c));
592: }
593:
594: Iterator it = this .columnPorts.iterator();
595: while (it.hasNext()) {
596: PortArea p = (PortArea) it.next();
597: p.setBackgroundColor(c);
598: }
599: }
600: }
|