blob: d596a2c50e9511e0b55b7896f12f8447ac8aae69 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006 Sybase, Inc. 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:
* Sybase, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.jst.pagedesigner.dnd.internal;
import org.eclipse.gef.SharedCursors;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jst.pagedesigner.dom.EditModelQuery;
import org.eclipse.jst.pagedesigner.dom.EditValidateUtil;
import org.eclipse.jst.pagedesigner.dom.IDOMPosition;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ST;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Caret;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
import org.eclipse.wst.sse.ui.StructuredTextEditor;
import org.eclipse.wst.xml.core.internal.contentmodel.modelquery.ModelQuery;
import org.eclipse.wst.xml.core.internal.modelquery.ModelQueryUtil;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
/**
* This class will 1. determine it's insertion or update 2. call validator
* corresponding helper to resolve it.
*
* @author mengbo
*/
public final class SourceViewerDragDropHelper {
private static SourceViewerDragDropHelper _instance;
/**
* @return the singleton instance
*/
public static SourceViewerDragDropHelper getInstance() {
if (_instance == null) {
_instance = new SourceViewerDragDropHelper();
}
return _instance;
}
private SourceViewerDragDropHelper()
{
// singleton, no external instantiation
}
private Point toControl(TextViewer textViewer, Point point) {
return (textViewer != null ? textViewer.getTextWidget()
.toControl(point) : point);
}
private int getDropOffset(StructuredTextEditor ste, Point pt) {
StyledText st = ste.getTextViewer().getTextWidget();
int offset = st.getCaretOffset();
try {
offset = st.getOffsetAtLocation(pt);
} catch (IllegalArgumentException e) {
boolean found = false;
Point p = new Point((pt.x > 0 ? pt.x : 0), pt.y);
// search nearest character
for (; p.x > -1; p.x--) {
try {
offset = st.getOffsetAtLocation(p);
/*
* Now that a valid offset has been found, try to place at
* the end of the line
*/
if (ste.getTextViewer() != null
&& ste.getTextViewer().getDocument() != null) {
IRegion lineInfo = null;
try {
lineInfo = ste.getTextViewer().getDocument()
.getLineInformationOfOffset(offset);
} catch (BadLocationException e1) {
// ignore exception and fall-through with lineInfo == null
}
if (lineInfo != null)
offset = lineInfo.getOffset()
+ lineInfo.getLength();
}
found = true;
break;
} catch (IllegalArgumentException ex) {
// for trying location, no need to catch.
}
}
if (!found) {
offset = st.getCharCount();
}
}
return offset;
}
/**
* @param textEditor
* @param location
* @param caret
*/
public void updateCaret(StructuredTextEditor textEditor, Point location,
Point caret) {
TextViewer textViewer = textEditor.getTextViewer();
if (textViewer != null) {
Point pt = toControl(textViewer, location);
StyledText st = textViewer.getTextWidget();
// auto scroll
Rectangle ca = st.getClientArea();
int margin = st.getLineHeight();
if (pt.y < margin) { // up
st.invokeAction(ST.LINE_UP);
} else if (pt.y > ca.height - margin) { // down
st.invokeAction(ST.LINE_DOWN);
}
// draw insertion point
int offset = getDropOffset(textEditor, pt);
if (offset != st.getCaretOffset()) {
st.setCaretOffset(offset);
st.setSelection(offset);
}
Point newCaret = st.getLocationAtOffset(offset);
if (newCaret.equals(caret)) {
return;
}
Caret ct = st.getCaret();
Point size = ct.getSize();
GC gc = new GC(st);
//gc.setXORMode(true);
gc.setLineWidth(size.x);
// erase old caret
if (caret != null) {
Color originalForeground = gc.getForeground();
gc.setForeground(st.getBackground());
gc.drawLine(caret.x, caret.y, caret.x, caret.y + size.y);
gc.setForeground(originalForeground);
}
st.redraw();
st.update();
// draw new caret
if (caret == null) {
caret = newCaret;
} else {
caret.x = newCaret.x;
caret.y = newCaret.y;
}
if (ct.getImage() != null) {
gc.drawImage(ct.getImage(), caret.x, caret.y);
} else {
gc.drawLine(caret.x, caret.y, caret.x, caret.y + size.y);
}
gc.dispose();
}
}
/**
* @param textEditor
* @param location
*/
public void updateCaret(StructuredTextEditor textEditor, Point location) {
TextViewer textViewer = textEditor.getTextViewer();
if (textViewer != null) {
Point pt = toControl(textViewer, location);
StyledText st = textViewer.getTextWidget();
// auto scroll
Rectangle ca = st.getClientArea();
int margin = st.getLineHeight();
if (pt.y < margin) { // up
st.invokeAction(ST.LINE_UP);
} else if (pt.y > ca.height - margin) { // down
st.invokeAction(ST.LINE_DOWN);
}
// draw insertion point
int offset = getDropOffset(textEditor, pt);
if (offset != st.getCaretOffset()) {
st.setCaretOffset(offset);
st.setSelection(offset);
}
}
}
/**
* @param textEditor
* @param location
* @return the caret offset
*/
public int showCaret(StructuredTextEditor textEditor, int location) {
StyledText text = textEditor.getTextViewer().getTextWidget();
text.setCursor(SharedCursors.CURSOR_TREE_ADD);
text.setCaretOffset(location);
if (!text.isFocusControl()) {
text.setFocus();
}
return text.getCaretOffset();
}
/**
* @param node
* @return the model query for the node or null if not available
*/
protected ModelQuery getModelQuery(Node node) {
if (node.getNodeType() == Node.DOCUMENT_NODE) {
return ModelQueryUtil.getModelQuery((Document) node);
}
return ModelQueryUtil.getModelQuery(node.getOwnerDocument());
}
/**
* @param caretPos
* @param element
* @return the position
*/
public IDOMPosition findPosition(int caretPos, Node element) {
EditValidateUtil.validNode(element);
IDOMPosition position = EditModelQuery.getInstance().createDomposition(
((IDOMNode) element).getModel(), caretPos, false);
return position;
}
/**
* @param viewer
* @param node
*/
public void format(TextViewer viewer, Node node) {
if (node == null) {
return;
}
Node tmp;
int start, offset;
if (node.getPreviousSibling() != null) {
tmp = node.getPreviousSibling();
start = ((IndexedRegion) tmp).getEndOffset();
} else {
tmp = node;
start = ((IndexedRegion) tmp).getStartOffset();
}
if (node.getNextSibling() != null) {
tmp = node.getNextSibling();
offset = ((IndexedRegion) tmp).getStartOffset() - start;
} else {
tmp = node;
offset = ((IndexedRegion) tmp).getEndOffset() - start;
}
viewer.setSelectedRange(start, offset);
viewer.doOperation(ISourceViewer.FORMAT);
}
/**
* @param textEditor
* @param reset
*/
public void changeCaret(StructuredTextEditor textEditor, boolean reset) {
if (reset) {
StyledText text = textEditor.getTextViewer().getTextWidget();
text.setCursor(new Cursor(null, SWT.CURSOR_IBEAM));
}
}
/**
* @param textEditor
* @param locationOffset
* @return the location offset
*/
public int getValidLocation(StructuredTextEditor textEditor,
int locationOffset) {
Node node = getCaretNode(textEditor, locationOffset);
if (node == null) {
// empty page?
return 0;
}
if (node.getNodeType() == Node.TEXT_NODE) {
return locationOffset;
}
return calculateCaretLocation(node, locationOffset);
}
/**
* @param textEditor
* @param location
* @return the offset
*/
public int getOffset(StructuredTextEditor textEditor, Point location) {
StyledText text = textEditor.getTextViewer().getTextWidget();
return text.getOffsetAtLocation(location);
}
// private IStructuredModel getModel(StructuredTextEditor textEditor)
// {
// IStructuredModel model = null;
// if (textEditor.getDocumentProvider() != null)
// {
// if (textEditor.getDocumentProvider() instanceof IModelProvider)
// {
// model = ((IModelProvider)
// textEditor.getDocumentProvider()).getModel(textEditor.getEditorInput());
// }
// else
// {
// IDocument doc =
// textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput());
// if (doc instanceof IDocument)
// {
// model =
// StructuredModelManager.getModelManager().getExistingModelForEdit(doc);
// if (model == null)
// {
// model =
// StructuredModelManager.getModelManager().getExistingModelForEdit((IDocument)
// doc);
// }
// }
// }
// }
// return model;
// }
/**
* @param textEditor
* @param pos
* @return the node
*/
public Node getCaretNode(StructuredTextEditor textEditor, int pos) {
// TODO: getModel is deprecated
IStructuredModel model = textEditor.getModel();
// getModel(textEditor);
if (model == null) {
return null;
}
IndexedRegion inode = model.getIndexedRegion(pos);
if (inode == null) {
inode = model.getIndexedRegion(pos - 1);
}
return (inode instanceof Node) ? (Node) inode : null;
}
/**
* Calculate and adjust the location in compare with Node.
*
* @param node
* @param location
* @return the location
*/
public int calculateCaretLocation(Node node, int location) {
int pos[][] = new int[2][2];
pos[0][0] = EditModelQuery.getNodeStartIndex(node);
pos[0][1] = EditModelQuery.getNodeStartNameEndIndex(node);
pos[1][0] = EditModelQuery.getNodeEndNameStartIndex(node);
pos[1][1] = EditModelQuery.getNodeEndIndex(node);
if (pos[0][0] >= location || pos[1][0] == location
|| pos[1][1] <= location) {
return location;
} else if (pos[0][0] <= location && pos[0][1] >= location) {
if (((pos[0][1] + pos[0][0]) / 2) >= location) {
return pos[0][0];
}
return pos[0][1];
} else if (pos[1][0] <= location && pos[1][1] >= location) {
if (((pos[1][1] + pos[1][0]) / 2) >= location) {
return pos[1][0];
}
return pos[1][1];
}
return location;
}
}