Author: thomasobrien95
Date: Thu Apr  2 10:05:17 2009
New Revision: 2969

Added:
   trunk/src/ca/sqlpower/architect/swingui/action/CopySelectedAction.java
   trunk/src/ca/sqlpower/architect/swingui/action/CutSelectedAction.java
   trunk/src/ca/sqlpower/architect/swingui/action/PasteSelectedAction.java
Modified:
   trunk/regress/ca/sqlpower/architect/swingui/TestDBTree.java
trunk/regress/ca/sqlpower/architect/swingui/TestingArchitectSwingSessionContext.java
   trunk/src/ca/sqlpower/architect/swingui/ArchitectFrame.java
   trunk/src/ca/sqlpower/architect/swingui/ArchitectSwingSessionContext.java
trunk/src/ca/sqlpower/architect/swingui/ArchitectSwingSessionContextImpl.java
   trunk/src/ca/sqlpower/architect/swingui/DBTree.java
   trunk/src/ca/sqlpower/architect/swingui/PlayPen.java
   trunk/src/ca/sqlpower/architect/swingui/action/messages.properties
   trunk/src/ca/sqlpower/architect/swingui/dbtree/SQLObjectSelection.java

Log:
Copy and cut has now been implemented. Copy and cut are based off
of methods in the DBTree.
Paste has also been implemented for pasting tables into the play pen.
Cutting and copying objects from Architect can be pasted as text which
is separated by newlines per entity name.

Modified: trunk/regress/ca/sqlpower/architect/swingui/TestDBTree.java
==============================================================================
--- trunk/regress/ca/sqlpower/architect/swingui/TestDBTree.java (original)
+++ trunk/regress/ca/sqlpower/architect/swingui/TestDBTree.java Thu Apr 2 10:05:17 2009
@@ -18,18 +18,22 @@
  */
 package ca.sqlpower.architect.swingui;

+import java.io.File;
+import java.sql.Connection;
+import java.sql.Statement;
+import java.util.Set;
+
 import javax.swing.JMenuItem;
 import javax.swing.JPopupMenu;
 import javax.swing.tree.TreePath;

 import junit.framework.TestCase;
-import ca.sqlpower.architect.swingui.ArchitectSwingSession;
-import ca.sqlpower.architect.swingui.DBTree;
 import ca.sqlpower.sql.PlDotIni;
 import ca.sqlpower.sql.SPDataSource;
-import ca.sqlpower.sqlobject.SQLObjectException;
 import ca.sqlpower.sqlobject.SQLCatalog;
 import ca.sqlpower.sqlobject.SQLDatabase;
+import ca.sqlpower.sqlobject.SQLObject;
+import ca.sqlpower.sqlobject.SQLObjectException;
 import ca.sqlpower.sqlobject.SQLSchema;
 import ca.sqlpower.sqlobject.SQLTable;

@@ -176,4 +180,104 @@
                        }
                    }
                }
+       
+       /**
+        * Regression test to confirm a selected table will be added to
+        * the copy selection list.
+        */
+    public void testTableAddedToCopy() throws Exception {
+        PlDotIni plIni = new PlDotIni();
+        plIni.read(new File("pl.regression.ini"));
+        SPDataSource dbcs = plIni.getDataSource("regression_test");
+        Connection con = dbcs.createConnection();
+        Statement stmt = con.createStatement();
+ stmt.execute("CREATE TABLE test1 (col1 varchar(50), col2 varchar(50))");
+        dbTree.addSourceConnection(dbcs);
+
+        //The SQLDatabase representing the SPDataSource
+ SQLDatabase db = (SQLDatabase) dbTree.getModel().getChild(dbTree.getModel().getRoot(), 2);
+        db.populate();
+        SQLObject schema = db.getChildByName("PUBLIC");
+        SQLObject table = schema.getChildByName("TEST1");
+        assertNotNull(table);
+ TreePath path = new TreePath(new Object[]{dbTree.getModel().getRoot(), db, schema, table});
+        dbTree.setSelectionPath(path);
+
+        Set<SQLObject> objectsToCopy = dbTree.findSQLObjectsToCopy();
+        assertEquals(1, objectsToCopy.size());
+        assertTrue(objectsToCopy.contains(table));
+
+    }
+
+    /**
+     * Regression test to confirm 2 selected columns will be added to
+     * the copy selection list even if the table is selected.
+     */
+    public void testColumnsAddedToCopy() throws Exception {
+        PlDotIni plIni = new PlDotIni();
+        plIni.read(new File("pl.regression.ini"));
+        SPDataSource dbcs = plIni.getDataSource("regression_test");
+        Connection con = dbcs.createConnection();
+        Statement stmt = con.createStatement();
+ stmt.execute("CREATE TABLE test2 (col1 varchar(50), col2 varchar(50))");
+        dbTree.addSourceConnection(dbcs);
+
+        //The SQLDatabase representing the SPDataSource
+ SQLDatabase db = (SQLDatabase) dbTree.getModel().getChild(dbTree.getModel().getRoot(), 2);
+        db.populate();
+        SQLObject schema = db.getChildByNameIgnoreCase("PUBLIC");
+ SQLTable table = (SQLTable) schema.getChildByNameIgnoreCase("TEST2");
+        SQLObject col1 = table.getColumnByName("COL1");
+        SQLObject col2 = table.getColumnByName("COL2");
+        assertNotNull(col1);
+        assertNotNull(col2);
+ TreePath tablePath = new TreePath(new Object[]{dbTree.getModel().getRoot(), db, schema, table}); + TreePath path = new TreePath(new Object[]{dbTree.getModel().getRoot(), db, schema, table, table.getColumnsFolder(), col1}); + TreePath path2 = new TreePath(new Object[]{dbTree.getModel().getRoot(), db, schema, table, table.getColumnsFolder(), col2});
+        dbTree.setSelectionPaths(new TreePath[]{path, path2, tablePath});
+
+        Set<SQLObject> objectsToCopy = dbTree.findSQLObjectsToCopy();
+        assertEquals(2, objectsToCopy.size());
+        assertTrue(objectsToCopy.contains(col1));
+        assertTrue(objectsToCopy.contains(col2));
+
+    }
+
+    /**
+     * This test selects two columns out of one table and another
+     * table that is not the column's parent table. The end result
+     * expected is to have both tables but not the columns to be
+     * added to the copy list.
+     */
+    public void testCopyTablesWithColumnsSelected() throws Exception {
+        PlDotIni plIni = new PlDotIni();
+        plIni.read(new File("pl.regression.ini"));
+        SPDataSource dbcs = plIni.getDataSource("regression_test");
+        Connection con = dbcs.createConnection();
+        Statement stmt = con.createStatement();
+ stmt.execute("CREATE TABLE test3 (col1 varchar(50), col2 varchar(50))"); + stmt.execute("CREATE TABLE test4 (col1 varchar(50), col2 varchar(50))");
+        dbTree.addSourceConnection(dbcs);
+
+        //The SQLDatabase representing the SPDataSource
+ SQLDatabase db = (SQLDatabase) dbTree.getModel().getChild(dbTree.getModel().getRoot(), 2);
+        db.populate();
+        SQLObject schema = db.getChildByNameIgnoreCase("PUBLIC");
+ SQLTable table = (SQLTable) schema.getChildByNameIgnoreCase("TEST3");
+        SQLObject col1 = table.getColumnByName("COL1");
+        SQLObject col2 = table.getColumnByName("COL2");
+        SQLObject table2 = schema.getChildByNameIgnoreCase("test4");
+        assertNotNull(col1);
+        assertNotNull(col2);
+ TreePath tablePath = new TreePath(new Object[]{dbTree.getModel().getRoot(), db, schema, table2}); + TreePath path = new TreePath(new Object[]{dbTree.getModel().getRoot(), db, schema, table, table.getColumnsFolder(), col1}); + TreePath path2 = new TreePath(new Object[]{dbTree.getModel().getRoot(), db, schema, table, table.getColumnsFolder(), col2});
+        dbTree.setSelectionPaths(new TreePath[]{path, path2, tablePath});
+
+        Set<SQLObject> objectsToCopy = dbTree.findSQLObjectsToCopy();
+        assertEquals(2, objectsToCopy.size());
+        assertTrue(objectsToCopy.contains(table));
+        assertTrue(objectsToCopy.contains(table2));
+
+    }
 }

Modified: trunk/regress/ca/sqlpower/architect/swingui/TestingArchitectSwingSessionContext.java
==============================================================================
--- trunk/regress/ca/sqlpower/architect/swingui/TestingArchitectSwingSessionContext.java (original) +++ trunk/regress/ca/sqlpower/architect/swingui/TestingArchitectSwingSessionContext.java Thu Apr 2 10:05:17 2009
@@ -19,6 +19,7 @@
 package ca.sqlpower.architect.swingui;

 import java.awt.Window;
+import java.awt.datatransfer.Transferable;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -183,5 +184,13 @@
         }
         this.plDotIniPath = plDotIniPath;
         this.plDotIni = null;
+    }
+
+    public Transferable getClipboardContents() {
+ throw new IllegalStateException("Getting clipboard contents not currently implemented.");
+    }
+
+    public void setClipboardContents(Transferable t) {
+ throw new IllegalStateException("Setting clipboard contents not currently implemented.");
     }
 }

Modified: trunk/src/ca/sqlpower/architect/swingui/ArchitectFrame.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/ArchitectFrame.java (original)
+++ trunk/src/ca/sqlpower/architect/swingui/ArchitectFrame.java Thu Apr 2 10:05:17 2009
@@ -73,8 +73,10 @@
 import ca.sqlpower.architect.swingui.action.CheckForUpdateAction;
 import ca.sqlpower.architect.swingui.action.CloseProjectAction;
 import ca.sqlpower.architect.swingui.action.CompareDMAction;
+import ca.sqlpower.architect.swingui.action.CopySelectedAction;
 import ca.sqlpower.architect.swingui.action.CreateRelationshipAction;
 import ca.sqlpower.architect.swingui.action.CreateTableAction;
+import ca.sqlpower.architect.swingui.action.CutSelectedAction;
 import ca.sqlpower.architect.swingui.action.DataMoverAction;
 import ca.sqlpower.architect.swingui.action.DataSourcePropertiesAction;
import ca.sqlpower.architect.swingui.action.DatabaseConnectionManagerAction;
@@ -94,6 +96,7 @@
 import ca.sqlpower.architect.swingui.action.InsertIndexAction;
 import ca.sqlpower.architect.swingui.action.KettleJobAction;
 import ca.sqlpower.architect.swingui.action.OpenProjectAction;
+import ca.sqlpower.architect.swingui.action.PasteSelectedAction;
 import ca.sqlpower.architect.swingui.action.PreferencesAction;
 import ca.sqlpower.architect.swingui.action.PrintAction;
 import ca.sqlpower.architect.swingui.action.ProfileAction;
@@ -195,6 +198,9 @@
     private Action compareDMAction;
     private Action dataMoverAction;
     private Action sqlQueryAction;
+    private CopySelectedAction copyAction;
+    private CutSelectedAction cutAction;
+    private PasteSelectedAction pasteAction;

     /**
      * Closes all sessions and terminates the JVM.
@@ -205,8 +211,6 @@
         }
     };

-
-
     /**
      * This constructor is used by the session implementation. To obtain an
      * Architect Frame, you have to create an
@@ -424,6 +428,9 @@
focusToParentAction = new FocusToChildOrParentTableAction(session, Messages.getString("ArchitectFrame.setFocusToParentTableActionName"), Messages.getString("ArchitectFrame.setFocusToParentTableActionDescription"), true); //$NON-NLS-1$ //$NON-NLS-2$ focusToChildAction = new FocusToChildOrParentTableAction(session, Messages.getString("ArchitectFrame.setFocusToChildTableActionName"), Messages.getString("ArchitectFrame.setFocusToChildTableActionDescription"), false); //$NON-NLS-1$ //$NON-NLS-2$

+        copyAction = new CopySelectedAction(session);
+        cutAction = new CutSelectedAction(session);
+        pasteAction = new PasteSelectedAction(session);

         menuBar = createNewMenuBar();
         setJMenuBar(menuBar);
@@ -532,6 +539,10 @@

JMenu editMenu = new JMenu(Messages.getString("ArchitectFrame.editMenu")); //$NON-NLS-1$
         editMenu.setMnemonic('e');
+        editMenu.add(cutAction);
+        editMenu.add(copyAction);
+        editMenu.add(pasteAction);
+        editMenu.addSeparator();
         editMenu.add(undoAction);
         editMenu.add(redoAction);
         editMenu.addSeparator();

Modified: trunk/src/ca/sqlpower/architect/swingui/ArchitectSwingSessionContext.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/ArchitectSwingSessionContext.java (original) +++ trunk/src/ca/sqlpower/architect/swingui/ArchitectSwingSessionContext.java Thu Apr 2 10:05:17 2009
@@ -19,6 +19,7 @@
 package ca.sqlpower.architect.swingui;

 import java.awt.Window;
+import java.awt.datatransfer.Transferable;
 import java.io.IOException;
 import java.io.InputStream;

@@ -145,4 +146,16 @@
      * Gets the user settings for this session
      */
     public abstract CoreUserSettings getUserSettings();
+
+    /**
+     * This gets either the clipboard internal to the context or the
+     * system's clipboard depending on the information contained by each.
+     */
+    public Transferable getClipboardContents();
+
+    /**
+     * This sets either the clipboard internal to the context or the
+     * system's clipboard depending on the information contained by each.
+     */
+    public void setClipboardContents(Transferable t);
 }

Modified: trunk/src/ca/sqlpower/architect/swingui/ArchitectSwingSessionContextImpl.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/ArchitectSwingSessionContextImpl.java (original) +++ trunk/src/ca/sqlpower/architect/swingui/ArchitectSwingSessionContextImpl.java Thu Apr 2 10:05:17 2009
@@ -19,7 +19,11 @@
 package ca.sqlpower.architect.swingui;

 import java.awt.Component;
+import java.awt.Toolkit;
 import java.awt.Window;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.ClipboardOwner;
+import java.awt.datatransfer.Transferable;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
@@ -36,6 +40,7 @@
 import ca.sqlpower.architect.ArchitectSessionContext;
 import ca.sqlpower.architect.ArchitectSessionContextImpl;
 import ca.sqlpower.architect.CoreUserSettings;
+import ca.sqlpower.architect.swingui.dbtree.SQLObjectSelection;
 import ca.sqlpower.sql.DataSourceCollection;
 import ca.sqlpower.sql.SPDataSource;
 import ca.sqlpower.sqlobject.SQLObjectException;
@@ -54,7 +59,7 @@
* It may one day be desirable for this to be an interface, but there didn't seem
  * to be a need for it when we first created this class.
  */
-public class ArchitectSwingSessionContextImpl implements ArchitectSwingSessionContext { +public class ArchitectSwingSessionContextImpl implements ArchitectSwingSessionContext, ClipboardOwner {

private static final Logger logger = Logger.getLogger(ArchitectSwingSessionContextImpl.class);

@@ -82,6 +87,13 @@
     private final PreferencesEditor prefsEditor;

     /**
+     * This internal clipboard allows copying and pasting objects within
+     * the app to stay as objects. The system clipboard throws modification
+     * exceptions when it is used with SQLObjects.
+     */
+ private final Clipboard clipboard = new Clipboard("Internal clipboard");
+
+    /**
* This factory just passes the request through to the {...@link ASUtils#showDbcsDialog(Window, SPDataSource, Runnable)}
      * method.
      */
@@ -339,5 +351,27 @@

     public void setPlDotIniPath(String plDotIniPath) {
         delegateContext.setPlDotIniPath(plDotIniPath);
+    }
+
+    public Transferable getClipboardContents() {
+        if (clipboard.getContents(null) != null) {
+            return clipboard.getContents(null);
+        }
+ return Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
+    }
+
+    public void setClipboardContents(Transferable t) {
+        clipboard.setContents(t, this);
+        if (t instanceof SQLObjectSelection) {
+            ((SQLObjectSelection) t).setLocal(false);
+        }
+ Toolkit.getDefaultToolkit().getSystemClipboard().setContents(t, this);
+        if (t instanceof SQLObjectSelection) {
+            ((SQLObjectSelection) t).setLocal(true);
+        }
+    }
+
+    public void lostOwnership(Clipboard clipboard, Transferable contents) {
+        clipboard.setContents(null, this);
     }
 }

Modified: trunk/src/ca/sqlpower/architect/swingui/DBTree.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/DBTree.java (original)
+++ trunk/src/ca/sqlpower/architect/swingui/DBTree.java Thu Apr 2 10:05:17 2009
@@ -19,6 +19,7 @@
 package ca.sqlpower.architect.swingui;

 import java.awt.Cursor;
+import java.awt.datatransfer.Transferable;
 import java.awt.dnd.DnDConstants;
 import java.awt.dnd.DragGestureEvent;
 import java.awt.dnd.DragGestureListener;
@@ -35,8 +36,13 @@
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;

 import javax.swing.AbstractAction;
 import javax.swing.Action;
@@ -64,13 +70,14 @@
 import ca.sqlpower.architect.swingui.dbtree.DBTreeModel;
 import ca.sqlpower.architect.swingui.dbtree.SQLObjectSelection;
 import ca.sqlpower.sql.SPDataSource;
-import ca.sqlpower.sqlobject.SQLObjectException;
-import ca.sqlpower.sqlobject.SQLObjectRuntimeException;
 import ca.sqlpower.sqlobject.SQLCatalog;
 import ca.sqlpower.sqlobject.SQLColumn;
 import ca.sqlpower.sqlobject.SQLDatabase;
 import ca.sqlpower.sqlobject.SQLIndex;
 import ca.sqlpower.sqlobject.SQLObject;
+import ca.sqlpower.sqlobject.SQLObjectException;
+import ca.sqlpower.sqlobject.SQLObjectRuntimeException;
+import ca.sqlpower.sqlobject.SQLObjectUtils;
 import ca.sqlpower.sqlobject.SQLRelationship;
 import ca.sqlpower.sqlobject.SQLSchema;
 import ca.sqlpower.sqlobject.SQLTable;
@@ -110,8 +117,7 @@
      */
        private static final Object KEY_DELETE_SELECTED
= "ca.sqlpower.architect.swingui.DBTree.KEY_DELETE_SELECTED"; //$NON-NLS-1$
-
-
+       
        // ----------- CONSTRUCTORS ------------

public DBTree(final ArchitectSwingSession session) throws SQLObjectException {
@@ -159,6 +165,18 @@
                 //no-op
             }
         });
+
+        getActionMap().put("copy", new AbstractAction() {
+            public void actionPerformed(ActionEvent e) {
+                copySelection();
+            }
+        });
+
+        getActionMap().put("cut", new AbstractAction() {
+            public void actionPerformed(ActionEvent e) {
+                cutSelection();
+            }
+        });
        }

        // ----------- INSTANCE METHODS ------------
@@ -812,44 +830,20 @@
                        }
                        
                        DBTree t = (DBTree) dge.getComponent();
-                       TreePath[] p = t.getSelectionPaths();
-                       if (p ==  null || p.length == 0) {
-                               // nothing to export
-                               return;
-                       } else {
-                               // export list of DnD-type tree paths
-                           StringBuilder userVisibleName = new StringBuilder();
-                           List<SQLObject> transferObjects = new 
ArrayList<SQLObject>();
-                               for (int i = 0; i < p.length; i++) {
-                                       // ignore any playpen tables
-                                   SQLObject so = (SQLObject) 
p[i].getLastPathComponent();
-                                   boolean transferObject = true;
-                                   SQLObject parent = so.getParent();
-                                   while(parent != null) {
- if (parent instanceof SQLDatabase && ((SQLDatabase) parent).isPlayPenDatabase()) {
-                                           transferObject = false;
-                                           break;
-                                       }
-                                       parent = parent.getParent();
-                                   }
-                    if (transferObject) {
-                        transferObjects.add(so);
-                        if (userVisibleName.length() != 0) {
-                            userVisibleName.append("\n");
-                        }
-                        userVisibleName.append(so.getName());
-                    }
-                               }
- logger.info("DBTree: exporting list of DnD-type tree paths"); //$NON-NLS-1$
+                       final Set<SQLObject> sqlObjectsToCopy = 
t.findSQLObjectsToCopy();
+                       if (!sqlObjectsToCopy.isEmpty()) {
+ Transferable transferObject = new SQLObjectSelection(sqlObjectsToCopy);
+                           if (transferObject != null) {
+                               // TODO add undo event
+                               dge.getDragSource().startDrag
+                                       (dge,
+                                       null, //DragSource.DefaultCopyNoDrop,
+                                       transferObject,
+                                       t);
+                           }
+                       }
+               }

-                               // TODO add undo event
-                               dge.getDragSource().startDrag
-                                       (dge,
-                                        null, //DragSource.DefaultCopyNoDrop,
-                                        new 
SQLObjectSelection(transferObjects),
-                                        t);
-                       }
-               }
        }
        
        public void setupKeyboardActions() {
@@ -872,10 +866,139 @@
         });
     }
        
+       /**
+ * Creates a list of SQLObjects to decide which of the selected object(s)
+     * in the tree are to be copied or dragged to a different location.
+     * An empty set will be returned if the transferable cannot be created.
+     * <p>
+     * This is package private for testing purposes.
+     */
+    Set<SQLObject> findSQLObjectsToCopy() {
+        TreePath[] p = this.getSelectionPaths();
+        Set<SQLObject> objectsToTransfer = new HashSet<SQLObject>();
+        if (p ==  null || p.length == 0) {
+            // nothing to export
+            return new HashSet<SQLObject>();
+        } else {
+
+            //If there are multiple selections, then transfer the objects
+            //that are of the same type. To choose what type to move look
+            //at the ancestors of each component to decide if (a) items
+            //selected are parents of other components and (b) where is the
+ //highest point in the tree path that multiple objects of the same
+            //type are selected.
+ Map<Integer, List<SQLObject>> pathLengthsToSelectedObjectsMap = new HashMap<Integer, List<SQLObject>>();
+            for (int i = 0; i < p.length; i++) {
+ if (pathLengthsToSelectedObjectsMap.get(p[i].getPathCount()) == null) { + pathLengthsToSelectedObjectsMap.put(p[i].getPathCount(), new ArrayList<SQLObject>());
+                }
+ pathLengthsToSelectedObjectsMap.get(p[i].getPathCount()).add((SQLObject) p[i].getLastPathComponent());
+            }
+
+ List<Integer> sortedLengths = new ArrayList<Integer>(pathLengthsToSelectedObjectsMap.keySet());
+            Collections.sort(sortedLengths);
+
+            for (int i = 0; i < sortedLengths.size(); i++) {
+                Integer pathCount = sortedLengths.get(i);
+ //get the length of each tree path to see if there are multiples
+                //at the lowest length
+ if (pathLengthsToSelectedObjectsMap.get(pathCount).size()
1) {
+ objectsToTransfer.addAll(pathLengthsToSelectedObjectsMap.get(pathCount));
+
+                    for (int j = i + 1; j < sortedLengths.size(); j++) {
+ for (SQLObject childObject : pathLengthsToSelectedObjectsMap.get(sortedLengths.get(j))) {
+                            SQLObject parent = childObject;
+ for (int k = 0; k < sortedLengths.get(j) - pathCount; k++) {
+                                parent = parent.getParent();
+                            }
+                            objectsToTransfer.add(parent);
+                        }
+                    }
+                    break;
+                } else {
+ //if there is only one at the lowest length we need to see if it
+                    //is the parent of the rest of the elements
+ SQLObject singleParent = pathLengthsToSelectedObjectsMap.get(pathCount).get(0);
+                    boolean isParentOfAllSelected = true;
+                    for (int j = i + 1; j < sortedLengths.size(); j++) {
+ for (SQLObject childObject : pathLengthsToSelectedObjectsMap.get(sortedLengths.get(j))) {
+                            SQLObject parent = childObject;
+ for (int k = 0; k < sortedLengths.get(j) - pathCount; k++) {
+                                parent = parent.getParent();
+                            }
+                            if (parent != singleParent) {
+                                isParentOfAllSelected = false;
+                                break;
+                            }
+                        }
+                        if (!isParentOfAllSelected) {
+                            break;
+                        }
+                    }
+ //if it is not the parent then that is the depth we will copy and need to find the parent
+                    //of all other selections
+                    if (!isParentOfAllSelected) {
+ objectsToTransfer.addAll(pathLengthsToSelectedObjectsMap.get(pathCount));
+
+ for (int j = i + 1; j < sortedLengths.size(); j++) { + for (SQLObject childObject : pathLengthsToSelectedObjectsMap.get(sortedLengths.get(j))) {
+                                SQLObject parent = childObject;
+ for (int k = 0; k < sortedLengths.get(j) - pathCount; k++) {
+                                    parent = parent.getParent();
+                                }
+                                objectsToTransfer.add(parent);
+                            }
+                        }
+                        break;
+                    }
+                }
+ //if it is the parent of the rest then we only need to copy selections that are lower + //but if it is the lowest component in the selections then the elements at this level
+                //should be selected.
+                if (i + 1 == sortedLengths.size()) {
+ objectsToTransfer.addAll(pathLengthsToSelectedObjectsMap.get(pathCount));
+                }
+
+            }
+
+ logger.info("DBTree: exporting list of DnD-type tree paths"); //$NON-NLS-1$
+
+        }
+        return objectsToTransfer;
+    }
+       
+       /**
+        * This will copy the selection of the DBTree to the system's clipboard
+        * via a Transferable.
+        */
+       public void copySelection() {
+ Transferable transferObject = new SQLObjectSelection(findSQLObjectsToCopy());
+           if (transferObject != null) {
+               session.getContext().setClipboardContents(transferObject);
+           }
+       }
+       
+       /**
+     * This will cut the selection of the DBTree to the system's clipboard
+     * via a Transferable.
+     */
+       public void cutSelection() {
+          final Set<SQLObject> copyObjects = findSQLObjectsToCopy();
+          Transferable transferObject = new SQLObjectSelection(copyObjects);
+       if (transferObject != null) {
+           session.getContext().setClipboardContents(transferObject);
+       }
+       for (SQLObject o : copyObjects) {
+           SQLDatabase target = session.getTargetDatabase();
+ if (SQLObjectUtils.ancestorList(o).contains(target) && !(o instanceof SQLTable.Folder)) {
+               o.getParent().removeChild(o);
+           }
+       }
+       }
+       

        /**
* Removes all selections of objects that are not represented on the playpen.
-        *
         */
     public void clearNonPlayPenSelections() {
         if (getSelectionPaths() == null) return;

Modified: trunk/src/ca/sqlpower/architect/swingui/PlayPen.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/PlayPen.java        (original)
+++ trunk/src/ca/sqlpower/architect/swingui/PlayPen.java Thu Apr 2 10:05:17 2009
@@ -121,14 +121,14 @@
 import ca.sqlpower.sql.SPDataSource;
 import ca.sqlpower.sql.jdbcwrapper.DatabaseMetaDataDecorator;
 import ca.sqlpower.sql.jdbcwrapper.DatabaseMetaDataDecorator.CacheType;
-import ca.sqlpower.sqlobject.SQLObjectException;
-import ca.sqlpower.sqlobject.SQLObjectRuntimeException;
 import ca.sqlpower.sqlobject.SQLCatalog;
 import ca.sqlpower.sqlobject.SQLColumn;
 import ca.sqlpower.sqlobject.SQLDatabase;
 import ca.sqlpower.sqlobject.SQLObject;
 import ca.sqlpower.sqlobject.SQLObjectEvent;
+import ca.sqlpower.sqlobject.SQLObjectException;
 import ca.sqlpower.sqlobject.SQLObjectListener;
+import ca.sqlpower.sqlobject.SQLObjectRuntimeException;
 import ca.sqlpower.sqlobject.SQLObjectUtils;
 import ca.sqlpower.sqlobject.SQLRelationship;
 import ca.sqlpower.sqlobject.SQLSchema;
@@ -472,6 +472,7 @@
      * stop using it.
      */
     public void destroy() {
+ logger.debug("Destroying playpen " + System.identityHashCode(this)); // FIXME the content pane must be notified of this destruction, either explicitly or via a lifecycle event
         firePlayPenLifecycleEvent();
         try {
@@ -1288,6 +1289,14 @@
         */
public synchronized TablePane importTableCopy(SQLTable source, Point preferredLocation) throws SQLObjectException { SQLTable newTable = SQLTable.getDerivedInstance(source, session.getTargetDatabase()); // adds newTable to db
+               
+               //If the root source is in the play pen it's not really a 
source for ETL.
+               for (SQLColumn col : newTable.getColumns()) {
+ if (col.getSourceColumn() != null && getTables().contains(col.getSourceColumn().getParentTable())) {
+                       col.setSourceColumn(null);
+                   }
+               }
+               
                String key = source.getName().toLowerCase();
                boolean isAlreadyOnPlaypen = false;
                int newSuffix = 0;
@@ -1451,7 +1460,7 @@
        /**
* Calls {...@link #importTableCopy} for each table contained in the given schema.
         */
- public synchronized void addObjects(List list, Point preferredLocation, SPSwingWorker nextProcess) throws SQLObjectException { + public synchronized void addObjects(List<SQLObject> list, Point preferredLocation, SPSwingWorker nextProcess) throws SQLObjectException {
                ProgressMonitor pm
                 = new ProgressMonitor(this,
Messages.getString("PlayPen.copyingObjectsToThePlaypen"), //$NON-NLS-1$
@@ -2055,42 +2064,27 @@

                        Transferable t = dtde.getTransferable();
                        PlayPen playpen = (PlayPen) 
dtde.getDropTargetContext().getComponent();
- DataFlavor importFlavor = bestImportFlavor(playpen, t.getTransferDataFlavors());
-                       if (importFlavor == null) {
-                               dtde.rejectDrop();
-                       } else {
-                               try {
-
-                                       
dtde.acceptDrop(DnDConstants.ACTION_COPY);
-                                       Point dropLoc = playpen.unzoomPoint(new 
Point(dtde.getLocation()));
-                                       Object[] paths = (Object[]) 
t.getTransferData(importFlavor);
-                                       // turn into a Collection of SQLObjects 
to make this more generic
-                                       List<SQLObject> sqlObjects = new 
ArrayList<SQLObject>();
-                                       for (Object oo : paths) {
-                                               if (oo instanceof SQLObject) {
-                                                       
sqlObjects.add((SQLObject) oo);
-                                               } else {
- logger.error("Unknown object dropped in PlayPen: "+oo); //$NON-NLS-1$
-                                               }
-                                       }
-
-                                       // null: no next task is chained off 
this
-                                       playpen.addObjects(sqlObjects, dropLoc, 
null);
-                                       dtde.dropComplete(true);
-
-                               } catch (UnsupportedFlavorException ufe) {
-                                       logger.error(ufe);
-                                       dtde.rejectDrop();
-                               } catch (IOException ioe) {
-                                       logger.error(ioe);
-                                       dtde.rejectDrop();
-                               } catch (InvalidDnDOperationException ex) {
-                                       logger.error(ex);
-                                       dtde.rejectDrop();
-                               } catch (SQLObjectException ex) {
-                                       logger.error(ex);
-                                       dtde.rejectDrop();
-                               }
+                       try {
+                           Point dropLoc = playpen.unzoomPoint(new 
Point(dtde.getLocation()));
+                           if (playpen.addTransferable(t, dropLoc)){
+                               dtde.acceptDrop(DnDConstants.ACTION_COPY);
+                               dtde.dropComplete(true);
+                           } else {
+                               dtde.rejectDrop();
+                           }
+
+                       } catch (UnsupportedFlavorException ufe) {
+                           logger.error(ufe);
+                           dtde.rejectDrop();
+                       } catch (IOException ioe) {
+                           logger.error(ioe);
+                           dtde.rejectDrop();
+                       } catch (InvalidDnDOperationException ex) {
+                           logger.error(ex);
+                           dtde.rejectDrop();
+                       } catch (SQLObjectException ex) {
+                           logger.error(ex);
+                           dtde.rejectDrop();
                        }
                }

@@ -2148,6 +2142,72 @@
                }
        }

+    /**
+ * This method takes a transferable object and tries to add the SQLObjects + * in the transferable to the play pen. If there is no transferable object + * then if there is a string or list of strings in the transferable this
+     * method will try to create SQLObjects for the transferred values.
+     *
+     * @param t
+ * The transferable to get objects from to add to the playpen
+     * @param dropPoint
+ * The location where new objects will be added to the playpen + * @return True if objects were added successfully to the playpen. False
+     *         otherwise.
+     * @throws IOException
+     * @throws UnsupportedFlavorException
+     * @throws SQLObjectException
+     */
+ private boolean addTransferable(Transferable t, Point dropPoint) throws UnsupportedFlavorException, IOException, SQLObjectException { + if (t.isDataFlavorSupported(SQLObjectSelection.LOCAL_SQLOBJECT_ARRAY_FLAVOUR)) { + SQLObject[] paths = (SQLObject[]) t.getTransferData(SQLObjectSelection.LOCAL_SQLOBJECT_ARRAY_FLAVOUR); + // turn into a Collection of SQLObjects to make this more generic
+            List<SQLObject> sqlObjects = new ArrayList<SQLObject>();
+            for (Object oo : paths) {
+                if (oo instanceof SQLObject) {
+                    sqlObjects.add((SQLObject) oo);
+                } else {
+ logger.error("Unknown object dropped in PlayPen: "+oo); //$NON-NLS-1$
+                }
+            }
+
+            // null: no next task is chained off this
+            addObjects(sqlObjects, dropPoint, null);
+               return true;
+           } else {
+               return false;
+           }
+       }
+       
+       /**
+ * This method takes a transferable object and tries to add the SQLObjects + * in the transferable to the play pen. If there is no transferable object + * then if there is a string or list of strings in the transferable this
+     * method will try to create SQLObjects for the transferred values. The
+ * objects will be placed at the mouse location if it is on the play pen
+     * or at the origin if it is not.
+     *
+     * @param t
+ * The transferable to get objects from to add to the playpen
+     */
+       public void addTransferable(Transferable t) {
+           Point p = getMousePosition();
+           if (p == null) {
+               p = new Point(0, 0);
+           }
+           try {
+            if (!addTransferable(t, p)) {
+ JOptionPane.showMessageDialog(this, "Cannot paste the copied objects. Unknown object type.", "Cannot Paste Objects", JOptionPane.WARNING_MESSAGE);
+            }
+        } catch (UnsupportedFlavorException e) {
+ throw new RuntimeException("Could not paste copied object type.", e);
+        } catch (IOException e) {
+            logger.error("The real IOException", e);
+ throw new RuntimeException("Data copied changed while pasting.", e);
+        } catch (SQLObjectException e) {
+ throw new RuntimeException("Exception while pasting a SQLObject.", e);
+        }
+       }

        public class TablePaneDragGestureListener implements 
DragGestureListener {
                public void dragGestureRecognized(DragGestureEvent dge) {

Added: trunk/src/ca/sqlpower/architect/swingui/action/CopySelectedAction.java
==============================================================================
--- (empty file)
+++ trunk/src/ca/sqlpower/architect/swingui/action/CopySelectedAction.java Thu Apr 2 10:05:17 2009
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2009, SQL Power Group Inc.
+ *
+ * This file is part of Power*Architect.
+ *
+ * Power*Architect is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Power*Architect is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package ca.sqlpower.architect.swingui.action;
+
+import java.awt.Component;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.KeyStroke;
+
+import org.apache.log4j.Logger;
+
+import ca.sqlpower.architect.swingui.ArchitectSwingSession;
+import ca.sqlpower.architect.swingui.DBTree;
+
+public class CopySelectedAction extends AbstractArchitectAction {
+ private static final Logger logger = Logger.getLogger(CopySelectedAction.class);
+
+    public CopySelectedAction(ArchitectSwingSession session) {
+ super(session, Messages.getString("CopySelectedAction.name"), Messages.getString("CopySelectedAction.description"));
+        putValue(AbstractAction.ACCELERATOR_KEY,
+ KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        final DBTree dbTree = session.getArchitectFrame().getDbTree();
+ final Component focusOwner = session.getArchitectFrame().getFocusOwner();
+        logger.debug("Copy action invoked. Focus owner is " + focusOwner);
+        if (session.getArchitectFrame().isAncestorOf(focusOwner)) {
+            dbTree.copySelection();
+        }
+    }
+
+}

Added: trunk/src/ca/sqlpower/architect/swingui/action/CutSelectedAction.java
==============================================================================
--- (empty file)
+++ trunk/src/ca/sqlpower/architect/swingui/action/CutSelectedAction.java Thu Apr 2 10:05:17 2009
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2009, SQL Power Group Inc.
+ *
+ * This file is part of Power*Architect.
+ *
+ * Power*Architect is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Power*Architect is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package ca.sqlpower.architect.swingui.action;
+
+import java.awt.Component;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.KeyStroke;
+
+import ca.sqlpower.architect.swingui.ArchitectSwingSession;
+import ca.sqlpower.architect.swingui.DBTree;
+
+public class CutSelectedAction extends AbstractArchitectAction {
+
+    public CutSelectedAction(ArchitectSwingSession session) {
+ super(session, Messages.getString("CutSelectedAction.name"), Messages.getString("CutSelectedAction.description"));
+        putValue(AbstractAction.ACCELERATOR_KEY,
+ KeyStroke.getKeyStroke(KeyEvent.VK_X, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        final DBTree dbTree = session.getArchitectFrame().getDbTree();
+ final Component focusOwner = session.getArchitectFrame().getFocusOwner();
+        if (session.getArchitectFrame().isAncestorOf(focusOwner)) {
+            dbTree.cutSelection();
+        }
+    }
+
+}

Added: trunk/src/ca/sqlpower/architect/swingui/action/PasteSelectedAction.java
==============================================================================
--- (empty file)
+++ trunk/src/ca/sqlpower/architect/swingui/action/PasteSelectedAction.java Thu Apr 2 10:05:17 2009
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2009, SQL Power Group Inc.
+ *
+ * This file is part of Power*Architect.
+ *
+ * Power*Architect is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Power*Architect is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package ca.sqlpower.architect.swingui.action;
+
+import java.awt.Component;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.ActionEvent;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JOptionPane;
+import javax.swing.KeyStroke;
+
+import org.apache.log4j.Logger;
+
+import ca.sqlpower.architect.swingui.ArchitectSwingSession;
+import ca.sqlpower.architect.swingui.PlayPen;
+import ca.sqlpower.swingui.event.SessionLifecycleEvent;
+import ca.sqlpower.swingui.event.SessionLifecycleListener;
+
+public class PasteSelectedAction extends AbstractArchitectAction {
+ private static final Logger logger = Logger.getLogger(PasteSelectedAction.class);
+
+    public PasteSelectedAction(final ArchitectSwingSession session) {
+ super(session, Messages.getString("PasteSelectedAction.name"), Messages.getString("PasteSelectedAction.description"));
+        putValue(AbstractAction.ACCELERATOR_KEY,
+ KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
+        final FocusListener focusListener = new FocusListener() {
+
+            public void focusLost(FocusEvent e) {
+                PasteSelectedAction.this.setEnabled(false);
+            }
+
+            public void focusGained(FocusEvent e) {
+                PasteSelectedAction.this.setEnabled(true);
+            }
+        };
+        session.getPlayPen().addFocusListener(focusListener);
+
+ final SessionLifecycleListener<ArchitectSwingSession> lifecycleListener = new SessionLifecycleListener<ArchitectSwingSession>() {
+
+ public void sessionClosing(SessionLifecycleEvent<ArchitectSwingSession> e) {
+                session.getPlayPen().removeFocusListener(focusListener);
+                session.removeSessionLifecycleListener(this);
+            }
+        };
+        session.addSessionLifecycleListener(lifecycleListener);
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        PlayPen playPen = session.getPlayPen();
+ final Component focusOwner = session.getArchitectFrame().getFocusOwner();
+        if (playPen.isAncestorOf(focusOwner) || playPen == focusOwner) {
+ Transferable clipboardContents = session.getContext().getClipboardContents(); + logger.debug("Pasting " + clipboardContents + " into the playpen.");
+            if (clipboardContents != null) {
+                playPen.addTransferable(clipboardContents);
+            } else {
+ JOptionPane.showMessageDialog(session.getArchitectFrame(), "There is no contents in the clipboard to paste.", "Clipboard empty", JOptionPane.INFORMATION_MESSAGE);
+            }
+        }
+    }
+
+}

Modified: trunk/src/ca/sqlpower/architect/swingui/action/messages.properties
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/action/messages.properties (original) +++ trunk/src/ca/sqlpower/architect/swingui/action/messages.properties Thu Apr 2 10:05:17 2009
@@ -18,6 +18,8 @@
 CloseProjectAction.name=Close Project
 CompareDMAction.description=Compare Data Models
 CompareDMAction.name=Compare DM...
+CopySelectedAction.name=Copy
+CopySelectedAction.description=Copy selected objects
CreateRelationshipAction.couldNotCreateRelationship=Couldn't create relationship. CreateRelationshipAction.createIdentifyingRelationshipActionDescription=New Identifying Relationship CreateRelationshipAction.createIdentifyingRelationshipActionName=New Identifying Relationship
@@ -27,6 +29,8 @@
 CreateTableAction.description=New Table (Shortcut T)
 CreateTableAction.name=New Table...
 CreateTableAction.tablePropertiesDialogTitle=Table Properties
+CutSelectedAction.name=Cut
+CutSelectedAction.description=Cut selected objects
 DatabaseConnectionManagerAction.description=Database Connection Manager
 DatabaseConnectionManagerAction.name=Database Connection Manager...
 DataMoverAction.couldNotStartDataMover=Couldn't start Data Mover
@@ -149,6 +153,8 @@
 OpenProjectAction.failedToOpenProjectFile=Failed to open project file
 OpenProjectAction.name=Open Project...
 OpenProjectAction.reading=Reading:
+PasteSelectedAction.name=Paste
+PasteSelectedAction.description=Paste values from clipboard
 PreferencesAction.description=User Preferences
 PreferencesAction.name=User Preferences...
 PrintAction.description=Print

Modified: trunk/src/ca/sqlpower/architect/swingui/dbtree/SQLObjectSelection.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/dbtree/SQLObjectSelection.java (original) +++ trunk/src/ca/sqlpower/architect/swingui/dbtree/SQLObjectSelection.java Thu Apr 2 10:05:17 2009
@@ -50,6 +50,12 @@
public static final DataFlavor SQLOBJECT_NAMES = new DataFlavor(String[].class, "List of selected object names");

     /**
+ * Data flavour that indicates a reference to a string containing the names
+     * of SQLObjects separated by a newline character.
+     */
+ public static final DataFlavor MULTILINE_SQLOBJECT_NAMES = new DataFlavor(String.class, "List of selected object names as one string separated by newlines");
+
+    /**
      * These are the actual SQLObjects we're transfering.
      */
     private final SQLObject[] sqlObjects;
@@ -58,6 +64,23 @@
      * These are the names of the SQLObjects we're transfering.
      */
     private final String[] sqlObjectNames;
+
+    /**
+ * Thesea re the names of the SQLObjects we're transfering separated by newline characters.
+     */
+    private final String sqlObjectNamesNewlineSeparated;
+
+    /**
+ * Tracks if this SQLObject is still local to the JVM it was created in. If + * this transferable is sent to the system's clipboard then it is no longer
+     * local and the SQLObject array cannot be used to copy or paste into
+     * other applications.
+     * <p>
+ * If another type of transferable is made this may need to be moved to an + * abstract class that is the parent of each transferable to make managing this
+     * simpler.
+     */
+    private boolean isLocal = true;

     /**
      * Creates a new transferable for the given collection of SQLObjects.
@@ -84,6 +107,14 @@
         }
         this.sqlObjects = sqlObjects;
         sqlObjectNames = getObjectNames(sqlObjects);
+        StringBuffer sb = new StringBuffer();
+        boolean first = true;
+        for (SQLObject o : sqlObjects) {
+            if (!first) sb.append("\n");
+            sb.append(getObjectName(o));
+            first = false;
+        }
+        sqlObjectNamesNewlineSeparated = sb.toString();
     }

     public Object getTransferData(DataFlavor flavor)
@@ -92,17 +123,23 @@
             return sqlObjects;
         } else if (flavor == SQLOBJECT_NAMES) {
             return sqlObjectNames;
+        } else if (flavor == MULTILINE_SQLOBJECT_NAMES) {
+            return sqlObjectNamesNewlineSeparated;
         } else {
             throw new UnsupportedFlavorException(flavor);
         }
     }

     public DataFlavor[] getTransferDataFlavors() {
- return new DataFlavor[] { LOCAL_SQLOBJECT_ARRAY_FLAVOUR, SQLOBJECT_NAMES };
+        if (isLocal) {
+ return new DataFlavor[] { LOCAL_SQLOBJECT_ARRAY_FLAVOUR, SQLOBJECT_NAMES, MULTILINE_SQLOBJECT_NAMES };
+        } else {
+ return new DataFlavor[] {SQLOBJECT_NAMES, MULTILINE_SQLOBJECT_NAMES };
+        }
     }

     public boolean isDataFlavorSupported(DataFlavor flavor) {
- return (flavor == LOCAL_SQLOBJECT_ARRAY_FLAVOUR || flavor == SQLOBJECT_NAMES); + return ((isLocal && flavor == LOCAL_SQLOBJECT_ARRAY_FLAVOUR) || flavor == SQLOBJECT_NAMES || flavor == MULTILINE_SQLOBJECT_NAMES);
     }

     /**
@@ -111,20 +148,33 @@
      private String[] getObjectNames(SQLObject[] objects){
          String[] nodeNames = new String[objects.length];
          for (int i = 0; i < objects.length; i++) {
-             if (objects[i] instanceof SQLTable) {
-                 nodeNames[i] = ((SQLTable) objects[i]).toQualifiedName();
-             } else if (objects[i] instanceof SQLColumn) {
- nodeNames[i] = ((SQLColumn) objects[i]).getParentTable().getName() + "." + ((SQLColumn) objects[i]).getName();
-             } else {
-                 nodeNames[i] = objects[i].getName();
-             }
+             final SQLObject object = objects[i];
+             nodeNames[i] = getObjectName(object);
          }
          return nodeNames;
      }
+
+     /**
+ * Takes the tree paths to store the name of a SQLObject which will be used in a flavor.
+      */
+    private String getObjectName(final SQLObject object) {
+        String nodeName;
+        if (object instanceof SQLTable) {
+            nodeName = ((SQLTable) object).toQualifiedName();
+        } else if (object instanceof SQLColumn) {
+ nodeName = ((SQLColumn) object).getParentTable().getName() + "." + ((SQLColumn) object).getName();
+        } else {
+            nodeName = object.getName();
+        }
+        return nodeName;
+    }

      @Override
     public String toString() {
         return Arrays.toString(sqlObjectNames);
     }

+    public void setLocal(boolean isLocal) {
+        this.isLocal = isLocal;
+    }
 }

Reply via email to