/** * Copyright (C) 2008-2010 Daniel Senff * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package de.danielsenff.imageflow.models; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; import de.danielsenff.imageflow.models.connection.Input; import de.danielsenff.imageflow.models.connection.Output; import de.danielsenff.imageflow.models.datatype.DataTypeFactory; import de.danielsenff.imageflow.models.datatype.ImageDataType; import de.danielsenff.imageflow.models.parameter.BooleanParameter; import de.danielsenff.imageflow.models.parameter.ChoiceParameter; import de.danielsenff.imageflow.models.parameter.DoubleParameter; import de.danielsenff.imageflow.models.parameter.IntegerParameter; import de.danielsenff.imageflow.models.parameter.Parameter; import de.danielsenff.imageflow.models.parameter.StringParameter; import de.danielsenff.imageflow.utils.Tools; /** * MacroElement is a processor class. It contains the ImageJ-syntax template. * Placeholders in this template will be replaced by concrete values during macro generation. * @author danielsenff * */ public class MacroElement { /** * the syntax that is to be used for this unit */ protected String imageJSyntax; /** * syntax with replaced variables */ protected String commandSyntax; /** * @param unitsImageJSyntax * */ public MacroElement(final String unitsImageJSyntax) { this.imageJSyntax = unitsImageJSyntax; this.commandSyntax = unitsImageJSyntax; } /** * Returns the ImageJ-Macro syntax of this unit. * This syntax is inserted in the macro and constructs the working flow. * @return */ public String getImageJSyntax() { return this.imageJSyntax; } /** * Returns the command-syntax with substituted variables. * @return */ public String getCommandSyntax() { return this.commandSyntax; } /** * Resets the MacroElement. All parsed commands will be removed. */ public void reset() { this.commandSyntax = this.imageJSyntax; } /** * @param searchString * @param parameterString */ public void replace(final String searchString, final String parameterString) { if(commandSyntax.contains(searchString)) { commandSyntax = Tools.replace(commandSyntax, searchString, parameterString); } } /** * Writes the values of the Parameters into the syntax. * @param parameters */ public void parseParameters(final ArrayList<Parameter> parameters) { this.commandSyntax = parseParameters(parameters, this.commandSyntax); } private static String parseParameters(ArrayList<Parameter> parameters, String command) { /** * my gut says, this should be refactored */ int parameterIndex = 0; // index of parameter in parameters collection int parameterCount = 0; // count of processed parameters int pd = 0, ps = 0, pi = 0, pb = 0; String searchString; String parameterString; Parameter parameter; Matcher matcher; while (parameterIndex < parameters.size()) { parameter = parameters.get(parameterIndex); //paraType = parameter.getParaType().toLowerCase(); searchString = "(PARA_DOUBLE_" + (pd+1) + ")(\\D)"; matcher = compileMatcherBy(searchString, command); if(matcher.find() && parameter instanceof DoubleParameter) { parameterString = "" + ((DoubleParameter)parameter).getValue(); command = matcher.replaceAll(parameterString+"$2"); // making sure, that we catch full numbers and not just single digits pd++; parameterIndex++; } // choiceParameter uses the PARA_STRING_x searchString = "(PARA_STRING_" + (ps+1) + ")(\\D)"; matcher = compileMatcherBy(searchString, command); boolean find = matcher.find(); if(find && (parameter instanceof StringParameter || parameter instanceof ChoiceParameter)) { parameterString = fixPath("" + ((StringParameter)parameter).getValue()); command = matcher.replaceAll(parameterString+"$2"); // making sure, that we catch full numbers and not just single digits ps++; parameterIndex++; } searchString = "(PARA_INTEGER_" + (pi+1) + ")(\\D)"; matcher = compileMatcherBy(searchString, command); if(matcher.find() && parameter instanceof IntegerParameter) { parameterString = "" + ((IntegerParameter)parameter).getValue(); command = matcher.replaceAll(parameterString+"$2"); // making sure, that we catch full numbers and not just single digits pi++; parameterIndex++; } searchString = "(PARA_BOOLEAN_" + (pb+1) + ")(\\D)"; matcher = compileMatcherBy(searchString, command); if(matcher.find() && parameter instanceof BooleanParameter) { boolean bool = ((BooleanParameter)parameter).getValue(); parameterString = (bool) ? ((BooleanParameter)parameter).getTrueString() : ""; command = matcher.replaceAll(parameterString+"$2"); // making sure, that we catch full numbers and not just single digits pb++; parameterIndex++; } parameterCount++; if (parameterIndex != parameterCount) { searchString = "_PARAMETER_" + (parameterIndex+1); matcher = compileMatcherBy(searchString, command); if(matcher.find() && knownParameterType(parameter)) { // This parameter is used as an "attibute" somewhere // Go ahead and increment parameter index, so subsequent parameters are still read parameterIndex++; } } if (parameterIndex != parameterCount) { // means, we have a parameter, that wasn't used // System.err.println("Error in parameters or ImageJ-syntax"); return command; } } return command; } private static boolean knownParameterType(final Parameter parameter) { return parameter instanceof BooleanParameter || parameter instanceof IntegerParameter || parameter instanceof StringParameter || parameter instanceof ChoiceParameter || parameter instanceof DoubleParameter; } /* * from ImageJ.Recorder */ static String fixPath (String path) { StringBuffer sb = new StringBuffer(); char c; for (int i=0; i<path.length(); i++) { sb.append(c=path.charAt(i)); if (c=='\\') sb.append("\\\\\\"); } return new String(sb); } /** * Compile a Matcher based on a SearchString and the Region which is to search. * @param searchString * @param region * @return */ private static Matcher compileMatcherBy(final String searchString, final String region) { return Pattern.compile(searchString).matcher(region); } /** * Writes values of input-DataTypes into the command-string. * @param inputs * @param i */ public void parseInputs(ArrayList<Input> inputs, final int i) { this.commandSyntax = parseInputs(inputs, this.commandSyntax, i); } /** * Writes values of output-DataTypes into the command-string. * @param outputs * @param i */ public void parseOutputs(ArrayList<Output> outputs, int i) { this.commandSyntax = parseOutputs(outputs, this.commandSyntax, i); } /** * Writes values of output-DataTypes into the command-string. * @param inputs * @param parameters * @param i */ public void parseAttributes(ArrayList<Input> inputs, ArrayList<Parameter> parameters, int i) { this.commandSyntax = parseAttributes(inputs, parameters, this.commandSyntax, i); } /** * Writes stack-command in the command-string, if input-DataType is stack * @param inputs */ public void parseStack(ArrayList<Input> inputs) { this.commandSyntax = parseStack(inputs, this.commandSyntax); } private static String parseOutputs(ArrayList<Output> outputs, String command, int i) { int index = 0, oDbl = 0, oInt = 0, oNbr = 0; String searchString, uniqueOutputName; Output output; while (index < outputs.size()) { output = outputs.get(index); uniqueOutputName = output.getOutputTitle() + "_" + i; searchString = "OUTPUT_DOUBLE_" + (oDbl+1); if(command.contains(searchString) && output.getDataType() instanceof DataTypeFactory.Double) { // System.out.println("Unit: " + unitID + " Parameter: " + parameterIndex + " Double Parameter: " + parameterString); command = Tools.replace(command, searchString, uniqueOutputName); oDbl++; // inputIndex++; } searchString = "OUTPUT_INTEGER_" + (oInt+1); if(command.contains(searchString) && output.getDataType() instanceof DataTypeFactory.Integer) { // System.out.println("Unit: " + unitID + " Parameter: " + parameterIndex + " String Parameter: " + parameterString); command = Tools.replace(command, searchString, uniqueOutputName); oInt++; // index++; } searchString = "OUTPUT_NUMBER_" + (oNbr+1); if(command.contains(searchString) && output.getDataType() instanceof DataTypeFactory.Number) { // System.out.println("Unit: " + unitID + " Parameter: " + parameterIndex + " String Parameter: " + parameterString); command = Tools.replace(command, searchString, uniqueOutputName); oNbr++; // index++; } index++; } return command; } private static String parseInputs(ArrayList<Input> inputs, String command, int i) { int index = 0, oDbl = 0, oInt = 0, oNbr = 0; String searchString, uniqueOutputName; while (index < inputs.size()) { Input input = inputs.get(index); if(input.isRequired() && input.isConnected()) { uniqueOutputName = input.getFromOutput().getOutputTitle() + "_" + i; searchString = "INPUT_DOUBLE_" + (oDbl+1); if(command.contains(searchString) && input.getDataType() instanceof DataTypeFactory.Double) { command = Tools.replace(command, searchString, uniqueOutputName); oDbl++; } searchString = "INPUT_INTEGER_" + (oInt+1); if(command.contains(searchString) && input.getDataType() instanceof DataTypeFactory.Integer ) { // System.out.println("Unit: " + unitID + " Parameter: " + parameterIndex + " String Parameter: " + parameterString); command = Tools.replace(command, searchString, uniqueOutputName); oInt++; } searchString = "INPUT_NUMBER_" + (oNbr+1); if(command.contains(searchString) && input.getDataType() instanceof DataTypeFactory.Number) { command = Tools.replace(command, searchString, uniqueOutputName); oNbr++; } } index++; } return command; } private static String parseAttributes(ArrayList<Input> inputs, ArrayList<Parameter> parameters, String command, int i) { int inputIndex, parameterIndex; String searchString; Parameter parameter; Input input; for (inputIndex = 0; inputIndex < inputs.size(); inputIndex++) { for (parameterIndex = 0; parameterIndex < parameters.size(); parameterIndex++) { input = inputs.get(inputIndex); if(!input.isRequired()) { parameter = parameters.get(parameterIndex); searchString = "ATTRIBUTE_INPUT_" + (inputIndex+1) + "_PARAMETER_" + (parameterIndex+1); if (command.contains(searchString)) { if (input.isConnected()) { String uniqueOutputName = input.getFromOutput().getOutputTitle() + "_" + i; command = Tools.replace(command, searchString, uniqueOutputName); } else { String parameterValue = ""; if (parameter instanceof IntegerParameter) parameterValue += ((IntegerParameter)parameter).getValue(); if (parameter instanceof DoubleParameter) parameterValue += ((DoubleParameter)parameter).getValue(); if (parameter instanceof BooleanParameter) parameterValue += ((BooleanParameter)parameter).getTrueString(); if (parameter instanceof StringParameter) parameterValue += ((StringParameter)parameter).getValue(); command = Tools.replace(command, searchString, parameterValue); } } } } } return command; } /** * @param inputs * @param command * @return */ public static String parseStack(final ArrayList<Input> inputs, String command) { String searchString = "STACK"; String stackParameter = ""; int binaryComparison, bitdepth; for (Input input : inputs) { if (input.isConnected() && (input.getDataType() instanceof ImageDataType) ) { bitdepth = ((ImageDataType)input.getFromOutput().getDataType()).getImageBitDepth(); binaryComparison = bitdepth & (ij.plugin.filter.PlugInFilter.DOES_STACKS); if (binaryComparison != 0) stackParameter = "stack"; } } command = Tools.replace(command, searchString, stackParameter); return command; } }