/* * Copyright 2010 Ronnie Kolehmainen * * 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.github.cssxfire.tree; import com.github.cssxfire.CssUtils; import com.github.cssxfire.ProjectSettings; import com.github.cssxfire.ui.Colors; import com.intellij.ide.SelectInEditorManager; import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.util.Iconable; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.css.CssDeclaration; import com.intellij.psi.css.CssElement; import com.intellij.psi.css.CssTerm; import com.intellij.psi.css.CssTermList; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.ui.EmptyIcon; import javax.swing.*; /** * Created by IntelliJ IDEA. * User: Ronnie */ public class CssDeclarationNode extends CssTreeNode implements Navigatable { protected final CssDeclaration cssDeclaration; protected final String value; protected boolean deleted; protected boolean important; public CssDeclarationNode(CssDeclaration cssDeclaration, String value, boolean deleted, boolean important) { this.cssDeclaration = cssDeclaration; this.value = value; this.deleted = deleted; this.important = important; } @Override public boolean getAllowsChildren() { return false; } @Override public Icon getIcon() { return isValid() ? cssDeclaration.getIcon(Iconable.ICON_FLAG_VISIBILITY | Iconable.ICON_FLAG_READ_STATUS) : EmptyIcon.ICON_16; } @Override public String getName() { return cssDeclaration.getPropertyName(); } @Override public String getText() { String text = getName() + ": " + value + (important ? " !important" : ""); return deleted ? wrapWithHtmlColor("<strike>" + text + "</strike>", isValid() ? Colors.getModified() : Colors.getInvalid()) : wrapWithHtmlColor(text, isValid() ? Colors.getModified() : Colors.getInvalid()); } public boolean isValid() { return cssDeclaration.isValid(); } public String getPropertyName() { return cssDeclaration.getPropertyName(); } /** * Applies this change to the corresponding source code.<br><br> * <b>Note:</b> Must be invoked in a {@link com.intellij.openapi.application.Application#runWriteAction write-action} */ public void applyToCode() { try { if (isValid()) { if (deleted) { PsiElement nextSibling = cssDeclaration.getNextSibling(); if (nextSibling != null && ";".equals(nextSibling.getText())) { nextSibling.delete(); // delete trailing semi-colon } cssDeclaration.delete(); } else { if (cssDeclaration.isImportant() == important) { // Priority not changed - only need to alter the value text. CssElement navigationElement = getNavigationElement(); if (navigationElement instanceof CssTerm) { navigationElement.replace(CssUtils.createTerm(navigationElement.getProject(), value)); } else if (navigationElement instanceof CssTermList) { navigationElement.replace(CssUtils.createTermList(navigationElement.getProject(), value)); } else if (navigationElement instanceof CssDeclaration) { ((CssDeclaration) navigationElement).setValue(value); } } else { // Priority has changed. In this case we need to create a new declaration element and replace the old one. CssDeclaration newDeclaration = CssUtils.createDeclaration(cssDeclaration.getProject(), ".foo", cssDeclaration.getPropertyName(), value, important); cssDeclaration.replace(newDeclaration); } } } } catch (IncorrectOperationException e) { e.printStackTrace(); } } @Override public ActionGroup getActionGroup() { return isValid() ? (ActionGroup) ActionManager.getInstance().getAction("IncomingChanges.DeclarationNodePopup.Single") : (ActionGroup) ActionManager.getInstance().getAction("IncomingChanges.DeclarationNodePopup.Single.Invalid"); } protected CssElement getNavigationElement() { if (!isValid()) { return null; } if (CssUtils.isDynamicCssLanguage(cssDeclaration) && ProjectSettings.getInstance(cssDeclaration.getProject()).isResolveVariables()) { PsiElement assignment = CssUtils.resolveVariableAssignment(cssDeclaration); if (assignment != null) { //noinspection unchecked CssElement terms = PsiTreeUtil.getChildOfAnyType(assignment, CssTermList.class, CssTerm.class); if (terms != null) { return terms; } } } return cssDeclaration; } public void navigate() { CssElement cssElement = getNavigationElement(); if (cssElement != null) { SelectInEditorManager selectInEditorManager = SelectInEditorManager.getInstance(cssElement.getProject()); VirtualFile virtualFile = cssElement.getContainingFile().getVirtualFile(); if (virtualFile != null) { TextRange textRange = cssElement.getTextRange(); selectInEditorManager.selectInEditor(virtualFile, textRange.getStartOffset(), textRange.getEndOffset(), false, false); } } } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } CssDeclarationNode that = (CssDeclarationNode) o; if (cssDeclaration != null ? !cssDeclaration.equals(that.cssDeclaration) : that.cssDeclaration != null) { return false; } return true; } @Override public int hashCode() { int result = cssDeclaration != null ? cssDeclaration.hashCode() : 0; result = 31 * result + (value != null ? value.hashCode() : 0); return result; } public boolean isDeleted() { return deleted; } public void markDeleted() { deleted = true; } }