blob: 1604cc17cae682b0d7c45b3b6e375c64882ffdc0 [file] [log] [blame]
/*
* Copyright 2000-2009 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.xml.actions;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.lang.xhtml.XHTMLLanguage;
import com.intellij.lang.xml.XMLLanguage;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.html.HtmlTag;
import com.intellij.psi.xml.*;
import com.intellij.util.IncorrectOperationException;
import com.intellij.xml.XmlBundle;
import org.jetbrains.annotations.NotNull;
/**
* @author spleaner
*/
public class XmlSplitTagAction implements IntentionAction {
@Override
@NotNull
public String getText() {
return XmlBundle.message("xml.split.tag.intention.action");
}
@Override
@NotNull
public String getFamilyName() {
return XmlBundle.message("xml.split.tag.intention.action");
}
@Override
public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) {
if (file instanceof XmlFile) {
if (editor != null) {
final int offset = editor.getCaretModel().getOffset();
final PsiElement psiElement = file.findElementAt(offset);
if (psiElement != null) {
final PsiElement parent = psiElement.getParent();
if (parent != null && parent instanceof XmlText && parent.getText().trim().length() > 0) {
final PsiElement grandParent = parent.getParent();
if (grandParent != null && !isInsideUnsplittableElement(grandParent)) {
return true;
}
}
}
}
}
return false;
}
private static boolean isInsideUnsplittableElement(final PsiElement grandParent) {
if (!(grandParent instanceof HtmlTag) && grandParent.getContainingFile().getLanguage() != XHTMLLanguage.INSTANCE) {
return false;
}
final String name = ((XmlTag)grandParent).getName();
return "html".equals(name) || "body".equals(name) || "title".equals(name);
}
@Override
public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException {
if (!FileModificationService.getInstance().prepareFileForWrite(file)) return;
if (editor != null) {
final int offset = editor.getCaretModel().getOffset();
final PsiElement psiElement = file.findElementAt(offset);
if (psiElement != null) {
final PsiElement xmlText = psiElement.getParent();
final TextRange textRange = xmlText.getTextRange();
final int offsetInElement = offset - textRange.getStartOffset();
final PsiElement containingTag = xmlText.getParent();
if (containingTag instanceof XmlTag) {
final XmlTag xmlTag = (XmlTag)containingTag;
final String s = xmlText.getText();
String first = s.substring(0, offsetInElement);
String second = s.substring(offsetInElement);
if (xmlText instanceof XmlTagChild) {
XmlTagChild prev = ((XmlTagChild)xmlText).getPrevSiblingInTag();
while(prev != null) {
first = prev.getText() + first;
prev = prev.getPrevSiblingInTag();
}
XmlTagChild next = ((XmlTagChild)xmlText).getNextSiblingInTag();
while(next != null) {
second += next.getText();
next = next.getNextSiblingInTag();
}
}
final String filetext = buildNewText(xmlTag, first, second);
final XmlFile xmlFile = (XmlFile)PsiFileFactory.getInstance(project).createFileFromText("dummy.xml", XMLLanguage.INSTANCE,
filetext);
final PsiElement parent2 = containingTag.getParent();
final XmlTag tag = xmlFile.getDocument().getRootTag();
XmlTag last = null;
final PsiElement[] children = tag.getChildren();
for (int i = children.length - 1; i >= 0; i--) {
PsiElement element = children[i];
if (element instanceof XmlTag) {
final XmlTag tag1 = (XmlTag)parent2.addAfter(element, containingTag);
if (last == null) {
last = tag1;
}
}
}
containingTag.delete();
editor.getCaretModel().moveToOffset(last.getValue().getTextRange().getStartOffset());
}
}
}
}
private static String buildNewText(final XmlTag xmlTag, final String first, final String second) {
final StringBuilder attrs = new StringBuilder();
final StringBuilder attrsWoId = new StringBuilder();
for (XmlAttribute attribute : xmlTag.getAttributes()) {
if (!"id".equals(attribute.getName())) {
attrs.append(attribute.getName()).append("=\"").append(attribute.getValue()).append("\" ");
attrsWoId.append(attribute.getName()).append("=\"").append(attribute.getValue()).append("\" ");
} else {
attrs.append(attribute.getName()).append("=\"").append(attribute.getValue()).append("\" ");
}
}
final StringBuilder sb = new StringBuilder();
final String name = xmlTag.getName();
sb.append("<root><").append(name);
if (attrs.length() > 0) {
sb.append(' ').append(attrs);
}
sb.append('>');
sb.append(first);
sb.append("</").append(name).append("><").append(name);
if (attrsWoId.length() > 0) {
sb.append(' ').append(attrsWoId);
}
sb.append('>');
sb.append(second).append("</").append(name).append("></root>");
return sb.toString();
}
@Override
public boolean startInWriteAction() {
return true;
}
}