Source Code Cross Referenced for TextSelection.java in  » Internationalization-Localization » icu4j » com » ibm » richtext » textpanel » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Internationalization Localization » icu4j » com.ibm.richtext.textpanel 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * (C) Copyright IBM Corp. 1998-2005.  All Rights Reserved.
003:         *
004:         * The program is provided "as is" without any warranty express or
005:         * implied, including the warranty of non-infringement and the implied
006:         * warranties of merchantibility and fitness for a particular purpose.
007:         * IBM will not be liable for any damages suffered by you as a result
008:         * of using the Program. In no event will IBM be liable for any
009:         * special, indirect or consequential damages or lost profits even if
010:         * IBM has been advised of the possibility of their occurrence. IBM
011:         * will not be liable for any third party claims against you.
012:         */
013:        /*
014:         7/1/97 - caret blinks
015:
016:         7/3/97 - fAnchor is no longer restricted to the start or end of the selection. {jbr}
017:         Also, removed fVisible - it was identical to enabled().
018:         */
019:
020:        package com.ibm.richtext.textpanel;
021:
022:        import java.awt.Graphics;
023:        import java.awt.Color;
024:        import java.awt.Rectangle;
025:
026:        import java.text.BreakIterator;
027:
028:        import java.awt.event.MouseEvent;
029:        import java.awt.event.KeyEvent;
030:        import java.awt.event.FocusEvent;
031:
032:        import com.ibm.richtext.styledtext.MConstText;
033:        import com.ibm.richtext.textformat.TextOffset;
034:
035:        import com.ibm.richtext.textformat.MFormatter;
036:
037:        class TextSelection extends Behavior implements  Runnable {
038:            static final String COPYRIGHT = "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
039:            static final Color HIGHLIGHTCOLOR = Color.pink;
040:
041:            private TextComponent fTextComponent;
042:            private MConstText fText;
043:            private TextOffset fStart;
044:            private TextOffset fLimit;
045:            private TextOffset fAnchor;
046:            private TextOffset fUpDownAnchor = null;
047:            private BreakIterator fBoundaries = null;
048:            private Color fHighlightColor = HIGHLIGHTCOLOR;
049:            private PanelEventBroadcaster fListener;
050:            private RunStrategy fRunStrategy;
051:            private boolean fMouseDown = false;
052:            private boolean fHandlingKeyOrCommand = false;
053:
054:            private boolean fCaretShouldBlink;
055:            private boolean fCaretIsVisible;
056:            private int fCaretCount;
057:
058:            // formerly in base class
059:            private boolean fEnabled;
060:
061:            private MouseEvent fPendingMouseEvent = null;
062:
063:            private static final int kCaretInterval = 500;
064:
065:            public void run() {
066:
067:                final Runnable blinkCaret = new Runnable() {
068:                    public void run() {
069:                        fCaretIsVisible = !fCaretIsVisible;
070:                        Graphics g = fTextComponent.getGraphics();
071:                        if (g != null) {
072:                            //System.out.println("caretIsVisible: " + fCaretIsVisible);
073:                            drawSelection(g, fCaretIsVisible);
074:                        } else {
075:                            // Not sure what else to do:
076:                            fCaretShouldBlink = false;
077:                        }
078:                    }
079:                };
080:
081:                // blink caret
082:                while (true) {
083:
084:                    synchronized (this ) {
085:
086:                        while (!fCaretShouldBlink) {
087:                            try {
088:                                wait();
089:                            } catch (InterruptedException e) {
090:                                System.out
091:                                        .println("Caught InterruptedException in caret thread.");
092:                            }
093:                        }
094:
095:                        ++fCaretCount;
096:
097:                        if (fCaretCount % 2 == 0) {
098:                            fRunStrategy.doIt(blinkCaret);
099:                        }
100:                    }
101:
102:                    try {
103:                        Thread.sleep(kCaretInterval);
104:                    } catch (InterruptedException e) {
105:                    }
106:                }
107:            }
108:
109:            public TextSelection(TextComponent textComponent,
110:                    PanelEventBroadcaster listener, RunStrategy runStrategy) {
111:
112:                fTextComponent = textComponent;
113:                fText = textComponent.getText();
114:                fListener = listener;
115:                fRunStrategy = runStrategy;
116:
117:                fStart = new TextOffset();
118:                fLimit = new TextOffset();
119:                fAnchor = new TextOffset();
120:                fMouseDown = false;
121:
122:                fCaretCount = 0;
123:                fCaretIsVisible = true;
124:                fCaretShouldBlink = false;
125:                setEnabled(false);
126:
127:                Thread caretThread = new Thread(this );
128:                caretThread.setDaemon(true);
129:                caretThread.start();
130:            }
131:
132:            boolean enabled() {
133:
134:                return fEnabled;
135:            }
136:
137:            private void setEnabled(boolean enabled) {
138:
139:                fEnabled = enabled;
140:            }
141:
142:            public boolean textControlEventOccurred(Behavior.EventType event,
143:                    Object what) {
144:
145:                boolean result;
146:                fHandlingKeyOrCommand = true;
147:
148:                if (event == Behavior.SELECT) {
149:                    select((TextRange) what);
150:                    result = true;
151:                } else if (event == Behavior.COPY) {
152:                    fTextComponent.getClipboard().setContents(
153:                            fText.extract(fStart.fOffset, fLimit.fOffset));
154:                    fListener
155:                            .textStateChanged(TextPanelEvent.CLIPBOARD_CHANGED);
156:                    result = true;
157:                } else {
158:                    result = false;
159:                }
160:
161:                fHandlingKeyOrCommand = false;
162:                return result;
163:            }
164:
165:            protected void advanceToNextBoundary(TextOffset offset) {
166:
167:                // If there's no boundaries object, or if position at the end of the
168:                // document, return the offset unchanged
169:                if (fBoundaries == null) {
170:                    return;
171:                }
172:
173:                int position = offset.fOffset;
174:
175:                if (position >= fText.length()) {
176:                    return;
177:                }
178:
179:                // If position is at a boundary and offset is before position,
180:                // leave it unchanged.  Otherwise move to next boundary.
181:                int nextPos = fBoundaries.following(position);
182:                if (fBoundaries.previous() == position
183:                        && offset.fPlacement == TextOffset.BEFORE_OFFSET) {
184:                    return;
185:                }
186:
187:                offset.setOffset(nextPos, TextOffset.AFTER_OFFSET);
188:            }
189:
190:            protected void advanceToPreviousBoundary(TextOffset offset) {
191:
192:                advanceToPreviousBoundary(offset, false);
193:            }
194:
195:            private void advanceToPreviousBoundary(TextOffset offset,
196:                    boolean alwaysMove) {
197:                // if there's no boundaries object, or if we're sitting at the beginning
198:                // of the document, return the offset unchanged
199:                if (fBoundaries == null) {
200:                    return;
201:                }
202:
203:                int position = offset.fOffset;
204:
205:                if (position == 0) {
206:                    return;
207:                }
208:
209:                // If position is at a boundary, leave it unchanged.  Otherwise
210:                // move to previous boundary.
211:                if (position == fText.length()) {
212:                    fBoundaries.last();
213:                } else {
214:                    fBoundaries.following(position);
215:                }
216:
217:                int prevPos = fBoundaries.previous();
218:
219:                if (prevPos == position) {
220:                    if (!alwaysMove
221:                            && offset.fPlacement == TextOffset.AFTER_OFFSET) {
222:                        return;
223:                    }
224:
225:                    prevPos = fBoundaries.previous();
226:                }
227:
228:                // and finally update the real offset with this new position we've found
229:                offset.setOffset(prevPos, TextOffset.AFTER_OFFSET);
230:            }
231:
232:            private void doArrowKey(KeyEvent e, int key) {
233:
234:                // when there's a selection range, the left and up arrow keys place an
235:                // insertion point at the beginning of the range, and the right and down
236:                // keys place an insertion point at the end of the range (unless the shift
237:                // key is down, of course)
238:
239:                if (!fStart.equals(fLimit) && !e.isShiftDown()) {
240:                    if (key == KeyEvent.VK_LEFT || key == KeyEvent.VK_UP)
241:                        setSelRangeAndDraw(fStart, fStart, fStart);
242:                    else
243:                        setSelRangeAndDraw(fLimit, fLimit, fLimit);
244:                } else {
245:                    if (!fAnchor.equals(fStart))
246:                        fAnchor.assign(fLimit);
247:
248:                    TextOffset liveEnd = (fStart.equals(fAnchor)) ? fLimit
249:                            : fStart;
250:                    TextOffset newPos = new TextOffset();
251:
252:                    // if the control key is down, the left and right arrow keys move by whole
253:                    // word in the appropriate direction (we use a line break object so that we're
254:                    // not treating spaces and punctuation as words)
255:                    if (e.isControlDown()
256:                            && (key == KeyEvent.VK_LEFT || key == KeyEvent.VK_RIGHT)) {
257:                        fUpDownAnchor = null;
258:                        fBoundaries = BreakIterator.getLineInstance();
259:                        fBoundaries.setText(fText.createCharacterIterator());
260:
261:                        newPos.assign(liveEnd);
262:                        if (key == KeyEvent.VK_RIGHT)
263:                            advanceToNextBoundary(newPos);
264:                        else
265:                            advanceToPreviousBoundary(newPos, true);
266:                    }
267:
268:                    // if we get down to here, this is a plain-vanilla insertion-point move,
269:                    // or the shift key is down and we're extending or shortening the selection
270:                    else {
271:
272:                        // fUpDownAnchor is used to keep track of the horizontal position
273:                        // across a run of up or down arrow keys (this prevents accumulated
274:                        // error from destroying our horizontal position)
275:                        if (key == KeyEvent.VK_LEFT || key == KeyEvent.VK_RIGHT)
276:                            fUpDownAnchor = null;
277:                        else {
278:                            if (fUpDownAnchor == null) {
279:                                fUpDownAnchor = new TextOffset(liveEnd);
280:                            }
281:                        }
282:
283:                        short direction = MFormatter.eRight; // just to have a default...
284:
285:                        switch (key) {
286:                        case KeyEvent.VK_UP:
287:                            direction = MFormatter.eUp;
288:                            break;
289:                        case KeyEvent.VK_DOWN:
290:                            direction = MFormatter.eDown;
291:                            break;
292:                        case KeyEvent.VK_LEFT:
293:                            direction = MFormatter.eLeft;
294:                            break;
295:                        case KeyEvent.VK_RIGHT:
296:                            direction = MFormatter.eRight;
297:                            break;
298:                        }
299:
300:                        // use the formatter to determine the actual effect of the arrow key
301:                        fTextComponent.findNewInsertionOffset(newPos,
302:                                fUpDownAnchor, liveEnd, direction);
303:                    }
304:
305:                    // if the shift key is down, the selection range is from the anchor point
306:                    // the site of the last insertion point or the beginning point of the last
307:                    // selection drag operation) to the newly-calculated position; if the
308:                    // shift key is down, the newly-calculated position is the insertion point position
309:                    if (!e.isShiftDown())
310:                        setSelRangeAndDraw(newPos, newPos, newPos);
311:                    else {
312:                        if (newPos.lessThan(fAnchor))
313:                            setSelRangeAndDraw(newPos, fAnchor, fAnchor);
314:                        else
315:                            setSelRangeAndDraw(fAnchor, newPos, fAnchor);
316:                    }
317:                }
318:
319:                scrollToShowSelectionEnd();
320:                fBoundaries = null;
321:            }
322:
323:            private void doEndKey(KeyEvent e) {
324:                // ctrl-end moves the insertsion point to the end of the document,
325:                // ctrl-shift-end extends the selection so that it ends at the end
326:                // of the document
327:
328:                TextOffset activeEnd, anchor;
329:
330:                if (fAnchor.equals(fStart)) {
331:                    activeEnd = new TextOffset(fStart);
332:                    anchor = new TextOffset(fLimit);
333:                } else {
334:                    activeEnd = new TextOffset(fLimit);
335:                    anchor = new TextOffset(fStart);
336:                }
337:
338:                if (e.isControlDown()) {
339:                    TextOffset end = new TextOffset(fText.length(),
340:                            TextOffset.BEFORE_OFFSET);
341:
342:                    if (e.isShiftDown())
343:                        setSelRangeAndDraw(anchor, end, anchor);
344:                    else
345:                        setSelRangeAndDraw(end, end, end);
346:                }
347:
348:                // end moves the insertion point to the end of the line containing
349:                // the end of the current selection
350:                // shift-end extends the selection to the end of the line containing
351:                // the end of the current selection
352:
353:                else {
354:
355:                    int oldOffset = activeEnd.fOffset;
356:
357:                    activeEnd.fOffset = fTextComponent
358:                            .lineRangeLimit(fTextComponent
359:                                    .lineContaining(activeEnd));
360:                    activeEnd.fPlacement = TextOffset.BEFORE_OFFSET;
361:
362:                    if (fText.paragraphLimit(oldOffset) == activeEnd.fOffset
363:                            && activeEnd.fOffset != fText.length()
364:                            && activeEnd.fOffset > oldOffset) {
365:                        activeEnd.fOffset--;
366:                        activeEnd.fPlacement = TextOffset.AFTER_OFFSET;
367:                    }
368:
369:                    if (!e.isShiftDown())
370:                        setSelRangeAndDraw(activeEnd, activeEnd, activeEnd);
371:                    else {
372:                        if (activeEnd.lessThan(anchor))
373:                            setSelRangeAndDraw(activeEnd, anchor, anchor);
374:                        else
375:                            setSelRangeAndDraw(anchor, activeEnd, anchor);
376:                    }
377:                }
378:
379:                scrollToShowSelectionEnd();
380:                fBoundaries = null;
381:                fUpDownAnchor = null;
382:            }
383:
384:            private void doHomeKey(KeyEvent e) {
385:                // ctrl-home moves the insertion point to the beginning of the document,
386:                // ctrl-shift-home extends the selection so that it begins at the beginning
387:                // of the document
388:
389:                TextOffset activeEnd, anchor;
390:
391:                if (fAnchor.equals(fStart)) {
392:                    activeEnd = new TextOffset(fStart);
393:                    anchor = new TextOffset(fLimit);
394:                } else {
395:                    activeEnd = new TextOffset(fLimit);
396:                    anchor = new TextOffset(fStart);
397:                }
398:
399:                if (e.isControlDown()) {
400:
401:                    TextOffset start = new TextOffset(0,
402:                            TextOffset.AFTER_OFFSET);
403:                    if (e.isShiftDown())
404:                        setSelRangeAndDraw(start, anchor, anchor);
405:                    else
406:                        setSelRangeAndDraw(start, start, start);
407:                }
408:
409:                // home moves the insertion point to the beginning of the line containing
410:                // the beginning of the current selection
411:                // shift-home extends the selection to the beginning of the line containing
412:                // the beginning of the current selection
413:
414:                else {
415:
416:                    activeEnd.fOffset = fTextComponent
417:                            .lineRangeLow(fTextComponent
418:                                    .lineContaining(activeEnd));
419:                    activeEnd.fPlacement = TextOffset.AFTER_OFFSET;
420:
421:                    if (!e.isShiftDown())
422:                        setSelRangeAndDraw(activeEnd, activeEnd, activeEnd);
423:                    else {
424:                        if (activeEnd.lessThan(anchor))
425:                            setSelRangeAndDraw(activeEnd, anchor, anchor);
426:                        else
427:                            setSelRangeAndDraw(anchor, activeEnd, anchor);
428:                    }
429:                }
430:
431:                scrollToShowSelectionEnd();
432:                fBoundaries = null;
433:                fUpDownAnchor = null;
434:            }
435:
436:            /** draws or erases the current selection
437:             * Draws or erases the highlight region or insertion caret for the current selection
438:             * range.
439:             * @param g The graphics environment to draw into
440:             * @param visible If true, draw the selection; if false, erase it
441:             */
442:            protected void drawSelection(Graphics g, boolean visible) {
443:                drawSelectionRange(g, fStart, fLimit, visible);
444:            }
445:
446:            /** draws or erases a selection highlight at the specfied positions
447:             * Draws or erases a selection highlight or insertion caret corresponding to
448:             * the specified selecion range
449:             * @param g The graphics environment to draw into.  If null, this method does nothing.
450:             * @param start The beginning of the range to highlight
451:             * @param limit The end of the range to highlight
452:             * @param visible If true, draw; if false, erase
453:             */
454:            protected void drawSelectionRange(Graphics g, TextOffset start,
455:                    TextOffset limit, boolean visible) {
456:                if (g == null) {
457:                    return;
458:                }
459:                Rectangle selBounds = fTextComponent.getBoundingRect(start,
460:                        limit);
461:
462:                selBounds.width = Math.max(1, selBounds.width);
463:                selBounds.height = Math.max(1, selBounds.height);
464:
465:                fTextComponent.drawText(g, selBounds, visible, start, limit,
466:                        fHighlightColor);
467:            }
468:
469:            protected TextOffset getAnchor() {
470:                return fAnchor;
471:            }
472:
473:            public TextOffset getEnd() {
474:                return fLimit;
475:            }
476:
477:            public Color getHighlightColor() {
478:                return fHighlightColor;
479:            }
480:
481:            public TextOffset getStart() {
482:                return fStart;
483:            }
484:
485:            public TextRange getSelectionRange() {
486:
487:                return new TextRange(fStart.fOffset, fLimit.fOffset);
488:            }
489:
490:            public boolean focusGained(FocusEvent e) {
491:
492:                setEnabled(true);
493:                drawSelection(fTextComponent.getGraphics(), true);
494:
495:                restartCaretBlinking(true);
496:                if (fPendingMouseEvent != null) {
497:                    mousePressed(fPendingMouseEvent);
498:                    fPendingMouseEvent = null;
499:                }
500:                fListener.textStateChanged(TextPanelEvent.CLIPBOARD_CHANGED);
501:
502:                return true;
503:            }
504:
505:            public boolean focusLost(FocusEvent e) {
506:                stopCaretBlinking();
507:                setEnabled(false);
508:                drawSelection(fTextComponent.getGraphics(), false);
509:                return true;
510:            }
511:
512:            /**
513:             * Return true if the given key event can affect the selection
514:             * range.
515:             */
516:            public static boolean keyAffectsSelection(KeyEvent e) {
517:
518:                if (e.getID() != KeyEvent.KEY_PRESSED) {
519:                    return false;
520:                }
521:
522:                int key = e.getKeyCode();
523:
524:                switch (key) {
525:                case KeyEvent.VK_HOME:
526:                case KeyEvent.VK_END:
527:                case KeyEvent.VK_LEFT:
528:                case KeyEvent.VK_RIGHT:
529:                case KeyEvent.VK_UP:
530:                case KeyEvent.VK_DOWN:
531:                    return true;
532:
533:                default:
534:                    return false;
535:                }
536:            }
537:
538:            public boolean keyPressed(KeyEvent e) {
539:
540:                fHandlingKeyOrCommand = true;
541:                int key = e.getKeyCode();
542:                boolean result = true;
543:
544:                switch (key) {
545:                case KeyEvent.VK_HOME:
546:                    doHomeKey(e);
547:                    break;
548:
549:                case KeyEvent.VK_END:
550:                    doEndKey(e);
551:                    break;
552:
553:                case KeyEvent.VK_LEFT:
554:                case KeyEvent.VK_RIGHT:
555:                case KeyEvent.VK_UP:
556:                case KeyEvent.VK_DOWN:
557:                    doArrowKey(e, key);
558:                    break;
559:
560:                default:
561:                    fUpDownAnchor = null;
562:                    result = false;
563:                    break;
564:                }
565:
566:                fHandlingKeyOrCommand = false;
567:                return result;
568:            }
569:
570:            public boolean mousePressed(MouseEvent e) {
571:
572:                if (!enabled()) {
573:                    fPendingMouseEvent = e;
574:                    fTextComponent.requestFocus();
575:                    return false;
576:                }
577:
578:                if (fMouseDown)
579:                    throw new Error(
580:                            "fMouseDown is out of sync with mouse in TextSelection.");
581:
582:                fMouseDown = true;
583:                stopCaretBlinking();
584:
585:                int x = e.getX(), y = e.getY();
586:                boolean wasZeroLength = rangeIsZeroLength(fStart, fLimit,
587:                        fAnchor);
588:
589:                TextOffset current = fTextComponent.pointToTextOffset(null, x,
590:                        y, null, true);
591:                TextOffset anchorStart = new TextOffset();
592:                TextOffset anchorEnd = new TextOffset();
593:
594:                fUpDownAnchor = null;
595:
596:                // if we're not extending the selection...
597:                if (!e.isShiftDown()) {
598:
599:                    // if there are multiple clicks, create the appopriate type of BreakIterator
600:                    // object for finding text boundaries (single clicks don't use a BreakIterator
601:                    // object)
602:                    if (e.getClickCount() == 2)
603:                        fBoundaries = BreakIterator.getWordInstance();
604:                    else if (e.getClickCount() == 3)
605:                        fBoundaries = BreakIterator.getSentenceInstance();
606:                    else
607:                        fBoundaries = null;
608:
609:                    // if we're using a BreakIterator object, use it to find the nearest boundaries
610:                    // on either side of the mouse-click position and make them our anchor range
611:                    if (fBoundaries != null)
612:                        fBoundaries.setText(fText.createCharacterIterator());
613:
614:                    anchorStart.assign(current);
615:                    advanceToPreviousBoundary(anchorStart);
616:                    anchorEnd.assign(current);
617:                    advanceToNextBoundary(anchorEnd);
618:                }
619:
620:                // if we _are_ extending the selection, determine our anchor range as follows:
621:                // fAnchor is the start of the anchor range;
622:                // the next boundary (after fAnchor) is the limit of the anchor range.
623:
624:                else {
625:
626:                    if (fBoundaries != null)
627:                        fBoundaries.setText(fText.createCharacterIterator());
628:
629:                    anchorStart.assign(fAnchor);
630:                    anchorEnd.assign(anchorStart);
631:
632:                    advanceToNextBoundary(anchorEnd);
633:                }
634:
635:                SelectionDragInteractor interactor = new SelectionDragInteractor(
636:                        this , fTextComponent, fRunStrategy, anchorStart,
637:                        anchorEnd, current, x, y, wasZeroLength);
638:
639:                interactor.addToOwner(fTextComponent);
640:
641:                return true;
642:            }
643:
644:            public boolean mouseReleased(MouseEvent e) {
645:
646:                fPendingMouseEvent = null;
647:                return false;
648:            }
649:
650:            // drag interactor calls this
651:            void mouseReleased(boolean zeroLengthChange) {
652:
653:                fMouseDown = false;
654:
655:                if (zeroLengthChange) {
656:                    fListener
657:                            .textStateChanged(TextPanelEvent.SELECTION_EMPTY_CHANGED);
658:                }
659:                fListener
660:                        .textStateChanged(TextPanelEvent.SELECTION_RANGE_CHANGED);
661:                fListener
662:                        .textStateChanged(TextPanelEvent.SELECTION_STYLES_CHANGED);
663:
664:                // if caret drawing during mouse drags is supressed, draw caret now.
665:
666:                restartCaretBlinking(true);
667:            }
668:
669:            /** draws the selection
670:             * Provided, of course, that the selection is visible, the adorner is enabled,
671:             * and we're calling it to adorn the view it actually belongs to
672:             * @param g The graphics environment to draw into
673:             * @return true if we actually drew
674:             */
675:            public boolean paint(Graphics g, Rectangle drawRect) {
676:                // don't draw anything unless we're enabled and the selection is visible
677:                if (!enabled())
678:                    return false;
679:
680:                fTextComponent.drawText(g, drawRect, true, fStart, fLimit,
681:                        fHighlightColor);
682:                return true;
683:            }
684:
685:            /** scrolls the view to reveal the live end of the selection
686:             * (i.e., the end that moves if you use the arrow keys with the shift key down)
687:             */
688:            public void scrollToShowSelection() {
689:                Rectangle selRect = fTextComponent.getBoundingRect(fStart,
690:                        fLimit);
691:
692:                fTextComponent.scrollToShow(selRect);
693:            }
694:
695:            /** scrolls the view to reveal the live end of the selection
696:             * (i.e., the end that moves if you use the arrow keys with the shift key down)
697:             */
698:            public void scrollToShowSelectionEnd() {
699:                TextOffset liveEnd;
700:                // variable not used Point[]     points;
701:                Rectangle caret;
702:
703:                if (fAnchor.equals(fStart))
704:                    liveEnd = fLimit;
705:                else
706:                    liveEnd = fStart;
707:
708:                //points = fTextComponent.textOffsetToPoint(liveEnd);
709:                //caret = new Rectangle(points[0]);
710:                //caret = caret.union(new Rectangle(points[1]));
711:                caret = fTextComponent.getCaretRect(liveEnd);
712:                fTextComponent.scrollToShow(caret);
713:            }
714:
715:            private void select(TextRange range) {
716:                // variable not used int textLength = fTextComponent.getText().length();
717:
718:                TextOffset start = new TextOffset(range.start);
719:
720:                stopCaretBlinking();
721:                setSelRangeAndDraw(start, new TextOffset(range.limit), start);
722:                restartCaretBlinking(true);
723:            }
724:
725:            public void setHighlightColor(Color newColor) {
726:                fHighlightColor = newColor;
727:                if (enabled())
728:                    drawSelection(fTextComponent.getGraphics(), true);
729:            }
730:
731:            static boolean rangeIsZeroLength(TextOffset start,
732:                    TextOffset limit, TextOffset anchor) {
733:
734:                return start.fOffset == limit.fOffset
735:                        && anchor.fOffset == limit.fOffset;
736:            }
737:
738:            // sigh... look out for aliasing
739:            public void setSelectionRange(TextOffset newStart,
740:                    TextOffset newLimit, TextOffset newAnchor) {
741:
742:                boolean zeroLengthChange = rangeIsZeroLength(newStart,
743:                        newLimit, newAnchor) != rangeIsZeroLength(fStart,
744:                        fLimit, fAnchor);
745:                TextOffset tempNewAnchor;
746:                if (newAnchor == fStart || newAnchor == fLimit) {
747:                    tempNewAnchor = new TextOffset(newAnchor); // clone in case of aliasing
748:                } else {
749:                    tempNewAnchor = newAnchor;
750:                }
751:
752:                // DEBUG {jbr}
753:
754:                if (newStart.greaterThan(newLimit))
755:                    throw new IllegalArgumentException(
756:                            "Selection limit is before selection start.");
757:
758:                if (newLimit != fStart) {
759:                    fStart.assign(newStart);
760:                    fLimit.assign(newLimit);
761:                } else {
762:                    fLimit.assign(newLimit);
763:                    fStart.assign(newStart);
764:                }
765:
766:                fAnchor.assign(tempNewAnchor);
767:
768:                if (fStart.fOffset == fLimit.fOffset) {
769:                    fStart.fPlacement = fAnchor.fPlacement;
770:                    fLimit.fPlacement = fAnchor.fPlacement;
771:                }
772:
773:                if (!fMouseDown) {
774:                    if (zeroLengthChange) {
775:                        fListener
776:                                .textStateChanged(TextPanelEvent.SELECTION_EMPTY_CHANGED);
777:                    }
778:                    fListener
779:                            .textStateChanged(TextPanelEvent.SELECTION_RANGE_CHANGED);
780:                    if (fHandlingKeyOrCommand) {
781:                        fListener
782:                                .textStateChanged(TextPanelEvent.SELECTION_STYLES_CHANGED);
783:                    }
784:                }
785:            }
786:
787:            private void sortOffsets(TextOffset offsets[]) {
788:
789:                int i, j;
790:
791:                for (i = 0; i < offsets.length - 1; i++) {
792:                    for (j = i + 1; j < offsets.length; j++) {
793:                        if (offsets[j].lessThan(offsets[i])) {
794:                            TextOffset temp = offsets[j];
795:                            offsets[j] = offsets[i];
796:                            offsets[i] = temp;
797:                        }
798:                    }
799:                }
800:
801:                // DEBUG {jbr}
802:                for (i = 0; i < offsets.length - 1; i++)
803:                    if (offsets[i].greaterThan(offsets[i + 1]))
804:                        throw new Error("sortOffsets failed!");
805:            }
806:
807:            private Rectangle getSelectionChangeRect(TextOffset rangeStart,
808:                    TextOffset rangeLimit, TextOffset oldStart,
809:                    TextOffset oldLimit, TextOffset newStart,
810:                    TextOffset newLimit, boolean drawIfInsPoint) {
811:
812:                if (!rangeStart.equals(rangeLimit))
813:                    return fTextComponent.getBoundingRect(rangeStart,
814:                            rangeLimit);
815:
816:                // here, rangeStart and rangeLimit are equal
817:
818:                if (rangeStart.equals(oldLimit)) {
819:
820:                    // range start is OLD insertion point.  Redraw if caret is currently visible.
821:
822:                    if (fCaretIsVisible)
823:                        return fTextComponent.getBoundingRect(rangeStart,
824:                                rangeStart);
825:                } else if (rangeStart.equals(newLimit)) {
826:
827:                    // range start is NEW insertion point.
828:
829:                    if (drawIfInsPoint)
830:                        return fTextComponent.getBoundingRect(rangeStart,
831:                                rangeStart);
832:                }
833:
834:                return null;
835:            }
836:
837:            private static boolean rectanglesOverlapVertically(Rectangle r1,
838:                    Rectangle r2) {
839:
840:                if (r1 == null || r2 == null) {
841:                    return false;
842:                }
843:
844:                return r1.y <= r2.y + r2.height || r2.y <= r1.y + r1.height;
845:            }
846:
847:            // Update to show new selection, redrawing as little as possible
848:
849:            private void updateSelectionDisplay(TextOffset oldStart,
850:                    TextOffset oldLimit, TextOffset newStart,
851:                    TextOffset newLimit, boolean drawIfInsPoint) {
852:
853:                //System.out.println("newStart:" + newStart + "; newLimit:" + newLimit);
854:
855:                TextOffset off[] = new TextOffset[4];
856:
857:                off[0] = oldStart;
858:                off[1] = oldLimit;
859:                off[2] = newStart;
860:                off[3] = newLimit;
861:
862:                sortOffsets(off);
863:
864:                Rectangle r1 = getSelectionChangeRect(off[0], off[1], oldStart,
865:                        oldLimit, newStart, newLimit, drawIfInsPoint);
866:                Rectangle r2 = getSelectionChangeRect(off[2], off[3], oldStart,
867:                        oldLimit, newStart, newLimit, drawIfInsPoint);
868:
869:                boolean drawSelection = drawIfInsPoint
870:                        || !newStart.equals(newLimit);
871:
872:                if (rectanglesOverlapVertically(r1, r2)) {
873:
874:                    fTextComponent.drawText(fTextComponent.getGraphics(), r1
875:                            .union(r2), drawSelection, newStart, newLimit,
876:                            fHighlightColor);
877:                } else {
878:                    if (r1 != null)
879:                        fTextComponent.drawText(fTextComponent.getGraphics(),
880:                                r1, drawSelection, newStart, newLimit,
881:                                fHighlightColor);
882:                    if (r2 != null)
883:                        fTextComponent.drawText(fTextComponent.getGraphics(),
884:                                r2, drawSelection, newStart, newLimit,
885:                                fHighlightColor);
886:                }
887:            }
888:
889:            public void setSelRangeAndDraw(TextOffset newStart,
890:                    TextOffset newLimit, TextOffset newAnchor) {
891:
892:                // if the old and new selection ranges are the same, don't do anything
893:                if (fStart.equals(newStart) && fLimit.equals(newLimit)
894:                        && fAnchor.equals(newAnchor))
895:                    return;
896:
897:                if (enabled())
898:                    stopCaretBlinking();
899:
900:                // update the selection on screen if we're enabled and visible
901:
902:                TextOffset oldStart = new TextOffset(fStart), oldLimit = new TextOffset(
903:                        fLimit);
904:
905:                setSelectionRange(newStart, newLimit, newAnchor);
906:
907:                if (enabled()) {
908:
909:                    // To supress drawing a caret during a mouse drag, pass !fMouseDown instead of true:
910:                    updateSelectionDisplay(oldStart, oldLimit, fStart, fLimit,
911:                            true);
912:                }
913:
914:                if (!fMouseDown && enabled())
915:                    restartCaretBlinking(true);
916:            }
917:
918:            public void stopCaretBlinking() {
919:
920:                synchronized (this ) {
921:                    fCaretShouldBlink = false;
922:                }
923:            }
924:
925:            /**
926:             * Resume blinking the caret, if the selection is an insertion point.
927:             * @param caretIsVisible true if the caret is displayed when this is called.
928:             * This method relies on the client to display (or not display) the caret.
929:             */
930:            public void restartCaretBlinking(boolean caretIsVisible) {
931:
932:                synchronized (this ) {
933:                    fCaretShouldBlink = fStart.equals(fLimit);
934:                    fCaretCount = 0;
935:                    fCaretIsVisible = caretIsVisible;
936:
937:                    if (fCaretShouldBlink) {
938:                        try {
939:                            notify();
940:                        } catch (IllegalMonitorStateException e) {
941:                            System.out
942:                                    .println("Caught IllegalMonitorStateException: "
943:                                            + e);
944:                        }
945:                    }
946:                }
947:            }
948:
949:            public void removeFromOwner() {
950:
951:                stopCaretBlinking();
952:                super.removeFromOwner();
953:            }
954:
955:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.