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.view.graph;
042:
043: import java.awt.Color;
044: import java.awt.Rectangle;
045: import java.awt.event.ActionEvent;
046: import java.awt.event.ActionListener;
047: import java.awt.event.ItemEvent;
048: import java.awt.event.ItemListener;
049: import java.net.URL;
050: import java.util.HashMap;
051: import java.util.Iterator;
052: import java.util.Map;
053: import java.util.MissingResourceException;
054: import java.util.Vector;
055:
056: import javax.swing.Icon;
057: import javax.swing.ImageIcon;
058: import javax.swing.JMenuItem;
059: import javax.swing.JPopupMenu;
060:
061: import org.netbeans.modules.sql.framework.model.SQLConnectableObject;
062: import org.netbeans.modules.sql.framework.model.SQLGenericOperator;
063: import org.netbeans.modules.sql.framework.model.SQLLiteral;
064: import org.netbeans.modules.sql.framework.model.SQLObject;
065: import org.netbeans.modules.sql.framework.model.SQLOperator;
066: import org.netbeans.modules.sql.framework.model.impl.SQLCustomOperatorImpl;
067: import org.netbeans.modules.sql.framework.ui.graph.ICommand;
068: import org.netbeans.modules.sql.framework.ui.graph.IGraphFieldNode;
069: import org.netbeans.modules.sql.framework.ui.graph.IGraphPort;
070: import org.netbeans.modules.sql.framework.ui.graph.IOperatorField;
071: import org.netbeans.modules.sql.framework.ui.graph.IOperatorXmlInfo;
072: import org.netbeans.modules.sql.framework.ui.graph.impl.BasicCellArea;
073: import org.netbeans.modules.sql.framework.ui.graph.impl.BasicComboBoxArea;
074: import org.netbeans.modules.sql.framework.ui.graph.impl.CanvasArea;
075: import org.netbeans.modules.sql.framework.ui.graph.impl.OperatorGraphFieldNode;
076: import org.netbeans.modules.sql.framework.ui.graph.impl.OperatorGraphNode;
077:
078: import com.nwoods.jgo.JGoBrush;
079: import com.nwoods.jgo.JGoPen;
080: import com.nwoods.jgo.JGoText;
081: import com.sun.sql.framework.exception.BaseException;
082: import net.java.hulp.i18n.Logger;
083: import org.netbeans.modules.etl.logger.Localizer;
084: import org.netbeans.modules.etl.logger.LogUtil;
085:
086: /**
087: * Graphical representation of a SQL operator.
088: *
089: * @author Ritesh Adval
090: * @author Jonathan Giron
091: */
092: public class SQLOperatorGraphNode extends OperatorGraphNode implements
093: ItemListener {
094:
095: protected static final JGoPen PEN_DEFAULT = JGoPen
096: .makeStockPen(Color.WHITE);
097:
098: protected static final Color COLOR_BG_OUTPUT = new Color(236, 217,
099: 217); // pink
100:
101: protected static final Color COLOR_BG_INPUT = new Color(240, 240,
102: 240); // light gray
103:
104: protected static final Color COLOR_BG_INPUT_HOVER = new Color(254,
105: 254, 244); // light beige
106:
107: protected static final Color TEXT_COLOR_RESULT = Color.BLACK;
108:
109: protected static final Color TEXT_COLOR_INPUT = new Color(100, 100,
110: 90); // gray
111:
112: protected static final Color TEXT_COLOR_LITERAL = new Color(30, 70,
113: 230); // navy
114:
115: protected static final JGoBrush BRUSH_OUTPUT_REGULAR = JGoBrush
116: .makeStockBrush(COLOR_BG_OUTPUT);
117:
118: protected static final JGoBrush BRUSH_INPUT_REGULAR = JGoBrush
119: .makeStockBrush(COLOR_BG_INPUT);
120:
121: protected static final JGoBrush BRUSH_INPUT_HIGHLIGHTED = JGoBrush
122: .makeStockBrush(COLOR_BG_INPUT_HOVER);
123:
124: private static URL showSqlUrl = SQLBasicTableArea.class
125: .getResource("/org/netbeans/modules/sql/framework/ui/resources/images/Show_Sql.png");
126:
127: private static URL removeUrl = SQLBasicTableArea.class
128: .getResource("/org/netbeans/modules/sql/framework/ui/resources/images/remove.png");
129:
130: protected static URL editUrl = SQLBasicTableArea.class
131: .getResource("/org/netbeans/modules/sql/framework/ui/resources/images/edit_join.png");
132:
133: private JMenuItem showSqlItem;
134:
135: private JMenuItem removeItem;
136:
137: private Map fieldNameToControlMap = new HashMap();
138:
139: private boolean showParen = false;
140:
141: private ParenthesisCheckBoxArea cbWrap;
142:
143: private static transient final Logger mLogger = LogUtil
144: .getLogger(SQLOperatorGraphNode.class.getName());
145:
146: private static transient final Localizer mLoc = Localizer.get();
147:
148: /** Creates a new instance of OperatorGraphNode */
149: public SQLOperatorGraphNode(IOperatorXmlInfo info) {
150: this (info, false);
151: }
152:
153: /** Creates a new instance of OperatorGraphNode */
154: public SQLOperatorGraphNode(IOperatorXmlInfo info, boolean show) {
155: super (info);
156:
157: initialize(info);
158: initializePopUpMenu();
159:
160: this .showParen = show;
161: if (this .showParen) {
162: cbWrap = new ParenthesisCheckBoxArea();
163: cbWrap.setBackgroundColor(BRUSH_INPUT_REGULAR.getColor());
164: cbWrap.setTextColor(TEXT_COLOR_INPUT);
165: this .addObjectAtTail(cbWrap);
166: this .addItemListener(new ParenthesisItemListener());
167: }
168:
169: setSize(this .getMaximumWidth(), this .getMaximumHeight());
170: }
171:
172: /** Creates a new instance of OperatorGraphNode */
173: public SQLOperatorGraphNode(IOperatorXmlInfo info, boolean show,
174: String nameOverride) {
175: super (nameOverride, info.getToolTip(), info.getIcon());
176:
177: initialize(info);
178: initializePopUpMenu();
179:
180: this .showParen = show;
181: if (this .showParen) {
182: cbWrap = new ParenthesisCheckBoxArea();
183: cbWrap.setBackgroundColor(BRUSH_INPUT_REGULAR.getColor());
184: cbWrap.setTextColor(TEXT_COLOR_INPUT);
185: this .addObjectAtTail(cbWrap);
186: this .addItemListener(new ParenthesisItemListener());
187: }
188:
189: setSize(this .getMaximumWidth(), this .getMaximumHeight());
190: }
191:
192: public SQLOperatorGraphNode(String displayName, String toolTip,
193: Icon icon) {
194: super (displayName, toolTip, icon);
195:
196: initializePopUpMenu();
197: setSize(this .getMinimumWidth(), this .getMinimumHeight());
198: }
199:
200: /**
201: * Gets output graph port, given its field name.
202: *
203: * @param fieldName field name
204: * @return graph port
205: */
206: public IGraphPort getOutputGraphPort(String fieldName) {
207: if (resultField != null) {
208: return resultField.getRightGraphPort();
209: }
210: return null;
211: }
212:
213: /**
214: * get input graph port, given a field name
215: *
216: * @param fieldName field name
217: * @return graph port
218: */
219: public IGraphPort getInputGraphPort(String fieldName) {
220: //special handling for variable argument operator we ignore the fieldName and
221: //always return port for first field in the field list
222: Object dataObj = this .getDataObject();
223: if (dataObj instanceof SQLGenericOperator) {
224:
225: SQLGenericOperator operator = (SQLGenericOperator) dataObj;
226: if (operator.hasVariableArgs()) {
227: IGraphFieldNode fieldNode = (IGraphFieldNode) fieldList
228: .get(0);
229: return fieldNode.getLeftGraphPort();
230: }
231: return super .getInputGraphPort(fieldName);
232: }
233:
234: return super .getInputGraphPort(fieldName);
235: }
236:
237: protected void initializePopUpMenu() {
238: OperatorActionListener aListener = new OperatorActionListener();
239: if (popUpMenu == null) {
240: popUpMenu = new JPopupMenu();
241: }
242: String nbBundle1 = mLoc.t("PRSR001: Show SQL...");
243: showSqlItem = new JMenuItem(Localizer.parse(nbBundle1),
244: new ImageIcon(showSqlUrl));
245: showSqlItem.addActionListener(aListener);
246: popUpMenu.add(showSqlItem);
247:
248: //remove menu
249: popUpMenu.addSeparator();
250: String nbBundle2 = mLoc.t("PRSR001: Remove");
251: removeItem = new JMenuItem(Localizer.parse(nbBundle2),
252: new ImageIcon(removeUrl));
253: removeItem.addActionListener(aListener);
254: popUpMenu.add(removeItem);
255: }
256:
257: protected class OperatorActionListener implements ActionListener {
258: /**
259: * Invoked when an action occurs.
260: */
261: public void actionPerformed(ActionEvent e) {
262: Object source = e.getSource();
263: if (source == showSqlItem) {
264: ShowSql_actionPerformed(e);
265: } else if (source == removeItem) {
266: Remove_ActionPerformed(e);
267: }
268: }
269: }
270:
271: /**
272: * Invoked when an action occurs.
273: */
274: private void ShowSql_actionPerformed(ActionEvent e) {
275: SQLObject sqlObject = (SQLObject) SQLOperatorGraphNode.this
276: .getDataObject();
277: this .getGraphView().execute(ICommand.SHOW_SQL_CMD,
278: new Object[] { sqlObject });
279: }
280:
281: private void Remove_ActionPerformed(ActionEvent e) {
282: this .getGraphView().deleteNode(this );
283: }
284:
285: protected void initialize(IOperatorXmlInfo info) {
286: fieldNameToControlMap = new HashMap();
287:
288: // Collect lists of input graph and parameter fields.
289: for (int i = 0; i < info.getInputCount(); i++) {
290: IOperatorField field = (IOperatorField) info
291: .getInputFields().get(i);
292: if (field.isStatic()) {
293: BasicComboBoxArea control = new BasicComboBoxArea(field
294: .getName(), null, new Vector(field
295: .getAcceptableValues()), new Vector(field
296: .getAcceptableDisplayValues()), field
297: .getToolTip(), field.isEditable());
298: control.addItemListener(this );
299: fieldNameToControlMap.put(field.getName(), control);
300: fieldList.add(control);
301: } else {
302: OperatorGraphFieldNode fieldNode = new OperatorGraphFieldNode(
303: BasicCellArea.LEFT_PORT_AREA, field);
304: fieldNode.setBrush(BRUSH_INPUT_REGULAR);
305: fieldNode.setTextColor(TEXT_COLOR_INPUT);
306: fieldNode.setLinePen(PEN_DEFAULT);
307: fieldNode.setHighlightEnabled(true);
308: fieldNode.getHighlightConfigurator().setHoverBrush(
309: BRUSH_INPUT_HIGHLIGHTED);
310:
311: fieldList.add(fieldNode);
312: }
313: }
314:
315: Iterator iter = fieldList.iterator();
316: while (iter.hasNext()) {
317: CanvasArea fieldNode = (CanvasArea) iter.next();
318: this .addObjectAtTail(fieldNode);
319: }
320:
321: // Add output graph field.
322: for (int i = 0; i < info.getOutputCount(); i++) {
323: IOperatorField field = (IOperatorField) info
324: .getOutputFields().get(i);
325:
326: OperatorGraphFieldNode fieldNode = new OperatorGraphFieldNode(
327: BasicCellArea.RIGHT_PORT_AREA, field,
328: JGoText.ALIGN_CENTER);
329: fieldNode.setBrush(BRUSH_OUTPUT_REGULAR);
330: fieldNode.setTextColor(TEXT_COLOR_RESULT);
331: fieldNode.setLinePen(PEN_DEFAULT);
332: fieldNode.setHighlightEnabled(false);
333:
334: //there is only one result field for operator
335: resultField = fieldNode;
336: this .addObjectAtTail(fieldNode);
337: fieldList.add(fieldNode);
338: }
339:
340: this .setResizable(true);
341: }
342:
343: /**
344: * Gets the maximum height of the node.
345: *
346: * @return max height
347: */
348: public int getMaximumHeight() {
349: int maxHt = super .getMaximumHeight();
350:
351: if (this .showParen) {
352: maxHt += cbWrap.getMaximumHeight();
353: }
354: return maxHt;
355: }
356:
357: /**
358: * Gets the maximum width of the node.
359: *
360: * @return max width
361: */
362: public int getMaximumWidth() {
363: int maxWidth = super .getMaximumWidth();
364:
365: if (this .showParen && cbWrap.getMaximumWidth() > maxWidth) {
366: maxWidth = cbWrap.getMaximumWidth();
367: }
368:
369: return maxWidth;
370: }
371:
372: public int getMinimumHeight() {
373: int minHeight = super .getMinimumHeight();
374:
375: if (this .showParen) {
376: minHeight += cbWrap.getMaximumHeight();
377: }
378:
379: return minHeight;
380: }
381:
382: public int getMinimumWidth() {
383: int minWidth = super .getMinimumWidth();
384:
385: if (this .showParen) {
386: minWidth = Math.max(minWidth, cbWrap.getMinimumWidth());
387: }
388:
389: return minWidth;
390: }
391:
392: public void setExpanded(boolean sExpanded) {
393: super .setExpanded(sExpanded);
394: if (sExpanded) {
395: setInitialComboBoxState();
396: }
397: }
398:
399: private void setInitialComboBoxState() {
400: try {
401: if (dataObject instanceof SQLOperator) { // also does implicit null check
402: SQLOperator operator = (SQLOperator) dataObject;
403: Iterator iter = fieldNameToControlMap.entrySet()
404: .iterator();
405: while (iter.hasNext()) {
406: Map.Entry entry = (Map.Entry) iter.next();
407: String field = (String) entry.getKey();
408: BasicComboBoxArea control = (BasicComboBoxArea) entry
409: .getValue();
410:
411: Object val = operator.getArgumentValue(field);
412: if (val != null && val instanceof SQLLiteral) {
413: SQLLiteral literal = (SQLLiteral) val;
414: String item = literal.getValue();
415: int idx = control.getAcceptableValues()
416: .indexOf(item);
417: if (idx != -1) {
418: control.setSelectedItem(control
419: .getAcceptableValues().get(idx));
420: } else if (control.isEditable()) {
421: control.setSelectedItem(item);
422: }
423: } else {
424: //by default first item is selected, so set
425: //that in SQLOperator
426: setArgument(control, (String) control
427: .getAcceptableValues().get(0));
428: }
429: }
430: }
431: } catch (BaseException ex) {
432: //TODO log me
433: throw new IllegalArgumentException(
434: "Cannot initialize values in function drop down list.");
435: }
436: }
437:
438: /**
439: * @see org.netbeans.modules.sql.framework.ui.graph.IGraphNode#setDataObject(java.lang.Object)
440: */
441: public void setDataObject(Object obj) {
442: if (obj instanceof SQLConnectableObject
443: && obj instanceof SQLOperator) {
444: super .setDataObject(obj);
445: this .setShowParenthesis(((SQLOperator) obj)
446: .isShowParenthesis());
447: setInitialComboBoxState();
448: } else {
449: String msg = "SQLOperatorGraphNode only accepts as its data object "
450: + "instances of SQLOperator.";
451: try {
452: String nbBundle1 = mLoc
453: .t("PRSR001: SQLParameterizedOperatorGraphNode only accepts as its data object instances of SQLOperator that implement HasStaticParameters.");
454: msg = Localizer.parse(nbBundle1);
455: } catch (MissingResourceException ignore) {
456: // Do nothing - use default message above.
457: }
458: throw new IllegalArgumentException(msg);
459: }
460: }
461:
462: /**
463: * Lays out child components.
464: */
465: public void layoutChildren() {
466: Rectangle boundingRect = new Rectangle(this .getBoundingRect());
467:
468: int minLayoutHeight = isExpandedState() ? getMaximumHeight()
469: : getMinimumHeight();
470: int maxLayoutHeight = isExpandedState() ? getMaximumHeight()
471: : getMinimumHeight();
472: if (boundingRect.height < minLayoutHeight) {
473: boundingRect.height = minLayoutHeight;
474: } else if (boundingRect.height > maxLayoutHeight) {
475: boundingRect.height = maxLayoutHeight;
476: }
477:
478: int minLayoutWidth = getMinimumWidth();
479: if (boundingRect.width < minLayoutWidth || !isExpandedState()) {
480: boundingRect.width = minLayoutWidth;
481: }
482:
483: this .setBoundingRect(boundingRect);
484:
485: columnRect.setBoundingRect(this .getBoundingRect());
486:
487: int rectleft = getLeft();
488: int recttop = getTop();
489: int rectwidth = getWidth();
490: int rectheight = getHeight();
491:
492: int left = rectleft + insets.left;
493: int top = recttop + insets.top;
494: int width = rectwidth - insets.left - insets.right;
495: int height = rectheight - insets.top - insets.bottom;
496:
497: titleArea.setBoundingRect(left, top, width, titleArea
498: .getMinimumHeight());
499:
500: // for generic parameterized operators, fields should be in order (top to bottow):
501: // HEADER, [all parameter controls], verticalgap, [all linkable inputs],
502: // verticalgap,
503: // [all linkable results]
504:
505: if (this .showParen) {
506: cbWrap.setBoundingRect(left, top
507: + titleArea.getMinimumHeight(), width, cbWrap
508: .getMaximumHeight());
509: }
510:
511: int aggrHeight = top + titleArea.getMinimumHeight()
512: + (this .showParen ? cbWrap.getMaximumHeight() : 0);
513:
514: // Linkable fields
515:
516: // loop from the next field onwards
517: for (int i = 0; i < fieldList.size(); i++) {
518: CanvasArea fieldNode = (CanvasArea) fieldList.get(i);
519:
520: if (aggrHeight < top + height) {
521: fieldNode.setVisible(true);
522: fieldNode.setBoundingRect(left, aggrHeight, width,
523: fieldNode.getHeight() + verticalGap);
524: } else {
525: fieldNode.setVisible(false);
526: fieldNode.setBoundingRect(left, top, width, fieldNode
527: .getHeight()
528: + verticalGap);
529: }
530: aggrHeight += fieldNode.getHeight() + verticalGap;
531: }
532: }
533:
534: public void itemStateChanged(ItemEvent e) {
535: setArgument(e.getSource(), (String) e.getItem());
536: setSize(getMaximumWidth(), getMaximumHeight());
537: layoutChildren();
538: }
539:
540: private void setArgument(Object control, String val) {
541: String fieldName = getFieldNameFor(control);
542: if (fieldName != null && getDataObject() instanceof SQLOperator) {
543: SQLOperator operator = (SQLOperator) getDataObject();
544: try {
545: operator.setArgument(fieldName, val);
546: } catch (BaseException ex) {
547: // Ignore for now.
548: }
549: }
550: }
551:
552: protected BasicComboBoxArea getComboBoxFor(String fieldName) {
553: return (BasicComboBoxArea) fieldNameToControlMap.get(fieldName);
554: }
555:
556: protected String getFieldNameFor(Object control) {
557: Iterator iter = fieldNameToControlMap.entrySet().iterator();
558: while (iter.hasNext()) {
559: Map.Entry entry = (Map.Entry) iter.next();
560: if (entry.getValue().equals(control)) {
561: return (String) entry.getKey();
562: }
563: }
564:
565: return null;
566: }
567:
568: public void addItemListener(ItemListener l) {
569: if (this .cbWrap != null) {
570: this .cbWrap.addItemListener(l);
571: }
572: }
573:
574: public void removeItemListener(ItemListener l) {
575: if (this .cbWrap != null) {
576: this .cbWrap.removeItemListener(l);
577: }
578: }
579:
580: /**
581: * whether to select or deselect check box ui
582: */
583: public void setShowParenthesis(boolean select) {
584: if (this .cbWrap != null) {
585: this .cbWrap.setShowParenthesis(select);
586: }
587: }
588:
589: class ParenthesisItemListener implements ItemListener {
590: /**
591: * Invoked when an item has been selected or deselected by the user. The code
592: * written for this method performs the operations that need to occur when an item
593: * is selected (or deselected).
594: */
595: public void itemStateChanged(ItemEvent e) {
596: SQLOperator operator = (SQLOperator) getDataObject();
597: if (operator == null) {
598: return;
599: }
600:
601: boolean showParens = false;
602: if (e.getStateChange() == ItemEvent.SELECTED) {
603: showParens = true;
604: }
605:
606: operator.setShowParenthesis(showParens);
607: }
608: }
609: }
|