From e5c527859a51c72d1c00134b0736d0f8453ade02 Mon Sep 17 00:00:00 2001 From: Jiheun Ha <89976598+jiheunha@users.noreply.github.com> Date: Wed, 29 Jul 2026 18:01:30 +0900 Subject: [PATCH 1/2] Add right-click copy with column headers to result tables --- .../ModelGUI2/tables/CopyPaste.java | 90 ++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/ModelInterface/ModelGUI2/tables/CopyPaste.java b/ModelInterface/ModelGUI2/tables/CopyPaste.java index 953c78f..894d85a 100644 --- a/ModelInterface/ModelGUI2/tables/CopyPaste.java +++ b/ModelInterface/ModelGUI2/tables/CopyPaste.java @@ -99,9 +99,97 @@ public void propertyChange(PropertyChangeEvent e) { } }); - + addCopyWithHeaderPopup(); } + + /** + * Attaches a right-click popup menu to the table with entries to copy + * the table contents as tab separated values with the column headers + * included as the first row. This makes it convenient to paste results + * into a spreadsheet such as Excel. + */ + private void addCopyWithHeaderPopup() { + final JPopupMenu popupMenu = new JPopupMenu(); + JMenuItem copyAllItem = new JMenuItem("Copy (with header)"); + copyAllItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + copyWithHeader(false); + } + }); + popupMenu.add(copyAllItem); + JMenuItem copySelectionItem = new JMenuItem("Copy selection (with header)"); + copySelectionItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + copyWithHeader(true); + } + }); + popupMenu.add(copySelectionItem); + myJTable.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + maybeShowPopup(e); + } + public void mouseReleased(MouseEvent e) { + maybeShowPopup(e); + } + private void maybeShowPopup(MouseEvent e) { + if(e.isPopupTrigger()) { + popupMenu.show(e.getComponent(), e.getX(), e.getY()); + } + } + }); + } + + /** + * Copies the table to the system clipboard as tab separated values with + * the column headers as the first row. Note we can not simply reuse + * BaseTableModel.exportToText since it prepends a title line and adds a + * trailing delimiter to each row which does not paste cleanly, and it + * can not restrict itself to the current selection. + * @param selectionOnly if true only copy the selected rows/columns, + * falls back to the whole table when there is no selection + */ + private void copyWithHeader(boolean selectionOnly) { + int[] rowsToCopy; + int[] colsToCopy; + if(selectionOnly && myJTable.getSelectedRowCount() > 0 && myJTable.getSelectedColumnCount() > 0) { + rowsToCopy = myJTable.getSelectedRows(); + colsToCopy = myJTable.getSelectedColumns(); + } else { + rowsToCopy = new int[myJTable.getRowCount()]; + for(int i = 0; i < rowsToCopy.length; i++) { + rowsToCopy[i] = i; + } + colsToCopy = new int[myJTable.getColumnCount()]; + for(int j = 0; j < colsToCopy.length; j++) { + colsToCopy[j] = j; + } + } + String lineEnding = System.getProperty("line.separator"); + StringBuffer stringBuffer = new StringBuffer(); + for(int j = 0; j < colsToCopy.length; j++) { + stringBuffer.append(myJTable.getColumnName(colsToCopy[j])); + if(j != colsToCopy.length - 1) { + stringBuffer.append("\t"); + } + } + stringBuffer.append(lineEnding); + for(int i = 0; i < rowsToCopy.length; i++) { + for(int j = 0; j < colsToCopy.length; j++) { + Object value = myJTable.getValueAt(rowsToCopy[i], colsToCopy[j]); + if(value != null) { + stringBuffer.append(value); + } + if(j != colsToCopy.length - 1) { + stringBuffer.append("\t"); + } + } + stringBuffer.append(lineEnding); + } + StringSelection selection = new StringSelection(stringBuffer.toString()); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection); + } + private BaseTableModel getMyModel() { if(myJTable.getModel() instanceof TableSorter) { return (BaseTableModel)((TableSorter)myJTable.getModel()).getTableModel(); From e164fb45d98985d96e4e75d08b5a817a99991ace Mon Sep 17 00:00:00 2001 From: Jiheun Ha <89976598+jiheunha@users.noreply.github.com> Date: Wed, 29 Jul 2026 18:46:07 +0900 Subject: [PATCH 2/2] Replace tabs and newlines in cell values with spaces --- ModelInterface/ModelGUI2/tables/CopyPaste.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ModelInterface/ModelGUI2/tables/CopyPaste.java b/ModelInterface/ModelGUI2/tables/CopyPaste.java index 894d85a..1e3d8b0 100644 --- a/ModelInterface/ModelGUI2/tables/CopyPaste.java +++ b/ModelInterface/ModelGUI2/tables/CopyPaste.java @@ -178,7 +178,7 @@ private void copyWithHeader(boolean selectionOnly) { for(int j = 0; j < colsToCopy.length; j++) { Object value = myJTable.getValueAt(rowsToCopy[i], colsToCopy[j]); if(value != null) { - stringBuffer.append(value); + stringBuffer.append(value.toString().replaceAll("[\t\r\n]", " ")); } if(j != colsToCopy.length - 1) { stringBuffer.append("\t");