/* Copyright (c) 2010, Carl Burch. License information is located in the
* com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */
package com.cburch.logisim.analyze.gui;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.io.Serializable;
import java.util.StringTokenizer;
import javax.swing.JOptionPane;
import com.cburch.logisim.analyze.model.Entry;
import com.cburch.logisim.analyze.model.TruthTable;
class TableTabClip implements ClipboardOwner {
private static final DataFlavor binaryFlavor = new DataFlavor(Data.class, "Binary data");
private static class Data implements Transferable, Serializable {
private String[] headers;
private String[][] contents;
Data(String[] headers, String[][] contents) {
this.headers = headers;
this.contents = contents;
}
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { binaryFlavor, DataFlavor.stringFlavor };
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor == binaryFlavor || flavor == DataFlavor.stringFlavor;
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if (flavor == binaryFlavor) {
return this;
} else if (flavor == DataFlavor.stringFlavor) {
StringBuilder buf = new StringBuilder();
for (int i = 0; i < headers.length; i++) {
buf.append(headers[i]);
buf.append(i == headers.length - 1 ? '\n' : '\t');
}
for (int i = 0; i < contents.length; i++) {
for (int j = 0; j < contents[i].length; j++) {
buf.append(contents[i][j]);
buf.append(j == contents[i].length - 1 ? '\n' : '\t');
}
}
return buf.toString();
} else {
throw new UnsupportedFlavorException(flavor);
}
}
}
private TableTab table;
TableTabClip(TableTab table) {
this.table = table;
}
public void copy() {
TableTabCaret caret = table.getCaret();
int c0 = caret.getCursorCol();
int r0 = caret.getCursorRow();
int c1 = caret.getMarkCol();
int r1 = caret.getMarkRow();
if (c1 < c0) { int t = c0; c0 = c1; c1 = t; }
if (r1 < r0) { int t = r0; r0 = r1; r1 = t; }
TruthTable t = table.getTruthTable();
int inputs = t.getInputColumnCount();
String[] header = new String[c1 - c0 + 1];
for (int c = c0; c <= c1; c++) {
if (c < inputs) {
header[c - c0] = t.getInputHeader(c);
} else {
header[c - c0] = t.getOutputHeader(c - inputs);
}
}
String[][] contents = new String[r1 - r0 + 1][c1 - c0 + 1];
for (int r = r0; r <= r1; r++) {
for (int c = c0; c <= c1; c++) {
if (c < inputs) {
contents[r - r0][c - c0] = t.getInputEntry(r, c).getDescription();
} else {
contents[r - r0][c - c0] = t.getOutputEntry(r, c - inputs).getDescription();
}
}
}
Clipboard clip = table.getToolkit().getSystemClipboard();
clip.setContents(new Data(header, contents), this);
}
public boolean canPaste() {
Clipboard clip = table.getToolkit().getSystemClipboard();
Transferable xfer = clip.getContents(this);
return xfer.isDataFlavorSupported(binaryFlavor);
}
public void paste() {
Clipboard clip = table.getToolkit().getSystemClipboard();
Transferable xfer;
try {
xfer = clip.getContents(this);
} catch (Throwable t) {
// I don't know - the above was observed to throw an odd ArrayIndexOutOfBounds
// exception on a Linux computer using Sun's Java 5 JVM
JOptionPane.showMessageDialog(table.getRootPane(),
Strings.get("clipPasteSupportedError"),
Strings.get("clipPasteErrorTitle"),
JOptionPane.ERROR_MESSAGE);
return;
}
Entry[][] entries;
if (xfer.isDataFlavorSupported(binaryFlavor)) {
try {
Data data = (Data) xfer.getTransferData(binaryFlavor);
entries = new Entry[data.contents.length][];
for (int i = 0; i < entries.length; i++) {
Entry[] row = new Entry[data.contents[i].length];
for (int j = 0; j < row.length; j++) {
row[j] = Entry.parse(data.contents[i][j]);
}
entries[i] = row;
}
} catch (UnsupportedFlavorException e) {
return;
} catch (IOException e) {
return;
}
} else if (xfer.isDataFlavorSupported(DataFlavor.stringFlavor)) {
try {
String buf = (String) xfer.getTransferData(DataFlavor.stringFlavor);
StringTokenizer lines = new StringTokenizer(buf, "\r\n");
String first;
if (!lines.hasMoreTokens()) return;
first = lines.nextToken();
StringTokenizer toks = new StringTokenizer(first, "\t,");
String[] headers = new String[toks.countTokens()];
Entry[] firstEntries = new Entry[headers.length];
boolean allParsed = true;
for (int i = 0; toks.hasMoreTokens(); i++) {
headers[i] = toks.nextToken();
firstEntries[i] = Entry.parse(headers[i]);
allParsed = allParsed && firstEntries[i] != null;
}
int rows = lines.countTokens();
if (allParsed) rows++;
entries = new Entry[rows][];
int cur = 0;
if (allParsed) {
entries[0] = firstEntries;
cur++;
}
while (lines.hasMoreTokens()) {
toks = new StringTokenizer(lines.nextToken(), "\t");
Entry[] ents = new Entry[toks.countTokens()];
for (int i = 0; toks.hasMoreTokens(); i++) {
ents[i] = Entry.parse(toks.nextToken());
}
entries[cur] = ents;
cur++;
}
} catch (UnsupportedFlavorException e) {
return;
} catch (IOException e) {
return;
}
} else {
JOptionPane.showMessageDialog(table.getRootPane(),
Strings.get("clipPasteSupportedError"),
Strings.get("clipPasteErrorTitle"),
JOptionPane.ERROR_MESSAGE);
return;
}
TableTabCaret caret = table.getCaret();
int c0 = caret.getCursorCol();
int c1 = caret.getMarkCol();
int r0 = caret.getCursorRow();
int r1 = caret.getMarkRow();
if (r0 < 0 || r1 < 0 || c0 < 0 || c1 < 0) return;
TruthTable model = table.getTruthTable();
int rows = model.getRowCount();
int inputs = model.getInputColumnCount();
int outputs = model.getOutputColumnCount();
if (c0 == c1 && r0 == r1) {
if (r0 + entries.length > rows
|| c0 + entries[0].length > inputs + outputs) {
JOptionPane.showMessageDialog(table.getRootPane(),
Strings.get("clipPasteEndError"),
Strings.get("clipPasteErrorTitle"),
JOptionPane.ERROR_MESSAGE);
return;
}
} else {
if (r0 > r1) { int t = r0; r0 = r1; r1 = t; }
if (c0 > c1) { int t = c0; c0 = c1; c1 = t; }
if (r1 - r0 + 1 != entries.length
|| c1 - c0 + 1 != entries[0].length) {
JOptionPane.showMessageDialog(table.getRootPane(),
Strings.get("clipPasteSizeError"),
Strings.get("clipPasteErrorTitle"),
JOptionPane.ERROR_MESSAGE);
return;
}
}
for (int r = 0; r < entries.length; r++) {
for (int c = 0; c < entries[0].length; c++) {
if (c0 + c >= inputs) {
model.setOutputEntry(r0 + r, c0 + c - inputs,
entries[r][c]);
}
}
}
}
public void lostOwnership(Clipboard clip, Transferable transfer) { }
}