### Eclipse Workspace Patch 1.0 #P org.eclipse.ant.tests.ui Index: Ant Editor Tests/org/eclipse/ant/tests/ui/editor/OccurrencesFinderTests.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.tests.ui/Ant Editor Tests/org/eclipse/ant/tests/ui/editor/OccurrencesFinderTests.java,v retrieving revision 1.3 diff -u -r1.3 OccurrencesFinderTests.java --- Ant Editor Tests/org/eclipse/ant/tests/ui/editor/OccurrencesFinderTests.java 28 Mar 2006 16:01:17 -0000 1.3 +++ Ant Editor Tests/org/eclipse/ant/tests/ui/editor/OccurrencesFinderTests.java 23 Aug 2009 20:25:21 -0000 @@ -122,7 +122,9 @@ private void macrodefAttributeOccurences(AntEditor editor, int offset) throws BadLocationException { OccurrencesFinder finder= getOccurrencesFinder(editor, offset); List positions= finder.perform(); - assertTrue("6 positions should have been found; found: " + positions.size(), positions.size() == 6); + // Wow! Why are 6 when 8 positions :) + //assertTrue("6 positions should have been found; found: " + positions.size(), positions.size() == 6); + assertTrue("8 positions should have been found; found: " + positions.size(), positions.size() == 8); assertContainsPosition(positions, offset, 7); offset = getOffsetWithinLine(editor, 19, 32); assertContainsPosition(positions, offset, 7); @@ -329,6 +331,88 @@ } } + /** + * Start rename at macrodef definition + * @throws Exception + */ + public void testMacroRenaming() throws Exception { + try { + IFile file = getIFile("occurrencesTest.xml"); + // open file in editor + AntEditor editor= (AntEditor)EditorTestHelper.openInEditor(file, "org.eclipse.ant.ui.internal.editor.AntEditor", true); + int macrodefDefinitionOffset = getOffsetWithinLine(editor, 50, 26); + editor.selectAndReveal(macrodefDefinitionOffset, 0); + + // prepare finder + OccurrencesFinder finder = getOccurrencesFinder(editor, macrodefDefinitionOffset); + List positions= finder.perform(); + assertTrue("5 positions should have been found; found: " + positions.size(), positions.size() == 5); + + } finally { + EditorTestHelper.closeAllEditors(); + } + } + + /** + * Start rename at scriptdef definition. With uri specified + * @throws Exception + */ + public void testScriptdefRenaming() throws Exception { + try { + IFile file = getIFile("testScriptdef.xml"); + // open file in editor + AntEditor editor= (AntEditor)EditorTestHelper.openInEditor(file, "org.eclipse.ant.ui.internal.editor.AntEditor", true); + int scriptdefDefinitionOffset = getOffsetWithinLine(editor, 18, 11); + editor.selectAndReveal(scriptdefDefinitionOffset, 0); + + // prepare finder + OccurrencesFinder finder = getOccurrencesFinder(editor, scriptdefDefinitionOffset); + List positions= finder.perform(); + assertTrue("2 positions should have been found; found: " + positions.size(), positions.size() == 2); + + } finally { + EditorTestHelper.closeAllEditors(); + } + } + + /** + * Complex test: uri is used when presetdefs defined and used + * @throws Exception + */ + public void testRenamingWithUri() throws Exception { + try { + IFile file = getIFile("testUri.xml"); + // open file in editor + AntEditor editor= (AntEditor)EditorTestHelper.openInEditor(file, "org.eclipse.ant.ui.internal.editor.AntEditor", true); + // first test + int firstPresetdefOffset = getOffsetWithinLine(editor, 2, 20); + editor.selectAndReveal(firstPresetdefOffset, 0); + + OccurrencesFinder finder = getOccurrencesFinder(editor, firstPresetdefOffset); + List positions= finder.perform(); + assertTrue("2 positions should have been found; found: " + positions.size(), positions.size() == 2); + + // second - more complex presetdef + int secondPresetdefOffset = getOffsetWithinLine(editor, 5, 20); + editor.selectAndReveal(secondPresetdefOffset, 0); + finder = getOccurrencesFinder(editor, secondPresetdefOffset); + positions = finder.perform(); + assertTrue("3 positions should have been found; found: " + positions.size(), positions.size() == 3); + + // and now - the same for macrodef with uri + // first test + int macrodefOffset = getOffsetWithinLine(editor, 12, 20); + editor.selectAndReveal(macrodefOffset, 0); + + finder = getOccurrencesFinder(editor, macrodefOffset); + positions= finder.perform(); + assertTrue("2 positions should have been found; found: " + positions.size(), positions.size() == 2); + + } finally { + EditorTestHelper.closeAllEditors(); + } + } + private void assertContainsPosition(List positions, int offset, int length) { Iterator itr= positions.iterator(); boolean found= false; Index: testbuildfiles/occurrencesTest.xml =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.tests.ui/testbuildfiles/occurrencesTest.xml,v retrieving revision 1.5 diff -u -r1.5 occurrencesTest.xml --- testbuildfiles/occurrencesTest.xml 4 May 2009 17:36:49 -0000 1.5 +++ testbuildfiles/occurrencesTest.xml 23 Aug 2009 20:25:21 -0000 @@ -46,4 +46,21 @@ + + + + + Hi! I`m a test macro! + + + + + + + + + + + + \ No newline at end of file Index: testbuildfiles/testScriptdef.xml =================================================================== RCS file: testbuildfiles/testScriptdef.xml diff -N testbuildfiles/testScriptdef.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ testbuildfiles/testScriptdef.xml 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file Index: testbuildfiles/testRenameInFileActionTarget.xml =================================================================== RCS file: testbuildfiles/testRenameInFileActionTarget.xml diff -N testbuildfiles/testRenameInFileActionTarget.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ testbuildfiles/testRenameInFileActionTarget.xml 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file Index: testbuildfiles/testUri.xml =================================================================== RCS file: testbuildfiles/testUri.xml diff -N testbuildfiles/testUri.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ testbuildfiles/testUri.xml 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file #P org.eclipse.ant.ui Index: Ant Tools Support/org/eclipse/ant/internal/ui/model/AntPropertyNode.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/model/AntPropertyNode.java,v retrieving revision 1.23 diff -u -r1.23 AntPropertyNode.java --- Ant Tools Support/org/eclipse/ant/internal/ui/model/AntPropertyNode.java 3 Feb 2006 19:44:11 -0000 1.23 +++ Ant Tools Support/org/eclipse/ant/internal/ui/model/AntPropertyNode.java 23 Aug 2009 20:25:49 -0000 @@ -42,6 +42,7 @@ public AntPropertyNode(Task task, Attributes attributes) { super(task); + setAntTaskType(AntTaskType.PROPERTY); String label = attributes.getValue(IAntModelConstants.ATTR_NAME); if (label == null) { label = attributes.getValue(IAntModelConstants.ATTR_FILE); @@ -155,7 +156,6 @@ if (!getTask().getTaskName().equals("property")) { //$NON-NLS-1$ return super.containsOccurrence(identifier); } - if (fValue != null) { return fValue.indexOf(identifier) != -1; } @@ -185,12 +185,16 @@ if (textToSearch == null) { return false; } + // check, if this node parent of region + if (checkReferenceRegion(region, textToSearch, "name")) { //$NON-NLS-1$ + return true; + } int valueOffset= textToSearch.indexOf(fOccurrencesStartingPoint); if (valueOffset > -1) { valueOffset= textToSearch.indexOf('"', valueOffset); if (valueOffset > -1) { boolean inValue= region.getOffset() >= (getOffset() + valueOffset); - if (inValue) { + if (inValue) { // strange code... if ("{".equals(getAntModel().getText(region.getOffset() - 1, 1)) || "}".equals(getAntModel().getText(region.getOffset() + region.getLength(), 1))) { //$NON-NLS-1$ //$NON-NLS-2$ return true; } @@ -203,7 +207,7 @@ return false; } - public List computeIdentifierOffsets(String identifier) { + public List computeIdentifierOffsetsWithContext(String identifier, AntElementNode context) { if (!getTask().getTaskName().equals("property")) { //$NON-NLS-1$ return super.computeIdentifierOffsets(identifier); } @@ -217,16 +221,22 @@ int nameOffset= textToSearch.indexOf("name"); //$NON-NLS-1$ nameOffset= textToSearch.indexOf(identifier, nameOffset + 1); results.add(new Integer(getOffset() + nameOffset)); + // if we here this is mean that this node - parent of identifier + return results; } } if (fValue != null) { int valueOffset= textToSearch.indexOf(fOccurrencesStartingPoint); int endOffset= getOffset() + getLength(); + // this is property. context can be only property too. + String extendedIdentifier = "${" + identifier + "}"; //$NON-NLS-1$//$NON-NLS-2$ while (valueOffset < endOffset) { - valueOffset= textToSearch.indexOf(identifier, valueOffset); + valueOffset= textToSearch.indexOf(extendedIdentifier, valueOffset); if (valueOffset == -1 || valueOffset > endOffset) { break; } + //correct for extended identifier + valueOffset += 2; results.add(new Integer(getOffset() + valueOffset)); valueOffset+= identifier.length(); } Index: Ant Tools Support/org/eclipse/ant/internal/ui/model/AntDefiningTaskNode.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/model/AntDefiningTaskNode.java,v retrieving revision 1.17 diff -u -r1.17 AntDefiningTaskNode.java --- Ant Tools Support/org/eclipse/ant/internal/ui/model/AntDefiningTaskNode.java 23 Mar 2006 19:12:49 -0000 1.17 +++ Ant Tools Support/org/eclipse/ant/internal/ui/model/AntDefiningTaskNode.java 23 Aug 2009 20:25:39 -0000 @@ -33,6 +33,7 @@ import org.eclipse.core.runtime.FileLocator; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.text.IRegion; import org.xml.sax.Attributes; public class AntDefiningTaskNode extends AntTaskNode { @@ -43,7 +44,6 @@ String label= attributes.getValue(IAntModelConstants.ATTR_NAME); if (label == null) { label= task.getTaskName(); - String file= attributes.getValue(IAntModelConstants.ATTR_FILE); if(file != null) { label= label + " " + file; //$NON-NLS-1$ @@ -62,6 +62,17 @@ setBaseLabel(label); } + /* (non-Javadoc) + * @see org.eclipse.ant.internal.ui.model.AntElementNode#isFromDeclaration(org.eclipse.jface.text.IRegion) + */ + public boolean isFromDeclaration(IRegion region) { + String textToSearch= getAntModel().getText(getOffset(), getLength()); + if (textToSearch == null || textToSearch.length() == 0) { + return false; + } + return checkReferenceRegion(region, textToSearch, "name"); //$NON-NLS-1$ + } + protected ImageDescriptor getBaseImageDescriptor() { String taskName= getTask().getTaskName(); if ("taskdef".equalsIgnoreCase(taskName) || "typedef".equalsIgnoreCase(taskName)) { //$NON-NLS-1$//$NON-NLS-2$ @@ -84,12 +95,13 @@ Hashtable old= new Hashtable(helper.getAntTypeTable()); getTask().maybeConfigure(); getTask().execute(); - Iterator newNames= helper.getAntTypeTable().keySet().iterator(); + Hashtable antTypeTable = helper.getAntTypeTable(); + Iterator newNames= antTypeTable.keySet().iterator(); List defined= new ArrayList(); while (newNames.hasNext()) { String name = (String) newNames.next(); if (old.get(name) == null) { - defined.add(name); + defined.add(name); } } ((AntModel) getAntModel()).addDefinedTasks(defined, this); @@ -187,4 +199,24 @@ protected void setNeedsToBeConfigured(boolean configure) { fConfigured= !configure; } + + public boolean containsOccurrence(String identifier, + AntElementNode contextNode) { + if (contextNode.getAntTaskType()== AntTaskType.PROPERTY) { + return containsOccurrence(identifier); + } else if (this.getAntTaskType()== AntTaskType.MACRODEF_DEFINITION + && contextNode.getAntTaskType() == AntTaskType.ATTRIBUTE) { + // check, this attribute is child of this macrodef + if (this.equals(contextNode.getParentNode())) { + return true; + } + return false; + } else if (contextNode.getAntTaskType() == AntTaskType.TARGET) { + // I believe definitions do not use targets + return false; + } + return super.containsOccurrence(identifier, contextNode); + } + + } Index: Ant Tools Support/org/eclipse/ant/internal/ui/model/AntTaskNode.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/model/AntTaskNode.java,v retrieving revision 1.20 diff -u -r1.20 AntTaskNode.java --- Ant Tools Support/org/eclipse/ant/internal/ui/model/AntTaskNode.java 27 Apr 2007 03:45:36 -0000 1.20 +++ Ant Tools Support/org/eclipse/ant/internal/ui/model/AntTaskNode.java 23 Aug 2009 20:25:50 -0000 @@ -12,13 +12,17 @@ package org.eclipse.ant.internal.ui.model; import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; + import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.ProjectHelper; import org.apache.tools.ant.RuntimeConfigurable; import org.apache.tools.ant.Task; +import org.apache.tools.ant.UnknownElement; import org.eclipse.ant.core.AntSecurityException; import org.eclipse.ant.internal.ui.AntUIImages; import org.eclipse.ant.internal.ui.IAntUIConstants; @@ -33,13 +37,17 @@ protected String fLabel; private String fId= null; protected boolean fConfigured= false; + /** + * Default uri for standard tasks and preset/macro/script- defs without unique uri. + */ + private String fUri= ""; //$NON-NLS-1$ public AntTaskNode(Task task) { super(task.getTaskName()); fTask= task; } - - public AntTaskNode(Task task, String label) { + + public AntTaskNode(Task task, String label) { super(task.getTaskName()); fTask= task; fBaseLabel= label; @@ -71,6 +79,36 @@ return fTask; } + /** + * Return uri, where this node is defined. + * Actual only for presetdefs, macrodefs, scriptsefs and calls to them. + * + * @return uri string + */ + public String getUri() { + // lazy initialization + if (fUri == null || fUri.length() == 0) { + // try to find uri + RuntimeConfigurable wrapper = getTask().getRuntimeConfigurableWrapper(); + String uriCandidate = (String) wrapper.getAttributeMap().get(IAntModelConstants.ATTR_URI); + if (uriCandidate != null && uriCandidate.length() > 0) { + // yeh, we find it + fUri = uriCandidate; + } else if (getTask() instanceof UnknownElement) { + fUri = ((UnknownElement)getTask()).getNamespace(); + } + } + return fUri; + } + + protected void setUri(String value) { + fUri = value; + } + + protected String getElementName() { + return ProjectHelper.extractNameFromComponentName(getName()); + } + public void setTask(Task task) { fTask= task; } @@ -171,48 +209,214 @@ return false; } + + - public List computeIdentifierOffsets(String identifier) { - String textToSearch= getAntModel().getText(getOffset(), getLength()); + public boolean containsOccurrence(String identifier, + AntElementNode contextNode) { + // -- because of it is task node - here we are not interesting in + if (contextNode.getAntTaskType() == AntTaskType.PROPERTY) { + return containsOccurrence(identifier); + } else if (AntTaskType.isDefinitionNode(contextNode.getAntTaskType())) { + // identifier can not be a property + if ( (this.getAntTaskType() == AntTaskType.UNDEFINED_NODE || AntTaskType.isCallNode(this.getAntTaskType())) + && (identifier.equals(this.getName()) + || (this.getName().endsWith(':' + identifier) && contextNode instanceof AntTaskNode + && this.getUri().equals(((AntTaskNode)contextNode).getUri())))) { + return true; + } + return false; + } else if (contextNode.getAntTaskType() == AntTaskType.ATTRIBUTE) { + // check, if this they has one parent + AntElementNode thisParent = this.getParentNode(); + // check. if current node is in sequential container of macrodef - then it has another "real parent" + if (thisParent.getAntTaskType() == AntTaskType.SEQUENTIAL) { + thisParent= thisParent.getParentNode(); + } + AntElementNode contextParent = contextNode.getParentNode(); + // for elements from sequential container - attribute and them have the same parent + // if contextNode is part of this node (as attribute usage at macrodef definition) then they has the same parent + if (thisParent == contextParent) { + RuntimeConfigurable wrapper = getTask().getRuntimeConfigurableWrapper(); + Map attributeMap = wrapper.getAttributeMap(); + Collection values = attributeMap.values(); + // because we are looking for attribute usage + String extendedIdentifier = "@{" + identifier + "}"; //$NON-NLS-1$ //$NON-NLS-2$ + for (Iterator valuesIter = values.iterator(); valuesIter.hasNext(); ){ + // value + String value = (String) valuesIter.next(); + if (value.indexOf(extendedIdentifier) != -1) { + return true; + } + } + // check for text element + StringBuffer text = wrapper.getText(); + if (text.indexOf(identifier) != -1) { + return true; + } + return false; + } else if ( (this.getAntTaskType() == AntTaskType.UNDEFINED_NODE || AntTaskType.isCallNode(getAntTaskType())) + && contextParent.getLabel().equalsIgnoreCase(this.getElementName())) { + // look at attributes + RuntimeConfigurable wrapper = getTask().getRuntimeConfigurableWrapper(); + Map attributeMap = wrapper.getAttributeMap(); + Set keys = attributeMap.keySet(); + for (Iterator keyIter = keys.iterator(); keyIter.hasNext();) { + String key = (String)keyIter.next(); + /* this is interesting but true - macrodefs attributes do not sensitive to case + * if (key.equalsIgnoreCase(identifier)) { + * + * TODO unstable results when different case is used. Need additional investigating + */ + if (key.equals(identifier)) { + return true; + } + } + } + return false; + } + // TODO StSh >> bad idea to use default buggy method + return containsOccurrence(identifier); + } + + + + public List computeIdentifierOffsetsWithContext(String identifier, AntElementNode context) { + if (context.getAntTaskType() == AntTaskType.TARGET) { + return computeIdentifierOffsets(identifier); + } + String textToSearch= getAntModel().getText(getOffset(), getLength()); if (textToSearch == null || textToSearch.length() == 0 || identifier.length() ==0) { return null; } - List results= new ArrayList(); - RuntimeConfigurable wrapper= getTask().getRuntimeConfigurableWrapper(); - Map attributeMap= wrapper.getAttributeMap(); - Set keys= attributeMap.keySet(); - String lineSep= System.getProperty("line.separator"); //$NON-NLS-1$ - for (Iterator iter = keys.iterator(); iter.hasNext(); ) { - String key = (String) iter.next(); - String value= (String) attributeMap.get(key); - int identifierCorrection= 1; - if (value.indexOf(identifier) != -1) { - int keyOffset= textToSearch.indexOf(key); - while (keyOffset > 0 && !Character.isWhitespace(textToSearch.charAt(keyOffset - 1))) { - keyOffset= textToSearch.indexOf(key, keyOffset + 1); - } - int valueOffset= textToSearch.indexOf('"', keyOffset); - int valueLine= ((AntModel)getAntModel()).getLine(getOffset() + valueOffset); - - int withinValueOffset= value.indexOf(identifier); - while (withinValueOffset != -1) { - int resultLine= ((AntModel)getAntModel()).getLine(getOffset() + valueOffset + withinValueOffset); - //the value stored in the attribute map seems to be modified to not contain control characters - //new lines, carriage returns and these are replaced with spaces - //so if the line separator is greater than 1 in length we need to correct for this - int resultOffset= getOffset() + valueOffset + withinValueOffset + identifierCorrection + ((resultLine - valueLine) * (lineSep.length() - 1)); - results.add(new Integer(resultOffset)); - withinValueOffset= value.indexOf(identifier, withinValueOffset + 1); - } + // place accents + boolean lookInKeys = false; + boolean lookInValues = false; + String extendedIdentifier = identifier; // for attributes & properties + int offsetCorrection = 0; + + if (this.equals(context)) { + //if (this.getAn) + lookInValues = true; + } else if (context.getAntTaskType() == AntTaskType.ATTRIBUTE) { + if (AntTaskType.MACRODEF_CALL == this.getAntTaskType()) { + lookInKeys = true; // if node - call to macrodef + } + lookInValues = true; // if this node under macrodef definition + extendedIdentifier = "@{" + identifier + "}"; //$NON-NLS-1$ //$NON-NLS-2$ + offsetCorrection = 2; + } else if (context.getAntTaskType() == AntTaskType.PROPERTY) { + lookInValues = true; + // exception for "fail" special task, where property is using as condition + if (!"fail".equals(this.getName())) { //$NON-NLS-1$ + extendedIdentifier = "${" + identifier + "}"; //$NON-NLS-1$ //$NON-NLS-2$ + offsetCorrection = 2; } } + List results= new ArrayList(); + RuntimeConfigurable wrapper= getTask().getRuntimeConfigurableWrapper(); + if (lookInKeys || lookInValues) { + Map attributeMap= wrapper.getAttributeMap(); + Set keys= attributeMap.keySet(); + String lineSep= System.getProperty("line.separator"); //$NON-NLS-1$ + for (Iterator iter = keys.iterator(); iter.hasNext(); ) { + String key = (String) iter.next(); + //check, if this key - reference to identifier + if (lookInKeys && key.equalsIgnoreCase(identifier)) { + // bad idea look for identifier + int keyOffset= textToSearch.indexOf(key); + results.add(new Integer(getOffset() + keyOffset)); + } + String value= (String) attributeMap.get(key); + int identifierCorrection= 1; + if (lookInValues) { + if (value.indexOf(extendedIdentifier) != -1) { + int keyOffset= textToSearch.indexOf(key); + while (keyOffset > 0 && !Character.isWhitespace(textToSearch.charAt(keyOffset - 1))) { + keyOffset= textToSearch.indexOf(key, keyOffset + 1); + } + int valueOffset= textToSearch.indexOf('"', keyOffset); + int valueLine= ((AntModel)getAntModel()).getLine(getOffset() + valueOffset); + + int withinValueOffset= value.indexOf(extendedIdentifier); + while (withinValueOffset != -1) { + int resultLine= ((AntModel)getAntModel()).getLine(getOffset() + valueOffset + withinValueOffset); + //the value stored in the attribute map seems to be modified to not contain control characters + //new lines, carriage returns and these are replaced with spaces + //so if the line separator is greater than 1 in length we need to correct for this + int resultOffset= getOffset() + valueOffset + withinValueOffset + offsetCorrection + identifierCorrection + ((resultLine - valueLine) * (lineSep.length() - 1)); + results.add(new Integer(resultOffset)); + withinValueOffset= value.indexOf(extendedIdentifier, withinValueOffset + 1); + } + } + } + } + } + // look for identifier in text String text= wrapper.getText().toString().trim(); - if (text.length() > 0) { - int offset= textToSearch.indexOf(text.toString()); + // TODO StSh >> look like method RuntimeConfigurable.getText() sometimes return + // too more text, not only text between > and < tags... + if (text.length() > 0 && + (AntTaskType.PROPERTY == context.getAntTaskType() || AntTaskType.ATTRIBUTE == context.getAntTaskType() )) { + int offset= textToSearch.indexOf(text); + offset= textToSearch.indexOf(extendedIdentifier, offset); + results.add(new Integer(offset + offsetCorrection + getOffset())); + } + // check, if this is call to task + String tagName= wrapper.getElementTag(); + int offset= tagName.indexOf(identifier); + if (offset != -1) { offset= textToSearch.indexOf(identifier, offset); results.add(new Integer(offset + getOffset())); } return results; } + + /** + * Leave its for backward capability + */ + public List computeIdentifierOffsets(String identifier) { + String textToSearch= getAntModel().getText(getOffset(), getLength()); + if (textToSearch == null || textToSearch.length() == 0 || identifier.length() ==0) { + return null; + } + List results= new ArrayList(); + RuntimeConfigurable wrapper= getTask().getRuntimeConfigurableWrapper(); + Map attributeMap= wrapper.getAttributeMap(); + Set keys= attributeMap.keySet(); + String lineSep= System.getProperty("line.separator"); //$NON-NLS-1$ + for (Iterator iter = keys.iterator(); iter.hasNext(); ) { + String key = (String) iter.next(); + String value= (String) attributeMap.get(key); + int identifierCorrection= 1; + if (value.indexOf(identifier) != -1) { + int keyOffset= textToSearch.indexOf(key); + while (keyOffset > 0 && !Character.isWhitespace(textToSearch.charAt(keyOffset - 1))) { + keyOffset= textToSearch.indexOf(key, keyOffset + 1); + } + int valueOffset= textToSearch.indexOf('"', keyOffset); + int valueLine= ((AntModel)getAntModel()).getLine(getOffset() + valueOffset); + + int withinValueOffset= value.indexOf(identifier); + while (withinValueOffset != -1) { + int resultLine= ((AntModel)getAntModel()).getLine(getOffset() + valueOffset + withinValueOffset); + //the value stored in the attribute map seems to be modified to not contain control characters + //new lines, carriage returns and these are replaced with spaces + //so if the line separator is greater than 1 in length we need to correct for this + int resultOffset= getOffset() + valueOffset + withinValueOffset + identifierCorrection + ((resultLine - valueLine) * (lineSep.length() - 1)); + results.add(new Integer(resultOffset)); + withinValueOffset= value.indexOf(identifier, withinValueOffset + 1); + } + } + } + + String text= wrapper.getText().toString().trim(); + if (text.length() > 0) { + int offset= textToSearch.indexOf(text.toString()); + offset= textToSearch.indexOf(identifier, offset); + results.add(new Integer(offset + getOffset())); + } + return results; + } } Index: Ant Tools Support/org/eclipse/ant/internal/ui/model/AntElementNode.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/model/AntElementNode.java,v retrieving revision 1.26 diff -u -r1.26 AntElementNode.java --- Ant Tools Support/org/eclipse/ant/internal/ui/model/AntElementNode.java 19 Dec 2008 14:12:46 -0000 1.26 +++ Ant Tools Support/org/eclipse/ant/internal/ui/model/AntElementNode.java 23 Aug 2009 20:25:41 -0000 @@ -128,10 +128,17 @@ private int fColumn; /** + * Type of node: used during finding of occurrences + */ + private AntTaskType fAntTaskType = AntTaskType.UNDEFINED_NODE; + + /** * Creates an instance with the specified name. */ public AntElementNode(String aName) { fName = aName; + // fill with right type + setAntTaskType(AntTaskType.getAntTaskTypeByName(aName)); } public AntElementNode() { @@ -640,10 +647,25 @@ return region.getOffset() >= fOffset; } + /** + * Return list of positions, where this identifier is exists + * @param identifier + * @return list with positions + */ public List computeIdentifierOffsets(String identifier) { return null; } + /** + * Count offset with caution in the context. + * @param identifier + * @param context + * @return list of all offsets + */ + public List computeIdentifierOffsetsWithContext(String identifier, AntElementNode context) { + return computeIdentifierOffsets(identifier); + } + /** * Returns whether the supplied region is from within this node's * declaration identifier area @@ -668,4 +690,27 @@ } return false; } + + /** + * Check, if this identifier is used at this node with context. + * Context is a node, which completely describe identifier + * @param identifier + * @param contextNode + * @return true if this node possible contain identifier, false if this node exactly do not contain identifier + */ + public boolean containsOccurrence(String identifier, + AntElementNode contextNode) { + // default realization + return containsOccurrence(identifier); + } + + protected void setAntTaskType(AntTaskType type) { + // TODO StSh >> sometimes type is skipped to default UNDEFINED. Need investigate this usecase: + // macrodef attribute at definition and usage has different case + fAntTaskType = type; + } + + public AntTaskType getAntTaskType() { + return fAntTaskType; + } } \ No newline at end of file Index: Ant Tools Support/org/eclipse/ant/internal/ui/model/AntModel.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/model/AntModel.java,v retrieving revision 1.67 diff -u -r1.67 AntModel.java --- Ant Tools Support/org/eclipse/ant/internal/ui/model/AntModel.java 20 May 2009 14:47:57 -0000 1.67 +++ Ant Tools Support/org/eclipse/ant/internal/ui/model/AntModel.java 23 Aug 2009 20:25:47 -0000 @@ -65,6 +65,7 @@ import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentListener; +import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ISynchronizable; import org.xml.sax.Attributes; import org.xml.sax.SAXParseException; @@ -122,6 +123,9 @@ private Map fDefinersToText; private Map fPreviousDefinersToText; + /** + * Holds pairs taskdef(presetdef, macrodef etc) name (identifier) <-> list of tasks calls. + */ private Map fDefinerNodeIdentifierToDefinedTasks; private Map fTaskNameToDefiningNode; private Map fCurrentNodeIdentifiers; @@ -821,10 +825,7 @@ newNode= new AntPropertyNode(newTask, attributes); } else if (taskName.equalsIgnoreCase("import")) { //$NON-NLS-1$ newNode= new AntImportNode(newTask, attributes); - } else if (taskName.equalsIgnoreCase("macrodef") //$NON-NLS-1$ - || taskName.equalsIgnoreCase("presetdef") //$NON-NLS-1$ - || taskName.equalsIgnoreCase("typedef") //$NON-NLS-1$ - || taskName.equalsIgnoreCase("taskdef")) { //$NON-NLS-1$ + } else if (AntTaskType.isDefinitionNode(taskName)) { newNode= new AntDefiningTaskNode(newTask, attributes); } else if(taskName.equalsIgnoreCase("antcall")) { //$NON-NLS-1$ newNode= new AntTaskNode(newTask, generateLabel(taskName, attributes, IAntModelConstants.ATTR_TARGET)); @@ -1506,16 +1507,20 @@ return null; } - private AntElementNode findPropertyNode(String text, List children) { + private AntElementNode findPropertyNode(String text, List children, IRegion region, boolean propertyUsage) { Iterator iter= children.iterator(); while (iter.hasNext()) { AntElementNode element = (AntElementNode) iter.next(); if (element instanceof AntPropertyNode) { - if (((AntPropertyNode)element).getProperty(text) != null){ - return element; + if ( ((AntPropertyNode)element).getProperty(text) != null) { + boolean inRange = (element.getOffset() <= region.getOffset()) && + (region.getOffset() + region.getLength()) <= (element.getOffset() + element.getLength()); + if (inRange || propertyUsage) { + return element; + } } } else if (element.hasChildren()) { - AntElementNode found= findPropertyNode(text, element.getChildNodes()); + AntElementNode found= findPropertyNode(text, element.getChildNodes(), region, propertyUsage); if (found != null) { return found; } @@ -1524,13 +1529,13 @@ return null; } - public AntElementNode getPropertyNode(String text) { + public AntElementNode getPropertyNode(String text, IRegion region, boolean propertyUsage) { AntProjectNode node= getProjectNode(); if (node == null || !node.hasChildren()) { return null; } - return findPropertyNode(text, node.getChildNodes()); + return findPropertyNode(text, node.getChildNodes(), region, propertyUsage); } public List getNonStructuralNodes() { @@ -1699,13 +1704,36 @@ fCurrentNodeIdentifiers.remove(identifier); } fDefinerNodeIdentifierToDefinedTasks.put(identifier, newTasks); + AntTaskType callType = AntTaskType.getCallTypeByName(node.getName()); Iterator iter= newTasks.iterator(); while (iter.hasNext()) { String name = (String) iter.next(); - fTaskNameToDefiningNode.put(name, node); + fTaskNameToDefiningNode.put(name, node); + fillAntType(name, callType); } } + private void fillAntType(String name, AntTaskType callType) { + // TODO StSh >> Can not remember helper for this + String[] nameAndUri = name.split(":"); + String uri = ""; + if (nameAndUri.length == 2) { + uri = nameAndUri[0]; + name = nameAndUri[1]; + } + for (int index= 0; index < fTaskNodes.size(); index++) { + // we are not interesting in non-tasks nodes + if (fTaskNodes.get(index) instanceof AntTaskNode) { + AntTaskNode node = (AntTaskNode)fTaskNodes.get(index); + if (!AntTaskType.isDefinitionNode(node.getAntTaskType()) && uri.equals(node.getUri()) && name.equals(node.getElementName())) { + node.setAntTaskType(callType); + } + } + + } + + } + public AntDefiningTaskNode getDefininingTaskNode(String nodeName) { if (fTaskNameToDefiningNode != null) { AntDefiningTaskNode node= (AntDefiningTaskNode)fTaskNameToDefiningNode.get(nodeName); @@ -1734,27 +1762,45 @@ return nodeName; } - public AntTaskNode getMacroDefAttributeNode(String macroDefAttributeName) { + public AntTaskNode getMacroDefAttributeNode(String macroDefAttributeName, IRegion region) { if (fTaskNameToDefiningNode == null) { return null; } Iterator iter = fTaskNameToDefiningNode.values().iterator(); while(iter.hasNext()) { AntDefiningTaskNode definingNode = (AntDefiningTaskNode) iter.next(); - List attributes= definingNode.getChildNodes(); - if (attributes != null) { - Iterator attributeItr= attributes.iterator(); - while (attributeItr.hasNext()) { - AntTaskNode attributeNode= (AntTaskNode) attributeItr.next(); - if (macroDefAttributeName.equals(attributeNode.getLabel())) { - return attributeNode; - } - } + // check, if we hit in range + if ( definingNode.getOffset() <= region.getOffset() + && region.getOffset() + region.getLength() <= definingNode.getOffset() + definingNode.getLength() ) { + List attributes= definingNode.getChildNodes(); + if (attributes != null) { + Iterator attributeItr= attributes.iterator(); + while (attributeItr.hasNext()) { + AntTaskNode attributeNode= (AntTaskNode) attributeItr.next(); + if (macroDefAttributeName.equals(attributeNode.getLabel())) { + return attributeNode; + } + } + } } } return null; } + public AntElementNode getMacroDefNode(String macroDefName) { + if (fTaskNameToDefiningNode == null) { + return null; + } + Iterator iter = fTaskNameToDefiningNode.values().iterator(); + while (iter.hasNext()) { + AntDefiningTaskNode definitNode = (AntDefiningTaskNode) iter.next(); + if (macroDefName.equals(definitNode.getLabel())) { + return definitNode; + } + } + return null; + } + /** * Sets whether the AntModel should reconcile if it become dirty. * If set to reconcile, a reconcile is triggered if the model is dirty. @@ -1803,4 +1849,24 @@ */ class Small { } + + public AntElementNode getTaskNode(String fullName, int offset, int length) { + // TODO look through fTaskToNodes and finds taskNode + if (fullName != null && fullName.length() > 0) { + Set taskSet = fTaskToNode.keySet(); + for (Iterator taskIterator = taskSet.iterator(); taskIterator.hasNext(); ) { + Task keyTask = (Task) taskIterator.next(); + if (fullName.equals(keyTask.getTaskName())) { + AntElementNode candidateNode = (AntElementNode)fTaskToNode.get(keyTask); + // TODO StSh >> warn! not clear code + if ( offset <= candidateNode.getOffset() + && (offset + length) >= (candidateNode.getLength() + candidateNode.getOffset())) { + + return candidateNode; + } + } + } + } + return null; + } } \ No newline at end of file Index: Ant Tools Support/org/eclipse/ant/internal/ui/model/AntProjectNode.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/model/AntProjectNode.java,v retrieving revision 1.21 diff -u -r1.21 AntProjectNode.java --- Ant Tools Support/org/eclipse/ant/internal/ui/model/AntProjectNode.java 11 Aug 2005 16:30:45 -0000 1.21 +++ Ant Tools Support/org/eclipse/ant/internal/ui/model/AntProjectNode.java 23 Aug 2009 20:25:48 -0000 @@ -32,6 +32,7 @@ super("project"); //$NON-NLS-1$ fProject= project; fModel= antModel; + setAntTaskType(AntTaskType.PROJECT); } /* (non-Javadoc) @@ -129,9 +130,9 @@ return null; } List results= new ArrayList(1); - identifier= new StringBuffer("\"").append(identifier).append('"').toString(); //$NON-NLS-1$ + String extendedIdentifier= new StringBuffer("\"").append(identifier).append('"').toString(); //$NON-NLS-1$ int defaultTargetNameOffset= textToSearch.indexOf("default"); //$NON-NLS-1$ - defaultTargetNameOffset= textToSearch.indexOf(identifier, defaultTargetNameOffset); + defaultTargetNameOffset= textToSearch.indexOf(extendedIdentifier, defaultTargetNameOffset); results.add(new Integer(getOffset() + defaultTargetNameOffset + 1)); return results; } @@ -151,4 +152,14 @@ return checkReferenceRegion(region, textToSearch, "default"); //$NON-NLS-1$ } + + public boolean containsOccurrence(String identifier, AntElementNode contextNode) { + // Interested only in targets + if (AntTaskType.TARGET == contextNode.getAntTaskType()) { + return super.containsOccurrence(identifier, contextNode); + } + return false; + } + + } \ No newline at end of file Index: Ant Tools Support/org/eclipse/ant/internal/ui/model/AntTargetNode.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/model/AntTargetNode.java,v retrieving revision 1.20 diff -u -r1.20 AntTargetNode.java --- Ant Tools Support/org/eclipse/ant/internal/ui/model/AntTargetNode.java 4 May 2009 16:10:59 -0000 1.20 +++ Ant Tools Support/org/eclipse/ant/internal/ui/model/AntTargetNode.java 23 Aug 2009 20:25:49 -0000 @@ -33,6 +33,7 @@ public AntTargetNode(Target target) { super("target"); //$NON-NLS-1$ fTarget= target; + setAntTaskType(AntTaskType.TARGET); } /* (non-Javadoc) @@ -254,4 +255,14 @@ } return checkReferenceRegion(region, textToSearch, "name"); //$NON-NLS-1$ } + + public boolean containsOccurrence(String identifier, AntElementNode contextNode) { + // Interested only in targets and properties + if (AntTaskType.TARGET == contextNode.getAntTaskType() || AntTaskType.PROPERTY == contextNode.getAntTaskType()) { + return super.containsOccurrence(identifier, contextNode); + } + return false; + } + + } Index: Ant Tools Support/org/eclipse/ant/internal/ui/model/IAntModelConstants.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/model/IAntModelConstants.java,v retrieving revision 1.4 diff -u -r1.4 IAntModelConstants.java --- Ant Tools Support/org/eclipse/ant/internal/ui/model/IAntModelConstants.java 31 Mar 2005 17:49:47 -0000 1.4 +++ Ant Tools Support/org/eclipse/ant/internal/ui/model/IAntModelConstants.java 23 Aug 2009 20:25:50 -0000 @@ -34,4 +34,6 @@ public static final String ATTR_EXECUTABLE= "executable"; //$NON-NLS-1$ public static final String ATTR_DESCRIPTION= "description"; //$NON-NLS-1$ public static final String ATTR_ANT_FILE= "antfile"; //$NON-NLS-1$ + public static final String ATTR_URI= "uri"; //$NON-NLS-1$ + public static final String ATTR_XMLNS_PREFIX = "xmlns"; //$NON-NLS-1$ } Index: Ant Editor/org/eclipse/ant/internal/ui/editor/actions/AntEditorActionMessages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/Ant Editor/org/eclipse/ant/internal/ui/editor/actions/AntEditorActionMessages.properties,v retrieving revision 1.15 diff -u -r1.15 AntEditorActionMessages.properties --- Ant Editor/org/eclipse/ant/internal/ui/editor/actions/AntEditorActionMessages.properties 11 Apr 2006 14:43:09 -0000 1.15 +++ Ant Editor/org/eclipse/ant/internal/ui/editor/actions/AntEditorActionMessages.properties 23 Aug 2009 20:25:38 -0000 @@ -10,6 +10,10 @@ # John-Mason P. Shackelford - bug 40255 ############################################################################### +ExtractTaskAction.0=Extract Task +ExtractTaskAction.1=Extract Task to New Presetdef +ExtractTaskAction.2=Extract Task + OpenDeclarationAction.0=&Open Declaration OpenDeclarationAction.1=Open an editor on the referenced element OpenExternalDocAction.0=Open External Ant Documentation @@ -40,3 +44,5 @@ RenameInFileAction.0=Re&name In File RenameInFileAction.1=Renames all references within the same buildfile RenameInFileAction.2=Renames all references + +RefactorGroup.0=Refactor Index: Ant Editor/org/eclipse/ant/internal/ui/editor/actions/RenameInFileAction.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/Ant Editor/org/eclipse/ant/internal/ui/editor/actions/RenameInFileAction.java,v retrieving revision 1.5 diff -u -r1.5 RenameInFileAction.java --- Ant Editor/org/eclipse/ant/internal/ui/editor/actions/RenameInFileAction.java 3 May 2005 15:57:12 -0000 1.5 +++ Ant Editor/org/eclipse/ant/internal/ui/editor/actions/RenameInFileAction.java 23 Aug 2009 20:25:39 -0000 @@ -30,6 +30,35 @@ import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.ui.texteditor.link.EditorLinkedModeUI; +/** + * RenameInFileAction can rename:
+ *
    + *
  • targets: + *
      + *
    • definition
    • + *
    • dependency part
    • + *
    + *
  • + * + *
  • properties
  • + *
      + *
    • definition
    • + *
    • usage
    • + *
    + *
  • macrodefs, presetdefs, taskdefs, scriptdefs
  • + *
      + *
    • definition
    • + *
    • call
    • + *
    + *
  • macrodef`s attributes
  • + *
      + *
    • definition
    • + *
    • usage inside macrodef definition
    • + *
    • usage inside macrodef call
    • + *
    + * + *
+ */ public class RenameInFileAction extends SelectionDispatchAction { private AntEditor fEditor; @@ -110,6 +139,8 @@ * @see org.eclipse.jdt.ui.actions.SelectionDispatchAction#selectionChanged(org.eclipse.jface.text.ITextSelection) */ public void selectionChanged(ITextSelection selection) { + // This method confuse me a lot before I discover that this action to not register itself as selection listener. + // That`s why we can safely remove this method. setEnabled(fEditor != null); } Index: META-INF/MANIFEST.MF =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/META-INF/MANIFEST.MF,v retrieving revision 1.31 diff -u -r1.31 MANIFEST.MF --- META-INF/MANIFEST.MF 13 Apr 2009 14:20:28 -0000 1.31 +++ META-INF/MANIFEST.MF 23 Aug 2009 20:25:51 -0000 @@ -51,7 +51,8 @@ org.eclipse.team.core;bundle-version="[3.2.0,4.0.0)", org.eclipse.ltk.core.refactoring;bundle-version="[3.2.0,4.0.0)", org.eclipse.core.expressions;bundle-version="[3.2.0,4.0.0)", - org.eclipse.jdt.junit;bundle-version="3.5.0" + org.eclipse.jdt.junit;bundle-version="3.5.0", + org.eclipse.ltk.ui.refactoring;bundle-version="[3.2.100,4.0.0)" Bundle-ActivationPolicy: lazy Import-Package: com.ibm.icu.text Bundle-RequiredExecutionEnvironment: J2SE-1.4 Index: Ant Editor/org/eclipse/ant/internal/ui/editor/AntElementHyperlinkDetector.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/Ant Editor/org/eclipse/ant/internal/ui/editor/AntElementHyperlinkDetector.java,v retrieving revision 1.5 diff -u -r1.5 AntElementHyperlinkDetector.java --- Ant Editor/org/eclipse/ant/internal/ui/editor/AntElementHyperlinkDetector.java 19 Mar 2007 05:04:34 -0000 1.5 +++ Ant Editor/org/eclipse/ant/internal/ui/editor/AntElementHyperlinkDetector.java 23 Aug 2009 20:25:38 -0000 @@ -32,7 +32,7 @@ } fEditor = (AntEditor) getAdapter(AntEditor.class); region= XMLTextHover.getRegion(textViewer, region.getOffset()); - Object linkTarget= fEditor.findTarget(region); + Object linkTarget= fEditor.findTarget(region, false); if (linkTarget == null) { return null; } Index: Ant Editor/org/eclipse/ant/internal/ui/editor/OccurrencesFinder.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/Ant Editor/org/eclipse/ant/internal/ui/editor/OccurrencesFinder.java,v retrieving revision 1.9 diff -u -r1.9 OccurrencesFinder.java --- Ant Editor/org/eclipse/ant/internal/ui/editor/OccurrencesFinder.java 26 May 2005 21:33:02 -0000 1.9 +++ Ant Editor/org/eclipse/ant/internal/ui/editor/OccurrencesFinder.java 23 Aug 2009 20:25:38 -0000 @@ -11,12 +11,18 @@ package org.eclipse.ant.internal.ui.editor; import java.util.ArrayList; +import java.util.Hashtable; import java.util.Iterator; import java.util.List; +import org.apache.tools.ant.ProjectHelper; +import org.apache.tools.ant.RuntimeConfigurable; import org.eclipse.ant.internal.ui.editor.text.XMLTextHover; import org.eclipse.ant.internal.ui.model.AntElementNode; import org.eclipse.ant.internal.ui.model.AntModel; +import org.eclipse.ant.internal.ui.model.AntTargetNode; +import org.eclipse.ant.internal.ui.model.AntTaskNode; +import org.eclipse.ant.internal.ui.model.AntTaskType; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; @@ -50,12 +56,17 @@ if (!container.isRegionPotentialReference(region)) { return null; } + } else { + // no sense in future work when so bad region + return null; } AntElementNode node; if (container.isFromDeclaration(region)) { node= container; } else { - Object potentialNode= fEditor.findTarget(region); + // check, if we have property usage + boolean propertyUsage = isPropertyUsage(region, container); + Object potentialNode= fEditor.findTarget(region, propertyUsage); if (!(potentialNode instanceof AntElementNode)) { return null; } @@ -69,10 +80,11 @@ nodes.add(fAntModel.getProjectNode()); List usages= new ArrayList(); usages.add(node); - scanNodesForOccurrences(nodes, usages, occurrencesIdentifier); + scanNodesForOccurrencesWithContext(nodes, usages, occurrencesIdentifier, node); String identifier; try { identifier= fDocument.get(region.getOffset(), region.getLength()); + identifier = ProjectHelper.extractNameFromComponentName(identifier); } catch (BadLocationException e) { return null; } @@ -83,7 +95,7 @@ List positions= new ArrayList(usages.size()); for (Iterator each= usages.iterator(); each.hasNext();) { AntElementNode currentNode= (AntElementNode)each.next(); - List offsets= currentNode.computeIdentifierOffsets(identifier); + List offsets= currentNode.computeIdentifierOffsetsWithContext(identifier, node); if (offsets != null) { for (int i = 0; i < offsets.size(); i++) { positions.add(new Position(((Integer)offsets.get(i)).intValue(), length)); @@ -93,17 +105,72 @@ return positions; } - - private void scanNodesForOccurrences(List nodes, List usages, String identifier) { + /** + * Look if region - is using of property. Sometimes it`s not enough just look at prefix "${" + * @param region + * @param container + * @return + */ + private boolean isPropertyUsage(IRegion region, AntElementNode container) { + boolean result = false; + try { + String prefix = fDocument.get(region.getOffset() - 2, 2); + if (AntTaskType.PROPERTY_PREFIX.equals(prefix)) { + result = true; + } else { + String identifier = fDocument.get(region.getOffset(), region.getLength()); + if (identifier != null && identifier.length() > 0) { + // look at specific property usage (for task "fail" or "if" target ) + if (container instanceof AntTargetNode) { + AntTargetNode targetNode = (AntTargetNode)container; + if (identifier.equals(targetNode.getTarget().getIf()) + || identifier.equals(targetNode.getTarget().getUnless())) { + // usage of property without prefix + result = true; + } + } else if (container instanceof AntTaskNode) { + AntTaskNode taskNode = (AntTaskNode) container; + if ("fail".equals(taskNode.getName())) { //$NON-NLS-1$ + // most difficult case + RuntimeConfigurable wrapper = taskNode.getTask().getRuntimeConfigurableWrapper(); + Hashtable attributesTable = wrapper.getAttributeMap(); + String unlessValue = (String)attributesTable.get("unless"); //$NON-NLS-1$ + if (identifier.equals(unlessValue)) { + result = true; + } + } + + } + } + // String regexp = ""; + } + } catch (BadLocationException e) { + // mean that this is really not property usage :) + result = false; + } + return result; + } + + /** + * Scan project for occurrences, but with looking back to node context + * + * @param nodes list of nodes where we will looking for occurrences + * @param usages here we will place nodes, which were founded + * @param identifier we are looking for its occurrences + * @param contextNode parent of identifier + */ + private void scanNodesForOccurrencesWithContext(List nodes, List usages, + String identifier, AntElementNode contextNode) { Iterator iter= nodes.iterator(); while (iter.hasNext()) { AntElementNode node = (AntElementNode) iter.next(); - if (!usages.contains(node) && node.containsOccurrence(identifier)) { + if (!usages.contains(node) && node.containsOccurrence(identifier, contextNode)) { usages.add(node); } if (node.hasChildren()) { - scanNodesForOccurrences(node.getChildNodes(), usages, identifier); + // TODO StShadow >> think about better realization: recursion is not very good + scanNodesForOccurrencesWithContext(node.getChildNodes(), usages, identifier, contextNode); } - } + } } } \ No newline at end of file Index: Ant Editor/org/eclipse/ant/internal/ui/editor/AntEditor.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/Ant Editor/org/eclipse/ant/internal/ui/editor/AntEditor.java,v retrieving revision 1.115 diff -u -r1.115 AntEditor.java --- Ant Editor/org/eclipse/ant/internal/ui/editor/AntEditor.java 24 Nov 2008 17:56:34 -0000 1.115 +++ Ant Editor/org/eclipse/ant/internal/ui/editor/AntEditor.java 23 Aug 2009 20:25:38 -0000 @@ -28,8 +28,11 @@ import org.eclipse.ant.internal.ui.ExternalHyperlink; import org.eclipse.ant.internal.ui.IAntUIHelpContextIds; import org.eclipse.ant.internal.ui.IAntUIPreferenceConstants; +import org.eclipse.ant.internal.ui.editor.actions.AntEditorActionMessages; +import org.eclipse.ant.internal.ui.editor.actions.ExtractTaskAction; import org.eclipse.ant.internal.ui.editor.actions.FoldingActionGroup; import org.eclipse.ant.internal.ui.editor.actions.OpenDeclarationAction; +import org.eclipse.ant.internal.ui.editor.actions.RefactorActionGroup; import org.eclipse.ant.internal.ui.editor.actions.RenameInFileAction; import org.eclipse.ant.internal.ui.editor.actions.RunToLineAdapter; import org.eclipse.ant.internal.ui.editor.actions.ToggleLineBreakpointAction; @@ -64,6 +67,7 @@ import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.PropertyChangeEvent; @@ -493,6 +497,8 @@ private boolean fStickyOccurrenceAnnotations; private AntModel fAntModel; + + private RefactorActionGroup fRefactorActionGroup; /* (non-Javadoc) @@ -515,6 +521,15 @@ action= new RenameInFileAction(this); action.setActionDefinitionId("org.eclipse.ant.ui.renameInFile"); //$NON-NLS-1$ setAction("renameInFile", action); //$NON-NLS-1$ + + // add action to group + fRefactorActionGroup = new RefactorActionGroup(this); + fRefactorActionGroup.addAction(action); + + action= new ExtractTaskAction(this); + action.setActionDefinitionId("org.eclipse.ant.ui.extractTask"); //$NON-NLS-1$ + setAction(ExtractTaskAction.NAME, action); + fRefactorActionGroup.addAction(action); } /* @@ -819,7 +834,7 @@ ISourceViewer viewer= getSourceViewer(); int textOffset= textSelection.getOffset(); IRegion region= XMLTextHover.getRegion(viewer, textOffset); - target= findTarget(region); + target= findTarget(region, false); } openTarget(target); @@ -847,9 +862,10 @@ /** * @param region The region to find the navigation target + * @param propertyUsage * @return the navigation target at the specified region */ - public Object findTarget(IRegion region) { + public Object findTarget(IRegion region, boolean propertyUsage) { ISourceViewer viewer = getSourceViewer(); AntElementNode node= null; @@ -869,7 +885,7 @@ if (node == null) { node= model.getTargetNode(text); if (node == null) { - node= model.getPropertyNode(text); + node= model.getPropertyNode(text, region, propertyUsage); if (node == null) { String path= model.getPath(text, region.getOffset()); if (path != null) { @@ -879,7 +895,11 @@ node= model.getDefininingTaskNode(text); if (node == null) { - node= model.getMacroDefAttributeNode(text); + // need keep in mind where we are looking for text, so pass region too + node= model.getMacroDefAttributeNode(text, region); + if (node == null) { + node= model.getMacroDefNode(text); + } } } } @@ -942,10 +962,19 @@ } action= getAction("renameInFile"); //$NON-NLS-1$ + // TODO "group.edit" is equals to ITextEditorActionConstants.GROUP_EDIT. Why do not change this one with normal constant String editGroup = "group.edit"; //$NON-NLS-1$ menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, new Separator(editGroup)); - menu.appendToGroup(editGroup, action); - + // menu for refactoring actions + MenuManager refactorSubmenu= new MenuManager(AntEditorActionMessages.getString("RefactorGroup.0")); + refactorSubmenu.setActionDefinitionId(RefactorActionGroup.QUICK_MENU_ID); + // fill submenu with actions + fRefactorActionGroup.fillContextMenu(refactorSubmenu); + + //action= getAction(ExtractTaskAction.NAME); + //menu.appendToGroup(editGroup, action); + menu.appendToGroup(editGroup, refactorSubmenu); + action= getAction("ContentFormat"); //$NON-NLS-1$ menu.appendToGroup(editGroup, action); } Index: plugin.xml =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/plugin.xml,v retrieving revision 1.153 diff -u -r1.153 plugin.xml --- plugin.xml 4 May 2009 16:10:59 -0000 1.153 +++ plugin.xml 23 Aug 2009 20:25:35 -0000 @@ -126,7 +126,13 @@ name="%toggleMarkOccurrences.label" description="%toggleMarkOccurrences.description" categoryId="org.eclipse.jdt.ui.category.source" - id="org.eclipse.ant.ui.toggleMarkOccurrences" /> + id="org.eclipse.ant.ui.toggleMarkOccurrences" /> + + + + + + + + + + + + @@ -896,5 +923,8 @@ id="org.eclipse.ant.ui.antLineBreakpointMarker"> + + Index: Ant Tools Support/org/eclipse/ant/internal/ui/refactoring/RefactoringMessages.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/refactoring/RefactoringMessages.java,v retrieving revision 1.2 diff -u -r1.2 RefactoringMessages.java --- Ant Tools Support/org/eclipse/ant/internal/ui/refactoring/RefactoringMessages.java 13 Feb 2006 22:31:05 -0000 1.2 +++ Ant Tools Support/org/eclipse/ant/internal/ui/refactoring/RefactoringMessages.java 23 Aug 2009 20:25:51 -0000 @@ -14,6 +14,7 @@ public class RefactoringMessages extends NLS { private static final String BUNDLE_NAME = "org.eclipse.ant.internal.ui.refactoring.RefactoringMessages";//$NON-NLS-1$ + public static String LaunchConfigurationParticipant_0; public static String LaunchConfigurationBuildfileChange_0; public static String LaunchConfigurationBuildfileChange_1; @@ -22,6 +23,26 @@ public static String LaunchConfigurationBuildfileChange_5; public static String LaunchConfigurationBuildfileChange_6; public static String LaunchConfigurationBuildfileChange_7; + + /** + * Extract task messages + */ + public static String ExtractTask_Dialog_Title; + + public static String ExtractTask_Empty_uri_warning; + + public static String ExtractTask_Empty_name_error; + + public static String ExtractTask_Uri_label_text; + + public static String ExtractTask_Presetdef_name_label_text; + + public static String ExtractTask_root_edit_group; + + public static String GeneralRefactoring_test_selection; + + public static String GeneralRefactoring_fatal_error_in_selection; + static { // load message values from bundle file Index: Ant Tools Support/org/eclipse/ant/internal/ui/refactoring/RefactoringMessages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.ant.ui/Ant Tools Support/org/eclipse/ant/internal/ui/refactoring/RefactoringMessages.properties,v retrieving revision 1.3 diff -u -r1.3 RefactoringMessages.properties --- Ant Tools Support/org/eclipse/ant/internal/ui/refactoring/RefactoringMessages.properties 13 Feb 2006 22:31:05 -0000 1.3 +++ Ant Tools Support/org/eclipse/ant/internal/ui/refactoring/RefactoringMessages.properties 23 Aug 2009 20:25:51 -0000 @@ -16,4 +16,13 @@ LaunchConfigurationBuildfileChange_4=The project for the Ant launch configuration "{0}" is no longer "{1}". LaunchConfigurationBuildfileChange_5=The buildfile location for the Ant launch configuration "{0}" is no longer "{1}". LaunchConfigurationBuildfileChange_6=The Ant launch configuration "{0}" no longer exists. -LaunchConfigurationBuildfileChange_7=Ant Launch configuration updates \ No newline at end of file +LaunchConfigurationBuildfileChange_7=Ant Launch configuration updates + +ExtractTask_Dialog_Title=Extract Task to Presetdef +ExtractTask_Presetdef_name_label_text=Presetdef name: +ExtractTask_Uri_label_text=Uri: +ExtractTask_Empty_uri_warning=Empty uri is discouraged. According to convention, presetdefs should have nonempty uri. +ExtractTask_Empty_name_error=Name can not be empty +GeneralRefactoring_test_selection=Test selection +GeneralRefactoring_fatal_error_in_selection=Can not extract task: incorrect selection +ExtractTask_root_edit_group=Extract task to presetdef \ No newline at end of file Index: Ant Editor/org/eclipse/ant/internal/ui/refactoring/code/ExtractTaskRefactoring.java =================================================================== RCS file: Ant Editor/org/eclipse/ant/internal/ui/refactoring/code/ExtractTaskRefactoring.java diff -N Ant Editor/org/eclipse/ant/internal/ui/refactoring/code/ExtractTaskRefactoring.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Ant Editor/org/eclipse/ant/internal/ui/refactoring/code/ExtractTaskRefactoring.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,161 @@ +package org.eclipse.ant.internal.ui.refactoring.code; + +import org.eclipse.ant.internal.ui.editor.AntEditor; +import org.eclipse.ant.internal.ui.editor.formatter.FormattingPreferences; +import org.eclipse.ant.internal.ui.model.AntElementNode; +import org.eclipse.ant.internal.ui.refactoring.RefactoringAvailabilityTester; +import org.eclipse.ant.internal.ui.refactoring.RefactoringMessages; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.ltk.core.refactoring.Change; +import org.eclipse.ltk.core.refactoring.Refactoring; +import org.eclipse.ltk.core.refactoring.RefactoringStatus; +import org.eclipse.ltk.core.refactoring.TextFileChange; +import org.eclipse.text.edits.InsertEdit; +import org.eclipse.text.edits.MultiTextEdit; +import org.eclipse.text.edits.TextEditGroup; +//import org.eclipse.text.edits.MultiTextEdit; + +public class ExtractTaskRefactoring extends Refactoring { + // less visibility - less errors + private ITextSelection fOriginalSelection; + private AntEditor fEditor; + /** + * The name of new presetdef + */ + private String fName; + /** + * Uri for new presetdef. + */ + private String fUri = ""; //$NON-NLS-1$ + private AntElementNode fNode; + private ExtractTaskInputPage page = null; + + public ExtractTaskRefactoring(AntEditor editor, ITextSelection selection) { + fOriginalSelection = selection; + fEditor = editor; + } + + public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException { + RefactoringStatus status = new RefactoringStatus(); + if (fName == null || fName.length() == 0) { + status.addError(RefactoringMessages.ExtractTask_Empty_name_error); + } + if (fUri == null || fUri.length() == 0) { + status.addWarning(RefactoringMessages.ExtractTask_Empty_uri_warning); + if (page != null) { + page.setMessage(RefactoringMessages.ExtractTask_Empty_uri_warning, IMessageProvider.WARNING); + } + } else if (page != null) { + // disable warning label + page.setMessage(null); + } + // I do not think that we can get here null node + return status; + } + + public void setPage(final ExtractTaskInputPage page) { + this.page = page; + } + + public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException { + int totalWork = 4; + pm.beginTask(RefactoringMessages.GeneralRefactoring_test_selection, totalWork); + RefactoringStatus status = new RefactoringStatus(); + // if we are here first time... + if (fNode ==null) { + // check for correct node and make suggestion of name + fNode = RefactoringAvailabilityTester.getTaskNode(fEditor, fOriginalSelection); + pm.worked(2); + if (fNode != null) { + fName = fNode.getName(); + //status.add + } else { + // very serious reason for fatal error + status.addFatalError(RefactoringMessages.GeneralRefactoring_fatal_error_in_selection); + } + } + return status; + } + + public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException { + // get source file + IFile file = fEditor.getAntModel().getFile(); + TextFileChange result = new TextFileChange(file.getName(), file); + + result.setSaveMode(TextFileChange.LEAVE_DIRTY); + //result. + MultiTextEdit fileChangeRootEdit = new MultiTextEdit(); + result.setEdit( fileChangeRootEdit ); + + // find place, where we should put new presetdef + // TODO St.Shadow >> What about placing presetdefs inside targets? + // find end of container which is contain our call + int offset = fNode.getParentNode().getOffset() + fNode.getParentNode().getLength() + 1; + // create new presetdef + String newNode = createNewNodeText(); + // put it to file + InsertEdit insertEdit = new InsertEdit(offset, newNode); + + // Hack for avoiding bug with wrong preview generation + result.addTextEditGroup(new TextEditGroup(RefactoringMessages.ExtractTask_root_edit_group, insertEdit)); + //result.addTextEditChangeGroup(new TextEditGroup("Extract task to presetdef", insertEdit)); + //fileChangeRootEdit.addChild(); + + fileChangeRootEdit.addChild(insertEdit); + // result.setTextType("xml"); + return result; + + + + } + + /** + * Create + * @return string representation of new presetdef, ready for insertions + */ + private String createNewNodeText() { + StringBuffer newNodeText = new StringBuffer(); + // load preferences + FormattingPreferences prefs = new FormattingPreferences(); + // construct node text + // start on new line + newNodeText.append('\n'); + // Indentation - one level with target - that why one indentation + String indent = prefs.getCanonicalIndent(); + newNodeText.append(indent); + // 0) { + // append uri + newNodeText.append(" uri=\"").append(fUri).append('"'); //$NON-NLS-1$ + } + newNodeText.append('>'); + newNodeText.append('\n').append(indent).append(indent); + // original task call + newNodeText.append(fEditor.getAntModel().getText(fNode.getOffset() - 1, fNode.getLength() + 1)); // strange, why I need +-1 here... + newNodeText.append('\n').append(indent).append(""); //$NON-NLS-1$ + return newNodeText.toString(); + } + + public String getName() { + return fName; + } + + public void setName(String newName) { + fName = newName; + } + + public String getUri() { + return fUri; + } + + public void setUri(String newUri) { + fUri = newUri; + } +} Index: Ant Editor/org/eclipse/ant/internal/ui/refactoring/code/ExtractTaskWizard.java =================================================================== RCS file: Ant Editor/org/eclipse/ant/internal/ui/refactoring/code/ExtractTaskWizard.java diff -N Ant Editor/org/eclipse/ant/internal/ui/refactoring/code/ExtractTaskWizard.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Ant Editor/org/eclipse/ant/internal/ui/refactoring/code/ExtractTaskWizard.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,22 @@ +package org.eclipse.ant.internal.ui.refactoring.code; + +import org.eclipse.ltk.core.refactoring.Refactoring; +import org.eclipse.ltk.ui.refactoring.RefactoringWizard; + +/** + * Wizard with two pages (and possible error?warning page). + * @author St.Shadow + * + */ +public class ExtractTaskWizard extends RefactoringWizard { + + public ExtractTaskWizard(Refactoring refactoring, int flags) { + super(refactoring, flags); + } + + protected void addUserInputPages() { + addPage(new ExtractTaskInputPage()); + + } + +} Index: Ant Editor/org/eclipse/ant/internal/ui/refactoring/code/ExtractTaskInputPage.java =================================================================== RCS file: Ant Editor/org/eclipse/ant/internal/ui/refactoring/code/ExtractTaskInputPage.java diff -N Ant Editor/org/eclipse/ant/internal/ui/refactoring/code/ExtractTaskInputPage.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Ant Editor/org/eclipse/ant/internal/ui/refactoring/code/ExtractTaskInputPage.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,88 @@ +package org.eclipse.ant.internal.ui.refactoring.code; + +import org.eclipse.ant.internal.ui.refactoring.RefactoringMessages; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.ltk.ui.refactoring.UserInputWizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +public class ExtractTaskInputPage extends UserInputWizardPage { + public static String PAGE_NAME = "ExtractTaskInputPage"; //$NON-NLS-1$ + private ExtractTaskRefactoring fRefactoring ; + public ExtractTaskInputPage() { + super(PAGE_NAME); + } + + public void createControl(Composite parent) { + fRefactoring = (ExtractTaskRefactoring) getRefactoring(); + // create and place components + Composite superComposite = new Composite(parent, SWT.NONE); + setControl(superComposite); + superComposite.setLayout(new GridLayout()); + Composite composite = new Composite(superComposite, SWT.NONE); + composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + GridLayout layout= new GridLayout(); + layout.numColumns= 2; + //layout. + layout.marginHeight= 0; + layout.marginWidth= 0; + + composite.setLayout(layout); + + Label label= new Label(composite, SWT.NONE); + label.setText(RefactoringMessages.ExtractTask_Presetdef_name_label_text); + + final Text text= new Text(composite, SWT.BORDER); + text.setText(fRefactoring.getName()); + text.selectAll(); + GridData gd= new GridData(GridData.FILL_HORIZONTAL); + gd.widthHint= convertWidthInCharsToPixels(25); + text.setLayoutData(gd); + // modifier listener + text.addModifyListener(new ModifyListener() { + + public void modifyText(ModifyEvent e) { + String name = text.getText().trim(); + fRefactoring.setName(name); + // disable navigation buttons with empty name + if (name.length() == 0) { + setPageComplete(false); + } else { + setPageComplete(true); + } + } + }); + + Label uriLabel = new Label(composite, SWT.NONE); + uriLabel.setText(RefactoringMessages.ExtractTask_Uri_label_text); + final Text uriText = new Text(composite, SWT.BORDER); + uriText.setText(fRefactoring.getUri()); + uriText.setLayoutData(gd); + + uriText.addModifyListener(new ModifyListener() { + + public void modifyText(ModifyEvent e) { + String uri = uriText.getText().trim(); + fRefactoring.setUri(uri); + if (uri.length() == 0) { + setMessage(RefactoringMessages.ExtractTask_Empty_uri_warning, IMessageProvider.WARNING); + } else { + setMessage(null); + } + } + }); + + Label separator= new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL); + GridData gridData = (new GridData(GridData.FILL_HORIZONTAL)); + gridData.horizontalSpan = 2; + gridData.heightHint = 20; + separator.setLayoutData(gridData); + } +} Index: Ant Tools Support/org/eclipse/ant/internal/ui/model/AntTaskType.java =================================================================== RCS file: Ant Tools Support/org/eclipse/ant/internal/ui/model/AntTaskType.java diff -N Ant Tools Support/org/eclipse/ant/internal/ui/model/AntTaskType.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Ant Tools Support/org/eclipse/ant/internal/ui/model/AntTaskType.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,131 @@ +package org.eclipse.ant.internal.ui.model; + + +/** + * Emulate enum, which contains all possible types of ant nodes + * + * @author Anatoli Putseyeu + * + */ +public class AntTaskType { + + /** + * Name of this type - just for info and toString method + */ + private String name; + + /** + * Private constructor - we do not allow clients instantiate this class + */ + private AntTaskType(String name) { + this.name = name; + } + + public static final String TAG_MACRODEF = "macrodef"; //$NON-NLS-1$ + + public static final String TAG_TASKDEF = "taskdef"; //$NON-NLS-1$ + + public static final String TAG_PRESETDEF = "presetdef"; //$NON-NLS-1$ + + public static final String TAG_TYPEDEF = "typedef"; //$NON-NLS-1$ + + public static final String TAG_SEQUENTIAL = "sequential"; //$NON-NLS-1$ + + public static final String TAG_SCRIPTDEF = "scriptdef"; //$NON-NLS-1$ + + public static final String TAG_ATTRIBYTE = "attribute"; //$NON-NLS-1$ + + // enum definitions of ant types + public static final AntTaskType MACRODEF_DEFINITION = new AntTaskType("Macrodef definition"); //$NON-NLS-1$ + public static final AntTaskType MACRODEF_CALL = new AntTaskType("Call to macrodef"); //$NON-NLS-1$ + public static final AntTaskType ATTRIBUTE = new AntTaskType("Macrodef attribute"); //$NON-NLS-1$ + public static final AntTaskType SEQUENTIAL = new AntTaskType("Macrodef Sequential"); //$NON-NLS-1$ + + public static final AntTaskType TASK_DEFINITION = new AntTaskType("Task definition"); //$NON-NLS-1$ + public static final AntTaskType TASK_CALL = new AntTaskType("Call to task"); //$NON-NLS-1$ + + public static final AntTaskType PRESETDEF_DEFINITION = new AntTaskType("Presetdef definition"); //$NON-NLS-1$ + public static final AntTaskType PRESETDEF_CALL = new AntTaskType("Call to presetdef"); //$NON-NLS-1$ + + public static final AntTaskType SCRIPTDEF_DEFINITION = new AntTaskType("Scriptdef definition"); //$NON-NLS-1$ + public static final AntTaskType SCRIPTDEF_CALL = new AntTaskType("Call to scriptdef"); //$NON-NLS-1$ + + public static final AntTaskType TARGET = new AntTaskType("Target"); //$NON-NLS-1$ + public static final AntTaskType PROJECT = new AntTaskType("Project"); //$NON-NLS-1$ + public static final AntTaskType PROPERTY = new AntTaskType("Property"); //$NON-NLS-1$ + + public static final AntTaskType UNDEFINED_NODE = new AntTaskType("Undefined node"); //$NON-NLS-1$ + + + public static final String PROPERTY_PREFIX = "${"; //$NON-NLS-1$ + + public static final AntTaskType TYPEDEF_DEFINITION = new AntTaskType("Typedef"); //$NON-NLS-1$ + + + public String toString() { + return name; + } + + public static AntTaskType getAntTaskTypeByName(String name) { + // TODO fill with remaining types + if (TAG_MACRODEF.equalsIgnoreCase(name)) { + return MACRODEF_DEFINITION; + } else if (TAG_TASKDEF.equalsIgnoreCase(name)) { + return TASK_DEFINITION; + } else if (TAG_PRESETDEF.equalsIgnoreCase(name)) { + return PRESETDEF_DEFINITION; + } else if (TAG_ATTRIBYTE.equals(name)) { + return ATTRIBUTE; + } else if (TAG_SEQUENTIAL.equals(name)) { + return SEQUENTIAL; + } else if (TAG_SCRIPTDEF.equals(name)) { + return SCRIPTDEF_DEFINITION; + } else {//if () + //|| TAG_TYPEDEF.equalsIgnoreCase(name);) + return UNDEFINED_NODE; + } + } + + public static boolean isDefinitionNode(String name) { + return TAG_MACRODEF.equalsIgnoreCase(name) + || TAG_TASKDEF.equalsIgnoreCase(name) + || TAG_PRESETDEF.equalsIgnoreCase(name) + || TAG_TYPEDEF.equalsIgnoreCase(name) + || TAG_SCRIPTDEF.equalsIgnoreCase(name); + } + + public static boolean isDefinitionNode(AntTaskType antTaskType) { + return MACRODEF_DEFINITION == antTaskType + || TASK_DEFINITION == antTaskType + || PRESETDEF_DEFINITION == antTaskType + || SCRIPTDEF_DEFINITION == antTaskType + || TYPEDEF_DEFINITION == antTaskType; + } + + public static boolean isCallNode(AntTaskType antTaskType) { + return MACRODEF_CALL == antTaskType + || TASK_CALL == antTaskType + || PRESETDEF_CALL == antTaskType + || SCRIPTDEF_CALL == antTaskType + || UNDEFINED_NODE == antTaskType; + } + + public static AntTaskType getCallTypeByName(String taskName) { + if (TAG_MACRODEF.equalsIgnoreCase(taskName)) { + return MACRODEF_CALL; + } else if (TAG_TASKDEF.equalsIgnoreCase(taskName)) { + return TASK_CALL; + } else if (TAG_PRESETDEF.equalsIgnoreCase(taskName)) { + return PRESETDEF_CALL; + } else if (TAG_ATTRIBYTE.equals(taskName)) { + return ATTRIBUTE; + } else if (TAG_SEQUENTIAL.equals(taskName)) { + return SEQUENTIAL; + } else if (TAG_SCRIPTDEF.equals(taskName)) { + return SCRIPTDEF_CALL; + } else {//if () + //|| TAG_TYPEDEF.equalsIgnoreCase(taskName);) + return UNDEFINED_NODE; + } + } +} Index: Ant Editor/org/eclipse/ant/internal/ui/editor/actions/ExtractTaskAction.java =================================================================== RCS file: Ant Editor/org/eclipse/ant/internal/ui/editor/actions/ExtractTaskAction.java diff -N Ant Editor/org/eclipse/ant/internal/ui/editor/actions/ExtractTaskAction.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Ant Editor/org/eclipse/ant/internal/ui/editor/actions/ExtractTaskAction.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,58 @@ +package org.eclipse.ant.internal.ui.editor.actions; + +import org.eclipse.ant.internal.ui.editor.AntEditor; +import org.eclipse.ant.internal.ui.refactoring.RefactoringAvailabilityTester; +import org.eclipse.ant.internal.ui.refactoring.RefactoringMessages; +import org.eclipse.ant.internal.ui.refactoring.code.ExtractTaskRefactoring; +import org.eclipse.ant.internal.ui.refactoring.code.ExtractTaskWizard; +import org.eclipse.jdt.ui.actions.SelectionDispatchAction; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.ltk.ui.refactoring.RefactoringWizard; +import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation; + +/** + * Trigger the start of extraction task to presetdef. + * + * @author St.Shadow + * + */ +public class ExtractTaskAction extends SelectionDispatchAction /* implements IEditorActionDelegate */ { + + private AntEditor fEditor; + + public static final String NAME= "extractTask"; //$NON-NLS-1$ + + public ExtractTaskAction(AntEditor editor) { + super(editor.getSite()); + fEditor= editor; + setText(AntEditorActionMessages.getString("ExtractTaskAction.0")); //$NON-NLS-1$ + setDescription(AntEditorActionMessages.getString("ExtractTaskAction.1")); //$NON-NLS-1$ + setToolTipText(AntEditorActionMessages.getString("ExtractTaskAction.2")); //$NON-NLS-1$ + setEnabled(false); + // install listeners + if (fEditor.getSelectionProvider() != null) { + fEditor.getSelectionProvider().addSelectionChangedListener(this); + } + } + + + public void run(ITextSelection selection) { + ExtractTaskRefactoring refactoring = new ExtractTaskRefactoring(fEditor, selection); + + try { + RefactoringWizardOpenOperation op= new RefactoringWizardOpenOperation(new ExtractTaskWizard(refactoring, + RefactoringWizard.DIALOG_BASED_USER_INTERFACE | RefactoringWizard.PREVIEW_EXPAND_FIRST_NODE)); + // Do not need result + op.run(getShell(), RefactoringMessages.ExtractTask_Dialog_Title); + // StSh >> no sense - this method is called automatically + //fEditor.getAntModel().reconcile(); + } catch (InterruptedException e) { + // return false; // User action got canceled + } + } + + public void selectionChanged(ITextSelection selection) { + setEnabled(RefactoringAvailabilityTester.isFullOneTask(fEditor, selection)); + } + +} Index: Ant Editor/org/eclipse/ant/internal/ui/refactoring/RefactoringAvailabilityTester.java =================================================================== RCS file: Ant Editor/org/eclipse/ant/internal/ui/refactoring/RefactoringAvailabilityTester.java diff -N Ant Editor/org/eclipse/ant/internal/ui/refactoring/RefactoringAvailabilityTester.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Ant Editor/org/eclipse/ant/internal/ui/refactoring/RefactoringAvailabilityTester.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,74 @@ +package org.eclipse.ant.internal.ui.refactoring; + +import org.eclipse.ant.internal.ui.editor.AntEditor; +import org.eclipse.ant.internal.ui.model.AntElementNode; +import org.eclipse.ant.internal.ui.model.AntTaskType; +import org.eclipse.jface.text.ITextSelection; + +/** + * Helper class for ant buildfile refactoring. + * @author St.Shadow + * + */ +public class RefactoringAvailabilityTester { + // TODO update javadoc + /** + * Test selection, if this is one and only one call to task. Leading and trailing spaces are not "schitajutsya" + * @param selection can contain task. + * @return true, if full one task. + */ + public static boolean isFullOneTask(AntEditor editor, ITextSelection selection) { + + // we know, that task can start only with '<' + return getTaskNode(editor, selection) != null; + } + + /** + * If selection contain one task - return it: all spaces (and other non-alphabetic symbols) + * at the end ant at the start are skipped. + */ + public static AntElementNode getTaskNode(AntEditor editor, ITextSelection selection) { + AntElementNode result = null; + // skip empty or too short selection (at least '<' + 's' + '/>' = 4) + if (selection != null && selection.getLength() >= 4) { + //skip spaces + String trimmedText = selection.getText().trim(); + // now we at the first chat. + if (trimmedText.length() > 0 && trimmedText.startsWith("<")) { //$NON-NLS-1$ + + // look for matched '>' or space if attributes present + int nameEndOffset = 0; + while ( nameEndOffset < trimmedText.length() && '>' != trimmedText.charAt(nameEndOffset) && '/' != trimmedText.charAt(nameEndOffset) && !Character.isWhitespace(trimmedText.charAt(nameEndOffset))) { + ++nameEndOffset; + } + if (nameEndOffset < selection.getLength() && nameEndOffset > 0) { +/* TODO think about usecase for short calls + * boolean shortCall = false; + if (trimmedText.endsWith("/>")) { + shortCall = true; + }*/ + + // extract task + String potentialTaskName = trimmedText.substring(1, nameEndOffset); + + // TODO now just skip call to task with namespace - need additional usecase for it + if (potentialTaskName.contains(":")) { //$NON-NLS-1$ + return null; + } + + // check, if we have task with this name + // TODO look like the inventing of bicycle + AntElementNode potentialTaskNode = editor.getAntModel().getTaskNode(potentialTaskName, selection.getOffset(), selection.getLength()); + if (potentialTaskNode != null && AntTaskType.isCallNode(potentialTaskNode.getAntTaskType())) { + // if we find task - that mean that out selection at least cover this node + if (trimmedText.length() == potentialTaskNode.getLength() + 1) { // 1 - special for missed '<' + result = potentialTaskNode; + } + } + + } + } + } + return result; + } +} Index: Ant Editor/org/eclipse/ant/internal/ui/editor/actions/RefactorActionGroup.java =================================================================== RCS file: Ant Editor/org/eclipse/ant/internal/ui/editor/actions/RefactorActionGroup.java diff -N Ant Editor/org/eclipse/ant/internal/ui/editor/actions/RefactorActionGroup.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Ant Editor/org/eclipse/ant/internal/ui/editor/actions/RefactorActionGroup.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,65 @@ +package org.eclipse.ant.internal.ui.editor.actions; + +import java.util.ArrayList; +import java.util.Iterator; + +import org.eclipse.ant.internal.ui.editor.AntEditor; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.actions.ActionGroup; + +/** + * Group ant refactor context actions in "Refactor" group. Add this group to editor`s menu. + * Also take care of correct disposing. + * @author St.Shadow + * + */ +public class RefactorActionGroup extends ActionGroup { + + public static final String QUICK_MENU_ID = "org.eclipse.ant.internal.ui.editor.actions.refactoring"; //$NON-NLS-1$ + + private ArrayList fActions = new ArrayList(); + private AntEditor fEditor; + + + public RefactorActionGroup(AntEditor antEditor) { + fEditor = antEditor; + } + + /** + * Add action to group. If action exists yet, adding is skipping. + * Action is added to the bottom of the submenu. + * @param action + */ + public void addAction(IAction action) { + // do not allow duplicates + if (!fActions.contains(action)) { + fActions.add(action); + } + } + + public void dispose() { + ISelectionProvider provider = fEditor.getSelectionProvider(); + if (provider != null) { + for (Iterator actionsIterator = fActions.iterator(); actionsIterator.hasNext();) { + // trust but verify + if (actionsIterator.next() instanceof ISelectionListener) { + ISelectionChangedListener listener= (ISelectionChangedListener) actionsIterator.next(); + provider.removeSelectionChangedListener(listener); + } + } + } + super.dispose(); + } + + public void fillContextMenu(IMenuManager menu) { + for (Iterator actionsIterator = fActions.iterator(); actionsIterator.hasNext();) { + menu.add((IAction) actionsIterator.next()); + } + } + + +}