| /* |
| * Copyright 2000-2011 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.refactoring.introduce.inplace; |
| |
| import com.intellij.codeInsight.highlighting.HighlightManager; |
| import com.intellij.codeInsight.template.TextResult; |
| import com.intellij.codeInsight.template.impl.TemplateManagerImpl; |
| import com.intellij.codeInsight.template.impl.TemplateState; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.application.Result; |
| import com.intellij.openapi.command.CommandProcessor; |
| import com.intellij.openapi.command.WriteCommandAction; |
| import com.intellij.openapi.command.impl.StartMarkAction; |
| import com.intellij.openapi.editor.*; |
| import com.intellij.openapi.editor.colors.EditorColors; |
| import com.intellij.openapi.editor.colors.EditorColorsManager; |
| import com.intellij.openapi.editor.event.DocumentAdapter; |
| import com.intellij.openapi.editor.event.DocumentEvent; |
| import com.intellij.openapi.editor.ex.EditorEx; |
| import com.intellij.openapi.editor.markup.RangeHighlighter; |
| import com.intellij.openapi.editor.markup.TextAttributes; |
| import com.intellij.openapi.fileTypes.FileType; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.ui.popup.Balloon; |
| import com.intellij.openapi.util.Key; |
| import com.intellij.openapi.util.Pair; |
| import com.intellij.openapi.util.Ref; |
| import com.intellij.openapi.util.TextRange; |
| import com.intellij.openapi.vfs.ReadonlyStatusHandler; |
| import com.intellij.psi.*; |
| import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; |
| import com.intellij.psi.search.searches.ReferencesSearch; |
| import com.intellij.psi.util.PsiTreeUtil; |
| import com.intellij.refactoring.RefactoringActionHandler; |
| import com.intellij.refactoring.listeners.RefactoringEventData; |
| import com.intellij.refactoring.listeners.RefactoringEventListener; |
| import com.intellij.refactoring.rename.inplace.InplaceRefactoring; |
| import com.intellij.ui.DottedBorder; |
| import com.intellij.util.ui.PositionTracker; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import javax.swing.border.EmptyBorder; |
| import javax.swing.border.LineBorder; |
| import java.awt.*; |
| import java.util.*; |
| import java.util.List; |
| |
| /** |
| * User: anna |
| * Date: 3/15/11 |
| */ |
| public abstract class AbstractInplaceIntroducer<V extends PsiNameIdentifierOwner, E extends PsiElement> extends |
| InplaceVariableIntroducer<E> { |
| protected V myLocalVariable; |
| protected RangeMarker myLocalMarker; |
| |
| protected final String myExprText; |
| private final String myLocalName; |
| |
| public static final Key<AbstractInplaceIntroducer> ACTIVE_INTRODUCE = Key.create("ACTIVE_INTRODUCE"); |
| |
| private EditorEx myPreview; |
| private final JComponent myPreviewComponent; |
| |
| private DocumentAdapter myDocumentAdapter; |
| protected final JPanel myWholePanel; |
| private boolean myFinished = false; |
| |
| public AbstractInplaceIntroducer(Project project, |
| Editor editor, |
| @Nullable E expr, |
| @Nullable V localVariable, |
| E[] occurrences, |
| String title, |
| final FileType languageFileType) { |
| super(null, editor, project, title, occurrences, expr); |
| myLocalVariable = localVariable; |
| if (localVariable != null) { |
| final PsiElement nameIdentifier = localVariable.getNameIdentifier(); |
| if (nameIdentifier != null) { |
| myLocalMarker = createMarker(nameIdentifier); |
| } |
| } |
| else { |
| myLocalMarker = null; |
| } |
| myExprText = getExpressionText(expr); |
| myLocalName = localVariable != null ? localVariable.getName() : null; |
| |
| myPreview = |
| (EditorEx)EditorFactory.getInstance().createEditor(EditorFactory.getInstance().createDocument(""), project, languageFileType, true); |
| myPreview.setOneLineMode(true); |
| final EditorSettings settings = myPreview.getSettings(); |
| settings.setAdditionalLinesCount(0); |
| settings.setAdditionalColumnsCount(1); |
| settings.setRightMarginShown(false); |
| settings.setFoldingOutlineShown(false); |
| settings.setLineNumbersShown(false); |
| settings.setLineMarkerAreaShown(false); |
| settings.setIndentGuidesShown(false); |
| settings.setVirtualSpace(false); |
| myPreview.setHorizontalScrollbarVisible(false); |
| myPreview.setVerticalScrollbarVisible(false); |
| myPreview.setCaretEnabled(false); |
| settings.setLineCursorWidth(1); |
| |
| final Color bg = myPreview.getColorsScheme().getColor(EditorColors.CARET_ROW_COLOR); |
| myPreview.setBackgroundColor(bg); |
| myPreview.setBorder(BorderFactory.createCompoundBorder(new DottedBorder(Color.gray), new LineBorder(bg, 2))); |
| |
| myPreviewComponent = new JPanel(new BorderLayout()); |
| myPreviewComponent.add(myPreview.getComponent(), BorderLayout.CENTER); |
| myPreviewComponent.setBorder(new EmptyBorder(2, 2, 6, 2)); |
| |
| myWholePanel = new JPanel(new GridBagLayout()); |
| myWholePanel.setBorder(null); |
| |
| showDialogAdvertisement(getActionName()); |
| } |
| |
| @Nullable |
| protected String getExpressionText(E expr) { |
| return expr != null ? expr.getText() : null; |
| } |
| |
| protected final void setPreviewText(final String text) { |
| if (myPreview == null) return; //already disposed |
| ApplicationManager.getApplication().runWriteAction(new Runnable() { |
| @Override |
| public void run() { |
| myPreview.getDocument().replaceString(0, myPreview.getDocument().getTextLength(), text); |
| } |
| }); |
| } |
| |
| protected final JComponent getPreviewComponent() { |
| return myPreviewComponent; |
| } |
| |
| protected final Editor getPreviewEditor() { |
| return myPreview; |
| } |
| |
| |
| @Override |
| protected StartMarkAction startRename() throws StartMarkAction.AlreadyStartedException { |
| return StartMarkAction.start(myEditor, myProject, getCommandName()); |
| } |
| |
| /** |
| * Returns ID of the action the shortcut of which is used to show the non-in-place refactoring dialog. |
| * |
| * @return action ID |
| */ |
| protected abstract String getActionName(); |
| |
| /** |
| * Creates an initial version of the declaration for the introduced element. Note that this method is not called in a write action |
| * and most likely needs to create one itself. |
| * |
| * @param replaceAll whether all occurrences are going to be replaced |
| * @param names the suggested names for the declaration |
| * @return the declaration |
| */ |
| @Nullable |
| protected abstract V createFieldToStartTemplateOn(boolean replaceAll, String[] names); |
| |
| /** |
| * Returns the suggested names for the introduced element. |
| * |
| * @param replaceAll whether all occurrences are going to be replaced |
| * @param variable introduced element declaration, if already created. |
| * @return the suggested names |
| */ |
| protected abstract String[] suggestNames(boolean replaceAll, @Nullable V variable); |
| |
| protected abstract void performIntroduce(); |
| protected void performPostIntroduceTasks() {} |
| |
| public abstract boolean isReplaceAllOccurrences(); |
| public abstract void setReplaceAllOccurrences(boolean allOccurrences); |
| @Override |
| protected abstract JComponent getComponent(); |
| |
| protected abstract void saveSettings(@NotNull V variable); |
| @Override |
| protected abstract V getVariable(); |
| |
| public abstract E restoreExpression(PsiFile containingFile, V variable, RangeMarker marker, String exprText); |
| |
| /** |
| * Begins the in-place refactoring operation. |
| * |
| * @return true if the in-place refactoring was successfully started, false if it failed to start and a dialog should be shown instead. |
| */ |
| public boolean startInplaceIntroduceTemplate() { |
| final boolean replaceAllOccurrences = isReplaceAllOccurrences(); |
| final Ref<Boolean> result = new Ref<Boolean>(); |
| CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { |
| @Override |
| public void run() { |
| final String[] names = suggestNames(replaceAllOccurrences, getLocalVariable()); |
| final V variable = createFieldToStartTemplateOn(replaceAllOccurrences, names); |
| boolean started = false; |
| if (variable != null) { |
| int caretOffset = getCaretOffset(); |
| myEditor.getCaretModel().moveToOffset(caretOffset); |
| myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); |
| |
| final LinkedHashSet<String> nameSuggestions = new LinkedHashSet<String>(); |
| nameSuggestions.add(variable.getName()); |
| nameSuggestions.addAll(Arrays.asList(names)); |
| initOccurrencesMarkers(); |
| setElementToRename(variable); |
| updateTitle(getVariable()); |
| started = AbstractInplaceIntroducer.super.performInplaceRefactoring(nameSuggestions); |
| if (started) { |
| myDocumentAdapter = new DocumentAdapter() { |
| @Override |
| public void documentChanged(DocumentEvent e) { |
| if (myPreview == null) return; |
| final TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor); |
| if (templateState != null) { |
| final TextResult value = templateState.getVariableValue(InplaceRefactoring.PRIMARY_VARIABLE_NAME); |
| if (value != null) { |
| updateTitle(getVariable(), value.getText()); |
| } |
| } |
| } |
| }; |
| myEditor.getDocument().addDocumentListener(myDocumentAdapter); |
| updateTitle(getVariable()); |
| if (TemplateManagerImpl.getTemplateState(myEditor) != null) { |
| myEditor.putUserData(ACTIVE_INTRODUCE, AbstractInplaceIntroducer.this); |
| } |
| } |
| } |
| result.set(started); |
| if (!started) { |
| finish(true); |
| } |
| } |
| |
| }, getCommandName(), getCommandName()); |
| return result.get(); |
| } |
| |
| protected int getCaretOffset() { |
| RangeMarker r; |
| if (myLocalMarker != null) { |
| final PsiReference reference = myExpr != null ? myExpr.getReference() : null; |
| if (reference != null && reference.resolve() == myLocalVariable) { |
| r = myExprMarker; |
| } else { |
| r = myLocalMarker; |
| } |
| } |
| else { |
| r = myExprMarker; |
| } |
| return r != null ? r.getStartOffset() : 0; |
| } |
| |
| protected void updateTitle(@Nullable V variable, String value) { |
| if (variable == null) return; |
| |
| final String variableText = variable.getText(); |
| final PsiElement identifier = variable.getNameIdentifier(); |
| if (identifier != null) { |
| final int startOffsetInParent = identifier.getStartOffsetInParent(); |
| setPreviewText(variableText.substring(0, startOffsetInParent) + value + variableText.substring(startOffsetInParent + identifier.getTextLength())); |
| } else { |
| setPreviewText(variableText.replaceFirst(variable.getName(), value)); |
| } |
| revalidate(); |
| } |
| |
| protected void updateTitle(@Nullable V variable) { |
| if (variable == null) return; |
| setPreviewText(variable.getText()); |
| revalidate(); |
| } |
| |
| protected void revalidate() { |
| myWholePanel.revalidate(); |
| if (myTarget != null) { |
| myBalloon.revalidate(new PositionTracker.Static<Balloon>(myTarget)); |
| } |
| } |
| |
| private boolean myShouldSelect = true; |
| @Override |
| protected boolean shouldSelectAll() { |
| return myShouldSelect; |
| } |
| |
| public void restartInplaceIntroduceTemplate() { |
| Runnable restartTemplateRunnable = new Runnable() { |
| @Override |
| public void run() { |
| final TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor); |
| if (templateState != null) { |
| myEditor.putUserData(INTRODUCE_RESTART, true); |
| try { |
| final TextRange range = templateState.getCurrentVariableRange(); |
| if (range != null && range.isEmpty()) { |
| final String[] names = suggestNames(isReplaceAllOccurrences(), getLocalVariable()); |
| ApplicationManager.getApplication().runWriteAction(new Runnable() { |
| @Override |
| public void run() { |
| myEditor.getDocument().insertString(myEditor.getCaretModel().getOffset(), names[0]); |
| } |
| }); |
| } |
| templateState.gotoEnd(true); |
| try { |
| myShouldSelect = false; |
| startInplaceIntroduceTemplate(); |
| } |
| finally { |
| myShouldSelect = true; |
| } |
| } |
| finally { |
| myEditor.putUserData(INTRODUCE_RESTART, false); |
| } |
| } |
| updateTitle(getVariable()); |
| } |
| }; |
| CommandProcessor.getInstance().executeCommand(myProject, restartTemplateRunnable, getCommandName(), getCommandName()); |
| } |
| |
| @Override |
| protected void restoreSelection() { |
| if (!shouldSelectAll()) { |
| myEditor.getSelectionModel().removeSelection(); |
| } |
| } |
| |
| public String getInputName() { |
| return myInsertedName; |
| } |
| |
| |
| @Override |
| public void finish(boolean success) { |
| myFinished = true; |
| final TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor); |
| if (templateState != null) { |
| myEditor.putUserData(ACTIVE_INTRODUCE, null); |
| } |
| if (myDocumentAdapter != null) { |
| myEditor.getDocument().removeDocumentListener(myDocumentAdapter); |
| } |
| if (myBalloon == null) { |
| releaseIfNotRestart(); |
| } |
| super.finish(success); |
| if (success) { |
| PsiDocumentManager.getInstance(myProject).commitAllDocuments(); |
| final V variable = getVariable(); |
| if (variable == null) { |
| return; |
| } |
| restoreState(variable); |
| } |
| } |
| |
| @Override |
| protected void releaseResources() { |
| super.releaseResources(); |
| if (myPreview == null) return; |
| |
| EditorFactory.getInstance().releaseEditor(myPreview); |
| myPreview = null; |
| } |
| |
| @Override |
| protected void addReferenceAtCaret(Collection<PsiReference> refs) { |
| final V variable = getLocalVariable(); |
| if (variable != null) { |
| for (PsiReference reference : ReferencesSearch.search(variable)) { |
| refs.add(reference); |
| } |
| } else { |
| refs.clear(); |
| } |
| } |
| |
| @Override |
| protected void collectAdditionalElementsToRename(List<Pair<PsiElement, TextRange>> stringUsages) { |
| if (isReplaceAllOccurrences()) { |
| for (E expression : getOccurrences()) { |
| LOG.assertTrue(expression.isValid(), expression.getText()); |
| stringUsages.add(Pair.<PsiElement, TextRange>create(expression, new TextRange(0, expression.getTextLength()))); |
| } |
| } else if (getExpr() != null) { |
| correctExpression(); |
| final E expr = getExpr(); |
| LOG.assertTrue(expr.isValid(), expr.getText()); |
| stringUsages.add(Pair.<PsiElement, TextRange>create(expr, new TextRange(0, expr.getTextLength()))); |
| } |
| |
| final V localVariable = getLocalVariable(); |
| if (localVariable != null) { |
| final PsiElement nameIdentifier = localVariable.getNameIdentifier(); |
| if (nameIdentifier != null) { |
| int length = nameIdentifier.getTextLength(); |
| stringUsages.add(Pair.<PsiElement, TextRange>create(nameIdentifier, new TextRange(0, length))); |
| } |
| } |
| } |
| |
| protected void correctExpression() {} |
| |
| @Override |
| protected void addHighlights(@NotNull Map<TextRange, TextAttributes> ranges, |
| @NotNull Editor editor, |
| @NotNull Collection<RangeHighlighter> highlighters, |
| @NotNull HighlightManager highlightManager) { |
| final TextAttributes attributes = |
| EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); |
| final V variable = getVariable(); |
| if (variable != null) { |
| final String name = variable.getName(); |
| LOG.assertTrue(name != null, variable); |
| final int variableNameLength = name.length(); |
| if (isReplaceAllOccurrences()) { |
| for (RangeMarker marker : getOccurrenceMarkers()) { |
| final int startOffset = marker.getStartOffset(); |
| highlightManager.addOccurrenceHighlight(editor, startOffset, startOffset + variableNameLength, attributes, 0, highlighters, null); |
| } |
| } |
| else if (getExpr() != null) { |
| final int startOffset = getExprMarker().getStartOffset(); |
| highlightManager.addOccurrenceHighlight(editor, startOffset, startOffset + variableNameLength, attributes, 0, highlighters, null); |
| } |
| } |
| |
| for (RangeHighlighter highlighter : highlighters) { |
| highlighter.setGreedyToLeft(true); |
| highlighter.setGreedyToRight(true); |
| } |
| } |
| |
| protected void restoreState(final V psiField) { |
| if (!ReadonlyStatusHandler.ensureDocumentWritable(myProject, InjectedLanguageUtil.getTopLevelEditor(myEditor).getDocument())) return; |
| ApplicationManager.getApplication().runWriteAction(new Runnable() { |
| @Override |
| public void run() { |
| final PsiFile containingFile = psiField.getContainingFile(); |
| final RangeMarker exprMarker = getExprMarker(); |
| if (exprMarker != null) { |
| myExpr = restoreExpression(containingFile, psiField, exprMarker, myExprText); |
| if (myExpr != null && myExpr.isPhysical()) { |
| myExprMarker = createMarker(myExpr); |
| } |
| } |
| if (myLocalMarker != null) { |
| final PsiElement refVariableElement = containingFile.findElementAt(myLocalMarker.getStartOffset()); |
| if (refVariableElement != null) { |
| final PsiElement parent = refVariableElement.getParent(); |
| if (parent instanceof PsiNamedElement) { |
| ((PsiNamedElement)parent).setName(myLocalName); |
| } |
| } |
| |
| final V localVariable = getLocalVariable(); |
| if (localVariable != null && localVariable.isPhysical()) { |
| myLocalVariable = localVariable; |
| final PsiElement nameIdentifier = localVariable.getNameIdentifier(); |
| if (nameIdentifier != null) { |
| myLocalMarker = createMarker(nameIdentifier); |
| } |
| } |
| } |
| final List<RangeMarker> occurrenceMarkers = getOccurrenceMarkers(); |
| for (int i = 0, occurrenceMarkersSize = occurrenceMarkers.size(); i < occurrenceMarkersSize; i++) { |
| RangeMarker marker = occurrenceMarkers.get(i); |
| if (getExprMarker() != null && marker.getStartOffset() == getExprMarker().getStartOffset() && myExpr != null) { |
| myOccurrences[i] = myExpr; |
| continue; |
| } |
| final E psiExpression = |
| restoreExpression(containingFile, psiField, marker, getLocalVariable() != null ? myLocalName : myExprText); |
| if (psiExpression != null) { |
| myOccurrences[i] = psiExpression; |
| } |
| } |
| |
| myOccurrenceMarkers = null; |
| deleteTemplateField(psiField); |
| } |
| }); |
| } |
| |
| protected void deleteTemplateField(V psiField) { |
| if (psiField.isValid()) { |
| psiField.delete(); |
| } |
| } |
| |
| @Override |
| protected boolean performRefactoring() { |
| final String newName = getInputName(); |
| if (getLocalVariable() == null && myExpr == null || |
| newName == null || |
| getLocalVariable() != null && !getLocalVariable().isValid() || |
| myExpr != null && !myExpr.isValid()) { |
| super.moveOffsetAfter(false); |
| return false; |
| } |
| if (getLocalVariable() != null) { |
| new WriteCommandAction(myProject, getCommandName(), getCommandName()) { |
| @Override |
| protected void run(Result result) throws Throwable { |
| getLocalVariable().setName(myLocalName); |
| } |
| }.execute(); |
| } |
| |
| if (!isIdentifier(newName, myExpr != null ? myExpr.getLanguage() : getLocalVariable().getLanguage())) return false; |
| CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { |
| @Override |
| public void run() { |
| final String refactoringId = getRefactoringId(); |
| if (refactoringId != null) { |
| final RefactoringEventData beforeData = new RefactoringEventData(); |
| beforeData.addElements(new PsiElement[] {getLocalVariable(), getExpr()}); |
| myProject.getMessageBus() |
| .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC).refactoringStarted(refactoringId, beforeData); |
| } |
| performIntroduce(); |
| } |
| }, getCommandName(), getCommandName()); |
| |
| V variable = getVariable(); |
| if (variable != null) { |
| saveSettings(variable); |
| } |
| return false; |
| } |
| |
| @Override |
| protected void moveOffsetAfter(boolean success) { |
| if (getLocalVariable() != null && getLocalVariable().isValid()) { |
| myEditor.getCaretModel().moveToOffset(getLocalVariable().getTextOffset()); |
| myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); |
| } |
| else if (getExprMarker() != null) { |
| final RangeMarker exprMarker = getExprMarker(); |
| if (exprMarker.isValid()) { |
| myEditor.getCaretModel().moveToOffset(exprMarker.getStartOffset()); |
| myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); |
| } |
| } |
| super.moveOffsetAfter(success); |
| if (myLocalMarker != null && !isRestart()) { |
| myLocalMarker.dispose(); |
| } |
| if (success) { |
| performPostIntroduceTasks(); |
| final String refactoringId = getRefactoringId(); |
| if (refactoringId != null) { |
| final RefactoringEventData afterData = new RefactoringEventData(); |
| afterData.addElement(getVariable()); |
| myProject.getMessageBus() |
| .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC).refactoringDone(refactoringId, afterData); |
| } |
| } |
| } |
| |
| protected String getRefactoringId() { |
| return null; |
| } |
| |
| @Override |
| protected boolean startsOnTheSameElement(RefactoringActionHandler handler, PsiElement element) { |
| return super.startsOnTheSameElement(handler, element) || getLocalVariable() == element; |
| } |
| |
| public V getLocalVariable() { |
| if (myLocalVariable != null && myLocalVariable.isValid()) { |
| return myLocalVariable; |
| } |
| if (myLocalMarker != null) { |
| V variable = getVariable(); |
| PsiFile containingFile; |
| if (variable != null) { |
| containingFile = variable.getContainingFile(); |
| } else { |
| containingFile = PsiDocumentManager.getInstance(myProject).getPsiFile(myEditor.getDocument()); |
| } |
| PsiNameIdentifierOwner identifierOwner = PsiTreeUtil.getParentOfType(containingFile.findElementAt(myLocalMarker.getStartOffset()), |
| PsiNameIdentifierOwner.class, false); |
| return identifierOwner != null && identifierOwner.getClass() == myLocalVariable.getClass() ? (V)identifierOwner : null; |
| |
| } |
| return myLocalVariable; |
| } |
| |
| public void stopIntroduce(Editor editor) { |
| final TemplateState templateState = TemplateManagerImpl.getTemplateState(editor); |
| if (templateState != null) { |
| final Runnable runnable = new Runnable() { |
| @Override |
| public void run() { |
| templateState.gotoEnd(true); |
| } |
| }; |
| CommandProcessor.getInstance().executeCommand(myProject, runnable, getCommandName(), getCommandName()); |
| } |
| } |
| |
| @Override |
| protected void navigateToAlreadyStarted(Document oldDocument, int exitCode) { |
| finish(true); |
| super.navigateToAlreadyStarted(oldDocument, exitCode); |
| } |
| |
| @Override |
| protected void showBalloon() { |
| if (myFinished) return; |
| super.showBalloon(); |
| } |
| |
| public boolean startsOnTheSameElement(E expr, V localVariable) { |
| if (myExprMarker != null && myExprMarker.isValid() && expr != null && myExprMarker.getStartOffset() == expr.getTextOffset()) { |
| return true; |
| } |
| |
| if (myLocalMarker != null && |
| myLocalMarker.isValid() && |
| localVariable != null && |
| myLocalMarker.getStartOffset() == localVariable.getTextOffset()) { |
| return true; |
| } |
| return isRestart(); |
| } |
| |
| @Nullable |
| public static AbstractInplaceIntroducer getActiveIntroducer(@Nullable Editor editor) { |
| if (editor == null) return null; |
| return editor.getUserData(ACTIVE_INTRODUCE); |
| } |
| } |