Compatibility fragment commit
[phpeclipse.git] / net.sourceforge.phpeclipse.32.compatibility / src / net / sourceforge / phpdt / ltk / core / RenameIdentifierDelegate.java
diff --git a/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/ltk/core/RenameIdentifierDelegate.java b/net.sourceforge.phpeclipse.32.compatibility/src/net/sourceforge/phpdt/ltk/core/RenameIdentifierDelegate.java
new file mode 100644 (file)
index 0000000..beaf423
--- /dev/null
@@ -0,0 +1,386 @@
+// Copyright (c) 2005 by Leif Frenzel. All rights reserved.
+// See http://leiffrenzel.de
+// modified for phpeclipse.de project by axelcl
+package net.sourceforge.phpdt.ltk.core;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
+import net.sourceforge.phpdt.core.compiler.InvalidInputException;
+import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
+import net.sourceforge.phpdt.internal.compiler.parser.SyntaxError;
+import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+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.TextFileChange;
+import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
+import org.eclipse.ltk.core.refactoring.participants.IConditionChecker;
+import org.eclipse.ltk.core.refactoring.participants.ValidateEditChecker;
+import org.eclipse.text.edits.MultiTextEdit;
+import org.eclipse.text.edits.ReplaceEdit;
+
+/**
+ * <p>
+ * delegate object that contains the logic used by the processor.
+ * </p>
+ * 
+ */
+public class RenameIdentifierDelegate {
+
+       // private static final String EXT_PROPERTIES = "properties"; //$NON-NLS-1$
+
+       protected final RenameIdentifierInfo info;
+
+       // PHP file with the identifier to rename -> offset of the key
+       protected final Map phpFiles;
+
+       public RenameIdentifierDelegate(final RenameIdentifierInfo info) {
+               this.info = info;
+               phpFiles = new HashMap();
+       }
+
+       RefactoringStatus checkInitialConditions() {
+               RefactoringStatus result = new RefactoringStatus();
+               IFile sourceFile = info.getSourceFile();
+               if (sourceFile == null || !sourceFile.exists()) {
+                       result.addFatalError(CoreTexts.renamePropertyDelegate_noSourceFile);
+               } else if (info.getSourceFile().isReadOnly()) {
+                       result.addFatalError(CoreTexts.renamePropertyDelegate_roFile);
+               } else if (isEmpty(info.getOldName())) {
+                       // || !isPropertyKey( info.getSourceFile(), info.getOldName() ) ) {
+                       result.addFatalError(CoreTexts.renamePropertyDelegate_noPHPKey);
+               }
+               return result;
+       }
+
+       RefactoringStatus checkFinalConditions(final IProgressMonitor pm,
+                       final CheckConditionsContext ctxt) {
+               RefactoringStatus result = new RefactoringStatus();
+               pm.beginTask(CoreTexts.renamePropertyDelegate_checking, 100);
+               // do something long-running here: traverse the entire project (or even
+               // workspace) to look for all *.properties files with the same bundle
+               // base name
+               IContainer rootContainer;
+               ArrayList phpProjects = new ArrayList();
+               IProject project;
+               if (info.isAllProjects()) {
+                       rootContainer = ResourcesPlugin.getWorkspace().getRoot();
+                       IResource[] members;
+                       try {
+                               members = rootContainer.members();
+                               for (int i = 0; i < members.length; i++) {
+                                       if (members[i] instanceof IProject) {
+                                               project = (IProject) members[i];
+                                               try {
+                                                       if (project
+                                                                       .isNatureEnabled(PHPeclipsePlugin.PHP_NATURE_ID)) {
+                                                               search(project, result);
+                                                       }
+                                               } catch (CoreException e) {
+                                                       String msg = "Project: "
+                                                                       + project.getLocation().toOSString()
+                                                                       + " CoreException " + e.getMessage();
+                                                       result.addError(msg);
+                                               } catch (Exception e) {
+                                                       String msg = "Project: "
+                                                                       + project.getLocation().toOSString()
+                                                                       + " Exception " + e.getMessage();
+                                                       result.addError(msg);
+                                               }
+                                       }
+                               }
+                       } catch (CoreException e) {
+                               String msg = "Workspace: "
+                                               + rootContainer.getLocation().toOSString()
+                                               + " CoreException " + e.getMessage();
+                               result.addError(msg);
+                       }
+               } else {
+                       project = info.getSourceFile().getProject();
+                       try {
+                               if (project.isNatureEnabled(PHPeclipsePlugin.PHP_NATURE_ID)) {
+                                       search(project, result);
+                               }
+                       } catch (CoreException e) {
+                               String msg = "Project: " + project.getLocation().toOSString()
+                                               + " CoreException " + e.getMessage();
+                               result.addError(msg);
+                       } catch (Exception e) {
+                               String msg = "Project: " + project.getLocation().toOSString()
+                                               + " Exception " + e.getMessage();
+                               result.addError(msg);
+                       }
+               }
+
+               pm.worked(50);
+
+               if (ctxt != null) {
+                       IFile[] files = new IFile[phpFiles.size()];
+                       phpFiles.keySet().toArray(files);
+                       IConditionChecker checker = ctxt
+                                       .getChecker(ValidateEditChecker.class);
+                       ValidateEditChecker editChecker = (ValidateEditChecker) checker;
+                       editChecker.addFiles(files);
+               }
+               pm.done();
+               return result;
+       }
+
+       protected void createChange(final IProgressMonitor pm,
+                       final CompositeChange rootChange) {
+               try {
+                       pm.beginTask(CoreTexts.renamePropertyDelegate_collectingChanges,
+                                       100);
+                       // all files in the same bundle
+                       if (info.isUpdateProject()) {
+                               rootChange.addAll(createChangesForContainer(pm));
+                       }
+               } finally {
+                       pm.done();
+               }
+       }
+
+       // helping methods
+       // ////////////////
+
+       // private Change createRenameChange() {
+       // // create a change object for the file that contains the property the
+       // // user has selected to rename
+       // IFile file = info.getSourceFile();
+       // TextFileChange 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
+       // ReplaceEdit edit = new ReplaceEdit(info.getOffset(),
+       // info.getOldName().length(), info.getNewName());
+       // fileChangeRootEdit.addChild(edit);
+       // return result;
+       // }
+
+       protected Change[] createChangesForContainer(final IProgressMonitor pm) {
+               List result = new ArrayList();
+               Iterator it = phpFiles.keySet().iterator();
+               int numberOfFiles = phpFiles.size();
+               double percent = 100 / numberOfFiles;
+               int work = 0;
+               int indx = 0;
+               while (it.hasNext()) {
+                       IFile file = (IFile) it.next();
+                       List list = getKeyOffsets(file);
+                       if (list != null && list.size() > 0) {
+                               TextFileChange tfc = new TextFileChange(file.getName(), file);
+                               MultiTextEdit fileChangeRootEdit = new MultiTextEdit();
+                               tfc.setEdit(fileChangeRootEdit);
+
+                               // edit object for the text replacement in the file, there could
+                               // be
+                               // multiple childs
+                               ReplaceEdit edit;
+                               for (int i = 0; i < list.size(); i++) {
+                                       edit = new ReplaceEdit(((Integer) list.get(i)).intValue(),
+                                                       info.getOldName().length(), info.getNewName());
+                                       fileChangeRootEdit.addChild(edit);
+                               }
+                               result.add(tfc);
+                       }
+                       work = new Double((++indx) * percent).intValue();
+                       pm.worked(work);
+               }
+               return (Change[]) result.toArray(new Change[result.size()]);
+       }
+
+       protected boolean isEmpty(final String candidate) {
+               return candidate == null || candidate.trim().length() == 0;
+       }
+
+       // private boolean isPropertyKey( final IFile file, final String candidate )
+       // {
+       // boolean result = false;
+       // try {
+       // Properties props = new Properties();
+       // props.load( file.getContents() );
+       // result = props.containsKey( candidate );
+       // } catch( Exception ex ) {
+       // // ignore this, we just assume this is not a favourable situation
+       // ex.printStackTrace();
+       // }
+       // return result;
+       // }
+
+       // // whether the file is a PHP file with the same base name as the
+       // // one we refactor and contains the key that interests us
+       // private boolean isToRefactor(final IFile file) {
+       // return PHPFileUtil.isPHPFile(file);
+       // // && !file.equals( info.getSourceFile() )
+       // // && isPropertyKey( file, info.getOldName() );
+       // }
+
+       // private String getBundleBaseName() {
+       // String result = info.getSourceFile().getName();
+       // int underscoreIndex = result.indexOf( '_' );
+       // if( underscoreIndex != -1 ) {
+       // result = result.substring( 0, underscoreIndex );
+       // } else {
+       // int index = result.indexOf( EXT_PROPERTIES ) - 1;
+       // result = result.substring( 0, index );
+       // }
+       // return result;
+       // }
+
+       private void search(final IContainer rootContainer,
+                       final RefactoringStatus status) {
+               try {
+                       IResource[] members = rootContainer.members();
+                       for (int i = 0; i < members.length; i++) {
+                               if (members[i] instanceof IContainer) {
+                                       search((IContainer) members[i], status);
+                               } else {
+                                       IFile file = (IFile) members[i];
+                                       handleFile(file, status);
+                               }
+                       }
+               } catch (final CoreException cex) {
+                       status.addFatalError(cex.getMessage());
+               }
+       }
+
+       private void handleFile(final IFile file, final RefactoringStatus status) {
+               if (PHPFileUtil.isPHPFile(file)) {
+                       determineKeyOffsets(file, status);
+                       // if (keyOffsets.size() > 0) {
+                       // Integer offset = new Integer(keyOffsets);
+                       // phpFiles.put(file, offset);
+                       // }
+               }
+       }
+
+       protected List getKeyOffsets(final IFile file) {
+               return (List) phpFiles.get(file);
+       }
+
+       // finds the offsets of the identifier to rename
+       // usually, this would be the job of a proper parser;
+       // using a primitive brute-force approach here
+       private void determineKeyOffsets(final IFile file,
+                       final RefactoringStatus status) {
+               ArrayList matches = new ArrayList();
+               try {
+                       String content = readFileContent(file, status);
+                       Scanner scanner = new Scanner(true, false);
+                       scanner.setSource(content.toCharArray());
+                       scanner.setPHPMode(false);
+                       char[] word = info.getOldName().toCharArray();
+
+                       int fToken = ITerminalSymbols.TokenNameEOF;
+                       try {
+                               fToken = scanner.getNextToken();
+                               while (fToken != ITerminalSymbols.TokenNameEOF) {
+                                       if (fToken == ITerminalSymbols.TokenNameVariable
+                                                       || fToken == ITerminalSymbols.TokenNameIdentifier) {
+                                               if (scanner.equalsCurrentTokenSource(word)) {
+                                                       matches.add(new Integer(scanner
+                                                                       .getCurrentTokenStartPosition()));
+                                               }
+                                       }
+                                       fToken = scanner.getNextToken();
+                               }
+
+                       } catch (InvalidInputException e) {
+                               String msg = "File: " + file.getLocation().toOSString()
+                                               + " InvalidInputException " + e.getMessage();
+                               status.addError(msg);
+                       } catch (SyntaxError e) {
+                               String msg = "File: " + file.getLocation().toOSString()
+                                               + " SyntaxError " + e.getMessage();
+                               status.addError(msg);
+                       }
+
+               } catch (Exception e) {
+                       String msg = "File: " + file.getLocation().toOSString()
+                                       + " Exception " + e.getMessage();
+                       status.addError(msg);
+               }
+               if (matches.size() > 0) {
+                       phpFiles.put(file, matches);
+               }
+
+               // int result = -1;
+               // int candidateIndex = content.indexOf(info.getOldName());
+               // result = candidateIndex;
+               // while( result == -1 && candidateIndex != -1 ) {
+               // if( isKeyOccurrence( content, candidateIndex ) ) {
+               // result = candidateIndex;
+               // }
+               // }
+               // if( result == -1 ) {
+               // // still nothing found, we add a warning to the status
+               // // (we have checked the file contains the property, so that we can't
+               // // determine it's offset is probably because of the rough way
+               // employed
+               // // here to find it)
+               // String msg = CoreTexts.renamePropertyDelegate_propNotFound
+               // + file.getLocation().toOSString();
+               // status.addWarning( msg );
+               // }
+               // return result;
+       }
+
+       private String readFileContent(final IFile file,
+                       final RefactoringStatus refStatus) {
+               String result = null;
+               try {
+                       InputStream is = file.getContents();
+                       byte[] buf = new byte[1024];
+                       ByteArrayOutputStream bos = new ByteArrayOutputStream();
+                       int len = is.read(buf);
+                       while (len > 0) {
+                               bos.write(buf, 0, len);
+                               len = is.read(buf);
+                       }
+                       is.close();
+                       result = new String(bos.toByteArray());
+               } catch (Exception ex) {
+                       String msg = ex.toString();
+                       refStatus.addFatalError(msg);
+                       String pluginId = PHPeclipsePlugin.getPluginId();
+                       IStatus status = new Status(IStatus.ERROR, pluginId, 0, msg, ex);
+                       PHPeclipsePlugin.getDefault().getLog().log(status);
+               }
+               return result;
+       }
+
+       // we check only that there is a separator before the next line break (this
+       // is not sufficient, the whole thing may be in a comment etc. ...)
+       // private boolean isKeyOccurrence( final String content,
+       // final int candidateIndex ) {
+       // int index = candidateIndex + info.getOldName().length();
+       // // skip whitespace
+       // while( content.charAt( index ) == ' ' || content.charAt( index ) == '\t'
+       // )
+       // {
+       // index++;
+       // }
+       // return content.charAt( index ) == '=' || content.charAt( index ) == ':';
+       // }
+}