1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 22:52:11 +02:00

Implement Bug 78677 - Text drag and drop in C/C++ editor window

This commit is contained in:
Anton Leherbauer 2006-07-05 14:43:32 +00:00
parent b8e8fd3c90
commit d65e25dbd5
6 changed files with 822 additions and 1 deletions

View file

@ -40,6 +40,11 @@
<adapter type="org.eclipse.ui.IActionFilter"/> <adapter type="org.eclipse.ui.IActionFilter"/>
<adapter type="org.eclipse.core.resources.IWorkspaceRoot"/> <adapter type="org.eclipse.core.resources.IWorkspaceRoot"/>
</factory> </factory>
<factory
adaptableType="org.eclipse.ui.texteditor.ITextEditor"
class="org.eclipse.cdt.internal.ui.dnd.TextEditorDropAdapter$Factory">
<adapter type="org.eclipse.ui.texteditor.ITextEditorDropTargetListener"/>
</factory>
</extension> </extension>
<!-- Implement our filters. --> <!-- Implement our filters. -->

View file

@ -8,6 +8,7 @@
# Contributors: # Contributors:
# Rational Software - Initial API and implementation # Rational Software - Initial API and implementation
# Markus Schorn (Wind River Systems) # Markus Schorn (Wind River Systems)
# Anton Leherbauer (Wind River Systems)
############################################################################### ###############################################################################
Drag.move.problem.title=Drag and Drop Problem Drag.move.problem.title=Drag and Drop Problem
@ -89,3 +90,8 @@ CHelpConfigurationPropertyPage.buttonLabels.UncheckAll=Uncheck All
CHelpConfigurationPropertyPage.HelpBooks=Help books CHelpConfigurationPropertyPage.HelpBooks=Help books
AsyncTreeContentProvider.JobName=Child Node Computation AsyncTreeContentProvider.JobName=Child Node Computation
AsyncTreeContentProvider.TaskName=Compute child nodes AsyncTreeContentProvider.TaskName=Compute child nodes
TextEditorDropAdapter.error.title=Drag and Drop
TextEditorDropAdapter.error.message=A problem occurred during drag and drop.
TextEditorDropAdapter.unreadableFile=Unreadable file: ''{0}''
TextEditorDropAdapter.noFile=Not a file: ''{0}''

View file

@ -0,0 +1,558 @@
/*******************************************************************************
* Copyright (c) 2006 Wind River Systems, 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:
* Anton Leherbauer (Wind River Systems) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.ui.dnd;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdapterFactory;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPositionCategoryException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextOperationTarget;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.ITextViewerExtension5;
import org.eclipse.jface.text.Position;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.StyledTextContent;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Caret;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.part.MarkerTransfer;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.ITextEditorDropTargetListener;
import org.eclipse.ui.texteditor.ITextEditorExtension;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.internal.ui.CUIMessages;
import org.eclipse.cdt.internal.ui.util.EditorUtility;
import org.eclipse.cdt.internal.ui.util.ExceptionHandler;
/**
* A drop adapter which supports dragging a non-workspace file from some
* external tool (e.g. explorer) into the editor area. The adaptor also supports
* text and marker transfer.
*/
public class TextEditorDropAdapter extends DropTargetAdapter implements
ITextEditorDropTargetListener {
/**
* Adapter factory for text editor drop target listeners. Can be registered
* to add text, file and marker drop support for all
* <code>ITextEditor</code>s.
*
* @see ITextEditorDropTargetListener
*/
public static class Factory implements IAdapterFactory {
private static final Class[] CLASSES= { ITextEditorDropTargetListener.class };
/*
* @see org.eclipse.core.runtime.IAdapterFactory#getAdapter(java.lang.Object,
* java.lang.Class)
*/
public Object getAdapter(Object adaptableObject, Class adapterType) {
if (adaptableObject instanceof ITextEditor) {
return TextEditorDropAdapter.create((ITextEditor) adaptableObject);
}
return null;
}
/*
* @see org.eclipse.core.runtime.IAdapterFactory#getAdapterList()
*/
public Class[] getAdapterList() {
return CLASSES;
}
}
/** Saved original caret during drag operation */
private Caret fOldCaret;
/** Caret used during drag operation to indicate insert point */
private Caret fCaret;
/** The text viewer target */
private ITextViewer fViewer;
/** The editor containing the viewer (can be null) */
private ITextEditor fEditor;
/** Direction of current autoscroll SWT.UP, SWT.DOWN or SWT.NULL */
private int fAutoScrollDirection= SWT.NULL;
/**
* Create an EditorDropAdapter for the given text viewer and (optional)
* editor.
*
* @param viewer
* the text viewer, may not be <code>null</code>
* @param editor
* the text editor, may be <code>null</code>
*/
public TextEditorDropAdapter(ITextViewer viewer, ITextEditor editor) {
super();
fViewer= viewer;
fEditor= editor;
}
/*
* @see org.eclipse.swt.dnd.DropTargetListener#drop(org.eclipse.swt.dnd.DropTargetEvent)
*/
public void drop(final DropTargetEvent event) {
try {
TransferData dataType= event.currentDataType;
if (isFileDataType(dataType)) {
// event.data is an array of strings which represent the
// absolute file pathes
assert event.data instanceof String[];
dropFiles((String[]) event.data);
} else if (isMarkerDataType(dataType)) {
assert event.data instanceof IMarker[];
dropMarkers((IMarker[]) event.data);
} else if (isTextDataType(dataType)) {
// event.data is a string
assert event.data instanceof String;
assert isDocumentEditable();
autoScroll(SWT.NULL);
int offset= getOffsetAtLocation(event.x, event.y, true);
dropText((String) event.data, offset);
}
} catch (CoreException exc) {
ExceptionHandler.handle(exc,
CUIMessages.getString("TextEditorDropAdapter.error.title"),
CUIMessages.getString("TextEditorDropAdapter.error.message"));
}
}
/*
* @see org.eclipse.swt.dnd.DropTargetListener#dragEnter(org.eclipse.swt.dnd.DropTargetEvent)
*/
public void dragEnter(DropTargetEvent event) {
TransferData dataType= event.currentDataType;
if (isFileDataType(dataType)) {
// make sure the file is never moved; always do a copy
event.detail= DND.DROP_COPY;
event.feedback= DND.FEEDBACK_NONE;
} else if (isMarkerDataType(dataType)) {
event.detail= DND.DROP_COPY;
event.feedback= DND.FEEDBACK_NONE;
} else if (isTextDataType(dataType)) {
if (isDocumentEditable()) {
if (event.detail == DND.DROP_DEFAULT) {
event.detail= getAcceptableOperation(event.operations);
}
StyledText textWidget= fViewer.getTextWidget();
textWidget.setFocus();
fOldCaret= textWidget.getCaret();
fCaret= new Caret(textWidget, SWT.NONE);
fCaret.setSize(fOldCaret.getSize());
int offset= getOffsetAtLocation(event.x, event.y, true);
if (offset >= 0) {
fCaret.setLocation(textWidget.getLocationAtOffset(offset));
}
} else {
event.detail= DND.DROP_NONE;
}
event.feedback= DND.FEEDBACK_SCROLL;
}
}
/*
* @see org.eclipse.swt.dnd.DropTargetListener#dragOver(org.eclipse.swt.dnd.DropTargetEvent)
*/
public void dragOver(DropTargetEvent event) {
TransferData dataType= event.currentDataType;
if (isFileDataType(dataType)) {
// make sure the file is never moved; always do a copy
event.detail= DND.DROP_COPY;
event.feedback= DND.FEEDBACK_NONE;
} else if (isMarkerDataType(dataType)) {
event.detail= DND.DROP_COPY;
event.feedback= DND.FEEDBACK_NONE;
} else if (isTextDataType(dataType)) {
if (isDocumentEditable()) {
if ((event.operations & event.detail) == 0) {
event.detail= getAcceptableOperation(event.operations);
}
int offset= getOffsetAtLocation(event.x, event.y, true);
StyledText textWidget= fViewer.getTextWidget();
if (offset >= 0) {
fCaret.setLocation(textWidget.getLocationAtOffset(offset));
} else {
event.detail= DND.DROP_NONE;
}
// scroll feedback has issues (bugs 149576, 139485): we do it
// ourselves
Point location= textWidget.toControl(event.x, event.y);
Rectangle viewPort= textWidget.getClientArea();
if (location.y < textWidget.getLineHeight()) {
autoScroll(SWT.UP);
} else if (location.y > viewPort.height
- textWidget.getLineHeight()) {
autoScroll(SWT.DOWN);
} else {
autoScroll(SWT.NULL);
}
} else {
event.detail= DND.DROP_NONE;
}
event.feedback= DND.FEEDBACK_SCROLL;
}
}
private static boolean isFileDataType(TransferData dataType) {
return FileTransfer.getInstance().isSupportedType(dataType);
}
private static boolean isTextDataType(TransferData dataType) {
return TextTransfer.getInstance().isSupportedType(dataType);
}
private static boolean isMarkerDataType(TransferData dataType) {
return MarkerTransfer.getInstance().isSupportedType(dataType);
}
/*
* @see org.eclipse.swt.dnd.DropTargetListener#dropAccept(org.eclipse.swt.dnd.DropTargetEvent)
*/
public void dropAccept(DropTargetEvent event) {
TransferData dataType= event.currentDataType;
if (isTextDataType(dataType)) {
// check if the offset is inside the drag source selection
IDocument doc= fViewer.getDocument();
if (doc.containsPositionCategory(TextViewerDragAdapter.DRAG_SELECTION_CATEGORY)) {
int widgetOffset= getOffsetAtLocation(event.x, event.y, true);
if (widgetOffset != -1) {
int documentOffset= getDocumentOffset(widgetOffset);
try {
Position[] dragSource= doc.getPositions(TextViewerDragAdapter.DRAG_SELECTION_CATEGORY);
if (dragSource.length == 0
|| event.detail == DND.DROP_MOVE
&& dragSource[0].includes(documentOffset)) {
// do not drop-move on the drag source
event.detail = DND.DROP_NONE;
}
} catch (BadPositionCategoryException e) {
event.detail= DND.DROP_NONE;
}
}
}
}
}
/*
* @see org.eclipse.swt.dnd.DropTargetListener#dragOperationChanged(org.eclipse.swt.dnd.DropTargetEvent)
*/
public void dragOperationChanged(DropTargetEvent event) {
TransferData dataType= event.currentDataType;
if (isFileDataType(dataType)) {
// make sure the file is never moved; always do a copy
event.detail= DND.DROP_COPY;
event.feedback= DND.FEEDBACK_NONE;
} else if (isMarkerDataType(dataType)) {
event.detail= DND.DROP_COPY;
event.feedback= DND.FEEDBACK_NONE;
} else if (isTextDataType(dataType)) {
if (isDocumentEditable()) {
if (event.detail == DND.DROP_DEFAULT) {
event.detail= getAcceptableOperation(event.operations);
}
} else {
event.detail= DND.DROP_NONE;
}
event.feedback= DND.FEEDBACK_SCROLL;
}
}
/**
* Get preferred operation out of allowed set.
*
* @param operations
* a bitset of allowed operations
* @return operation the preferred operation
*/
private int getAcceptableOperation(int operations) {
if ((operations & DND.DROP_MOVE) != 0 && isDocumentEditable()) {
return DND.DROP_MOVE;
}
if ((operations & DND.DROP_COPY) != 0) {
return DND.DROP_COPY;
}
return DND.DROP_NONE;
}
/*
* @see org.eclipse.swt.dnd.DropTargetListener#dragLeave(org.eclipse.swt.dnd.DropTargetEvent)
*/
public void dragLeave(DropTargetEvent event) {
autoScroll(SWT.NULL);
if (fOldCaret != null) {
StyledText textWidget= fViewer.getTextWidget();
textWidget.setCaret(fOldCaret);
fOldCaret= null;
}
if (fCaret != null) {
fCaret.dispose();
fCaret= null;
}
}
/**
* Drop text data at offset.
*
* @param text
* @param offset
* @throws CoreException
*/
private void dropText(String text, int offset) throws CoreException {
IDocument d= fViewer.getDocument();
try {
int docOffset= getDocumentOffset(offset);
d.replace(docOffset, 0, text);
fViewer.setSelectedRange(docOffset, text.length());
} catch (BadLocationException e) {
// should not happen
throw new CoreException(
new Status(IStatus.ERROR, CUIPlugin.getPluginId(), 0,
e.getLocalizedMessage(), e));
}
}
/**
* Drop (external) files.
*
* @param fileNames
*/
private void dropFiles(String[] fileNames) throws CoreException {
for (int i= 0; i < fileNames.length; i++) {
Path path= new Path(fileNames[i]);
java.io.File file= path.toFile();
if (!file.isFile()) {
throw new CoreException(new Status(IStatus.ERROR, CUIPlugin
.getPluginId(), 0, CUIMessages.getFormattedString(
"TextEditorDropAdapter.noFile", fileNames[i]),
null));
}
if (file.canRead()) {
IEditorInput editorInput= EditorUtility.getEditorInputForLocation(path);
IEditorDescriptor desc= IDE.getEditorDescriptor(file.getName());
String editorId= desc.getId();
IDE.openEditor(getPage(), editorInput, editorId);
} else {
throw new CoreException(new Status(IStatus.ERROR, CUIPlugin
.getPluginId(), 0, CUIMessages.getFormattedString(
"TextEditorDropAdapter.unreadableFile", fileNames[i]),
null));
}
}
}
/**
* Drop markers (open editor and navigate to marker).
*
* @param markers
* @throws PartInitException
*/
private void dropMarkers(IMarker[] markers) throws PartInitException {
for (int i= 0; i < markers.length; i++) {
IMarker marker= markers[i];
IDE.openEditor(getPage(), marker);
}
}
private IWorkbenchPage getPage() {
if (fEditor != null) {
return ((IWorkbenchPart) fEditor).getSite().getPage();
}
return CUIPlugin.getActivePage();
}
/**
* Convert mouse screen coordinates to a <code>StyledText</code> offset.
*
* @param x
* @param y
* @param absolute
* if <code>true</code>, coordinates are expected to be
* absolute screen coordinates
* @return text offset
*
* @see StyledText#getOffsetAtLocation() \
*/
private int getOffsetAtLocation(int x, int y, boolean absolute) {
StyledText textWidget= fViewer.getTextWidget();
StyledTextContent content= textWidget.getContent();
Point location;
if (absolute) {
location= textWidget.toControl(x, y);
} else {
location= new Point(x, y);
}
int line= (textWidget.getTopPixel() + location.y)
/ textWidget.getLineHeight();
if (line >= content.getLineCount()) {
return content.getCharCount();
}
int lineOffset= content.getOffsetAtLine(line);
String lineText= content.getLine(line);
Point endOfLine= textWidget.getLocationAtOffset(lineOffset
+ lineText.length());
if (location.x >= endOfLine.x) {
return lineOffset + lineText.length();
}
try {
return textWidget.getOffsetAtLocation(location);
} catch (IllegalArgumentException iae) {
// we are expecting this
return -1;
}
}
/**
* Convert a widget offset to the corresponding document offset.
*
* @param widgetOffset
* @return document offset
*/
private int getDocumentOffset(int widgetOffset) {
if (fViewer instanceof ITextViewerExtension5) {
ITextViewerExtension5 extension= (ITextViewerExtension5) fViewer;
return extension.widgetOffset2ModelOffset(widgetOffset);
} else {
IRegion visible= fViewer.getVisibleRegion();
if (widgetOffset > visible.getLength()) {
return -1;
}
return widgetOffset + visible.getOffset();
}
}
/**
* Scrolls the viewer into the given direction.
*
* @param direction
* the scroll direction
*/
private void autoScroll(int direction) {
if (fAutoScrollDirection == direction)
return;
final int TIMER_INTERVAL= 20;
final Display display= fViewer.getTextWidget().getDisplay();
Runnable timer= null;
switch (direction) {
case SWT.UP:
timer= new Runnable() {
public void run() {
if (fAutoScrollDirection == SWT.UP) {
int top= getInclusiveTopIndex();
if (top > 0) {
fViewer.setTopIndex(top - 1);
display.timerExec(TIMER_INTERVAL, this);
}
}
}
};
break;
case SWT.DOWN:
timer= new Runnable() {
public void run() {
if (fAutoScrollDirection == SWT.DOWN) {
int top= getInclusiveTopIndex();
fViewer.setTopIndex(top + 1);
display.timerExec(TIMER_INTERVAL, this);
}
}
};
break;
}
fAutoScrollDirection= direction;
if (timer != null) {
display.timerExec(TIMER_INTERVAL, timer);
}
}
/**
* Returns the viewer's first visible line, even if only partially visible.
*
* @return the viewer's first visible line
*/
private int getInclusiveTopIndex() {
StyledText textWidget= fViewer.getTextWidget();
if (textWidget != null && !textWidget.isDisposed()) {
int top= fViewer.getTopIndex();
if ((textWidget.getTopPixel() % textWidget.getLineHeight()) != 0)
--top;
return top;
}
return -1;
}
/**
* @return true if the document may be changed by the drag.
*/
private boolean isDocumentEditable() {
if (fEditor instanceof ITextEditorExtension) {
return !((ITextEditorExtension) fEditor).isEditorInputReadOnly();
}
return fViewer.isEditable();
}
/*
* @see org.eclipse.ui.texteditor.ITextEditorDropTargetListener#getTransfers()
*/
public Transfer[] getTransfers() {
return new Transfer[] { TextTransfer.getInstance(),
FileTransfer.getInstance(), MarkerTransfer.getInstance() };
}
/**
* Factory method to create a drop target listener for the given text
* editor.
*
* @param textEditor
* @return a drop target listener or <code>null</code>
*/
protected static ITextEditorDropTargetListener create(ITextEditor textEditor) {
ITextViewer textViewer= (ITextViewer) textEditor
.getAdapter(ITextViewer.class);
if (textViewer == null) {
// this is a little trick to get the viewer from a text editor
ITextOperationTarget target= (ITextOperationTarget) textEditor
.getAdapter(ITextOperationTarget.class);
if (target instanceof ITextViewer) {
textViewer= (ITextViewer) target;
}
}
if (textViewer == null) {
return null;
}
return new TextEditorDropAdapter(textViewer, textEditor);
}
}

View file

@ -0,0 +1,203 @@
/*******************************************************************************
* Copyright (c) 2006 Wind River Systems, 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:
* Anton Leherbauer (Wind River Systems) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.ui.dnd;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPositionCategoryException;
import org.eclipse.jface.text.DefaultPositionUpdater;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IPositionUpdater;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.ITextViewerExtension;
import org.eclipse.jface.text.ITextViewerExtension5;
import org.eclipse.jface.text.Position;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.StyledTextContent;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.texteditor.ITextEditorExtension;
/**
* Drag source adapter for text selections in ITextViewers.
*/
public class TextViewerDragAdapter extends DragSourceAdapter {
/** The position category to be used to indicate a drag source selection */
public final static String DRAG_SELECTION_CATEGORY= "dragSelectionCategory"; //$NON-NLS-1$
/** The position updater for the drag selection position */
private IPositionUpdater fPositionUpdater;
/** The drag selection position */
private Position fSelectionPosition;
/** The text viewer allowing drag */
private ITextViewer fViewer;
/** The editor of the viewer (may be null) */
private ITextEditorExtension fEditor;
/**
* Create a new TextViewerDragAdapter.
* @param viewer the text viewer
*/
public TextViewerDragAdapter(ITextViewer viewer) {
this(viewer, null);
}
/**
* Create a new TextViewerDragAdapter.
* @param viewer the text viewer
*/
public TextViewerDragAdapter(ITextViewer viewer, ITextEditorExtension editor) {
fViewer= viewer;
fEditor= editor;
}
/*
* @see org.eclipse.swt.dnd.DragSourceListener#dragFinished(org.eclipse.swt.dnd.DragSourceEvent)
*/
public void dragFinished(DragSourceEvent event) {
IDocument doc= fViewer.getDocument();
try {
doc.removePositionCategory(DRAG_SELECTION_CATEGORY);
doc.removePositionUpdater(fPositionUpdater);
} catch (BadPositionCategoryException e1) {
// cannot happen
}
if (event.doit && event.detail == DND.DROP_MOVE && isDocumentEditable()) {
try {
doc.replace(fSelectionPosition.offset, fSelectionPosition.length, null);
} catch (BadLocationException e) {
// ignore
}
}
if (fViewer instanceof ITextViewerExtension) {
((ITextViewerExtension)fViewer).getRewriteTarget().endCompoundChange();
}
}
/*
* @see org.eclipse.swt.dnd.DragSourceListener#dragSetData(org.eclipse.swt.dnd.DragSourceEvent)
*/
public void dragSetData(DragSourceEvent event) {
IDocument doc= fViewer.getDocument();
try {
event.data= doc.get(fSelectionPosition.offset, fSelectionPosition.length);
} catch (BadLocationException e) {
event.detail= DND.DROP_NONE;
event.doit= false;
}
}
/*
* @see org.eclipse.swt.dnd.DragSourceListener#dragStart(org.eclipse.swt.dnd.DragSourceEvent)
*/
public void dragStart(DragSourceEvent event) {
/// convert screen coordinates to widget offest
int offset= getOffsetAtLocation(event.x, event.y, false);
// convert further to a document offset
offset= getDocumentOffset(offset);
Point selection= fViewer.getSelectedRange();
if (selection != null && offset >= selection.x && offset < selection.x+selection.y) {
fSelectionPosition= new Position(selection.x, selection.y);
if (fViewer instanceof ITextViewerExtension) {
((ITextViewerExtension)fViewer).getRewriteTarget().beginCompoundChange();
}
IDocument doc= fViewer.getDocument();
try {
// add the drag selection position
// the position is used to delete the selection on a DROP_MOVE
// and it can be used by the drop target to determine if it should
// allow the drop (e.g. if drop location overlaps selection)
doc.addPositionCategory(DRAG_SELECTION_CATEGORY);
fPositionUpdater= new DefaultPositionUpdater(DRAG_SELECTION_CATEGORY);
doc.addPositionUpdater(fPositionUpdater);
doc.addPosition(DRAG_SELECTION_CATEGORY, fSelectionPosition);
} catch (BadLocationException e) {
// should not happen
} catch (BadPositionCategoryException e) {
// cannot happen
}
event.doit= true;
// this has no effect?
event.detail = DND.DROP_COPY;
if (isDocumentEditable()) {
event.detail |= DND.DROP_MOVE;
}
} else {
event.doit= false;
event.detail = DND.DROP_NONE;
}
}
/**
* Convert mouse screen coordinates to a <code>StyledText</code> offset.
* @param x
* @param y
* @param absolute if true, coordinates are expected to be absolute
* screen coordinates
* @return text offset
*/
private int getOffsetAtLocation(int x, int y, boolean absolute) {
StyledText textWidget= fViewer.getTextWidget();
StyledTextContent content= textWidget.getContent();
Point location;
if (absolute) {
location= textWidget.toControl(x, y);
} else {
location= new Point(x ,y);
}
int line= (textWidget.getTopPixel() + location.y) / textWidget.getLineHeight();
if (line >= content.getLineCount()) {
return content.getCharCount();
}
int lineOffset= content.getOffsetAtLine(line);
String lineText= content.getLine(line);
Point endOfLine= textWidget.getLocationAtOffset(lineOffset + lineText.length());
if (location.x >= endOfLine.x) {
return lineOffset + lineText.length();
}
try {
return textWidget.getOffsetAtLocation(location);
} catch (IllegalArgumentException iae) {
// we are expecting this
return -1;
}
}
/**
* Convert a widget offset to the corresponding document offset.
* @param widgetOffset
* @return document offset
*/
private int getDocumentOffset(int widgetOffset) {
if (fViewer instanceof ITextViewerExtension5) {
ITextViewerExtension5 extension= (ITextViewerExtension5)fViewer;
return extension.widgetOffset2ModelOffset(widgetOffset);
} else {
IRegion visible= fViewer.getVisibleRegion();
if (widgetOffset > visible.getLength()) {
return -1;
}
return widgetOffset + visible.getOffset();
}
}
/**
* @return true if the document may be changed by the drag.
*/
private boolean isDocumentEditable() {
if (fEditor != null) {
return !fEditor.isEditorInputReadOnly();
}
return fViewer.isEditable();
}
}

View file

@ -32,6 +32,8 @@ import org.eclipse.cdt.internal.ui.actions.FoldingActionGroup;
import org.eclipse.cdt.internal.ui.actions.GoToNextPreviousMemberAction; import org.eclipse.cdt.internal.ui.actions.GoToNextPreviousMemberAction;
import org.eclipse.cdt.internal.ui.actions.JoinLinesAction; import org.eclipse.cdt.internal.ui.actions.JoinLinesAction;
import org.eclipse.cdt.internal.ui.actions.RemoveBlockCommentAction; import org.eclipse.cdt.internal.ui.actions.RemoveBlockCommentAction;
import org.eclipse.cdt.internal.ui.dnd.TextEditorDropAdapter;
import org.eclipse.cdt.internal.ui.dnd.TextViewerDragAdapter;
import org.eclipse.cdt.internal.ui.search.actions.OpenDeclarationsAction; import org.eclipse.cdt.internal.ui.search.actions.OpenDeclarationsAction;
import org.eclipse.cdt.internal.ui.search.actions.OpenDefinitionAction; import org.eclipse.cdt.internal.ui.search.actions.OpenDefinitionAction;
import org.eclipse.cdt.internal.ui.search.actions.SelectionSearchGroup; import org.eclipse.cdt.internal.ui.search.actions.SelectionSearchGroup;
@ -87,9 +89,16 @@ import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.search.ui.actions.TextSearchGroup; import org.eclipse.search.ui.actions.TextSearchGroup;
import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IEditorActionBarContributor; import org.eclipse.ui.IEditorActionBarContributor;
import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.IFileEditorInput;
@ -113,6 +122,7 @@ import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.IEditorStatusLine; import org.eclipse.ui.texteditor.IEditorStatusLine;
import org.eclipse.ui.texteditor.ITextEditorActionConstants; import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.texteditor.ITextEditorDropTargetListener;
import org.eclipse.ui.texteditor.MarkerAnnotation; import org.eclipse.ui.texteditor.MarkerAnnotation;
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport; import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
import org.eclipse.ui.texteditor.TextOperationAction; import org.eclipse.ui.texteditor.TextOperationAction;
@ -839,6 +849,25 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IS
} }
/*
* @see org.eclipse.ui.texteditor.AbstractTextEditor#initializeDragAndDrop(org.eclipse.jface.text.source.ISourceViewer)
*/
protected void initializeDragAndDrop(ISourceViewer viewer) {
Control control= viewer.getTextWidget();
int operations= DND.DROP_MOVE | DND.DROP_COPY;
DropTarget dropTarget= new DropTarget(control, operations);
ITextEditorDropTargetListener dropTargetListener= new TextEditorDropAdapter(viewer, this);
dropTarget.setTransfer(dropTargetListener.getTransfers());
dropTarget.addDropListener(dropTargetListener);
DragSource dragSource= new DragSource(control, operations);
Transfer[] dragTypes= new Transfer[] { TextTransfer.getInstance() };
dragSource.setTransfer(dragTypes);
DragSourceListener dragSourceListener= new TextViewerDragAdapter(viewer, this);
dragSource.addDragListener(dragSourceListener);
}
/* (non-Javadoc) /* (non-Javadoc)
* @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#gotoMarker(org.eclipse.core.resources.IMarker) * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#gotoMarker(org.eclipse.core.resources.IMarker)
*/ */

View file

@ -29,6 +29,8 @@ import org.eclipse.cdt.internal.ui.editor.CEditor;
import org.eclipse.cdt.internal.ui.editor.CEditorMessages; import org.eclipse.cdt.internal.ui.editor.CEditorMessages;
import org.eclipse.cdt.internal.ui.editor.ITranslationUnitEditorInput; import org.eclipse.cdt.internal.ui.editor.ITranslationUnitEditorInput;
import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IFolder;
@ -261,6 +263,24 @@ public class EditorUtility {
return null; return null;
} }
/**
* Utility method to get an editor input for the given file system location.
* If the location denotes a workspace file, a <code>FileEditorInput</code>
* is returned, otherwise, the input is an <code>IStorageEditorInput</code>
* assuming the location points to an existing file in the file system.
*
* @param location a valid file system location
* @return an editor input
*/
public static IEditorInput getEditorInputForLocation(IPath location) {
IFile resource= FileBuffers.getWorkspaceFileAtLocation(location);
if (resource != null) {
return new FileEditorInput(resource);
} else {
return new ExternalEditorInput(new FileStorage(location));
}
}
/** /**
* If the current active editor edits a c element return it, else * If the current active editor edits a c element return it, else
@ -282,7 +302,7 @@ public class EditorUtility {
/** /**
* Gets the working copy of an compilation unit opened in an editor * Gets the working copy of an compilation unit opened in an editor
* @param part the editor part *
* @param cu the original compilation unit (or another working copy) * @param cu the original compilation unit (or another working copy)
* @return the working copy of the compilation unit, or null if not found * @return the working copy of the compilation unit, or null if not found
*/ */