| /******************************************************************************* |
| * Copyright (c) 2004 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.wst.css.core.internal.formatter; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.wst.css.core.internal.provisional.adapters.ICSSModelAdapter; |
| import org.eclipse.wst.css.core.internal.provisional.adapters.IStyleDeclarationAdapter; |
| import org.eclipse.wst.css.core.internal.provisional.adapters.IStyleSheetAdapter; |
| import org.eclipse.wst.css.core.internal.provisional.document.ICSSModel; |
| import org.eclipse.wst.css.core.internal.provisional.document.ICSSNode; |
| import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; |
| import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; |
| import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; |
| import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; |
| import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.Text; |
| |
| |
| public class CSSFormatUtil { |
| public List collectCSSNodes(IStructuredModel model, int start, int length) { |
| List nodes = new ArrayList(); |
| |
| IndexedRegion startNode = model.getIndexedRegion(start); |
| IndexedRegion endNode = model.getIndexedRegion(start + length - 1); |
| |
| if (startNode == null || endNode == null) { |
| return nodes; |
| } |
| |
| if (model instanceof ICSSModel && startNode instanceof ICSSNode && endNode instanceof ICSSNode) { |
| // CSS model |
| ICSSNode ca = getCommonAncestor((ICSSNode) startNode, (ICSSNode) endNode); |
| if (ca != null) { |
| for (ICSSNode node = ca.getFirstChild(); node != null && start + length < ((IndexedRegion) node).getStartOffset(); node = node.getNextSibling()) { |
| if (start < ((IndexedRegion) node).getEndOffset()) { |
| nodes.add(node); |
| } |
| } |
| } |
| } |
| else if (model instanceof IDOMModel && startNode instanceof IDOMNode && endNode instanceof IDOMNode) { |
| if (startNode instanceof Text) { |
| startNode = (IndexedRegion) ((Text) startNode).getParentNode(); |
| } |
| if (endNode instanceof Text) { |
| endNode = (IndexedRegion) ((Text) endNode).getParentNode(); |
| } |
| // HTML model, maybe |
| IDOMNode ca = (IDOMNode) getCommonAncestor((Node) startNode, (Node) endNode); |
| findCSS(nodes, ca); |
| } |
| |
| return nodes; |
| } |
| |
| /** |
| * getCommonAncestor method |
| * |
| * @return org.w3c.dom.Node |
| * @param node |
| * org.w3c.dom.Node |
| */ |
| private Node getCommonAncestor(Node node1, Node node2) { |
| if (node1 == null || node2 == null) |
| return null; |
| |
| for (Node na = node2; na != null; na = na.getParentNode()) { |
| for (Node ta = node1; ta != null; ta = ta.getParentNode()) { |
| if (ta == na) |
| return ta; |
| } |
| } |
| return null; // not found |
| } |
| |
| private void findCSS(List cssNodes, IDOMNode node) { |
| ICSSModelAdapter adapter; |
| adapter = (ICSSModelAdapter) node.getAdapterFor(IStyleSheetAdapter.class); |
| if (adapter != null) { |
| ICSSModel model = adapter.getModel(); |
| if (model != null && model.getStyleSheetType() == ICSSModel.EMBEDDED) { |
| cssNodes.add(model.getDocument()); |
| } |
| } |
| else { |
| adapter = (ICSSModelAdapter) node.getAdapterFor(IStyleDeclarationAdapter.class); |
| if (adapter != null) { |
| ICSSModel model = adapter.getModel(); |
| if (model != null && model.getStyleSheetType() == ICSSModel.INLINE) { |
| cssNodes.add(model.getDocument()); |
| } |
| } |
| } |
| |
| for (IDOMNode child = (IDOMNode) node.getFirstChild(); child != null; child = (IDOMNode) child.getNextSibling()) { |
| findCSS(cssNodes, child); |
| } |
| } |
| |
| private ICSSNode getCommonAncestor(ICSSNode nodeA, ICSSNode nodeB) { |
| if (nodeA == null || nodeB == null) { |
| return null; |
| } |
| |
| for (ICSSNode na = nodeA; na != null; na = na.getParentNode()) { |
| for (ICSSNode ta = nodeB; ta != null; ta = ta.getParentNode()) { |
| if (ta == na) { |
| return ta; |
| } |
| } |
| } |
| |
| return null; // not found |
| } |
| |
| /** |
| */ |
| public void replaceSource(IStructuredModel model, int offset, int length, String source) { |
| if (model == null) |
| return; |
| IStructuredDocument structuredDocument = model.getStructuredDocument(); |
| if (structuredDocument == null) |
| return; |
| if (offset >= 0 && length >= 0 && offset + length <= structuredDocument.getLength()) { |
| if (structuredDocument.containsReadOnly(offset, length)) |
| return; |
| if (source == null) |
| source = new String(); |
| // We use 'structuredDocument' as the requester object just so |
| // this and the other |
| // format-related 'repalceText' (in replaceSource) can use the |
| // same requester. |
| // Otherwise, if requester is not identical, |
| // the undo group gets "broken" into multiple pieces based |
| // on the requesters being different. Technically, any unique, |
| // common |
| // requester object would work. |
| structuredDocument.replaceText(structuredDocument, offset, length, source); |
| } |
| } |
| |
| public synchronized static CSSFormatUtil getInstance() { |
| if (fInstance == null) { |
| fInstance = new CSSFormatUtil(); |
| } |
| return fInstance; |
| } |
| |
| private CSSFormatUtil() { |
| super(); |
| } |
| |
| private static CSSFormatUtil fInstance; |
| } |