| /***************************************************************************** |
| * 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.ui.internal.contentassist; |
| |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.wst.css.core.internal.metamodel.CSSMetaModel; |
| import org.eclipse.wst.css.core.internal.metamodel.util.CSSMetaModelFinder; |
| import org.eclipse.wst.css.core.internal.parserz.CSSRegionContexts; |
| import org.eclipse.wst.css.core.internal.provisional.document.ICSSDocument; |
| import org.eclipse.wst.css.core.internal.provisional.document.ICSSModel; |
| import org.eclipse.wst.css.core.internal.provisional.document.ICSSNode; |
| import org.eclipse.wst.css.core.internal.util.CSSUtil; |
| import org.eclipse.wst.css.core.internal.util.RegionIterator; |
| import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; |
| import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; |
| import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion; |
| import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion; |
| |
| class CSSContentAssistContext { |
| |
| private int fReplaceBegin = -1; |
| private String fTextToReplace = null; |
| private String fTextToCompare = null; |
| private int fTargetPos = -1; |
| private ICSSNode fTargetNode = null; |
| private int fCursorPos = -1; |
| private IStructuredDocument fStructuredDocument = null; |
| private int fDocumentOffset = 0; |
| private char fQuote = 0; |
| private ICSSModel fModel = null; |
| |
| /** |
| * |
| */ |
| private CSSContentAssistContext() { |
| super(); |
| } |
| |
| /** |
| * |
| */ |
| CSSContentAssistContext(int documentPosition, ICSSNode node, int documentOffset, char quote) { |
| super(); |
| fCursorPos = documentPosition; |
| fDocumentOffset = documentOffset; |
| fQuote = quote; |
| initialize(node.getOwnerDocument()); |
| } |
| |
| /** |
| * @return int |
| */ |
| int getCursorPos() { |
| return fCursorPos; |
| } |
| |
| /** |
| * @return int |
| */ |
| int getDocumentOffset() { |
| return fDocumentOffset; |
| } |
| |
| /** |
| * @return com.ibm.sed.structuredDocument.IStructuredDocument |
| */ |
| IStructuredDocument getStructuredDocument() { |
| return fStructuredDocument; |
| } |
| |
| /** |
| * @return com.ibm.sse.model.css.model.ICSSModel |
| */ |
| ICSSModel getModel() { |
| return fModel; |
| } |
| |
| private ICSSNode getNodeAt(int offset) { |
| return (ICSSNode) ((fModel != null) ? fModel.getIndexedRegion(offset) : null); |
| } |
| |
| /** |
| * |
| * @return char |
| */ |
| char getQuoteOfStyleAttribute() { |
| return fQuote; |
| } |
| |
| /** |
| * |
| */ |
| ITextRegion getRegionByOffset(int offset) { |
| ITextRegion region = null; |
| if (fStructuredDocument != null) { |
| IStructuredDocumentRegion flatNode = fStructuredDocument.getRegionAtCharacterOffset(offset); |
| if (flatNode != null) { |
| region = flatNode.getRegionAtCharacterOffset(offset); |
| } |
| } |
| return region; |
| } |
| |
| /** |
| * |
| */ |
| // String getRegionText() { |
| // ITextRegion targetRegion = getTargetRegion(); |
| // if (targetRegion != null) { |
| // return targetRegion.getText(); |
| // } else { |
| // return ""; //$NON-NLS-1$ |
| // } |
| // } |
| /** |
| * |
| */ |
| int getReplaceBegin() { |
| return fReplaceBegin; |
| } |
| |
| /** |
| * |
| * @return com.ibm.sed.structuredDocument.ITextRegion |
| */ |
| // ITextRegion getSignificantTargetRegion() { |
| // ITextRegion targetRegion = getTargetRegion(); |
| // RegionIterator iterator = null; |
| // if (targetRegion == null) { |
| // if (0 < fCursorPos) { |
| // iterator = new RegionIterator(fStructuredDocument, fCursorPos - 1); |
| // } |
| // } else { |
| // iterator = getRegionIterator(); |
| // } |
| // if (iterator != null) { |
| // while (iterator.hasPrev()) { |
| // ITextRegion region = iterator.prev(); |
| // String type = region.getType(); |
| // if (type != CSSRegionContexts.CSS_S && type != |
| // CSSRegionContexts.CSS_COMMENT && |
| // type != CSSRegionContexts.CSS_CDO && type != CSSRegionContexts.CSS_CDC) |
| // { |
| // targetRegion = region; |
| // break; |
| // } |
| // } |
| // } |
| // |
| // return targetRegion; |
| // } |
| /** |
| * |
| */ |
| ICSSNode getTargetNode() { |
| return fTargetNode; |
| } |
| |
| /** |
| * |
| */ |
| private int getTargetPos() { |
| return fTargetPos; |
| } |
| |
| /** |
| * @return com.ibm.sed.structuredDocument.ITextRegion |
| */ |
| ITextRegion getTargetRegion() { |
| return getRegionByOffset(getTargetPos()); |
| } |
| |
| private IStructuredDocumentRegion getTargetDocumentRegion() { |
| return getDocumentRegionByOffset(getTargetPos()); |
| } |
| |
| private IStructuredDocumentRegion getDocumentRegionByOffset(int offset) { |
| return (fStructuredDocument != null) ? fStructuredDocument.getRegionAtCharacterOffset(offset) : null; |
| } |
| |
| /** |
| * |
| * @return com.ibm.sed.structuredDocument.ITextRegion |
| */ |
| ITextRegion getTargetRegionPrevious() { |
| ITextRegion previousRegion = null; |
| ITextRegion targetRegion = getTargetRegion(); |
| RegionIterator iterator = null; |
| if (targetRegion == null) { |
| if (0 < fCursorPos) { |
| iterator = new RegionIterator(fStructuredDocument, fCursorPos - 1); |
| } |
| } else { |
| iterator = getRegionIterator(); |
| if (iterator.hasPrev()) { |
| iterator.prev(); |
| } else { |
| iterator = null; |
| } |
| } |
| if (iterator != null) { |
| while (iterator.hasPrev()) { |
| ITextRegion region = iterator.prev(); |
| String type = region.getType(); |
| if (type != CSSRegionContexts.CSS_S && type != CSSRegionContexts.CSS_COMMENT && type != CSSRegionContexts.CSS_CDO && type != CSSRegionContexts.CSS_CDC) { |
| previousRegion = region; |
| break; |
| } |
| } |
| } |
| |
| return previousRegion; |
| } |
| |
| /** |
| * @return java.lang.String |
| */ |
| String getTextToCompare() { |
| return fTextToCompare; |
| } |
| |
| /** |
| * |
| */ |
| String getTextToReplace() { |
| return fTextToReplace; |
| } |
| |
| /** |
| * |
| */ |
| private void initialize(ICSSDocument doc) { |
| if (doc == null) { |
| return; |
| } |
| ICSSModel model = doc.getModel(); |
| fModel = model; |
| fStructuredDocument = model.getStructuredDocument(); |
| |
| initializeTargetPos(); |
| initializeTargetText(); |
| initializeTargetNode(); |
| } |
| |
| /** |
| * |
| */ |
| private void initializeTargetNode() { |
| if (fCursorPos == 0) { |
| fTargetNode = fModel.getDocument(); |
| return; |
| } |
| |
| // find edge of tree node |
| ICSSNode cursorNode = getNodeAt(fCursorPos); |
| if (cursorNode == null) { // end of document |
| cursorNode = fModel.getDocument(); |
| } |
| ICSSNode node = null; |
| IStructuredDocumentRegion flatNode = fStructuredDocument.getRegionAtCharacterOffset(fCursorPos - 1); |
| while (flatNode != null && (node = getNodeAt(flatNode.getStartOffset())) == cursorNode && ((IndexedRegion) node).getStartOffset() != flatNode.getStartOffset()) { |
| flatNode = flatNode.getPrevious(); |
| } |
| if (flatNode == null) { // top of document |
| fTargetNode = (node == null) ? fModel.getDocument() : node; |
| return; |
| } |
| // v<--| |
| // AAAAAA |
| // BBBBBBBBBB cursorNode:A , node:B -> target is A |
| if (cursorNode != null) { |
| for (ICSSNode parent = cursorNode.getParentNode(); parent != null; parent = parent.getParentNode()) { |
| if (parent == cursorNode) { |
| fTargetNode = cursorNode; |
| return; |
| } |
| } |
| } |
| // v<--| |
| // AAA |
| // BBBBBBBBBB cursorNode:B , node:A -> depend on A's node type |
| short nodeType = node.getNodeType(); |
| if (nodeType == ICSSNode.STYLEDECLITEM_NODE || nodeType == ICSSNode.CHARSETRULE_NODE || nodeType == ICSSNode.IMPORTRULE_NODE) { |
| String type = CSSUtil.getStructuredDocumentRegionType(flatNode); |
| if (type == CSSRegionContexts.CSS_DELIMITER || type == CSSRegionContexts.CSS_DECLARATION_DELIMITER) { |
| fTargetNode = node.getParentNode(); |
| } else { |
| fTargetNode = node; |
| } |
| // fTargetNode = (bOverSemiColon) ? node.getParentNode() : node; |
| } else if (CSSUtil.getStructuredDocumentRegionType(flatNode) == CSSRegionContexts.CSS_RBRACE) { |
| fTargetNode = node.getParentNode(); |
| } else { |
| fTargetNode = node; |
| } |
| |
| return; |
| } |
| |
| /** |
| * |
| */ |
| private void initializeTargetPos() { |
| if (fCursorPos == 0 || isSpecialDelimiterRegion(fCursorPos - 1)) { |
| fTargetPos = fCursorPos; |
| } else { |
| fTargetPos = fCursorPos - 1; |
| } |
| } |
| |
| /** |
| * |
| */ |
| private void initializeTargetText() { |
| ITextRegion targetRegion = getTargetRegion(); |
| IStructuredDocumentRegion documentRegion = getTargetDocumentRegion(); |
| if (targetRegion == null) { |
| fReplaceBegin = fCursorPos; |
| fTextToReplace = ""; //$NON-NLS-1$ |
| fTextToCompare = ""; //$NON-NLS-1$ |
| } else { |
| String regionText = documentRegion.getText(targetRegion); |
| int regionStart = documentRegion.getStartOffset(targetRegion); |
| if (regionStart == fCursorPos || regionText.trim().length() == 0 || regionStart + regionText.length() - 1 < fTargetPos) { |
| // to insertion |
| fReplaceBegin = fCursorPos; |
| fTextToReplace = ""; //$NON-NLS-1$ |
| fTextToCompare = ""; //$NON-NLS-1$ |
| } else { |
| // to replace |
| fReplaceBegin = regionStart; |
| fTextToReplace = regionText; |
| fTextToCompare = regionText.substring(0, fCursorPos - fReplaceBegin); |
| } |
| } |
| } |
| |
| /** |
| * |
| */ |
| private boolean isSpecialDelimiterRegion(int pos) { |
| ITextRegion region = getRegionByOffset(pos); |
| String type = region.getType(); |
| return (type == CSSRegionContexts.CSS_LBRACE || type == CSSRegionContexts.CSS_RBRACE || type == CSSRegionContexts.CSS_DELIMITER || type == CSSRegionContexts.CSS_DECLARATION_SEPARATOR || type == CSSRegionContexts.CSS_DECLARATION_DELIMITER || type == CSSRegionContexts.CSS_DECLARATION_VALUE_OPERATOR); |
| } |
| |
| /** |
| * |
| */ |
| boolean isTargetPosAfterOf(String regionType) { |
| int start = ((IndexedRegion) fTargetNode).getStartOffset(); |
| if (start < 0 || ((IndexedRegion) fTargetNode).getEndOffset() <= 0) { |
| return false; |
| } |
| |
| RegionIterator iRegion = new RegionIterator(fStructuredDocument, start); |
| while (iRegion.hasNext()) { |
| ITextRegion region = iRegion.next(); |
| if (fTargetPos < iRegion.getStructuredDocumentRegion().getTextEndOffset(region)) { |
| break; |
| } |
| if (region.getType() == regionType) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * |
| */ |
| boolean isTargetPosBeforeOf(String regionType) { |
| return !isTargetPosAfterOf(regionType); |
| } |
| |
| /** |
| * @return boolean |
| * @param regionType |
| * java.lang.String |
| */ |
| boolean targetFollows(String regionType) { |
| RegionIterator iRegion; |
| ITextRegion region = null; |
| if (fStructuredDocument.getLength() <= fTargetPos) { |
| iRegion = new RegionIterator(fStructuredDocument, fStructuredDocument.getLength() - 1); |
| } else { |
| iRegion = new RegionIterator(fStructuredDocument, fTargetPos); |
| try { |
| if (!Character.isWhitespace(fStructuredDocument.getChar(fTargetPos)) && iRegion.hasPrev()) { |
| region = iRegion.prev(); |
| } |
| } catch (BadLocationException e) { |
| iRegion = new RegionIterator(fStructuredDocument, fStructuredDocument.getLength() - 1); |
| } |
| } |
| while (iRegion.hasPrev()) { |
| region = iRegion.prev(); |
| String type = region.getType(); |
| if (type == CSSRegionContexts.CSS_S || type == CSSRegionContexts.CSS_COMMENT) { |
| continue; |
| } else { |
| break; |
| } |
| } |
| if (region != null && region.getType() == regionType) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * |
| */ |
| boolean targetHas(String regionType) { |
| int start = ((IndexedRegion) fTargetNode).getStartOffset(); |
| int end = ((IndexedRegion) fTargetNode).getEndOffset(); |
| if (start < 0 || end <= 0) { |
| return false; |
| } |
| RegionIterator iRegion = new RegionIterator(fStructuredDocument, start); |
| while (iRegion.hasNext()) { |
| ITextRegion region = iRegion.next(); |
| if (end <= iRegion.getStructuredDocumentRegion().getStartOffset(region)) { |
| break; |
| } |
| if (region.getType() == regionType) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| RegionIterator getRegionIterator() { |
| return new RegionIterator(getStructuredDocument(), getTargetPos()); |
| } |
| |
| /** |
| * |
| */ |
| CSSMetaModel getMetaModel() { |
| CSSMetaModelFinder finder = CSSMetaModelFinder.getInstance(); |
| return finder.findMetaModelFor(getModel()); |
| } |
| } |