This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 53439
Collapse All | Expand All

(-)openide/src/org/openide/explorer/view/ExplorerDragSupport.java (+14 lines)
Lines 213-216 Link Here
213
    */
213
    */
214
    abstract Node[] obtainNodes (DragGestureEvent dge);
214
    abstract Node[] obtainNodes (DragGestureEvent dge);
215
215
216
217
    // <>
218
    // We need to let some top components listen to the drags so
219
    // they can for example clear explorer selection.
220
    // See bug 5048028.
221
    public void addDragSourceListener(DragSourceListener dsl) {
222
        getDefaultGestureRecognizer().getDragSource().addDragSourceListener(dsl);
223
    }
224
    public void removeDragSourceListener(DragSourceListener dsl) {
225
        getDefaultGestureRecognizer().getDragSource().removeDragSourceListener(dsl);
226
    }
227
    // </>
228
229
216
} /* end class ExplorerDragSupport */
230
} /* end class ExplorerDragSupport */
(-)openide/src/org/openide/explorer/view/TreeView.java (+31 lines)
Lines 16-21 Link Here
16
16
17
import java.awt.*;
17
import java.awt.*;
18
import java.awt.dnd.DnDConstants;
18
import java.awt.dnd.DnDConstants;
19
// <>
20
import java.awt.dnd.DragSourceListener;
21
// </>
19
import java.awt.dnd.Autoscroll;
22
import java.awt.dnd.Autoscroll;
20
import java.awt.event.*;
23
import java.awt.event.*;
21
import java.beans.PropertyChangeEvent;
24
import java.beans.PropertyChangeEvent;
Lines 350-355 Link Here
350
        }
353
        }
351
    }
354
    }
352
355
356
    // <>
357
    // We need to let some top components listen to the drags so
358
    // they can for example clear explorer selection.
359
    // See bug 5048028.
360
    /** 
361
     * Add a drag source listener.
362
     * @param dsl The drag source listener to be added
363
     */
364
    public void addDragSourceListener(DragSourceListener dsl) {
365
        if (!dragActive) {
366
            setDragSource(true);
367
        }
368
        dragSupport.addDragSourceListener(dsl);
369
    }
370
    /** 
371
     * Remove a drag source listener.
372
     * @param dsl The drag source listener to be removed
373
     */
374
    public void removeDragSourceListener(DragSourceListener dsl) {
375
        if (dragSupport != null) {
376
            dragSupport.removeDragSourceListener(dsl);
377
        }
378
    }
379
    // </>
380
 
381
382
    
383
353
    /** Drop support is enabled by default.
384
    /** Drop support is enabled by default.
354
    * @return true if dropping to the view is enabled, false
385
    * @return true if dropping to the view is enabled, false
355
    * otherwise<br>
386
    * otherwise<br>
(-)openide/src/org/openide/text/CloneableEditor.java (+15 lines)
Lines 198-203 Link Here
198
        pane.setEditorKit (support.kit ());
198
        pane.setEditorKit (support.kit ());
199
199
200
        pane.setDocument (doc);
200
        pane.setDocument (doc);
201
// <> Temporary put back (to fix a bug),
202
// when is figured out another method to hack this (at least from editor module).
203
// Modified for  by Tor: install drag & drop handlers on the editor
204
        // Enable drag & drop
205
//        pane.setDragEnabled(true); // seems not necessary
206
        pane.setTransferHandler(new TextTransferHandler());
207
        if (pane.getDropTarget() != null) {
208
            TextDropTargetListener dropTargetListener = new TextDropTargetListener();
209
            try {
210
                pane.getDropTarget().addDropTargetListener(dropTargetListener);
211
            } catch(java.util.TooManyListenersException tmle) {
212
                ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, tmle);
213
            }
214
        }
215
// </>
201
        if (doc instanceof NbDocument.CustomEditor) {
216
        if (doc instanceof NbDocument.CustomEditor) {
202
            NbDocument.CustomEditor ce = (NbDocument.CustomEditor)doc;
217
            NbDocument.CustomEditor ce = (NbDocument.CustomEditor)doc;
203
            customComponent = ce.createEditor(pane);
218
            customComponent = ce.createEditor(pane);
(-)openide/src/org/openide/text/TextDropTargetListener.java (+326 lines)
Line 0 Link Here
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.openide.text;
15
16
import java.awt.*;
17
import java.awt.event.*;
18
import java.awt.font.*;
19
import java.awt.datatransfer.*;
20
import java.awt.dnd.*;
21
import java.beans.*;
22
import java.io.*;
23
import java.net.*;
24
import javax.swing.*;
25
import javax.swing.plaf.*;
26
import javax.swing.text.*;
27
import javax.swing.event.*;
28
import javax.swing.border.Border;
29
import javax.swing.plaf.UIResource;
30
import javax.swing.Timer;
31
32
/* A drop listener for text components. This seems necessary because
33
 * the NetBeans editor doesn't inherit from the Swing plaf.basic package,
34
 * so it's missing a bunch of drag & drop behavior.
35
 * In particular, this class is responsible for moving the caret
36
 * to the nearest drag location in the document, as well as autoscrolling
37
 * the view when necesary.
38
 * <p>
39
 * This code is basically a merged version of text-related code in
40
 * javax.swing.plaf.basic: BasicTextUI's TextDropTargetListener and
41
 * its parent class, BasickDropTargetListener.
42
 * <p>
43
 * I had to copy it since it has package protected access in
44
 * javax.swing.plaf.basic.
45
 *
46
 * <p>
47
 * @author Tor Norbye
48
 */
49
class TextDropTargetListener implements DropTargetListener,
50
                                               UIResource, ActionListener {
51
52
    // The first code is the general BasicDropTargetListener code; at the
53
    // end you'll find the TextDropTargetListener code
54
55
    
56
    /**
57
     * construct a DropTargetAutoScroller
58
     * <P>
59
     * @param c the <code>Component</code>
60
     * @param p the <code>Point</code>
61
     */
62
    protected TextDropTargetListener() {
63
    }
64
65
66
    /**
67
     * Update the geometry of the autoscroll region.  The geometry is
68
     * maintained as a pair of rectangles.  The region can cause
69
     * a scroll if the pointer sits inside it for the duration of the
70
     * timer.  The region that causes the timer countdown is the area
71
     * between the two rectangles.
72
     * <p>
73
     * This is implemented to use the visible area of the component 
74
     * as the outer rectangle and the insets are based upon the
75
     * Scrollable information (if any).  If the Scrollable is
76
     * scrollable along an axis, the step increment is used as
77
     * the autoscroll inset.  If the component is not scrollable,
78
     * the insets will be zero (i.e. autoscroll will not happen).
79
     */
80
    void updateAutoscrollRegion(JComponent c) {
81
	// compute the outer
82
	Rectangle visible = c.getVisibleRect();
83
	outer.reshape(visible.x, visible.y, visible.width, visible.height);
84
85
	// compute the insets
86
	// TBD - the thing with the scrollable
87
	Insets i = new Insets(0, 0, 0, 0);
88
	if (c instanceof Scrollable) {
89
	    Scrollable s = (Scrollable) c;
90
	    i.left = s.getScrollableUnitIncrement(visible, SwingConstants.HORIZONTAL, 1);
91
	    i.top = s.getScrollableUnitIncrement(visible, SwingConstants.VERTICAL, 1);
92
	    i.right = s.getScrollableUnitIncrement(visible, SwingConstants.HORIZONTAL, -1);
93
	    i.bottom = s.getScrollableUnitIncrement(visible, SwingConstants.VERTICAL, -1);
94
	}
95
96
	// set the inner from the insets
97
	inner.reshape(visible.x + i.left, 
98
		      visible.y + i.top,
99
		      visible.width - (i.left + i.right),
100
		      visible.height - (i.top  + i.bottom));
101
    }
102
103
    /**
104
     * Perform an autoscroll operation.  This is implemented to scroll by the
105
     * unit increment of the Scrollable using scrollRectToVisible.  If the 
106
     * cursor is in a corner of the autoscroll region, more than one axis will
107
     * scroll.
108
     */
109
    void autoscroll(JComponent c, Point pos) {
110
	if (c instanceof Scrollable) {
111
	    Scrollable s = (Scrollable) c;
112
	    if (pos.y < inner.y) {
113
		// scroll top downward
114
		int dy = s.getScrollableUnitIncrement(outer, SwingConstants.VERTICAL, 1);
115
		Rectangle r = new Rectangle(inner.x, outer.y - dy, inner.width, dy);
116
		c.scrollRectToVisible(r);
117
	    } else if (pos.y > (inner.y + inner.height)) {
118
		// scroll bottom upward
119
		int dy = s.getScrollableUnitIncrement(outer, SwingConstants.VERTICAL, -1);
120
		Rectangle r = new Rectangle(inner.x, outer.y + outer.height, inner.width, dy);
121
		c.scrollRectToVisible(r);
122
	    }
123
124
	    if (pos.x < inner.x) {
125
		// scroll left side to the right
126
		int dx = s.getScrollableUnitIncrement(outer, SwingConstants.HORIZONTAL, 1);
127
		Rectangle r = new Rectangle(outer.x - dx, inner.y, dx, inner.height);
128
		c.scrollRectToVisible(r);
129
	    } else if (pos.x > (inner.x + inner.width)) {
130
		// scroll right side to the left
131
		int dx = s.getScrollableUnitIncrement(outer, SwingConstants.HORIZONTAL, -1);
132
		Rectangle r = new Rectangle(outer.x + outer.width, inner.y, dx, inner.height);
133
		c.scrollRectToVisible(r);
134
	    }
135
	}
136
    }
137
138
    /**
139
     * Initializes the internal properties if they haven't been already
140
     * inited. This is done lazily to avoid loading of desktop properties.
141
     */
142
    private void initPropertiesIfNecessary() {
143
        if (timer == null) {
144
            Toolkit t  = Toolkit.getDefaultToolkit();
145
            Integer    initial  = new Integer(100);
146
            Integer    interval = new Integer(100);
147
148
            try {
149
                initial = (Integer)t.getDesktopProperty(
150
                                                        "DnD.Autoscroll.initialDelay");
151
            } catch (Exception e) {
152
                // ignore
153
            }
154
            try {
155
                interval = (Integer)t.getDesktopProperty(
156
                                                         "DnD.Autoscroll.interval");
157
            } catch (Exception e) {
158
                // ignore
159
            }
160
            timer = new Timer(interval.intValue(), this);
161
162
            timer.setCoalesce(true);
163
            timer.setInitialDelay(initial.intValue());
164
165
            try {
166
                hysteresis = ((Integer)t.getDesktopProperty(
167
                                                            "DnD.Autoscroll.cursorHysteresis")).intValue();
168
            } catch (Exception e) {
169
                // ignore
170
            }
171
        }
172
    }
173
174
    static JComponent getComponent(DropTargetEvent e) {
175
	DropTargetContext context = e.getDropTargetContext();
176
	return (JComponent) context.getComponent();
177
    }
178
179
    // --- ActionListener methods --------------------------------------
180
181
    /**
182
     * The timer fired, perform autoscroll if the pointer is within the
183
     * autoscroll region.
184
     * <P>
185
     * @param e the <code>ActionEvent</code>
186
     */
187
    public synchronized void actionPerformed(ActionEvent e) {
188
	updateAutoscrollRegion(component);
189
	if (outer.contains(lastPosition) && !inner.contains(lastPosition)) {
190
	    autoscroll(component, lastPosition);
191
	}
192
    }
193
194
    // --- DropTargetListener methods -----------------------------------
195
196
    public void dragEnter(DropTargetDragEvent e) {
197
	component = getComponent(e);
198
	TransferHandler th = component.getTransferHandler();
199
	canImport = th.canImport(component, e.getCurrentDataFlavors());
200
	if (canImport) {
201
	    saveComponentState(component);
202
	    lastPosition = e.getLocation();
203
	    updateAutoscrollRegion(component);
204
            initPropertiesIfNecessary();
205
	}
206
    }
207
208
    public void dragOver(DropTargetDragEvent e) {
209
	if (canImport) {
210
	    Point p = e.getLocation();
211
	    updateInsertionLocation(component, p);
212
213
214
	    // check autoscroll
215
	    synchronized(this) {
216
		if (Math.abs(p.x - lastPosition.x) > hysteresis ||
217
		    Math.abs(p.y - lastPosition.y) > hysteresis) {
218
		    // no autoscroll 
219
		    if (timer.isRunning()) timer.stop();
220
		} else {
221
		    if (!timer.isRunning()) timer.start();
222
		}
223
		lastPosition = p;
224
	    }
225
	}
226
    }
227
228
    public void dragExit(DropTargetEvent e) {
229
        if (canImport) {
230
            restoreComponentState(component);
231
        }
232
        cleanup();
233
    }
234
235
    public void drop(DropTargetDropEvent e) {
236
        if (canImport) {
237
            restoreComponentStateForDrop(component);
238
        }
239
        cleanup();
240
    }
241
242
    public void dropActionChanged(DropTargetDragEvent e) {
243
    }
244
245
    /**
246
     * Cleans up internal state after the drop has finished (either succeeded
247
     * or failed).
248
     */
249
    private void cleanup() {
250
        if (timer != null) {
251
            timer.stop();
252
        }
253
	component = null;
254
	lastPosition = null;
255
    }
256
257
    // --- fields --------------------------------------------------
258
	
259
    private Timer timer;
260
    private Point lastPosition;
261
    private Rectangle  outer = new Rectangle();
262
    private Rectangle  inner = new Rectangle();
263
    private int	   hysteresis = 10;
264
    private boolean canImport;
265
266
    /** 
267
     * The current component. The value is cached from the drop events and used
268
     * by the timer. When a drag exits or a drop occurs, this value is cleared.
269
     */
270
    private JComponent component;
271
272
273
274
275
    // TEXT DROP LISTENER SPECIFIC STUFF - from BasicTextUI's
276
    // TextDropListener
277
278
        
279
    /**
280
     * called to save the state of a component in case it needs to
281
     * be restored because a drop is not performed.
282
     */
283
    protected void saveComponentState(JComponent comp) {
284
        JTextComponent c = (JTextComponent) comp;
285
        Caret caret = c.getCaret();
286
        dot = caret.getDot();
287
        mark = caret.getMark();
288
        visible = caret.isVisible();
289
        caret.setVisible(true);
290
    }
291
292
    /**
293
     * called to restore the state of a component 
294
     * because a drop was not performed.
295
     */
296
    protected void restoreComponentState(JComponent comp) {
297
        JTextComponent c = (JTextComponent) comp;
298
        Caret caret = c.getCaret();
299
        caret.setDot(mark);
300
        caret.moveDot(dot);
301
        caret.setVisible(visible);
302
    }
303
304
    /**
305
     * called to restore the state of a component
306
     * because a drop was performed.
307
     */
308
    protected void restoreComponentStateForDrop(JComponent comp) {
309
        JTextComponent c = (JTextComponent) comp;
310
        Caret caret = c.getCaret();
311
        caret.setVisible(visible);
312
    }
313
314
    /**
315
     * called to set the insertion location to match the current
316
     * mouse pointer coordinates.
317
     */
318
    protected void updateInsertionLocation(JComponent comp, Point p) {
319
        JTextComponent c = (JTextComponent) comp;
320
        c.setCaretPosition(c.viewToModel(p));
321
    }
322
323
    int dot;
324
    int mark;
325
    boolean visible;
326
}
(-)openide/src/org/openide/text/TextTransferHandler.java (+748 lines)
Line 0 Link Here
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.openide.text;
15
16
import java.awt.*;
17
import java.awt.event.*;
18
import java.awt.font.*;
19
import java.awt.datatransfer.*;
20
import java.awt.dnd.*;
21
import java.beans.*;
22
import java.io.*;
23
import java.net.*;
24
import javax.swing.*;
25
import javax.swing.plaf.*;
26
import javax.swing.text.*;
27
import javax.swing.event.*;
28
import javax.swing.border.Border;
29
import javax.swing.plaf.UIResource;
30
import javax.swing.Timer;
31
32
import org.openide.windows.TopComponent;
33
34
35
/* A transfer handler for the editor component. This seems necessary because
36
 * the NetBeans editor doesn't inherit from the Swing plaf.basic package,
37
 * so it's missing a bunch of drag & drop behavior.
38
 * <p>
39
 * This code is basically a merged version of text-related code in
40
 * javax.swing.plaf.basic: BasicTextUI, BasicTransferable, ...
41
 * I had to copy it since it has package protected access in
42
 * javax.swing.plaf.basic.
43
 * <p>
44
 * <b>There is one important difference</b>. In order to allow the DESTINATION
45
 * to decide if the transferable should be moved or copied (e.g. if the
46
 * destination is the same document, move, if it's the clipboard palette,
47
 * copy), there's a global flag that can be set which basically turns off
48
 * moving when a drag is in progress. Yup, this is a bit of a hack, but
49
 * I couldn't find a better way. With Swing, the copy-vs-move decision is
50
 * made when the drag is -started-, and at that point we don't know yet
51
 * where you're going to drop. The docs for TransferHandler exportAsDrag says:
52
 *  <blockquote> action - the transfer action initially requested; this should
53
 *  be a value of either <code>COPY</code> or <code>MOVE</code>;
54
 *  the value may be changed during the course of the drag operation
55
 *  </blockquote>.
56
 * However, it does not say HOW you can change the action, and from looking
57
 * at the code, I suspect it cannot be done, since the action is passed
58
 * to a gesture listener that has private access.
59
 * <p>
60
 * @author Tor Norbye
61
 */
62
63
public class TextTransferHandler extends TransferHandler implements UIResource {
64
65
    /** Flag which is only defined during a drag & drop operation.
66
     * Clients (typically drop zones) can set it to true to indicate
67
     * that the data being dragged should be copied, not moved.
68
     * For example, the clipboard viewer sets this when it handles
69
     * the import. That way, the exportDone method knows not to remove
70
     * the text being placed on the clipboard from the document, since
71
     * text dragging (without modified keys) defaults to moving, not
72
     * copying. And we don't want to disallow copying in getSourceActions,
73
     * since dragging text from one place in the document to another
74
     * SHOULD be moved, not copied. */
75
    public static boolean dontRemove = false;
76
77
    
78
    private JTextComponent exportComp;
79
    private boolean shouldRemove;
80
    private int p0;
81
    private int p1;
82
    
83
    /**
84
     * Try to find a flavor that can be used to import a Transferable.  
85
     * The set of usable flavors are tried in the following order:
86
     * <ol>
87
     *     <li>First, an attempt is made to find a flavor matching the content type
88
     *         of the EditorKit for the component.
89
     *     <li>Second, an attempt to find a text/plain flavor is made.
90
     *     <li>Third, an attempt to find a flavor representing a String reference
91
     *         in the same VM is made.
92
     *     <li>Lastly, DataFlavor.stringFlavor is searched for.
93
     * </ol>
94
     */
95
    protected DataFlavor getImportFlavor(DataFlavor[] flavors, JTextComponent c) {
96
        DataFlavor plainFlavor = null;
97
        DataFlavor refFlavor = null;
98
        DataFlavor stringFlavor = null;
99
        if (c instanceof JEditorPane) {
100
            for (int i = 0; i < flavors.length; i++) {
101
                String mime = flavors[i].getMimeType();
102
                if (mime.startsWith(((JEditorPane)c).getEditorKit().getContentType())) {
103
                    return flavors[i];
104
                } else if (plainFlavor == null && mime.startsWith("text/plain")) {
105
                    plainFlavor = flavors[i];
106
                } else if (refFlavor == null && mime.startsWith("application/x-java-jvm-local-objectref")
107
                           && flavors[i].getRepresentationClass() == java.lang.String.class) {
108
                    refFlavor = flavors[i];
109
                } else if (stringFlavor == null && flavors[i].equals(DataFlavor.stringFlavor)) {
110
                    stringFlavor = flavors[i];
111
                }
112
            }
113
            if (plainFlavor != null) {
114
                return plainFlavor;
115
            } else if (refFlavor != null) {
116
                return refFlavor;
117
            } else if (stringFlavor != null) {
118
                return stringFlavor;
119
            }
120
            return null;
121
        }
122
            
123
        for (int i = 0; i < flavors.length; i++) {
124
            String mime = flavors[i].getMimeType();
125
            if (mime.startsWith("text/plain")) {
126
                return flavors[i];
127
            } else if (refFlavor == null && mime.startsWith("application/x-java-jvm-local-objectref")
128
                       && flavors[i].getRepresentationClass() == java.lang.String.class) {
129
                refFlavor = flavors[i];
130
            } else if (stringFlavor == null && flavors[i].equals(DataFlavor.stringFlavor)) {
131
                stringFlavor = flavors[i];
132
            }
133
        }
134
        if (refFlavor != null) {
135
            return refFlavor;
136
        } else if (stringFlavor != null) {
137
            return stringFlavor;
138
        }
139
        return null;
140
    }
141
142
    /**
143
     * Import the given stream data into the text component.
144
     */
145
    protected void handleReaderImport(Reader in, JTextComponent c, boolean useRead)
146
        throws BadLocationException, IOException {
147
        if (useRead) {
148
            int startPosition = c.getSelectionStart();
149
            int endPosition = c.getSelectionEnd();
150
            int length = endPosition - startPosition;
151
            EditorKit kit = c.getUI().getEditorKit(c);
152
            Document doc = c.getDocument();
153
            if (length > 0) {
154
                doc.remove(startPosition, length);
155
            }
156
            kit.read(in, doc, startPosition);
157
        } else {
158
            char[] buff = new char[1024];
159
            int nch;
160
            boolean lastWasCR = false;
161
            int last;
162
            StringBuffer sbuff = null;
163
                
164
            // Read in a block at a time, mapping \r\n to \n, as well as single
165
            // \r to \n.
166
            while ((nch = in.read(buff, 0, buff.length)) != -1) {
167
                if (sbuff == null) {
168
                    sbuff = new StringBuffer(nch);
169
                }
170
                last = 0;
171
                for(int counter = 0; counter < nch; counter++) {
172
                    switch(buff[counter]) {
173
                    case '\r':
174
                        if (lastWasCR) {
175
                            if (counter == 0) {
176
                                sbuff.append('\n');
177
                            } else {
178
                                buff[counter - 1] = '\n';
179
                            }
180
                        } else {
181
                            lastWasCR = true;
182
                        }
183
                        break;
184
                    case '\n':
185
                        if (lastWasCR) {
186
                            if (counter > (last + 1)) {
187
                                sbuff.append(buff, last, counter - last - 1);
188
                            }
189
                            // else nothing to do, can skip \r, next write will
190
                            // write \n
191
                            lastWasCR = false;
192
                            last = counter;
193
                        }
194
                        break;
195
                    default:
196
                        if (lastWasCR) {
197
                            if (counter == 0) {
198
                                sbuff.append('\n');
199
                            } else {
200
                                buff[counter - 1] = '\n';
201
                            }
202
                            lastWasCR = false;
203
                        }
204
                        break;
205
                    }
206
                }
207
                if (last < nch) {
208
                    if (lastWasCR) {
209
                        if (last < (nch - 1)) {
210
                            sbuff.append(buff, last, nch - last - 1);
211
                        }
212
                    } else {
213
                        sbuff.append(buff, last, nch - last);
214
                    }
215
                }
216
            }
217
            if (lastWasCR) {
218
                sbuff.append('\n');
219
            }
220
            c.replaceSelection(sbuff != null ? sbuff.toString() : "");
221
        }
222
    }
223
224
    // --- TransferHandler methods ------------------------------------
225
226
    /**
227
     * This is the type of transfer actions supported by the source.  Some models are 
228
     * not mutable, so a transfer operation of COPY only should
229
     * be advertised in that case.
230
     * 
231
     * @param c  The component holding the data to be transfered.  This
232
     *  argument is provided to enable sharing of TransferHandlers by
233
     *  multiple components.
234
     * @return  This is implemented to return NONE if the component is a JPasswordField
235
     *  since exporting data via user gestures is not allowed.  If the text component is
236
     *  editable, COPY_OR_MOVE is returned, otherwise just COPY is allowed.
237
     */
238
    public int getSourceActions(JComponent c) {
239
        int actions = NONE;
240
        if (! (c instanceof JPasswordField)) {
241
            if (((JTextComponent)c).isEditable()) {
242
                actions = COPY_OR_MOVE;
243
            } else {
244
                actions = COPY;
245
            }
246
        }
247
        return actions;
248
    }
249
250
    /**
251
     * Create a Transferable to use as the source for a data transfer.
252
     *
253
     * @param comp  The component holding the data to be transfered.  This
254
     *  argument is provided to enable sharing of TransferHandlers by
255
     *  multiple components.
256
     * @return  The representation of the data to be transfered. 
257
     *  
258
     */
259
    protected Transferable createTransferable(JComponent comp) {
260
        exportComp = (JTextComponent)comp;
261
        shouldRemove = true;
262
        dontRemove = false;
263
        p0 = exportComp.getSelectionStart();
264
        p1 = exportComp.getSelectionEnd();
265
        return (p0 != p1) ? (new TextTransferable(exportComp, p0, p1)) : null;
266
    }
267
268
    /**
269
     * This method is called after data has been exported.  This
270
     * method should remove the data that was transfered if the action
271
     * was MOVE.
272
     *
273
     * @param source The component that was the source of the data.
274
     * @param data   The data that was transferred or possibly null
275
     *               if the action is <code>NONE</code>.
276
     * @param action The actual action that was performed.  
277
     */
278
    protected void exportDone(JComponent source, Transferable data, int action) {
279
        // only remove the text if shouldRemove has not been set to
280
        // false by importData and only if the action is a move
281
        if (shouldRemove && action == MOVE) {
282
            TextTransferable t = (TextTransferable)data;
283
            if (!dontRemove) {
284
                t.removeText();
285
            }
286
        }
287
            
288
        exportComp = null;
289
    }
290
291
    /**
292
     * This method causes a transfer to a component from a clipboard or a 
293
     * DND drop operation.  The Transferable represents the data to be
294
     * imported into the component.  
295
     *
296
     * @param comp  The component to receive the transfer.  This
297
     *  argument is provided to enable sharing of TransferHandlers by
298
     *  multiple components.
299
     * @param t     The data to import
300
     * @return  true if the data was inserted into the component, false otherwise.
301
     */
302
    public boolean importData(JComponent comp, Transferable t) {
303
        JTextComponent c = (JTextComponent)comp;
304
305
        // if we are importing to the same component that we exported from
306
        // then don't actually do anything if the drop location is inside
307
        // the drag location and set shouldRemove to false so that exportDone
308
        // knows not to remove any data
309
        if (c == exportComp && c.getCaretPosition() >= p0 && c.getCaretPosition() <= p1) {
310
            shouldRemove = false;
311
            return true;
312
        }
313
314
        boolean imported = false;
315
        DataFlavor importFlavor = getImportFlavor(t.getTransferDataFlavors(), c);
316
        if (importFlavor != null) {
317
            try {
318
                boolean useRead = false;
319
                if (comp instanceof JEditorPane) {
320
                    JEditorPane ep = (JEditorPane)comp;
321
                    if (!ep.getContentType().startsWith("text/plain") &&
322
                        importFlavor.getMimeType().startsWith(ep.getContentType())) {
323
                        useRead = true;
324
                        
325
                    }
326
327
                    try {
328
                        // XXX Hacking the code clips transfer.
329
                        Runnable r = (Runnable)t.getTransferData(CodeClipTransferData.CODE_CLIP_DATA_FLAVOR);
330
                        if(r != null) {
331
                            r.run();
332
                        }
333
                    } catch(Exception e) {
334
//                        e.printStackTrace();
335
                    }
336
                }
337
                Reader r = importFlavor.getReaderForText(t);
338
                handleReaderImport(r, c, useRead);
339
                imported = true;
340
                
341
                // #4946925 Trying to put the activation to the drop target.
342
                TopComponent tc = (TopComponent)SwingUtilities.getAncestorOfClass(TopComponent.class, c);
343
                if(tc != null) {
344
                    tc.requestActive();
345
                }
346
            } catch (UnsupportedFlavorException ufe) {
347
            } catch (BadLocationException ble) {
348
            } catch (IOException ioe) {
349
            }
350
        }
351
        return imported;
352
    }
353
354
    /**
355
     * This method indicates if a component would accept an import of the given
356
     * set of data flavors prior to actually attempting to import it. 
357
     *
358
     * @param comp  The component to receive the transfer.  This
359
     *  argument is provided to enable sharing of TransferHandlers by
360
     *  multiple components.
361
     * @param flavors  The data formats available
362
     * @return  true if the data can be inserted into the component, false otherwise.
363
     */
364
    public boolean canImport(JComponent comp, DataFlavor[] flavors) {
365
        JTextComponent c = (JTextComponent)comp;
366
        if (!(c.isEditable() && c.isEnabled())) {
367
            return false;
368
        }
369
        return (getImportFlavor(flavors, c) != null);
370
    }
371
372
    /**
373
     * A possible implementation of the Transferable interface
374
     * for text components.  For a JEditorPane with a rich set
375
     * of EditorKit implementations, conversions could be made
376
     * giving a wider set of formats.  This is implemented to
377
     * offer up only the active content type and text/plain
378
     * (if that is not the active format) since that can be
379
     * extracted from other formats.
380
     */
381
    static class TextTransferable implements Transferable, UIResource {
382
            
383
        // begin copied from BasicTransferable
384
        protected String plainData = null;
385
        protected String htmlData = null;
386
387
        private static DataFlavor[] htmlFlavors;
388
        private static DataFlavor[] stringFlavors;
389
        private static DataFlavor[] plainFlavors;
390
391
        static {
392
            try {
393
                htmlFlavors = new DataFlavor[3];
394
                htmlFlavors[0] = new DataFlavor("text/html;class=java.lang.String");
395
                htmlFlavors[1] = new DataFlavor("text/html;class=java.io.Reader");
396
                htmlFlavors[2] = new DataFlavor("text/html;charset=unicode;class=java.io.InputStream");
397
398
                plainFlavors = new DataFlavor[3];
399
                plainFlavors[0] = new DataFlavor("text/plain;class=java.lang.String");
400
                plainFlavors[1] = new DataFlavor("text/plain;class=java.io.Reader");
401
                plainFlavors[2] = new DataFlavor("text/plain;charset=unicode;class=java.io.InputStream");
402
403
                stringFlavors = new DataFlavor[2];
404
                stringFlavors[0] = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType+";class=java.lang.String");
405
                stringFlavors[1] = DataFlavor.stringFlavor;
406
 
407
            } catch (ClassNotFoundException cle) {
408
                System.err.println("error initializing javax.swing.plaf.basic.BasicTranserable");
409
            }
410
        }
411
    
412
        /**
413
         * Returns an array of DataFlavor objects indicating the flavors the data 
414
         * can be provided in.  The array should be ordered according to preference
415
         * for providing the data (from most richly descriptive to least descriptive).
416
         * @return an array of data flavors in which this data can be transferred
417
         */
418
        public DataFlavor[] getTransferDataFlavors() {
419
            DataFlavor[] richerFlavors = getRicherFlavors();
420
            int nRicher = (richerFlavors != null) ? richerFlavors.length : 0;
421
            int nHTML = (isHTMLSupported()) ? htmlFlavors.length : 0;
422
            int nPlain = (isPlainSupported()) ? plainFlavors.length: 0;
423
            int nString = (isPlainSupported()) ? stringFlavors.length : 0;
424
            int nFlavors = nRicher + nHTML + nPlain + nString;
425
            DataFlavor[] flavors = new DataFlavor[nFlavors];
426
	
427
            // fill in the array
428
            int nDone = 0;
429
            if (nRicher > 0) {
430
                System.arraycopy(richerFlavors, 0, flavors, nDone, nRicher);
431
                nDone += nRicher;
432
            }
433
            if (nHTML > 0) {
434
                System.arraycopy(htmlFlavors, 0, flavors, nDone, nHTML);
435
                nDone += nHTML;
436
            }
437
            if (nPlain > 0) {
438
                System.arraycopy(plainFlavors, 0, flavors, nDone, nPlain);
439
                nDone += nPlain;
440
            }
441
            if (nString > 0) {
442
                System.arraycopy(stringFlavors, 0, flavors, nDone, nString);
443
                nDone += nString;
444
            }
445
            return flavors;
446
        }
447
448
        /**
449
         * Returns whether or not the specified data flavor is supported for
450
         * this object.
451
         * @param flavor the requested flavor for the data
452
         * @return boolean indicating whether or not the data flavor is supported
453
         */
454
        public boolean isDataFlavorSupported(DataFlavor flavor) {
455
            DataFlavor[] flavors = getTransferDataFlavors();
456
            for (int i = 0; i < flavors.length; i++) {
457
                if (flavors[i].equals(flavor)) {
458
                    return true;
459
                }
460
            }
461
            return false;
462
        }
463
464
        /**
465
         * Returns an object which represents the data to be transferred.  The class 
466
         * of the object returned is defined by the representation class of the flavor.
467
         *
468
         * @param flavor the requested flavor for the data
469
         * @see DataFlavor#getRepresentationClass
470
         * @exception IOException                if the data is no longer available
471
         *              in the requested flavor.
472
         * @exception UnsupportedFlavorException if the requested data flavor is
473
         *              not supported.
474
         */
475
        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
476
            DataFlavor[] richerFlavors = getRicherFlavors();
477
            if (isRicherFlavor(flavor)) {
478
                return getRicherData(flavor);
479
            } else if (isHTMLFlavor(flavor)) {
480
                String data = getHTMLData();
481
                data = (data == null) ? "" : data;
482
                if (String.class.equals(flavor.getRepresentationClass())) {
483
                    return data;
484
                } else if (Reader.class.equals(flavor.getRepresentationClass())) {
485
                    return new StringReader(data);
486
                } else if (InputStream.class.equals(flavor.getRepresentationClass())) {
487
                    return new StringBufferInputStream(data);
488
                }
489
                // fall through to unsupported
490
            } else if (isPlainFlavor(flavor)) {
491
                String data = getPlainData();
492
                data = (data == null) ? "" : data;
493
                if (String.class.equals(flavor.getRepresentationClass())) {
494
                    return data;
495
                } else if (Reader.class.equals(flavor.getRepresentationClass())) {
496
                    return new StringReader(data);
497
                } else if (InputStream.class.equals(flavor.getRepresentationClass())) {
498
                    return new StringBufferInputStream(data);
499
                }
500
                // fall through to unsupported
501
502
            } else if (isStringFlavor(flavor)) {
503
                String data = getPlainData();
504
                data = (data == null) ? "" : data;
505
                return data;
506
            }
507
            throw new UnsupportedFlavorException(flavor);
508
        }
509
510
        // --- richer subclass flavors ----------------------------------------------
511
512
        protected boolean isRicherFlavor(DataFlavor flavor) {
513
            DataFlavor[] richerFlavors = getRicherFlavors();
514
            int nFlavors = (richerFlavors != null) ? richerFlavors.length : 0;
515
            for (int i = 0; i < nFlavors; i++) {
516
                if (richerFlavors[i].equals(flavor)) {
517
                    return true;
518
                }
519
            }
520
            return false;
521
        }
522
	
523
        // --- html flavors ----------------------------------------------------------
524
525
        /**
526
         * Returns whether or not the specified data flavor is an HTML flavor that
527
         * is supported.
528
         * @param flavor the requested flavor for the data
529
         * @return boolean indicating whether or not the data flavor is supported
530
         */
531
        protected boolean isHTMLFlavor(DataFlavor flavor) {
532
            DataFlavor[] flavors = htmlFlavors;
533
            for (int i = 0; i < flavors.length; i++) {
534
                if (flavors[i].equals(flavor)) {
535
                    return true;
536
                }
537
            }
538
            return false;
539
        }
540
541
        /**
542
         * Should the HTML flavors be offered?  If so, the method
543
         * getHTMLData should be implemented to provide something reasonable.
544
         */
545
        protected boolean isHTMLSupported() {
546
            return htmlData != null;
547
        }
548
549
        /**
550
         * Fetch the data in a text/html format
551
         */
552
        protected String getHTMLData() {
553
            return htmlData;
554
        }
555
556
        // --- plain text flavors ----------------------------------------------------
557
558
        /**
559
         * Returns whether or not the specified data flavor is an plain flavor that
560
         * is supported.
561
         * @param flavor the requested flavor for the data
562
         * @return boolean indicating whether or not the data flavor is supported
563
         */
564
        protected boolean isPlainFlavor(DataFlavor flavor) {
565
            DataFlavor[] flavors = plainFlavors;
566
            for (int i = 0; i < flavors.length; i++) {
567
                if (flavors[i].equals(flavor)) {
568
                    return true;
569
                }
570
            }
571
            return false;
572
        }
573
574
        /**
575
         * Should the plain text flavors be offered?  If so, the method
576
         * getPlainData should be implemented to provide something reasonable.
577
         */
578
        protected boolean isPlainSupported() {
579
            return plainData != null;
580
        }
581
582
        /**
583
         * Fetch the data in a text/plain format.
584
         */
585
        protected String getPlainData() {
586
            return plainData;
587
        }
588
589
        // --- string flavorss --------------------------------------------------------
590
591
        /**
592
         * Returns whether or not the specified data flavor is a String flavor that
593
         * is supported.
594
         * @param flavor the requested flavor for the data	
595
         * @return boolean indicating whether or not the data flavor is supported
596
         */
597
        protected boolean isStringFlavor(DataFlavor flavor) {
598
            DataFlavor[] flavors = stringFlavors;
599
            for (int i = 0; i < flavors.length; i++) {
600
                if (flavors[i].equals(flavor)) {
601
                    return true;
602
                }
603
            }
604
            return false;
605
        }
606
607
        // end copied from BasicTransferable
608
609
610
        TextTransferable(JTextComponent c, int start, int end) {
611
            this.c = c;
612
                
613
            Document doc = c.getDocument();
614
615
            try {
616
                p0 = doc.createPosition(start);
617
                p1 = doc.createPosition(end);
618
619
                plainData = c.getSelectedText();
620
621
                if (c instanceof JEditorPane) {
622
                    JEditorPane ep = (JEditorPane)c;
623
                        
624
                    mimeType = ep.getContentType();
625
626
                    if (mimeType.startsWith("text/plain")) {
627
                        return;
628
                    }
629
630
                    StringWriter sw = new StringWriter(p1.getOffset() - p0.getOffset());
631
                    ep.getEditorKit().write(sw, doc, p0.getOffset(), p1.getOffset() - p0.getOffset());
632
                        
633
                    if (mimeType.startsWith("text/html")) {
634
                        htmlData = sw.toString();
635
                    } else {
636
                        richText = sw.toString();
637
                    }
638
                }
639
            } catch (BadLocationException ble) {
640
            } catch (IOException ioe) {
641
            }
642
        }
643
644
        void removeText() {
645
            if ((p0 != null) && (p1 != null) && (p0.getOffset() != p1.getOffset())) {
646
                try {
647
                    Document doc = c.getDocument();
648
                    doc.remove(p0.getOffset(), p1.getOffset() - p0.getOffset());
649
                } catch (BadLocationException e) {
650
                }
651
            }
652
        }
653
654
        // ---- EditorKit other than plain or HTML text -----------------------
655
656
        /** 
657
         * If the EditorKit is not for text/plain or text/html, that format
658
         * is supported through the "richer flavors" part of BasicTransferable.
659
         */
660
        protected DataFlavor[] getRicherFlavors() {
661
            if (richText == null) {
662
                return null;
663
            }
664
665
            try {
666
                DataFlavor[] flavors = new DataFlavor[3];
667
                flavors[0] = new DataFlavor(mimeType + ";class=java.lang.String");
668
                flavors[1] = new DataFlavor(mimeType + ";class=java.io.Reader");
669
                flavors[2] = new DataFlavor(mimeType + ";class=java.io.InputStream;charset=unicode");
670
                return flavors;
671
            } catch (ClassNotFoundException cle) {
672
                // fall through to unsupported (should not happen)
673
            }
674
675
            return null;
676
        }
677
678
        /**
679
         * The only richer format supported is the file list flavor
680
         */
681
        protected Object getRicherData(DataFlavor flavor) throws UnsupportedFlavorException {
682
            if (richText == null) {
683
                return null;
684
            }
685
686
            if (String.class.equals(flavor.getRepresentationClass())) {
687
                return richText;
688
            } else if (Reader.class.equals(flavor.getRepresentationClass())) {
689
                return new StringReader(richText);
690
            } else if (InputStream.class.equals(flavor.getRepresentationClass())) {
691
                return new StringBufferInputStream(richText);
692
            }
693
            throw new UnsupportedFlavorException(flavor);
694
        }
695
696
        Position p0;
697
        Position p1;
698
        String mimeType;
699
        String richText;
700
        JTextComponent c;
701
    }
702
    
703
    // XXX Hack to enable poping up a dialog when DnD of code clip.
704
    public static class CodeClipTransferData extends StringSelection {
705
        
706
        // XXX Fake DataFlavor.. for cheating to retrieve the callback.
707
        public static final DataFlavor CODE_CLIP_DATA_FLAVOR
708
            = new DataFlavor(CodeClipTransferData.class, CodeClipTransferData.class.getName()); // TEMP
709
        
710
        // XXX Callback to provide the popup.
711
        private Runnable callback;
712
        // XXX We need to manipulate the data in this class (the superclass is private).
713
        private String data;
714
        
715
        
716
        public CodeClipTransferData(String data) {
717
            super(data); // Just fake.
718
            this.data = data;
719
        }
720
721
        
722
        public void setCallback(Runnable callback) {
723
            this.callback = callback;
724
        }
725
        
726
        public void resetData(String data) {
727
            this.data = data;
728
        }
729
        
730
        // XXX Overriden to manipulate with our data field and provide the hacking callback.
731
        public Object getTransferData(DataFlavor flavor)
732
        throws UnsupportedFlavorException, IOException {
733
            if(flavor == CODE_CLIP_DATA_FLAVOR) {
734
                return callback;
735
            }
736
            
737
            // JCK Test StringSelection0007: if 'flavor' is null, throw NPE
738
            if (flavor.equals(DataFlavor.stringFlavor)) {
739
                return (Object)data;
740
            } else if (flavor.equals(DataFlavor.plainTextFlavor)) { // deprecated
741
                return new StringReader(data);
742
            } else {
743
                throw new UnsupportedFlavorException(flavor);
744
            }
745
        }
746
747
    }
748
}
(-)editor/libsrc/org/netbeans/editor/BaseCaret.java (-5 / +188 lines)
Lines 35-43 Link Here
35
import java.beans.PropertyChangeListener;
35
import java.beans.PropertyChangeListener;
36
import java.beans.PropertyChangeEvent;
36
import java.beans.PropertyChangeEvent;
37
import java.io.IOException;
37
import java.io.IOException;
38
import javax.swing.Action;
38
// <>
39
import javax.swing.Timer;
39
import javax.swing.*;
40
import javax.swing.SwingUtilities;
40
// </>
41
import javax.swing.text.BadLocationException;
41
import javax.swing.text.BadLocationException;
42
import javax.swing.text.Document;
42
import javax.swing.text.Document;
43
import javax.swing.text.JTextComponent;
43
import javax.swing.text.JTextComponent;
Lines 49-54 Link Here
49
import javax.swing.event.EventListenerList;
49
import javax.swing.event.EventListenerList;
50
import javax.swing.text.AbstractDocument;
50
import javax.swing.text.AbstractDocument;
51
import javax.swing.text.Position;
51
import javax.swing.text.Position;
52
// <>
53
import sun.awt.dnd.SunDragSourceContextPeer;
54
// </>
52
import org.netbeans.api.editor.fold.Fold;
55
import org.netbeans.api.editor.fold.Fold;
53
import org.netbeans.api.editor.fold.FoldHierarchy;
56
import org.netbeans.api.editor.fold.FoldHierarchy;
54
import org.netbeans.api.editor.fold.FoldHierarchyEvent;
57
import org.netbeans.api.editor.fold.FoldHierarchyEvent;
Lines 58-65 Link Here
58
/**
61
/**
59
* Caret implementation
62
* Caret implementation
60
*
63
*
61
* @author Miloslav Metelka
64
* <p>
62
* @version 1.00
65
* Modified for  by Tor: added drag & drop handling in the mouse
66
* listeners: specifically, recognize drag gestures and initiate drags
67
* when recognized. Did this by merging in code from
68
* BasicDragGestureRecognizer.java and BaseTextUI.java's
69
* TextDragGestureRecognizer and modifiying the existing
70
* various mouse-event methods to check for drags before proceeding
71
* with their previous (selection-swiping etc.) stuff.
72
* <p>
73
* There was one problem with that - if you click inside the
74
* selection (to unselect the text), the mouse click is ignored - and
75
* the selection not unselected. This was especially troublesome if
76
* you've Selected All so it's hard to go outside the selection.
77
* So I modified it such that if you release the mouse, when you've
78
* ignored a mouse press (because a drag was possible), the selection
79
* is cleared and the caret moved.
80
* <p>
81
*
82
* @author Miloslav Metelka, Tor Norbye
63
*/
83
*/
64
84
65
public class BaseCaret extends Rectangle implements Caret, FocusListener,
85
public class BaseCaret extends Rectangle implements Caret, FocusListener,
Lines 1112-1118 Link Here
1112
        }
1132
        }
1113
    }
1133
    }
1114
1134
1135
    // <>
1136
    // Add support for dragging within the source editor. You can select
1137
    // text, then drag this text around to a different location in the
1138
    // editor buffer, or even to other windows. In , this lets you
1139
    // drag source text to the palette to create a code clip.
1140
    // The code works by setting up the mouse listeners to recognize a
1141
    // drag gesture then uses the standard Swing mechanism to export
1142
    // a transferable.
1115
    public void mousePressed(MouseEvent evt) {
1143
    public void mousePressed(MouseEvent evt) {
1144
        dndArmedEvent = null;
1145
1146
        MouseEvent e = evt;
1147
	if (isDragPossible(e) && mapDragOperationFromModifiers(e) != TransferHandler.NONE) {
1148
            dndArmedEvent = e;
1149
	    e.consume();
1150
            return;
1151
	}
1152
        setPosition(evt);
1153
    }
1154
1155
    private void setPosition(MouseEvent evt) {
1116
        JTextComponent c = component;
1156
        JTextComponent c = component;
1117
        if (c != null) {
1157
        if (c != null) {
1118
            Utilities.getEditorUI(c).getWordMatch().clear(); // [PENDING] should be done cleanly
1158
            Utilities.getEditorUI(c).getWordMatch().clear(); // [PENDING] should be done cleanly
Lines 1139-1154 Link Here
1139
    }
1179
    }
1140
1180
1141
    public void mouseReleased(MouseEvent evt) {
1181
    public void mouseReleased(MouseEvent evt) {
1182
        // If you click on a selection, but don't drag it, we should
1183
        // treat it as a regular mouse click in the buffer -> move the
1184
        // dot to this point
1185
        if (dndArmedEvent != null) {
1186
            setPosition(dndArmedEvent);
1187
            dndArmedEvent = null;
1188
        }
1142
    }
1189
    }
1143
1190
1144
    public void mouseEntered(MouseEvent evt) {
1191
    public void mouseEntered(MouseEvent evt) {
1192
        //dndArmedEvent = null;
1145
    }
1193
    }
1146
1194
1147
    public void mouseExited(MouseEvent evt) {
1195
    public void mouseExited(MouseEvent evt) {
1196
        //if (dndArmedEvent != null && mapDragOperationFromModifiers(e) == TransferHandler.NONE) {
1197
        //    dndArmedEvent = null;
1198
        //}
1148
    }
1199
    }
1149
1200
1150
    // MouseMotionListener methods
1201
    // MouseMotionListener methods
1151
    public void mouseDragged(MouseEvent evt) {
1202
    public void mouseDragged(MouseEvent evt) {
1203
	if (dndArmedEvent != null) {
1204
            MouseEvent e = evt;
1205
            e.consume();
1206
            
1207
            int action = mapDragOperationFromModifiers(e);
1208
            if (action == TransferHandler.NONE) {
1209
                return;
1210
            }
1211
            
1212
	    int dx = Math.abs(e.getX() - dndArmedEvent.getX());
1213
	    int dy = Math.abs(e.getY() - dndArmedEvent.getY());
1214
            if ((dx > getMotionThreshold()) || (dy > getMotionThreshold())) {
1215
		// start transfer... shouldn't be a click at this point
1216
                JComponent c = getComponent(e);
1217
		TransferHandler th = c.getTransferHandler();
1218
		//th.exportAsDrag(c, dndArmedEvent, action);
1219
		th.exportAsDrag(c, dndArmedEvent, TransferHandler.COPY);
1220
		dndArmedEvent = null;
1221
	    }
1222
            return;
1223
	}
1224
        
1152
        JTextComponent c = component;
1225
        JTextComponent c = component;
1153
        if (SwingUtilities.isLeftMouseButton(evt)) {
1226
        if (SwingUtilities.isLeftMouseButton(evt)) {
1154
            if (c != null) {
1227
            if (c != null) {
Lines 1167-1172 Link Here
1167
    public void mouseMoved(MouseEvent evt) {
1240
    public void mouseMoved(MouseEvent evt) {
1168
    }
1241
    }
1169
1242
1243
1244
1245
    // Drag Gesture related stuff; borrowed from BasicDragGestureRecognizer.java
1246
    // in javax.swing.plaf.basic.  The mouse method stuff is merged into the
1247
    // above mouse handlers, so consult the source.
1248
1249
    private MouseEvent dndArmedEvent = null;
1250
    
1251
    private static int motionThreshold;
1252
    
1253
    private static boolean checkedMotionThreshold = false;
1254
1255
    private static int getMotionThreshold() {
1256
        if (checkedMotionThreshold) {
1257
            return motionThreshold;
1258
        } else {
1259
            checkedMotionThreshold = true;
1260
            try {
1261
                motionThreshold = ((Integer)Toolkit.getDefaultToolkit().getDesktopProperty("DnD.gestureMotionThreshold")).intValue();
1262
            } catch (Exception e) {
1263
                motionThreshold = 5;
1264
            }
1265
        }
1266
        return motionThreshold;
1267
    }
1268
    
1269
    protected int mapDragOperationFromModifiers(MouseEvent e) {
1270
        int mods = e.getModifiersEx();
1271
        
1272
        if ((mods & InputEvent.BUTTON1_DOWN_MASK) != InputEvent.BUTTON1_DOWN_MASK) {
1273
            return TransferHandler.NONE;
1274
        }
1275
1276
        JComponent c = getComponent(e);
1277
        TransferHandler th = c.getTransferHandler();
1278
        return SunDragSourceContextPeer.convertModifiersToDropAction(mods, th.getSourceActions(c)); 
1279
    }
1280
    
1281
    private TransferHandler getTransferHandler(MouseEvent e) {
1282
        JComponent c = getComponent(e);
1283
        return c == null ? null : c.getTransferHandler();
1284
    }
1285
1286
    
1287
    protected JComponent getComponent(MouseEvent e) {
1288
	Object src = e.getSource();
1289
	if (src instanceof JComponent) {
1290
	    JComponent c = (JComponent) src;
1291
	    return c;
1292
	}
1293
	return null;
1294
    }    
1295
1296
    // Copied from BaseTextUI's TextDragGestureRecognizer
1297
    /**
1298
     * Determines if the following are true:
1299
     * <ul>
1300
     * <li>the press event is located over a selection
1301
     * <li>the dragEnabled property is true
1302
     * <li>A TranferHandler is installed
1303
     * </ul>
1304
     * <p>
1305
     * This is implemented to check for a TransferHandler.
1306
     * Subclasses should perform the remaining conditions.
1307
     */
1308
    protected boolean isDragPossible(MouseEvent e) {
1309
        JTextComponent c = (JTextComponent) this.getComponent(e);
1310
        
1311
        // Check if the associated text component has drag enabled:
1312
        //boolean dragEnabled = c.getDragEnabled();
1313
        // However, we'd like the default to be "true" in the whole
1314
        // IDE, since that's how most IDEs work. However, that means
1315
        // that all places in the IDE which create an editor
1316
        // (new JEditorPane()) we'd have to go and call 
1317
        // pane.setDraggable(true). Instead, there's probably no good
1318
        // reason to have inconsistent behavior for different editors
1319
        // in the IDE, so we globally enforce editor draggability.
1320
        // (An alternative would be for the install() method in
1321
        // the UIDelegate to go and set draggable true, giving
1322
        // clients a chance to turn it off after install, but this
1323
        // seems like overkill for something clients ought not to
1324
        // do.)
1325
        boolean dragEnabled = true;
1326
        
1327
        if (dragEnabled) {
1328
            Caret caret = c.getCaret();
1329
            int dot = caret.getDot();
1330
            int mark = caret.getMark();
1331
            if (dot != mark) {
1332
                Point p = new Point(e.getX(), e.getY());
1333
                int pos = c.viewToModel(p);
1334
                
1335
                int p0 = Math.min(dot, mark);
1336
                int p1 = Math.max(dot, mark);
1337
                if ((pos >= p0) && (pos < p1)) {
1338
                    return true;
1339
                }
1340
            }
1341
        }
1342
        return false;
1343
    }
1344
1345
    // End stuff copied from BasicDragGestureRecognizer
1346
1347
    // </>
1348
1349
1350
1351
1352
1170
    // PropertyChangeListener methods
1353
    // PropertyChangeListener methods
1171
    public void propertyChange(PropertyChangeEvent evt) {
1354
    public void propertyChange(PropertyChangeEvent evt) {
1172
        String propName = evt.getPropertyName();
1355
        String propName = evt.getPropertyName();

Return to bug 53439