// Copyright (c) 2007-2008 by Leif Frenzel - see http://leiffrenzel.de // This code is made available under the terms of the Eclipse Public License, // version 1.0 (EPL). See http://www.eclipse.org/legal/epl-v10.html package net.sf.eclipsefp.haskell.ui.internal.refactoring; import java.util.List; import net.sf.eclipsefp.haskell.buildwrapper.types.Location; import net.sf.eclipsefp.haskell.buildwrapper.types.Occurrence; import net.sf.eclipsefp.haskell.buildwrapper.types.ThingAtPoint; import net.sf.eclipsefp.haskell.buildwrapper.usage.UsageQueryFlags; import net.sf.eclipsefp.haskell.ui.HaskellUIPlugin; import net.sf.eclipsefp.haskell.ui.handlers.ReferencesWorkspaceHandler; import net.sf.eclipsefp.haskell.ui.internal.editors.haskell.HaskellEditor; import net.sf.eclipsefp.haskell.ui.internal.refactoring.participants.ChangeCreator; import net.sf.eclipsefp.haskell.ui.internal.search.UsageQuery; import net.sf.eclipsefp.haskell.ui.internal.search.UsageSearchResult; import net.sf.eclipsefp.haskell.ui.internal.util.UITexts; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.ltk.core.refactoring.Change; import org.eclipse.ltk.core.refactoring.CompositeChange; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext; import org.eclipse.ltk.core.refactoring.participants.IConditionChecker; import org.eclipse.ltk.core.refactoring.participants.ValidateEditChecker; /** <p>delegate object that contains the logic used by the processor.</p> * * @author Leif Frenzel */ public class RenameDelegate extends RefDelegate { private CompositeChange change; private String newName; private IProject project; public RenameDelegate( final RefInfo info ) { super( info ); info.setAllowEmptySelection( true ); ThingAtPoint tap=getThingAtPoint(); if (tap!=null){ newName=tap.getName(); project=info.getSourceFile().getProject(); } } @Override RefactoringStatus checkFinalConditions( final IProgressMonitor pm, final CheckConditionsContext ctxt ) { RefactoringStatus result = new RefactoringStatus(); try { pm.beginTask( UITexts.refDelegate_checking, 100 ); if( ctxt != null ) { IConditionChecker checker = ctxt.getChecker( ValidateEditChecker.class ); ValidateEditChecker editChecker = ( ValidateEditChecker )checker; editChecker.addFile( info.getSourceFile() ); } change = createRenameChange(pm); if( change == null ) { result.addFatalError( UITexts.mkPointFreeDelegate_notApplicable ); } } finally { pm.done(); } return result; } @Override void createChange( final IProgressMonitor pm, final CompositeChange rootChange ) { try { pm.beginTask( UITexts.mkPointFreeDelegate_collectingChanges, 100 ); if( change == null ) { throw new IllegalStateException(); } // do not have the intermediate step for (Change c:change.getChildren()){ change.remove( c ); rootChange.add( c ); } //rootChange.add( change ); } finally { pm.done(); } } // helping methods ////////////////// private CompositeChange createRenameChange(final IProgressMonitor pm) { CompositeChange result = null; if (info.getTargetEditor() instanceof HaskellEditor){ final HaskellEditor haskellEditor= (HaskellEditor)info.getTargetEditor(); try { Location l=getLocation(); if (l!=null){ ThingAtPoint tap=getThingAtPoint(l); if (tap!=null){ UsageQuery uq=ReferencesWorkspaceHandler.getUsageQuery( haskellEditor, getProject(), tap ); uq.setScopeFlags( UsageQueryFlags.SCOPE_ALL ); uq.run( pm ); UsageSearchResult usr=(UsageSearchResult)uq.getSearchResult(); if (usr.getResults().getSize()>0){ CompositeChange cc=ChangeCreator.getReferencesChange( usr.getResults(), tap.getName(), getNewName() ); return cc; } else { // nothing found: change locally List<Occurrence> occs=haskellEditor.getTokenScanner().getOccurrences( l.getStartOffset( haskellEditor.getDocument() ) ); Location spanLocation=haskellEditor.getOutlineSpan( getLocation().getStartOffset( haskellEditor.getDocument() ) ); if (spanLocation!=null){ CompositeChange cc=ChangeCreator.getLocalReferencesChange(haskellEditor.findFile(),spanLocation, occs, tap.getName(), getNewName() ); return cc; } } } } } catch (Exception e){ HaskellUIPlugin.log( e ); } } // TODO TtC replace by something not Cohatoe-based /* CohatoeServer server = CohatoeServer.getInstance(); IRename fun = server.createFunction( IRename.class ); if( fun != null ) { String newName = "I-AM-THE-NEW-NAME"; int line = info.getLine(); int column = info.getColumn(); List<IReplaceEditDesc> descs = fun.performRename( info.getSourceFile(), line, column, newName ); Map<IFile, List<IReplaceEditDesc>> map = mapByFile( descs ); for( IFile file: map.keySet() ) { result = new TextFileChange( file.getName(), file ); // a file change contains a tree of edits, first add the root of them MultiTextEdit fileChangeRootEdit = new MultiTextEdit(); result.setEdit( fileChangeRootEdit ); // edit object for the text replacement in the file, // this is the only child List<IReplaceEditDesc> editDescs = map.get( file ); for( IReplaceEditDesc editDesc: editDescs ) { ReplaceEdit edit = new ReplaceEdit( editDesc.getOffset(), editDesc.getLength(), editDesc.getReplacement() ); fileChangeRootEdit.addChild( edit ); } } } */ return result; } public String getNewName() { return newName; } public void setNewName( final String newName ) { this.newName = newName; } public IProject getProject() { return project; } public void setProject( final IProject project ) { this.project = project; } /* private Map<IFile, List<IReplaceEditDesc>> mapByFile( final List<IReplaceEditDesc> editDescs ) { Map<IFile, List<IReplaceEditDesc>> result = new HashMap<IFile, List<IReplaceEditDesc>>(); for( IReplaceEditDesc editDesc: editDescs ) { List<IReplaceEditDesc> list = result.get( editDesc.getFile() ); if( list == null ) { list = new ArrayList<IReplaceEditDesc>(); result.put( editDesc.getFile(), list ); } list.add( editDesc ); } return result; } */ }