001: /*
002: * TextAreaMouseHandler.java - Handles services.xml files in plugins
003: * :tabSize=8:indentSize=8:noTabs=false:
004: * :folding=explicit:collapseFolds=1:
005: *
006: * Copyright (C) 2006 Matthieu Casanova
007: *
008: * This program is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public License
010: * as published by the Free Software Foundation; either version 2
011: * of the License, or any later version.
012: *
013: * This program is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public License
019: * along with this program; if not, write to the Free Software
020: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
021: */
022: package org.gjt.sp.jedit.textarea;
023:
024: import org.gjt.sp.jedit.OperatingSystem;
025: import org.gjt.sp.jedit.TextUtilities;
026: import org.gjt.sp.util.StandardUtilities;
027:
028: import javax.swing.event.MouseInputAdapter;
029: import java.awt.event.MouseEvent;
030: import java.awt.*;
031:
032: /**
033: * @author Matthieu Casanova
034: * @version $Id: FoldHandler.java 5568 2006-07-10 20:52:23Z kpouer $
035: */
036: public class TextAreaMouseHandler extends MouseInputAdapter {
037: //{{{ MouseHandler constructor
038: TextAreaMouseHandler(TextArea textArea) {
039: this .textArea = textArea;
040: } //}}}
041:
042: //{{{ mousePressed() method
043: public void mousePressed(MouseEvent evt) {
044: showCursor();
045:
046: control = (OperatingSystem.isMacOS() && evt.isMetaDown())
047: || (!OperatingSystem.isMacOS() && evt.isControlDown());
048:
049: ctrlForRectangularSelection = true;
050:
051: // so that Home <mouse click> Home is not the same
052: // as pressing Home twice in a row
053: textArea.getInputHandler().resetLastActionCount();
054:
055: quickCopyDrag = (textArea.isQuickCopyEnabled() && isMiddleButton(evt
056: .getModifiers()));
057:
058: if (!quickCopyDrag) {
059: textArea.requestFocus();
060: TextArea.focusedComponent = textArea;
061: }
062:
063: if (textArea.getBuffer().isLoading())
064: return;
065:
066: int x = evt.getX();
067: int y = evt.getY();
068:
069: dragStart = textArea
070: .xyToOffset(x, y, !(textArea.getPainter()
071: .isBlockCaretEnabled() || textArea
072: .isOverwriteEnabled()));
073: dragStartLine = textArea.getLineOfOffset(dragStart);
074: dragStartOffset = dragStart
075: - textArea.getLineStartOffset(dragStartLine);
076:
077: dragged = false;
078:
079: textArea.blink = true;
080: textArea.invalidateLine(textArea.getCaretLine());
081:
082: clickCount = evt.getClickCount();
083:
084: if (textArea.isDragEnabled()
085: && textArea.selectionManager.insideSelection(x, y)
086: && clickCount == 1 && !evt.isShiftDown()) {
087: maybeDragAndDrop = true;
088: textArea.moveCaretPosition(dragStart, false);
089: return;
090: } else
091: maybeDragAndDrop = false;
092:
093: if (quickCopyDrag) {
094: // ignore double clicks of middle button
095: doSingleClick(evt);
096: } else {
097: switch (clickCount) {
098: case 1:
099: doSingleClick(evt);
100: break;
101: case 2:
102: doDoubleClick();
103: break;
104: default: //case 3:
105: doTripleClick();
106: break;
107: }
108: }
109: } //}}}
110:
111: //{{{ doSingleClick() method
112: protected void doSingleClick(MouseEvent evt) {
113: int x = evt.getX();
114:
115: int extraEndVirt = 0;
116: if (textArea.chunkCache.getLineInfo(textArea
117: .getLastScreenLine()).lastSubregion) {
118: int dragStart = textArea.xyToOffset(x, evt.getY(),
119: !textArea.getPainter().isBlockCaretEnabled()
120: && !textArea.isOverwriteEnabled());
121: int screenLine = textArea.getScreenLineOfOffset(dragStart);
122: ChunkCache.LineInfo lineInfo = textArea.chunkCache
123: .getLineInfo(screenLine);
124: int offset = textArea.getScreenLineEndOffset(screenLine);
125: if ((1 != offset - dragStart) || (lineInfo.lastSubregion)) {
126: offset--;
127: }
128: float dragStartLineWidth = textArea.offsetToXY(offset).x;
129: if (x > dragStartLineWidth) {
130: extraEndVirt = (int) ((x - dragStartLineWidth) / textArea.charWidth);
131: if (!textArea.getPainter().isBlockCaretEnabled()
132: && !textArea.isOverwriteEnabled()
133: && (x - textArea.getHorizontalOffset())
134: % textArea.charWidth > textArea.charWidth / 2) {
135: extraEndVirt++;
136: }
137: }
138: }
139:
140: if (((control && ctrlForRectangularSelection) || textArea
141: .isRectangularSelectionEnabled())
142: && textArea.isEditable()) {
143: int screenLine = (evt.getY() / textArea.getPainter()
144: .getFontMetrics().getHeight());
145: if (screenLine > textArea.getLastScreenLine())
146: screenLine = textArea.getLastScreenLine();
147: ChunkCache.LineInfo info = textArea.chunkCache
148: .getLineInfo(screenLine);
149: if (info.lastSubregion && extraEndVirt != 0) {
150: // control-click in virtual space inserts
151: // whitespace and moves caret
152: String whitespace = StandardUtilities.createWhiteSpace(
153: extraEndVirt, 0);
154: textArea.getBuffer().insert(dragStart, whitespace);
155:
156: dragStart += whitespace.length();
157: }
158: }
159:
160: if (evt.isShiftDown()) {
161: // XXX: getMarkPosition() deprecated!
162: textArea
163: .resizeSelection(
164: textArea.getMarkPosition(),
165: dragStart,
166: extraEndVirt,
167: textArea.isRectangularSelectionEnabled()
168: || (control && ctrlForRectangularSelection));
169:
170: if (!quickCopyDrag)
171: textArea.moveCaretPosition(dragStart, false);
172:
173: // so that shift-click-drag works
174: dragStartLine = textArea.getMarkLine();
175: dragStart = textArea.getMarkPosition();
176: dragStartOffset = dragStart
177: - textArea.getLineStartOffset(dragStartLine);
178:
179: // so that quick copy works
180: dragged = true;
181:
182: return;
183: }
184:
185: if (!quickCopyDrag)
186: textArea.moveCaretPosition(dragStart, false);
187:
188: if (!(textArea.isMultipleSelectionEnabled() || quickCopyDrag))
189: textArea.selectNone();
190: } //}}}
191:
192: //{{{ doDoubleClick() method
193: protected void doDoubleClick() {
194: // Ignore empty lines
195: if (textArea.getLineLength(dragStartLine) == 0)
196: return;
197:
198: String lineText = textArea.getLineText(dragStartLine);
199: String noWordSep = textArea.getBuffer().getStringProperty(
200: "noWordSep");
201: if (dragStartOffset == textArea.getLineLength(dragStartLine))
202: dragStartOffset--;
203:
204: boolean joinNonWordChars = textArea.getJoinNonWordChars();
205: int wordStart = TextUtilities.findWordStart(lineText,
206: dragStartOffset, noWordSep, joinNonWordChars, false,
207: false);
208: int wordEnd = TextUtilities.findWordEnd(lineText,
209: dragStartOffset + 1, noWordSep, joinNonWordChars,
210: false, false);
211:
212: int lineStart = textArea.getLineStartOffset(dragStartLine);
213: Selection sel = new Selection.Range(lineStart + wordStart,
214: lineStart + wordEnd);
215: if (textArea.isMultipleSelectionEnabled())
216: textArea.addToSelection(sel);
217: else
218: textArea.setSelection(sel);
219:
220: if (quickCopyDrag)
221: quickCopyDrag = false;
222:
223: textArea.moveCaretPosition(lineStart + wordEnd, false);
224:
225: dragged = true;
226: } //}}}
227:
228: //{{{ doTripleClick() method
229: protected void doTripleClick() {
230: int newCaret = textArea.getLineEndOffset(dragStartLine);
231: if (dragStartLine == textArea.getLineCount() - 1)
232: newCaret--;
233:
234: Selection sel = new Selection.Range(textArea
235: .getLineStartOffset(dragStartLine), newCaret);
236: if (textArea.isMultipleSelectionEnabled())
237: textArea.addToSelection(sel);
238: else
239: textArea.setSelection(sel);
240:
241: if (quickCopyDrag)
242: quickCopyDrag = false;
243:
244: textArea.moveCaretPosition(newCaret, false);
245:
246: dragged = true;
247: } //}}}
248:
249: //{{{ mouseMoved() method
250: public void mouseMoved(MouseEvent evt) {
251: showCursor();
252: } //}}}
253:
254: //{{{ mouseDragged() method
255: public void mouseDragged(MouseEvent evt) {
256: if (maybeDragAndDrop) {
257: textArea.startDragAndDrop(evt, control);
258: return;
259: }
260:
261: if (textArea.isDragInProgress())
262: return;
263:
264: if (textArea.getBuffer().isLoading())
265: return;
266:
267: TextAreaPainter painter = textArea.getPainter();
268: if (evt.getY() < 0) {
269: int delta = Math.min(-1, evt.getY()
270: / painter.getFontMetrics().getHeight());
271: textArea.setFirstLine(textArea.getFirstLine() + delta);
272: } else if (evt.getY() >= painter.getHeight()) {
273: int delta = Math.max(1, (evt.getY() - painter.getHeight())
274: / painter.getFontMetrics().getHeight());
275: if (textArea.lastLinePartial)
276: delta--;
277: textArea.setFirstLine(textArea.getFirstLine() + delta);
278: }
279:
280: switch (clickCount) {
281: case 1:
282: doSingleDrag(evt);
283: break;
284: case 2:
285: doDoubleDrag(evt);
286: break;
287: default: //case 3:
288: doTripleDrag(evt);
289: break;
290: }
291: } //}}}
292:
293: //{{{ doSingleDrag() method
294: private void doSingleDrag(MouseEvent evt) {
295: dragged = true;
296:
297: TextAreaPainter painter = textArea.getPainter();
298:
299: int x = evt.getX();
300: int y = evt.getY();
301: if (y < 0)
302: y = 0;
303: else if (y >= painter.getHeight())
304: y = painter.getHeight() - 1;
305:
306: int dot = textArea.xyToOffset(x, y, (!painter
307: .isBlockCaretEnabled() && !textArea
308: .isOverwriteEnabled())
309: || quickCopyDrag);
310: int dotLine = textArea.getLineOfOffset(dot);
311: int extraEndVirt = 0;
312:
313: if (textArea.chunkCache.getLineInfo(textArea
314: .getLastScreenLine()).lastSubregion) {
315: int screenLine = textArea.getScreenLineOfOffset(dot);
316: ChunkCache.LineInfo lineInfo = textArea.chunkCache
317: .getLineInfo(screenLine);
318: int offset = textArea.getScreenLineEndOffset(screenLine);
319: if ((1 != offset - dot) || (lineInfo.lastSubregion)) {
320: offset--;
321: }
322: float dotLineWidth = textArea.offsetToXY(offset).x;
323: if (x > dotLineWidth) {
324: extraEndVirt = (int) ((x - dotLineWidth) / textArea.charWidth);
325: if (!painter.isBlockCaretEnabled()
326: && !textArea.isOverwriteEnabled()
327: && (x - textArea.getHorizontalOffset())
328: % textArea.charWidth > textArea.charWidth / 2)
329: extraEndVirt++;
330: }
331: }
332:
333: textArea.resizeSelection(dragStart, dot, extraEndVirt, textArea
334: .isRectangularSelectionEnabled()
335: || (control && ctrlForRectangularSelection));
336:
337: if (quickCopyDrag) {
338: // just scroll to the dragged location
339: textArea.scrollTo(dotLine, dot
340: - textArea.getLineStartOffset(dotLine), false);
341: } else {
342: if (dot != textArea.getCaretPosition())
343: textArea.moveCaretPosition(dot, false);
344: if (textArea.isRectangularSelectionEnabled()
345: && extraEndVirt != 0) {
346: textArea.scrollTo(dotLine, dot
347: - textArea.getLineStartOffset(dotLine)
348: + extraEndVirt, false);
349: }
350: }
351: } //}}}
352:
353: //{{{ doDoubleDrag() method
354: private void doDoubleDrag(MouseEvent evt) {
355: int markLineStart = textArea.getLineStartOffset(dragStartLine);
356: int markLineLength = textArea.getLineLength(dragStartLine);
357: int mark = dragStartOffset;
358:
359: TextAreaPainter painter = textArea.getPainter();
360:
361: int pos = textArea.xyToOffset(evt.getX(), Math.max(0, Math.min(
362: painter.getHeight(), evt.getY())),
363: !(painter.isBlockCaretEnabled() || textArea
364: .isOverwriteEnabled()));
365: int line = textArea.getLineOfOffset(pos);
366: int lineStart = textArea.getLineStartOffset(line);
367: int lineLength = textArea.getLineLength(line);
368: int offset = pos - lineStart;
369:
370: String lineText = textArea.getLineText(line);
371: String markLineText = textArea.getLineText(dragStartLine);
372: String noWordSep = textArea.getBuffer().getStringProperty(
373: "noWordSep");
374: boolean joinNonWordChars = textArea.getJoinNonWordChars();
375:
376: if (markLineStart + dragStartOffset > lineStart + offset) {
377: if (offset != 0 && offset != lineLength) {
378: offset = TextUtilities.findWordStart(lineText, offset,
379: noWordSep, joinNonWordChars);
380: }
381:
382: if (markLineLength != 0) {
383: mark = TextUtilities.findWordEnd(markLineText, mark,
384: noWordSep, joinNonWordChars);
385: }
386: } else {
387: if (offset != 0 && lineLength != 0) {
388: offset = TextUtilities.findWordEnd(lineText, offset,
389: noWordSep, joinNonWordChars);
390: }
391:
392: if (mark != 0 && mark != markLineLength) {
393: mark = TextUtilities.findWordStart(markLineText, mark,
394: noWordSep, joinNonWordChars);
395: }
396: }
397:
398: if (lineStart + offset == textArea.getCaretPosition())
399: return;
400:
401: textArea.resizeSelection(markLineStart + mark, lineStart
402: + offset, 0, false);
403: textArea.moveCaretPosition(lineStart + offset, false);
404:
405: dragged = true;
406: } //}}}
407:
408: //{{{ doTripleDrag() method
409: private void doTripleDrag(MouseEvent evt) {
410: TextAreaPainter painter = textArea.getPainter();
411:
412: int offset = textArea.xyToOffset(evt.getX(), Math.max(0, Math
413: .min(painter.getHeight(), evt.getY())), false);
414: int mouseLine = textArea.getLineOfOffset(offset);
415: int mark;
416: int mouse;
417: if (dragStartLine > mouseLine) {
418: mark = textArea.getLineEndOffset(dragStartLine) - 1;
419: if (offset == textArea.getLineEndOffset(mouseLine) - 1)
420: mouse = offset;
421: else
422: mouse = textArea.getLineStartOffset(mouseLine);
423: } else {
424: mark = textArea.getLineStartOffset(dragStartLine);
425: if (offset == textArea.getLineStartOffset(mouseLine))
426: mouse = offset;
427: else if (offset == textArea.getLineEndOffset(mouseLine) - 1
428: && mouseLine != textArea.getLineCount() - 1)
429: mouse = textArea.getLineEndOffset(mouseLine);
430: else
431: mouse = textArea.getLineEndOffset(mouseLine) - 1;
432: }
433:
434: mouse = Math.min(textArea.getBuffer().getLength(), mouse);
435:
436: if (mouse == textArea.getCaretPosition())
437: return;
438:
439: textArea.resizeSelection(mark, mouse, 0, false);
440: textArea.moveCaretPosition(mouse, false);
441:
442: dragged = true;
443: } //}}}
444:
445: //{{{ mouseReleased() method
446: public void mouseReleased(MouseEvent evt) {
447: if (!dragged && textArea.isQuickCopyEnabled()
448: && isMiddleButton(evt.getModifiers())) {
449: textArea.requestFocus();
450: TextArea.focusedComponent = textArea;
451:
452: textArea.setCaretPosition(dragStart, false);
453: } else if (maybeDragAndDrop
454: && !textArea.isMultipleSelectionEnabled()) {
455: textArea.selectNone();
456: }
457:
458: dragged = false;
459: } //}}}
460:
461: //{{{ isPopupTrigger() method
462: /**
463: * Returns if the specified event is the popup trigger event.
464: * This implements precisely defined behavior, as opposed to
465: * MouseEvent.isPopupTrigger().
466: * @param evt The event
467: * @since jEdit 4.3pre7
468: */
469: public static boolean isPopupTrigger(MouseEvent evt) {
470: return isRightButton(evt.getModifiers());
471: } //}}}
472:
473: //{{{ isMiddleButton() method
474: /**
475: * @param modifiers The modifiers flag from a mouse event
476: * @since jEdit 4.3pre7
477: */
478: public static boolean isMiddleButton(int modifiers) {
479: if (OperatingSystem.isMacOS()) {
480: if ((modifiers & MouseEvent.BUTTON1_MASK) != 0)
481: return (modifiers & MouseEvent.ALT_MASK) != 0;
482: else
483: return (modifiers & MouseEvent.BUTTON2_MASK) != 0;
484: } else
485: return (modifiers & MouseEvent.BUTTON2_MASK) != 0;
486: } //}}}
487:
488: //{{{ isRightButton() method
489: /**
490: * @param modifiers The modifiers flag from a mouse event
491: * @since jEdit 4.3pre7
492: */
493: public static boolean isRightButton(int modifiers) {
494: if (OperatingSystem.isMacOS()) {
495: if ((modifiers & MouseEvent.BUTTON1_MASK) != 0)
496: return (modifiers & MouseEvent.CTRL_MASK) != 0;
497: else
498: return (modifiers & MouseEvent.BUTTON3_MASK) != 0;
499: } else
500: return (modifiers & MouseEvent.BUTTON3_MASK) != 0;
501: } //}}}
502:
503: //{{{ Private members
504: protected TextArea textArea;
505: protected int dragStartLine;
506: protected int dragStartOffset;
507: protected int dragStart;
508: protected int clickCount;
509: protected boolean dragged;
510: protected boolean quickCopyDrag;
511: protected boolean control;
512: protected boolean ctrlForRectangularSelection;
513: /* with drag and drop on, a mouse down in a selection does not
514: immediately deselect */
515: protected boolean maybeDragAndDrop;
516:
517: //{{{ showCursor() method
518: protected void showCursor() {
519: textArea.getPainter().setCursor(
520: Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
521: } //}}}
522:
523: //}}}
524: }
|