package com.redhat.ceylon.eclipse.code.refactor; import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.LINKED_MODE_RENAME; import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.LINKED_MODE_RENAME_SELECT; import static com.redhat.ceylon.eclipse.code.refactor.RenameRefactoring.getIdentifier; import static com.redhat.ceylon.eclipse.ui.CeylonPlugin.PLUGIN_ID; import static com.redhat.ceylon.eclipse.util.DocLinks.nameRegion; import static com.redhat.ceylon.eclipse.util.Nodes.getIdentifyingNode; import java.util.List; import org.eclipse.core.resources.IProject; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.link.LinkedPosition; import org.eclipse.jface.text.link.LinkedPositionGroup; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.ltk.ui.refactoring.RefactoringWizard; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.ui.IWorkbenchPartSite; import com.redhat.ceylon.compiler.typechecker.tree.Node; import com.redhat.ceylon.compiler.typechecker.tree.Tree; import com.redhat.ceylon.compiler.typechecker.tree.Tree.DocLink; import com.redhat.ceylon.eclipse.code.editor.CeylonEditor; import com.redhat.ceylon.eclipse.core.builder.CeylonNature; import com.redhat.ceylon.eclipse.ui.CeylonPlugin; import com.redhat.ceylon.ide.common.util.escaping_; import com.redhat.ceylon.model.typechecker.model.TypeDeclaration; public final class RenameLinkedMode extends RefactorLinkedMode { private final RenameRefactoring refactoring; protected LinkedPosition namePosition; protected LinkedPositionGroup linkedPositionGroup; public RenameLinkedMode(CeylonEditor editor) { super(editor); this.refactoring = new RenameRefactoring(editor); } public static boolean useLinkedMode() { return CeylonPlugin.getPreferences() .getBoolean(LINKED_MODE_RENAME); } @Override protected boolean canStart() { return refactoring.getEnabled(); } @Override protected int getSaveMode() { return refactoring.getSaveMode(); } @Override protected boolean forceSave() { return refactoring.isAffectingOtherFiles(); } private boolean isEnabled() { String newName = getNewNameFromNamePosition(); return !getInitialName().equals(newName) && newName.matches("^\\w(\\w|\\d)*$") && !escaping_.get_().isKeyword(newName); } @Override public void done() { if (isEnabled()) { IProject project = editor.getParseController() .getProject(); if (CeylonNature.isEnabled(project)) { try { hideEditorActivity(); setName(getNewNameFromNamePosition()); revertChanges(); if (isShowPreview()) { openPreview(); } else { IWorkbenchPartSite site = editor.getSite(); new RefactoringExecutionHelper( refactoring, RefactoringStatus.WARNING, getSaveMode(), site.getShell(), site.getWorkbenchWindow()) .perform(false, true); } } catch (Exception e) { e.printStackTrace(); } finally { unhideEditorActivity(); } } super.done(); } else { super.cancel(); } } @Override public String getHintTemplate() { return "Enter new name for " + refactoring.getCount() + " occurrences of '" + getName() + "' {0}"; } private void addLinkedPositions(IDocument document, Tree.CompilationUnit rootNode, int adjust, LinkedPositionGroup linkedPositionGroup) throws BadLocationException { Node selectedNode = refactoring.getNode(); int offset; int len; if (selectedNode instanceof DocLink) { DocLink docLink = (DocLink) selectedNode; int i = 0; if (docLink.getQualified()!=null) { i+=docLink.getQualified().size(); } Region region = nameRegion(docLink, i); offset = region.getOffset(); len = region.getLength(); } else { Node node = getIdentifyingNode(selectedNode); offset = node.getStartIndex(); len = node.getDistance(); } namePosition = new LinkedPosition(document, offset, len, 0); linkedPositionGroup.addPosition(namePosition); int i=1; List<Node> nodesToRename = refactoring.getNodesToRename(rootNode); for (Node node: nodesToRename) { Node identifyingNode = getIdentifier(node); try { linkedPositionGroup.addPosition( new LinkedPosition(document, identifyingNode.getStartIndex(), identifyingNode.getDistance(), i++)); } catch (BadLocationException e) { e.printStackTrace(); } } List<Region> stringsToReplace = refactoring.getStringsToReplace(rootNode); for (Region region: stringsToReplace) { try { linkedPositionGroup.addPosition( new LinkedPosition(document, region.getOffset(), region.getLength(), i++)); } catch (BadLocationException e) { e.printStackTrace(); } } } @Override protected String getName() { return refactoring.getDeclaration().getName(); } @Override protected void setName(String name) { refactoring.setNewName(name); } @Override protected String getActionName() { return PLUGIN_ID + ".action.rename"; } @Override protected void openPreview() { new RenameRefactoringAction(editor) { @Override public Refactoring createRefactoring() { return RenameLinkedMode.this.refactoring; } @Override public RefactoringWizard createWizard( Refactoring refactoring) { return new RenameWizard( (RenameRefactoring) refactoring) { @Override protected void addUserInputPages() {} }; } }.run(); } @Override protected void openDialog() { new RenameRefactoringAction(editor) { @Override public AbstractRefactoring createRefactoring() { return RenameLinkedMode.this.refactoring; } }.run(); } @Override protected String getNewNameFromNamePosition() { try { return namePosition.getContent(); } catch (BadLocationException e) { return getInitialName(); } } @Override protected void setupLinkedPositions( final IDocument document, final int adjust) throws BadLocationException { Tree.CompilationUnit rootNode = editor.getParseController() .getLastCompilationUnit(); linkedPositionGroup = new LinkedPositionGroup(); addLinkedPositions(document, rootNode, adjust, linkedPositionGroup); linkedModeModel.addGroup(linkedPositionGroup); } @Override protected void enterLinkedMode( IDocument document, int exitSequenceNumber, int exitPosition) throws BadLocationException { super.enterLinkedMode(document, exitSequenceNumber, exitPosition); if (!CeylonPlugin.getPreferences() .getBoolean(LINKED_MODE_RENAME_SELECT)) { // by default, full word is selected; restore original selection editor.getCeylonSourceViewer() .setSelectedRange(getOriginalSelection().x, getOriginalSelection().y); } } @Override protected void openPopup() { super.openPopup(); getInfoPopup().getMenuManager() .addMenuListener(new IMenuListener() { @Override public void menuAboutToShow(IMenuManager manager) { manager.add(new Separator()); Action renameLocals = new Action("Rename Values And Functions", IAction.AS_CHECK_BOX) { @Override public void run() { refactoring.setRenameValuesAndFunctions( isChecked()); } }; renameLocals.setChecked( refactoring.isRenameValuesAndFunctions()); boolean typeDec = refactoring.getDeclaration() instanceof TypeDeclaration; renameLocals.setEnabled(typeDec); manager.add(renameLocals); Action renameFile = new Action("Rename Source File", IAction.AS_CHECK_BOX) { @Override public void run() { refactoring.setRenameFile(isChecked()); } }; renameFile.setChecked(refactoring.isRenameFile()); manager.add(renameFile); } }); } private Image image = null; private Label label = null; private void hideEditorActivity() { Control viewerControl = editor.getCeylonSourceViewer() .getControl(); if (viewerControl instanceof Composite) { Composite composite = (Composite) viewerControl; Display display = composite.getDisplay(); // Flush pending redraw requests: while (!display.isDisposed() && display.readAndDispatch()) {} // Copy editor area: GC gc = new GC(composite); Point size; try { size = composite.getSize(); image = new Image(gc.getDevice(), size.x, size.y); gc.copyArea(image, 0, 0); } finally { gc.dispose(); gc= null; } // Persist editor area while executing refactoring: label = new Label(composite, SWT.NONE); label.setImage(image); label.setBounds(0, 0, size.x, size.y); label.moveAbove(null); } } private void unhideEditorActivity() { if (label!=null) label.dispose(); if (image!=null) image.dispose(); } }