/*****************************************************************************
* This file is part of Rinzo
*
* Author: Claudio Cancinos
* WWW: https://sourceforge.net/projects/editorxml
* Copyright (C): 2008, Claudio Cancinos
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; If not, see <http://www.gnu.org/licenses/>
****************************************************************************/
package ar.com.tadp.xml.rinzo.core;
import java.util.Iterator;
import org.apache.commons.lang.StringUtils;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextHover;
import org.eclipse.jface.text.ITextHoverExtension2;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.ISourceViewerExtension2;
import ar.com.tadp.xml.rinzo.core.model.XMLNode;
import ar.com.tadp.xml.rinzo.core.model.tags.AttributeDefinition;
/**
* This implementation of {@link org.eclipse.jface.text.ITextHover}. displays
*
* @author ccancinos
*/
public class MultipleLinesTextHover implements ITextHover {
/** This hover's source viewer */
private ISourceViewer sourceViewer;
private RinzoXMLEditor editor;
/**
* Creates a new annotation hover.
*
* @param sourceViewer this hover's annotation model
* @param editor
*/
public MultipleLinesTextHover(ISourceViewer sourceViewer, RinzoXMLEditor editor) {
this.editor = editor;
Assert.isNotNull(sourceViewer);
this.sourceViewer = sourceViewer;
}
/**
* {@inheritDoc}
*
* @deprecated As of 3.4, replaced by {@link ITextHoverExtension2#getHoverInfo2(ITextViewer, IRegion)}
*/
public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
if (hoverRegion.getLength() == 0) {
return null;
}
String annotationMessage = this.getAnnotationMessage(textViewer, hoverRegion);
if (!StringUtils.isEmpty(annotationMessage)) {
return annotationMessage;
}
try {
XMLNode activeNode = this.editor.getModel().getTree().getActiveNode(hoverRegion.getOffset());
if (activeNode.isTag() || activeNode.isEndTag() || activeNode.isEmptyTag()) {
int startName = activeNode.getOffset();
int endName = activeNode.getFullTagName().length();
if (startName <= hoverRegion.getOffset() && ((startName + endName) >= hoverRegion.getOffset())) {
if (activeNode.isEndTag()) {
activeNode = activeNode.getCorrespondingNode();
}
return activeNode.getTypeDefinition().getComment() + "<br>" + "<b>XPath:</b> "
+ activeNode.getXPath();
}
AttributeDefinition attribute = activeNode.getTypeDefinition().getAttribute(
this.sourceViewer.getDocument().get(hoverRegion.getOffset(), hoverRegion.getLength()));
if (attribute != null) {
return attribute.getComment() + "<br>" + "<b>XPath:</b> " + activeNode.getXPath() + "[@"
+ attribute.getName() + "]";
}
}
} catch (Exception e1) {
//DO NOTHING
}
return null;
}
private String getAnnotationMessage(ITextViewer textViewer, IRegion hoverRegion) {
IAnnotationModel model = getAnnotationModel(sourceViewer);
if (model == null) {
return null;
}
Iterator e = model.getAnnotationIterator();
StringBuffer buffer = new StringBuffer();
while (e.hasNext()) {
Annotation a = (Annotation) e.next();
if (isIncluded(a)) {
Position p = model.getPosition(a);
if (p != null && p.overlapsWith(hoverRegion.getOffset(), hoverRegion.getLength())) {
String msg = a.getText();
if (msg != null && msg.trim().length() > 0 && !msg.trim().endsWith("changed lines")
&& !msg.trim().endsWith("changed line")) {
buffer.append("-" + msg);
buffer.append("<br>");
}
}
}
}
return buffer.toString();
}
/*
* @see org.eclipse.jface.text.ITextHover#getHoverRegion(org.eclipse.jface.text.ITextViewer, int)
*/
public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
return findWord(textViewer.getDocument(), offset);
}
/**
* Tells whether the annotation should be included in
* the computation.
*
* @param annotation the annotation to test
* @return <code>true</code> if the annotation is included in the computation
*/
protected boolean isIncluded(Annotation annotation) {
return true;
}
private IAnnotationModel getAnnotationModel(ISourceViewer viewer) {
if (viewer instanceof ISourceViewerExtension2) {
ISourceViewerExtension2 extension = (ISourceViewerExtension2) viewer;
return extension.getVisualAnnotationModel();
}
return viewer.getAnnotationModel();
}
private IRegion findWord(IDocument document, int offset) {
int start= -2;
int end= -1;
try {
int pos= offset;
char c;
while (pos >= 0) {
c = document.getChar(pos);
if (!Character.isUnicodeIdentifierPart(c) && c != '-') {
break;
}
--pos;
}
start= pos;
pos= offset;
int length= document.getLength();
while (pos < length) {
c = document.getChar(pos);
if (!Character.isUnicodeIdentifierPart(c) && c != '-') {
break;
}
++pos;
}
end = pos;
} catch (BadLocationException x) {
}
if (start >= -1 && end > -1) {
if (start == offset && end == offset) {
return new Region(offset, 0);
} else if (start == offset) {
return new Region(start, end - start);
} else {
return new Region(start + 1, end - start - 1);
}
}
return null;
}
}