001/*
002 * Copyright (c) 2003-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: welker $'
006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 
007 * '$Revision: 24234 $'
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.Color;
033import java.awt.Component;
034import java.awt.Point;
035import java.awt.datatransfer.DataFlavor;
036import java.awt.dnd.DnDConstants;
037import java.awt.dnd.DropTarget;
038import java.awt.dnd.DropTargetDragEvent;
039import java.awt.dnd.DropTargetDropEvent;
040import java.awt.dnd.DropTargetEvent;
041import java.awt.dnd.DropTargetListener;
042import java.awt.event.MouseAdapter;
043import java.awt.event.MouseEvent;
044import java.util.Enumeration;
045import java.util.Vector;
046
047import javax.swing.DefaultCellEditor;
048import javax.swing.JCheckBox;
049import javax.swing.JComboBox;
050import javax.swing.JMenuItem;
051import javax.swing.JPopupMenu;
052import javax.swing.JTable;
053import javax.swing.table.TableCellEditor;
054import javax.swing.table.TableCellRenderer;
055
056/**
057 * The JTable abstract base class for rendering portions (or all) of the select
058 * statement.
059 * 
060 */
061public abstract class DBSelectTableUIBase extends JTable implements
062                DropTargetListener {
063        protected DBSelectTableModelBase mModel = null;
064        protected DataFlavor[] mDataFlavor = new DataFlavor[1];
065        protected int mAceptableActions = DnDConstants.ACTION_COPY_OR_MOVE;
066        protected DropTarget mDropTarget = new DropTarget(this, mAceptableActions,
067                        this);
068
069        protected Vector mListeners = new Vector();
070
071        protected JCheckBox mIsDisplayedCheckbox = null;
072
073        protected JComboBox mTablesComboBox = null;
074        protected JComboBox mFieldsComboBox = null;
075        protected JComboBox mBoolOpers = null;
076
077        protected String mDragTableName = "";
078
079        protected boolean mCheckOkToDrop = true;
080        protected boolean mOkToDrop = true;
081
082        private static final int INCLUDECLOWIDTH = 100;
083
084        /**
085         * Constructs a Table "View" which allows DBTable items to be dropped onto
086         * it
087         * 
088         */
089        public DBSelectTableUIBase() {
090        }
091
092        /*
093         * sets tyhe listener to null
094         */
095        public void finalize() {
096                mListeners = null;
097        }
098
099        /**
100         * Perform the drop action for the sub-class of choice
101         * 
102         * @param e
103         *            the ebent
104         */
105        protected abstract void doDrop(DropTargetDropEvent e);
106
107        /**
108         * Notification that an model item was added.
109         * 
110         * @param aItem
111         *            the item to be added
112         */
113        protected void itemWasAdded(DBSelectTableModelItem aItem) {
114                if (mListeners != null) {
115                        for (Enumeration ef = mListeners.elements(); ef.hasMoreElements();) {
116                                ((DBSelectTableFieldChangedListener) ef.nextElement())
117                                                .notifyFieldChanged();
118                        }
119                }
120        }
121
122        /**
123         * Adds listener
124         * 
125         * @param aListener
126         *            listener to be added
127         * 
128         */
129        public void addFieldChangeListener(
130                        DBSelectTableFieldChangedListener aListener) {
131                if (aListener != null)
132                        mListeners.add(aListener);
133        }
134
135        /**
136         * Sets a single listener for this object, remove it by setting it to null
137         * 
138         * @param aListener
139         *            listener to be added
140         * 
141         */
142        public void removeFieldChangeListener(
143                        DBSelectTableFieldChangedListener aListener) {
144                if (aListener != null)
145                        mListeners.remove(aListener);
146        }
147
148        /**
149         * Receices this notification before the editor is paced in the cell
150         * 
151         * @param aRow
152         *            row of cell
153         * @param aColumn
154         *            coloumn of cell
155         */
156        public TableCellEditor getCellEditor(int aRow, int aColumn) {
157                // fill the comboboxes that will be used for the cell
158                if (aColumn == 0) {
159                        fillTableCombobox(aRow);
160
161                } else if (aColumn == 1) {
162                        fillFieldCombobox(aRow);
163                }
164                return super.getCellEditor(aRow, aColumn);
165        }
166
167        /**
168         * Fill the table combobox, note that if all the fields have been already
169         * used the table won't show in the list unless they are editting a row
170         * containing that table name
171         * 
172         * @param aRow
173         *            the row of the item
174         */
175        protected void fillTableCombobox(int aRow) {
176                mTablesComboBox.removeAllItems();
177                Vector tableNames = mModel.getAvailableTableNames(aRow);
178                for (Enumeration ef = tableNames.elements(); ef.hasMoreElements();) {
179                        mTablesComboBox.addItem((String) ef.nextElement());
180                }
181        }
182
183        /**
184         * Fill the fields combobox with any field names for that table that have
185         * not been used. BUT! Remember to include the name of the item that is
186         * currently being editted
187         * 
188         * @param aRow
189         *            the row of the item
190         * 
191         */
192        protected void fillFieldCombobox(int aRow) {
193                mFieldsComboBox.removeAllItems();
194                String tableName = mModel.getFieldForRow(aRow).getTableName();
195                Vector fieldNames = mModel.getAvailableFieldNames(tableName);
196                for (Enumeration ef = fieldNames.elements(); ef.hasMoreElements();) {
197                        mFieldsComboBox.addItem((String) ef.nextElement());
198                }
199        }
200
201        /**
202         * Set the data model into the table
203         * 
204         * @param aModel
205         *            the table data model
206         */
207        public void setModel(DBSelectTableModelBase aModel) {
208                if (aModel != null)
209                        super.setModel(aModel);
210                mModel = aModel;
211        }
212
213        /**
214         * Creates and Installs cell editors, must be called AFTER setting the model
215         */
216        public void installEditors() {
217                mIsDisplayedCheckbox = new JCheckBox();
218
219                if (mModel != null && mModel.getSchema() != null) {
220                        // Use the combo box as the editor in the "Favorite Color" column.
221                        mTablesComboBox = new JComboBox();
222                        mTablesComboBox.setBackground(Color.WHITE);
223                        mFieldsComboBox = new JComboBox();
224                        mFieldsComboBox.setBackground(Color.WHITE);
225                        mBoolOpers = new JComboBox();
226                        mBoolOpers.setBackground(Color.WHITE);
227
228                        mTablesComboBox.addItem("  ");
229                        DBUIUtils.fillTableCombobox(mModel.getSchema(), mTablesComboBox);
230                        setRowHeight(mTablesComboBox.getPreferredSize().height);
231
232                        getColumn("Table").setCellEditor(
233                                        new DefaultCellEditor(mTablesComboBox));
234                        getColumn("Table").setCellRenderer(new JComboBoxCellRenderer());
235                        getColumn("Field").setCellEditor(
236                                        new DefaultCellEditor(mFieldsComboBox));
237                        getColumn("Field").setCellRenderer(new JComboBoxCellRenderer());
238                        getColumn(DBSelectTableModelStd.INCLUDESELECTION)
239                                        .setPreferredWidth(INCLUDECLOWIDTH);
240
241                }
242        }
243
244        /**
245         * Indicates whether the items can be dropped
246         * 
247         * @param aTableName
248         *            the table name
249         * @param aFieldName
250         *            the field name
251         * @return true if is can be dropped, otherwise false
252         */
253        private boolean okToDrop(String aTableName, String aFieldName) {
254
255                Vector fieldNames = mModel.getAvailableFieldNames(aTableName);
256                for (Enumeration et = fieldNames.elements(); et.hasMoreElements();) {
257                        String tblFieldName = (String) et.nextElement();
258                        if (tblFieldName.equals(aFieldName)) {
259                                return true;
260                        }
261                }
262                return false;
263        }
264
265        // --------------------------------------------------------------
266        // ------------------ Drop Target Methods -----------------------
267        // --------------------------------------------------------------
268
269        /**
270         * Checks to see if it is the right type of object
271         */
272        public void dragEnter(DropTargetDragEvent e) {
273                if (!isDragOk(e)) {
274                        e.rejectDrag();
275                        return;
276                }
277        }
278
279        /**
280         * Stubbed
281         */
282        public void dragExit(DropTargetEvent dropTargetEvent) {
283        }
284
285        /**
286         * Checks to see if it is the right type of object
287         */
288        public void dragOver(DropTargetDragEvent e) {
289
290                if (!isDragOk(e)) {
291                        e.rejectDrag();
292                        return;
293                }
294        }
295
296        /**
297         * Checks to make sure the transaferable is OK to be dropped
298         * 
299         * @param e
300         *            current D&D event
301         * @return whether it can be dropped
302         */
303        private boolean isDragOk(DropTargetDragEvent e) {
304                if (!e.isDataFlavorSupported(mDataFlavor[0])) {
305                        return false;
306                }
307
308                // the actions specified when the source
309                // created the DragGestureRecognizer
310                int sa = e.getSourceActions();
311
312                // we're saying that these actions are necessary
313                if ((sa & mAceptableActions) == 0)
314                        return false;
315
316                // System.out.println("isDragOk: "+e.getSourceActions() +
317                // " mAceptableActions "+mAceptableActions +"  "+(((e.getSourceActions()
318                // & mAceptableActions) != 0)));
319                return true;
320        }
321
322        /**
323         * Stubbed
324         */
325        public void dropActionChanged(DropTargetDragEvent dropTargetDragEvent) {
326        }
327
328        /**
329         * Allows DBTable items to be droped and then creates a new "row" in the
330         * table representing the item
331         */
332        public synchronized void drop(DropTargetDropEvent e) {
333                doDrop(e);
334        }
335
336        /*
337         * This calss will render at table cell as JComboBox
338         */
339        protected class JComboBoxCellRenderer implements TableCellRenderer {
340                public Component getTableCellRendererComponent(JTable table,
341                                Object Value, boolean isSelected, boolean hasFocus, int row,
342                                int column) {
343                        // System.out.println("value in ===================== is "+Value);
344                        String[] itemList = new String[1];
345                        if (Value == null) {
346                                itemList[0] = "";
347                        } else {
348                                itemList[0] = Value.toString();
349                        }
350                        JComboBox renderer = new JComboBox(itemList);
351                        renderer.setSelectedIndex(0);
352                        renderer.setBackground(Color.WHITE);
353                        return renderer;
354                }
355        }
356
357        /*
358         * This class will add listener to pop up a right click menu - deleting this
359         * row
360         */
361        protected class PopupListener extends MouseAdapter {
362                // on the Mac, popups are triggered on mouse pressed, while
363                // mouseReleased triggers them on the PC; use the trigger flag to
364                // record a trigger, but do not show popup until the
365                // mouse released event
366                private boolean trigger = false;
367                private DBSelectTableUIBase table;
368
369                public PopupListener(DBSelectTableUIBase table) {
370                        this.table = table;
371                }
372
373                /**
374                 * Description of the Method
375                 * 
376                 *@param e
377                 *            Description of the Parameter
378                 */
379                public void mousePressed(MouseEvent e) {
380                        // maybeShowPopup(e);
381                        if (e.isPopupTrigger()) {
382                                trigger = true;
383                        }
384                }
385
386                /**
387                 * Description of the Method
388                 * 
389                 *@param e
390                 *            Description of the Parameter
391                 */
392                public void mouseReleased(MouseEvent e) {
393                        maybeShowPopup(e);
394                }
395
396                /**
397                 * Description of the Method
398                 * 
399                 *@param e
400                 *            Description of the Parameter
401                 */
402                private void maybeShowPopup(MouseEvent e) {
403                        if ((e.isPopupTrigger()) || (trigger) && table != null
404                                        && mModel != null) {
405                                // System.out.println("start in myabe show popup");
406                                trigger = false;
407                                int selectedRow = table
408                                                .rowAtPoint(new Point(e.getX(), e.getY()));
409                                // System.out.println("the selected row number is "+selectedRow);
410                                int rowLength = mModel.getRowCount();
411                                // System.out.println("the row number in the model is "+rowLength);
412                                // the last row wouldn't popup a deletion menu because
413                                // it is
414                                if ((selectedRow != rowLength - 1)) {
415                                        DBSelectTableModelStd stdModel = (DBSelectTableModelStd) mModel;
416                                        // System.out.println("in generate pop menu (pass selected != rowLength");
417                                        DBSelectTableModelDeleteAction deleteAction = new DBSelectTableModelDeleteAction(
418                                                        "Delete", table, stdModel, selectedRow);
419                                        JPopupMenu popup = new JPopupMenu();
420                                        ;
421                                        JMenuItem deletionMenuItem = new JMenuItem(deleteAction);
422                                        deletionMenuItem.setBackground(Color.LIGHT_GRAY);
423                                        popup.add(deletionMenuItem);
424                                        popup.show(e.getComponent(), e.getX(), e.getY());
425
426                                }
427                        }
428                }
429        }
430
431}