package org.geogebra.web.web.gui.view.algebra; 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.kernel.Kernel; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.main.Feature; import org.geogebra.common.util.AsyncOperation; 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.util.CancelEventTimer; import org.geogebra.web.html5.gui.util.ClickStartHandler; import org.geogebra.web.web.gui.inputbar.AlgebraInputW; import org.geogebra.web.web.gui.inputfield.InputSuggestions; import com.google.gwt.canvas.client.Canvas; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.Widget; import com.himamis.retex.editor.share.model.MathFormula; import com.himamis.retex.editor.share.serializer.TeXSerializer; import com.himamis.retex.editor.web.MathFieldW; import com.himamis.retex.renderer.share.CursorBox; /** * * @author Zbynek * */ public class LatexTreeItem extends RadioTreeItem { // implements MathFieldListener { private MathFieldW mf; /** * @param geo0 * geo element */ public LatexTreeItem(GeoElement geo0) { super(geo0); getWidget().addStyleName("latexEditor"); } /** * @param kernel * Kernel */ public LatexTreeItem(Kernel kernel) { super(kernel); this.insertHelpToggle(); if (app.has(Feature.AV_INPUT_BUTTON_COVER)) { content.addStyleName("scrollableTextBox"); if (isInputTreeItem()) { content.addStyleName("inputBorder"); } } getWidget().addStyleName("latexEditor"); content.addStyleName("noPreview"); renderLatex("", false); } @Override protected RadioTreeItemController createController() { return new LatexTreeItemController(this); } /** * * @return The controller as LatexTreeItemController. */ public LatexTreeItemController getLatexController() { return (LatexTreeItemController) getController(); } @Override public void showKeyboard() { getLatexController().showKeyboard(); } /** * @param old * what to replace */ private void renderLatex(String text0, boolean showKeyboard) { // if (!forceMQ) { // canvas = DrawEquationW.paintOnCanvas(geo, text0, canvas, // getFontSize()); // // if (canvas != null && ihtml.getElement().isOrHasChild(old)) { // ihtml.getElement().replaceChild(canvas.getCanvasElement(), old); // } // // } // latexItem.addStyleName("avTextItem"); // TODO updateColor(latexItem); content.clear(); if (app.has(Feature.AV_SINGLE_TAP_EDIT) && !(latexItem == null || isInputTreeItem() || isSliderItem())) { latexItem.getElement().getStyle().setProperty("minHeight", getController().getEditHeigth() + "px"); } ensureCanvas(); appendCanvas(); if (!content.isAttached()) { main.add(content); } setText(text0); getLatexController().initAndShowKeyboard(showKeyboard); } private void appendCanvas() { if (latexItem == null) { latexItem = new FlowPanel(); } latexItem.clear(); latexItem.add(canvas); content.add(latexItem); } /** * @return whether canvas was created */ protected boolean ensureCanvas() { if (canvas == null) { canvas = Canvas.createIfSupported(); initMathField(); return true; } if (mf == null) { initMathField(); } return false; } private void initMathField() { if (latexItem == null) { latexItem = new FlowPanel(); } mf = new MathFieldW(latexItem, canvas, getLatexController(), app.has(Feature.DIRECT_FORMULA_CONVERSION)); mf.setFontSize(getFontSize()); mf.setPixelRatio(app.getPixelRatio()); mf.setOnBlur(getLatexController()); } @Override public void setFocus(boolean focus, boolean sv) { if (focus) { removeDummy(); } if (app.has(Feature.AV_INPUT_BUTTON_COVER)) { if (focus) { content.addStyleName("scrollableTextBox"); if (isInputTreeItem()) { MinMaxPanel.closeMinMaxPanel(); if (app.has(Feature.AV_SINGLE_TAP_EDIT)) { getAV().restoreWidth(true); } else { setItemWidth(getAV().getOffsetWidth()); } } } else { if (isInputTreeItem()) { setItemWidth(getAV().getMaxItemWidth()); } else { content.removeStyleName("scrollableTextBox"); } //this.getAV().setActiveTreeItem(null); } } if (ensureCanvas()) { main.clear(); main.add(this.marblePanel); if (isInputTreeItem()) { appendCanvas(); } main.add(content); if (controls != null) { main.add(controls); updateButtonPanelPosition(); } } if (focus) { preventBlur(); canvas.setVisible(true); } else { if (geo == null && errorMessage == null) { addDummyLabel(); } } mf.setFocus(focus); int kH = (int) (app.getAppletFrame().getKeyboardHeight()); if (getAlgebraDockPanel().getOffsetHeight() < kH) { app.adjustViews(true); } } @Override public String getText() { if (mf == null) { return ""; } GeoGebraSerializer s = new GeoGebraSerializer(); return s.serialize(mf.getFormula()); } @Override public void onEnter(final boolean keepFocus) { getLatexController().onEnter(keepFocus); } @Override public void setText(String text0) { if (!"".equals(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(); } } updatePreview(); } @Override public void setLabels() { if (dummyLabel != null) { dummyLabel.setText(loc.getPlain("InputLabel") + Unicode.ellipsis); super.setLabels(); } } @Override public String getCommand() { return mf == null ? "" : mf.getCurrentWord(); } @Override public void autocomplete(String text) { getLatexController().autocomplete(text); } @Override protected void focusAfterHelpClosed() { getController().setFocus(true); } /** * Update after key was typed */ public void onKeyTyped() { this.removeDummy(); app.closePerspectivesPopup(); updatePreview(); popupSuggestions(); onCursorMove(); } /** * Cursor listener */ public void onCursorMove() { if (latexItem.getOffsetWidth() + latexItem.getElement().getScrollLeft() - 10 < CursorBox.startX) { latexItem.getElement().setScrollLeft( (int) CursorBox.startX - latexItem.getOffsetWidth() + 10); } else if (CursorBox.startX < latexItem.getElement().getScrollLeft() + 10) { latexItem.getElement().setScrollLeft((int) CursorBox.startX - 10); } } @Override public boolean popupSuggestions() { return getInputSuggestions().popupSuggestions(); } /** * @return suggestions model */ InputSuggestions getInputSuggestions() { return getLatexController().getInputSuggestions(); } private void updatePreview() { if (getController().isInputAsText()) { return; } String text = getText(); app.getKernel() .getInputPreviewHelper() .updatePreviewFromInputBar(text, AlgebraInputW.getWarningHandler(this, app)); } @Override public RadioTreeItem copy() { return new LatexTreeItem(geo); } @Override public void insertString(String text) { new MathFieldProcessing(mf).autocomplete(text); } @Override public void cancelEditing() { this.stopEditing(null, null); } @Override protected void blurEditor() { // TODO Auto-generated method stub } @Override protected void renderLatex(String text0, Widget w, boolean forceMQ) { if (forceMQ) { // TODO // editLatexMQ(text0); } else { replaceToCanvas(text0, w); } } @Override protected void clearInput() { setText(""); } @Override public void handleFKey(int key, GeoElement geoElement) { // TODO Auto-generated method stub } @Override protected void updateGUIfocus(Object source, boolean blurtrue) { if (geo == null) { updateEditorFocus(source, blurtrue); } } @Override public List<String> getCompletions() { return getInputSuggestions().getCompletions(); } @Override public List<String> resetCompletions() { return getInputSuggestions().resetCompletions(); } @Override public boolean getAutoComplete() { return true; } @Override public boolean isSuggesting() { return getLatexController().isSuggesting(); } @Override public void setPixelRatio(double pixelRatio) { if (mf != null) { mf.setPixelRatio(pixelRatio); mf.repaint(); } } @Override protected void updateAfterRedefine(boolean success) { if (mf != null && success) { mf.setEnabled(false); } super.updateAfterRedefine(success); } @Override public boolean isInputTreeItem() { return getAV().getInputTreeItem() == this; } @Override protected void updateButtonPanelPosition() { super.updateButtonPanelPosition(); if (isInputTreeItem() && !getController().isEditing()) { // getAlgebraDockPanel().scrollToActiveItem(); } } /** * @return math field */ public MathFieldW getMathField() { return mf; } @Override public boolean onEditStart(boolean substituteNumbers) { String text = geo == null ? "" : geo.getDefinitionForEditor(); if (geo != null && !geo.isDefined() && lastInput != null) { text = lastInput; } if (text == null) { return false; } clearErrorLabel(); removeDummy(); renderLatex(text, true); getMathField().requestViewFocus(); app.getGlobalKeyDispatcher().setFocused(true); // canvas.addBlurHandler(getLatexController()); CancelEventTimer.keyboardSetVisible(); ClickStartHandler.init(main, new ClickStartHandler(false, false) { @Override public void onClickStart(int x, int y, final PointerEventType type) { getLatexController().setOnScreenKeyboardTextField(); } }); return true; } @Override public void adjustCaret(int x, int y) { if (mf != null) { mf.adjustCaret(x, y); } } @Override public void updateFonts() { if (mf != null) { mf.setFontSize(getFontSize()); } super.updateFonts(); } @Override protected String getEditorLatex() { return mf == null ? null : TeXSerializer.serialize(mf.getFormula().getRootComponent(), mf.getMetaModel()); } @Override protected void doUpdate() { if (mf != null) { mf.setEnabled(false); } super.doUpdate(); } @Override public void preventBlur() { ((LatexTreeItemController) getController()).preventBlur(); } @Override protected boolean showSliderDialog(final String string, final AsyncOperation<String[]> callback) { Runnable r = new Runnable() { @Override public void run() { app.getGuiManager().checkAutoCreateSliders(string, new AsyncOperation<String[]>() { @Override public void callback(String[] obj) { callback.callback(obj); listenToBlur(); } }); } }; if (mf != null) { mf.setOnBlur(null); mf.checkEnterReleased(r); } else { r.run(); } return false; } /** * Start listening to blur events */ protected void listenToBlur(){ mf.setOnBlur(getLatexController()); } /** * Switches editor to text mode * * @param value * switches editor to text mode */ protected void setInputAsText(boolean value) { mf.setPlainTextMode(value); } }