KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > db > sql > visualeditor > querybuilder > QueryBuilderGraphFrame


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.db.sql.visualeditor.querybuilder;
20
21 import org.openide.nodes.AbstractNode;
22
23 import java.awt.BorderLayout JavaDoc;
24 import java.awt.Dimension JavaDoc;
25 import java.awt.Color JavaDoc;
26 import java.awt.Font JavaDoc;
27 import java.awt.FontMetrics JavaDoc;
28 import java.awt.Point JavaDoc;
29 import java.awt.event.*;
30 import java.awt.Component JavaDoc;
31 import java.awt.Graphics JavaDoc;
32 import java.awt.Graphics2D JavaDoc;
33 import java.awt.Toolkit JavaDoc;
34
35 import java.awt.dnd.*;
36 import java.awt.datatransfer.*;
37
38 import java.awt.font.FontRenderContext JavaDoc;
39 import java.awt.geom.Rectangle2D JavaDoc;
40
41 import java.beans.PropertyVetoException JavaDoc;
42
43 import java.net.URL JavaDoc;
44
45 import java.util.Map JavaDoc;
46 import java.util.HashMap JavaDoc;
47 import java.util.Iterator JavaDoc;
48 import java.util.ArrayList JavaDoc;
49 import java.util.List JavaDoc;
50
51 import javax.swing.AbstractAction JavaDoc;
52 import javax.swing.Action JavaDoc;
53 import javax.swing.ImageIcon JavaDoc;
54 import javax.swing.JPopupMenu JavaDoc;
55 import javax.swing.JScrollPane JavaDoc;
56 import javax.swing.JLabel JavaDoc;
57 import javax.swing.JInternalFrame JavaDoc;
58 import javax.swing.JPanel JavaDoc;
59 import javax.swing.JTextPane JavaDoc;
60 import javax.swing.JDesktopPane JavaDoc;
61 import javax.swing.JMenu JavaDoc;
62 import javax.swing.JMenuItem JavaDoc;
63 import javax.swing.JCheckBoxMenuItem JavaDoc;
64 import javax.swing.JLayeredPane JavaDoc;
65 import javax.swing.JViewport JavaDoc;
66 import javax.swing.SwingUtilities JavaDoc;
67 import javax.swing.JComboBox JavaDoc;
68 import javax.swing.DefaultCellEditor JavaDoc;
69 import javax.swing.UIManager JavaDoc;
70
71 import javax.swing.event.TableModelEvent JavaDoc;
72 import javax.swing.event.TableModelListener JavaDoc;
73 import javax.swing.event.InternalFrameEvent JavaDoc;
74 import javax.swing.event.InternalFrameAdapter JavaDoc;
75 import javax.swing.event.InternalFrameListener JavaDoc;
76 import javax.swing.table.TableModel JavaDoc;
77 import javax.swing.table.DefaultTableModel JavaDoc;
78 import javax.swing.table.TableColumn JavaDoc;
79 import javax.swing.plaf.basic.BasicInternalFrameUI JavaDoc;
80
81 import java.sql.*;
82
83 import org.openide.util.NbBundle;
84 import org.openide.ErrorManager;
85 import org.openide.nodes.Node;
86 import org.openide.NotifyDescriptor;
87 import org.openide.DialogDisplayer;
88 import org.openide.windows.WindowManager;
89
90 import com.jgraph.JGraph;
91
92 import com.jgraph.graph.GraphConstants;
93 import com.jgraph.graph.ConnectionSet;
94 import com.jgraph.graph.DefaultEdge;
95 import com.jgraph.graph.DefaultPort;
96 import com.jgraph.graph.DefaultGraphCell;
97 import com.jgraph.graph.DefaultGraphModel;
98 import com.jgraph.graph.CellView;
99 import com.jgraph.graph.AbstractCellView;
100 import com.jgraph.graph.Port;
101 import com.jgraph.graph.PortView;
102 import com.jgraph.graph.Edge;
103
104 import com.jgraph.event.GraphSelectionListener;
105 import com.jgraph.event.GraphSelectionEvent;
106
107 import org.netbeans.modules.db.sql.visualeditor.Log;
108
109 import org.netbeans.modules.db.sql.visualeditor.querymodel.JoinTable;
110 import org.netbeans.modules.db.sql.visualeditor.querymodel.Column;
111 import org.netbeans.modules.db.sql.visualeditor.querymodel.Expression;
112 import org.netbeans.modules.db.sql.visualeditor.querymodel.Value;
113 import org.netbeans.modules.db.sql.visualeditor.querymodel.Predicate;
114 import org.netbeans.modules.db.sql.visualeditor.querymodel.And;
115 import org.netbeans.modules.db.sql.visualeditor.querymodel.Or;
116 import org.netbeans.modules.db.sql.visualeditor.querymodel.Table;
117 import org.netbeans.modules.db.sql.visualeditor.querymodel.Where;
118 import org.netbeans.modules.db.sql.visualeditor.querymodel.SQLQueryFactory;
119 import org.netbeans.modules.db.sql.visualeditor.querymodel.ExpressionList;
120
121 /**
122  *
123  * @author Sanjay Dhamankar, Jim Davidson
124  */

125 public class QueryBuilderGraphFrame extends JPanel JavaDoc
126         implements ActionListener, TableModelListener JavaDoc, ItemListener,
127         KeyListener, DropTargetListener {
128     // Private/package variables
129

130     private static final boolean DEBUG = false;
131
132     private boolean _disableQBGF = false;
133
134     private QueryBuilder _queryBuilder;
135
136     private DropTarget _dropTarget;
137
138     private JDesktopPane JavaDoc _desktopPane = null;
139     private QBGFJPanel _canvas = null;
140     private QueryBuilderInputTable _queryBuilderInputTable;
141     private DefaultTableModel JavaDoc _inputTableModel;
142     private JTextPane JavaDoc _sqlTextArea;
143     private DefaultTableModel JavaDoc _resultTableModel;
144     private JGraph _graph = null;
145     private DefaultGraphModel _graphModel = null;
146     
147     private JScrollPane JavaDoc _desktopScrollPane;
148     private JViewport JavaDoc viewport;
149     
150     private FrameSelectionListener _fsl = null;
151     private FrameComponentListener _fcl = null;
152     private ComponentListener _cl = null;
153     private JPopupMenu JavaDoc _backgroundPopup;
154     private JPopupMenu JavaDoc _tableTitlePopup;
155     private AddTableDlg _addTableDlg = null;
156     
157     private boolean _firstTableInserted = false;
158     private Point JavaDoc _location;
159     
160     // constants used in the getNextLocation
161
private static final int initX = 40;
162     private static final int initY = 40;
163     
164     private static final int offsetX = 20;
165     private int offsetY = 20;
166     
167     private static final int MAX_TABLES_IN_A_ROW = 5;
168     
169     
170     private java.util.Random JavaDoc randomVal = new java.util.Random JavaDoc();
171     
172     private JMenuItem JavaDoc runQueryMenuItem;
173     private JMenuItem JavaDoc groupByMenuItem;
174     
175     // private String[] _tableStrings;
176
// private List _tableNames = null;
177
// an array of TableColumns
178
// private List _tableColumnNames ;
179

180     private boolean _checkTableColumnValidity = false;
181     
182     private boolean _inputTableAddCriteria = false;
183     
184     java.net.URL JavaDoc url_primary_key =
185             getClass().getResource("/org/netbeans/modules/db/sql/visualeditor/resources/primaryKey.gif"); // NOI18N
186
java.net.URL JavaDoc url_foreign_key =
187             getClass().getResource("/org/netbeans/modules/db/sql/visualeditor/resources/foreignKey.gif"); // NOI18N
188

189     
190     // Constructor
191

192     // Note that this takes as parameter the models that underlie the other three panes.
193
// The QBGF could post listeners on each of those panes; the only one currently
194
// listened to is inputTableModel
195
public QueryBuilderGraphFrame(QueryBuilder queryBuilder,
196             QueryBuilderInputTable queryBuilderInputTable,
197             JTextPane JavaDoc sqlTextArea,
198             DefaultTableModel JavaDoc resultTableModel) {
199         super(new BorderLayout JavaDoc());
200         
201         Log.err.log(ErrorManager.INFORMATIONAL, "Entering QueryBuilderGraphFrame ctor"); // NOI18N
202

203         _queryBuilder = queryBuilder;
204         _queryBuilderInputTable = queryBuilderInputTable;
205         _inputTableModel = (DefaultTableModel JavaDoc) _queryBuilderInputTable.getModel();
206         _sqlTextArea = sqlTextArea;
207         _resultTableModel = resultTableModel;
208         
209         // Listen for events in the input table (column list)
210
// Unfortunately, this gets triggered with every change to the model.
211
// We need a way to make a group of changes to the input table, then invoke the
212
// listener once at the end.
213
_inputTableModel.addTableModelListener(this);
214         
215         // Get a list of tables in the DB
216

217         JMenu JavaDoc menu, subMenu;
218         JMenuItem JavaDoc menuItem;
219         
220         // Create three listeners
221
_fsl = new FrameSelectionListener();
222         _fcl = new FrameComponentListener();
223         _cl = new CompListener();
224         
225         // Create the new JGraph, with its model
226
_graphModel = new DefaultGraphModel();
227         _graph = new JGraph(_graphModel);
228         _graph.setEditable(false);
229         _graph.addKeyListener(this);
230         
231         // Create a JPanel (a lightweight container), and add the JGraph to it
232
_canvas = new QBGFJPanel();
233         _canvas.setBackground(Color.white);
234         _canvas.add(_graph, BorderLayout.CENTER);
235         _canvas.addKeyListener(this);
236         
237         
238         // Create the JDesktopPane (a container used to contain internal frame objects)
239
_desktopPane = new JDesktopPane JavaDoc();
240         _desktopPane.setBackground(Color.white);
241         _desktopPane.setDragMode(JDesktopPane.LIVE_DRAG_MODE);
242         _desktopPane.addComponentListener(_cl);
243         _desktopPane.addKeyListener(this);
244         
245         // Add the canvas panel to the desktop
246
_desktopPane.add(_canvas,JLayeredPane.FRAME_CONTENT_LAYER);
247         
248         // Create a JScrollPane, which contains a JViewport, which contains the desktopPane
249
_desktopScrollPane = new JScrollPane JavaDoc();
250         viewport = new JViewport JavaDoc();
251         viewport.setView(_desktopPane);
252         _desktopScrollPane.setViewportView(viewport);
253         _desktopScrollPane.setPreferredSize(new Dimension JavaDoc(100,100)); //very important
254

255         // Create two popup menus
256
_backgroundPopup = createBackgroundPopup();
257         _tableTitlePopup = createTableTitlePopup();
258         
259         // Add listener to components that can bring up popup menus.
260
// Create a listener that will bring up background menu
261
MouseListener backgroundPopupListener = new BackgroundPopupListener();
262         
263         // Add it as listener
264
_graph.addMouseListener(backgroundPopupListener);
265         _desktopPane.addMouseListener(backgroundPopupListener);
266         _desktopScrollPane.addMouseListener(backgroundPopupListener);
267         
268         // Create a new listener for noticing graph selection
269
_graph.addGraphSelectionListener(new GraphSelListener());
270         
271         // Add the JScrollPane to the QueryBuilderGraphFrame
272
this.add(_desktopScrollPane,BorderLayout.CENTER);
273         
274         // Make the GraphFrame visible
275
setVisible(true);
276         
277         _dropTarget = new DropTarget(_desktopScrollPane,
278                 DnDConstants.ACTION_COPY_OR_MOVE, this);
279         
280     }
281     
282     void getCanvasFocus() {
283         _canvas.requestFocus(true);
284     }
285     
286     void setQBGFEnabled( boolean value ) {
287         _disableQBGF = ! ( value );
288         if ( _disableQBGF ) {
289             int frameWidth = (int) this.getSize().getWidth();
290             int frameHeight = (int) this.getSize().getHeight();
291             
292             _canvas.setSize(new Dimension JavaDoc( frameWidth, frameHeight ) );
293             _canvas.updateUI();
294             _desktopPane.revalidate();
295         }
296     }
297     
298     void resizeDesktop() {
299         if (DEBUG) {
300             System.out.println(" resizeDesktop() called " + "\n" ); // NOI18N
301
System.out.println(" width = " + _graph.getSize().getWidth() + " Height = " + _graph.getSize().getHeight() + "\n" ); // NOI18N
302
}
303         int graphWidth = (int) _graph.getSize().getWidth();
304         int graphHeight = (int) _graph.getSize().getHeight();
305         
306         int frameWidth = (int) this.getSize().getWidth();
307         int frameHeight = (int) this.getSize().getHeight();
308         
309         // when graph width height is zero set canvas to the frame size.
310
if ( graphWidth == 0 )
311             graphWidth = frameWidth;
312         if ( graphHeight == 0 )
313             graphHeight = frameHeight;
314         
315         if (DEBUG) {
316             System.out.println(" width = " + graphWidth + " Height = " + graphHeight + "\n" ); // NOI18N
317
}
318         _canvas.setSize(new Dimension JavaDoc( graphWidth, graphHeight ) );
319         _canvas.updateUI();
320         _desktopPane.setPreferredSize(new Dimension JavaDoc(graphWidth, graphHeight));
321         _desktopPane.revalidate();
322     }
323     
324     void setActivatedNode( QueryBuilderInternalFrame currentSelectedFrame ) {
325         if ( currentSelectedFrame != null ) {
326             TableNode tn = currentSelectedFrame.getNode();
327             _queryBuilder.setActivatedNodes(new Node[] {tn});
328         } else {
329             _queryBuilder.setActivatedNodes(new Node[0]);
330         }
331         _queryBuilder.activateActions();
332     }
333     
334     class QBGFJPanel extends JPanel JavaDoc {
335         protected void paintComponent(Graphics JavaDoc g) {
336             if (DEBUG) {
337                 System.out.println(" paintComponent() called _parseErrorMessage = " + _queryBuilder.getParseErrorMessage() + "\n" ); // NOI18N
338
}
339             super.paintComponent(g);
340             if ( _queryBuilder.getParseErrorMessage() != null ) {
341                 Graphics2D JavaDoc g2d = (Graphics2D JavaDoc)g;
342                 paintCenteredText(g2d);
343                 if (DEBUG) {
344                     System.out.println(" paintCenteredText() called " + "\n" ); // NOI18N
345
}
346             }
347         }
348         
349         /** Paint the "help" text when the page is empty */
350         private void paintCenteredText(Graphics2D JavaDoc g) {
351             final int PADDING = 5; // Padding around text that's cleared
352
final int LINESPACING = 3; // Extra pixels between text lines
353

354             // This implementation is slow/inefficient, but since it's only run
355
// when the page is empty we know we're not busy
356
String JavaDoc text;
357             text = _queryBuilder.getParseErrorMessage();
358             int textLines = 1;
359             if (DEBUG) {
360                 System.out.println(" paintCenteredText() called _parseErrorMessage = " + _queryBuilder.getParseErrorMessage() + "\n" ); // NOI18N
361
}
362             for (int i = 0, n = text.length(); i < n; i++) {
363                 if (text.charAt(i) == '\n') {
364                     textLines++;
365                 }
366             }
367             
368             int width =
369                     _desktopScrollPane.getViewport().getWidth();
370             int height =
371                     _desktopScrollPane.getViewport().getHeight();
372             
373             this.setSize(new Dimension JavaDoc( width, height ) );
374             int center = height/2;
375             
376             Font JavaDoc font = UIManager.getFont("Label.font"); // NOI18N
377
g.setFont(font);
378             FontMetrics JavaDoc metrics = Toolkit.getDefaultToolkit().getFontMetrics(font);
379             FontRenderContext JavaDoc frc = g.getFontRenderContext();
380             int lineHeight = metrics.getHeight()+LINESPACING;
381             
382             int top = center-lineHeight*textLines/2;
383             
384             int minx = width;
385             int maxx = 0;
386             int nextLine = 0;
387             for (int line = 0; line < textLines; line++) {
388                 int lineEnd = text.indexOf('\n', nextLine);
389                 String JavaDoc lineText;
390                 if (lineEnd != -1) {
391                     lineText = text.substring(nextLine, lineEnd);
392                     nextLine = lineEnd+1;
393                 } else {
394                     lineText = text.substring(nextLine);
395                 }
396                 
397                 Rectangle2D JavaDoc bounds1 = font.getStringBounds(lineText, frc);
398                 int lx = (width-((int)bounds1.getWidth()))/2;
399                 if (lx < minx) {
400                     minx = lx;
401                 }
402                 int xw = lx+(int)bounds1.getWidth();
403                 if (xw > maxx) {
404                     maxx = xw;
405                 }
406             }
407             
408             
409             // Clear background under text
410
Color JavaDoc background = null;
411             background = getBackground();
412             g.setColor(background);
413             int miny = top;
414             int maxy = top+textLines*lineHeight;
415             g.fillRect(minx-PADDING, miny, maxx-minx+2*PADDING, maxy-miny+2*PADDING);
416             // Draw text
417
g.setColor(java.awt.Color.gray);
418             nextLine = 0;
419             int y = top+2*PADDING; // XXX change to padding constant
420
y += metrics.getHeight() - metrics.getDescent();
421             for (int line = 0; line < textLines; line++) {
422                 int lineEnd = text.indexOf('\n', nextLine);
423                 String JavaDoc lineText;
424                 if (lineEnd != -1) {
425                     lineText = text.substring(nextLine, lineEnd);
426                     nextLine = lineEnd+1;
427                 } else {
428                     lineText = text.substring(nextLine);
429                 }
430                 
431                 Rectangle2D JavaDoc bounds1 = font.getStringBounds(lineText, frc);
432                 int lx = (width-((int)bounds1.getWidth()))/2;
433                 
434                 g.drawString(lineText, lx, y);
435                 y += lineHeight;
436             }
437         }
438     }
439     
440     /** Handle the key typed event from the sql text area. */
441     public void keyTyped(KeyEvent e) {
442         _checkTableColumnValidity = true;
443     }
444     
445     /** Handle the key pressed event. */
446     public void keyPressed(KeyEvent e) {
447         if ( DEBUG )
448             System.out.println(" QBGF : key pressed called. " + "\n" ); // NOI18N
449
_checkTableColumnValidity = true;
450         if( e.isShiftDown() ) {
451             int code = e.getKeyCode();
452             switch(code) {
453                 // diagram pane
454
case KeyEvent.VK_F10:
455                     _backgroundPopup.show( e.getComponent(), e.getComponent().getX(), e.getComponent().getY() );
456                     break;
457             }
458         }
459         _queryBuilder.handleKeyPress(e);
460     }
461     
462     /** Handle the key released event from the sql text area. */
463     public void keyReleased(KeyEvent e) {
464         _checkTableColumnValidity = true;
465     }
466     
467     public void setTableColumnValidity(boolean value) {
468         _checkTableColumnValidity = value;
469     }
470     
471     
472     // check the table and column validity only if the user manually
473
// changes the sql query.
474
public boolean checkTableColumnValidity() {
475         return ( _checkTableColumnValidity &&
476                 _queryBuilder.getQueryBuilderPane().getQueryBuilderSqlTextArea().queryChanged() );
477     }
478     
479     // Adding a method to access _graph as per QE request
480

481     
482     public JGraph getGraph() {
483         return (_graph);
484     }
485     
486     // Create a popup menu that will appear when the user clicks on the background
487
// and similar places.
488
JPopupMenu JavaDoc createBackgroundPopup() {
489         
490         JPopupMenu JavaDoc backgroundPopup;
491         JMenu JavaDoc menu, subMenu;
492         JMenuItem JavaDoc menuItem;
493         JMenuItem JavaDoc subMenuItem;
494         
495         //Create the popup menu.
496
backgroundPopup = new JPopupMenu JavaDoc();
497         
498         runQueryMenuItem = new JMenuItem JavaDoc(NbBundle.getMessage(QueryBuilderGraphFrame.class, "RUN_QUERY")); // NOI18N
499
runQueryMenuItem.addActionListener(this);
500         backgroundPopup.add(runQueryMenuItem);
501         
502         menuItem = new JMenuItem JavaDoc(NbBundle.getMessage(QueryBuilderGraphFrame.class, "Add_Table")); // NOI18N
503
menuItem.addActionListener(this);
504         backgroundPopup.add(menuItem);
505         
506         /*
507         menuItem = new JMenuItem(NbBundle.getMessage(QueryBuilderGraphFrame.class, "SELECT_ALL")); // NOI18N
508         menuItem.addActionListener(this);
509         backgroundPopup.add(menuItem);
510          */

511         
512         groupByMenuItem =
513                 new JCheckBoxMenuItem JavaDoc(NbBundle.getMessage(QueryBuilderGraphFrame.class, "GROUP_BY")); // NOI18N
514
groupByMenuItem.addItemListener(this);
515         backgroundPopup.add(groupByMenuItem);
516         
517         /*
518         //a submenu
519          
520         subMenu = new JMenu(NbBundle.getMessage(QueryBuilderGraphFrame.class, "INPUT_TABLE_CHANGE_TYPE")); // NOI18N
521          
522         subMenuItem = new JMenuItem(NbBundle.getMessage(QueryBuilderGraphFrame.class, "SELECT")); // NOI18N
523         subMenuItem.addActionListener(this);
524         subMenu.add(subMenuItem);
525          
526         subMenuItem = new JMenuItem(NbBundle.getMessage(QueryBuilderGraphFrame.class, "UPDATE")); // NOI18N
527         subMenuItem.addActionListener(this);
528         subMenu.add(subMenuItem);
529          
530         subMenuItem = new JMenuItem(NbBundle.getMessage(QueryBuilderGraphFrame.class, "INSERT")); // NOI18N
531         subMenuItem.addActionListener(this);
532         subMenu.add(subMenuItem);
533          
534         subMenuItem = new JMenuItem(NbBundle.getMessage(QueryBuilderGraphFrame.class, "DELETE")); // NOI18N
535         subMenuItem.addActionListener(this);
536         subMenu.add(subMenuItem);
537          
538         backgroundPopup.add(subMenu);
539          
540         menuItem = new JMenuItem(NbBundle.getMessage(QueryBuilderGraphFrame.class, "INPUT_TABLE_COLLAPSE_PANE")); // NOI18N
541         menuItem.addActionListener(this);
542         backgroundPopup.add(menuItem);
543          
544         menuItem = new JMenuItem(NbBundle.getMessage(QueryBuilderGraphFrame.class, "PROPERTIES")); // NOI18N
545         menuItem.addActionListener(this);
546         backgroundPopup.add(menuItem);
547          */

548         
549         return (backgroundPopup);
550     }
551     
552     // Create a menu that will appear when the user clicks on the title bar of a node (table)
553

554     JPopupMenu JavaDoc createTableTitlePopup() {
555         
556         JPopupMenu JavaDoc tableTitlePopup;
557         JMenu JavaDoc menu, subMenu;
558         JMenuItem JavaDoc menuItem;
559         JMenuItem JavaDoc subMenuItem;
560         
561         // Create the popup menu.
562
tableTitlePopup = new JPopupMenu JavaDoc();
563         
564         /*
565         menuItem = new JMenuItem(NbBundle.getMessage(QueryBuilderGraphFrame.class, "COLUMN_NAMES")); // NOI18N
566         menuItem.addActionListener(this);
567         tableTitlePopup.add(menuItem);
568          
569         menuItem = new JMenuItem(NbBundle.getMessage(QueryBuilderGraphFrame.class, "TABLE_NAME_ONLY")); // NOI18N
570         menuItem.addActionListener(this);
571         tableTitlePopup.add(menuItem);
572          
573         menuItem = new JMenuItem(NbBundle.getMessage(QueryBuilderGraphFrame.class, "SELECT_ALL_COLUMNS")); // NOI18N
574         menuItem.addActionListener(this);
575         tableTitlePopup.add(menuItem);
576          */

577         
578         menuItem = new JMenuItem JavaDoc(NbBundle.getMessage(QueryBuilderGraphFrame.class, "REMOVE_FROM_QUERY")); // NOI18N
579
menuItem.addActionListener(this);
580         tableTitlePopup.add(menuItem);
581         
582         /*
583          * 4979425
584         menuItem = new JMenuItem(NbBundle.getMessage(QueryBuilderGraphFrame.class, "PROPERTIES")); // NOI18N
585         menuItem.addActionListener(this);
586         tableTitlePopup.add(menuItem);
587          */

588         
589         return (tableTitlePopup);
590     }
591     
592     
593     // A class for listeners that will bring up the TableTitlePopup menu.
594
// An instance of this class will listen on every new InternalFrame
595
// (table node)
596

597     class TableTitlePopupListener extends MouseAdapter {
598         
599         public void mousePressed(MouseEvent e) {
600             maybeShowPopup(e);
601         }
602         
603         public void mouseReleased(MouseEvent e) {
604             maybeShowPopup(e);
605         }
606         
607         private void maybeShowPopup(MouseEvent e) {
608             if (e.isPopupTrigger() && e.getComponent().isEnabled()) {
609                 _tableTitlePopup.show(e.getComponent(),
610                         e.getX(), e.getY());
611             }
612         }
613     }
614     
615     // Returns just the class name -- no package info.
616
protected String JavaDoc getClassName(Object JavaDoc o) {
617         String JavaDoc classString = o.getClass().getName();
618         int dotIndex = classString.lastIndexOf("."); // NOI18N
619
return classString.substring(dotIndex+1);
620     }
621     
622     // Specified by TableModelListener.
623
// Invoked when a TableModel generates an event; implemented by JTable.
624
// Events come from both QueryBuilderTableModel and
625
// QueryBuilderInputTableModel,
626
// The QueryBuilderTableModel indicates columns that are
627
// selected/deselected; that in turn
628
// causes them to be added/dropped from the InputTable
629

630     public void tableChanged(TableModelEvent JavaDoc e) {
631         
632         // if the graph is disabled, do not handle any events.
633
if ( _disableQBGF ) return;
634         
635         // if the graph is being generated from model, do not handle events.
636
if (_queryBuilder._updateModel == false) return;
637         
638         Log.err.log(ErrorManager.INFORMATIONAL,
639                 "Entering QBGF.tableChanged, source: " + e.getSource()); // NOI18N
640
if (DEBUG)
641             System.out.println("Entering QBGF.tableChanged source = " + e.getSource()); // NOI18N
642

643         if (e.getSource() instanceof QueryBuilderTableModel)
644             tableModelChanged(e);
645         
646         else if (e.getSource() instanceof QueryBuilderInputTableModel)
647             inputTableModelChanged(e);
648     }
649     
650     
651     // Called when we have received a change in a graph node
652

653     private void tableModelChanged(TableModelEvent JavaDoc e) {
654         
655         Log.err.log(ErrorManager.INFORMATIONAL, "Entering QBGF.tableModelChanged");
656         // We have a mouse click inside a graph table node, indicating select/deselect.
657
// Propagate the information to the input table
658

659         // Extract some information from the event
660
int row = e.getFirstRow(); // the first row that changed
661
int column = e.getColumn(); // the column for this event
662

663         QueryBuilderTableModel model = (QueryBuilderTableModel) e.getSource();
664         String JavaDoc tableSpec = model.getTableSpec();
665         
666         // DB column name
667
String JavaDoc columnName = (String JavaDoc) model.getValueAt(row, column+2);
668         
669         // boolean - Selected/deselected
670
Object JavaDoc value = model.getValueAt(row, column);
671         
672         // ask Val if this should be THE behavior
673
// if (value==Boolean.TRUE) && data.equals("* { All Columns }"))
674
// { _inputTableModel.addRow (rowData);
675
// _inputTableModel.setValueAt ("*", _inputTableModel.getRowCount()-1, 0);
676
// for (int i =1; i < model.getRowCount(); i++) model.setValueAt(Boolean.TRUE, i, 0);
677
// }
678
// else if (value==Boolean.FALSE) && data.equals("* { All Columns }"))
679
// { _inputTableModel.setValueAt ("", _inputTableModel.getRowCount()-1, 0);
680
// for (int i =1; i < model.getRowCount(); i++) model.setValueAt(Boolean.FALSE, i, 0);
681
// }
682

683         if (value==Boolean.TRUE) { // A column has been selected
684

685             // Update the query model if appropriate
686
// Do this first so that it's available when adding the row
687
if (_queryBuilder._updateModel) {
688                 _queryBuilder.getQueryModel().addColumn(tableSpec, columnName);
689                 _queryBuilderInputTable.selectColumn(tableSpec, columnName, Boolean.TRUE);
690             }
691             // handle this in createNode.
692

693             // Add a row to the InputTableModel
694
// _queryBuilderInputTable.addRow(tableSpec, columnName);
695
// _queryBuilderInputTable.selectColumn(tableSpec, columnName, Boolean.TRUE);
696

697         }
698         
699         else if (value==Boolean.FALSE) { // A column has been deselected
700

701             // Update the query model, if we're not being driven by it
702
// Do this before updating the grid, because we use the model to generate sortorder
703
if (_queryBuilder._updateModel) {
704                 _queryBuilder.getQueryModel().removeColumn(tableSpec, columnName); }
705             
706             // do not remove the whole row, just deselect the output column.
707
_queryBuilderInputTable.selectColumn(tableSpec, columnName, Boolean.FALSE);
708             
709             // Remove a row from the InputTableModel
710
// _queryBuilderInputTable.removeRow(tableSpec, columnName);
711

712             // If we've removed the last selected column from a table, drop it.
713
// **Revision: do not drop it -- the table could still affect the query.
714
// If we wanted to be clever, we could remove the table iff it is no longer
715
// mentioned in any part except the from, but that's not necessary.
716
// if ( _queryBuilder.getQueryModel().isSelectColumnCountZero(tableSpec) ) {
717
// QueryBuilderInternalFrame currentSelectedFrame =
718
// (QueryBuilderInternalFrame)_desktopPane.getSelectedFrame();
719
// removeTable(currentSelectedFrame);
720
// }
721
}
722         
723         // We used to update the text query after every event. That
724
// caused degraded performance. Now, we check whether we've
725
// received a real event, or we're generating the graph as a
726
// batch operation. Also, we trigger only on TableModel events,
727
// so InputTableMode must explicitly invoke
728
if (_queryBuilder._updateText) {
729             // An interactive event -- update the text query
730
_queryBuilder.generateText();
731         }
732     }
733     
734     
735     // Called when we have received a change in the input table.
736

737     private void inputTableModelChanged(TableModelEvent JavaDoc e) {
738         
739         Log.err.log(ErrorManager.INFORMATIONAL, "Entering QBGF.inputTableModelChanged");
740         
741         // if _inputTableAddCriteria is true we should not handle any
742
// events. This is set when the events are not directly generated
743
// by the user interaction. e.g. when we set value of say
744
// Criteria column, CriteriaOrder column will be set a value.
745
// To avoid the recursive calls this is used.
746
if (_inputTableAddCriteria)
747             return;
748         
749         // Only pay attention to changes to the output column
750
// Propagate information to the graph node for this table
751

752         // ** We could also do this by listening to the checkbox for
753
// the particular column in QueryBuilderInputTable, the same
754
// as we do for SortType, SortOrder, and AddCriteria **
755

756         // Extract some information from the event, and dispatch on column
757
int column = e.getColumn(); // the column for this event
758
int row = e.getFirstRow(); // the first row that changed
759
QueryBuilderInputTableModel model = (QueryBuilderInputTableModel) e.getSource();
760         
761         if (column!=-1) {
762             
763             String JavaDoc columnName = (String JavaDoc) model.getValueAt(row, QueryBuilderInputTable.Column_COLUMN);
764             String JavaDoc tableSpec = (String JavaDoc) model.getValueAt(row, QueryBuilderInputTable.Table_COLUMN);
765             
766             if (DEBUG)
767                 System.out.println("QBGF.iTMC, row: "+row + " columnName: "+columnName + // NOI18N
768
" column: "+column); // NOI18N
769

770             if (column==QueryBuilderInputTable.Alias_COLUMN) {
771                 
772                 String JavaDoc result = ((String JavaDoc) model.getValueAt(row,
773                         QueryBuilderInputTable.Alias_COLUMN )).trim();
774                 if ( result == null || result.length() == 0 ) // Clear alias
775
_queryBuilder.getQueryModel().removeDerivedColName( tableSpec, columnName );
776                 else
777                     _queryBuilder.getQueryModel().setDerivedColName(tableSpec, columnName, result);
778                 
779                 // Regenerate the query, if someone else isn't doing it
780
if (_queryBuilder._updateText)
781                     _queryBuilder.generateText();
782             }
783             if (column==QueryBuilderInputTable.Output_COLUMN) {
784                 
785                 Boolean JavaDoc value = (Boolean JavaDoc) model.getValueAt(row, column); // Selected/deselected
786
DefaultGraphCell dgc = findNode(tableSpec);
787                 QueryBuilderInternalFrame qbif =
788                         (QueryBuilderInternalFrame) dgc.getUserObject();
789                 QueryBuilderTableModel qbtm = qbif.getQueryBuilderTableModel();
790                 qbtm.selectColumn(columnName, value);
791             } else if (column==QueryBuilderInputTable.Criteria_COLUMN) {
792                 
793                 String JavaDoc result = ((String JavaDoc) model.getValueAt(row,
794                         QueryBuilderInputTable.Criteria_COLUMN )).trim();
795                 
796                 // The the value is "" remove the criteria order from the combo box
797
if ( result != null && result.length() == 0 ) {
798                     // The following lines appear to be unnecessary
799
_inputTableAddCriteria = true;
800                     model.setValueAt("", row,QueryBuilderInputTable.CriteriaOrder_COLUMN); // NOI18N
801
_inputTableAddCriteria = false;
802                     _queryBuilder.getQueryModel().removeCriteria( tableSpec, columnName, 1 );
803                 } else if ( result.trim().equals(QueryBuilderInputTable.Criteria_Uneditable_String)) {
804                     return;
805                 } else {
806                     Predicate pred = checkCriteria( tableSpec, columnName, result ) ;
807                     if ( pred == null ) {
808                         _queryBuilderInputTable.getModel().setValueAt("",row, column); // NOI18N
809
return;
810                     }
811                     
812                     int criteriaCount=
813                             _queryBuilder.getQueryModel().getCriteriaCount();
814                     String JavaDoc order = (String JavaDoc)model.getValueAt(row,
815                             QueryBuilderInputTable.CriteriaOrder_COLUMN);
816                     if (order != null && order.trim().length() !=0 &&
817                             order.trim().equals(QueryBuilderInputTable.CriteriaOrder_Uneditable_String)) {
818                         return;
819                     }
820                     int orderNum = ((order == null) || (order.trim().length()==0))
821                     ? criteriaCount+1
822                             : Integer.parseInt(order);
823                     _inputTableAddCriteria = true;
824                     model.setValueAt(new Integer JavaDoc(orderNum).toString(), row,
825                             QueryBuilderInputTable.CriteriaOrder_COLUMN);
826                     _inputTableAddCriteria = false;
827                     if ( orderNum < criteriaCount+1 ) {
828                         _queryBuilder.getQueryModel().
829                                 replaceCriteria(tableSpec, columnName, pred, orderNum);
830                     } else {
831                         _queryBuilder.getQueryModel().
832                                 addCriteria(tableSpec, columnName, pred);
833                     }
834                 }
835                 _queryBuilderInputTable.clearSelection();
836                 _inputTableAddCriteria = true;
837                 // Regenerate the input table, based on the latest change.
838
// Is this necessary? May be required to get Criteria Order right
839
_queryBuilderInputTable.generateTableWhere(_queryBuilder.getQueryModel());
840                 _inputTableAddCriteria = false;
841                 // Regenerate the query, if someone else isn't doing it
842
if (_queryBuilder._updateText)
843                     _queryBuilder.generateText();
844             } else if (column==QueryBuilderInputTable.CriteriaOrder_COLUMN) {
845                 
846                 String JavaDoc criteria = ( (String JavaDoc) model.getValueAt(row,
847                         QueryBuilderInputTable.Criteria_COLUMN ) ).trim();
848                 String JavaDoc order = (String JavaDoc) model.getValueAt(row,column );
849                 
850                 if (order != null && order.trim().length() !=0 &&
851                         order.trim().equals(QueryBuilderInputTable.CriteriaOrder_Uneditable_String )) {
852                     return;
853                 }
854                 // remove the old criteria first anyway
855
_queryBuilder.getQueryModel().removeCriteria( tableSpec, columnName, 1 );
856                 
857                 if ((order == null) || (order.trim().length()==0)) {
858                     _inputTableAddCriteria = true;
859                     model.setValueAt("", row,QueryBuilderInputTable.Criteria_COLUMN); // NOI18N
860
_inputTableAddCriteria = false;
861                 } else {
862                     int orderNum = Integer.parseInt(order);
863                     
864                     Predicate pred = checkCriteria( tableSpec, columnName,
865                             criteria ) ;
866                     if ( pred == null ) {
867                         _queryBuilderInputTable.getModel().setValueAt("",row, column); // NOI18N
868
return;
869                     }
870                     
871                     if (criteria.trim().length() != 0 ) {
872                         _queryBuilder.getQueryModel().addCriteria(tableSpec, columnName, pred, orderNum);
873                     }
874                 }
875                 
876                 _queryBuilderInputTable.clearSelection();
877                 _inputTableAddCriteria = true;
878                 _queryBuilderInputTable.generateTableWhere(_queryBuilder.getQueryModel());
879                 _inputTableAddCriteria = false;
880                 if (_queryBuilder._updateText)
881                     _queryBuilder.generateText();
882                 return;
883             }
884             if (_queryBuilder._updateText) {
885                 _queryBuilder.generateText();
886             }
887         }
888     }
889     
890     
891     /**
892      * Given a criteria string retrun Predicate or null if result is
893      * an error. Displays appropriate message.
894      */

895     private Predicate checkCriteria( String JavaDoc tableSpec, String JavaDoc columnName, String JavaDoc result ) {
896         String JavaDoc op=null;
897         String JavaDoc val=null;
898         if ( result.startsWith(">=") ) { // NOI18N
899
op = ">="; // NOI18N
900
val = result.substring(2).trim();
901         } else if ( result.startsWith("<=") ) { // NOI18N
902
op = "<="; // NOI18N
903
val = result.substring(2).trim();
904         } else if ( result.startsWith("<>") ) { // NOI18N
905
op = "<>"; // NOI18N
906
val = result.substring(2).trim();
907         } else if ( result.startsWith(">") ) { // NOI18N
908
op = ">"; // NOI18N
909
val = result.substring(1).trim();
910         } else if ( result.startsWith("<") ) { // NOI18N
911
op = "<"; // NOI18N
912
val = result.substring(1).trim();
913         } else if ( result.startsWith("=") ) { // NOI18N
914
op = "="; // NOI18N
915
val = result.substring(1).trim();
916         } else if ( result.toUpperCase().startsWith("LIKE" ) ) { // NOI18N
917
op = " LIKE "; // NOI18N
918
val = result.substring(5).trim();
919         } else if ( result.toUpperCase().startsWith("IN" ) ) { // NOI18N
920
op = " IN "; // NOI18N
921
val = result.substring(3).trim();
922         }
923         
924         // if val or op is still null
925
// display an error and clear the cell and return.
926
if ( op == null || (op.trim().length() == 0) || val == null || (val.trim().length() == 0 ) ) {
927             String JavaDoc msg = NbBundle.getMessage(QueryBuilderGraphFrame.class, "CRITERIA_ERROR"); // NOI18N
928
NotifyDescriptor d =
929                     new NotifyDescriptor.Message(msg + "\n\n", NotifyDescriptor.ERROR_MESSAGE); // NOI18N
930
DialogDisplayer.getDefault().notify(d);
931             _queryBuilderInputTable.clearSelection();
932             return null;
933         }
934         
935         Column JavaDoc col1 = SQLQueryFactory.createColumn(tableSpec, columnName);
936         Predicate pred = SQLQueryFactory.createPredicate(col1, val, op);
937         
938         return pred;
939     }
940     
941     public void setCurrentSelectedFrameTitle( String JavaDoc title ) {
942         if ((QueryBuilderInternalFrame)_desktopPane.getSelectedFrame() != null )
943             ((QueryBuilderInternalFrame)_desktopPane.getSelectedFrame()).setTitle(title);
944     }
945     
946     // Add a node (representing a database table) to the query graph
947
// If _updateModel is true, add edges corresponding to any FK relationships
948
// ToDo: Add provisions for selecting only some of the columns in the table
949
// for inclusion in the query.
950
private void insertTableInteractively(String JavaDoc fullTableName) {
951         if (DEBUG) {
952             System.out.println(
953                     "Entering QBGF.insertTableInteractively, fullTableName: " + fullTableName + " queryBuilder.queryModel : " + _queryBuilder._queryModel); // NOI18N
954
}
955         Log.err.log(ErrorManager.INFORMATIONAL,
956                 "Entering QBGF.insertTableInteractively, fullTableName: " + fullTableName); // NOI18N
957

958         // fix for 6316681 Opening QE on a rowset where command=null throws NPE
959
// If the query model is null then the QueryBuilder was not opened
960
// before. So for the initial table populate the command
961
// This will initiate the QueryBuilder properly.
962
if ( ( _queryBuilder.getQueryModel() == null ) ||
963                 ( _queryBuilder.getQueryModel().genText() == null ) ) {
964             String JavaDoc query = new String JavaDoc("select * from " + fullTableName);
965             _queryBuilder.populate(query);
966             _queryBuilder.setSqlCommand(query);
967             return;
968         }
969         
970         // Disable text query re-generation until we're ready
971
QueryBuilder.showBusyCursor( true );
972         _queryBuilder._updateText=false;
973         try {
974             // Extend to handle full tablespec, including schema
975
String JavaDoc schemaName=null, tableName, tabName;
976             String JavaDoc[] res = fullTableName.split("\\."); // NOI18N
977
if (res.length>1) {
978                 schemaName=res[0];
979                 tabName=res[1];
980             } else
981                 tabName=fullTableName;
982             
983             /*
984             if ( !tabName.startsWith("\"") && (tabName.indexOf(' ') != -1) ) {
985                 tableName = new String ("\"" + tabName + "\"" );
986             }
987             else {
988              */

989             tableName = new String JavaDoc(tabName);
990             /*
991              }
992              */

993             
994             // Create the querymodel object representing the table to be added
995
String JavaDoc corrName=_queryBuilder.getQueryModel().genUniqueName(fullTableName);
996             Table tbl = (corrName==null) ?
997                 SQLQueryFactory.createTable(tableName, null, schemaName) :
998                 SQLQueryFactory.createTable(tableName, corrName, schemaName);
999             JoinTable joinTable=SQLQueryFactory.createJoinTable(tbl);
1000            
1001            List JavaDoc columnNames = new ArrayList JavaDoc();
1002            columnNames.add("*"); // NOI18N
1003

1004            // Insert the table into the model first, so that column insertions can refer to it
1005
_queryBuilder.getQueryModel().insertTable(joinTable);
1006            
1007            // Insert the node into the graph
1008
QueryBuilderInternalFrame internalFrame = insertTable(joinTable, columnNames);
1009            if ( internalFrame == null ) {
1010                QueryBuilder.showBusyCursor( false );
1011                return;
1012            }
1013            
1014            // Add appropriate edges in the graph to connect the new node to previous ones,
1015
// based entirely on relationships (Foreign Key constraints)
1016
// This should be refactored, to do computation of edges separately
1017
List JavaDoc edges = insertFKEdges(internalFrame.getGraphCell(), fullTableName);
1018            // Add the relationships for this table into the model, based in the edges
1019
_queryBuilder.getQueryModel().addRelationships(joinTable, edges);
1020            
1021            // Redraw the new frame. Must be done after adding edges, to work around
1022
// some painting glitches.
1023
// redrawFrame(currentSelectedFrame);
1024
redrawFrame(internalFrame);
1025            
1026            try {
1027                // Make the new frame the selected one
1028
internalFrame.setSelected(true);
1029                // Update the [0,0] cell for the table model; wasn't this already false?
1030
// This will cause an event to fire, but it's not clear what the intent was.
1031
// internalFrame.getQueryBuilderTableModel().setValueAt(Boolean.FALSE, 0, 0);
1032
_desktopPane.setSelectedFrame(internalFrame);
1033                setActivatedNode( internalFrame ) ;
1034            } catch(PropertyVetoException JavaDoc pve) {
1035            }
1036            
1037            _firstTableInserted = true;
1038        } finally {
1039            _queryBuilder._updateText=true;
1040            QueryBuilder.showBusyCursor( false );
1041        }
1042    }
1043    
1044    
1045    // Add a node to the query graph, based on the parsed query
1046
// ToDo: Generalize this to support joinTable with conjoined predicates
1047

1048    void insertTableFromModel(JoinTable joinTable, List JavaDoc columnNames) {
1049        Log.err.log(ErrorManager.INFORMATIONAL,
1050                "Entering QBGF.insertTableFromModel, tablespec: " + joinTable.getTableSpec()); // NOI18N
1051

1052        // Save the state of _updateText
1053
boolean updateText = _queryBuilder._updateText;
1054        _queryBuilder._updateText=false;
1055        try {
1056            QueryBuilderInternalFrame internalFrame = insertTable(joinTable, columnNames);
1057            if ( internalFrame == null ) return;
1058            
1059            // Insert the edges that are explicitly specified in the query
1060
insertJoinEdges(joinTable);
1061            
1062// if (DEBUG)
1063
// perfTimer.print("insertTableInGraph: After inserting edges");
1064

1065            redrawFrame(internalFrame);
1066            
1067            // ToDo: This code used to be called twice. Decide whether there was a reason for it.
1068
try {
1069                // Make the new frame the selected one
1070
internalFrame.setSelected(true);
1071                // Update the [0,0] cell for the table model; wasn't this already false?
1072
// This will cause an event to fire, but it's not clear what the intent was.
1073
// internalFrame.getQueryBuilderTableModel().setValueAt(Boolean.FALSE, 0, 0);
1074
_desktopPane.setSelectedFrame(internalFrame);
1075                _queryBuilder.enableDelete();
1076                runQueryMenuItem.setEnabled(true);
1077                groupByMenuItem.setEnabled(true);
1078            } catch(PropertyVetoException JavaDoc pve) {
1079            }
1080            
1081            _firstTableInserted = true;
1082        } finally {
1083            _queryBuilder._updateText=updateText;
1084        }
1085    }
1086    
1087    
1088    // Insert a table into the query graph
1089

1090    QueryBuilderInternalFrame insertTable(JoinTable joinTable, List JavaDoc columnNames) {
1091        
1092        Log.err.log(ErrorManager.INFORMATIONAL, "Entering QBGF.insertTable"); // NOI18N
1093

1094        // if ( _queryBuilder.checkDatabaseAndDisable(null) == false ) return null;
1095

1096        // you can not insert a non-existent table.
1097
String JavaDoc joinTableName = joinTable.getFullTableName();
1098        
1099        // Create the internal frame
1100
QueryBuilderInternalFrame internalFrame = createNode(joinTable, columnNames);
1101        
1102        // Set a location for it
1103
internalFrame.setLocation(getNextLocation(internalFrame));
1104        Log.err.log(ErrorManager.INFORMATIONAL,
1105                "Location for new cell: " + internalFrame.getLocation()); // NOI18N
1106

1107        //Add new cell (table) to graph model, with the internalFrame as userObject
1108
DefaultGraphCell insertCell = new DefaultGraphCell(internalFrame);
1109        internalFrame.setGraphCell(insertCell);
1110        // Add a listener to the title bar (or outside edge) of the new frame
1111
MouseListener tableTitlePopupListener = new TableTitlePopupListener();
1112        // trying to handle different LNFs
1113
try {
1114            if (!System.getProperty("os.name").startsWith("Mac OS")) // NOI18N
1115
((BasicInternalFrameUI JavaDoc)internalFrame.getUI()).getNorthPane().addMouseListener(tableTitlePopupListener);
1116            else
1117                internalFrame.addMouseListener(tableTitlePopupListener);
1118        } catch (Exception JavaDoc e) {
1119            e.printStackTrace();
1120        }
1121        
1122        // Insert the cell, without any edges
1123
Object JavaDoc insertCells[] = new Object JavaDoc[] {insertCell};
1124        _graphModel.insert(insertCells,null,null,null,null);
1125        
1126// if (DEBUG) {
1127
// perfTimer.print("insertTableInGraph: After inserting cell"); // NOI18N
1128
// printRoots();
1129
// }
1130

1131        // Add listeners that notice when the frame is activated, or moved/resized
1132
internalFrame.addInternalFrameListener(_fsl);
1133        internalFrame.addComponentListener(_fcl);
1134        
1135        // Add the internal frame to the desktopPane. Per the JInternalFrame demo this seems to be
1136
// necessary (marked VERY IMPORTANT), but needs to be undone if we delete it.
1137
_desktopPane.add(internalFrame);
1138        
1139        refresh();
1140        
1141        return internalFrame;
1142    }
1143    
1144    
1145    // Create an internal frame, which will represent a table in the graph
1146

1147    QueryBuilderInternalFrame createNode(JoinTable joinTable, List JavaDoc selectColumnNames) {
1148        
1149        String JavaDoc fullTableName = joinTable.getFullTableName();
1150        String JavaDoc[] table = fullTableName.split("\\."); // NOI18N
1151
String JavaDoc tableName = (table.length>1) ? table[1] : table[0];
1152        String JavaDoc corrName = joinTable.getCorrName();
1153        
1154        String JavaDoc tableSpec = ((corrName!=null) ? corrName : fullTableName);
1155        
1156        Log.err.log(ErrorManager.INFORMATIONAL,
1157                "Entering QBGF.createNode, fullTableName: " + fullTableName + " corrName: " + corrName); // NOI18N
1158

1159        // Correct case of table name...
1160
try { // TODO JFB shouldn't catch this...
1161
String JavaDoc newS = _queryBuilder.checkFullTableName(fullTableName) ;
1162            if ( newS != null & ! fullTableName.equals(newS)) {
1163                fullTableName = newS ;
1164                Log.log(" fullTableName corrected to " + fullTableName ) ;
1165            }
1166        } catch (SQLException se) {
1167            Log.log( " fullTableName " + se.getMessage() ) ;
1168        }
1169        
1170        final String JavaDoc[] columnNames = {"", // "Output", // NOI18N
1171
"", // NOI18N
1172
"" // "Column" // NOI18N
1173
};
1174        
1175        //Create initial internal frame
1176
Object JavaDoc [][] dbData ;
1177        
1178        
1179        List JavaDoc dbColumnNames ;
1180        try {
1181            dbColumnNames = _queryBuilder.getColumnNames(fullTableName);
1182        } catch(SQLException sqle) {
1183            dbColumnNames = new ArrayList JavaDoc() ;
1184        }
1185        
1186        // This data will populate the QueryBuilderTableModel, which represents
1187
// the schema information shown inside the table node
1188
dbData = new Object JavaDoc[dbColumnNames.size()/* +1 */][3];
1189        Iterator JavaDoc iterator = dbColumnNames.iterator();
1190        
1191        // Fencepost case for the first row
1192
// Remove for the time being
1193
// Restore later if we have decide to handle '* { All Columns }'
1194
/*
1195          dbData[0][0] = Boolean.FALSE;
1196          dbData[0][1] = null;
1197          dbData[0][2] = new String("* { All Columns }"); // NOI18N
1198         */

1199        
1200        // Primary keys and foreign keys are marked with special icons
1201
List JavaDoc primaryKeys = null ,foreignKeyCols = null ;
1202        try {
1203            primaryKeys = _queryBuilder.getPrimaryKeys(fullTableName);
1204            foreignKeyCols = _queryBuilder.getImportedKeyColumns(fullTableName);
1205        } catch (SQLException sqle) {
1206            // HACK! log and dispose
1207
Log.err.log(ErrorManager.WARNING, "QueryBuilderGraphFrame: cannot get info " + sqle.getLocalizedMessage()) ;
1208            primaryKeys = new ArrayList JavaDoc() ;
1209            foreignKeyCols = new ArrayList JavaDoc() ;
1210        }
1211        
1212        int i = 0;
1213        
1214        // Iterate through the column names
1215
// Put a check by any that are included in the Select clause
1216
while (iterator.hasNext() && i < dbColumnNames.size() /* +1 */) {
1217            
1218            String JavaDoc columnName = new String JavaDoc(iterator.next().toString()) ;
1219            
1220            // Mark them all as selected/deselected, based on Select clause
1221
if (selectColumnNames.contains("*") || selectColumnNames.contains(columnName)) // NOI18N
1222
dbData[i][0] = Boolean.TRUE;
1223            else
1224                dbData[i][0] = Boolean.FALSE;
1225            
1226            // Check if this is primary or foreign key and then attach appropriate icon
1227
// JLabel (String text, Icon image, SwingConstants.LEFT);
1228
// We used to use toUpperCase() during comparison, but drop that now that we are
1229
// canonicalizing table/column names.
1230
if (primaryKeys.contains(columnName.trim()))
1231                dbData[i][1] = new ImageIcon JavaDoc(url_primary_key);
1232            else if (foreignKeyCols.contains(columnName.trim()))
1233                dbData[i][1] = new ImageIcon JavaDoc(url_foreign_key);
1234            else
1235                dbData[i][1] = null;
1236            
1237            dbData[i][2] = columnName;
1238            _queryBuilderInputTable.addRow(tableSpec, columnName);
1239            _queryBuilderInputTable.selectColumn(tableSpec, columnName, (Boolean JavaDoc) dbData[i][0]);
1240            i++;
1241        }
1242        
1243        // Create a model from the column info, and wrap it in a frame
1244
QueryBuilderTableModel qbtModel =
1245                new QueryBuilderTableModel(fullTableName, corrName, columnNames, dbData);
1246        QueryBuilderInternalFrame internalFrame = new QueryBuilderInternalFrame(qbtModel, _queryBuilder);
1247        internalFrame.addKeyListener(this);
1248        qbtModel.addTableModelListener(this);
1249        
1250        // This action is now incorporated into the initialization loop above
1251
// We end up doing it again in order to propagate the events
1252
// Update the internalframe. By event propagation, will update the input table.
1253
// ToDo: Replace this with an explicit update to the InputTableModel.
1254
// This also sets all db columns to display, which is the wrong thing!!!
1255
// We need some way to update the input table. fireTableDataChanged will raise
1256
// an event, but the listener doesn't handle it right. Instead, explicitly update
1257
// the table.
1258
// Add one row to the input table for each column that appears in this node.
1259
// The current code for adding rows is designed to support interactive mouse clicks,
1260
// in tableChanged. We may want to break that out into a separate routine for
1261
// calling from here.
1262

1263        for (i =0; i < qbtModel.getRowCount(); i++) {
1264            qbtModel.setValueAt(dbData[i][0], i, 0);
1265        }
1266        
1267        
1268        // Set the various contents of the internal frame
1269
internalFrame.create();
1270        String JavaDoc title = (corrName==null) ? tableName : corrName+": "+tableName; // NOI18N
1271
internalFrame.setTitle(title);
1272        
1273        Log.err.log(ErrorManager.INFORMATIONAL, "TableName for new cell: " + tableName); // NOI18N
1274

1275        return internalFrame;
1276    }
1277    
1278    
1279    // Insert edges that are implied by Foreign Key constraints between existing nodes
1280
// and the new one. Return the list of FKs that are used.
1281
// ToDo: Enable support for multiple edges between a pair of nodes
1282

1283    private List JavaDoc insertFKEdges(DefaultGraphCell newCell, String JavaDoc newFullTableName) {
1284        Log.err.log(ErrorManager.INFORMATIONAL,
1285                "Entering QBGF.insertFKEdges, newFullTableName: " + newFullTableName); // NOI18N
1286

1287        // Get foreign key information, for deciding relationship status
1288
// Do this once, to avoid repeated calls to database
1289
List JavaDoc foreignKeys ;
1290        try {
1291            foreignKeys = _queryBuilder.getForeignKeys(newFullTableName);
1292        } catch (SQLException sqle) {
1293            foreignKeys = new ArrayList JavaDoc() ;
1294        }
1295        List JavaDoc foreignKeysUsed = new ArrayList JavaDoc();
1296        
1297        // Iterate through the current set of roots, drawing arcs to the new node as needed
1298
for (int i=0; i<_graphModel.getRootCount(); i++) {
1299            
1300            Object JavaDoc root = _graphModel.getRootAt(i);
1301            
1302            // Check whether this root is related to the new one
1303
String JavaDoc[] fk;
1304            
1305            if ((root instanceof DefaultGraphCell) // Do we have a cell of some form?
1306
&& !(_graphModel.isEdge(root)) // ... that is a node, not an edge?
1307
&& (root != newCell)) // ... and is not the cell we just created?
1308
{
1309                DefaultGraphCell oldCell = (DefaultGraphCell)root;
1310                String JavaDoc oldFullTableName=((QueryBuilderInternalFrame)oldCell.getUserObject()).getFullTableName();
1311                if ((fk=_queryBuilder.findForeignKey(oldFullTableName,newFullTableName,foreignKeys)) != null)
1312                    // ... and is related to the new cell by an FK?
1313
{
1314                    String JavaDoc oldTableSpec=((QueryBuilderInternalFrame)oldCell.getUserObject()).getTableSpec();
1315                    String JavaDoc newTableSpec=((QueryBuilderInternalFrame)newCell.getUserObject()).getTableSpec();
1316                    // Insert an edge between the existing cell and the new one
1317
// Directionality (old -> new) is just a convention, since we make the choice
1318
// fix for 6270428 : querybuilder Issues with SELF JOIN
1319
// having self referential integrity (Employee-Manager
1320
// Scenario)
1321
if ( fk[0].equals(fk[2]) ) {
1322                        fk[0] = oldTableSpec;
1323                        fk[2] = newTableSpec;
1324                    }
1325                    // Default to INNER
1326
insertEdge(oldCell, newCell, oldFullTableName, newFullTableName, oldTableSpec,
1327                            newTableSpec, null, null, fk, "INNER");
1328                    foreignKeysUsed.add(fk);
1329                }
1330            }
1331        }
1332        return foreignKeysUsed;
1333    }
1334    
1335    
1336    // Insert edges connected to this table, which are implied by the join conditions
1337
// associate with the table in the FROM list
1338
void insertJoinEdges(JoinTable joinTable) {
1339        
1340        Log.err.log(ErrorManager.INFORMATIONAL, "Entering insertJoinEdges"); // NOI18N
1341
// We're generating the graph from the model.
1342
// Don't look for new edges to add, but add the edges that are
1343
// explicitly mentioned in the join condition for this table
1344
String JavaDoc joinType = joinTable.getJoinType();
1345        
1346        // We don't have edges if either
1347
// - this is the first table
1348
// - this is a cross join
1349
// Otherwise, there will be an edge
1350
// Extended 10/22 to support Conditions consisting of conjoined predicates
1351

1352        if ((joinType!=null) && (!joinType.equals("CROSS"))) { // NOI18N
1353

1354            Expression cond = joinTable.getExpression();
1355            if (cond instanceof Predicate) {
1356                Predicate pred = (Predicate) cond;
1357                insertJoinEdge(pred, joinType);
1358            }
1359// else if (cond instanceof And) {
1360
// And a = (And) cond;
1361
// insertMultiJoinEdge(a);
1362
// }
1363
}
1364    }
1365    
1366    
1367    // Insert the graph edge corrsponding to this predicate
1368
void insertJoinEdge(Predicate pred, String JavaDoc joinType) {
1369        
1370        Log.err.log(ErrorManager.INFORMATIONAL, "QBGF.Entering insertJoinEdge"); // NOI18N
1371

1372        Value val1 = pred.getVal1();
1373        Value val2 = pred.getVal2();
1374        
1375        // Only insert an edge if we're comparing columns, rather than literals
1376
if ((val1 instanceof Column JavaDoc) && (val2 instanceof Column JavaDoc)) {
1377            
1378            Column JavaDoc col1=(Column JavaDoc)val1;
1379            String JavaDoc tableSpec1 = col1.getTableSpec();
1380            String JavaDoc fullTableName1 = _queryBuilder.getQueryModel().getFullTableName(tableSpec1);
1381            DefaultGraphCell cell1 = findNode(tableSpec1);
1382            String JavaDoc colName1 = col1.getColumnName();
1383            
1384            Column JavaDoc col2=(Column JavaDoc)val2;
1385            String JavaDoc tableSpec2 = col2.getTableSpec();
1386            String JavaDoc fullTableName2 = _queryBuilder.getQueryModel().getFullTableName(tableSpec2);
1387            DefaultGraphCell cell2 = findNode(tableSpec2);
1388            String JavaDoc colName2 = col2.getColumnName();
1389            
1390            if ((cell1==null) || (cell2==null))
1391                Log.err.log(ErrorManager.ERROR, "Could not find node"); // NOI18N
1392
else {
1393                // See if there's a foreign key on exactly this combination of tables/columns
1394
// If not, we will have no direction label on the join
1395
String JavaDoc[] fk = null;
1396                try {
1397                    fk = _queryBuilder.findForeignKey(fullTableName1, colName1, fullTableName2, colName2);
1398                } catch (SQLException sqle) {
1399                    Log.err.log(ErrorManager.WARNING,"QBDF: findforeignKey "+sqle.getLocalizedMessage()) ;
1400                }
1401                
1402                // Direction is cell1 -> cell2, matching the join
1403
// tableName is the table that we are adding
1404
insertEdge(cell1, cell2, fullTableName1, fullTableName2, tableSpec1, tableSpec2,
1405                        colName1, colName2, fk, joinType);
1406            }
1407        }
1408    }
1409    
1410    
1411// /**
1412
// * Insert a thick edge between two nodes, with multiple predicates behind it
1413
// */
1414
// void insertMultiJoinEdge(And a) {
1415

1416// // Test whether this And is suitable
1417
// if ()
1418
// {
1419
// // Do all the predicates mention the same pair of tables
1420
// }
1421
// }
1422

1423    // Insert an edge from one cell to another
1424
// Arrowhead is implied by the FK, if present, else none
1425
// Direction is always cell1 -> cell2
1426
// ToDo: Add an extra arg to represent the join type
1427
// ToDo: Make sure order of cells matches order of JoinCondition
1428
void insertEdge(DefaultGraphCell cell1, DefaultGraphCell cell2,
1429            String JavaDoc fullTableName1, String JavaDoc fullTableName2,
1430            String JavaDoc tableSpec1, String JavaDoc tableSpec2,
1431            String JavaDoc colName1, String JavaDoc colName2,
1432            String JavaDoc[] fk, String JavaDoc joinType) {
1433        Log.err.log(ErrorManager.INFORMATIONAL,
1434                "Entering QBGF.insertEdge, fullTableName1: " + fullTableName1 + // NOI18N
1435
" fullTableName2: " + fullTableName2); // NOI18N
1436

1437        // Create the ports on the two cells
1438
DefaultPort cell1Port = new DefaultPort();
1439        cell1.add(cell1Port);
1440        DefaultPort cell2Port = new DefaultPort();
1441        cell2.add(cell2Port);
1442        
1443        // Initialize the set of attributes for the new edge, and start setting properties
1444
Map JavaDoc atts = GraphConstants.createMap();
1445        
1446        // Create the node object for the edge (for the Property Sheet), and also
1447
// set the arrowhead to show an FK constraint, if any
1448
AbstractNode an;
1449        if (colName1==null) {
1450            
1451            // We are adding the edge interactively, based on the FK
1452
// Use the columns specified in the FK
1453
if (fullTableName1.equalsIgnoreCase(fk[0]))
1454                an = createPropertyNode(tableSpec1, fk[1], tableSpec2, fk[3], joinType, _queryBuilder); // NOI18N
1455
else
1456                an = createPropertyNode(tableSpec2, fk[1], tableSpec1, fk[3], joinType, _queryBuilder); // NOI18N
1457

1458        } else {
1459            // Adding an edge from the model, based on join condition
1460
an = createPropertyNode(tableSpec1, colName1, tableSpec2, colName2, joinType, _queryBuilder); // NOI18N
1461
}
1462        
1463        // If we have an FK, draw the appropriate arrowhead, otherwise don't do anything
1464
if (fk!=null) {
1465            if (fk[0].equalsIgnoreCase(fullTableName1)) {
1466                GraphConstants.setLineEnd(atts,GraphConstants.ARROW_TECHNICAL);
1467                GraphConstants.setEndFill(atts,true);
1468            } else {
1469                GraphConstants.setLineBegin(atts,GraphConstants.ARROW_TECHNICAL);
1470                GraphConstants.setBeginFill(atts,true);
1471            }
1472        }
1473        
1474        GraphConstants.setLineWidth(atts,2);
1475// GraphConstants.setBeginSize(atts,20);
1476

1477        // Create a JGraph edge with the property as its userObject
1478
DefaultEdge edge = new DefaultEdge(an);
1479        
1480        // Wrap the edge and its attributes in a HashMap
1481
HashMap JavaDoc map = new HashMap JavaDoc();
1482        map.put(edge, atts);
1483        
1484        // Create a ConnectionSet with the edge connecting the two cells
1485
ConnectionSet cs = new ConnectionSet(edge, cell1Port, cell2Port);
1486        
1487        // Create a singleton root set containing the edge
1488
Object JavaDoc insertEdges[] = new Object JavaDoc[] {edge};
1489        
1490        // Finally insert the edge, with the associated attributes and connections
1491
_graphModel.insert(insertEdges, map, cs, null, null);
1492        
1493        // Mark the edge as activated (updates property sheet)
1494
_queryBuilder.setActivatedNodes(new Node[] {an});
1495        
1496        QueryBuilderInternalFrame currentSelectedFrame =
1497                (QueryBuilderInternalFrame)_desktopPane.getSelectedFrame();
1498        try {
1499            if ( currentSelectedFrame != null ) {
1500                currentSelectedFrame.setSelected( false );
1501            }
1502        } catch ( java.beans.PropertyVetoException JavaDoc pve ) {
1503            // do nothing
1504
}
1505// // Temporary hack -- redraw frame, because of arrow location glitch
1506
// redrawFrame((QueryBuilderInternalFrame)cell1.getUserObject());
1507
// redrawFrame((QueryBuilderInternalFrame)cell2.getUserObject());
1508
}
1509    
1510    
1511    AbstractNode createPropertyNode(String JavaDoc tableSpec1, String JavaDoc fk1, String JavaDoc tableSpec2, String JavaDoc fk3,
1512            String JavaDoc joinType, QueryBuilder _queryBuilder) {
1513        if ((joinType==null) || (joinType.equals("")))
1514            return new CondNode(tableSpec1, fk1, tableSpec2, fk3, _queryBuilder);
1515        else
1516            return new JoinNode(tableSpec1, fk1, tableSpec2, fk3, joinType, _queryBuilder);
1517    }
1518    
1519    /**
1520     * Remove a table (node) from the graph
1521     */

1522    void removeTable(QueryBuilderInternalFrame currentSelectedFrame) {
1523        String JavaDoc tableSpec = currentSelectedFrame.getTableSpec();
1524        
1525        Log.err.log(ErrorManager.INFORMATIONAL, "Entering QBGF.removeTable, tableSpec: " + tableSpec); // NOI18N
1526
if (DEBUG) {
1527            printRoots();
1528        }
1529        
1530        DefaultGraphCell graphCell = currentSelectedFrame.getGraphCell();
1531        
1532        // Before removing the node, remove all the edges that were connected to it
1533

1534        // Get all ports on the node
1535
List JavaDoc ports = graphCell.getChildren();
1536        
1537        // Traverse from back to front, so removals don't cause instability
1538
for (int i=ports.size()-1; i>=0; i--) {
1539            Port p = (Port)ports.get(i);
1540            
1541            // Get all edges for the port
1542
Iterator JavaDoc edges = p.edges();
1543            while (edges.hasNext()) {
1544                
1545                // Remove this edge
1546
Edge e = (Edge)edges.next();
1547                p.removeEdge(e);
1548                _graphModel.remove(new Object JavaDoc[] {e});
1549            }
1550            
1551            // Remove the port itself from its parent
1552
graphCell.remove(i);
1553        }
1554        
1555        // Remove the node itself from the graph
1556
_graphModel.remove(new Object JavaDoc[] {graphCell});
1557        
1558        // Remove the InternalFrame (graphical node) from the desktop
1559
// Required because we added it earlier
1560
_desktopPane.remove(currentSelectedFrame);
1561        
1562        _desktopPane.setSelectedFrame(null);
1563        
1564        // Update the input table model, by removing all rows that mention this table
1565
_queryBuilderInputTable.removeRows(tableSpec);
1566        
1567        // Now update the QueryModel
1568
// Note that we always do this, since the model-driven graph generation never contain deletion
1569
_queryBuilder.getQueryModel().removeTable(tableSpec);
1570        
1571        _queryBuilder.generate();
1572        
1573        // update the groupby checkbox menu item.
1574
setGroupBy(_queryBuilder.getQueryModel().hasGroupBy() );
1575        
1576        int tableCount = 0;
1577        Component JavaDoc[] comps = _desktopPane.getComponents();
1578        for(int i=0; i<comps.length; i++) {
1579            Component JavaDoc comp = comps[i];
1580            if (comp instanceof QueryBuilderInternalFrame) {
1581                // somehow the graph still thinks we are not changed enough to redraw.
1582
// this causes the edges not to get drawn, as well as the scroll bars
1583
// not getting updated.
1584
redrawFrameWithMove( (QueryBuilderInternalFrame) comp );
1585                tableCount++;
1586            }
1587        }
1588        if ( tableCount == 0 ) {
1589            _firstTableInserted = false;
1590            _queryBuilder.setActivatedNodes(new Node[0]);
1591            _queryBuilder.activateActions();
1592        }
1593    }
1594    
1595    // Generate the Graph and Table from a query model
1596
// General algorithm:
1597
// - Select clause defines the internal frame (node for each Table)
1598
// - From clause defines the structure of the Graph
1599
// - Where clause has no effect on Graph, but does affect the tabular version
1600
// - Group by, Having, Order by are not shown in the Graph at all
1601
// Select clause entries in the table are filled in as a side effect during createNode
1602

1603    void generateGraph(QueryModel query) {
1604        
1605        if ( _disableQBGF ) return;
1606        
1607        Log.err.log(ErrorManager.INFORMATIONAL, "Entering QueryBuilderGraphFrame.generateGraph"); // NOI18N
1608

1609        // Reset the graph and input table
1610
clearGraph();
1611        
1612        _queryBuilder._updateModel = false;
1613        try {
1614            
1615            generateGraphFrom(query);
1616            generateGraphWhere(query);
1617            generateGraphOrderBy(query);
1618            refresh();
1619        } catch (Exception JavaDoc e) {
1620            e.printStackTrace();
1621        } finally {
1622            _queryBuilder._updateModel = true;
1623        }
1624    }
1625    
1626    
1627    // Reset the graph and input table to an empty state
1628
// This could be implemented in various ways; either retain the same data structure
1629
// but explicitly empty it, or just create a new instance. We favor explicit emptying,
1630
// except for the graph model
1631
void clearGraph() {
1632        
1633        Log.err.log(ErrorManager.INFORMATIONAL, "Entering QBGF.clearGraph"); // NOI18N
1634

1635        // This is used in certain places
1636
_firstTableInserted=false;
1637        
1638        // Start with a fresh graph model
1639
// Setting the model sometimes generates a NPE. We should try explicitly deleting
1640
// all roots from the current model, as painful as that may be
1641
// _graphModel = new DefaultGraphModel();
1642
// _graph.setModel(_graphModel);
1643
// Take the transitive closer from the set of roots
1644
// This is complicated because the jgraph API is somewhat user-unfriendly
1645
_graphModel.remove((_graphModel.getDescendants(_graphModel,
1646                _graphModel.getRoots(_graphModel))).toArray());
1647        
1648        if (DEBUG) {
1649            printRoots();
1650        }
1651        
1652        // Clear the InputTableModel
1653
_inputTableModel.setRowCount(0);
1654        
1655        // Remove any nodes (internal frames) that have been added to the desktop pane
1656
Component JavaDoc[] comps = _desktopPane.getComponents();
1657        for(int i=0; i<comps.length; i++) {
1658            Component JavaDoc comp = comps[i];
1659            if (comp instanceof QueryBuilderInternalFrame)
1660                _desktopPane.remove(comp);
1661        }
1662        
1663        // Reset the location for placing nodes
1664
QueryBuilderInternalFrame.resetLocation();
1665    }
1666    
1667    
1668    // Generate the graph corresponding to the FROM clause.
1669
// Also updates the table entries corresponding to the SELECT clause;
1670
// that should be refactored.
1671

1672    private void generateGraphFrom(QueryModel query) {
1673        
1674        Log.err.log(ErrorManager.INFORMATIONAL,
1675                "Entering QBGF.generateGraphFrom"); // NOI18N
1676

1677        // Start with the From clause
1678
List JavaDoc tables = query.getFrom().getTableList();
1679        
1680        // Iterate through the list of tables, adding them to the graph
1681
for (int i=0; i<tables.size(); i++) {
1682            
1683            JoinTable joinTable = (JoinTable) tables.get(i);
1684            String JavaDoc tableSpec = joinTable.getTableSpec();
1685            String JavaDoc fullTableName = joinTable.getFullTableName();
1686            
1687            // We also need to use the SELECT list to set the columns in the
1688
// interior of the table node. We could pass in the whole FROM list,
1689
// and scan in with each table, or we could partition it once, and
1690
// pass in the relevant entries with each table. If we go the
1691
// partitioning approach, we could revise the model to use it.
1692
List JavaDoc columnNames = new ArrayList JavaDoc();
1693            query.getColumnNames(tableSpec, columnNames);
1694            insertTableFromModel(joinTable, columnNames);
1695        }
1696    }
1697    
1698    // check if the where clause has any duplicate columns
1699
// e.g. if the where caluse is like "where table.c > 10 AND table.c < 20"
1700
// then this will return true. Current decisoin is not to display multiple
1701
// columns in the grid pane.
1702
private boolean whereHasDuplicateColumns( List JavaDoc whereColumns,
1703            Predicate expr ) {
1704        List JavaDoc columns = new ArrayList JavaDoc();
1705        expr.getReferencedColumns(columns);
1706        for (int i=0; i<columns.size(); i++) {
1707            if (DEBUG) {
1708                System.out.println("expr getReferencedColumn i = " + i +
1709                        " " + ((Column JavaDoc)columns.get(i)).genText());
1710            }
1711            
1712            Column JavaDoc c = (Column JavaDoc)columns.get(i);
1713            int found = 0;
1714            for (int j=0; j<whereColumns.size(); j++) {
1715                if (((Column JavaDoc)whereColumns.get(j)).equals(c)) {
1716                    found++;
1717                    if (DEBUG) {
1718                        System.out.println(
1719                                "where getReferencedColumn j = " + j + " " +
1720                                " found = " + found +
1721                                ((Column JavaDoc)whereColumns.get(j)).genText());
1722                    }
1723                }
1724                if ( found > 1 ) // more than one instance
1725
return true;
1726            }
1727        }
1728        return false;
1729    }
1730    
1731    // Generate the Graph and Table entries corresponding to the WHERE clause
1732
// Graph: edges Table: criteria
1733

1734    private void generateGraphWhere(QueryModel query) {
1735        
1736        Log.err.log(ErrorManager.INFORMATIONAL, "Entering QBGF.generateGraphWhere"); // NOI18N
1737
if (DEBUG)
1738            System.out.println("Entering QBGF.generateGraphWhere"); // NOI18N
1739

1740        // if this is true we should not handle any events in tableChanged.
1741
_inputTableAddCriteria = true;
1742        
1743        // Now handle the WHERE clause
1744
// For now, assume a single predicate, possibly parameterized
1745
// Each predicate becomes a row in the InputTable, with an appte entry in Criteria
1746
// Example code for adding rows to the table is in tableChanged
1747
// For each predicate (col = [ value | ? ] )
1748
// ToDo: handle all values, not just *, ?
1749
// ToDo: introduce a different class for join predicates
1750
Where where = query.getWhere();
1751        if (where != null) {
1752            
1753            Expression expr = where.getExpression();
1754            
1755            List JavaDoc whereColumns = new ArrayList JavaDoc();
1756            where.getReferencedColumns(whereColumns);
1757            
1758            if ( expr == null ) {
1759                _inputTableAddCriteria = false;
1760                return;
1761            } else if ( expr instanceof Predicate ) {
1762                if ( whereHasDuplicateColumns(whereColumns, (Predicate) expr)) // more than one instance
1763
insertPredicate((Predicate)expr, -1);
1764                else
1765                    insertPredicate((Predicate)expr, 0);
1766            } else if ( expr instanceof And ) {
1767                insertAndOr(expr, whereColumns, 0);
1768            } else if ( expr instanceof Or ) {
1769                insertAndOr(expr, whereColumns, 0);
1770            }
1771        }
1772        _inputTableAddCriteria = false;
1773    }
1774    
1775    // insert AND / OR expression in the grid pane. if a column appears
1776
// more than once in the where clause then we display the "****" in the
1777
// criteria column and the order is displayed as "*".
1778
private void insertAndOr(Expression expr, List JavaDoc whereColumns, int order) {
1779        ExpressionList exprList = (ExpressionList)expr;
1780        for (int i=0; i<exprList.size(); i++) {
1781            expr = exprList.getExpression(i);
1782            if ( expr instanceof Predicate ) {
1783                if ( whereHasDuplicateColumns(whereColumns, (Predicate)expr))
1784                    // more than one instance
1785
insertPredicate((Predicate)expr, -1);
1786                else
1787                    insertPredicate((Predicate)expr, order++);
1788            } else if ( expr instanceof And ) {
1789                insertAndOr(expr, whereColumns, order++ );
1790            } else if ( expr instanceof Or ) {
1791                insertAndOr(expr, whereColumns, order++ );
1792            }
1793        }
1794    }
1795    
1796    /**
1797     * Insert the predicate into visual editor, either as a graph edge (for
1798     * a relationship) or as a table entry (for a criterion).
1799     * Order is the initial value for the criteria order.
1800     * if order is -1, then add "*****" to criteria column and "*" to
1801     * order column and make both of them uneditable.
1802     */

1803    private void insertPredicate(Predicate pred, int order) {
1804        
1805        Value val1 = pred.getVal1();
1806        Value val2 = pred.getVal2();
1807        
1808        if ((val1 instanceof Column JavaDoc) && (val2 instanceof Column JavaDoc)) {
1809            // Comparing two columns -- insert an edge
1810
insertJoinEdge(pred, "");
1811        } else {
1812            // Assume that the right hand side is a literal value
1813
// This will result in an entry into the InputTable
1814
String JavaDoc marker = pred.getVal2().toString();
1815            
1816            // Treat this like any other literal value now
1817
// if (marker.equals("?")) {}
1818

1819            // We can only count on the tableSpec; tableName might contain corrName
1820
Column JavaDoc col = (Column JavaDoc)val1;
1821            String JavaDoc tableSpec=col.getTableSpec();
1822            String JavaDoc columnName=col.getColumnName();
1823            
1824            // Create the value that we're going to put into the table
1825
String JavaDoc val = pred.getOp() + " " + marker; // NOI18N
1826

1827            // If we're inserting a criterion, get order. -1 is a special case, meaning ""
1828
if ( order == -1) {
1829                _queryBuilderInputTable.addCriterion(tableSpec, columnName,
1830                        QueryBuilderInputTable.Criteria_Uneditable_String,
1831                        QueryBuilderInputTable.CriteriaOrder_Uneditable_String);
1832            } else {
1833                String JavaDoc orderString = (order == -1) ? "" : new Integer JavaDoc(order+1).toString();
1834                
1835                // Update the appropriate row, or add a new one
1836
_queryBuilderInputTable.addCriterion(tableSpec, columnName,
1837                        val, orderString);
1838            }
1839        }
1840    }
1841    
1842    // Update the InputTable to show the OrderBy specs
1843

1844    private void generateGraphOrderBy(QueryModel query) {
1845        
1846        // Delegate this to the InputTable, which is the only component affected
1847
_queryBuilderInputTable.generateTableOrderBy(query);
1848    }
1849    
1850    
1851    /**
1852     * Finds a graph node with the specified name (tableSpec)
1853     */

1854    DefaultGraphCell findNode(String JavaDoc tableSpec) {
1855        
1856        Log.err.log(ErrorManager.INFORMATIONAL,
1857                "Entering QBGF.findNode, searching for cell: " + tableSpec); // NOI18N
1858

1859        for (int i=0; i<_graphModel.getRootCount(); i++) {
1860            
1861            Object JavaDoc root = _graphModel.getRootAt(i);
1862            
1863            if ((root instanceof DefaultGraphCell) // Do we have a cell of some form?
1864
&& !(_graphModel.isEdge(root)) // ... that is a node, not an edge?
1865
&& !(root instanceof DefaultPort)) // ... that is not a port (shouldn't happen!)
1866
{
1867                QueryBuilderInternalFrame internalFrame =
1868                        (QueryBuilderInternalFrame) (((DefaultGraphCell) root).getUserObject());
1869                if (internalFrame.getTableSpec().equals(tableSpec))
1870                    return (DefaultGraphCell) root;
1871            }
1872        }
1873        
1874        return null;
1875    }
1876    
1877    
1878    // Top-level method for adding a table to the query.
1879
// Called from the "Add Table" menu item
1880
public void addTable() {
1881        Log.err.log(ErrorManager.INFORMATIONAL, "Entering QBGF.addTable"); // NOI18N
1882

1883        // if ( _queryBuilder.checkDatabaseAndDisable(null) == false ) return;
1884

1885        QueryBuilder.showBusyCursor( true );
1886        try {
1887            
1888            List JavaDoc tableNames = _queryBuilder.getCachedAllTablesInDataSource();
1889            String JavaDoc[] tableStrings = new String JavaDoc[tableNames.size()];
1890            tableNames.toArray(tableStrings);
1891            _addTableDlg = new AddTableDlg(tableStrings, true);
1892            if (DEBUG)
1893                System.out.println("Database tablenames: " + tableNames); // NOI18N
1894

1895            // It's not clear why we need to do this here, since we passed
1896
// tables into the constructor
1897
// _addTableDlg.setTableValues(_tableStrings) ;
1898
if (_addTableDlg.getReturnStatus() == 1) {
1899                // <change/> Moving to NB winsys.
1900
// WindowManager.getDefault().showBusyCursor(true);
1901
SwingUtilities.invokeLater(new Runnable JavaDoc() {
1902                    public void run() {
1903                        Object JavaDoc[] selectedTables = _addTableDlg.getSelectedValues();
1904                        // refresh();
1905
// QueryBuilder.showBusyCursor ( true );
1906
for ( int i=0; i < selectedTables.length; i++ ) {
1907                            final String JavaDoc finalVal = (String JavaDoc) selectedTables[i];
1908                            insertTableInteractively(finalVal);
1909                        }
1910                        _queryBuilder.generateText();
1911                        runQueryMenuItem.setEnabled(true);
1912                        groupByMenuItem.setEnabled(true);
1913                        _queryBuilder.getQueryBuilderPane().getQueryBuilderSqlTextArea().setRunQueryMenuEnabled(true);
1914                        _queryBuilder.getQueryBuilderPane().getQueryBuilderSqlTextArea().setParseQueryMenuEnabled(true);
1915                        // QueryBuilder.showBusyCursor ( false );
1916
}
1917                }
1918                );
1919                // <change/> Moving to NB winsys.
1920
// WindowManager.getDefault().showBusyCursor(false);
1921
}
1922            // somehow the graph still thinks we are not changed enough to redraw.
1923
// this causes the edges not to get drawn, as well as the scroll bars
1924
// not getting updated.
1925
QueryBuilderInternalFrame currentSelectedFrame =
1926                    (QueryBuilderInternalFrame)_desktopPane.getSelectedFrame();
1927            if ( currentSelectedFrame != null ) {
1928                redrawFrameWithMove( currentSelectedFrame );
1929            }
1930        } catch (SQLException sqe) {
1931            _queryBuilder.checkDatabaseAndDisable(null) ;
1932        } finally {
1933            QueryBuilder.showBusyCursor( false );
1934        }
1935    }
1936    
1937    /**
1938     * Responds to a menu selection
1939     *
1940     * Current choices are "Add Table", "Run Query", "Remove From Query"
1941     */

1942    public void actionPerformed(ActionEvent e) {
1943        
1944        if (DEBUG)
1945            System.out.println("Entering QBGF.actionPerformed"); //NOI18N
1946

1947        JMenuItem JavaDoc source = (JMenuItem JavaDoc)(e.getSource());
1948        
1949        if (source.getText().equals(NbBundle.getMessage(QueryBuilderGraphFrame.class, "Add_Table"))) { // NOI18N
1950
addTable();
1951        }
1952        
1953        else if (source.getText().equals(NbBundle.getMessage(QueryBuilderGraphFrame.class, "RUN_QUERY"))) // NOI18N
1954
{
1955            // Execute the query
1956

1957            _queryBuilder.executeQuery(_sqlTextArea.getText());
1958        }
1959        
1960        else if (source.getText().equals(NbBundle.getMessage(QueryBuilderGraphFrame.class, "REMOVE_FROM_QUERY"))) { // NOI18N
1961
removeTable();
1962        }
1963    }
1964    
1965    public boolean isSelectionEmpty() {
1966        // if there are no tables, selection should be empty.
1967
if ( _firstTableInserted == false ) return true;
1968        QueryBuilderInternalFrame currentSelectedFrame =
1969                (QueryBuilderInternalFrame)_desktopPane.getSelectedFrame();
1970        return ( currentSelectedFrame == null );
1971    }
1972    
1973    // Remove the table node from the graph (and model)
1974
// update delete menu
1975
public void removeNode(TableNode node) {
1976        QueryBuilder.showBusyCursor( true );
1977        
1978        /*
1979        Component[] comps = _desktopPane.getComponents();
1980        for(int i=0; i<comps.length; i++) {
1981            Component comp = comps[i];
1982            if (comp instanceof QueryBuilderInternalFrame) {
1983                QueryBuilderInternalFrame qbif =
1984                                         (QueryBuilderInternalFrame) comp;
1985                TableNode tNode = qbif.getNode();
1986                System.out.println(" tNode.getTableName() = " + tNode.getTableName() + " node.getTableName() = " + node.getTableName() + "\n" ); // NOI18N
1987                System.out.println(" tNode.getCorrName() = " + tNode.getCorrName() + " node.getCorrName() = " + node.getCorrName() + "\n" ); // NOI18N
1988                if ( (tNode.getTableName().equals(node.getTableName()) ) &&
1989                     (tNode.getCorrName().equals(node.getCorrName()) ) ) {
1990                    removeTable ( qbif );
1991                }
1992            }
1993        }
1994         */

1995        // remove the selected table to fix
1996
// 6253516 : "delete" key doesn't work for same tables in QE.
1997
removeTable();
1998        QueryBuilder.showBusyCursor( false );
1999    }
2000    
2001    // Remove the condition node from the graph (and model)
2002
// update delete menu
2003
public void removeNode(CondNode node) {
2004        QueryBuilder.showBusyCursor( true );
2005        String JavaDoc[] rel = new String JavaDoc[4];
2006        rel[0] = node.getTable1();
2007        rel[1] = node.getColumn1();
2008        rel[2] = node.getTable2();
2009        rel[3] = node.getColumn2();
2010        
2011        if (DEBUG) {
2012            System.out.println(" QBGF.removeNode() table1 = " + rel[0] + " column1 = " + rel[1] + " table2 = " + rel[2] + " column2 = " + rel[3] + "\n" ); // NOI18N
2013
}
2014        
2015        Predicate pred = SQLQueryFactory.createPredicate(rel);
2016        _queryBuilder._updateText=false;
2017        _queryBuilder.getQueryModel().removeCondition( pred );
2018        Object JavaDoc cell = _graph.getSelectionCell();
2019        if (cell instanceof DefaultEdge) {
2020            _graphModel.remove(new Object JavaDoc[] {cell});
2021        }
2022        _queryBuilder._updateText=true;
2023        _queryBuilder.generateText();
2024        _queryBuilder.activateActions();
2025        QueryBuilder.showBusyCursor( false );
2026    }
2027    
2028    // Remove the join node from the graph (and model)
2029
// update delete menu
2030
public void removeNode(JoinNode node) {
2031        QueryBuilder.showBusyCursor( true );
2032        String JavaDoc[] rel = new String JavaDoc[4];
2033        rel[0] = node.getTable1();
2034        rel[1] = node.getColumn1();
2035        rel[2] = node.getTable2();
2036        rel[3] = node.getColumn2();
2037        
2038        if (DEBUG) {
2039            System.out.println(" QBGF.removeNode() table1 = " + rel[0] + " column1 = " + rel[1] + " table2 = " + rel[2] + " column2 = " + rel[3] + "\n" ); // NOI18N
2040
}
2041        
2042        _queryBuilder._updateText=false;
2043        _queryBuilder.getQueryModel().removeJoinNode( rel[0], rel[1], rel[2], rel[3] );
2044        Object JavaDoc cell = _graph.getSelectionCell();
2045        if (cell instanceof DefaultEdge) {
2046            _graphModel.remove(new Object JavaDoc[] {cell});
2047        }
2048        _queryBuilder._updateText=true;
2049        _queryBuilder.generateText();
2050        _queryBuilder.activateActions();
2051        QueryBuilder.showBusyCursor( false );
2052    }
2053    
2054    // Remove the selected frame from the graph (and model)
2055
// update delete menu
2056
public void removeTable() {
2057        
2058        QueryBuilder.showBusyCursor( true );
2059        // Important: suppress bogus regeneration of the text query
2060
_queryBuilder._updateText=false;
2061        try {
2062            QueryBuilderInternalFrame currentSelectedFrame =
2063                    (QueryBuilderInternalFrame)_desktopPane.getSelectedFrame();
2064            if (currentSelectedFrame != null)
2065                removeTable(currentSelectedFrame);
2066        } finally {
2067            _queryBuilder._updateText=true;
2068        }
2069        
2070        // enable/disable group_by menu item
2071
if ( _sqlTextArea.getText() == null ) {
2072            runQueryMenuItem.setEnabled(false);
2073            groupByMenuItem.setEnabled(false);
2074            _queryBuilder.getQueryBuilderPane().getQueryBuilderSqlTextArea().setRunQueryMenuEnabled(false);
2075            _queryBuilder.getQueryBuilderPane().getQueryBuilderSqlTextArea().setParseQueryMenuEnabled(false);
2076        } else if ( _sqlTextArea.getText().trim().length() == 0 ) {
2077            runQueryMenuItem.setEnabled(false);
2078            groupByMenuItem.setEnabled(false);
2079            _queryBuilder.getQueryBuilderPane().getQueryBuilderSqlTextArea().setRunQueryMenuEnabled(false);
2080            _queryBuilder.getQueryBuilderPane().getQueryBuilderSqlTextArea().setParseQueryMenuEnabled(false);
2081        } else {
2082            runQueryMenuItem.setEnabled(true);
2083            groupByMenuItem.setEnabled(true);
2084            _queryBuilder.getQueryBuilderPane().getQueryBuilderSqlTextArea().setRunQueryMenuEnabled(true);
2085            _queryBuilder.getQueryBuilderPane().getQueryBuilderSqlTextArea().setParseQueryMenuEnabled(true);
2086        }
2087        QueryBuilder.showBusyCursor( false );
2088    }
2089    
2090    // Responds to a CheckBoxMenuItem -- Group by
2091

2092    public void itemStateChanged(ItemEvent e) {
2093        
2094        JMenuItem JavaDoc source = (JMenuItem JavaDoc)(e.getSource());
2095        
2096        if (source.getText().equals(NbBundle.getMessage(QueryBuilderGraphFrame.class, "GROUP_BY"))) { // NOI18N
2097

2098            // Add or remove a Group by clause
2099
if (e.getStateChange() == ItemEvent.SELECTED) {
2100                // Add a Group By to the model
2101
_queryBuilder.getQueryModel().addGroupBy();
2102            } else {
2103                // Remove a Group By from the model
2104
_queryBuilder.getQueryModel().removeGroupBy();
2105            }
2106            _queryBuilder.generateText();
2107        }
2108    }
2109    
2110    
2111    // Set the checkbox in the GroupBy menu item
2112
public void setGroupBy(boolean b) {
2113        groupByMenuItem.setSelected(b);
2114    }
2115    
2116    
2117    // somehow the graph still thinks we are not changed enough to redraw.
2118
// this causes the edges not to get drawn, as well as the scroll bars
2119
// not getting updated.
2120
void redrawFrameWithMove(QueryBuilderInternalFrame frame) {
2121        if (frame != null)
2122            // && frame.isShowing()
2123
{
2124            HashMap JavaDoc map = new HashMap JavaDoc();
2125            Map JavaDoc atts = GraphConstants.createMap();
2126            
2127            GraphConstants.setBounds(atts,frame.getBounds());
2128            map.put(frame.getGraphCell(),atts);
2129            // Update the graph model with the new attributes, which include frame bounds(?)
2130
_graphModel.edit(map,null,null,null);
2131        }
2132        
2133        // the 2 lines below need to be there for this to work
2134
// but they should not be there in redrawFrame.
2135
// That is the only difference between redrawFrame and
2136
// redrawFrameWithMove
2137
_desktopPane.setBounds(_canvas.getBounds());
2138        _desktopPane.updateUI();
2139        
2140        resizeDesktop();
2141        _queryBuilder.getQueryBuilderPane().getQueryBuilderSqlTextArea().requestFocus(true);
2142    }
2143    
2144    
2145    // Redraw an internal frame?
2146

2147    private void redrawFrame(QueryBuilderInternalFrame frame) {
2148        if (frame != null)
2149            // && frame.isShowing()
2150
{
2151            HashMap JavaDoc map = new HashMap JavaDoc();
2152            Map JavaDoc atts = GraphConstants.createMap();
2153            
2154            GraphConstants.setBounds(atts,frame.getBounds());
2155            map.put(frame.getGraphCell(),atts);
2156            // Update the graph model with the new attributes, which include frame bounds(?)
2157
_graphModel.edit(map,null,null,null);
2158        }
2159    }
2160    
2161    
2162    // Manually refresh the graph display -- copied from ComponentListener below
2163
// The forum suggested something like graphDidChange(); revalidate(); but not tried
2164

2165    void refresh() {
2166        _graph.graphDidChange();
2167        _graph.revalidate();
2168        if (DEBUG) {
2169            System.out.println(" refresh() called " + "\n" ); // NOI18N
2170
System.out.println(" width = " + _graph.getSize().getWidth() + " Height = " + _graph.getSize().getHeight() + "\n" ); // NOI18N
2171
}
2172        resizeDesktop();
2173    }
2174    
2175    
2176    /**
2177     * Returns the next location for placing a node.
2178     * Right now it uses a standard offset from the previous location.
2179     */

2180    Point JavaDoc getNextLocation(QueryBuilderInternalFrame internalFrame) {
2181        
2182        if (!_firstTableInserted ) {
2183            _location = new Point JavaDoc(initX, initY);
2184        } else {
2185            Dimension JavaDoc size = internalFrame.getSize();
2186            _location = new Point JavaDoc((int)(
2187                    _location.getX() +
2188                    size.getWidth() +
2189                    offsetX +
2190                    randomVal.nextInt((int)size.getWidth()/2)),
2191                    (int)(_location.getY() +
2192                    offsetY +
2193                    randomVal.nextInt((int)size.getHeight()/2)));
2194            offsetY *= -1;
2195            if ( _location.getX() >
2196                    (int) size.getWidth() * MAX_TABLES_IN_A_ROW ) {
2197                _location = new Point JavaDoc(initX, (int)_location.getY()+(int)size.getHeight()+2*offsetY);
2198            }
2199        }
2200        return _location;
2201    }
2202    
2203
2204    // Inner classes, mostly for Listeners
2205

2206    // A listener that will bring up the background menu
2207

2208    class BackgroundPopupListener extends MouseAdapter {
2209        
2210        public void mousePressed(MouseEvent e) {
2211            maybeShowPopup(e);
2212        }
2213        
2214        public void mouseReleased(MouseEvent e) {
2215            maybeShowPopup(e);
2216        }
2217        
2218        private void maybeShowPopup(MouseEvent e) {
2219            if ( _disableQBGF ) return;
2220            if (e.isPopupTrigger() ) {
2221                Object JavaDoc cell = _graph.getFirstCellForLocation(e.getX(), e.getY());
2222                if ( ( cell != null ) && ( cell instanceof DefaultEdge ) ) {
2223                    // do not show popup.
2224
// bug 4979403 right click and double click the Join edge
2225
return;
2226                }
2227                if (e.getComponent().isEnabled() )
2228                    _backgroundPopup.show( e.getComponent(), e.getX(), e.getY() );
2229            }
2230        }
2231    }
2232    
2233    
2234    /**
2235     * An adapter class for receiving internal frame events. Used
2236     * to detect when a Frame (graph node representing a table) is selected
2237     */

2238    private class FrameSelectionListener extends InternalFrameAdapter JavaDoc {
2239        
2240        public void internalFrameActivated(InternalFrameEvent JavaDoc ife) {
2241            Object JavaDoc source = (Object JavaDoc)(ife.getSource());
2242            
2243            // When any internal frame is activated, enable these two listeners?
2244
// _apifa.setEnabled(true);
2245
// _acifa.setEnabled(true);
2246

2247            // Finally, bring up property sheet. Ignore event, just check which frame is selected.
2248
QueryBuilderInternalFrame currentSelectedFrame =
2249                    (QueryBuilderInternalFrame)_desktopPane.getSelectedFrame();
2250            setActivatedNode( currentSelectedFrame ) ;
2251        }
2252        
2253        public void internalFrameDeactivated(InternalFrameEvent JavaDoc ife) {
2254// _apifa.setEnabled(false);
2255
// _acifa.setEnabled(false);
2256
}
2257    }
2258    
2259    
2260    // An adapter class for receiving component events
2261
// This listens for events from the desktopPane
2262

2263    private class CompListener extends ComponentAdapter {
2264        
2265        public void componentResized(ComponentEvent ce) {
2266            if ( _disableQBGF ) {
2267                return;
2268            } else {
2269                refresh();
2270            }
2271        }
2272    }
2273    
2274    
2275    // An adapter class for receiving component events
2276
// This listens for events from nodes (internal frames)
2277

2278    private class FrameComponentListener extends ComponentAdapter {
2279        
2280        // The following two methods are defined on the ComponentListener interface
2281
public void componentResized(ComponentEvent ce) {
2282            componentMoved(ce);
2283        }
2284        
2285        public void componentMoved(ComponentEvent ce) {
2286            HashMap JavaDoc map = new HashMap JavaDoc();
2287            Map JavaDoc atts = GraphConstants.createMap();
2288            QueryBuilderInternalFrame frame = (QueryBuilderInternalFrame)ce.getComponent();
2289            refresh();
2290            
2291            GraphConstants.setBounds(atts,frame.getBounds());
2292            map.put(frame.getGraphCell(),atts);
2293            _graphModel.edit(map,null,null,null);
2294            
2295            resizeDesktop();
2296        }
2297    }
2298    
2299    /**
2300     * Listener for detecting changes to the graph selection, to update Property Sheet
2301     *
2302     * This only detects selection for edges (joins); nodes are handled elsewhere.
2303     */

2304    private class GraphSelListener implements GraphSelectionListener {
2305        
2306        public void valueChanged(GraphSelectionEvent e) {
2307            
2308            Log.err.log(ErrorManager.INFORMATIONAL, "Graph selection changed, event: "+e); // NOI18N
2309
if (_graph.getSelectionCount() > 0) {
2310                // Use the first selection; should only be one
2311
Object JavaDoc cell = _graph.getSelectionCell();
2312                if ( ( cell != null ) && ( cell instanceof DefaultEdge ) ) {
2313                    // We've selected an edge. Update the Property Sheet, by setting
2314
// the activated node to the underlying join
2315
AbstractNode an = (AbstractNode)(((DefaultEdge) cell).getUserObject());
2316                    _queryBuilder.setActivatedNodes(new Node[] { an });
2317                    QueryBuilderInternalFrame currentSelectedFrame =
2318                            (QueryBuilderInternalFrame)
2319                            _desktopPane.getSelectedFrame();
2320                    try {
2321                        if ( currentSelectedFrame != null ) {
2322                            currentSelectedFrame.setSelected( false );
2323                        }
2324                    } catch ( java.beans.PropertyVetoException JavaDoc pve ) {
2325                        // do nothing
2326
}
2327                }
2328            }
2329        }
2330    }
2331    
2332    
2333    // Utility method for printing graph information
2334

2335    private void printRoots() {
2336        if (DEBUG) {
2337            System.out.println("Root Count" + _graphModel.getRootCount()); // NOI18N
2338
for (int i=0; i<_graphModel.getRootCount(); i++)
2339                System.out.println("Root["+i+"] class: " + _graphModel.getRootAt(i).getClass()); // NOI18N
2340
}
2341    }
2342    
2343    
2344    // Utility class for timing
2345

2346    public class PerfTimer {
2347        
2348        long _time;
2349        
2350        public PerfTimer() {
2351            resetTimer();
2352        }
2353        
2354        // reset Timer
2355
public void resetTimer(){
2356            // set current time
2357
_time = System.currentTimeMillis();
2358        }
2359        
2360        public long elapsedTime() {
2361            // get elapsed Time
2362
return (System.currentTimeMillis() - _time);
2363        }
2364        
2365        public void print(String JavaDoc aString) {
2366            System.out.println(aString + ": " + this.elapsedTime() + " ms"); // NOI18N
2367
}
2368    }
2369    
2370    public void dragEnter(DropTargetDragEvent e) {
2371        e.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
2372    }
2373    
2374    public void drop(DropTargetDropEvent e) {
2375        if ( _disableQBGF ) return;
2376        try {
2377            Transferable tr = e.getTransferable();
2378            DataFlavor[] dataFlavors = tr.getTransferDataFlavors();
2379            for (int i = 0; i < dataFlavors.length; i++) {
2380                Object JavaDoc o = tr.getTransferData( dataFlavors[i] );
2381                if ( o instanceof Node ) {
2382                    e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
2383                    // user should be allowed to drop tables from the
2384
// current data source only.
2385
List JavaDoc tableNamesArrayList =
2386                            _queryBuilder.getCachedAllTablesInDataSource();
2387                    String JavaDoc fullTableName = ( ( Node ) o ).getName();
2388                    
2389                     // Reassign fullTableName to just the table name - minus the schema name
2390
String JavaDoc tableName;
2391                    String JavaDoc justTableName;
2392                    for (int j=0; j < tableNamesArrayList.size(); j++){
2393                        tableName = (String JavaDoc) tableNamesArrayList.get(j);
2394                        justTableName = (String JavaDoc)tableName.split("\\.")[1];
2395                        if (justTableName.equals(fullTableName )){
2396                            fullTableName = tableName;
2397                            break;
2398                        }
2399                    }
2400                    
2401                    if ( tableNamesArrayList.contains( fullTableName ) ) {
2402                        insertTableInteractively( fullTableName );
2403                        _queryBuilder.generateText();
2404                        runQueryMenuItem.setEnabled(true);
2405                        groupByMenuItem.setEnabled(true);
2406                        _queryBuilder.getQueryBuilderPane().getQueryBuilderSqlTextArea().setRunQueryMenuEnabled(true);
2407                        _queryBuilder.getQueryBuilderPane().getQueryBuilderSqlTextArea().setParseQueryMenuEnabled(true);
2408                        refresh();
2409                        _graph.getGraphLayoutCache().reload();
2410                        resizeDesktop();
2411                        // somehow the graph still thinks we are not changed
2412
// enough to redraw. this causes the edges not to get
2413
// drawn, as well as the scroll bars not getting
2414
// updated.
2415
QueryBuilderInternalFrame currentSelectedFrame =
2416                                (QueryBuilderInternalFrame)_desktopPane.getSelectedFrame();
2417                        if ( currentSelectedFrame != null ) {
2418                            redrawFrameWithMove( currentSelectedFrame );
2419                        }
2420                    } else {
2421                        String JavaDoc msg =
2422                                NbBundle.getMessage(QueryBuilderGraphFrame.class,
2423                                "DRAG_AND_DROP_FROM_CURRENT_DATASOURCE");
2424                        NotifyDescriptor d = new NotifyDescriptor.Message(
2425                                msg + " = " +
2426                                _queryBuilder. getConnectionInfo() +
2427                                "\n\n", // NOI18N
2428
NotifyDescriptor.ERROR_MESSAGE);
2429                        DialogDisplayer.getDefault().notify(d);
2430                    }
2431                    e.dropComplete(true);
2432                    return;
2433                }
2434            }
2435            e.rejectDrop();
2436        } catch (Exception JavaDoc ex) {
2437            System.out.println("Data transfer exception: " + ex); //NOI18N
2438
}
2439    }
2440    
2441    public void dragExit(DropTargetEvent e) {
2442        
2443    }
2444    
2445    public void dragOver(DropTargetDragEvent e) {
2446        
2447    }
2448    
2449    public void dropActionChanged(DropTargetDragEvent e) {
2450        
2451    }
2452    
2453    public void dragOver(DragSourceDragEvent e) {
2454        
2455    }
2456    
2457    public void dropActionChanged(DragSourceDragEvent e) {
2458        
2459    }
2460}
2461
Popular Tags