| /******************************************************************************* |
| * Copyright (c) 2004, 2010 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.ITextSelection; |
| import org.eclipse.jface.text.ITextViewer; |
| import org.eclipse.jface.text.contentassist.ICompletionProposal; |
| import org.eclipse.jface.text.contentassist.IContentAssistProcessor; |
| import org.eclipse.wst.css.core.internal.provisional.adapters.ICSSModelAdapter; |
| 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.ui.internal.templates.TemplateContextTypeIdsCSS; |
| import org.eclipse.wst.html.core.internal.htmlcss.StyleAdapterFactory; |
| import org.eclipse.wst.sse.core.StructuredModelManager; |
| import org.eclipse.wst.sse.core.internal.provisional.INodeAdapter; |
| import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; |
| import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; |
| import org.eclipse.wst.sse.ui.internal.contentassist.ContentAssistUtils; |
| import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode; |
| import org.eclipse.wst.xml.ui.internal.contentassist.XMLContentAssistUtilities; |
| import org.eclipse.wst.xml.ui.internal.util.SharedXMLEditorPluginImageHelper; |
| |
| /** |
| * @deprecated This class is no longer used locally and will be removed in the future |
| * @see CSSStructuredContentAssistProcessor |
| */ |
| public class CSSContentAssistProcessor implements IContentAssistProcessor { |
| |
| private int fDocumentOffset = 0; |
| private char fQuote = 0; |
| private CSSTemplateCompletionProcessor fTemplateProcessor = null; |
| |
| /** |
| * Return a list of proposed code completions based on the specified |
| * location within the document that corresponds to the current cursor |
| * position within the text-editor control. |
| * |
| * @param documentPosition |
| * a location within the document |
| * @return an array of code-assist items |
| */ |
| public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int documentPosition) { |
| |
| IndexedRegion indexedNode = ContentAssistUtils.getNodeAt(viewer, documentPosition + fDocumentOffset); |
| IDOMNode xNode = null; |
| IDOMNode parent = null; |
| CSSProposalArranger arranger = null; |
| boolean isEmptyDocument = false; |
| // If there is a selected region, we'll need to replace the text |
| ITextSelection selection = (ITextSelection) viewer.getSelectionProvider().getSelection(); |
| boolean selected = (selection != null && selection.getText() != null && selection.getText().trim().length() > 0); |
| |
| // bail if we couldn't get an indexed node |
| // if(indexedNode == null) return new ICompletionProposal[0]; |
| if (indexedNode instanceof IDOMNode) { |
| xNode = (IDOMNode) indexedNode; |
| parent = (IDOMNode) xNode.getParentNode(); |
| } |
| // need to get in here if there in the no 0 region <style>|</style> |
| // case |
| if ((xNode != null) && xNode.getNodeName().equalsIgnoreCase(HTML40Namespace.ElementName.STYLE)) { |
| // now we know the cursor is in a <style> tag w/out region |
| IStructuredModel cssModel = getCSSModel(xNode); |
| if (cssModel != null) { |
| // adjust offsets for embedded style |
| int offset = documentPosition + fDocumentOffset; |
| int pos = 0; |
| IndexedRegion keyIndexedNode = cssModel.getIndexedRegion(pos); |
| if (keyIndexedNode == null) { |
| keyIndexedNode = (IndexedRegion) ((ICSSModel) cssModel).getDocument(); |
| } |
| arranger = new CSSProposalArranger(pos, (ICSSNode) keyIndexedNode, offset, (char) 0, selected); |
| } |
| } else if ((parent != null) && parent.getNodeName().equalsIgnoreCase(HTML40Namespace.ElementName.STYLE)) { |
| // now we know the cursor is in a <style> tag with a region |
| // use the parent because that will be the <style> tag |
| IStructuredModel cssModel = getCSSModel(parent); |
| if (cssModel != null) { |
| // adjust offsets for embedded style |
| int offset = indexedNode.getStartOffset(); |
| int pos = documentPosition - offset; |
| IndexedRegion keyIndexedNode = cssModel.getIndexedRegion(pos); |
| if (keyIndexedNode == null) { |
| keyIndexedNode = (IndexedRegion) ((ICSSModel) cssModel).getDocument(); |
| } |
| arranger = new CSSProposalArranger(pos, (ICSSNode) keyIndexedNode, offset, (char) 0, selected); |
| } |
| } else if (indexedNode instanceof IDOMNode) { |
| // get model for node w/ style attribute |
| IStructuredModel cssModel = getCSSModel((IDOMNode) indexedNode); |
| if (cssModel != null) { |
| IndexedRegion keyIndexedNode = cssModel.getIndexedRegion(documentPosition - fDocumentOffset); |
| if (keyIndexedNode == null) { |
| keyIndexedNode = (IndexedRegion) ((ICSSModel) cssModel).getDocument(); |
| } |
| if (keyIndexedNode instanceof ICSSNode) { |
| // inline style for a tag, not embedded |
| arranger = new CSSProposalArranger(documentPosition, (ICSSNode) keyIndexedNode, fDocumentOffset, fQuote, selected); |
| } |
| } |
| } else if (indexedNode instanceof ICSSNode) { |
| // when editing external CSS using CSS Designer, ICSSNode is |
| // passed. |
| ICSSDocument cssdoc = ((ICSSNode) indexedNode).getOwnerDocument(); |
| if (cssdoc != null) { |
| IStructuredModel cssModel = cssdoc.getModel(); |
| if (cssModel != null) { |
| IndexedRegion keyIndexedNode = cssModel.getIndexedRegion(documentPosition - fDocumentOffset); |
| if (keyIndexedNode == null) { |
| keyIndexedNode = (IndexedRegion) ((ICSSModel) cssModel).getDocument(); |
| } |
| if (keyIndexedNode instanceof ICSSNode) { |
| // inline style for a tag, not embedded |
| arranger = new CSSProposalArranger(documentPosition, (ICSSNode) keyIndexedNode, fDocumentOffset, fQuote, selected); |
| } |
| } |
| } |
| } else if ((indexedNode == null) && isViewerEmpty(viewer)) { |
| isEmptyDocument = true; |
| // the top of empty CSS Document |
| IStructuredModel cssModel = null; |
| try { |
| cssModel = StructuredModelManager.getModelManager().getExistingModelForRead(viewer.getDocument()); |
| if (cssModel instanceof ICSSModel) { |
| IndexedRegion keyIndexedNode = cssModel.getIndexedRegion(documentPosition - fDocumentOffset); |
| if (keyIndexedNode == null) { |
| keyIndexedNode = (IndexedRegion) ((ICSSModel) cssModel).getDocument(); |
| } |
| if (keyIndexedNode instanceof ICSSNode) { |
| // inline style for a tag, not embedded |
| arranger = new CSSProposalArranger(documentPosition, (ICSSNode) keyIndexedNode, fDocumentOffset, fQuote); |
| } |
| } |
| } finally { |
| if (cssModel != null) |
| cssModel.releaseFromRead(); |
| } |
| } |
| |
| ICompletionProposal[] proposals = new ICompletionProposal[0]; |
| if (arranger != null) { |
| fDocumentOffset = 0; |
| proposals = arranger.getProposals(); |
| |
| ICompletionProposal[] newfileproposals = new ICompletionProposal[0]; |
| ICompletionProposal[] anyproposals = new ICompletionProposal[0]; |
| // add template proposals |
| if (getTemplateCompletionProcessor() != null) { |
| if (isEmptyDocument) { |
| getTemplateCompletionProcessor().setContextType(TemplateContextTypeIdsCSS.NEW); |
| newfileproposals = getTemplateCompletionProcessor().computeCompletionProposals(viewer, documentPosition); |
| } |
| getTemplateCompletionProcessor().setContextType(TemplateContextTypeIdsCSS.ALL); |
| anyproposals = getTemplateCompletionProcessor().computeCompletionProposals(viewer, documentPosition); |
| } |
| |
| // add end tag if parent is not closed |
| ICompletionProposal endTag = XMLContentAssistUtilities.computeXMLEndTagProposal(viewer, documentPosition, indexedNode, HTML40Namespace.ElementName.STYLE, SharedXMLEditorPluginImageHelper.IMG_OBJ_TAG_GENERIC); |
| |
| // add the additional proposals |
| int additionalLength = newfileproposals.length + anyproposals.length; |
| additionalLength = (endTag != null) ? ++additionalLength : additionalLength; |
| if (additionalLength > 0) { |
| ICompletionProposal[] plusOnes = new ICompletionProposal[proposals.length + additionalLength]; |
| int appendPos = proposals.length; |
| // add end tag proposal |
| if (endTag != null) { |
| System.arraycopy(proposals, 0, plusOnes, 1, proposals.length); |
| plusOnes[0] = endTag; |
| ++appendPos; |
| } else { |
| System.arraycopy(proposals, 0, plusOnes, 0, proposals.length); |
| } |
| // add items in newfileproposals |
| for (int i = 0; i < newfileproposals.length; ++i) { |
| plusOnes[appendPos + i] = newfileproposals[i]; |
| } |
| // add items in anyproposals |
| appendPos = appendPos + newfileproposals.length; |
| for (int i = 0; i < anyproposals.length; ++i) { |
| plusOnes[appendPos + i] = anyproposals[i]; |
| } |
| proposals = plusOnes; |
| } |
| } |
| return proposals; |
| } |
| |
| /** |
| * Returns true if there is no text or it's all white space, otherwise |
| * returns false |
| * |
| * @param treeNode |
| * @param textViewer |
| * @return boolean |
| */ |
| private boolean isViewerEmpty(ITextViewer textViewer) { |
| boolean isEmpty = false; |
| String text = textViewer.getTextWidget().getText(); |
| if ((text == null) || ((text != null) && text.trim().equals(""))) //$NON-NLS-1$ |
| isEmpty = true; |
| return isEmpty; |
| } |
| |
| /** |
| * Get CSSModel for an indexed node |
| * |
| * @param indexedNode |
| * @return IStructuredModel |
| */ |
| // private IStructuredModel getCSSModel(IndexedRegion indexedNode) { |
| // if (indexedNode == null) return null; |
| // Node node = (Node)indexedNode; |
| // INodeNotifier notifier = (INodeNotifier)node.getParentNode(); |
| // if (notifier == null) return null; |
| // INodeAdapter adapter = |
| // StyleAdapterFactory.getInstance().adapt(notifier); |
| // if (adapter == null || !(adapter instanceof CSSModelAdapter)) return |
| // null; |
| // CSSModelAdapter modelAdapter = (CSSModelAdapter)adapter; |
| // return modelAdapter.getModel(); |
| // } |
| /** |
| * Returns the CSSmodel for a given XML node. |
| * |
| * @param element |
| * @return IStructuredModel |
| */ |
| private IStructuredModel getCSSModel(IDOMNode element) { |
| if (element == null) |
| return null; |
| INodeAdapter adapter = StyleAdapterFactory.getInstance().adapt(element); |
| if ((adapter == null) || !(adapter instanceof ICSSModelAdapter)) |
| return null; |
| ICSSModelAdapter modelAdapter = (ICSSModelAdapter) adapter; |
| return modelAdapter.getModel(); |
| } |
| |
| /** |
| * Returns information about possible contexts based on the specified |
| * location within the document that corresponds to the current cursor |
| * position within the text viewer. |
| * |
| * @param viewer |
| * the viewer whose document is used to compute the possible |
| * contexts |
| * @param documentPosition |
| * an offset within the document for which context information |
| * should be computed |
| * @return an array of context information objects or <code>null</code> |
| * if no context could be found |
| */ |
| public org.eclipse.jface.text.contentassist.IContextInformation[] computeContextInformation(org.eclipse.jface.text.ITextViewer viewer, int documentOffset) { |
| return null; |
| } |
| |
| /** |
| * Returns the characters which when entered by the user should |
| * automatically trigger the presentation of possible completions. |
| * |
| * @return the auto activation characters for completion proposal or |
| * <code>null</code> if no auto activation is desired |
| */ |
| public char[] getCompletionProposalAutoActivationCharacters() { |
| return null; |
| } |
| |
| /** |
| * Returns the characters which when entered by the user should |
| * automatically trigger the presentation of context information. |
| * |
| * @return the auto activation characters for presenting context |
| * information or <code>null</code> if no auto activation is |
| * desired |
| */ |
| public char[] getContextInformationAutoActivationCharacters() { |
| return null; |
| } |
| |
| /** |
| * Returns a validator used to determine when displayed context |
| * information should be dismissed. May only return <code>null</code> if |
| * the processor is incapable of computing context information. |
| * |
| * @return a context information validator, or <code>null</code> if the |
| * processor is incapable of computing context information |
| */ |
| public org.eclipse.jface.text.contentassist.IContextInformationValidator getContextInformationValidator() { |
| return null; |
| } |
| |
| /** |
| * Return the reason why computeProposals was not able to find any |
| * completions. |
| * |
| * @return an error message or null if no error occurred |
| */ |
| public String getErrorMessage() { |
| return null; |
| } |
| |
| /** |
| * Insert the method's description here. Creation date: (2001/05/22 |
| * 10:37:05) |
| * |
| * @param offset |
| * int |
| */ |
| public void setDocumentOffset(int offset) { |
| fDocumentOffset = offset; |
| } |
| |
| /** |
| * |
| * @param quote |
| * char |
| */ |
| public void setQuoteCharOfStyleAttribute(char quote) { |
| fQuote = quote; |
| } |
| |
| private CSSTemplateCompletionProcessor getTemplateCompletionProcessor() { |
| if (fTemplateProcessor == null) { |
| fTemplateProcessor = new CSSTemplateCompletionProcessor(); |
| } |
| return fTemplateProcessor; |
| } |
| } |