--- /dev/null
+package org.simantics.spreadsheet.ui;\r
+\r
+import java.awt.Toolkit;\r
+import java.awt.datatransfer.Clipboard;\r
+import java.awt.datatransfer.ClipboardOwner;\r
+import java.awt.datatransfer.DataFlavor;\r
+import java.awt.datatransfer.StringSelection;\r
+import java.awt.datatransfer.Transferable;\r
+import java.awt.datatransfer.UnsupportedFlavorException;\r
+import java.awt.event.ActionEvent;\r
+import java.awt.event.ActionListener;\r
+import java.awt.event.KeyEvent;\r
+import java.io.IOException;\r
+import java.util.ArrayList;\r
+import java.util.regex.Pattern;\r
+\r
+import javax.swing.JComponent;\r
+import javax.swing.JOptionPane;\r
+import javax.swing.JTable;\r
+import javax.swing.KeyStroke;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.binding.mutable.MutableVariant;\r
+import org.simantics.databoard.binding.mutable.Variant;\r
+import org.simantics.spreadsheet.Adaptable;\r
+import org.simantics.spreadsheet.CellEditor;\r
+import org.simantics.spreadsheet.CellEditor.Transaction;\r
+import org.simantics.spreadsheet.ClientModel.OperationMode;\r
+import org.simantics.spreadsheet.ClientModel;\r
+import org.simantics.spreadsheet.Range;\r
+import org.simantics.spreadsheet.common.cell.StringCellParser;\r
+import org.simantics.spreadsheet.util.SpreadsheetUtils;\r
+import org.simantics.utils.threads.logger.ITask;\r
+import org.simantics.utils.threads.logger.ThreadLogger;\r
+\r
+/**\r
+ * ExcelAdapter enables Copy-Paste Clipboard functionality on JTables.\r
+ * The clipboard data format used by the adapter is compatible with\r
+ * the clipboard format used by Excel. This provides for clipboard\r
+ * interoperability between enabled JTables and Excel.\r
+ */\r
+public class ExcelAdapter implements ActionListener {\r
+\r
+ final private JTable table;\r
+ final private ClientModel model;\r
+ //final private SheetManipulator manager;\r
+ final private CellEditor editor;\r
+ final static private Pattern newline = Pattern.compile("\n");\r
+ final static private Pattern tab = Pattern.compile("\t");\r
+ final private StringCellParser[] parsers;\r
+\r
+// public boolean ownClipboard = false;\r
+ private Object clipboard = null;\r
+ private ClipboardOwner clipboardOwner = null;\r
+ private String rowstring, value;\r
+\r
+ public ExcelAdapter(JTable table, ClientModel model, Adaptable serverInterface, StringCellParser[] parsers) {\r
+\r
+ this.table = table;\r
+ this.model = model;\r
+ //this.manager = serverInterface.getAdapter(SheetManipulator.class);\r
+ this.editor = serverInterface.getAdapter(CellEditor.class);\r
+ this.parsers = parsers;\r
+\r
+ // system = Toolkit.getDefaultToolkit().getSystemClipboard();\r
+\r
+ KeyStroke copy = KeyStroke.getKeyStroke(KeyEvent.VK_C,ActionEvent.CTRL_MASK,false);\r
+ // Identifying the copy KeyStroke user can modify this\r
+ // to copy on some other Key combination.\r
+ KeyStroke paste = KeyStroke.getKeyStroke(KeyEvent.VK_V,ActionEvent.CTRL_MASK,false);\r
+ // Identifying the Paste KeyStroke user can modify this\r
+ //to copy on some other Key combination.\r
+ table.registerKeyboardAction(this,"Copy",copy,JComponent.WHEN_FOCUSED);\r
+ table.registerKeyboardAction(this,"Paste",paste,JComponent.WHEN_FOCUSED);\r
+\r
+ }\r
+ // /**\r
+ // * Public Accessor methods for the Table on which this adapter acts.\r
+ // */\r
+ // public JTable getJTable() {return jTable1;}\r
+ // public void setJTable(JTable jTable1) {this.jTable1=jTable1;}\r
+ /**\r
+ * This method is activated on the Keystrokes we are listening to\r
+ * in this implementation. Here it listens for Copy and Paste ActionCommands.\r
+ * Selections comprising non-adjacent cells result in invalid selection and\r
+ * then copy action cannot be performed.\r
+ * Paste is done by aligning the upper left corner of the selection with the\r
+ * 1st element in the current selection of the JTable.\r
+ */\r
+ public void actionPerformed(ActionEvent e)\r
+ {\r
+\r
+ Clipboard system = Toolkit.getDefaultToolkit().getSystemClipboard();\r
+\r
+ if (e.getActionCommand().compareTo("Copy")==0)\r
+ {\r
+\r
+ // Check to ensure we have selected only a contiguous block of\r
+ // cells\r
+ int numcols=table.getSelectedColumnCount();\r
+ int numrows=table.getSelectedRowCount();\r
+ if (numcols == 0 || numrows == 0)\r
+ return;\r
+\r
+ int[] rowsselected=table.getSelectedRows();\r
+ int[] colsselected=table.getSelectedColumns();\r
+ if (!((numrows-1==rowsselected[rowsselected.length-1]-rowsselected[0] &&\r
+ numrows==rowsselected.length) &&\r
+ (numcols-1==colsselected[colsselected.length-1]-colsselected[0] &&\r
+ numcols==colsselected.length)))\r
+ {\r
+ JOptionPane.showMessageDialog(null, "Invalid Copy Selection",\r
+ "Invalid Copy Selection",\r
+ JOptionPane.ERROR_MESSAGE);\r
+ return;\r
+ }\r
+\r
+ Object[] rows = new Object[numrows];\r
+ for (int i=0;i<numrows;i++) {\r
+ Object[] cols = new Object[numcols];\r
+ rows[i] = cols;\r
+ for (int j=0;j<numcols;j++) {\r
+ cols[j] = SpreadsheetUtils.getLabel(model, rowsselected[i],colsselected[j]);\r
+ }\r
+ }\r
+\r
+ StringBuilder builder = new StringBuilder();\r
+ for(int i=0;i<rows.length;i++) {\r
+ Object[] cols = (Object[])rows[i];\r
+ for(int j=0;j<cols.length;j++) {\r
+ if(j>0) builder.append("\t");\r
+ Object value=(Object)cols[j];\r
+ if(value != null) {\r
+ builder.append(value.toString());\r
+ }\r
+ }\r
+ builder.append("\n");\r
+ }\r
+ \r
+ clipboard = new Range(rowsselected[0],rowsselected[0]+numrows-1,colsselected[0],colsselected[0]+numcols-1);\r
+ clipboardOwner = new ClipboardOwner() {\r
+ \r
+ @Override\r
+ public void lostOwnership(Clipboard arg0, Transferable arg1) {\r
+ if(clipboardOwner == this) {\r
+ clipboardOwner = null;\r
+ clipboard = null;\r
+ }\r
+ }\r
+ \r
+ };\r
+\r
+ system.setContents(new StringSelection(builder.toString()), clipboardOwner);\r
+\r
+ }\r
+ if (e.getActionCommand().compareTo("Paste")==0)\r
+ {\r
+ int[] selectedRows = table.getSelectedRows();\r
+ int[] selectedColumns = table.getSelectedColumns();\r
+ if (selectedRows.length == 0 || selectedColumns.length == 0)\r
+ return;\r
+ int startRow = selectedRows[0];\r
+ int startCol = selectedColumns[0];\r
+\r
+ if(clipboardOwner == null) {\r
+ \r
+ //if(manager == null) return;\r
+ if(editor == null) return;\r
+\r
+ String trstring = null;\r
+ try {\r
+ trstring = (String)(system.getContents(this).getTransferData(DataFlavor.stringFlavor));\r
+ } catch (UnsupportedFlavorException e1) {\r
+ e1.printStackTrace();\r
+ } catch (IOException e1) {\r
+ e1.printStackTrace();\r
+ }\r
+\r
+ if(trstring == null || trstring.isEmpty()) return;\r
+\r
+ ITask task = ThreadLogger.getInstance().begin("Spreadsheet.paste");\r
+\r
+ /*\r
+ * Analyse the target area. No computed cells are allowed. Collect cells to remove.\r
+ */\r
+\r
+ ArrayList<String> removals = new ArrayList<String>();\r
+ \r
+ String[] rows = newline.split(trstring);\r
+ for(int i=0;i<rows.length;i++) {\r
+ String[] cols = tab.split(rows[i]);\r
+ for(int j=0;j<cols.length;j++) {\r
+ value=cols[j];\r
+ if (value.length() > 0 && startRow+i< table.getRowCount() &&\r
+ startCol+j< table.getColumnCount()) {\r
+\r
+ CellValue cell = (CellValue)table.getValueAt(startRow+i, startCol+j);\r
+ if(cell.label != null) {\r
+ String location = SpreadsheetUtils.cellName(startRow+i, startCol+j);\r
+ Boolean computed = model.getPropertyAt(location, ClientModel.COMPUTED);\r
+ if(computed != null && computed) return;\r
+ removals.add(location);\r
+ }\r
+\r
+ }\r
+ }\r
+ }\r
+ \r
+ /*\r
+ * Create the cell data\r
+ * \r
+ */\r
+\r
+ Transaction tr = editor.startTransaction(OperationMode.OPERATION);\r
+ \r
+ for(int i=0;i<rows.length;i++) {\r
+ String[] cols = tab.split(rows[i]);\r
+ for(int j=0;j<cols.length;j++) {\r
+ value=cols[j];\r
+ if (value.length() > 0 && startRow+i< table.getRowCount() &&\r
+ startCol+j< table.getColumnCount()) {\r
+\r
+ if (value.startsWith("=")) {\r
+ editor.edit(tr, SpreadsheetUtils.cellName(startRow+i, startCol+j), ClientModel.CONTENT_EXPRESSION, value, Bindings.STRING, null);\r
+ } else {\r
+ editor.edit(tr, SpreadsheetUtils.cellName(startRow+i, startCol+j), Variant.ofInstance(value), null);\r
+ }\r
+\r
+ }\r
+ }\r
+ }\r
+ \r
+ tr.commit();\r
+\r
+ task.finish();\r
+\r
+ } else {\r
+\r
+ Range from = (Range)clipboard;\r
+ Range to = new Range(startRow, startRow+from.height()-1, startCol, startCol+from.width()-1);\r
+ \r
+ Transaction tr = editor.startTransaction(OperationMode.OPERATION);\r
+\r
+ for(int i=0;i<from.height();i++) {\r
+ for(int j=0;j<from.width();j++) {\r
+ String fromCell = SpreadsheetUtils.cellName(from.startRow+i, from.startColumn+j);\r
+ String toCell = SpreadsheetUtils.cellName(to.startRow+i, to.startColumn+j);\r
+ Object obj = model.getPropertyAt(fromCell, "content");\r
+ if (obj == null)\r
+ continue;\r
+ MutableVariant variant = SpreadsheetUtils.createVariant();\r
+ System.out.println("asdasd fromCell toCell " + fromCell + " " + toCell);\r
+ editor.copy(tr, fromCell, variant, null);\r
+ editor.edit(tr, toCell, variant, null);\r
+ }\r
+ }\r
+ \r
+ tr.commit(); \r
+\r
+ }\r
+ }\r
+ }\r
+}
\ No newline at end of file