/*
* 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.responder;
import geom.Position;
import ket.MathCollection;
import ket.Message;
import ket.Selection;
import ket.display.box.Box;
import ket.display.box.BoxText;
import ket.math.*;
import ket.math.convert.ArgumentParser;
import ket.math.purpose.Text;
import ketUI.Clipboard;
import ketUI.Document;
import ketUI.DocumentManager;
import ketUI.Ket;
import ketUI.MouseButton;
import ketUI.MouseEventHandler;
import ketUI.chord.Chord;
import ketUI.chord.KeyboardEventHandler;
import ketUI.chord.Macros;
import ketUI.modes.*;
import ketUI.panel.KetPanel;
public class TextResponder extends Responder {
final Modes modes;
final MathCollection mathCollection;
public TextResponder(Modes modes) {
this.modes = modes;
this.mathCollection = modes.getMathCollection();
}
private String processNextChordIterationString(String string, Chord chord) {
if (!getCurrent().isText()) {
Ket.out.println(" !!! textResponder.processNextChordIterationString()::Cannot be in UPDATE_TEXT state unless current state is Text !!! ");
Ket.out.println("current = "+getCurrent());
return string;
}
Ket.out.println(" ----------------------------------- ");
Ket.out.println(" process next chord iteration string ");
Ket.out.println("string = " + string);
Ket.out.println(" ----------------------------------- ");
Message message = getMessage();
String messageString = message.getLine();
Text updatedText = new Text(messageString);
getSelection().replace(new Token(updatedText));
return string;
}
private Argument getCurrent() {
return getSelection().getCurrent();
}
private Selection getSelection() {
return modes.getSelection();
}
private void setCurrent(Argument argument) {
modes.getSelection().setCurrent(argument);
}
private Message getMessage() {
return modes.getMessage();
}
@Override
public void prepareToRespond() {
modes.getMessage().ensureEditingStarted();
displayText(getMessage(), true);
}
@Override
public void cleanAfterRespond() {
Message m = getMessage();
String line = m.getLine();
if (line.indexOf('$')!=-1) {
String[] parts = line.split("\\$");
Branch paragraph = new Branch(Function.SENTENCE); // Chooose between SENTENCE, PARAGRAPH etc. more carefully.
for (int i=0; i<parts.length; i++) {
String p = parts[i];
if (i%2==0) {
paragraph.append(new Token(new Text(p)));
} else {
Argument u = getDocument().parseArgument(p);
paragraph.append(u);
}
}
getSelection().replace(paragraph);
} else {
displayText(m, false);
}
m.cancelAndClear();
modes.getMathCollection().updateUndoStack();
}
private void displayText(Message message, boolean showCursor) { // TODO: call getMessage() internally.
/*-
if (! getCurrent().isText()) {
Ket.out.println(" !!! textResponder.displayText()::Cannot be in UPDATE_TEXT state unless current state is Text !!! ");
Ket.out.println("current = "+getCurrent());
throw new RuntimeException("Attempting to update non-text as text.");
//return;
}
*/
String messageString = showCursor ? message.getCursorLine() : message.getLine();
Text updatedText = new Text(messageString);
getSelection().replace(new Token(new Text(messageString)));
}
/**
* Append the last ketUI.chord's key press to the current message and respond
* appropriately to complete messages.
*/
@Override
public void respondToChordEvent(Chord chord, Macros macros, KeyboardEventHandler keyboardEventHandler) {
Message message = getMessage();
assert modes.getDocumentState()==DocumentState.UPDATE_TEXT;
chord.appendLastKeypressToMessage(message, true);
//! If text mode changed to equation display it will handle drawing internally.
if (modes.getDocumentState()==DocumentState.UPDATE_TEXT) {
displayText(message, true);
}
if (!message.isComplete()) {
// Continue appending characters while in message.APPEND_MODE.
chord.setComplete(false);
return;
}
String messageString = message.getLine();
String processedMessageString = processNextChordIterationString(messageString, chord);
if (processedMessageString==null) {
// TODO: Display a suitable error message if not already done so?
chord.setError(true);
return;
}
chord.appendMessage(processedMessageString);
return;
}
public boolean textSelect(Position p) {
Message message = modes.getMessage();
Box box = findDeepestBox(p);
Argument finishArgument = box!=null ? box.getArgument() : null;
if ( ! (box instanceof BoxText) ) {
return false;
}
int index = ((BoxText) box).getIndex(p);
if (index==-1) {
return false;
}
displayText(message, false); //-?
message.setIndex(index);
displayText(message, true);
return true;
}
@Override
public void respondToMouseClick(MouseButton mouseButton, boolean singleClick, Position p) {
Message message = modes.getMessage();
Ket.out.println("current selection = " + getCurrent());
switch (mouseButton) {
case LEFT:
Argument finishArgument = findDeepestArgument(p);
Ket.out.println("finish argument = " + (finishArgument!=null ? finishArgument : null));
if (modes.getDocumentState()==DocumentState.UPDATE_TEXT) {
boolean done = textSelect(p);
if (done) {
return;
}
}
// Otherwise clear selection.
String messageString = message.getLine();
processNextChordIterationString(messageString, null); //?
modes.setDocumentState(DocumentState.NORMAL);
if ( ! singleClick && finishArgument!=null ) {
// Double click to go on to select what was clicked on.
setCurrent(finishArgument);
}
return;
case MIDDLE:
return;
case RIGHT:
return;
default:
return;
}
}
private KetPanel getKetPanel() {
return getDocument().getKetPanel();
}
private Box findDeepestBox(Position release) {
return getKetPanel().findDeepestBox(release);
}
private Argument findDeepestArgument(Position release) {
return getKetPanel().findDeepestArgument(release);
}
private Document getDocument() {
return modes.getDocument();
}
private NormalMode getNormalMode() {
return modes.getNormalMode();
}
@Override
public void respondToMouseDrag(MouseButton mouseButton, Position initial, Position release) {
// Do nothing.
}
}