001: /*
002: * Dispatcher.java
003: *
004: * Copyright (C) 1998-2004 Peter Graves
005: * $Id: Dispatcher.java,v 1.13 2004/09/13 13:48:31 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j;
023:
024: import java.awt.AWTEvent;
025: import java.awt.Cursor;
026: import java.awt.Image;
027: import java.awt.Point;
028: import java.awt.Toolkit;
029: import java.awt.datatransfer.DataFlavor;
030: import java.awt.datatransfer.StringSelection;
031: import java.awt.datatransfer.Transferable;
032: import java.awt.dnd.DnDConstants;
033: import java.awt.dnd.DragGestureEvent;
034: import java.awt.dnd.DragGestureListener;
035: import java.awt.dnd.DragGestureRecognizer;
036: import java.awt.dnd.DragSource;
037: import java.awt.dnd.DragSourceContext;
038: import java.awt.dnd.DragSourceDragEvent;
039: import java.awt.dnd.DragSourceDropEvent;
040: import java.awt.dnd.DragSourceEvent;
041: import java.awt.dnd.DragSourceListener;
042: import java.awt.dnd.DropTargetContext;
043: import java.awt.dnd.DropTargetDragEvent;
044: import java.awt.dnd.DropTargetDropEvent;
045: import java.awt.dnd.DropTargetEvent;
046: import java.awt.dnd.DropTargetListener;
047: import java.awt.event.ActionEvent;
048: import java.awt.event.ActionListener;
049: import java.awt.event.InputEvent;
050: import java.awt.event.KeyEvent;
051: import java.awt.event.KeyListener;
052: import java.awt.event.MouseEvent;
053: import java.awt.event.MouseListener;
054: import java.awt.event.MouseMotionListener;
055: import java.net.URL;
056: import java.util.List;
057: import javax.swing.JPopupMenu;
058: import javax.swing.SwingUtilities;
059: import javax.swing.ToolTipManager;
060: import javax.swing.undo.CompoundEdit;
061:
062: public final class Dispatcher implements Constants, KeyListener,
063: MouseListener, MouseMotionListener, ActionListener,
064: DragGestureListener, DragSourceListener, DropTargetListener {
065: // For IdleThread.run.
066: private static long lastEventMillis = System.currentTimeMillis();
067:
068: // Needed by dropBookmark, gotoBookmark.
069: private AWTEvent lastEvent;
070:
071: private static final boolean DEBUG_KEY_PRESSED = false;
072:
073: private final Editor editor;
074: private final Display display;
075:
076: private Thread eventQueueThread;
077:
078: private boolean ignoreKeyTyped;
079:
080: private int lastKeyEvent;
081:
082: private char charToBeIgnored = '\0';
083:
084: private boolean enabled = true;
085:
086: // Drag/drop.
087: private DragSource dragSource;
088: private static DragSourceContext dragSourceContext;
089: private boolean inDragText;
090: private Region dragTextRegion;
091: private static boolean isLineRegion;
092:
093: // Cursors for drag/drop.
094: private static final int CURSOR_NO = 0;
095: private static final int CURSOR_MOVE = 1;
096: private static final int CURSOR_COPY = 2;
097: private static final Cursor[] cursors = new Cursor[3];
098:
099: public Dispatcher(Editor editor) {
100: this .editor = editor;
101: display = editor.getDisplay();
102:
103: dragSource = DragSource.getDefaultDragSource();
104: DragGestureRecognizer dgr = dragSource
105: .createDefaultDragGestureRecognizer(display,
106: DnDConstants.ACTION_COPY_OR_MOVE, this );
107: dgr.setSourceActions(dgr.getSourceActions()
108: & ~InputEvent.BUTTON3_MASK);
109: }
110:
111: public final AWTEvent getLastEvent() {
112: return lastEvent;
113: }
114:
115: public static synchronized final long getLastEventMillis() {
116: return lastEventMillis;
117: }
118:
119: private static synchronized final void setLastEventMillis(long when) {
120: lastEventMillis = when;
121: }
122:
123: public void setEnabled(boolean enabled) {
124: this .enabled = enabled;
125: }
126:
127: private void dispatch(AWTEvent e) {
128: // Ignore events that don't come from the normal event queue thread.
129: if (eventQueueThread == null)
130: eventQueueThread = Thread.currentThread();
131: else if (Thread.currentThread() != eventQueueThread) {
132: setLastEventMillis(System.currentTimeMillis());
133: return;
134: }
135:
136: lastEvent = e;
137:
138: boolean handled = false;
139:
140: switch (e.getID()) {
141: case KeyEvent.KEY_PRESSED:
142: handled = dispatchKeyPressed((KeyEvent) e);
143: break;
144: case KeyEvent.KEY_TYPED:
145: handled = dispatchKeyTyped((KeyEvent) e);
146: break;
147: case KeyEvent.KEY_RELEASED:
148: break;
149: case MouseEvent.MOUSE_PRESSED:
150: handled = dispatchMousePressed((MouseEvent) e);
151: break;
152: case MouseEvent.MOUSE_DRAGGED:
153: handled = dispatchMouseDragged((MouseEvent) e);
154: break;
155: case ActionEvent.ACTION_PERFORMED:
156: handled = dispatchActionPerformed((ActionEvent) e);
157: break;
158: }
159:
160: if (handled)
161: eventHandled();
162: else
163: setLastEventMillis(System.currentTimeMillis());
164: }
165:
166: public void eventHandled() {
167: final Buffer buffer = editor.getBuffer();
168: if (buffer.needsRenumbering())
169: buffer.renumber();
170:
171: // Update all editors displaying buffer.
172: for (EditorIterator it = new EditorIterator(); it.hasNext();) {
173: Editor ed = it.nextEditor();
174: if (ed == editor) {
175: ed.getDisplay().setCaretVisible(true);
176: ed.updateDisplay();
177: } else if (ed.getBuffer() == buffer) {
178: if (buffer.getModeId() != IMAGE_MODE) {
179: ed.getDisplay().repaintChangedLines();
180: ed.updateScrollBars();
181: }
182: ed.getFrame().repaintStatusBar();
183: }
184: }
185:
186: final int currentCommand = editor.getCurrentCommand();
187: if (editor.getLastCommand() == COMMAND_PASTE)
188: if (currentCommand != COMMAND_PASTE)
189: if (currentCommand != COMMAND_UNDO)
190: Editor.promoteLastPaste();
191:
192: editor.setLastCommand(currentCommand);
193: editor.setCurrentCommand(COMMAND_NOTHING);
194:
195: if (Editor.isLispInitialized())
196: LispAPI.eventHandled();
197:
198: SystemSelection.updateSystemSelection(editor);
199:
200: setLastEventMillis(System.currentTimeMillis());
201: }
202:
203: private boolean dispatchKeyPressed(KeyEvent e) {
204: if (editor.getStatusBar() != null)
205: editor.getStatusBar().setText(null);
206:
207: if (Editor.isMenuSelected) {
208: charToBeIgnored = e.getKeyChar();
209: ignoreKeyTyped = true;
210: return false;
211: }
212:
213: int keycode = e.getKeyCode();
214:
215: // Ignore modifier keystrokes.
216: if (keycode == KeyEvent.VK_SHIFT
217: || keycode == KeyEvent.VK_CONTROL
218: || keycode == KeyEvent.VK_ALT
219: || keycode == KeyEvent.VK_META)
220: return false;
221:
222: int modifiers = e.getModifiers();
223:
224: char c = e.getKeyChar();
225:
226: if (DEBUG_KEY_PRESSED) {
227: Log.debug("keyPressed, keycode = 0x"
228: + Integer.toString(keycode, 16));
229: Log.debug("modifiers = 0x"
230: + Integer.toString(modifiers, 16));
231: Log.debug("character = " + String.valueOf(c));
232: Log.debug("character = 0x" + Integer.toString((int) c, 16));
233: }
234:
235: // Mask off the bits we don't care about (Java 1.4).
236: modifiers &= 0x0f;
237:
238: if (DEBUG_KEY_PRESSED)
239: Log.debug("modifiers = 0x"
240: + Integer.toString(modifiers, 16));
241:
242: boolean handled = editor.handleKeyEvent(c, keycode, modifiers);
243:
244: if (handled) {
245: ignoreKeyTyped = true;
246: e.consume();
247: } else {
248: // If we consume indiscriminately here, Alt F no longer works to
249: // drop the File menu (for example). So we only consume keystrokes
250: // with no modifiers.
251: if (modifiers == 0)
252: e.consume();
253: }
254:
255: return handled;
256: }
257:
258: private boolean dispatchKeyTyped(KeyEvent e) {
259: if (Editor.isMenuSelected)
260: return false;
261:
262: if (ignoreKeyTyped)
263: return false;
264:
265: int modifiers = e.getModifiers();
266:
267: // Mask off the bits we don't care about (Java 1.4).
268: modifiers &= 0x0f;
269:
270: if (modifiers != 0 && modifiers != InputEvent.SHIFT_MASK
271: && modifiers != InputEvent.ALT_GRAPH_MASK)
272: return false;
273:
274: char c = e.getKeyChar();
275:
276: boolean handled = editor.handleKeyEvent(c, 0, 0);
277:
278: Buffer buffer = editor.getBuffer();
279:
280: if (!handled && !buffer.isBusy() && c != 0x1b && c != 0x08
281: && c != charToBeIgnored) {
282: if (c == '\t') {
283: if (Editor.isRecordingMacro())
284: Macro.record(editor, "insertTab");
285: editor.insertTab();
286: } else if (!Character.isISOControl(c)) {
287: if (Editor.isRecordingMacro())
288: Macro.record(editor, c);
289: editor.insertNormalChar(c);
290: }
291: handled = true;
292: }
293:
294: charToBeIgnored = '\0';
295:
296: if (handled)
297: e.consume();
298:
299: // Jun 12 2000 3:06 PM
300: // With IBM 1.3 on Linux, if the user brings up a menu and then
301: // immediately cancels by hitting Escape, the cursor keys don't work
302: // in the edit window. Work around this problem by requesting focus
303: // and making sure the dispatcher is enabled if we see 0x1b here.
304: if (c == 0x1b) {
305: editor.setFocusToDisplay();
306: enabled = true;
307: }
308:
309: return handled;
310: }
311:
312: public void keyPressed(KeyEvent e) {
313: // Force tool tip to be hidden.
314: ToolTipManager.sharedInstance().setEnabled(false);
315: ToolTipManager.sharedInstance().setEnabled(true);
316:
317: if (editor.getFrame().getFocusedComponent() != display)
318: return;
319:
320: editor.ensureActive();
321: Editor.setCurrentEditor(editor);
322:
323: if (enabled) {
324: lastKeyEvent = KeyEvent.KEY_PRESSED;
325: ignoreKeyTyped = false;
326: dispatch(e);
327: }
328: }
329:
330: public void keyReleased(KeyEvent e) {
331: e.consume();
332: if (editor.getFrame().getFocusedComponent() != display)
333: return;
334:
335: if (lastKeyEvent == KeyEvent.KEY_RELEASED) {
336: // Work around bug in Windows VMs that causes a subsequent
337: // KEY_TYPED event after the Alt key is released when the original
338: // keystroke generates an ActionEvent.
339:
340: // If we get two (or more) KEY_RELEASED events in a row, wait
341: // until we see KEY_PRESSED again before paying attention to
342: // KEY_TYPED.
343: if (e.getKeyCode() == KeyEvent.VK_ALT)
344: ignoreKeyTyped = true;
345: } else
346: ignoreKeyTyped = false;
347:
348: lastKeyEvent = KeyEvent.KEY_RELEASED;
349: }
350:
351: public void keyTyped(KeyEvent e) {
352: if (editor.getFrame().getFocusedComponent() != display)
353: return;
354:
355: lastKeyEvent = KeyEvent.KEY_TYPED;
356: dispatch(e);
357: }
358:
359: public void mouseClicked(MouseEvent e) {
360: // Mask off the bits we don't care about (Java 1.4).
361: int modifiers = e.getModifiers() & 0x1f;
362: if (modifiers != InputEvent.BUTTON1_MASK)
363: return;
364: if (editor.getMark() != null && e.getClickCount() == 1) {
365: final Buffer buffer = editor.getBuffer();
366: if (buffer.getBooleanProperty(Property.ENABLE_DRAG_TEXT)) {
367: Region r = new Region(editor);
368: Position pos = display.positionFromPoint(e.getPoint());
369: if (pos.isAfter(r.getBegin())
370: && pos.isBefore(r.getEnd())) {
371: editor.addUndo(SimpleEdit.MOVE);
372: editor.unmark();
373: display.moveCaretToPoint(e.getPoint());
374: if (buffer
375: .getBooleanProperty(Property.RESTRICT_CARET))
376: editor.moveCaretToDotCol();
377: editor.updateDisplay();
378: }
379: }
380: }
381: }
382:
383: private boolean dragTextStarting;
384:
385: public void mousePressed(MouseEvent e) {
386: if (editor.getFocusedComponent() == editor
387: .getLocationBarTextField()) {
388: TextFieldHandler handler = editor.getLocationBarTextField()
389: .getHandler();
390: if (handler instanceof IncrementalFindTextFieldHandler) {
391: handler.enter();
392: } else
393: handler.escape();
394: } else
395: LocationBar.cancelInput();
396: editor.ensureActive();
397: if (editor != Editor.currentEditor()) {
398: Editor oldEditor = Editor.currentEditor();
399: Editor.setCurrentEditor(editor);
400: if (oldEditor.getDot() != null)
401: oldEditor.update(oldEditor.getDotLine());
402: oldEditor.updateDisplay();
403: Frame frame = editor.getFrame();
404: frame.setMenu();
405: frame.setToolbar();
406: Sidebar sidebar = frame.getSidebar();
407: if (sidebar != null)
408: sidebar.setUpdateFlag(SIDEBAR_SET_BUFFER);
409: }
410: int modifiers = e.getModifiers() & 0x1f;
411: JPopupMenu popup = editor.getPopup();
412: if (popup != null) {
413: if (popup.isVisible()) {
414: editor.killPopup();
415: if (modifiers != InputEvent.BUTTON1_MASK)
416: return;
417: }
418: editor.setPopup(null);
419: }
420: if (modifiers == InputEvent.BUTTON1_MASK
421: && editor.getMark() != null) {
422: if (editor.getBuffer().getBooleanProperty(
423: Property.ENABLE_DRAG_TEXT)) {
424: Region r = new Region(editor);
425: if (!r.isColumnRegion()) {
426: Position pos = display.positionFromPoint(e
427: .getPoint());
428: if (pos.isAfter(r.getBegin())
429: && pos.isBefore(r.getEnd())) {
430: dragTextStarting = true;
431: return;
432: }
433: }
434: }
435: }
436: dragTextStarting = false;
437: dispatch(e);
438: }
439:
440: public void mouseReleased(MouseEvent e) {
441: }
442:
443: public void mouseEntered(MouseEvent e) {
444: }
445:
446: public void mouseExited(MouseEvent e) {
447: }
448:
449: private boolean dispatchMousePressed(MouseEvent e) {
450: editor.setFocusToDisplay();
451:
452: enabled = true;
453:
454: if (editor.getStatusBar() != null)
455: editor.getStatusBar().setText(null);
456:
457: if (editor.getModeId() == IMAGE_MODE)
458: return false;
459:
460: final int x = e.getX();
461: final int y = e.getY();
462:
463: // Mask off the bits we don't care about (Java 1.4).
464: int modifiers = e.getModifiers() & 0x1f;
465:
466: final Mode mode = editor.getMode();
467: final Buffer buffer = editor.getBuffer();
468:
469: // Folding.
470: if (x < display.getGutterWidth(buffer)) {
471: Position pos = display.positionFromPoint(x, y);
472: Line next = pos.getLine().next();
473: if (next != null && next.isHidden()) {
474: editor.unfold(next);
475: return true;
476: } else if (modifiers == InputEvent.BUTTON2_MASK) {
477: // Middle button.
478: editor.foldNearLine(pos.getLine());
479: return true;
480: }
481: // else fall through...
482: } else if (modifiers == InputEvent.BUTTON2_MASK) {
483: Position pos = display.positionFromPoint(x, y);
484: if (pos != null
485: && pos.getOffset() < pos.getLine().getIndentation()) {
486: Line next = pos.getLine().next();
487: if (next != null) {
488: if (next.isHidden()) {
489: editor.unfold(next);
490: return true;
491: } else if (next.trim().endsWith("{")) {
492: next = next.next();
493: if (next != null && next.isHidden()) {
494: editor.unfold(next);
495: return true;
496: }
497: }
498: }
499: // Couldn't find a fold to expand.
500: editor.foldNearLine(pos.getLine());
501: return true;
502: }
503: // else fall through...
504: }
505:
506: int keycode = 0;
507: final int clickCount = e.getClickCount();
508: if ((modifiers & InputEvent.BUTTON1_MASK) != 0) {
509: modifiers &= ~InputEvent.BUTTON1_MASK;
510: switch (clickCount) {
511: case 1:
512: keycode = VK_MOUSE_1;
513: break;
514: case 2:
515: keycode = VK_DOUBLE_MOUSE_1;
516: break;
517: }
518: } else if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
519: modifiers &= ~InputEvent.BUTTON2_MASK;
520: switch (clickCount) {
521: case 1:
522: keycode = VK_MOUSE_2;
523: break;
524: case 2:
525: keycode = VK_DOUBLE_MOUSE_2;
526: break;
527: }
528: } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
529: modifiers &= ~InputEvent.BUTTON3_MASK;
530: switch (clickCount) {
531: case 1:
532: keycode = VK_MOUSE_3;
533: break;
534: case 2:
535: keycode = VK_DOUBLE_MOUSE_3;
536: break;
537: }
538: }
539: if (keycode == 0)
540: return false;
541: return editor.handleKeyEvent('\0', keycode, modifiers);
542: }
543:
544: public void mouseDragged(MouseEvent e) {
545: dispatch(e);
546: }
547:
548: public void mouseMoved(MouseEvent e) {
549: final Buffer buffer = editor.getBuffer();
550: final Position pos = display.positionFromPoint(e.getPoint());
551: final String contextString = buffer.getMode()
552: .getMouseMovedContextString(editor, pos);
553: if (contextString != null) {
554: // Context string will be "" rather than null if we should clear
555: // the status text (e.g. web mode).
556: editor.status(contextString);
557: }
558: if (buffer.isBusy())
559: editor.setWaitCursor();
560: else if (e.getX() < Display.getGutterWidth(buffer))
561: editor.setCursor(Cursor
562: .getPredefinedCursor(Cursor.DEFAULT_CURSOR));
563: else
564: editor.setCursor(buffer.getDefaultCursor(pos));
565: }
566:
567: private boolean dispatchMouseDragged(MouseEvent e) {
568: if (editor.getModeId() == IMAGE_MODE)
569: return false;
570: final Position dot = editor.getDot();
571: if (dot == null)
572: return false;
573:
574: // Mask off the bits we don't care about (Java 1.4).
575: final int modifiers = e.getModifiers() & 0x1f;
576:
577: // IBM Windows VM reports modifiers are 0 even when the left button is
578: // down. So instead of looking for button 1 to be down, we verify that
579: // buttons 2 and 3 are NOT down.
580: if ((modifiers & InputEvent.BUTTON2_MASK) != 0)
581: return false;
582: if ((modifiers & InputEvent.BUTTON3_MASK) != 0)
583: return false;
584:
585: if ((modifiers & InputEvent.CTRL_MASK) != 0)
586: return false;
587: if ((modifiers & InputEvent.SHIFT_MASK) != 0)
588: return false;
589:
590: // No drag select with column selections.
591: if (editor.isColumnSelection())
592: return false;
593:
594: // Reaching here, button 1 must be down, or we wouldn't have a mouse
595: // dragged event.
596: if (inDragText)
597: return false;
598:
599: Point point = e.getPoint();
600: if (point.y < 0) {
601: display.windowUp();
602: point.y = 1;
603: } else {
604: int limit = display.getRows() * display.getCharHeight();
605: if (point.y >= limit) {
606: display.windowDown();
607: point.y = limit - 1;
608: }
609: }
610:
611: Position pos = display.positionFromPoint(point);
612: if (pos == null || pos.equals(dot))
613: return false;
614:
615: if (editor.getMark() != null) {
616: if (editor.getBuffer().getBooleanProperty(
617: Property.ENABLE_DRAG_TEXT)) {
618: if (dragTextStarting)
619: return false;
620: }
621: }
622:
623: if (editor.getMark() == null) {
624: editor.addUndo(SimpleEdit.MOVE);
625: editor.setMarkAtDot();
626: }
627:
628: final Position oldDot = new Position(editor.getDot());
629:
630: final Line newLine = pos.getLine();
631: if (newLine != dot.getLine()) {
632: editor.updateDotLine();
633: dot.setLine(newLine);
634: }
635: editor.moveDotToCol(display.getColumn(newLine, point.x)
636: + display.getShift());
637:
638: // Don't let caret go beyond end of text on line.
639: editor.moveCaretToDotCol();
640:
641: Region r = new Region(editor.getBuffer(), editor.getDot(),
642: oldDot);
643: for (Line line = r.getBeginLine(); line != r.getEndLine(); line = line
644: .next())
645: editor.update(line);
646:
647: return true;
648: }
649:
650: private boolean dispatchActionPerformed(ActionEvent event) {
651: editor.executeCommand(event.getActionCommand());
652: return true;
653: }
654:
655: public void actionPerformed(final ActionEvent e) {
656: Runnable r = new Runnable() {
657: public void run() {
658: dispatch(e);
659: }
660: };
661: SwingUtilities.invokeLater(r);
662: }
663:
664: public void dragEnter(DropTargetDragEvent event) {
665: if (editor.getBuffer().isReadOnly()) {
666: event.rejectDrag();
667: } else {
668: if (Platform.isPlatformUnix() && dragSourceContext != null)
669: dragSourceContext.setCursor(getCursorForAction(event
670: .getDropAction()));
671: editor.getFrame().toFront();
672: }
673: }
674:
675: public void dragExit(DropTargetEvent e) {
676: display.setDragCaretPos(null);
677: if (Platform.isPlatformUnix() && dragSourceContext != null)
678: dragSourceContext.setCursor(getDragCursor(CURSOR_NO));
679: }
680:
681: public void dragOver(DropTargetDragEvent event) {
682: if (event.isDataFlavorSupported(DataFlavor.stringFlavor)) {
683: Point pt = event.getLocation();
684:
685: Line line = display.lineFromY(pt.y);
686: if (line == null)
687: return;
688: Position pos = new Position(line, 0);
689: int absCol = 0;
690:
691: if (isLineRegion) {
692: // Leave drag caret in column 0.
693: ;
694: } else {
695: int col = Math.max(display.getColumn(line, pt.x), 0);
696: absCol = col + display.getShift();
697: pos.moveToCol(absCol, editor.getBuffer().getTabWidth());
698: }
699:
700: boolean ok = false;
701: if (dragTextRegion == null)
702: ok = true;
703: else if (pos.isBefore(dragTextRegion.getBegin()))
704: ok = true;
705: else if (pos.isAfter(dragTextRegion.getEnd()))
706: ok = true;
707: else if (pos.equals(dragTextRegion.getEnd())) {
708: if (absCol > editor.getBuffer().getCol(
709: dragTextRegion.getEnd()))
710: ok = true;
711: }
712:
713: if (ok) {
714: display.setDragCaretPos(pos);
715: // The point in question might be beyond the end of the line.
716: display.setDragCaretCol(absCol);
717: } else
718: display.setDragCaretPos(null);
719: display.repaintChangedLines();
720: }
721: }
722:
723: public void drop(DropTargetDropEvent event) {
724: Transferable t = event.getTransferable();
725: if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
726: acceptFileDrop(event, t);
727: else if (t.isDataFlavorSupported(DataFlavor.stringFlavor))
728: acceptTextDrop(event, t);
729: else
730: event.rejectDrop();
731: }
732:
733: private void acceptFileDrop(DropTargetDropEvent event,
734: Transferable t) {
735: event.acceptDrop(DnDConstants.ACTION_LINK);
736: try {
737: List files = (List) t
738: .getTransferData(DataFlavor.javaFileListFlavor);
739: for (int i = 0; i < files.size(); i++) {
740: String path = ((java.io.File) files.get(i)).getPath();
741: Buffer buffer = editor.openFile(File.getInstance(path));
742: if (buffer != null) {
743: editor.makeNext(buffer);
744: editor.activate(buffer);
745: } else
746: event.rejectDrop();
747: }
748: event.getDropTargetContext().dropComplete(true);
749: } catch (Exception e) {
750: Log.error(e);
751: event.rejectDrop();
752: }
753: editor.updateDisplay();
754: }
755:
756: private void acceptTextDrop(DropTargetDropEvent event,
757: Transferable t) {
758: final int dropAction = event.getDropAction(); // copy = 1, move = 2
759: if (dropAction != DnDConstants.ACTION_COPY
760: && dropAction != DnDConstants.ACTION_MOVE) {
761: // Not copy or move.
762: event.rejectDrop();
763: return;
764: }
765: if (!editor.checkReadOnly()) {
766: event.rejectDrop();
767: return;
768: }
769: // Copy or move.
770: try {
771: event.acceptDrop(dropAction);
772: final String s = (String) t
773: .getTransferData(DataFlavor.stringFlavor);
774: final Point point = event.getLocation();
775: Position posDrop = display.positionFromPoint(point);
776: boolean ok = false;
777: if (dragTextRegion == null)
778: ok = true;
779: else if (posDrop.isBefore(dragTextRegion.getBegin()))
780: ok = true;
781: else if (posDrop.isAfter(dragTextRegion.getEnd()))
782: ok = true;
783: else if (posDrop.equals(dragTextRegion.getEnd())) {
784: int col = Math.max(display.getColumn(posDrop.getLine(),
785: point.x), 0);
786: int absCol = col + display.getShift();
787: if (absCol > editor.getBuffer().getCol(
788: dragTextRegion.getEnd()))
789: ok = true;
790: }
791: if (ok) {
792: if (dropAction == DnDConstants.ACTION_COPY) {
793: // Copy.
794: CompoundEdit compoundEdit = editor
795: .beginCompoundEdit();
796: moveCaretToDropPoint(point);
797: editor.paste(s, true);
798: editor.endCompoundEdit(compoundEdit);
799: } else if (dropAction == DnDConstants.ACTION_MOVE) {
800: // Move.
801: CompoundEdit compoundEdit = editor
802: .beginCompoundEdit();
803: if (dragTextRegion != null
804: && posDrop.isBefore(dragTextRegion
805: .getBegin())) {
806: editor.deleteRegion();
807: dragTextRegion = null;
808: }
809: moveCaretToDropPoint(point);
810: editor.paste(s, true); // Leave paste selected.
811: Region r = new Region(editor);
812: posDrop = r.getBegin(); // Where the drop actually occurred.
813: if (dragTextRegion != null
814: && posDrop.isAfter(dragTextRegion.getEnd())) {
815: Position savedDot = editor.getDotCopy();
816: Position savedMark = editor.getMark().copy();
817: dragTextRegion.adjustMarker(savedDot);
818: dragTextRegion.adjustMarker(savedMark);
819: editor.addUndo(SimpleEdit.MOVE);
820: editor.setMark(dragTextRegion.getBegin());
821: editor.setDot(dragTextRegion.getEnd());
822: editor.deleteRegion();
823: dragTextRegion = null;
824: editor.addUndo(SimpleEdit.MOVE);
825: editor.setMark(savedMark);
826: editor.setDot(savedDot);
827: }
828: editor.endCompoundEdit(compoundEdit);
829: }
830: editor.updateDisplay();
831: }
832: event.getDropTargetContext().dropComplete(true);
833: // Make sure destination is current editor after drop.
834: editor.ensureActive();
835: Editor.setCurrentEditor(editor);
836: editor.setFocusToDisplay();
837: } catch (Exception e) {
838: Log.error(e);
839: event.rejectDrop();
840: }
841: inDragText = false;
842: dragTextRegion = null;
843: display.setDragCaretPos(null);
844: editor.setDefaultCursor();
845: editor.repaint();
846: }
847:
848: private void moveCaretToDropPoint(Point point) {
849: editor.addUndo(SimpleEdit.MOVE);
850: editor.setMark(null);
851: display.moveCaretToPoint(point);
852: if (editor.getBuffer().getBooleanProperty(
853: Property.RESTRICT_CARET))
854: display.moveCaretToDotCol();
855: }
856:
857: public void dropActionChanged(DropTargetDragEvent event) {
858: if (Platform.isPlatformUnix() && dragSourceContext != null)
859: dragSourceContext.setCursor(getCursorForAction(event
860: .getDropAction()));
861: }
862:
863: public void dragGestureRecognized(DragGestureEvent event) {
864: if (!Editor.preferences().getBooleanProperty(
865: Property.ENABLE_DRAG_TEXT))
866: return;
867: if (editor.getMark() != null) {
868: Region r = new Region(editor);
869: Position pos = display.positionFromPoint(event
870: .getDragOrigin());
871: if (!pos.isAfter(r.getBegin()))
872: return;
873: if (!pos.isBefore(r.getEnd()))
874: return;
875: dragTextRegion = r;
876: Transferable transferable = new StringSelection(
877: dragTextRegion.toString());
878: isLineRegion = dragTextRegion.isLineRegion();
879: inDragText = true;
880: int action = event.getDragAction();
881: Cursor cursor = Platform.isPlatformUnix() ? getCursorForAction(action)
882: : null;
883: dragSource.startDrag(event, cursor, transferable, this );
884: dragSourceContext = null;
885: }
886: }
887:
888: public void dragDropEnd(DragSourceDropEvent event) {
889: if (dragTextRegion != null && !editor.getBuffer().isReadOnly())
890: if (event.getDropAction() == DnDConstants.ACTION_MOVE)
891: editor.deleteRegion();
892: inDragText = false;
893: dragTextRegion = null;
894: isLineRegion = false;
895: display.setDragCaretPos(null);
896: display.repaintChangedLines();
897: }
898:
899: public void dragEnter(DragSourceDragEvent event) {
900: if (Platform.isPlatformUnix()) {
901: DragSourceContext dsc = event.getDragSourceContext();
902: dsc.setCursor(getCursorForAction(event.getDropAction()));
903: }
904: }
905:
906: public void dragOver(DragSourceDragEvent event) {
907: }
908:
909: public void dropActionChanged(DragSourceDragEvent event) {
910: if (Platform.isPlatformUnix()) {
911: DragSourceContext dsc = event.getDragSourceContext();
912: int dropAction = event.getDropAction();
913: if (dropAction == DnDConstants.ACTION_COPY)
914: dsc.setCursor(getDragCursor(CURSOR_COPY));
915: else if (dropAction == DnDConstants.ACTION_MOVE)
916: dsc.setCursor(getDragCursor(CURSOR_MOVE));
917: }
918: }
919:
920: public void dragExit(DragSourceEvent event) {
921: DragSourceContext dsc = event.getDragSourceContext();
922: if (Platform.isPlatformUnix())
923: dsc.setCursor(getDragCursor(CURSOR_NO));
924: dragSourceContext = dsc;
925: }
926:
927: // Only used on Unix.
928: public static Cursor getCursorForAction(int action) {
929: int index;
930: if (action == DnDConstants.ACTION_COPY)
931: index = CURSOR_COPY;
932: else if (action == DnDConstants.ACTION_MOVE)
933: index = CURSOR_MOVE;
934: else
935: index = CURSOR_NO;
936: return getDragCursor(index);
937: }
938:
939: // Only used on Unix.
940: private static Cursor getDragCursor(int index) {
941: if (cursors[index] != null)
942: return cursors[index];
943: // Need to create cursor.
944: String name, filename;
945: switch (index) {
946: case CURSOR_NO:
947: default:
948: name = "NoDrop";
949: filename = "nodrop.png";
950: break;
951: case CURSOR_MOVE:
952: name = "MoveDrop";
953: filename = "movedrop.png";
954: break;
955: case CURSOR_COPY:
956: name = "CopyDrop";
957: filename = "copydrop.png";
958: break;
959: }
960: Cursor cursor = null;
961: URL url = Editor.class.getResource("images/".concat(filename));
962: if (url != null) {
963: Toolkit toolkit = java.awt.Toolkit.getDefaultToolkit();
964: Image image = toolkit.createImage(url);
965: if (image != null)
966: cursor = toolkit.createCustomCursor(image, new Point(1,
967: 1), name);
968: }
969: if (cursor == null)
970: cursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
971: // Cache the result.
972: cursors[index] = cursor;
973: return cursor;
974: }
975: }
|