View Javadoc

1   package com.explosion.datastream.exql.gui.table;
2   
3   /*
4    * =============================================================================
5    * 
6    * Copyright 2004 Stephen Cowx
7    * 
8    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
9    * use this file except in compliance with the License. You may obtain a copy of
10   * the License at
11   * 
12   * http://www.apache.org/licenses/LICENSE-2.0
13   * 
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17   * License for the specific language governing permissions and limitations under
18   * the License.
19   * 
20   * =============================================================================
21   */
22  
23  import java.awt.Color;
24  import java.awt.Font;
25  import java.awt.Toolkit;
26  import java.awt.datatransfer.Clipboard;
27  import java.awt.datatransfer.ClipboardOwner;
28  import java.awt.datatransfer.DataFlavor;
29  import java.awt.datatransfer.Transferable;
30  import java.awt.datatransfer.UnsupportedFlavorException;
31  import java.awt.event.MouseEvent;
32  import java.io.IOException;
33  import java.util.ArrayList;
34  import java.util.Arrays;
35  import java.util.HashMap;
36  import java.util.Iterator;
37  import java.util.List;
38  import java.util.Map;
39  import java.util.StringTokenizer;
40  import java.util.Vector;
41  
42  import javax.swing.JOptionPane;
43  import javax.swing.JTable;
44  import javax.swing.ListSelectionModel;
45  import javax.swing.event.ListSelectionEvent;
46  import javax.swing.event.ListSelectionListener;
47  import javax.swing.event.TableModelEvent;
48  import javax.swing.event.TableModelListener;
49  import javax.swing.table.DefaultTableModel;
50  import javax.swing.table.TableCellEditor;
51  import javax.swing.table.TableCellRenderer;
52  import javax.swing.table.TableModel;
53  import javax.swing.text.JTextComponent;
54  
55  import org.apache.log4j.LogManager;
56  import org.apache.log4j.Logger;
57  
58  import com.explosion.datastream.exql.EXQLConstants;
59  import com.explosion.datastream.exql.EXQLModuleManager;
60  import com.explosion.datastream.exql.gui.EXQLBaseTool;
61  import com.explosion.datastream.exql.gui.table.editandrender.DeletedValueCellRenderer;
62  import com.explosion.datastream.exql.gui.table.editandrender.DisplayValueCellRenderer;
63  import com.explosion.datastream.exql.gui.table.editandrender.EditorAndRenderFactory;
64  import com.explosion.datastream.exql.gui.table.editandrender.NonEditableValueCellRenderer;
65  import com.explosion.datastream.exql.gui.table.editandrender.TextBasedTableCellEditor;
66  import com.explosion.datastream.exql.gui.table.editandrender.UpdatedValueCellRenderer;
67  import com.explosion.expf.Application;
68  import com.explosion.expf.ExpConstants;
69  import com.explosion.expf.ExpFrame;
70  import com.explosion.expf.menusandtools.menu.MenuHelper;
71  import com.explosion.expf.menusandtools.menu.popup.ExpPopupIntercepter;
72  import com.explosion.expf.menusandtools.menu.popup.ExpPopupableMenu;
73  import com.explosion.expf.menusandtools.menu.segmented.ExpMenuSegment;
74  import com.explosion.expfmodules.rdbmsconn.dbom.DBEntity;
75  import com.explosion.expfmodules.rdbmsconn.dbom.DBEntityColumn;
76  import com.explosion.expfmodules.rdbmsconn.dbom.utils.InvalidDataException;
77  import com.explosion.expfmodules.rdbmsconn.dbom.utils.SQLEngine;
78  import com.explosion.expfmodules.texteditor.Editable;
79  import com.explosion.utilities.exception.ExceptionManagerFactory;
80  
81  /***
82   * Displays data. Edited values go red. Deleted values are struck through
83   * 
84   * @author Stephen Created on Apr 30, 2004
85   */
86  public class DsProTable extends JTable implements ExpPopupIntercepter, Editable, ClipboardOwner
87  {
88  
89  	private Map insertedRows = new HashMap();
90  	private Map deletedRows = new HashMap();
91  	private Map updatedRows = new HashMap();
92  	private static Logger log = LogManager.getLogger(DsProTable.class);
93  	private EXQLBaseTool tool;
94  	private Object cachedPreChangeValue;
95  	private boolean isEditable = true;
96  	private DBEntity entity = null;
97      private ExpPopupableMenu menu = null;
98      private Clipboard system;
99          
100 	public DsProTable(EXQLBaseTool tool, boolean isEditable) {
101 		this.tool = tool;
102 		this.isEditable = isEditable;
103 		setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
104 		setRowSelectionAllowed(true);
105 		setColumnSelectionAllowed(false);
106 		setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
107 		SelectionListener listener = new SelectionListener(this, tool);
108 		getSelectionModel().addListSelectionListener(listener);
109         
110         /* Drag and drop enabled */
111         setDragEnabled(true);
112         /*Edit support*/
113         system = Toolkit.getDefaultToolkit().getSystemClipboard();
114         /* Initialise the local listener */
115         DsProTableLocalListener localListener = new DsProTableLocalListener(this, tool);
116         //this.getR
117 	}
118 
119     /***
120 	 * Applies the properties for this tool;
121 	 */
122 	public void applyPreferences() {
123 
124 		setGridColor((Color) EXQLModuleManager.instance().getPreference(
125 				EXQLConstants.TABLE_GRID_COLOR).getValue());
126 		setForeground((Color) EXQLModuleManager.instance().getPreference(
127 				EXQLConstants.TABLE_COLORS_FOREGROUND).getValue());
128 		setBackground((Color) EXQLModuleManager.instance().getPreference(
129 				EXQLConstants.TABLE_COLORS_BACKGROUND).getValue());
130 		setSelectionForeground((Color) EXQLModuleManager.instance()
131 				.getPreference(EXQLConstants.TABLE_COLOR_SELECTEDFORGROUND)
132 				.getValue());
133 		setSelectionBackground((Color) EXQLModuleManager.instance()
134 				.getPreference(EXQLConstants.TABLE_COLOR_SELECTEDBACKGROUND)
135 				.getValue());
136 
137 		setShowHorizontalLines(((Boolean) EXQLModuleManager.instance()
138 				.getPreference(
139 						EXQLConstants.RDBMS_OPTION_SHOW_VERTICAL_GRID_LINES)
140 				.getValue()).booleanValue());
141 		setShowVerticalLines(((Boolean) EXQLModuleManager.instance()
142 				.getPreference(
143 						EXQLConstants.RDBMS_OPTION_SHOW_HORIZONTAL_GRID_LINES)
144 				.getValue()).booleanValue());
145 		setShowGrid(((Boolean) EXQLModuleManager.instance().getPreference(
146 				EXQLConstants.RDBMS_OPTION_SHOW_GRID).getValue())
147 				.booleanValue());
148 
149 		//if (!EXQLModuleManager.instance().getPreference(
150 			//	EXQLConstants.TABLE_FONT).isDefaulted())
151 			setFont((Font) EXQLModuleManager.instance().getPreference(
152 					EXQLConstants.TABLE_FONT).getValue());
153 	}
154 
155 	/***
156 	 * Returns whether or not this scell is editable.
157 	 * 
158 	 * @param arg0
159 	 * @param arg1
160 	 * @return
161 	 */
162 	public boolean isCellEditable(int row, int column) {
163 		try {
164 			
165 			DBEntityColumn col = getDBEntityColumn(column);
166 			if (col.isAutoIncrement()) 
167 			{
168 				return false;
169 			}
170 			else if (!SQLEngine.isSupportedEditableType(col.getType()))
171 			{ 
172 			   return false;      
173 			} 
174 			else if (deletedRows.get(new Integer(row)) != null) 
175 			{
176 				return false;
177 			}
178 		} catch (Exception e) {
179 			return true;
180 		}
181 
182 		return true;
183 	}
184 
185 	/***
186 	 * Inserts a row into the table
187 	 * 
188 	 * @param row
189 	 * @param v
190 	 */
191 	public int insertNewRow() {
192 		if (!isEditable)
193 			return -1;
194 
195 		int selectedRow = getSelectedRow();
196 
197 		if (selectedRow < 0) {
198 			insertedRows = reindex(insertedRows, 0);
199 			deletedRows = reindex(deletedRows, 0);
200 			updatedRows = reindex(updatedRows, 0);
201 
202 			((DefaultTableModel) getModel()).insertRow(0, new Vector());
203 			insertedRows.put(new Integer(0), new Integer(0));
204 		} else {
205 			insertedRows = reindex(insertedRows, selectedRow);
206 			deletedRows = reindex(deletedRows, selectedRow);
207 			updatedRows = reindex(updatedRows, selectedRow);
208 
209 			insertedRows
210 					.put(new Integer(selectedRow), new Integer(selectedRow));
211 			((DefaultTableModel) getModel()).insertRow(selectedRow,
212 					new Vector());
213 		}
214 		
215 		checkDirty();
216 		tool.repaint();
217         return selectedRow;
218 	}
219 
220 	/***
221 	 * Removes a row from the table
222 	 */
223 	public void deleteSelectedRows() {
224 		if (!isEditable)
225 			return;
226 
227 		int selectedRows[] = this.getSelectedRows();
228 		Arrays.sort(selectedRows);
229 		for (int i = 0; i < selectedRows.length; i++) {
230 			deletedRows.put(new Integer(selectedRows[i]), new Integer(
231 					selectedRows[i]));
232 		}
233 		
234 		checkDirty();
235 
236 		this.clearSelection();
237 
238 	}
239 
240 	/***
241 	 * Overrides the default behaviour because it has to reset the insertedRows
242 	 * HashMap. I.E Presume that the new data is all fresh
243 	 * 
244 	 * @see javax.swing.JTable#setModel(javax.swing.table.TableModel)
245 	 * @param model
246 	 */
247 	public void setModel(TableModel model) {
248 		insertedRows = new HashMap();
249 		deletedRows = new HashMap();
250 		updatedRows = new HashMap();
251 		checkDirty();
252 		Application.ensureLocalCookie(EXQLConstants.MENU_EXECUTE_CHANGES, 0,tool);
253 		super.setModel(model);
254 		if (isEditable) {
255 
256             Application.ensureLocalCookie(EXQLConstants.MENU_INSERT_ROW, 1, tool);
257             
258             model.addTableModelListener(new TableModelListener() {
259 
260 				public void tableChanged(TableModelEvent event) {
261 					int first = event.getFirstRow();
262 					int last = event.getLastRow();
263 					int column = event.getColumn();
264 					int type = event.getType();
265 					if (type == TableModelEvent.UPDATE) {
266 						if (first == last) {
267 							boolean changed = true;
268 
269 							/* If it was actually changed */
270 							Map row = (Map) updatedRows.get(new Integer(first));
271 							
272 							if (row == null)
273 							{
274 							    /* We can assume that this row has not been updated before, create a new HashMap for the row*/
275 							    row = new HashMap();
276 							    /* Store the original value at the column index*/ 
277 								row.put(new Integer(column), cachedPreChangeValue);
278 								/* Store the row updatedRows HashMap */
279 								updatedRows.put(new Integer(first), row);
280 								/* Update the dirtiness of the table */
281 								checkDirty();
282 							}
283 							else
284 							{
285 							    /* At least one value in this row has changed before 
286 							       Check to see if it is this column */
287 							    Object originalValue = row.get(new Integer(column));
288 							    if (originalValue == null)
289 								{
290 								    /* It isn't.  Add this column */
291 							        row.put(new Integer(column), cachedPreChangeValue);
292 							        /* Update the dirtiness of the table */
293 							        checkDirty();
294 								}
295 							    else
296 							    {
297 							        /* It is this column.  Check to see if the value has been changed back to the original */
298 							        Object newValue = getModel().getValueAt(first, column);
299 							        if (originalValue.equals(newValue))
300 							        {
301 							            /* If it has, remove the row from the scheduled updates */
302 							            row.remove(new Integer(column));
303 							            if (row.size() < 1)
304 							            {
305 							                updatedRows.remove(new Integer(first));
306 							                checkDirty();
307 							            }
308 							        }
309 							        else
310 							        {
311 							            /* No it hasn't.   Update the dirtiness of the table */
312 							            checkDirty();
313 							        }
314 							    }
315 							}
316 							
317 							/*
318 							 * The value may have been edited but not actually
319 							 * changed
320 							 */
321 							if (cachedPreChangeValue != null) {
322 							    Object originalValue = getOriginalValueAt(first, column);
323 							    changed = !cachedPreChangeValue.equals(originalValue);
324 							} else {
325 								changed = getModel().getValueAt(first, column) != null;
326 							}
327 
328 							if (changed) {
329 								/* If it was actually changed */
330 								
331 								if (row == null) {
332 									
333 								}
334 								/* We only want to store the original value that corresponds with the value
335 								 * in the actual table in this map.  The reason for this
336 								 * is that it will be used for selections in where clauses
337 								 * for updating and deleting rows.
338 								 * 
339 								 * Maintaining a redo/undo history must be achieved 
340 								 * through a different mechanism. */
341 								if (row.get(new Integer(column)) == null)
342 								{
343 								    row.put(new Integer(column), getModel().getValueAt(first,
344 										column));
345 								    Application.ensureLocalCookie(EXQLConstants.MENU_EXECUTE_CHANGES, 1,tool);
346 								}
347 							}
348 							cachedPreChangeValue = null;
349 						}
350 					}
351 				}
352 			});
353 		}
354         else
355         {
356             Application.ensureLocalCookie(EXQLConstants.MENU_INSERT_ROW, 0, tool);
357             Application.ensureLocalCookie(EXQLConstants.MENU_DELETE_ROW, 0, tool);
358             Application.ensureLocalCookie(EXQLConstants.MENU_EXECUTE_CHANGES, 0, tool);
359         }
360 	}
361 	
362 	/***
363 	 * This method returns the original value at the specified location.
364 	 * (This will be the same as was originally populated in the table)
365 	 * If the value hasn;t changed, this will have the same effect as calling getValueAt
366 	 * @param row
367 	 * @param column
368 	 * @return
369 	 */
370 	public Object getOriginalValueAt(int row, int column)
371 	{
372 	    Map update = (Map) updatedRows.get(new Integer(row));
373 		if (update != null) {
374 		    Object value = update.get(new Integer(column));
375 		    if (value != null)
376 		        return value;
377 		}
378 		
379 		return getValueAt(row, column);
380 	}	
381 
382 	/***
383 	 * Reindex
384 	 * 
385 	 * @param insertedRowIndex
386 	 */
387 	private Map reindex(Map mapToReIndex, int insertedRowIndex) {
388 		Map newHashMap = new HashMap();
389 		for (Iterator it = mapToReIndex.keySet().iterator(); it.hasNext();) {
390 			int oldValue = ((Integer) it.next()).intValue();
391 			if (oldValue >= insertedRowIndex) {
392 				int newValue = oldValue + 1;
393 				newHashMap.put(new Integer(newValue), mapToReIndex
394 						.get(new Integer(oldValue)));
395 			} else {
396 				newHashMap.put(new Integer(oldValue), mapToReIndex
397 						.get(new Integer(oldValue)));
398 			}
399 		}
400 		return newHashMap;
401 
402 	}
403 
404 	/***
405 	 * Overrides TableInterface getCellRenederer. Bases it's decision on what
406 	 * renderer to return by looking at the property type for the Preference
407 	 * in the given row
408 	 * 
409 	 * @param row
410 	 * @param column
411 	 * @return
412 	 */
413 	public TableCellRenderer getCellRenderer(int row, int column) {
414 	    DBEntityColumn col = getDBEntityColumn(column);
415 	    
416 	    if (!isCellEditable(row, column)) {
417 			/*
418 			 * If this is one of the inserted rows, it should display
419 			 * differently
420 			 */
421 			if (deletedRows.get(new Integer(row)) != null) {
422 				return new DeletedValueCellRenderer(col, this);
423 			}
424 
425 			return new NonEditableValueCellRenderer(col, this);
426 		}
427 
428 		/* If this is one of the inserted rows, it should display differently */
429 		if (insertedRows.get(new Integer(row)) != null) {
430 			return new UpdatedValueCellRenderer(col, this);
431 		}
432 
433 		/* If this is one of the updated values then we will also know about it */
434 		Map update = (Map) updatedRows.get(new Integer(row));
435 		if (update != null && update.get(new Integer(column)) != null)
436 			return new UpdatedValueCellRenderer(col, this);
437 
438 		return new DisplayValueCellRenderer(col, this);
439 
440 	}
441 
442 	/***
443      * @param column
444      * @return
445      */
446     public DBEntityColumn getDBEntityColumn(int column)
447     {
448         if (tool != null)
449 		{
450 	        if (tool.getCurrentEntityMetaData() != null)
451 	        {
452 	          entity = tool.getCurrentEntityMetaData().getDbEntity();
453 	        }
454 		}
455         
456 	    DBEntityColumn col = null;
457 	    if (entity != null)
458 	    {
459 	        int modelColumn = convertColumnIndexToModel(column);
460 	        col = entity.getColumn(getColumnName(column));	        
461 	    }
462         return col;
463     }
464 
465     /***
466 	 * @see javax.swing.JTable#getCellEditor(int, int)
467 	 * @param row
468 	 * @param column
469 	 * @return
470 	 */
471 	public TableCellEditor getCellEditor(int row, int column) {
472 		cachedPreChangeValue = getModel().getValueAt(row, column);
473 		DBEntityColumn col = getDBEntityColumn(column);
474 		return new TextBasedTableCellEditor(tool, this, col);
475 	}
476 	
477 	/***
478 	 * This method checks whether or not this table should be dirty or not 
479 	 * and sets and resets the application cookie for accepting commit actions.
480 	 * if it should.
481 	 *
482 	 */
483 	private void checkDirty()
484 	{
485         if (updatedRows.size() > 0 || deletedRows.size() > 0 || insertedRows.size() > 0 )
486             Application.ensureLocalCookie(EXQLConstants.MENU_EXECUTE_CHANGES, 1,tool);
487         else
488             Application.ensureLocalCookie(EXQLConstants.MENU_EXECUTE_CHANGES, 0,tool);
489 	}
490 
491 	/***
492 	 * @return Returns the dirty.
493 	 */
494 	public boolean isDirty() {
495 		return updatedRows.size() > 0 || deletedRows.size() > 0 || insertedRows.size() > 0;
496 	}
497 
498 	/***
499 	 * @return Returns the isEditable.
500 	 */
501 	public boolean isEditable() {
502 		return isEditable;
503 	}
504 	/***
505 	 * @param isEditable
506 	 *            The isEditable to set.
507 	 */
508 	public void setEditable(boolean isEditable) {
509 		this.isEditable = isEditable;
510 	}
511 	
512 	/***
513 	 * Returns a map of the indexes of the deleted rows in the table
514 	 * @return
515 	 */
516     public Map getDeletedRows()
517     {
518         return deletedRows;
519     }
520     
521 	/***
522 	 * Returns a map of the indexes of the inserted rows in the table
523 	 * @return
524 	 */
525     public Map getInsertedRows()
526     {
527         return insertedRows;
528     }
529     
530 	/***
531 	 * Returns a map of the indexes of the changed rows in the table
532 	 * @return
533 	 */
534     public Map getUpdatedRows()
535     {
536         return updatedRows;
537     }
538        
539     /***
540      * Undo the last command executed by the user
541      */
542     public void undo() throws Exception
543     {   
544     }
545 
546     /***
547      * Undo the last n commands executed by the user
548      */
549     public void undo(int numberOfSteps) throws Exception
550     {
551         
552     }
553 
554     /***
555      * Allows redoable edits to be redone
556      * @throws Exception
557      */
558     public void redo() throws Exception
559     {   
560     }
561     
562     /***
563      * Allows Cut to be performed
564      * @throws Exception
565      */
566     public void cut() throws Exception
567     {
568         this.deleteSelectedRows();
569     }
570     
571     /***
572      * Allows sopy to be performed
573      * @throws Exception
574      */
575     public void copy() throws Exception
576     {
577       Transferable t = new RowsTransferable(this);
578       system.setContents(t,this);
579     }
580     
581     public void lostOwnership(Clipboard clipboard, Transferable contents)
582     {
583     }
584     
585     /***
586      * Allows paste to be performed
587      * @throws Exception
588      */
589     public void paste() throws Exception
590     {
591         Transferable data = system.getContents(null);
592         if (data.isDataFlavorSupported(DsProTableDataFlavor.dsproTableDataFlavor()))
593         {
594             pasteInFromTransferableRows(data);
595         }
596         else if (data.isDataFlavorSupported(DataFlavor.stringFlavor))
597         {
598             pasteInFromText(data);
599         }
600         else
601         {
602             JOptionPane.showMessageDialog(this, "Cannot paste: Incompatible clipboard data");
603         }
604     }
605     
606     /***
607      * Uses an existing Transferrable rows object to paste into the database
608      * @param data
609      * @throws IOException 
610      * @throws UnsupportedFlavorException 
611      */
612     private void pasteInFromTransferableRows(Transferable data) throws UnsupportedFlavorException, IOException
613     {
614         RowsTransferable transferable = (RowsTransferable) data.getTransferData(DsProTableDataFlavor.dsproTableDataFlavor());
615         List rows = transferable.getRows();
616         if (this.getColumnCount() != transferable.getColumnCount())
617         {
618             JOptionPane.showMessageDialog(this, "Cannot paste rows as the number of columns does not match");
619             return;
620         }
621         
622         for (int i=0;i<rows.size();i++)
623         {
624             int rowId = insertNewRow();
625             List values = (ArrayList) rows.get(i);
626             for (int t=0;t<values.size();t++)
627             {
628                Object object = values.get(t);
629                DBEntityColumn entityColumn = (DBEntityColumn) transferable.getColumn(t);
630                if (isCellEditable(rowId, t))
631                {
632                  this.setValueAt(object, rowId, t);
633                }
634             }
635         }
636     }
637 
638     /***
639      * Parses out delimited text into rows and columns and pastes it in if possible
640      * @param data
641      * @throws UnsupportedFlavorException
642      * @throws IOException
643      * @throws InvalidDataException
644      */
645     private void pasteInFromText(Transferable data) throws UnsupportedFlavorException, IOException, InvalidDataException {
646         String text = (String) data.getTransferData(DataFlavor.stringFlavor);
647         log.debug(text);
648         StringTokenizer lineTokenizer = new StringTokenizer(text, System.getProperty("line.separator"));
649         while(lineTokenizer.hasMoreTokens())
650         {
651             StringTokenizer fieldTokenizer = new StringTokenizer(lineTokenizer.nextToken(), "\t");
652             int column = 0;
653             int rowId = insertNewRow();
654             int numberOfTokens = fieldTokenizer.countTokens();
655             if ( numberOfTokens != this.getColumnCount())
656             {
657                 JOptionPane.showMessageDialog(this, "Cannot paste rows as the number of columns does not match");
658             }
659             else
660             {
661                 while(fieldTokenizer.hasMoreTokens())
662                 {
663                     if (column < this.getColumnCount())
664                     {
665                         Object value = EditorAndRenderFactory.convertIntoCorrectTypeForColumn(fieldTokenizer.nextToken(),getDBEntityColumn(column) );
666                         if (isCellEditable(rowId, column))
667                         {
668                           this.setValueAt(value, rowId, column);
669                         }
670                         column++;
671                     }
672                     else
673                     {
674                         log.debug(fieldTokenizer.nextToken());
675                     }
676                 }
677             }
678         }
679     }
680     
681     /***
682      * Returns the textComponent associated with this object
683      * @return
684      */
685     public JTextComponent getTextComponent()
686     {
687         return null;
688     }
689     
690     /***
691      * @see com.explosion.expfmodules.texteditor.Editable#clear()
692      */
693     public void clear() throws Exception {
694     }
695 
696     /***
697      * @see com.explosion.expfmodules.texteditor.Editable#select(int, int)
698      */
699     public void select(int startSelection, int endSelection) {
700         this.getSelectionModel().setAnchorSelectionIndex(startSelection);
701         this.getSelectionModel().setLeadSelectionIndex(endSelection);
702     }
703 
704     /***
705      * Pops up a popup menu
706      * @param event
707      */
708     public void popupEvent(MouseEvent event) {
709       try
710       {
711           menu = new ExpPopupableMenu();
712           MenuHelper menuHelper = new MenuHelper(((ExpFrame)Application.getApplicationFrame()).getListener());
713 
714           ExpMenuSegment actionsSegment = menu.createNewSegment(ExpMenuSegment.ANY_POSITION);
715           ExpMenuSegment cutcopy = menu.createNewSegment(ExpMenuSegment.ANY_POSITION);
716           ExpMenuSegment select = menu.createNewSegment(ExpMenuSegment.ANY_POSITION);
717           
718           
719           
720           
721           if (tool.getCurrentEntityMetaData() != null && tool.getCurrentEntityMetaData().getDbEntity() != null && tool.getCurrentEntityMetaData().getDbEntity().getEntityName() != null)
722           {
723             actionsSegment.addElement(menuHelper.createMenuItem("Commit changes", 'e', EXQLConstants.MENU_EXECUTE_CHANGES, null, 1));
724             cutcopy.addElement(menuHelper.createMenuItem("Insert empty row", 'i', EXQLConstants.MENU_INSERT_ROW, null, 1));
725             cutcopy.addElement(menuHelper.createMenuItem("Delete row", 'd', EXQLConstants.MENU_DELETE_ROW, null, 1));
726           }
727 
728           actionsSegment.addElement(menuHelper.createMenuItem("Export results", 'x', EXQLConstants.MENU_EXPORT, null, 1));
729           cutcopy.addElement(menuHelper.createMenuItem("Copy row", 'c', ExpConstants.MENU_COPY, null, 1));
730           cutcopy.addElement(menuHelper.createMenuItem("Paste copied row", 'p', ExpConstants.MENU_PASTE, null, 1));
731           
732           select.addElement(menuHelper.createMenuItem("Select All", 'a', ExpConstants.MENU_SELECTALL, null, 1));
733           
734           if (this.getSelectedRowCount() < 1)
735           {
736              Application.ensureLocalCookie(EXQLConstants.MENU_DELETE_ROW, 0,tool); 
737              Application.ensureLocalCookie(ExpConstants.MENU_COPY, 0,tool);
738           }
739           else
740           {
741               Application.ensureLocalCookie(EXQLConstants.MENU_DELETE_ROW, 1,tool); 
742               Application.ensureLocalCookie(ExpConstants.MENU_COPY, 1,tool);
743           }
744           
745           Transferable data = system.getContents(null);
746           if (data.isDataFlavorSupported(DsProTableDataFlavor.dsproTableDataFlavor()))
747           {
748           	Application.ensureLocalCookie(ExpConstants.MENU_PASTE, 1,tool);
749           }
750           else if (data.isDataFlavorSupported(DataFlavor.stringFlavor))
751           {
752           	Application.ensureLocalCookie(ExpConstants.MENU_PASTE, 1,tool);
753           }
754           else
755           {
756           	Application.ensureLocalCookie(ExpConstants.MENU_PASTE, 0,tool);
757           }
758           
759           /*J2SE1.5 code ready for action one day
760           if (system.isDataFlavorAvailable(DsProTableDataFlavor.dsproTableDataFlavor()))
761           {
762           	Application.ensureLocalCookie(ExpConstants.MENU_PASTE, 1,tool); 
763           }
764           else
765           {
766               Application.ensureLocalCookie(ExpConstants.MENU_PASTE, 0,tool);
767           }
768           */
769           menuHelper.checkEnabled();
770           menu.show(event);
771       }
772       catch (Exception e)
773       {
774           ExceptionManagerFactory.getExceptionManager().manageException(e,"Exception caught while handling popupEvent");
775       }
776     } 
777     
778 }
779 
780 /***
781  * Listens for selection events on this table
782  * 
783  * @author Stephen Created on May 9, 2004
784  */
785 
786 class SelectionListener implements ListSelectionListener {
787 
788 	private DsProTable table;
789 	private EXQLBaseTool tool;
790 
791 	// It is necessary to keep the table since it is not possible
792 	// to determine the table from the event's source
793 	SelectionListener(DsProTable table, EXQLBaseTool tool) {
794 		this.table = table;
795 		this.tool = tool;
796 	}
797 
798 	public void valueChanged(ListSelectionEvent e) {
799 		//Ignore extra messages.
800 		if (e.getValueIsAdjusting())
801 			return;
802 
803 		ListSelectionModel lsm = (ListSelectionModel) e.getSource();
804 		if (!table.isEditable() || lsm.isSelectionEmpty()) {
805 			Application.ensureLocalCookie(EXQLConstants.MENU_DELETE_ROW, 0,
806 					tool);
807 		} else {
808 			Application.ensureLocalCookie(EXQLConstants.MENU_DELETE_ROW, 1,
809 					tool);
810 		}
811 	}
812 
813 }