| /******************************************************************************* |
| * 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.document; |
| |
| |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Enumeration; |
| import java.util.Iterator; |
| |
| import org.eclipse.wst.css.core.document.ICSSNode; |
| import org.eclipse.wst.css.core.util.CSSUtil; |
| import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; |
| import org.eclipse.wst.sse.core.text.IStructuredDocumentRegionList; |
| |
| |
| /** |
| * |
| */ |
| class CSSModelDeletionContext { |
| |
| private int fOldStart = -1; |
| private int fOldLength = 0; |
| private int fNewStart = -1; |
| private int fNewLength = 0; |
| private int fLengthDifference = 0; |
| private IStructuredDocumentRegionList fOldStructuredDocumentRegions = null; |
| // private ICSSNode fRootNode = null; |
| private int fRemovedRangeBegin = -1; |
| private int fRemovedRangeEnd = -1; |
| private CSSNodeListImpl fNodesToBeRemoved = new CSSNodeListImpl(); |
| |
| /** |
| * CSSModelDeletionContext constructor comment. |
| */ |
| CSSModelDeletionContext(ICSSNode rootNode) { |
| super(); |
| |
| // fRootNode = rootNode; |
| } |
| |
| /** |
| * |
| */ |
| boolean addNodeToBeRemoved(ICSSNode node) { |
| int nNodes = fNodesToBeRemoved.getLength(); |
| for (int i = 0; i < nNodes; i++) { |
| ICSSNode parent = fNodesToBeRemoved.item(i); |
| if (CSSModelUtil.isParentOf(parent, node)) { |
| return false; |
| } |
| } |
| fNodesToBeRemoved.appendNode(node); |
| return true; |
| } |
| |
| /** |
| * |
| */ |
| void expandRemovedRangeBegin(IStructuredDocumentRegion flatNode) { |
| if (flatNode == null) { |
| return; |
| } |
| int newBegin = flatNode.getStart(); // fOldStart == fNewStart, right?? |
| if (fRemovedRangeBegin < 0 || newBegin < fRemovedRangeBegin) { |
| fRemovedRangeBegin = newBegin; |
| } |
| } |
| |
| /** |
| * |
| */ |
| void expandRemovedRangeEnd(IStructuredDocumentRegion flatNode) { |
| if (flatNode == null) { |
| return; |
| } |
| int newEnd = flatNode.getEnd() + ((isOldNode(flatNode)) ? fLengthDifference : 0); |
| if (fRemovedRangeEnd < 0 || fRemovedRangeEnd < newEnd) { |
| fRemovedRangeEnd = newEnd; |
| } |
| } |
| |
| /** |
| * |
| */ |
| private CSSStructuredDocumentRegionContainer findContainer(CSSNodeImpl parent, IStructuredDocumentRegion flatNode) { |
| if (parent instanceof CSSStructuredDocumentRegionContainer) { |
| // Am i a container of flatNode? |
| IStructuredDocumentRegion firstNode = ((CSSStructuredDocumentRegionContainer) parent).getFirstStructuredDocumentRegion(); |
| IStructuredDocumentRegion lastNode = ((CSSStructuredDocumentRegionContainer) parent).getLastStructuredDocumentRegion(); |
| int firstStart = getOriginalOffset(firstNode); |
| int lastStart = getOriginalOffset(lastNode); |
| int start = flatNode.getStart(); |
| |
| if (firstStart <= start && start <= lastStart) { |
| // I am a container, is my child a container ? |
| for (ICSSNode node = parent.getFirstChild(); node != null; node = node.getNextSibling()) { |
| if (node instanceof CSSNodeImpl) { |
| CSSStructuredDocumentRegionContainer container = findContainer((CSSNodeImpl) node, flatNode); |
| if (container != null) { |
| return container; |
| } |
| } |
| } |
| return (CSSStructuredDocumentRegionContainer) parent; |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * |
| */ |
| CSSStructuredDocumentRegionContainer findDeletionTarget(CSSNodeImpl parent, IStructuredDocumentRegion flatNode) { |
| CSSStructuredDocumentRegionContainer target = findContainer(parent, flatNode); |
| if (target == null) { |
| return null; |
| } |
| |
| // System.out.print(flatNode.toString() + ": "); |
| |
| // child a(=====)b(=====)c |
| // parent (================) a,c can remove parent, but b cannot. |
| |
| ICSSNode child; |
| |
| for (child = target.getFirstChild(); child != null && !(child instanceof CSSStructuredDocumentRegionContainer); child = child.getNextSibling()) { |
| // just advancing |
| } |
| |
| if (child == null) { |
| // System.out.println("target has no children."); // TESTBYCOZY |
| return target; // has no child containers. |
| } |
| else { |
| IStructuredDocumentRegion firstNode = ((CSSStructuredDocumentRegionContainer) child).getFirstStructuredDocumentRegion(); |
| if (flatNode.getStart() < getOriginalOffset(firstNode)) { |
| // System.out.println("flatNode is in front of first child"); |
| // // TESTBYCOZY |
| return target; // a |
| } |
| } |
| |
| for (child = target.getLastChild(); child != null && !(child instanceof CSSStructuredDocumentRegionContainer); child = child.getPreviousSibling()) { |
| // just advancing |
| } |
| |
| if (child == null) { |
| // System.out.println("target has no children."); // TESTBYCOZY |
| return target; // has no child containers. |
| } |
| else { |
| IStructuredDocumentRegion firstNode = ((CSSStructuredDocumentRegionContainer) child).getFirstStructuredDocumentRegion(); |
| if (getOriginalOffset(firstNode) < flatNode.getStart()) { |
| // System.out.println("flatNode is in after of last child"); |
| // // TESTBYCOZY |
| return target; // c |
| } |
| } |
| |
| // System.out.println("flatNode inner of children"); // TESTBYCOZY |
| return null; // b |
| } |
| |
| /** |
| * |
| */ |
| Iterator getNodesToBeRemoved() { |
| Collection nodes = new ArrayList(); |
| int nNodes = fNodesToBeRemoved.getLength(); |
| for (int i = 0; i < nNodes; i++) { |
| nodes.add(fNodesToBeRemoved.item(i)); |
| } |
| return nodes.iterator(); |
| } |
| |
| /** |
| * |
| */ |
| private int getOriginalOffset(IStructuredDocumentRegion flatNode) { |
| int offset = 0; |
| if (flatNode != null) { |
| offset = flatNode.getStart(); |
| if (0 <= fLengthDifference) { |
| if (fNewStart + fNewLength < offset) { |
| offset -= fLengthDifference; |
| } |
| } |
| else { |
| if (fOldStart + fOldLength <= offset || (fNewStart < 0 && fOldStart <= offset && !isOldNode(flatNode)) || (0 <= fNewStart && fNewStart + fNewLength <= offset && !isOldNode(flatNode))) { |
| offset -= fLengthDifference; |
| } |
| } |
| } |
| |
| return offset; |
| } |
| |
| /** |
| * |
| */ |
| int getRemovedRangeBegin() { |
| return fRemovedRangeBegin; |
| } |
| |
| /** |
| * |
| */ |
| int getRemovedRangeEnd() { |
| return fRemovedRangeEnd; |
| } |
| |
| /** |
| * |
| */ |
| private boolean isOldNode(IStructuredDocumentRegion flatNode) { |
| if (fOldStructuredDocumentRegions != null) { |
| for (Enumeration e = fOldStructuredDocumentRegions.elements(); e.hasMoreElements();) { |
| if (e.nextElement() == flatNode) { |
| return true; |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * |
| */ |
| void setupContext(IStructuredDocumentRegionList newStructuredDocumentRegions, IStructuredDocumentRegionList oldStructuredDocumentRegions) { |
| IStructuredDocumentRegion flatNode = null; |
| fOldLength = CSSUtil.getTextLength(oldStructuredDocumentRegions); |
| if (oldStructuredDocumentRegions != null && 0 < oldStructuredDocumentRegions.getLength() && (flatNode = oldStructuredDocumentRegions.item(0)) != null) { |
| fOldStart = flatNode.getStart(); |
| } |
| else { |
| fOldStart = -1; |
| } |
| fNewLength = CSSUtil.getTextLength(newStructuredDocumentRegions); |
| if (newStructuredDocumentRegions != null && 0 < newStructuredDocumentRegions.getLength() && (flatNode = newStructuredDocumentRegions.item(0)) != null) { |
| fNewStart = flatNode.getStart(); |
| fRemovedRangeBegin = fNewStart; |
| fRemovedRangeEnd = fNewStart + fNewLength; |
| } |
| else { |
| fNewStart = -1; |
| fRemovedRangeBegin = fRemovedRangeEnd = -1; |
| } |
| fLengthDifference = fNewLength - fOldLength; |
| fOldStructuredDocumentRegions = oldStructuredDocumentRegions; |
| |
| // cleanup nodes |
| while (0 < fNodesToBeRemoved.getLength()) { |
| fNodesToBeRemoved.removeNode(0); |
| } |
| } |
| } |