package org.geogebra.common.gui.dialog; import java.util.ArrayList; import java.util.Iterator; import java.util.TreeSet; import org.geogebra.common.euclidian.EuclidianConstants; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.Macro; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.main.App; import org.geogebra.common.util.Exercise; import org.geogebra.common.util.GeoAssignment; import org.geogebra.common.util.debug.Log; /** * Model for the ToolCreationDialog * * @author Christoph * */ public class ToolCreationDialogModel { // private Kernel kernel; private App app; // Drop Down Lists private ToolInputOutputList inputAddList; private ToolInputOutputList outputAddList; // List Boxes private ToolInputOutputList inputList; private ToolInputOutputList outputList; // Change Listener private ToolInputOutputListener listener; private Macro newTool; /** * @param app * application * @param listener * listener for changes in the ToolModel to update the view */ public ToolCreationDialogModel(App app, ToolInputOutputListener listener) { this.app = app; // this.kernel = app.getKernel(); this.listener = listener; initLists(); } @SuppressWarnings("serial") private void initLists() { inputAddList = new ToolInputOutputList() { private static final long serialVersionUID = 1L; @Override public boolean remove(Object geo) { boolean ret = super.remove(geo); outputList.remove(geo); return ret; } }; outputAddList = new ToolInputOutputList(); inputList = new ToolInputOutputList() { @Override public boolean add(GeoElement geo) { if (!geo.hasChildren() || contains(geo)) { return false; } // add geo to list boolean ret = super.add(geo); if (ret) { inputAddList.remove(geo); } return ret; } }; outputList = new ToolInputOutputList() { @Override public boolean add(GeoElement geo) { if (geo.isIndependent() || contains(geo)) { return false; } // add geo to list boolean ret = super.add(geo); if (ret) { outputAddList.remove(geo); } return ret; } }; } /** * Adds all possible input and output Geos to addLists should be called as * before addSelectedGeosToOutput */ public void initAddLists() { if (inputAddList.size() == 0 || outputAddList.size() == 0) { TreeSet<GeoElement> sortedSet = app.getKernel().getConstruction() .getGeoSetNameDescriptionOrder(); Iterator<GeoElement> it = sortedSet.iterator(); while (it.hasNext()) { GeoElement geo = it.next(); if (geo.hasChildren()) { inputAddList.add(geo); } if (!geo.isIndependent()) { outputAddList.add(geo); } } } listener.updateLists(); } /** * Adds selected Geos to outputList if outputList is empty */ public void addSelectedGeosToOutput() { if (outputList.size() == 0) { ArrayList<GeoElement> selGeos = app.getSelectionManager() .getSelectedGeos(); for (int i = 0; i < selGeos.size(); i++) { GeoElement geo = selGeos.get(i); outputList.add(geo); } } listener.updateLists(); } /** * Updates the list of input objects by using the specified output objects. */ public void updateInputList() { // only change empty input list if (inputList.size() > 0) { return; } // get output objects GeoElement[] output = outputList.toGeoElements(); // determine all free parents of output TreeSet<GeoElement> freeParents = new TreeSet<GeoElement>(); for (int i = 0; i < output.length; i++) { output[i].addPredecessorsToSet(freeParents, true); } // fill input list with labeled free parents Iterator<GeoElement> it = freeParents.iterator(); while (it.hasNext()) { GeoElement geo = it.next(); if (geo.isVisibleInputForMacro()) { inputList.add(geo); } } listener.updateLists(); } /** * Tries to create a new Macro to decide whether finish button should be * shown * * @return false if creation of Macro fails, else true */ public boolean createTool() { // get input and output objects GeoElement[] input = inputList.toGeoElements(); GeoElement[] output = outputList.toGeoElements(); // try to create macro Kernel kernel = app.getKernel(); try { newTool = new Macro(kernel, "newTool", input, output); return true; } catch (Exception e) { // show error message app.showError(app.getLocalization().getError("Tool.CreationFailed") + "\n" + e.getMessage()); e.printStackTrace(); newTool = null; return false; } } /** * Finish creation of user defined tool * * @param appToSave * application in which the macro should be saved (differnt from * current if in macro editing mode) * @param cmdName * command name of the macro * @param toolName * name of the macro * @param toolHelp * help for the tool (might be empty) * @param showInToolBar * whether the tool should be shown in toolbar, might be a empty * string * @param iconFileName * fileName of the Icon to use for the macro, might be a empty * string * @return true if successful and false if a macro existed which could not * be overwritten because the new macro was not compatible with the * old. */ public boolean finish(App appToSave, String cmdName, String toolName, String toolHelp, boolean showInToolBar, String iconFileName) { newTool.setCommandName(cmdName); newTool.setToolName(toolName); newTool.setToolHelp(toolHelp); newTool.setShowInToolBar(showInToolBar); newTool.setIconFileName(iconFileName); // make sure new macro command gets into dictionary appToSave.updateCommandDictionary(); Kernel kernel = appToSave.getKernel(); // check if command name is not used already by another macro if (kernel.getMacro(cmdName) != null) { return overwriteMacro(kernel.getMacro(cmdName)); } kernel.addMacro(newTool); // make sure new macro command gets into dictionary appToSave.updateCommandDictionary(); // set macro mode if (newTool.isShowInToolBar()) { newTool.setViewId( app.getGuiManager().getActiveEuclidianView().getViewID()); int mode = kernel.getMacroID(newTool) + EuclidianConstants.MACRO_MODE_ID_OFFSET; appToSave.getGuiManager().addToToolbarDefinition(mode); appToSave.getGuiManager().updateToolbar(); appToSave.setMode(mode); } return true; } /** * Overwrites an existing macro with the macro (without warning) * * @param macro * the new user defined tool * @return true if the existing macro was overwritten, false if the macro * was not compatible with the old */ public boolean overwriteMacro(Macro macro) { boolean compatible = newTool.getNeededTypesString() .equals(macro.getNeededTypesString()); for (int i = 0; compatible && i < macro.getMacroOutput().length; i++) { compatible = compatible && macro.getMacroOutput()[i].getClass() .equals(newTool.getMacroOutput()[i].getClass()); } Kernel kernel = macro.getKernel(); App appToSave = kernel.getApplication(); if (compatible) { StringBuilder sb = new StringBuilder(); newTool.getXML(sb); Exercise ex = app.getKernel().getExercise(); GeoAssignment assignment = ex.getAssignment(macro); int assignmentIndex = ex.getParts().indexOf(assignment); if (app.getMacro() != null) { kernel.removeMacro(app.getMacro()); } else { kernel.removeMacro(macro); } if (appToSave.addMacroXML(sb.toString())) { // successfully saved, quitting appToSave.setXML(appToSave.getXML(), true); if (app.getMacro() != null) { app.setSaved(); // app.exit(); TODO! goto last window... } if (assignment != null) { assignment.setMacro(newTool); ex.addAssignment(assignmentIndex, assignment); } } return true; } Log.debug("not compatible"); return false; } public GeoElement[] getInputAddList() { return inputAddList.toGeoElements(); } public GeoElement[] getOutputAddList() { return outputAddList.toGeoElements(); } public GeoElement[] getInputList() { return inputList.toGeoElements(); } public GeoElement[] getOutputList() { return outputList.toGeoElements(); } public Macro getNewTool() { return newTool; } public void addToOutput(GeoElement geo) { outputList.add(geo); listener.updateLists(); } public void addToOutput(int selectedIndex) { if (selectedIndex >= 0) { addToOutput(outputAddList.get(selectedIndex)); } } public void addToInput(GeoElement geo) { inputList.add(geo); listener.updateLists(); } public void addToInput(int selectedIndex) { if (selectedIndex >= 0) { addToInput(inputAddList.get(selectedIndex)); } } public void removeFromOutput(ArrayList<Integer> selIndices) { for (int i = selIndices.size() - 1; i >= 0; i--) { int selectedIndex = selIndices.get(i); outputAddList.add(outputList.remove(selectedIndex)); // TODO insert // sorted } listener.updateLists(); } public void removeFromInput(ArrayList<Integer> selIndices) { for (int i = selIndices.size() - 1; i >= 0; i--) { int selectedIndex = selIndices.get(i); inputAddList.add(inputList.remove(selectedIndex)); // TODO insert // sorted } listener.updateLists(); } public void moveOutputUp(ArrayList<Integer> selIndices) { for (int i = 0; i < selIndices.size(); i++) { int selectedIndex = selIndices.get(i); if (selectedIndex > 0) { GeoElement geo = outputList.remove(selectedIndex); outputList.add(selectedIndex - 1, geo); selIndices.set(i, selectedIndex - 1); } } listener.updateLists(); } public void moveOutputDown(ArrayList<Integer> selIndices) { for (int i = selIndices.size() - 1; i >= 0; i--) { int selectedIndex = selIndices.get(i); if (selectedIndex < outputList.size() - 1) { GeoElement geo = outputList.remove(selectedIndex); outputList.add(selectedIndex + 1, geo); selIndices.set(i, selectedIndex + 1); } } listener.updateLists(); } public void moveInputUp(ArrayList<Integer> selIndices) { for (int i = 0; i < selIndices.size(); i++) { int selectedIndex = selIndices.get(i); if (selectedIndex > 0) { GeoElement geo = inputList.remove(selectedIndex); inputList.add(selectedIndex - 1, geo); selIndices.set(i, selectedIndex - 1); } } listener.updateLists(); } public void moveInputDown(ArrayList<Integer> selIndices) { for (int i = selIndices.size() - 1; i >= 0; i--) { int selectedIndex = selIndices.get(i); if (selectedIndex < inputList.size() - 1) { GeoElement geo = inputList.remove(selectedIndex); inputList.add(selectedIndex + 1, geo); selIndices.set(i, selectedIndex + 1); } } listener.updateLists(); } public void setFromMacro(Macro macro) { for (int i = 0; i < macro.getMacroInput().length; i++) { GeoElement el = app.getKernel().lookupLabel(macro.getMacroInput()[i] .getLabel(StringTemplate.defaultTemplate)); if (el != null) { this.inputList.add(0, el); } } for (int i = 0; i < macro.getMacroOutput().length; i++) { GeoElement el = app.getKernel() .lookupLabel(macro.getMacroOutput()[i] .getLabel(StringTemplate.defaultTemplate)); if (el != null) { this.outputList.add(0, el); } } } }