001/*
002 * Copyright (c) 2003-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2012-06-12 00:46:03 +0000 (Tue, 12 Jun 2012) $' 
007 * '$Revision: 29919 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.ecoinformatics.seek.querybuilder;
031
032import java.awt.BorderLayout;
033import java.awt.Color;
034import java.awt.Dimension;
035import java.awt.GraphicsConfiguration;
036import java.awt.GraphicsEnvironment;
037import java.awt.Insets;
038import java.awt.Rectangle;
039import java.awt.Toolkit;
040import java.awt.event.ActionEvent;
041import java.beans.PropertyChangeEvent;
042import java.beans.PropertyChangeListener;
043import java.io.BufferedWriter;
044import java.io.File;
045import java.io.FileNotFoundException;
046import java.io.FileWriter;
047import java.io.IOException;
048import java.io.Writer;
049import java.util.Vector;
050
051import javax.swing.AbstractAction;
052import javax.swing.Action;
053import javax.swing.Box;
054import javax.swing.BoxLayout;
055import javax.swing.JButton;
056import javax.swing.JComponent;
057import javax.swing.JEditorPane;
058import javax.swing.JFileChooser;
059import javax.swing.JFrame;
060import javax.swing.JMenu;
061import javax.swing.JMenuBar;
062import javax.swing.JMenuItem;
063import javax.swing.JOptionPane;
064import javax.swing.JPanel;
065import javax.swing.JTabbedPane;
066import javax.swing.JTextField;
067import javax.swing.SingleSelectionModel;
068import javax.swing.SwingUtilities;
069import javax.swing.border.EtchedBorder;
070import javax.swing.event.ChangeEvent;
071import javax.swing.event.ChangeListener;
072import javax.swing.event.TableModelEvent;
073import javax.swing.event.TableModelListener;
074import javax.swing.table.TableCellEditor;
075
076import org.kepler.objectmanager.data.DataType;
077import org.kepler.objectmanager.data.db.Attribute;
078import org.kepler.objectmanager.data.db.DSSchemaDef;
079import org.kepler.objectmanager.data.db.DSSchemaIFace;
080import org.kepler.objectmanager.data.db.DSTableDef;
081import org.kepler.objectmanager.data.db.Entity;
082import org.kepler.objectmanager.data.db.QBEditor;
083
084import ptolemy.gui.PtFileChooser;
085import ptolemy.gui.PtFilenameFilter;
086
087/**
088 * The Query Builder app which extends a JPanel. This enables it to be embedded
089 * in an applet or an application.
090 */
091public class QBApp extends JPanel implements ChangeListener, TableModelListener {
092
093        // The preferred size of the demo
094        private static final int PREFERRED_WIDTH = 720;
095        private static final int PREFERRED_HEIGHT = 640;
096        private static final String ADD_MSG = "Add an item by clicking in the empty \"table\" cell, or drag a \"field\" item from the top panel to the bottom.";
097        private static final String CHANGED_MSG = "Query has Changed.";
098
099        private static final int STD_TAB = 0;
100        // private static final int INTER_TAB = 1;
101        // private static final int ADV_TAB = 2;
102        private static final int SQL_TAB = 1;
103
104        private boolean mDoingDemo = false;
105        private boolean mDoingDemoTests = false;
106
107        private JPanel mDemoPanel = null;
108
109        private boolean mIsChanged = false;
110        private boolean mNoOuterUI = false;
111
112        // Status Bar
113        private JTextField mStatusField = null;
114        private JMenuBar mMenuBar = null;
115        private GenericMenuAction mSaveQueryAction = null;
116        private GenericMenuAction mSaveSchemaAction = null;
117        private JFrame mFrame = null;
118        private QBApplet mApplet = null;
119
120        private JTabbedPane mTabbedPane = null;
121        private int mTabInx = 0;
122        private int mLastTabInx = 0;
123
124        private DSSchemaIFace mSchema = null;
125        private DBQueryDef mQueryDef = null;
126
127        private QBSplitPaneStandard mStdSP = null;
128        // private QBSplitPaneIntermediate mInterSP = null;
129        // private QBSplitPaneAdvanced mAdvSP = null;
130        private QBSplitPaneSQL mSQLSP = null;
131        private QBBuilderInterface mBuilderTab = null;
132
133        private TableModelListener mExternalTMListener = null;
134        private QBEditor qbEditor = null;
135
136        private static final int BUTTONXSIZE = 90;
137        private static final int BUTTONYSIZE = 30;
138
139        /**
140         * Constructor with Applet
141         * 
142         * @param aApplet
143         */
144        public QBApp(QBEditor editor) {
145                qbEditor = editor;
146                mNoOuterUI = true;
147                initialize();
148        }
149
150        /**
151         * Constructor with Applet
152         * 
153         * @param aApplet
154         */
155        public QBApp(QBApplet aApplet) {
156                this(aApplet, null);
157        }
158
159        /**
160         * QBApp Constructor
161         */
162        public QBApp(QBApplet aApplet, GraphicsConfiguration gc) {
163
164                // Note that the applet may null if this is started as an application
165                mApplet = aApplet;
166
167                // Create Frame here for app-mode
168                if (!isApplet() && gc != null) {
169                        mFrame = new JFrame(gc);
170                }
171                initialize();
172        }
173
174        /**
175         * General Method for initializing the class
176         * 
177         */
178        private void initialize() {
179                setLayout(new BorderLayout());
180
181                // set the preferred size of the demo
182                setPreferredSize(new Dimension(PREFERRED_WIDTH, PREFERRED_HEIGHT));
183
184                initializeUI();
185
186                JEditorPane editorPane = new JEditorPane("text/text",
187                                "Generated SQL will go here!");
188                editorPane.setEditable(false);
189
190                // create tab
191                mTabbedPane = new JTabbedPane();
192
193                DBQueryDef queryDef = null;
194                if (mDoingDemo) {
195                        queryDef = createDemoQuery();
196                        loadSchemaIntoUI(createDemoSchema());
197                }
198
199                add(mTabbedPane, BorderLayout.CENTER);
200                JPanel buttonPane = createButtonPanel();
201                add(buttonPane, BorderLayout.SOUTH);
202
203                setStatus(ADD_MSG);
204
205                if (mDoingDemo) {
206                        loadQuery(queryDef);
207                        // mIsChanged = false;
208                        // mLastTabInx = mQueryDef.isAdv() ? 1 : 0;
209                        // mTabbedPane.setSelectedIndex(mLastTabInx);
210                }
211
212                // Note that
213                // we again must do this on the GUI thread using invokeLater.
214                SwingUtilities.invokeLater(new Runnable() {
215                        public void run() {
216                                showQBApp();
217                        }
218                });
219        }
220
221        private JPanel createButtonPanel() {
222                JPanel wholePanel = new JPanel();
223                wholePanel.setLayout(new BoxLayout(wholePanel, BoxLayout.Y_AXIS));
224                wholePanel.add(Box.createVerticalStrut(10));
225                JPanel buttonPanel = new JPanel();
226                buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
227                buttonPanel.add(Box.createHorizontalGlue());
228                JButton cancelButton = new JButton(new CancelAction(qbEditor));
229                cancelButton.setPreferredSize(new Dimension(BUTTONXSIZE, BUTTONYSIZE));
230                JButton OKButton = new JButton(new OKAction(qbEditor));
231                OKButton.setPreferredSize(new Dimension(BUTTONXSIZE, BUTTONYSIZE));
232                buttonPanel.add(OKButton);
233                buttonPanel.add(Box.createHorizontalStrut(10));
234                buttonPanel.add(cancelButton);
235                buttonPanel.add(Box.createHorizontalStrut(10));
236                wholePanel.add(buttonPanel);
237                wholePanel.add(Box.createVerticalStrut(10));
238                return wholePanel;
239        }
240
241        /**
242         * Sets a new Schema into the UI and recreates the UI for it
243         * 
244         * @param aSchema
245         *            the new schema
246         */
247        public void loadSchemaIntoUI(DSSchemaIFace aSchema) {
248                if (aSchema == null)
249                        return;
250
251                mSchema = aSchema;
252
253                // if (mAdvSP != null)
254                // mAdvSP.shutdown();
255
256                try {
257                        mTabbedPane.removeAll();
258                } catch (Exception e) {
259                        System.err.println(e);
260                }
261
262                mStdSP = null;
263                // mInterSP = null;
264                // mAdvSP = null;
265                mSQLSP = null;
266
267                /*
268                 * if (!isApplet()) { java.lang.System.gc();
269                 * java.lang.System.runFinalization();
270                 * java.lang.System.runFinalizersOnExit(true); }
271                 */
272
273                // if (!firstTime) return;
274                mStdSP = new QBSplitPaneStandard(mSchema);
275                // mInterSP = new QBSplitPaneIntermediate(mSchema, this);
276                // mAdvSP = new QBSplitPaneAdvanced(mSchema, this);
277                mSQLSP = new QBSplitPaneSQL();
278
279                // Initialize
280                mStdSP.setTableModelListener(this);
281                // mInterSP.setTableModelListener(this);
282                // mAdvSP.setTableModelListener(this);
283
284                mTabbedPane.add("General", mStdSP);
285                // mTabbedPane.add("Intermediate", mInterSP);
286                // mTabbedPane.add("Advanced", mAdvSP);
287                mTabbedPane.add("SQL", mSQLSP);
288
289                mTabbedPane.getModel().addChangeListener(this);
290        }
291
292        /**
293         * 
294         * @return returns a test/demo schema
295         */
296        private DSSchemaDef createDemoSchema() {
297                DSSchemaDef schema = null;
298                if (mDoingDemo) {
299                        schema = new DSSchemaDef("Test Schema");
300                        boolean useTableEntity = true;
301                        if (useTableEntity) {
302                                Entity table1 = new Entity("", "Employees", "", new Boolean(
303                                                true), Entity.ROWMAJOR, 0);
304                                table1.add(new Attribute("", "EmpNo", DataType.INT));
305                                table1.add(new Attribute("", "First Name", DataType.STR));
306                                table1.add(new Attribute("", "Last Name", DataType.STR));
307                                table1.add(new Attribute("", "Addr 1", DataType.STR));
308                                table1.add(new Attribute("", "Addr 2", DataType.STR));
309                                table1.add(new Attribute("", "City", DataType.STR));
310                                table1.add(new Attribute("", "State", DataType.STR));
311                                table1.add(new Attribute("", "Zip", DataType.STR));
312                                schema.addTable(table1);
313
314                                table1 = new Entity("", "EmpDept", "", new Boolean(true),
315                                                Entity.ROWMAJOR, 0);
316                                table1.add(new Attribute("", "EmpNo", DataType.INT));
317                                table1.add(new Attribute("", "DeptNo", DataType.INT));
318                                schema.addTable(table1);
319
320                                table1 = new Entity("", "Department", "", new Boolean(true),
321                                                Entity.ROWMAJOR, 0);
322                                table1.add(new Attribute("", "DeptNo", DataType.INT));
323                                table1.add(new Attribute("", "Name", DataType.STR));
324                                for (int i = 0; i < 15; i++) {
325                                        table1.add(new Attribute("", "User Field " + i,
326                                                        DataType.STR));
327                                }
328                                schema.addTable(table1);
329
330                                table1 = new Entity("", "EmpDoc", "", new Boolean(true),
331                                                Entity.ROWMAJOR, 0);
332                                table1.add(new Attribute("", "EmpNo", DataType.INT));
333                                table1.add(new Attribute("", "DocNo", DataType.INT));
334                                schema.addTable(table1);
335
336                                table1 = new Entity("", "Document", "", new Boolean(true),
337                                                Entity.ROWMAJOR, 0);
338                                table1.add(new Attribute("", "DocNo", DataType.INT));
339                                table1.add(new Attribute("", "Title", DataType.STR));
340                                table1.add(new Attribute("", "Desc", DataType.STR));
341                                table1.add(new Attribute("", "Biblo", DataType.STR));
342                                schema.addTable(table1);
343
344                        } else {
345                                DSTableDef table1 = new DSTableDef("Employees");
346                                table1.addPrimaryKey("EmpNo", DataType.INT, null);
347                                table1.addField("First Name", DataType.STR, null);
348                                table1.addField("Last Name", DataType.STR, null);
349                                table1.addField("Addr 1", DataType.STR, null);
350                                table1.addField("Addr 2", DataType.STR, null);
351                                table1.addField("City", DataType.STR, null);
352                                table1.addField("State", DataType.STR, null);
353                                table1.addField("Zip", DataType.STR, null);
354                                schema.addTable(table1);
355
356                                table1 = new DSTableDef("EmpDept");
357                                table1.addPrimaryKey("EmpNo", DataType.INT, null);
358                                table1.addSecondaryKey("DeptNo", DataType.INT, null);
359                                schema.addTable(table1);
360
361                                table1 = new DSTableDef("Department");
362                                table1.addPrimaryKey("DeptNo", DataType.INT, null);
363                                table1.addField("Name", DataType.STR, null);
364                                for (int i = 0; i < 15; i++) {
365                                        table1.addField("User Field " + i, DataType.STR, null);
366                                }
367                                schema.addTable(table1);
368
369                                table1 = new DSTableDef("EmpDoc");
370                                table1.addPrimaryKey("EmpNo", DataType.INT, null);
371                                table1.addSecondaryKey("DocNo", DataType.INT, null);
372                                schema.addTable(table1);
373
374                                table1 = new DSTableDef("Document");
375                                table1.addPrimaryKey("DocNo", DataType.INT, null);
376                                table1.addField("Title", DataType.STR, null);
377                                table1.addField("Desc", DataType.STR, null);
378                                table1.addField("Biblo", DataType.STR, null);
379                                schema.addTable(table1);
380                        }
381                }
382                return schema;
383        }
384
385        /**
386         * 
387         * @return returns a demo query object
388         */
389        private DBQueryDef createDemoQuery() {
390                DBQueryDef queryDef = new DBQueryDef();
391                Vector joins = new Vector();
392                String tableNames[] = { "Employees", "EmpDept", "EmpDept",
393                                "Department", "Employees", "EmpDoc", "EmpDoc", "Document" };
394                String fieldNames[] = { "EmpNo", "EmpNo", "DeptNo", "DeptNo", "EmpNo",
395                                "EmpNo", "DocNo", "DocNo" };
396                int tableIds[] = { 0, 1, 1, 2, 0, 3, 3, 4 };
397                for (int i = 0; i < tableNames.length; i++) {
398                        Vector missingValue = null;
399                        DBSelectTableModelItem item = new DBSelectTableModelItem(
400                                        tableNames[i], fieldNames[i], "", false, "", "",
401                                        missingValue);
402                        item.setTableId(tableIds[i]);
403                        joins.add(item);
404                }
405                queryDef.setJoins(joins);
406
407                int tableFrameIds[] = { 0, 1, 2, 3, 4 };
408                String tableFrameNames[] = { "Employees", "EmpDept", "Department",
409                                "EmpDoc", "Document" };
410                for (int i = 0; i < tableFrameIds.length; i++) {
411                        queryDef.addTable(tableFrameIds[i], tableFrameNames[i], -1, -1);
412                }
413                queryDef.setIsAdv(true);
414                return queryDef;
415        }
416
417        // *******************************************************
418        // *************** Load UI ******************
419        // *******************************************************
420
421        public void initializeUI() {
422
423                JPanel top = new JPanel();
424                top.setLayout(new BorderLayout());
425                add(top, BorderLayout.NORTH);
426
427                mMenuBar = createMenus();
428                if (mMenuBar != null)
429                        top.add(mMenuBar, BorderLayout.NORTH);
430
431                mStatusField = new JTextField("");
432                mStatusField.setEditable(false);
433                add(mStatusField, BorderLayout.SOUTH);
434
435                mDemoPanel = new JPanel();
436                mDemoPanel.setLayout(new BorderLayout());
437                mDemoPanel.setBorder(new EtchedBorder());
438                mDemoPanel.setBackground(Color.green);
439                add(mDemoPanel, BorderLayout.CENTER);
440
441        }
442
443        /**
444         * Set qb tableau
445         * 
446         * @param tableau
447         */
448        public void setQBEditor(QBEditor editor) {
449                this.qbEditor = editor;
450        }
451
452        /**
453         * @param b
454         *       */
455        protected PropertyChangeListener createActionChangeListener(JMenuItem b) {
456                return new ActionChangedListener(b);
457        }
458
459        /**
460         * 
461         * @author globus
462         * 
463         *         TODO To change the template for this generated type comment go to
464         *         Window - Preferences - Java - Code Generation - Code and Comments
465         */
466        private class ActionChangedListener implements PropertyChangeListener {
467                JMenuItem menuItem;
468
469                ActionChangedListener(JMenuItem mi) {
470                        super();
471                        this.menuItem = mi;
472                }
473
474                public void propertyChange(PropertyChangeEvent e) {
475                        String propertyName = e.getPropertyName();
476                        if (e.getPropertyName().equals(Action.NAME)) {
477                                String text = (String) e.getNewValue();
478                                menuItem.setText(text);
479                        } else if (propertyName.equals("enabled")) {
480                                Boolean enabledState = (Boolean) e.getNewValue();
481                                menuItem.setEnabled(enabledState.booleanValue());
482                        }
483                }
484        }
485
486        /**
487         * Create menus
488         */
489        public JMenuBar createMenus() {
490                JMenuBar menuBar = null;
491
492                if (!isApplet() && !mNoOuterUI) {
493                        menuBar = new JMenuBar();
494                        JMenu fileMenu = (JMenu) menuBar.add(new JMenu("File"));
495                        fileMenu.setMnemonic('F');
496                        createMenuItem(fileMenu, "Open Query", "O", "Open Query File",
497                                        new GenericMenuAction(this,
498                                                        GenericMenuAction.OPEN_QUERY_ACTION), true);
499                        createMenuItem(fileMenu, "Save Query", "S", "Save Query",
500                                        mSaveQueryAction = new GenericMenuAction(this,
501                                                        GenericMenuAction.SAVE_QUERY_ACTION), false);
502                        fileMenu.addSeparator();
503                        createMenuItem(fileMenu, "Open Schema", "O", "Open Schema File",
504                                        new GenericMenuAction(this,
505                                                        GenericMenuAction.OPEN_SCHEMA_ACTION), true);
506                        createMenuItem(fileMenu, "Save Schema", "S", "Save Schema",
507                                        mSaveSchemaAction = new GenericMenuAction(this,
508                                                        GenericMenuAction.SAVE_SCHEMA_ACTION), false);
509                        fileMenu.addSeparator();
510                        createMenuItem(fileMenu, "Exit", "x", "Exit Appication",
511                                        new GenericMenuAction(this, GenericMenuAction.EXIT_ACTION),
512                                        true);
513
514                        if (mDoingDemoTests) {
515                                fileMenu = (JMenu) menuBar.add(new JMenu("Tests"));
516                                fileMenu.setMnemonic('T');
517                                createMenuItem(fileMenu, "Test Queries", "e", "Test Queries",
518                                                new GenericMenuAction(this,
519                                                                GenericMenuAction.QUERY_TESTS_ACTION), true);
520                        }
521                }
522
523                return menuBar;
524        }
525
526        /**
527         * Creates a generic menu item
528         */
529        public JMenuItem createMenuItem(JMenu menu, String label, String mnemonic,
530                        String accessibleDescription, Action action, boolean enabled) {
531                JMenuItem mi = (JMenuItem) menu.add(new JMenuItem(label));
532                mi.setMnemonic(mnemonic.charAt(0));
533                mi.getAccessibleContext().setAccessibleDescription(
534                                accessibleDescription);
535                mi.addActionListener(action);
536                if (action == null) {
537                        mi.setEnabled(false);
538                } else {
539                        action.addPropertyChangeListener(createActionChangeListener(mi));
540                        action.setEnabled(enabled);
541                }
542                return mi;
543        }
544
545        /**
546         * Bring up the QBApp demo by showing the frame (only applicable if coming
547         * up as an application, not an applet);
548         */
549        public void showQBApp() {
550                if (!isApplet() && getFrame() != null) {
551                        // put QBApp in a frame and show it
552                        JFrame f = getFrame();
553                        f.setTitle("Query Builder");
554                        f.getContentPane().add(this, BorderLayout.CENTER);
555                        f.pack();
556
557                        Rectangle screenRect = f.getGraphicsConfiguration().getBounds();
558                        Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(
559                                        f.getGraphicsConfiguration());
560
561                        // Make sure we don't place the demo off the screen.
562                        int centerWidth = screenRect.width < f.getSize().width ? screenRect.x
563                                        : screenRect.x + screenRect.width / 2 - f.getSize().width
564                                                        / 2;
565                        int centerHeight = screenRect.height < f.getSize().height ? screenRect.y
566                                        : screenRect.y + screenRect.height / 2 - f.getSize().height
567                                                        / 2;
568
569                        centerHeight = centerHeight < screenInsets.top ? screenInsets.top
570                                        : centerHeight;
571
572                        f.setLocation(centerWidth, centerHeight);
573                        f.show();
574                }
575        }
576
577        /**
578         * Determines if this is an applet or application
579         */
580        public boolean isApplet() {
581                return (mApplet != null);
582        }
583
584        /**
585         * Returns the applet instance
586         */
587        public QBApplet getApplet() {
588                return mApplet;
589        }
590
591        /**
592         * Returns the frame instance
593         */
594        public JFrame getFrame() {
595                return mFrame;
596        }
597
598        /**
599         * Returns the menubar
600         */
601        public JMenuBar getMenuBar() {
602                return mMenuBar;
603        }
604
605        /**
606         * Set the status
607         */
608        public void setStatus(String s) {
609                // do the following on the gui thread
610                SwingUtilities.invokeLater(new QBAppRunnable(this, s) {
611                        public void run() {
612                                mQBApp.mStatusField.setText((String) obj);
613                        }
614                });
615        }
616
617        public void setIsChanged(boolean aIsChanged) {
618                mIsChanged = aIsChanged;
619                if (mSaveQueryAction != null) {
620                        mSaveQueryAction.setEnabled(aIsChanged);
621                }
622        }
623
624        public void setExternalTMListener(TableModelListener aL) {
625                mExternalTMListener = aL;
626        }
627
628        /**
629         * Saves Query to a file
630         */
631        public Writer saveFile(String aTitle, String aFilterStr, String aFilterTitle) {
632                PtFileChooser chooser = new PtFileChooser(mFrame, "Save " + aTitle, JFileChooser.SAVE_DIALOG);
633                chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
634                chooser.setSelectedFile(null);
635                final DBFileFilter dbFileFilter = new DBFileFilter(aFilterStr, aFilterTitle);
636                chooser.addChoosableFileFilter(new PtFilenameFilter() {
637                        @Override
638                    public boolean accept(File file) {
639                        return dbFileFilter.accept(file);
640                    }
641
642                        @Override
643                    public boolean accept(File directory, String name) {
644                        return dbFileFilter.accept(new File(directory, name));
645                    }
646
647                        @Override
648                    public String getDescription() {
649                        return dbFileFilter.getDescription();
650                    }
651                });
652                int retval = chooser.showDialog(this, "Save");
653                if (retval == JFileChooser.APPROVE_OPTION) {
654                        // declared here only to make visible to finally clause; generic
655                        // reference
656                        Writer output = null;
657                        try {
658                                // use buffering
659                                return new BufferedWriter(new FileWriter(chooser
660                                                .getSelectedFile()));
661                        } catch (FileNotFoundException ex) {
662                                JOptionPane.showMessageDialog(this, ex.toString());
663                        } catch (IOException ex) {
664                                JOptionPane.showMessageDialog(this, ex.toString());
665                        } finally {
666                                // flush and close both "output" and its underlying FileWriter
667                                try {
668                                        if (output != null)
669                                                output.close();
670                                } catch (IOException ex) {
671                                        JOptionPane.showMessageDialog(this, ex.toString());
672                                }
673                        }
674                }
675                return null;
676        }
677
678        /**
679         * Saves Query to a file
680         */
681        public void saveQueryFile() {
682                Writer output = saveFile("Query", "query", "Query Files");
683                if (output != null) {
684                        DBQueryDef queryDef = new DBQueryDef();
685                        mBuilderTab.fillQueryDef(queryDef);
686
687                        try {
688                                output.write(DBQueryDefParserEmitter.emitXML(queryDef));
689                                output.close();
690                                setIsChanged(false);
691                                setStatus(ADD_MSG);
692                        } catch (IOException ex) {
693                                JOptionPane.showMessageDialog(this, ex.toString());
694                        }
695                }
696        }
697
698        /**
699         * Saves Query to a file
700         */
701        public void saveSchemaFile() {
702                Writer output = saveFile("Schema", "schema", "QueSchemary Files");
703                if (output != null) {
704                        try {
705                                output.write(DBSchemaParserEmitter.emitXML(mSchema));
706                                output.close();
707                        } catch (IOException ex) {
708                                JOptionPane.showMessageDialog(this, ex.toString());
709                        }
710                }
711        }
712
713        /**
714         * Loads the QueryDef object into the UI
715         * 
716         * @param aQueryDef
717         *            the query def
718         */
719        protected void loadQuery(DBQueryDef aQueryDef) {
720                if (aQueryDef != null) {
721                        mQueryDef = aQueryDef;
722
723                        QBBuilderInterface builder = null;
724                        int tabInx = SQL_TAB;
725
726                        boolean debug = false;
727                        /*
728                         * if (debug) { int status = mInterSP.buildFromQueryDef(aQueryDef);
729                         * if (status == DBQueryDef.BUILD_TOO_COMPLEX_WHERE || status ==
730                         * DBQueryDef.BUILD_TOO_COMPLEX_JOINS) {
731                         * JOptionPane.showMessageDialog(this,
732                         * "Switching to the Advanced View,\nthe query is too complex for the Standard Tab."
733                         * ); tabInx = ADV_TAB; builder = mAdvSP;
734                         * builder.buildFromQueryDef(mQueryDef); } else { tabInx =
735                         * INTER_TAB; builder = mInterSP; } } else { if (aQueryDef.isAdv())
736                         * { int status = mInterSP.buildFromQueryDef(aQueryDef); if (status
737                         * == DBQueryDef.BUILD_TOO_COMPLEX_WHERE || status ==
738                         * DBQueryDef.BUILD_TOO_COMPLEX_JOINS) {
739                         * JOptionPane.showMessageDialog(this,
740                         * "Switching to the Advanced View,\nthe query is too complex for the Intermediate Tab."
741                         * ); tabInx = ADV_TAB; builder = mAdvSP;
742                         * builder.buildFromQueryDef(mQueryDef); } else { tabInx =
743                         * INTER_TAB; builder = mInterSP; } } else { int status =
744                         * mStdSP.buildFromQueryDef(aQueryDef); if (status ==
745                         * DBQueryDef.BUILD_TOO_COMPLEX_WHERE || status ==
746                         * DBQueryDef.BUILD_TOO_COMPLEX_JOINS) {
747                         * mTabbedPane.setSelectedIndex(INTER_TAB);
748                         * JOptionPane.showMessageDialog(this,
749                         * "Switching to the Intermediate View,\nthe query is too complex for the Standard Tab."
750                         * ); tabInx = INTER_TAB; builder = mInterSP;
751                         * builder.buildFromQueryDef(mQueryDef); } else { tabInx = STD_TAB;
752                         * builder = mStdSP; } }
753                         * 
754                         * }
755                         */
756
757                        // only handle stand panel
758                        int status = mStdSP.buildFromQueryDef(aQueryDef);
759                        if (status == DBQueryDef.BUILD_TOO_COMPLEX_WHERE
760                                        || status == DBQueryDef.BUILD_TOO_COMPLEX_JOINS) {
761                                JOptionPane.showMessageDialog(this,
762                                                "The query is too complex for the Standard Tab.");
763                        } else {
764                                tabInx = STD_TAB;
765                                builder = mStdSP;
766                        }
767
768                        if (mBuilderTab == null) {
769                                mBuilderTab = builder;
770                                mLastTabInx = tabInx;
771                                mTabInx = tabInx;
772                        }
773                        mTabbedPane.setSelectedIndex(tabInx);
774
775                } else {
776                        JOptionPane
777                                        .showMessageDialog(this,
778                                                        "There was an error parsing the query.\nIt could not be loaded.");
779                }
780                setIsChanged(false);
781                setStatus(ADD_MSG);
782        }
783
784        /**
785         * Fills QueryDef from Model
786         */
787        public void fillQueryDef(DBQueryDef aQueryDef) {
788                if (aQueryDef == null)
789                        return;
790
791                mBuilderTab.fillQueryDef(aQueryDef);
792
793        }
794
795        /**
796         * Sets which builder tab should be used if the query is null
797         * 
798         */
799        public void initializeBuilder() {
800                if (mBuilderTab == null) {
801                        mBuilderTab = mStdSP;
802                        mTabInx = STD_TAB;
803                        mLastTabInx = STD_TAB;
804                        mTabbedPane.setSelectedIndex(mLastTabInx);
805                }
806
807        }
808
809        /**
810         * Loads a Schema and a Query into the Builder
811         * 
812         * @param aSchema
813         *            The schema to be used
814         * @param aQueryDef
815         *            the query def to be loaded (can be null)
816         */
817        public void set(DSSchemaIFace aSchema, DBQueryDef aQueryDef) {
818                mQueryDef = aQueryDef;
819                loadSchemaIntoUI(aSchema);
820                if (mQueryDef != null) {
821                        loadQuery(mQueryDef);
822                } else {
823                        initializeBuilder();
824                }
825        }
826
827        /**
828         * 
829         * Opens a Query and loads into the builder
830         */
831        public String openFile(String aTitle, String aFilterStr, String aFilterTitle) {
832                PtFileChooser chooser = new PtFileChooser(mFrame, "Open " + aTitle, JFileChooser.OPEN_DIALOG);
833                chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
834                chooser.setSelectedFile(null);
835                final DBFileFilter dbFileFilter = new DBFileFilter(aFilterStr, aFilterTitle);
836                chooser.addChoosableFileFilter(new PtFilenameFilter() {
837                        @Override
838                    public boolean accept(File file) {
839                        return dbFileFilter.accept(file);
840                    }
841
842                        @Override
843                    public boolean accept(File directory, String name) {
844                        return dbFileFilter.accept(new File(directory, name));
845                    }
846
847                        @Override
848                    public String getDescription() {
849                        return dbFileFilter.getDescription();
850                    }
851                });
852                JComponent frame = this;
853
854                // clear the preview from the previous display of the chooser
855                int retval = chooser.showDialog(frame, "Open");
856                if (retval == JFileChooser.APPROVE_OPTION) {
857                        File theFile = chooser.getSelectedFile();
858                        if (theFile != null) {
859                                if (theFile.isDirectory()) {
860                                        // JOptionPane.showMessageDialog(frame,
861                                        // "You chose this directory: " + theFile.getPath());
862                                } else {
863                                        return theFile.getPath();
864                                }
865                        }
866
867                } else if (retval == JFileChooser.CANCEL_OPTION) {
868                        // JOptionPane.showMessageDialog(frame,
869                        // "User cancelled operation. No file was chosen.");
870                } else if (retval == JFileChooser.ERROR_OPTION) {
871                        JOptionPane.showMessageDialog(frame,
872                                        "An error occured. No file was chosen.");
873                } else {
874                        JOptionPane.showMessageDialog(frame, "Unknown operation occured.");
875                }
876                return null;
877        }
878
879        /**
880         * 
881         * Opens a Query and loads into the builder
882         */
883        public void openQueryFile() {
884                String path = openFile("Query", "query", "Query Files");
885                if (path != null) {
886                        mQueryDef = DBQueryDefParserEmitter.readQueryDef(mSchema, path);
887                        if (mQueryDef == null) {
888                                JOptionPane.showMessageDialog(this, DBQueryDefParserEmitter
889                                                .getErrorCodeText(), "Query Error",
890                                                JOptionPane.ERROR_MESSAGE);
891                        } else {
892                                mBuilderTab = null; // must be done here
893                                loadQuery(mQueryDef);
894                        }
895                }
896        }
897
898        /**
899         * 
900         * Opens a Query and loads into the builder
901         */
902        public void openSchemaFile() {
903                String path = openFile("Schema", "schema", "Schema Files");
904                if (path != null) {
905
906                        DSSchemaIFace schema = DBSchemaParserEmitter.readSchemaDef(path);
907                        if (schema != null) {
908                                mQueryDef = null;
909                                loadSchemaIntoUI(schema);
910                                initializeBuilder();
911                        }
912                }
913        }
914
915        /**
916         * Helper method
917         * 
918         * @param aFileName
919         */
920        private void runQueryTest(String aFileName) {
921                DBQueryDef queryDef = DBQueryDefParserEmitter.readQueryDef(mSchema,
922                                aFileName);
923                System.err.print(aFileName + " - ");
924                System.err.println(queryDef == null ? DBQueryDefParserEmitter
925                                .getErrorCodeText() : "OK");
926
927        }
928
929        /**
930         * 
931         * Loads various queries for testing the parser
932         */
933        public void testQueries() {
934                String dirStr = "/home/globus/";
935
936                runQueryTest(dirStr + "good.query");
937                runQueryTest(dirStr + "join_fieldname_bad.query");
938                // runQueryTest(dirStr + "join_tableid_bad.query");
939                runQueryTest(dirStr + "join_tablename_bad.query");
940                runQueryTest(dirStr + "select_fieldname_bad.query");
941                runQueryTest(dirStr + "select_tablename_bad.query");
942                runQueryTest(dirStr + "table_tablename_bad.query");
943                runQueryTest(dirStr + "where_fieldname_bad.query");
944                runQueryTest(dirStr + "where_tablename_bad.query");
945        }
946
947        /**
948         * Returns the SQL in a TAB of the builder and sets it into the SQL Tab's
949         * readonly text editor
950         * 
951         * @param aLastInx
952         *            the last builder tab to be used
953         * @return the SQL string of that tab
954         */
955        public String processTabForSQL(int aLastInx) {
956                switch (aLastInx) {
957                case 0:
958                        return mStdSP.createSQL();
959
960                        // case 1 :
961                        // return mInterSP.createSQL();
962
963                        // case 2 :
964                        // return mAdvSP.createSQL();
965
966                case SQL_TAB:
967                        // should never get here
968                        break;
969                }
970                return null;
971        }
972
973        /**
974         * Return the appropriate builder for a given tab index
975         * 
976         * @param aTabIndex
977         *            the tabe index
978         * @return the QBBuilderInterface object for the tab index
979         */
980        private QBBuilderInterface getBuilderFromTabIndex(int aTabIndex) {
981                switch (aTabIndex) {
982                case 0:
983                        return mStdSP;
984                        // case 1 : return mInterSP;
985                        // case 2 : return mAdvSP;
986                }
987                return null;
988        }
989
990        /**
991         * Process when TAB changes
992         */
993        public void processTabChange() {
994                // Bail if there is no valid Query Obj
995                /*
996                 * if (mQueryDef == null) { System.out.println("the mQueryDef= null");
997                 * return; }
998                 */
999
1000                if (mStdSP != null) {
1001                        // System.out.println("clear the selection");
1002                        DBSelectTableUIBase table = mStdSP.getSelectedTableView();
1003                        if (table != null) {
1004                                TableCellEditor editor = table.getCellEditor();
1005                                if (editor != null) {
1006                                        editor.stopCellEditing();
1007                                }
1008                        }
1009                        /*
1010                         * int column = table.getSelectedColumn();
1011                         * System.out.println("selected column "+column); int row =
1012                         * table.getSelectedRow(); System.out.println("selected row "+row);
1013                         * Object obj = table.getModel().getValueAt(row, column);
1014                         * System.out.println("!!!!!!!!!the selected value is "+obj); column
1015                         * = table.getSelectedColumn();
1016                         * System.out.println("selected column "+column); row =
1017                         * table.getSelectedRow(); table.getModel().setValueAt(obj, row,
1018                         * column);
1019                         * 
1020                         * obj = table.getModel().getValueAt(row, column);
1021                         * System.out.println("!!!!!!!!!the selected value is "+obj);
1022                         * table.transferFocus();
1023                         */
1024
1025                }
1026
1027                // This can happen if the user clicks to the SQL tab and
1028                // then back to the same tab as before
1029                //
1030                // So we do not try to process (or convert) the Query from one tab to
1031                // the next
1032                if (mLastTabInx == mTabInx) {
1033                        return;
1034                }
1035
1036                if (mTabInx == SQL_TAB) {
1037                        mSQLSP.setText(processTabForSQL(mLastTabInx));
1038                        return;
1039                }
1040
1041                // System.out.println("mTableInx is "+mTabInx);
1042                QBBuilderInterface newBldr = getBuilderFromTabIndex(mTabInx);
1043                // System.out.println("newbldr is "+newBldr);
1044
1045                boolean cachedIsChanged = false;
1046                boolean doSwitch = true;
1047                if (!mBuilderTab.canConvertTo(newBldr)) {
1048                        String msg = "Data Loss will occur for this query when switching to from "
1049                                        + mBuilderTab.getName() + " to " + newBldr.getName();
1050                        Object[] options = { "Continue", "Do Not Switch" };
1051                        int option = JOptionPane.showOptionDialog(null, msg,
1052                                        "Switching Error", JOptionPane.YES_NO_OPTION,
1053                                        JOptionPane.WARNING_MESSAGE, null, options, options[0]);
1054
1055                        if (option == JOptionPane.NO_OPTION) {
1056                                mTabInx = mBuilderTab.getType();
1057                                mTabbedPane.setSelectedIndex(mTabInx);
1058                                doSwitch = false;
1059                        }
1060
1061                }
1062
1063                if (doSwitch) {
1064                        mTabInx = newBldr.getType();
1065                        cachedIsChanged = true;
1066                        mQueryDef = new DBQueryDef();
1067
1068                        mBuilderTab.fillQueryDef(mQueryDef);
1069                        newBldr.buildFromQueryDef(mQueryDef);
1070
1071                        mBuilderTab = newBldr;
1072
1073                        mTabbedPane.setSelectedIndex(mTabInx);
1074                }
1075
1076                setIsChanged(cachedIsChanged);
1077                // setStatus(mIsChanged? CHANGED_MSG : msgStr);
1078
1079        }
1080
1081        /**
1082         * @return whether the SQL tab is the current Tab
1083         */
1084        public boolean isSQLTab() {
1085                return mTabInx == SQL_TAB;
1086        }
1087
1088        /**
1089         * 
1090         * @return the SQL string for the "current" or more recent builder tab
1091         */
1092        public String getSQLString() {
1093                return "";
1094        }
1095
1096        // *******************************************************
1097        // ****************** Runnables ***********************
1098        // *******************************************************
1099
1100        /**
1101         * Generic QBApp runnable. This is intended to run on the AWT gui event
1102         * thread so as not to muck things up by doing gui work off the gui thread.
1103         * Accepts a QBApp and an Object as arguments, which gives subtypes of this
1104         * class the two "must haves" needed in most runnables for this demo.
1105         */
1106        class QBAppRunnable implements Runnable {
1107
1108                protected QBApp mQBApp;
1109
1110                protected Object obj;
1111
1112                public QBAppRunnable(QBApp aQBApp, Object obj) {
1113                        this.mQBApp = aQBApp;
1114                        this.obj = obj;
1115                }
1116
1117                public void run() {
1118                }
1119        }
1120
1121        // *******************************************************
1122        // ******************** Actions ***********************
1123        // *******************************************************
1124
1125        class GenericMenuAction extends AbstractAction {
1126                public static final int OPEN_QUERY_ACTION = 0;
1127                public static final int SAVE_QUERY_ACTION = 1;
1128                public static final int OPEN_SCHEMA_ACTION = 2;
1129                public static final int SAVE_SCHEMA_ACTION = 3;
1130                public static final int EXIT_ACTION = 4;
1131                public static final int QUERY_TESTS_ACTION = 5;
1132
1133                QBApp mQueryBuilder;
1134                int mActionType;
1135
1136                protected GenericMenuAction(QBApp aQBApp, int aActionType) {
1137                        super("Action");
1138                        mQueryBuilder = aQBApp;
1139                        mActionType = aActionType;
1140                }
1141
1142                public void actionPerformed(ActionEvent e) {
1143                        switch (mActionType) {
1144                        case OPEN_QUERY_ACTION:
1145                                mQueryBuilder.openQueryFile();
1146                                break;
1147                        case SAVE_QUERY_ACTION:
1148                                mQueryBuilder.saveQueryFile();
1149                                break;
1150                        case OPEN_SCHEMA_ACTION:
1151                                mQueryBuilder.openSchemaFile();
1152                                break;
1153                        case SAVE_SCHEMA_ACTION:
1154                                mQueryBuilder.saveSchemaFile();
1155                                break;
1156                        case EXIT_ACTION: {
1157                                System.out.println("here!!!!!!!!!!!11");
1158                                if (mIsChanged) {
1159                                        int x0 = JOptionPane.CLOSED_OPTION;
1160                                        int x1 = JOptionPane.YES_OPTION;
1161                                        int x2 = JOptionPane.NO_OPTION;
1162                                        int x3 = JOptionPane.OK_OPTION;
1163                                        int x4 = JOptionPane.CLOSED_OPTION;
1164                                        Object[] options = { "Discard and Exit", "Save and Exit",
1165                                                        "Cancel" };
1166                                        String msg = "You have changed the query, do you wish to save it before exiting?";
1167                                        int option = JOptionPane.showOptionDialog(null, msg,
1168                                                        "Exiting", JOptionPane.DEFAULT_OPTION,
1169                                                        JOptionPane.WARNING_MESSAGE, null, options,
1170                                                        options[1]);
1171                                        System.out.println("the option chose is " + option);
1172                                        if (option == JOptionPane.NO_OPTION) {
1173                                                mQueryBuilder.saveQueryFile();
1174                                        } else if (option == 2) {
1175                                                return;
1176                                        }
1177                                }
1178                                System.exit(0);
1179                        }
1180                                break;
1181                        case QUERY_TESTS_ACTION:
1182                                mQueryBuilder.testQueries();
1183                                break;
1184                        }
1185
1186                }
1187        }
1188
1189        class CancelAction extends AbstractAction {
1190                QBEditor frame;
1191
1192                protected CancelAction(QBEditor frame) {
1193                        super("Cancel");
1194                        this.frame = frame;
1195                }
1196
1197                public void actionPerformed(ActionEvent e) {
1198                        if (frame != null) {
1199                                frame.closeWindows();
1200                        }
1201
1202                        // System.exit(0);
1203
1204                }
1205        }
1206
1207        class OKAction extends AbstractAction {
1208
1209                QBEditor frame;
1210
1211                protected OKAction(QBEditor frame) {
1212                        super("OK");
1213                        this.frame = frame;
1214
1215                }
1216
1217                public void actionPerformed(ActionEvent e) {
1218                        if (frame != null) {
1219                                if (mStdSP != null) {
1220
1221                                        DBSelectTableUIBase table = mStdSP.getSelectedTableView();
1222                                        if (table != null) {
1223                                                TableCellEditor editor = table.getCellEditor();
1224                                                if (editor != null) {
1225                                                        editor.stopCellEditing();
1226                                                }
1227                                        }
1228                                }
1229
1230                                frame.save();
1231                        }
1232
1233                }
1234        }
1235
1236        // -----------------------------------------------------------------------------
1237        // -- ChangeListener Interface
1238        // -----------------------------------------------------------------------------
1239
1240        /**
1241         * Notify when TAB changes
1242         */
1243        public void stateChanged(ChangeEvent e) {
1244                if (mTabInx != SQL_TAB) {
1245                        mLastTabInx = mTabInx;
1246                }
1247
1248                SingleSelectionModel model = (SingleSelectionModel) e.getSource();
1249                mTabInx = model.getSelectedIndex();
1250
1251                processTabChange();
1252        }
1253
1254        // -----------------------------------------------------------------------------
1255        // -- TableModelListener Interface
1256        // -----------------------------------------------------------------------------
1257
1258        public void tableChanged(TableModelEvent e) {
1259                setIsChanged(true);
1260                setStatus(CHANGED_MSG);
1261                if (mExternalTMListener != null) {
1262                        mExternalTMListener.tableChanged(e);
1263                }
1264        }
1265
1266        // -----------------------------------------------------------------------------
1267        // -- Application MAIN
1268        // -----------------------------------------------------------------------------
1269
1270        /**
1271         * QBApp Main. Called only if we're an application, not an applet.
1272         */
1273        public static void main(String[] args) {
1274                // Create QBApp on the default monitor
1275                QBApp qbApp = new QBApp(null, GraphicsEnvironment
1276                                .getLocalGraphicsEnvironment().getDefaultScreenDevice()
1277                                .getDefaultConfiguration());
1278        }
1279
1280}