package org.geogebra.web.web.cas.view; import java.util.ArrayList; import java.util.List; import org.geogebra.common.euclidian.event.PointerEventType; import org.geogebra.common.io.latex.GeoGebraSerializer; import org.geogebra.common.io.latex.ParseException; import org.geogebra.common.io.latex.Parser; import org.geogebra.common.main.App; import org.geogebra.common.main.Feature; import org.geogebra.common.util.StringUtil; import org.geogebra.common.util.debug.Log; import org.geogebra.common.util.lang.Unicode; import org.geogebra.web.editor.MathFieldProcessing; import org.geogebra.web.html5.gui.GuiManagerInterfaceW; import org.geogebra.web.html5.gui.inputfield.AbstractSuggestionDisplay; import org.geogebra.web.html5.gui.util.CancelEventTimer; import org.geogebra.web.html5.gui.util.ClickStartHandler; import org.geogebra.web.html5.gui.util.MathKeyboardListener; import org.geogebra.web.html5.main.AppW; import org.geogebra.web.web.gui.GuiManagerW; import org.geogebra.web.web.gui.inputfield.InputSuggestions; import org.geogebra.web.web.gui.view.algebra.RetexKeyboardListener; import org.geogebra.web.web.main.AppWFull; import com.google.gwt.canvas.client.Canvas; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.BlurHandler; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Widget; import com.himamis.retex.editor.share.event.MathFieldListener; import com.himamis.retex.editor.share.meta.MetaModel; import com.himamis.retex.editor.share.model.MathFormula; import com.himamis.retex.editor.share.model.MathSequence; import com.himamis.retex.editor.share.serializer.TeXSerializer; import com.himamis.retex.editor.web.MathFieldW; /** * ReTeX editor for CAS * */ public class CASLaTeXEditor extends FlowPanel implements CASEditorW, MathKeyboardListener, MathFieldListener, BlurHandler { /** suggestions */ InputSuggestions sug; private MathFieldW mf; /** keyboard connector */ RetexKeyboardListener retexListener; private AppWFull app; private CASTableW table; private CASTableControllerW controller; private boolean autocomplete = true; private Widget dummy; /** * @param table * table * @param app * application * @param controller * controller */ public CASLaTeXEditor(CASTableW table, final AppW app, final CASTableControllerW controller) { this.app = (AppWFull) app; this.table = table; this.controller = controller; Canvas canvas = Canvas.createIfSupported(); mf = new MathFieldW(this, canvas, this, app.has(Feature.DIRECT_FORMULA_CONVERSION)); retexListener = new RetexKeyboardListener(canvas, mf); mf.setOnBlur(this); add(mf); dummy = new Label( app.getLocalization().getMenu("InputLabel") + Unicode.ellipsis); dummy.getElement().getStyle().setMarginLeft(5, Unit.PX); } public void onBlur(BlurEvent event) { // autocommitting empty text produces $1 if (!isSuggesting()) { onEnter(false); } } @Override public int getInputSelectionEnd() { // TODO Auto-generated method stub return 0; } @Override public int getInputSelectionStart() { // TODO Auto-generated method stub return 0; } @Override public String getInputSelectedText() { // TODO Auto-generated method stub return null; } @Override public String getText() { if (mf == null) { return ""; } GeoGebraSerializer s = new GeoGebraSerializer(); return s.serialize(mf.getFormula()); } @Override public String getLaTeX() { if (mf == null) { return ""; } TeXSerializer s = new TeXSerializer(new MetaModel()); return s.serialize(mf.getFormula()); } @Override public String getInput() { return getText(); } @Override public void setInputSelectionStart(int selStart) { // TODO Auto-generated method stub } @Override public void setInputSelectionEnd(int selEnd) { // TODO Auto-generated method stub } @Override public void clearInputText() { setText(""); } @Override public void setInput(String string) { if (getWidget(0) != mf.asWidget()) { setWidget(mf.asWidget()); } setText(string); } private void setWidget(Widget asWidget) { insert(asWidget, 0); } @Override public void setText(String text0) { // removeDummy(); if (mf != null) { Parser parser = new Parser(mf.getMetaModel()); MathFormula formula; try { formula = parser.parse(text0); mf.setFormula(formula); } catch (ParseException e) { Log.warn("Problem parsing: " + text0); e.printStackTrace(); } } // updateLineHeight(); } @Override public Object getCellEditorValue(int index) { if (table != null) { return table.getGeoCasCell(index); } return null; } @Override public void setLabels() { // TODO Auto-generated method stub } @Override public void setFocus(boolean focus, boolean scheduled) { remove(focus ? dummy : mf); setWidget(focus ? mf.asWidget() : dummy); mf.setFocus(focus); } @Override public void onEnter(boolean keepFocus) { // TODO Auto-generated method stub if (sug != null && sug.needsEnterForSuggestion()) { return; } // got here by blur: do not use previous cell ref if (!keepFocus && StringUtil.empty(getText())) { this.setFocus(false, false); return; } this.controller.handleEnterKey(false, false, app, keepFocus); } @Override public void resetInput() { // TODO Auto-generated method stub } @Override public void setAutocomplete(boolean b) { this.autocomplete = b; } @Override public void setLaTeX(String plain, String latex) { // not needed } @Override public void ensureEditing() { final GuiManagerInterfaceW gui = app.getGuiManager(); gui.setOnScreenKeyboardTextField(this.retexListener); CancelEventTimer.keyboardSetVisible(); ClickStartHandler.init(this, new ClickStartHandler(false, false) { @Override public void onClickStart(int x, int y, final PointerEventType type) { doClickStart(); gui.setActivePanelAndToolbar(App.VIEW_CAS); } }); setFocus(true, false); } /** * Click start callback */ protected void doClickStart() { setFocus(true, false); app.showKeyboard(retexListener); // prevent that keyboard is closed on clicks (changing // cursor position) CancelEventTimer.keyboardSetVisible(); } @Override public boolean getAutoComplete() { return autocomplete; } @Override public List<String> resetCompletions() { return getInputSuggestions().resetCompletions(); } @Override public List<String> getCompletions() { return getInputSuggestions().getCompletions(); } @Override public void insertString(String text) { new MathFieldProcessing(mf).autocomplete(text); } @Override public void toggleSymbolButton(boolean toggled) { // only for linear input } @Override public ArrayList<String> getHistory() { // TODO Auto-generated method stub return null; } @Override public boolean isSuggesting() { return sug != null && sug.isSuggesting(); } @Override public void requestFocus() { if (getWidget(0) != mf.asWidget()) { setWidget(mf.asWidget()); } mf.requestViewFocus(); } @Override public Widget toWidget() { return this; } @Override public void autocomplete(String text) { GuiManagerW.makeKeyboardListener(retexListener).insertString(text); } @Override public void updatePosition(AbstractSuggestionDisplay sugPanel) { sugPanel.setPositionRelativeTo(this); } @Override public boolean isForCAS() { return true; } @Override public String getCommand() { return mf == null ? "" : mf.getCurrentWord(); } private InputSuggestions getInputSuggestions() { if (sug == null) { sug = new InputSuggestions(app, this); } return sug; } @Override public void onEnter() { // TODO or onEnter(false) ? onEnter(true); } @Override public void onKeyTyped() { // TODO Auto-generated method stub getInputSuggestions().popupSuggestions(); } @Override public boolean needsAutofocus() { return true; } @Override public void onCursorMove() { // TODO Auto-generated method stub } @Override public String alt(int unicodeKeyChar, boolean shift) { return retexListener.alt(unicodeKeyChar, shift); } @Override public void onUpKeyPressed() { if (isSuggesting()) { sug.onKeyUp(); } } @Override public void onDownKeyPressed() { if (isSuggesting()) { sug.onKeyDown(); } } @Override public String serialize(MathSequence selectionText) { return GeoGebraSerializer.serialize(selectionText); } @Override public void onInsertString() { mf.setFormula(GeoGebraSerializer.reparse(this.mf.getFormula())); } public boolean onEscape() { // TODO Auto-generated method stub return false; } public boolean hasFocus() { return mf.hasFocus(); } }