package org.geogebra.desktop.euclidian; import java.awt.Point; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; import java.util.ArrayList; import javax.swing.AbstractAction; import javax.swing.JComponent; import javax.swing.TransferHandler; import org.geogebra.common.euclidian.EuclidianView; import org.geogebra.common.kernel.arithmetic.TextValue; import org.geogebra.common.kernel.geos.GeoText; import org.geogebra.common.kernel.kernelND.GeoElementND; import org.geogebra.common.main.App; import org.geogebra.common.util.debug.Log; import org.geogebra.desktop.euclidianND.EuclidianViewInterfaceD; import org.geogebra.desktop.gui.GuiManagerD; import org.geogebra.desktop.gui.view.data.PlotPanelEuclidianViewD; import org.geogebra.desktop.main.AppD; import org.geogebra.desktop.util.AlgebraViewTransferHandler; import org.geogebra.desktop.util.CASTransferHandler; /** * Transfer handler for EuclidianView * * @author G. Sturr * */ public class EuclidianViewTransferHandler extends TransferHandler implements Transferable { private static final long serialVersionUID = 1L; private EuclidianView ev; private AppD app; static DataFlavor textReaderFlavor; static { try { textReaderFlavor = new DataFlavor( "text/plain;class=java.io.Reader"); } catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); } } // supported data flavors private static volatile DataFlavor supportedFlavors[] = null;// { // null,//DataFlavor.imageFlavor, // null,//DataFlavor.stringFlavor, // null,//DataFlavor.javaFileListFlavor, // null,//AlgebraViewTransferHandler.algebraViewFlavor, // null};//PlotPanelEuclidianView.plotPanelFlavor}; private void setSupportedFlavours() { if (supportedFlavors == null) { DataFlavor[] supportedFlavors0; if (app.isUsingFullGui()) { supportedFlavors0 = new DataFlavor[5]; supportedFlavors0[0] = DataFlavor.imageFlavor; supportedFlavors0[1] = DataFlavor.stringFlavor; supportedFlavors0[2] = DataFlavor.javaFileListFlavor; supportedFlavors0[3] = AlgebraViewTransferHandler.algebraViewFlavor; supportedFlavors0[4] = PlotPanelEuclidianViewD.plotPanelFlavor; } else { supportedFlavors0 = new DataFlavor[3]; supportedFlavors0[0] = DataFlavor.imageFlavor; supportedFlavors0[1] = DataFlavor.stringFlavor; supportedFlavors0[2] = DataFlavor.javaFileListFlavor; } supportedFlavors = supportedFlavors0; } } /**************************************** * Constructor * * @param ev * euclidian view */ public EuclidianViewTransferHandler(EuclidianView ev) { this.ev = ev; this.app = (AppD) ev.getApplication(); } /** * Ensures that transfer are done in COPY mode */ @Override public int getSourceActions(JComponent c) { return TransferHandler.COPY; } /** * Returns true if any element of the DataFlavor parameter array is a * supported flavor. */ @Override public boolean canImport(JComponent comp, DataFlavor flavor[]) { setSupportedFlavours(); for (int i = 0, n = flavor.length; i < n; i++) { // System.out.println(flavor[i].getMimeType()); for (int j = 0, m = supportedFlavors.length; j < m; j++) { if (flavor[i].equals(supportedFlavors[j])) { return true; } } } return false; } /** * Handles data import. */ @Override public boolean importData(JComponent comp, Transferable t) { // give the drop target (this EV) the view focus requestViewFocus(); Point mousePos = ((EuclidianViewInterfaceD) ev).getMousePosition(); // ------------------------------------------ // Import handling is done in this order: // 1) PlotPanel GeoElement copies // 2) Images // 3) Text // 4) CASTableCells // 5) GGB files // ------------------------------------------ // try to get PlotPanel GeoElement copies if (t.isDataFlavorSupported(PlotPanelEuclidianViewD.plotPanelFlavor)) { try { AbstractAction act = (AbstractAction) t.getTransferData( PlotPanelEuclidianViewD.plotPanelFlavor); act.putValue("euclidianViewID", ev.getViewID()); act.actionPerformed(new ActionEvent(act, 0, null)); } catch (UnsupportedFlavorException e) { e.printStackTrace(); return false; } catch (IOException e) { e.printStackTrace(); return false; } return true; } // try to get an image boolean imageDropped = ((GuiManagerD) ev.getApplication() .getGuiManager()).loadImage(t, false); if (imageDropped) { return true; } // handle CAS table cells as simple latex string (not dynamic!!) // ToDo: make it dynamic (after ticket 2449 is finished) DataFlavor[] df = t.getTransferDataFlavors(); for (DataFlavor d : df) { Log.debug(d); } if (t.isDataFlavorSupported(CASTransferHandler.casTableFlavor)) { try { // after it is possible to refer to cas cells with "$1" we can // refer dynamically // String tableRef; StringBuilder sb = new StringBuilder("FormulaText[$"); sb.append(1 + (Integer) t .getTransferData(CASTransferHandler.casTableFlavor)); sb.append("]"); // tableRef = "$" + (cellnumber+1); // create a GeoText on the specific mouse position GeoElementND[] ret = ev.getApplication().getKernel() .getAlgebraProcessor() .processAlgebraCommandNoExceptionsOrErrors( sb.toString(), false); if (ret != null && ret[0] instanceof TextValue) { GeoText geo = (GeoText) ret[0]; geo.setLaTeX(true, false); // TODO: h should equal the geo height, this is just an // estimate double h = 2 * app.getFontSize(); geo.setRealWorldLoc(ev.toRealWorldCoordX(mousePos.x), ev.toRealWorldCoordY(mousePos.y - h)); geo.updateRepaint(); app.storeUndoInfo(); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } // check for ggb file drop boolean ggbFileDropped = ((GuiManagerD) app.getGuiManager()) .handleGGBFileDrop(t); if (ggbFileDropped) { return true; } // handle all text flavors if (t.isDataFlavorSupported(DataFlavor.stringFlavor) || t.isDataFlavorSupported( AlgebraViewTransferHandler.algebraViewFlavor)) { try { String text = null; // expression to be converted into GeoText boolean isLaTeX = false; // get text from AlgebraView flavor if (t.isDataFlavorSupported( AlgebraViewTransferHandler.algebraViewFlavor)) { isLaTeX = true; // get list of selected geo labels ArrayList<String> list = (ArrayList<String>) t .getTransferData( AlgebraViewTransferHandler.algebraViewFlavor); text = EuclidianView.getDraggedLabels(list); if (text == null) { return false; } } // get text from String flavor else { try { // first try to read text line-by-line Reader r = textReaderFlavor.getReaderForText(t); if (r != null) { StringBuilder sb = new StringBuilder(); String line = null; BufferedReader br = new BufferedReader(r); line = br.readLine(); while (line != null) { sb.append(line + "\n"); line = br.readLine(); } br.close(); text = sb.toString(); } } catch (Exception e) { Log.debug("Caught exception decoding text transfer:" + e.getMessage()); } // if the reader didn't work, try to get whatever string is // available if (text == null) { text = (String) t .getTransferData(DataFlavor.stringFlavor); } // exit if no text found if (text == null) { return false; } // TODO --- validate the text? e.g. no quotes for a GeoText // wrap text in quotes text = "\"" + text + "\""; } // --------------------------------- // create GeoText GeoElementND[] ret = ev.getApplication().getKernel() .getAlgebraProcessor() .processAlgebraCommand(text, true); if (ret != null && ret[0] instanceof TextValue) { GeoText geo = (GeoText) ret[0]; geo.setLaTeX(isLaTeX, false); // TODO: h should equal the geo height, this is just an // estimate double h = 2 * app.getFontSize(); geo.setRealWorldLoc(ev.toRealWorldCoordX(mousePos.x), ev.toRealWorldCoordY(mousePos.y - h)); geo.updateRepaint(); } return true; } catch (UnsupportedFlavorException ignored) { // TODO } catch (IOException ignored) { // TODO } } return false; } /** * Sets the focus to this EV. TODO: use this view's id directly to set the * focus (current code assumes only 2 EVs) */ private void requestViewFocus() { if (ev.equals(app.getEuclidianView1())) { ((GuiManagerD) app.getGuiManager()).getLayout() .getDockManager().setFocusedPanel(App.VIEW_EUCLIDIAN); } else { ((GuiManagerD) app.getGuiManager()).getLayout() .getDockManager().setFocusedPanel(App.VIEW_EUCLIDIAN2); } } @Override public Transferable createTransferable(JComponent comp) { return null; } @Override public Object getTransferData(DataFlavor flavor) { return null; } @Override public DataFlavor[] getTransferDataFlavors() { return supportedFlavors; } @Override public boolean isDataFlavorSupported(DataFlavor flavor) { for (int i = 0; i < supportedFlavors.length; i++) { if (supportedFlavors[i].equals(flavor)) { return true; } } return false; } }