package org.geogebra.web.web.gui.dialog;
import org.geogebra.common.euclidian.EuclidianConstants;
import org.geogebra.common.euclidian.EuclidianViewInterfaceCommon;
import org.geogebra.common.gui.InputHandler;
import org.geogebra.common.gui.dialog.TextInputDialog;
import org.geogebra.common.gui.view.algebra.DialogType;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.geos.GeoText;
import org.geogebra.common.kernel.kernelND.GeoElementND;
import org.geogebra.common.kernel.kernelND.GeoPointND;
import org.geogebra.common.main.App;
import org.geogebra.common.main.Feature;
import org.geogebra.common.main.error.ErrorHandler;
import org.geogebra.common.util.AsyncOperation;
import org.geogebra.common.util.debug.Log;
import org.geogebra.web.html5.Browser;
import org.geogebra.web.html5.gui.GPopupPanel;
import org.geogebra.web.html5.main.AppW;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.user.client.ui.TextBox;
/**
* Web implementation of Text Dialog
*/
public class TextInputDialogW extends InputDialogW implements TextInputDialog{
/** edited text */
GeoText editGeo;
/** start point */
GeoPointND startPoint;
/** whether to position text in RW coords or EV */
boolean rw;
private TextEditPanel editor;
private int cols;
private int rows;
private String dialogTitle;
private boolean isTextMode;
/**
* @param app2
* app
* @param title
* title
* @param editGeo
* text to edit
* @param startPoint
* start point
* @param rw
* whether to use RW for position
* @param cols
* columns of edit area
* @param rows
* rows of edit area
* @param isTextMode
* whether text mode was active when this was called
*/
public TextInputDialogW(App app2, String title, GeoText editGeo,
GeoPointND startPoint, boolean rw, int cols, int rows, boolean isTextMode) {
super(false, (AppW) app2, false);
this.startPoint = startPoint;
this.rw = rw;
dialogTitle = title;
this.cols = cols;
this.rows = rows;
this.isTextMode = isTextMode;
this.editGeo = editGeo;
// textInputDialog = this;
setInputHandler(new TextInputHandler());
// isIniting = true;
createTextGUI(title, "", false, cols, rows, /* false */ true, false,
false, false,
DialogType.DynamicText);
}
private void createTextGUI(String title, String message,
boolean autoComplete, int columns, int rows1,
boolean showSymbolPopupIcon, boolean selectInitText,
boolean showProperties, boolean showApply, DialogType type) {
super.createGUI(title, message, autoComplete, columns, rows1,
showSymbolPopupIcon, selectInitText, showProperties, showApply,
type);
app.unregisterPopup(wrappedPopup);
editor = inputPanel.getTextAreaComponent();
if (editor != null) {
editor.setText(editGeo);
} else if (inputPanel.getTextComponent() != null) {
// this branch probably does not run (rows > 1), educated guess
inputPanel.getTextComponent().setText(editGeo.getTextString());
}
wrappedPopup.addStyleName("TextInputDialog");
wrappedPopup.center();
wrappedPopup.show();
focus();
wrappedPopup.addCloseHandler(new CloseHandler<GPopupPanel>() {
@Override
public void onClose(CloseEvent<GPopupPanel> event) {
resetEditor();
}
});
}
/*
* Close iOS keyboard at creating text. At using TextInputDialog iOS
* keyboard has to be closed programmatically at clicking on OK or Cancel,
* otherwise it won't be closed after the dialog will be hidden.
*/
protected void closeIOSKeyboard() {
if (!app.has(Feature.KEYBOARD_BEHAVIOUR)) {
return;
}
if (inputPanel == null || inputPanel.getTextAreaComponent() == null) {
return;
}
TextBox dummyTextBox = new TextBox();
editor.add(dummyTextBox);
dummyTextBox.setFocus(true);
dummyTextBox.setFocus(false);
}
/**
* Removes current editor
*/
void resetEditor() {
editor = null;
}
@Override
protected void resetMode() {
if (isTextMode) {
app.setMode(EuclidianConstants.MODE_TEXT);
}
}
/**
* Updates latex / serif / font size of the text from GUI
*
* @param t
* text
*/
void updateTextStyle(GeoText t) {
if (editor == null) {
Log.debug("null editor");
return;
}
t.setLaTeX(editor.isLatex(), true);
t.setFontStyle(editor.getFontStyle());
t.setSerifFont(editor.isSerif());
// make sure for new LaTeX texts we get nice "x"s
if (editor.isLatex()) {
t.setSerifFont(true);
}
}
/**
* @return whether latex checkbox is active
*/
boolean isLatex() {
if (editor == null) {
Log.debug("null editor");
return false;
}
return editor.isLatex();
}
// =============================================================
// TextInputHandler
// =============================================================
/**
* Handles creating or redefining GeoText using the current editor string.
*
*/
private class TextInputHandler implements InputHandler {
private Kernel kernel;
TextInputHandler() {
kernel = app.getKernel();
}
@Override
public void processInput(String input, ErrorHandler handler,
AsyncOperation<Boolean> callback) {
if (input == null) {
callback.callback(false);
return;
}
String inputValue = input;
// no quotes?
if (inputValue.indexOf('"') < 0) {
// this should become either
// (1) a + "" where a is an object label or
// (2) "text", a plain text
// ad (1) OBJECT LABEL
// add empty string to end to make sure
// that this will become a text object
if (kernel.lookupLabel(inputValue.trim()) != null) {
inputValue = "(" + inputValue + ") + \"\"";
}
// ad (2) PLAIN TEXT
// add quotes to string
else {
inputValue = "\"" + inputValue + "\"";
}
} else {
// replace \n\" by \"\n, this is useful for e.g.:
// "a = " + a +
// "b = " + b
inputValue = inputValue.replaceAll("\n\"", "\"\n");
}
if ("\"\"".equals(inputValue)) {
callback.callback(false);
return;
}
// create new GeoText
boolean createText = editGeo == null;
handler.resetError();
if (createText) {
kernel.getAlgebraProcessor()
.processAlgebraCommandNoExceptionHandling(inputValue,
false, handler, true,
getCallback(callback));
return;
}
// change existing text
try {
kernel.getAlgebraProcessor().changeGeoElement(editGeo,
inputValue, true, true, TextInputDialogW.this,
new AsyncOperation<GeoElementND>() {
@Override
public void callback(GeoElementND newText) {
if (newText instanceof GeoText) {
// make sure newText is using correct LaTeX
// setting
((GeoText) newText).setLaTeX(isLatex(),
true);
if (newText.getParentAlgorithm() != null) {
newText.getParentAlgorithm().update();
} else {
newText.updateRepaint();
}
app.doAfterRedefine(newText);
// make redefined text selected
app.getSelectionManager()
.addSelectedGeo(newText);
}
}
});
callback.callback(true);
} catch (Exception e) {
app.showError(e.getMessage());
callback.callback(false);
}
}
private AsyncOperation<GeoElementND[]> getCallback(
final AsyncOperation<Boolean> callback) {
// TODO Auto-generated method stub
return new AsyncOperation<GeoElementND[]>() {
@Override
public void callback(GeoElementND[] ret) {
if (ret != null && ret[0] instanceof GeoText) {
GeoText t = (GeoText) ret[0];
positionText(t);
app.storeUndoInfo();
callback.callback(true);
return;
}
callback.callback(false);
return;
}
};
}
protected void positionText(GeoText t) {
updateTextStyle(t);
EuclidianViewInterfaceCommon activeView = kernel.getApplication()
.getActiveEuclidianView();
if (startPoint.isLabelSet()) {
t.checkVisibleIn3DViewNeeded();
try {
t.setStartPoint(startPoint);
} catch (Exception e) {
// circular definition
}
} else {
// changed to
// RealWorld
// not absolute
// startpoint contains mouse coords
// t.setAbsoluteScreenLoc(euclidianView.toScreenCoordX(startPoint.inhomX),
// euclidianView.toScreenCoordY(startPoint.inhomY));
// t.setAbsoluteScreenLocActive(true);
if (rw) {
Coords coords = startPoint.getInhomCoordsInD3();
t.setRealWorldLoc(
activeView.toRealWorldCoordX(
coords.getX()),
activeView.toRealWorldCoordY(
coords.getY()));
t.setAbsoluteScreenLocActive(false);
} else {
Coords coords = startPoint.getInhomCoordsInD3();
t.setAbsoluteScreenLoc((int) coords.getX(),
(int) coords.getY());
t.setAbsoluteScreenLocActive(true);
}
// when not a point clicked, show text only in
// active
// view
if (activeView.isEuclidianView3D()) {
// we need to add it to 3D view since by default
// it may not
kernel.getApplication().addToViews3D(t);
app.removeFromEuclidianView(t);
t.setVisibleInViewForPlane(false);
kernel.getApplication()
.removeFromViewsForPlane(t);
} else if (activeView.isDefault2D()) {
if (kernel.getApplication()
.isEuclidianView3Dinited()) {
kernel.getApplication()
.removeFromViews3D(t);
} else {
t.removeViews3D();
}
t.setVisibleInViewForPlane(false);
kernel.getApplication()
.removeFromViewsForPlane(t);
} else { // view for plane
app.removeFromEuclidianView(t);
if (kernel.getApplication()
.isEuclidianView3Dinited()) {
kernel.getApplication()
.removeFromViews3D(t);
} else {
t.removeViews3D();
}
t.setVisibleInViewForPlane(true);
kernel.getApplication().addToViewsForPlane(t);
}
}
// make sure (only) the output of the text tool is
// selected
activeView.getEuclidianController()
.memorizeJustCreatedGeos(t.asArray());
t.updateRepaint();
}
}
private void focus() {
if (inputPanel.getTextAreaComponent() != null) {
// probably this branch will run (rows > 1)
if (Browser.isFirefox()) {
// Code that works in Firefox but not in IE and Chrome
inputPanel.getTextAreaComponent().getTextArea().getElement()
.blur();
inputPanel.getTextAreaComponent().getTextArea().getElement()
.focus();
} else {
// Code that works in Chrome but not in Firefox
inputPanel.getTextAreaComponent().getTextArea().setFocus(false);
inputPanel.getTextAreaComponent().getTextArea().setFocus(true);
}
} else if (inputPanel.getTextComponent() != null) {
// what if? educated guess
inputPanel.getTextComponent().setFocus(false);
inputPanel.getTextComponent().setFocus(true);
}
}
@Override
public void reInitEditor(GeoText text, GeoPointND startPoint2,
boolean rw1) {
if (editor == null) {
createTextGUI(dialogTitle, "", false, cols, rows, /* false */true,
false,
false, false, DialogType.DynamicText);
// return;
}
isTextMode = app.getMode() == EuclidianConstants.MODE_TEXT;
this.startPoint = startPoint2;
this.rw = rw1;
setGeoText(text);
focus();
}
private void setGeoText(GeoText geo) {
// handlingDocumentEventOff = true;
editGeo = geo;
editor.setEditGeo(geo);
//isLaTeX = geo == null ? false : geo.isLaTeX();
inputPanel.getTextAreaComponent().setText(geo);
// inputPanel.getTextAreaComponent().setCaretPosition(0);
//editor.setCaretPosition(0);
// cbLaTeX.setSelected(false);
// if (isLaTeX) {
// cbLaTeX.doClick();
// }
// handlingDocumentEventOff = false;
// updatePreviewText();
// editOccurred = false;
}
@Override
public void setLabels(){
super.setLabels();
if(editor != null){
editor.setLabels();
}
}
/*
* @Override public void setVisible(boolean visible) {
*
* inputPanel.setVisible(visible); wrappedPopup.setVisible(visible); if
* (visible){ inputPanel.setTextComponentFocus(); }else{ if(app!=null){
* app.setErrorHandler(null); } } }
*/
}