From ec4c61acf61d0e04a98838efa7d43de3c84c026f Mon Sep 17 00:00:00 2001 From: axelcl Date: Tue, 3 Jan 2006 23:07:05 +0000 Subject: [PATCH] Basic Reafctoring functionality adapted from Leif Frenzels sources in eclipse-magazin (published under Eclipse Public License - v 1.0) See sources at: http://www.eclipse-magazin.de/itr/ausgaben/psfile/datei/61/frenzel_lt437d8f486fb21.zip Feature #1358828 --- .../net/sourceforge/phpdt/ltk/core/CoreTexts.java | 36 +++ .../phpdt/ltk/core/RenamePropertyDelegate.java | 280 ++++++++++++++++++++ .../phpdt/ltk/core/RenamePropertyInfo.java | 82 ++++++ .../phpdt/ltk/core/RenamePropertyProcessor.java | 71 +++++ .../phpdt/ltk/core/RenamePropertyRefactoring.java | 31 +++ .../phpdt/ltk/core/coretexts.properties | 7 + .../src/net/sourceforge/phpdt/ltk/ui/UITexts.java | 32 +++ .../phpdt/ltk/ui/actions/RenamePHPIdentifier.java | 167 ++++++++++++ .../sourceforge/phpdt/ltk/ui/uitexts.properties | 5 + .../ltk/ui/wizards/RenamePropertyInputPage.java | 176 ++++++++++++ .../phpdt/ltk/ui/wizards/RenamePropertyWizard.java | 40 +++ 11 files changed, 927 insertions(+), 0 deletions(-) create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/CoreTexts.java create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/RenamePropertyDelegate.java create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/RenamePropertyInfo.java create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/RenamePropertyProcessor.java create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/RenamePropertyRefactoring.java create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/coretexts.properties create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/UITexts.java create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/actions/RenamePHPIdentifier.java create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/uitexts.properties create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/wizards/RenamePropertyInputPage.java create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/wizards/RenamePropertyWizard.java diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/CoreTexts.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/CoreTexts.java new file mode 100644 index 0000000..3c8c23f --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/CoreTexts.java @@ -0,0 +1,36 @@ +// Copyright (c) 2005 by Leif Frenzel. All rights reserved. +// See http://leiffrenzel.de +package net.sourceforge.phpdt.ltk.core; + +import org.eclipse.osgi.util.NLS; + +/** + *

+ * provides internationalized messages Strings from the coretexts resource + * bundle. + *

+ * + * @author Leif Frenzel + */ +public class CoreTexts extends NLS { + + private static final String BUNDLE_NAME = "net.sourceforge.phpdt.ltk.core.coretexts"; //$NON-NLS-1$ + + static { + NLS.initializeMessages(BUNDLE_NAME, CoreTexts.class); + } + + // message fields + public static String renamePropertyProcessor_name; + + public static String renamePropertyDelegate_noSourceFile; + + public static String renamePropertyDelegate_roFile; + + public static String renamePropertyDelegate_noPHPKey; + + public static String renamePropertyDelegate_collectingChanges; + + public static String renamePropertyDelegate_checking; + // public static String renamePropertyDelegate_propNotFound; +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/RenamePropertyDelegate.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/RenamePropertyDelegate.java new file mode 100644 index 0000000..80677a8 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/RenamePropertyDelegate.java @@ -0,0 +1,280 @@ +// Copyright (c) 2005 by Leif Frenzel. All rights reserved. +// See http://leiffrenzel.de +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.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.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; + +/** + *

+ * delegate object that contains the logic used by the processor. + *

+ * + * @author Leif Frenzel + */ +class RenamePropertyDelegate { + + // private static final String EXT_PROPERTIES = "properties"; //$NON-NLS-1$ + + private final RenamePropertyInfo info; + + // properties file with the key to rename -> offset of the key + private final Map phpFiles; + + RenamePropertyDelegate(final RenamePropertyInfo 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; + if (info.isAllProjects()) { + rootContainer = ResourcesPlugin.getWorkspace().getRoot(); + } else { + rootContainer = info.getSourceFile().getProject(); + } + search(rootContainer, result); + 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; + } + + void createChange(final IProgressMonitor pm, final CompositeChange rootChange) { + try { + pm.beginTask(CoreTexts.renamePropertyDelegate_collectingChanges, 100); + // the property which was directly selected by the user + rootChange.add(createRenameChange()); + pm.worked(10); + // all files in the same bundle + if (info.isUpdateBundle()) { + rootChange.addAll(createChangesForBundle()); + } + pm.worked(90); + } 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; + } + + private Change[] createChangesForBundle() { + List result = new ArrayList(); + Iterator it = phpFiles.keySet().iterator(); + while (it.hasNext()) { + IFile file = (IFile) it.next(); + + TextFileChange tfc = new TextFileChange(file.getName(), file); + MultiTextEdit fileChangeRootEdit = new MultiTextEdit(); + tfc.setEdit(fileChangeRootEdit); + + // edit object for the text replacement in the file, this is the only + // child + ReplaceEdit edit = new ReplaceEdit(getKeyOffset(file), info.getOldName().length(), info.getNewName()); + fileChangeRootEdit.addChild(edit); + + result.add(tfc); + } + return (Change[]) result.toArray(new Change[result.size()]); + } + + private 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 (isToRefactor(file)) { + determineKeyOffsets(file, status); + // if (keyOffsets.size() > 0) { + // Integer offset = new Integer(keyOffsets); + // phpFiles.put(file, offset); + // } + } + } + + private int getKeyOffset(final IFile file) { + return ((Integer) phpFiles.get(file)).intValue(); + } + + // finds the offset of the property key 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) { + String content = readFileContent(file, status); + int indx = 0; + while ((indx = content.indexOf(info.getOldName(), indx)) >= 0) { + phpFiles.put(file, Integer.valueOf(indx++)); + } + // 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 ) == ':'; + // } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/RenamePropertyInfo.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/RenamePropertyInfo.java new file mode 100644 index 0000000..b1c95a7 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/RenamePropertyInfo.java @@ -0,0 +1,82 @@ +// Copyright (c) 2005 by Leif Frenzel. All rights reserved. +// See http://leiffrenzel.de +package net.sourceforge.phpdt.ltk.core; + +import org.eclipse.core.resources.IFile; + + +/**

an info object that holds the information that is passed from + * the user to the refactoring.

+ * + * @author Leif Frenzel + */ +public class RenamePropertyInfo { + + // the offset of the property to be renamed in the file + private int offset; + // the new name for the property + private String newName; + // the old name of the property (as selected by the user) + private String oldName; + // the file that contains the property to be renamed + private IFile sourceFile; + // whether the refactoring should also change the name of the property + // in corresponding properties files in the same bundle (i.e. which start + // with the same name) + private boolean updateBundle; + // whether the refactoring should also update properties files in other + // projects than the current one + private boolean allProjects; + + + // interface methods of IRenamePropertyInfo + /////////////////////////////////////////// + + public int getOffset() { + return offset; + } + + public void setOffset( final int offset ) { + this.offset = offset; + } + + public String getNewName() { + return newName; + } + + public void setNewName( final String newName ) { + this.newName = newName; + } + + public String getOldName() { + return oldName; + } + + public void setOldName( final String oldName ) { + this.oldName = oldName; + } + + public IFile getSourceFile() { + return sourceFile; + } + + public void setSourceFile( final IFile sourceFile ) { + this.sourceFile = sourceFile; + } + + public boolean isAllProjects() { + return allProjects; + } + + public void setAllProjects( final boolean allProjects ) { + this.allProjects = allProjects; + } + + public boolean isUpdateBundle() { + return updateBundle; + } + + public void setUpdateBundle( final boolean updateBundle ) { + this.updateBundle = updateBundle; + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/RenamePropertyProcessor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/RenamePropertyProcessor.java new file mode 100644 index 0000000..46cde24 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/RenamePropertyProcessor.java @@ -0,0 +1,71 @@ +// Copyright (c) 2005 by Leif Frenzel. All rights reserved. +// See http://leiffrenzel.de +package net.sourceforge.phpdt.ltk.core; + +import org.eclipse.core.runtime.*; +import org.eclipse.ltk.core.refactoring.*; +import org.eclipse.ltk.core.refactoring.participants.*; + +/**

The processor is where the work is delegated to if participants are + * involved. The processor loads the participants and manages the lifecycle + * of the refactoring. In order to do that, the refactoring entry point + * methods must be implemented.

+ * + * @author Leif Frenzel + */ +public class RenamePropertyProcessor extends RefactoringProcessor { + + private final RenamePropertyInfo info; + private final RenamePropertyDelegate delegate; + + public RenamePropertyProcessor( final RenamePropertyInfo info ) { + this.info = info; + delegate = new RenamePropertyDelegate( info ); + } + + + // interface methods of RefactoringProcessor + //////////////////////////////////////////// + + public Object[] getElements() { + // usually, this would be some element object in the object model on which + // we work (e.g. a Java element if we were in the Java Model); in this case + // we have only the property name + return new Object[] { info.getOldName() }; + } + + public String getIdentifier() { + return getClass().getName(); + } + + public String getProcessorName() { + return CoreTexts.renamePropertyProcessor_name; + } + + public boolean isApplicable() throws CoreException { + return true; + } + + public RefactoringStatus checkInitialConditions( final IProgressMonitor pm ) { + return delegate.checkInitialConditions(); + } + + public RefactoringStatus checkFinalConditions( + final IProgressMonitor pm, final CheckConditionsContext context ) { + return delegate.checkFinalConditions( pm, context ); + } + + public Change createChange( final IProgressMonitor pm ) { + CompositeChange result = new CompositeChange( getProcessorName() ); + delegate.createChange( pm, result ); + return result; + } + + public RefactoringParticipant[] loadParticipants( + final RefactoringStatus status, + final SharableParticipants sharedParticipants ) { + // This would be the place to load the participants via the + // ParticipantManager and decide which of them are allowed to participate. + return new RefactoringParticipant[ 0 ]; + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/RenamePropertyRefactoring.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/RenamePropertyRefactoring.java new file mode 100644 index 0000000..2cff300 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/RenamePropertyRefactoring.java @@ -0,0 +1,31 @@ +// Copyright (c) 2005 by Leif Frenzel. All rights reserved. +// See http://leiffrenzel.de +package net.sourceforge.phpdt.ltk.core; + +import org.eclipse.ltk.core.refactoring.participants.ProcessorBasedRefactoring; +import org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor; + +/**

Refactoring for renaming properties in Java Properties files.

+ * + *

All the actual work is done in the processor, so we just have to + * keep a reference to one here.

+ * + * @author Leif Frenzel + */ +public class RenamePropertyRefactoring extends ProcessorBasedRefactoring { + + private final RefactoringProcessor processor; + + public RenamePropertyRefactoring( final RefactoringProcessor processor ) { + super( processor ); + this.processor = processor; + } + + + // interface methods of ProcessorBasedRefactoring + ///////////////////////////////////////////////// + + public RefactoringProcessor getProcessor() { + return processor; + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/coretexts.properties b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/coretexts.properties new file mode 100644 index 0000000..d9494a8 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/core/coretexts.properties @@ -0,0 +1,7 @@ +renamePropertyProcessor_name=Rename PHP Identifier +renamePropertyDelegate_noSourceFile=No source file could be determined. +renamePropertyDelegate_roFile=File is read-only. +renamePropertyDelegate_noPHPKey=The selected text does not appear to be a valid PHP identifier. +renamePropertyDelegate_collectingChanges=Collecting changes +renamePropertyDelegate_checking=Checking +renamePropertyDelegate_propNotFound=Could not find the property in file\: \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/UITexts.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/UITexts.java new file mode 100644 index 0000000..949c04b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/UITexts.java @@ -0,0 +1,32 @@ +// Copyright (c) 2005 by Leif Frenzel. All rights reserved. +// See http://leiffrenzel.de +package net.sourceforge.phpdt.ltk.ui; + +import org.eclipse.osgi.util.NLS; + +/** + *

+ * provides internationalized String messages for the UI. + *

+ * + * @author Leif Frenzel + */ +public class UITexts { + + private static final String BUNDLE_NAME = "net.sourceforge.phpdt.ltk.ui.uitexts"; //$NON-NLS-1$ + + static { + NLS.initializeMessages(BUNDLE_NAME, UITexts.class); + } + + // message fields + public static String renameProperty_refuseDlg_title; + + public static String renameProperty_refuseDlg_message; + + public static String renamePropertyInputPage_lblNewName; + + public static String renamePropertyInputPage_cbUpdateBundle; + + public static String renamePropertyInputPage_cbAllProjects; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/actions/RenamePHPIdentifier.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/actions/RenamePHPIdentifier.java new file mode 100644 index 0000000..9e38cd5 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/actions/RenamePHPIdentifier.java @@ -0,0 +1,167 @@ +// Copyright (c) 2005 by Leif Frenzel. All rights reserved. +// See http://leiffrenzel.de +package net.sourceforge.phpdt.ltk.ui.actions; + +import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil; +import net.sourceforge.phpdt.ltk.core.RenamePropertyInfo; +import net.sourceforge.phpdt.ltk.core.RenamePropertyProcessor; +import net.sourceforge.phpdt.ltk.core.RenamePropertyRefactoring; +import net.sourceforge.phpdt.ltk.ui.UITexts; +import net.sourceforge.phpdt.ltk.ui.wizards.RenamePropertyWizard; +import net.sourceforge.phpeclipse.phpeditor.PHPEditor; +import net.sourceforge.phpeclipse.phpeditor.php.PHPWordExtractor; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor; +import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IEditorActionDelegate; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.ide.IDE; +import org.eclipse.ui.texteditor.ITextEditor; + +/** + *

+ * action that is triggered from the editor context menu. + *

+ * + *

+ * This action is declared in the plugin.xml. + *

+ * + * @author Leif Frenzel + */ +public class RenamePHPIdentifier implements IEditorActionDelegate { + + private static final String EXT_PROPERTIES = "properties"; //$NON-NLS-1$ + + private ISelection selection; + + private IEditorPart targetEditor; + + private boolean onPropertiesFile; + + private RenamePropertyInfo info = new RenamePropertyInfo(); + + // interface methods of IEditorActionDelegate + // /////////////////////////////////////////// + + public void setActiveEditor(final IAction action, final IEditorPart targetEditor) { + this.targetEditor = targetEditor; + onPropertiesFile = false; + IFile file = getFile(); + + if (file != null && PHPFileUtil.isPHPFile(file)) { + onPropertiesFile = true; + } + } + + public void run(final IAction action) { + if (!onPropertiesFile) { + refuse(); + } else { + if (selection != null && selection instanceof ITextSelection) { + String word = null; + Point point = null; + if (targetEditor != null && (targetEditor instanceof PHPEditor)) { + PHPEditor editor = (PHPEditor) targetEditor; + if (editor != null) { + ITextSelection textSelection = (ITextSelection) editor.getSelectionProvider().getSelection(); + IDocument doc = editor.getDocumentProvider().getDocument(editor.getEditorInput()); + int pos = textSelection.getOffset(); + point = PHPWordExtractor.findWord(doc, pos); + if (point != null) { + try { + word = doc.get(point.x, point.y); + } catch (BadLocationException e) { + } + } + } + } + applySelection((ITextSelection) selection, word, point); + if (saveAll()) { + openWizard(); + } + } + } + } + + public void selectionChanged(final IAction action, final ISelection selection) { + this.selection = selection; + } + + // helping methods + // //////////////// + + private void applySelection(final ITextSelection textSelection, String word, Point point) { + if (word != null) { + info.setOldName(word); + info.setNewName(word); + info.setOffset(point.x); + } else { + info.setOldName(textSelection.getText()); + info.setNewName(textSelection.getText()); + info.setOffset(textSelection.getOffset()); + } + info.setSourceFile(getFile()); + } + + private void refuse() { + String title = UITexts.renameProperty_refuseDlg_title; + String message = UITexts.renameProperty_refuseDlg_message; + MessageDialog.openInformation(getShell(), title, message); + } + + private static boolean saveAll() { + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + return IDE.saveAllEditors(new IResource[] { workspaceRoot }, false); + } + + private void openWizard() { + RefactoringProcessor processor = new RenamePropertyProcessor(info); + RenamePropertyRefactoring ref = new RenamePropertyRefactoring(processor); + RenamePropertyWizard wizard = new RenamePropertyWizard(ref, info); + RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard); + try { + String titleForFailedChecks = ""; //$NON-NLS-1$ + op.run(getShell(), titleForFailedChecks); + } catch (final InterruptedException irex) { + // operation was cancelled + } + } + + private Shell getShell() { + Shell result = null; + if (targetEditor != null) { + result = targetEditor.getSite().getShell(); + } else { + result = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); + } + return result; + } + + private final IFile getFile() { + IFile result = null; + if (targetEditor instanceof ITextEditor) { + ITextEditor editor = (ITextEditor) targetEditor; + IEditorInput input = editor.getEditorInput(); + if (input instanceof IFileEditorInput) { + result = ((IFileEditorInput) input).getFile(); + } + } + return result; + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/uitexts.properties b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/uitexts.properties new file mode 100644 index 0000000..f3ad862 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/uitexts.properties @@ -0,0 +1,5 @@ +renameProperty_refuseDlg_title=Rename PHP identifier +renameProperty_refuseDlg_message=This refactoring is only available on PHP files. +renamePropertyInputPage_lblNewName=New name\: +renamePropertyInputPage_cbUpdateBundle=Update all properties files in the same bundle +renamePropertyInputPage_cbAllProjects=Update all projects in the workspace (forces preview) \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/wizards/RenamePropertyInputPage.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/wizards/RenamePropertyInputPage.java new file mode 100644 index 0000000..2f7eb74 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/wizards/RenamePropertyInputPage.java @@ -0,0 +1,176 @@ +// Copyright (c) 2005 by Leif Frenzel. All rights reserved. +// See http://leiffrenzel.de +package net.sourceforge.phpdt.ltk.ui.wizards; + +import net.sourceforge.phpdt.ltk.core.RenamePropertyInfo; +import net.sourceforge.phpdt.ltk.ui.UITexts; +import net.sourceforge.phpeclipse.PHPeclipsePlugin; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.ltk.ui.refactoring.UserInputWizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + + +/**

the input page for the Rename Property refactoring, where users can + * control the effects of the refactoring; to be shown in the wizard.

+ * + *

We let the user enter the new name for the property, and we let her + * decide whether other property files in the bundle should be affected, and + * whether the operation is supposed to span the entire workspace or only + * the current project.

+ * + * @author Leif Frenzel + */ +public class RenamePropertyInputPage extends UserInputWizardPage { + + private static final String DS_KEY = RenamePropertyInputPage.class.getName(); + private static final String DS_UPDATE_BUNDLE = "UPDATE_BUNDLE"; //$NON-NLS-1$ + private static final String DS_ALL_PROJECTS = "ALL_PROJECTS"; //$NON-NLS-1$ + + private final RenamePropertyInfo info; + + private IDialogSettings dialogSettings; + private Text txtNewName; + private Button cbUpdateBundle; + private Button cbAllProjects; + + + public RenamePropertyInputPage( final RenamePropertyInfo info ) { + super( RenamePropertyInputPage.class.getName() ); + this.info = info; + initDialogSettings(); + } + + + // interface methods of UserInputWizardPage + /////////////////////////////////////////// + + public void createControl( final Composite parent ) { + Composite composite = createRootComposite( parent ); + setControl( composite ); + + createLblNewName( composite ); + createTxtNewName( composite ); + createCbUpdateBundle( composite ); + createCbAllProjects( composite ); + + validate(); + } + + + // UI creation methods + ////////////////////// + + private Composite createRootComposite( final Composite parent ) { + Composite result = new Composite( parent, SWT.NONE ); + GridLayout gridLayout = new GridLayout( 2, false ); + gridLayout.marginWidth = 10; + gridLayout.marginHeight = 10; + result.setLayout( gridLayout ); + initializeDialogUnits( result ); + Dialog.applyDialogFont( result ); + return result; + } + + private void createLblNewName( final Composite composite ) { + Label lblNewName = new Label( composite, SWT.NONE ); + lblNewName.setText( UITexts.renamePropertyInputPage_lblNewName ); + } + + private void createTxtNewName(Composite composite) { + txtNewName = new Text( composite, SWT.BORDER ); + txtNewName.setText( info.getOldName() ); + txtNewName.setLayoutData( new GridData( GridData.FILL_HORIZONTAL ) ); + txtNewName.selectAll(); + txtNewName.addKeyListener( new KeyAdapter() { + public void keyReleased( final KeyEvent e ) { + info.setNewName( txtNewName.getText() ); + validate(); + } + } ); + } + + private void createCbUpdateBundle( final Composite composite ) { + String texts = UITexts.renamePropertyInputPage_cbUpdateBundle; + cbUpdateBundle = createCheckbox( composite, texts ); + cbUpdateBundle.addSelectionListener( new SelectionAdapter() { + public void widgetSelected( final SelectionEvent event ) { + boolean selected = cbUpdateBundle.getSelection(); + dialogSettings.put( DS_UPDATE_BUNDLE, selected ); + info.setUpdateBundle( selected ); + } + } ); + initUpdateBundleOption(); + } + + private void createCbAllProjects( final Composite composite ) { + String text = UITexts.renamePropertyInputPage_cbAllProjects; + cbAllProjects = createCheckbox( composite, text ); + cbAllProjects.addSelectionListener( new SelectionAdapter() { + public void widgetSelected( final SelectionEvent event ) { + boolean selected = cbAllProjects.getSelection(); + dialogSettings.put( DS_ALL_PROJECTS, selected ); + info.setAllProjects( selected ); + // for demonstration purposes, we enforce the preview for refactorings + // that span the entire workspace + getRefactoringWizard().setForcePreviewReview( selected ); + } + } ); + initAllProjectsOption(); + } + + private Button createCheckbox( final Composite composite, + final String text ) { + Button result = new Button( composite, SWT.CHECK ); + result.setText( text ); + + GridData gridData = new GridData( GridData.FILL_HORIZONTAL ); + gridData.horizontalSpan = 2; + result.setLayoutData( gridData ); + + return result; + } + + + // helping methods + ////////////////// + + private void initDialogSettings() { + IDialogSettings ds = PHPeclipsePlugin.getDefault().getDialogSettings(); + dialogSettings = ds.getSection( DS_KEY ); + if( dialogSettings == null ) { + dialogSettings = ds.addNewSection( DS_KEY ); + // init default values + dialogSettings.put( DS_UPDATE_BUNDLE, true ); + dialogSettings.put( DS_ALL_PROJECTS, false ); + } + } + + private void validate() { + String txt = txtNewName.getText(); + setPageComplete( txt.length() > 0 && !txt.equals( info.getOldName() ) ); + } + + private void initUpdateBundleOption() { + boolean updateRefs = dialogSettings.getBoolean( DS_UPDATE_BUNDLE ); + cbUpdateBundle.setSelection( updateRefs ); + info.setUpdateBundle( updateRefs ); + } + + private void initAllProjectsOption() { + boolean allProjects = dialogSettings.getBoolean( DS_ALL_PROJECTS ); + cbAllProjects.setSelection( allProjects ); + info.setAllProjects( allProjects ); + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/wizards/RenamePropertyWizard.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/wizards/RenamePropertyWizard.java new file mode 100644 index 0000000..4c5084c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ltk/ui/wizards/RenamePropertyWizard.java @@ -0,0 +1,40 @@ +// Copyright (c) 2005 by Leif Frenzel. All rights reserved. +// See http://leiffrenzel.de +package net.sourceforge.phpdt.ltk.ui.wizards; + +import net.sourceforge.phpdt.ltk.core.RenamePropertyInfo; +import net.sourceforge.phpdt.ltk.core.RenamePropertyRefactoring; + +import org.eclipse.ltk.ui.refactoring.RefactoringWizard; + + + +/**

The wizard that is shown to the user for entering the necessary + * information for property renaming.

+ * + *

The wizard class is primarily needed for deciding which pages are + * shown to the user. The actual user interface creation goes on the + * pages.

+ * + * @author Leif Frenzel + */ +public class RenamePropertyWizard extends RefactoringWizard { + + private final RenamePropertyInfo info; + + + public RenamePropertyWizard( final RenamePropertyRefactoring refactoring, + final RenamePropertyInfo info ) { + super( refactoring, DIALOG_BASED_USER_INTERFACE ); + this.info = info; + } + + + // interface methods of RefactoringWizard + ///////////////////////////////////////// + + protected void addUserInputPages() { + setDefaultPageTitle( getRefactoring().getName() ); + addPage( new RenamePropertyInputPage( info ) ); + } +} -- 1.7.1