/**
* (c) 2011, Alejandro Serrano
* Released under the terms of the EPL.
*/
package net.sf.eclipsefp.haskell.ui.internal.refactoring.participants;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import net.sf.eclipsefp.haskell.buildwrapper.BuildWrapperPlugin;
import net.sf.eclipsefp.haskell.buildwrapper.types.Location;
import net.sf.eclipsefp.haskell.buildwrapper.types.Occurrence;
import net.sf.eclipsefp.haskell.buildwrapper.types.SearchResultLocation;
import net.sf.eclipsefp.haskell.buildwrapper.types.UsageResults;
import net.sf.eclipsefp.haskell.buildwrapper.usage.UsageAPI;
import net.sf.eclipsefp.haskell.core.util.ResourceUtil;
import net.sf.eclipsefp.haskell.ui.HaskellUIPlugin;
import net.sf.eclipsefp.haskell.ui.internal.util.UITexts;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.text.IDocument;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.ui.editors.text.TextFileDocumentProvider;
import org.eclipse.ui.texteditor.IDocumentProvider;
/**
* Common methods for creating changes in participants, because
* most of them are reused between file and folder operations.
* @author Alejandro Serrano
* @author JP Moresmau
*/
public class ChangeCreator {
public static TextFileChange createCopyChange(final IFile oldFile, final IFile newFile) {
String oldModule = ResourceUtil.getModuleName( oldFile );
String newModule = ResourceUtil.getModuleName( newFile );
// Create changes in module
TextFileChange change = new TextFileChange( UITexts.copyParticipant_title, newFile );
int moduleNamePos = Util.getModuleNameOffset( newFile,oldModule );
if (moduleNamePos != -1) {
change.setEdit( new ReplaceEdit( moduleNamePos, oldModule.length(), newModule ) );
}
return change;
}
public static CompositeChange createRenameMoveFolderChange(final List<IFile> files,
final IPath oldPath, final IPath newPath, final boolean updateReferences,
final String compositeTitle, final String elementTitle) {
CompositeChange change = new CompositeChange( compositeTitle );
for (IFile file : files) {
IPath oldFilePath = file.getProjectRelativePath();
IPath noPrefixPath = oldFilePath.removeFirstSegments( oldPath.segmentCount() );
IPath newFilePath = newPath.append( noPrefixPath );
Change fileChange = createRenameMoveChange( file, newFilePath, updateReferences, elementTitle );
change.add( fileChange );
}
return change;
}
public static Change createRenameMoveFolderCabalChange(final IProject project, final IPath oldPath, final IPath newPath) {
// Cabal reference
String newCabalFile = Util.newSourceFolderCabalFile( project, oldPath, newPath );
IFile cabalF = BuildWrapperPlugin.getCabalFile( project );
TextFileDocumentProvider provider = new TextFileDocumentProvider();
TextFileChange cabalChanges = null;
try {
provider.connect( cabalF );
IDocument doc = provider.getDocument( cabalF );
int length = doc.getLength();
if (!newCabalFile.equals( doc.get() )) {
cabalChanges = new TextFileChange( UITexts.updateCabalFile, cabalF);
cabalChanges.setEdit( new ReplaceEdit( 0, length, newCabalFile ) );
}
} catch (Exception e) {
cabalChanges = null;
} finally {
provider.disconnect( cabalF );
}
return cabalChanges;
}
public static CompositeChange getReferencesChange(final UsageResults ur,final String oldName,final String newName){
CompositeChange referencesChange = new CompositeChange( UITexts.updateReferences );
for (IProject refP:ur.listProjects()){
Map<IFile,Map<String,Collection<SearchResultLocation>>> um =ur.getUsageInProject( refP );
for (IFile f:um.keySet()){
TextFileChange importChanges = new TextFileChange( UITexts.updateReferences,f);
MultiTextEdit multiEdit = new MultiTextEdit();
IDocumentProvider prov=new TextFileDocumentProvider();
try {
prov.connect( f );
IDocument doc=prov.getDocument( f );
try {
for (Collection<SearchResultLocation> csrl:um.get( f ).values()){
for (SearchResultLocation srl:csrl){
int offset=srl.getStartOffset( doc );
multiEdit.addChild( new ReplaceEdit( offset, oldName.length(), newName ));
}
}
} finally {
prov.disconnect( f );
}
} catch (Exception ce){
HaskellUIPlugin.log( ce );
}
importChanges.setEdit( multiEdit );
referencesChange.add( importChanges );
}
}
return referencesChange;
}
/**
* change occurrence locally
* @param f the file
* @param filter the location of the outline span, only occurrences within this location are used
* @param occs the occurences
* @param oldName the old name
* @param newName the new name
* @return the change
*/
public static CompositeChange getLocalReferencesChange(final IFile f,final Location filter,final List<Occurrence> occs,final String oldName,final String newName){
CompositeChange referencesChange = new CompositeChange( UITexts.updateReferences );
TextFileChange importChanges = new TextFileChange( UITexts.updateReferences,f);
MultiTextEdit multiEdit = new MultiTextEdit();
IDocumentProvider prov=new TextFileDocumentProvider();
try {
prov.connect( f );
IDocument doc=prov.getDocument( f );
try {
for (Occurrence occ: occs){
if (filter.contains( occ.getLine() , occ.getColumn())){
int offset=doc.getLineOffset( occ.getLine()-1 )+occ.getColumn();
multiEdit.addChild( new ReplaceEdit( offset, oldName.length(), newName ));
}
}
} finally {
prov.disconnect( f );
}
} catch (Exception ce){
HaskellUIPlugin.log( ce );
}
importChanges.setEdit( multiEdit );
referencesChange.add( importChanges );
return referencesChange;
}
public static Change createRenameMoveChange(final IFile file, final IPath newPath,
final boolean updateReferences, final String title) {
String oldModule = ResourceUtil.getModuleName( file );
String newModule = ResourceUtil.getModuleName(file.getProject().getFile( newPath ));
// Create changes in module
TextFileChange change = new TextFileChange( title, file );
int moduleNamePos = Util.getModuleNameOffset( file,oldModule );
if (moduleNamePos != -1) {
change.setEdit( new ReplaceEdit( moduleNamePos, oldModule.length(), newModule ) );
}
if( updateReferences ) {
// Update references
UsageAPI api=BuildWrapperPlugin.getDefault().getUsageAPI();
if (api==null){
return change;
}
UsageResults ur=api.getModuleReferences( null, oldModule, null, true );
boolean someChange = ur.getSize()>0;
CompositeChange referencesChange=getReferencesChange( ur, oldModule,newModule);
/*for (IResource resource : Util.getHaskellFiles( file.getProject(), file )) {
List<Integer> offsets = Util.getImportModuleOffsets( resource, oldModule );
if (offsets.size() > 0) {
TextFileChange importChanges = new TextFileChange( UITexts.updateReferences, (IFile)resource);
MultiTextEdit multiEdit = new MultiTextEdit();
for (int offset : offsets) {
multiEdit.addChild( new ReplaceEdit( offset, oldModule.length(), newModule ) );
}
importChanges.setEdit( multiEdit );
referencesChange.add( importChanges );
someChange = true;
}
}*/
// Cabal reference
String newCabalFile = Util.newCabalFile( file.getProject(), file, newModule );
IFile cabalF = BuildWrapperPlugin.getCabalFile( file.getProject() );
TextFileDocumentProvider provider = new TextFileDocumentProvider();
TextFileChange cabalChanges = null;
try {
provider.connect( cabalF );
try {
IDocument doc = provider.getDocument( cabalF );
int length = doc.getLength();
if (!newCabalFile.equals( doc.get() )) {
cabalChanges = new TextFileChange( UITexts.updateCabalFile, cabalF);
cabalChanges.setEdit( new ReplaceEdit( 0, length, newCabalFile ) );
someChange = true;
}
} finally {
provider.disconnect( cabalF );
}
} catch (Exception e) {
// Do nothing
}
if (someChange) {
return new CompositeChange( title, new Change[] { change, referencesChange, cabalChanges } );
} else {
return change;
}
} else {
return change;
}
}
public static Change createRenameMoveInOtherProjectChange(final IFile file, final IPath newPath,
final boolean updateReferences, final String title) {
String oldModule = ResourceUtil.getModuleName( file );
String newModule = ResourceUtil.getModuleName( file.getProject().getFile( newPath));
// Create changes in module
TextFileChange change = new TextFileChange( title, file );
int moduleNamePos = Util.getModuleNameOffset( file,oldModule );
if (moduleNamePos != -1) {
change.setEdit( new ReplaceEdit( moduleNamePos, oldModule.length(), newModule ) );
}
if( updateReferences ) {
boolean someChange = false;
// Cabal reference
String newCabalFile = Util.newRemoveModuleCabalFile( file.getProject(), file );
IFile cabalF = BuildWrapperPlugin.getCabalFile( file.getProject() );
TextFileDocumentProvider provider = new TextFileDocumentProvider();
TextFileChange cabalChanges = null;
try {
provider.connect( cabalF );
IDocument doc = provider.getDocument( cabalF );
int length = doc.getLength();
if (!newCabalFile.equals( doc.get() )) {
cabalChanges = new TextFileChange( UITexts.updateCabalFile, cabalF);
cabalChanges.setEdit( new ReplaceEdit( 0, length, newCabalFile ) );
someChange = true;
}
provider.disconnect( cabalF );
} catch (Exception e) {
// Do nothing
}
if (someChange) {
return new CompositeChange( title, new Change[] { change, cabalChanges } );
} else {
return change;
}
} else {
return change;
}
}
}