/*******************************************************************************
* This file is part of logisim-evolution.
*
* logisim-evolution 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.
*
* logisim-evolution 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 logisim-evolution. If not, see <http://www.gnu.org/licenses/>.
*
* Original code by Carl Burch (http://www.cburch.com), 2011.
* Subsequent modifications by :
* + Haute École Spécialisée Bernoise
* http://www.bfh.ch
* + Haute École du paysage, d'ingénierie et d'architecture de Genève
* http://hepia.hesge.ch/
* + Haute École d'Ingénierie et de Gestion du Canton de Vaud
* http://www.heig-vd.ch/
* The project is currently maintained by :
* + REDS Institute - HEIG-VD
* Yverdon-les-Bains, Switzerland
* http://reds.heig-vd.ch
*******************************************************************************/
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 class Data implements Transferable, Serializable {
private static final long serialVersionUID = 1L;
private String[] headers;
private String[][] contents;
Data(String[] headers, String[][] contents) {
this.headers = headers;
this.contents = contents;
}
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);
}
}
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { binaryFlavor, DataFlavor.stringFlavor };
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor == binaryFlavor || flavor == DataFlavor.stringFlavor;
}
}
private static final DataFlavor binaryFlavor = new DataFlavor(Data.class,
"Binary data");
private TableTab table;
TableTabClip(TableTab table) {
this.table = table;
}
public boolean canPaste() {
Clipboard clip = table.getToolkit().getSystemClipboard();
Transferable xfer = clip.getContents(this);
return xfer.isDataFlavorSupported(binaryFlavor);
}
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 void lostOwnership(Clipboard clip, Transferable transfer) {
}
public void paste() {
Clipboard clip = table.getToolkit().getSystemClipboard();
Transferable xfer;
try {
xfer = clip.getContents(this);
} catch (IllegalStateException | ArrayIndexOutOfBoundsException 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]);
}
}
}
}
}