/*
* Copyright (C) 2011 Alasdair C. Hamilton
*
* This program 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.
*
* This program 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 ketUI;
import java.util.*;
import java.awt.Toolkit;
import java.io.IOException;
import ket.math.*;
import ket.math.purpose.Word;
import ket.math.purpose.IntegerValue;
import ket.math.convert.ArgumentParser;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
/**
* Store a series of copies of branches of equations which may be accessed by a
* given letter. The class functions as a glorified hash table of letters that
* can each have added to them an argument.
*/
public class Clipboard {
final KnownArguments knownArguments;
final LinkedList<Argument> recentlyDeleted;
Argument yankedArgument;
String registerName;
TreeMap<String, Argument> registerMap;
public Clipboard(KnownArguments knownArguments) {
this.knownArguments = knownArguments;
recentlyDeleted = new LinkedList<Argument>();
yankedArgument = null;
registerName = "%";
registerMap = new TreeMap<String, Argument>();
registerMap.put("%", null);
}
/**
* As pre-selecting the desired register is a separate process, an
* internal record of the register's value is stored between calls to
* process stack.
*/
private void setArgument(Argument argument) {
//- Ket.out.println(" --- clipboard.setArgument("+argument+") --- ");
//- Ket.out.println("register name = " + registerName);
//- Ket.out.println("register map = " + registerMap);
if (registerName.equals("*")) {
// Also update system clipboard.
writeToSystemClipboard(argument.toString());
}
Argument clone = Argument.cloneArgument(argument);
registerMap.put(registerName, clone);
this.registerName = "%";
}
public void setYankedArgument(Argument argument) {
yankedArgument = Argument.cloneArgument(argument);
setArgument(argument);
}
public void setDeletedArgument(Argument argument) {
Argument clone = Argument.cloneArgument(argument);
recentlyDeleted.addFirst(clone);
if (recentlyDeleted.size()>8) { // %1, %2...%9
recentlyDeleted.removeLast();
}
setArgument(argument);
}
public Argument getArgument(int register) {
return getArgument(""+register);
}
/**
* Return a clone of the clipboard's value in the requested register
* without changing the default register's value.
*/
public Argument getArgument(String registerName) {
Argument copy = null;
if (registerName.equals("\"")) {
// While either '%' or '"' are acceptable, always use the same consistent register.
registerName = "%";
}
Ket.out.println(" --- clipboard.get("+registerName+") --- ");
Ket.out.println("register name = " + registerName);
Ket.out.println("register map = " + registerMap);
if (registerName.matches("\\d")) {
int i = Integer.parseInt(registerName);
copy = getNumberArgument(i);
} else if (registerName.equals("*")) {
// System clipboard.
copy = readArgumentFromSystemClipboard();
} else {
// Local argument
Argument argument = registerMap.get(registerName);
copy = Argument.cloneArgument(argument);
}
// Clear the current register and return to the default.
this.registerName = "%";
return copy;
}
/**
* Return the value in the already-selected register then reset the
* selected register..
*/
public Argument getArgument() {
return getArgument(registerName);
}
public void setRegister(String registerName) {
this.registerName = registerName;
}
public String getRegister() {
return registerName;
}
public String toString() {
return registerMap.toString();
}
private Argument getNumberArgument(int number) {
if (number==0) {
// Register %0 refers to the last yanked argument.
return Argument.cloneArgument(yankedArgument);
} else if (0<number && number-1<recentlyDeleted.size()) {
// Registers %1...%9 refer to deleted arguments.
Argument deleted = recentlyDeleted.get(number-1);
return Argument.cloneArgument(deleted);
} else {
Ket.out.println(" !!! unexpected number ("+number+") !!!");
return null;
}
}
private Argument readArgumentFromSystemClipboard() {
String argumentString = readFromSystemClipboard();
if ( argumentString != null ) {
Ket.out.println("argument string = /" + argumentString + "/");
return ArgumentParser.parseArgument(argumentString, knownArguments, this, null);
} else {
Ket.out.println(" !!! Parsed argument was null !!! ");
return null;
}
}
public void copyToClipboard(Argument a) {
setRegister("*");
setYankedArgument(a);
}
public String readFromSystemClipboard() {
Transferable transferable = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
try {
if (transferable==null) {
Ket.out.println(" !!! Null transferable object when accessing system clipboard !!! ");
return null;
} else if (! transferable.isDataFlavorSupported(DataFlavor.stringFlavor) ) {
Ket.out.println(" !!! Can't interpret system clipboard as a string !!! ");
return null;
} else {
return (String) transferable.getTransferData(DataFlavor.stringFlavor);
}
} catch (UnsupportedFlavorException unsupportedFlavorException) {
Ket.out.println(" !!! Can't read from system clipboard !!! ");
Ket.out.println(unsupportedFlavorException);
return null;
} catch (IOException iOException) {
Ket.out.println(" !!! Can't read from system clipboard !!! ");
Ket.out.println(iOException);
return null;
}
}
private void writeToSystemClipboard(String string) {
StringSelection stringSelection = new StringSelection(string);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, null);
}
/**
* Access a clipboard register using 'percentage letter' notation;
* either by a letter or a digit depending on the type of purpose.
*/
public Argument getArgument(Purpose purpose) {
if (purpose instanceof Word) {
Word word = (Word) purpose;
String value = word.getValue();
if (value.length()==1) {
return getArgument(value);
} else {
return null;
}
} else if (purpose instanceof IntegerValue) {
IntegerValue integerValue = (IntegerValue) purpose;
int value = integerValue.getInt();
return getArgument(value);
} else {
return null;
}
}
}