1
/*******************************************************************************
2
* Copyright (c) 2006, 2007 Wind River Systems, Inc. and others.
3
* All rights reserved. This program and the accompanying materials
4
* are made available under the terms of the Eclipse Public License v1.0
5
* which accompanies this distribution, and is available at
6
* http://www.eclipse.org/legal/epl-v10.html
9
* Anton Leherbauer (Wind River Systems) - initial API and implementation
10
*******************************************************************************/
11
package org.eclipse.cdt.internal.ui.dnd;
13
import org.eclipse.jface.text.BadLocationException;
14
import org.eclipse.jface.text.BadPositionCategoryException;
15
import org.eclipse.jface.text.DefaultPositionUpdater;
16
import org.eclipse.jface.text.IDocument;
17
import org.eclipse.jface.text.IPositionUpdater;
18
import org.eclipse.jface.text.IRegion;
19
import org.eclipse.jface.text.ITextViewer;
20
import org.eclipse.jface.text.ITextViewerExtension;
21
import org.eclipse.jface.text.ITextViewerExtension5;
22
import org.eclipse.jface.text.Position;
23
import org.eclipse.swt.custom.StyledText;
24
import org.eclipse.swt.custom.StyledTextContent;
25
import org.eclipse.swt.dnd.DND;
26
import org.eclipse.swt.dnd.DragSourceAdapter;
27
import org.eclipse.swt.dnd.DragSourceEvent;
28
import org.eclipse.swt.graphics.Point;
29
import org.eclipse.ui.texteditor.ITextEditorExtension;
32
* Drag source adapter for text selections in ITextViewers.
36
public class TextViewerDragAdapter extends DragSourceAdapter {
38
/** The position category to be used to indicate a drag source selection */
39
public final static String DRAG_SELECTION_CATEGORY= "dragSelectionCategory"; //$NON-NLS-1$
40
/** The position updater for the drag selection position */
41
private IPositionUpdater fPositionUpdater;
42
/** The drag selection position */
43
private Position fSelectionPosition;
44
/** The text viewer allowing drag */
45
private ITextViewer fViewer;
46
/** The editor of the viewer (may be null) */
47
private ITextEditorExtension fEditor;
48
/** Flag whether this drag source listener allows to drag */
49
private boolean fIsEnabled= true;
52
* Create a new TextViewerDragAdapter.
53
* @param viewer the text viewer
55
public TextViewerDragAdapter(ITextViewer viewer) {
60
* Create a new TextViewerDragAdapter.
61
* @param viewer the text viewer
63
public TextViewerDragAdapter(ITextViewer viewer, ITextEditorExtension editor) {
69
* @see org.eclipse.swt.dnd.DragSourceListener#dragFinished(org.eclipse.swt.dnd.DragSourceEvent)
72
public void dragFinished(DragSourceEvent event) {
73
IDocument doc= fViewer.getDocument();
75
doc.removePositionCategory(DRAG_SELECTION_CATEGORY);
76
doc.removePositionUpdater(fPositionUpdater);
77
} catch (BadPositionCategoryException e1) {
80
if (event.doit && event.detail == DND.DROP_MOVE && isDocumentEditable()) {
82
doc.replace(fSelectionPosition.offset, fSelectionPosition.length, null);
83
} catch (BadLocationException e) {
87
if (fViewer instanceof ITextViewerExtension) {
88
((ITextViewerExtension)fViewer).getRewriteTarget().endCompoundChange();
93
* @see org.eclipse.swt.dnd.DragSourceListener#dragSetData(org.eclipse.swt.dnd.DragSourceEvent)
96
public void dragSetData(DragSourceEvent event) {
97
IDocument doc= fViewer.getDocument();
99
event.data= doc.get(fSelectionPosition.offset, fSelectionPosition.length);
100
} catch (BadLocationException e) {
101
event.detail= DND.DROP_NONE;
107
* @see org.eclipse.swt.dnd.DragSourceListener#dragStart(org.eclipse.swt.dnd.DragSourceEvent)
110
public void dragStart(DragSourceEvent event) {
115
// convert screen coordinates to widget offest
116
int offset= getOffsetAtLocation(event.x, event.y, false);
117
// convert further to a document offset
118
offset= getDocumentOffset(offset);
119
Point selection= fViewer.getSelectedRange();
120
if (selection != null && offset >= selection.x && offset < selection.x+selection.y) {
121
fSelectionPosition= new Position(selection.x, selection.y);
122
if (fViewer instanceof ITextViewerExtension) {
123
((ITextViewerExtension)fViewer).getRewriteTarget().beginCompoundChange();
125
IDocument doc= fViewer.getDocument();
127
// add the drag selection position
128
// the position is used to delete the selection on a DROP_MOVE
129
// and it can be used by the drop target to determine if it should
130
// allow the drop (e.g. if drop location overlaps selection)
131
doc.addPositionCategory(DRAG_SELECTION_CATEGORY);
132
fPositionUpdater= new DefaultPositionUpdater(DRAG_SELECTION_CATEGORY);
133
doc.addPositionUpdater(fPositionUpdater);
134
doc.addPosition(DRAG_SELECTION_CATEGORY, fSelectionPosition);
135
} catch (BadLocationException e) {
137
} catch (BadPositionCategoryException e) {
141
// this has no effect?
142
event.detail = DND.DROP_COPY;
143
if (isDocumentEditable()) {
144
event.detail |= DND.DROP_MOVE;
148
event.detail = DND.DROP_NONE;
153
* Convert mouse screen coordinates to a <code>StyledText</code> offset.
156
* screen X-coordinate
158
* screen Y-coordinate
160
* if <code>true</code>, coordinates are expected to be
161
* absolute screen coordinates
162
* @return text offset
164
* @see StyledText#getOffsetAtLocation()
166
private int getOffsetAtLocation(int x, int y, boolean absolute) {
167
StyledText textWidget= fViewer.getTextWidget();
168
StyledTextContent content= textWidget.getContent();
171
location= textWidget.toControl(x, y);
173
location= new Point(x ,y);
175
int line= (textWidget.getTopPixel() + location.y) / textWidget.getLineHeight();
176
if (line >= content.getLineCount()) {
177
return content.getCharCount();
179
int lineOffset= content.getOffsetAtLine(line);
180
String lineText= content.getLine(line);
181
Point endOfLine= textWidget.getLocationAtOffset(lineOffset + lineText.length());
182
if (location.x >= endOfLine.x) {
183
return lineOffset + lineText.length();
186
return textWidget.getOffsetAtLocation(location);
187
} catch (IllegalArgumentException iae) {
188
// we are expecting this
194
* Convert a widget offset to the corresponding document offset.
195
* @param widgetOffset
196
* @return document offset
198
private int getDocumentOffset(int widgetOffset) {
199
if (fViewer instanceof ITextViewerExtension5) {
200
ITextViewerExtension5 extension= (ITextViewerExtension5)fViewer;
201
return extension.widgetOffset2ModelOffset(widgetOffset);
203
IRegion visible= fViewer.getVisibleRegion();
204
if (widgetOffset > visible.getLength()) {
207
return widgetOffset + visible.getOffset();
211
* @return true if the document may be changed by the drag.
213
private boolean isDocumentEditable() {
214
if (fEditor != null) {
215
return !fEditor.isEditorInputReadOnly();
217
return fViewer.isEditable();
221
* Enable or disable this drag listener.
224
public void setEnabled(boolean enabled) {