blob: a4a51b963a0cd1cb858b7295444af10eb03fca32 [file] [log] [blame]
/*
* Copyright 2000-2014 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.
*/
/*
* Created by IntelliJ IDEA.
* User: spleaner
* Date: Aug 7, 2007
* Time: 2:44:37 PM
*/
package com.intellij.xml.refactoring;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.ide.TitledHandler;
import com.intellij.lang.Language;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.refactoring.actions.BaseRefactoringAction;
import com.intellij.refactoring.rename.PsiElementRenameHandler;
import com.intellij.refactoring.rename.RenameHandler;
import com.intellij.xml.XmlElementDescriptor;
import com.intellij.xml.impl.schema.AnyXmlElementDescriptor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class XmlTagRenameHandler implements RenameHandler, TitledHandler {
private static final Logger LOG = Logger.getInstance("#com.intellij.xml.refactoring.XmlTagRenameHandler");
@Override
public boolean isAvailableOnDataContext(final DataContext dataContext) {
final PsiElement element = getElement(dataContext);
if (element == null || PsiElementRenameHandler.isVetoed(element)) return false;
PsiElement parent = element.getParent();
if (!(parent instanceof XmlTag)) {
return false;
}
XmlTag tag = (XmlTag)parent;
String prefix = tag.getNamespacePrefix();
if (StringUtil.isNotEmpty(prefix)) {
Editor editor = getEditor(dataContext);
assert editor != null;
int offset = editor.getCaretModel().getOffset();
if (offset <= element.getTextRange().getStartOffset() + prefix.length()) {
return false;
}
}
//noinspection ConstantConditions
return isDeclarationOutOfProjectOrAbsent(element.getProject(), dataContext);
}
@Override
public boolean isRenaming(final DataContext dataContext) {
return isAvailableOnDataContext(dataContext);
}
@Override
public String getActionTitle() {
return "Rename XML tag";
}
private static boolean isInplaceRenameAvailable(final Editor editor) {
return editor.getSettings().isVariableInplaceRenameEnabled();
}
private static boolean isDeclarationOutOfProjectOrAbsent(@NotNull final Project project, final DataContext context) {
final PsiElement[] elements = BaseRefactoringAction.getPsiElementArray(context);
return elements.length == 0 || elements.length == 1 && shouldBeRenamedInplace(project, elements);
}
private static boolean shouldBeRenamedInplace(Project project, PsiElement[] elements) {
boolean inProject = PsiManager.getInstance(project).isInProject(elements[0]);
if (inProject && elements[0] instanceof XmlTag) {
XmlElementDescriptor descriptor = ((XmlTag)elements[0]).getDescriptor();
return descriptor instanceof AnyXmlElementDescriptor;
}
return !inProject;
}
@Nullable
private static Editor getEditor(@Nullable DataContext context) {
return CommonDataKeys.EDITOR.getData(context);
}
@Nullable
private static PsiElement getElement(@Nullable final DataContext context) {
if (context != null) {
final Editor editor = getEditor(context);
if (editor != null) {
final int offset = editor.getCaretModel().getOffset();
final PsiFile file = CommonDataKeys.PSI_FILE.getData(context);
if (file instanceof XmlFile) {
return file.getViewProvider().findElementAt(offset);
}
if (file != null) {
final Language language = PsiUtilCore.getLanguageAtOffset(file, offset);
if (language != file.getLanguage()) {
final PsiFile psiAtOffset = file.getViewProvider().getPsi(language);
if (psiAtOffset instanceof XmlFile) {
return psiAtOffset.findElementAt(offset);
}
}
}
}
}
return null;
}
private void invoke(@Nullable final Editor editor, @NotNull final PsiElement element, @Nullable final DataContext context) {
if (!isRenaming(context)) {
return;
}
FeatureUsageTracker.getInstance().triggerFeatureUsed("refactoring.rename");
if (isInplaceRenameAvailable(editor)) {
XmlTagInplaceRenamer.rename(editor, (XmlTag)element.getParent());
}
else {
XmlTagRenameDialog.renameXmlTag(editor, element, (XmlTag)element.getParent());
}
}
@Override
public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file, @Nullable final DataContext dataContext) {
if (!isRenaming(dataContext)) {
return;
}
final PsiElement element = getElement(dataContext);
assert element != null;
invoke(editor, element, dataContext);
}
@Override
public void invoke(@NotNull final Project project, @NotNull final PsiElement[] elements, @Nullable final DataContext dataContext) {
PsiElement element = elements.length == 1 ? elements[0] : null;
if (element == null) {
element = getElement(dataContext);
}
LOG.assertTrue(element != null);
invoke(getEditor(dataContext), element, dataContext);
}
}