KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > gjt > sp > jedit > textarea > InputMethodSupport


1 /*
2  * InputMethodSupport.java - Input method support for JEditTextArea
3  *
4  * :tabSize=8:indentSize=8:noTabs=false:
5  * :folding=explicit:collapseFolds=1:
6  *
7  * Copyright (C) 2006 Kazutoshi Satoda
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22  */

23
24 package org.gjt.sp.jedit.textarea;
25
26 // {{{ Imports
27
import java.text.AttributedString JavaDoc;
28 import java.text.AttributedCharacterIterator JavaDoc;
29 import java.awt.Point JavaDoc;
30 import java.awt.Rectangle JavaDoc;
31 import java.awt.Graphics2D JavaDoc;
32 import java.awt.FontMetrics JavaDoc;
33 import java.awt.im.InputMethodRequests JavaDoc;
34 import java.awt.event.InputMethodListener JavaDoc;
35 import java.awt.event.InputMethodEvent JavaDoc;
36 import java.awt.font.TextLayout JavaDoc;
37 import java.awt.font.TextAttribute JavaDoc;
38 import java.awt.font.TextHitInfo JavaDoc;
39 // }}}
40

41 /**
42  * Input method support for JEditTextArea
43  *
44  * @author Kazutoshi Satoda
45  * @since jEdit 4.3pre7
46  */

47
48 class InputMethodSupport
49     extends TextAreaExtension
50     implements InputMethodRequests JavaDoc, InputMethodListener JavaDoc
51 {
52     // The owner.
53
private TextArea owner;
54     // The composed text layout which was built from last InputMethodEvent.
55
private TextLayout JavaDoc composedTextLayout = null;
56     // The X offset to the caret in the composed text.
57
private int composedCaretX = 0;
58     // Last committed information to support cancelLatestCommittedText()
59
private int lastCommittedAt = 0;
60     private String JavaDoc lastCommittedText = null;
61
62     public InputMethodSupport(TextArea owner)
63     {
64         this.owner = owner;
65         owner.addInputMethodListener(this);
66         owner.getPainter().addExtension(TextAreaPainter.HIGHEST_LAYER, this);
67     }
68
69
70     // {{{ Private utilities
71
// Compute return value of getTextLocation() from (x, y).
72
private Rectangle JavaDoc getCaretRectangle(int x, int y)
73     {
74         TextAreaPainter painter = owner.getPainter();
75         Point JavaDoc origin = painter.getLocationOnScreen();
76         int height = painter.getFontMetrics().getHeight();
77         return new Rectangle JavaDoc(origin.x + x, origin.y + y, 0, height);
78     }
79     // }}}
80

81
82     // {{{ extends TextAreaExtension
83
public void paintValidLine(Graphics2D JavaDoc gfx, int screenLine,
84                    int physicalLine, int start, int end, int y)
85     {
86         if(composedTextLayout != null)
87         {
88             int caret = owner.getCaretPosition();
89             if(start <= caret && caret < end)
90             {
91                 TextAreaPainter painter = owner.getPainter();
92                 // The hight and baseline are taken from
93
// painter's FontMetrics instead of TextLayout
94
// so that the composed text is rendered at
95
// the same position with text in the TextArea.
96
FontMetrics JavaDoc fm = painter.getFontMetrics();
97                 int x = owner.offsetToXY(caret).x;
98                 int width = Math.round(composedTextLayout.getAdvance());
99                 int height = fm.getHeight();
100                 int offset_to_baseline = height
101                     - fm.getLeading() - fm.getDescent();
102                 int caret_x = x + composedCaretX;
103
104                 gfx.setColor(painter.getBackground());
105                 gfx.fillRect(x, y, width, height);
106                 gfx.setColor(painter.getForeground());
107                 composedTextLayout.draw(gfx, x, y + offset_to_baseline);
108                 gfx.setColor(painter.getCaretColor());
109                 gfx.drawLine(caret_x, y, caret_x, y + height - 1);
110             }
111         }
112     }
113     // }}}
114

115
116     // {{{ implements InputMethodRequests
117
public Rectangle JavaDoc getTextLocation(TextHitInfo JavaDoc offset)
118     {
119         if(composedTextLayout != null)
120         {
121             // return location of composed text.
122
Point JavaDoc caret = owner.offsetToXY(owner.getCaretPosition());
123             return getCaretRectangle(caret.x + composedCaretX, caret.y);
124         }
125         else
126         {
127             // return location of selected text.
128
Selection selection_on_caret = owner.getSelectionAtOffset(owner.getCaretPosition());
129             if(selection_on_caret != null)
130             {
131                 Point JavaDoc selection_start = owner.offsetToXY(selection_on_caret.getStart());
132                 return getCaretRectangle(selection_start.x, selection_start.y);
133             }
134         }
135         return null;
136     }
137
138     public TextHitInfo JavaDoc getLocationOffset(int x, int y)
139     {
140         if(composedTextLayout != null)
141         {
142             Point JavaDoc origin = owner.getPainter().getLocationOnScreen();
143             Point JavaDoc caret = owner.offsetToXY(owner.getCaretPosition());
144             float local_x = x - origin.x - caret.x;
145             float local_y = y - origin.y - caret.y
146                 - composedTextLayout.getLeading()
147                 - composedTextLayout.getAscent();
148             return composedTextLayout.hitTestChar(local_x, local_y);
149         }
150         return null;
151     }
152
153     public int getInsertPositionOffset()
154     {
155         return owner.getCaretPosition();
156     }
157
158     public AttributedCharacterIterator JavaDoc getCommittedText(int beginIndex , int endIndex
159         , AttributedCharacterIterator.Attribute JavaDoc[] attributes)
160     {
161         return (new AttributedString JavaDoc(owner.getText(beginIndex, endIndex - beginIndex))).getIterator();
162     }
163
164     public int getCommittedTextLength()
165     {
166         return owner.getBufferLength();
167     }
168
169     public AttributedCharacterIterator JavaDoc cancelLatestCommittedText(AttributedCharacterIterator.Attribute JavaDoc[] attributes)
170     {
171         if(lastCommittedText != null)
172         {
173             int offset = lastCommittedAt;
174             int length = lastCommittedText.length();
175             String JavaDoc sample = owner.getText(offset, length);
176             if(sample != null && sample.equals(lastCommittedText))
177             {
178                 AttributedCharacterIterator JavaDoc canceled = (new AttributedString JavaDoc(sample)).getIterator();
179                 owner.getBuffer().remove(offset, length);
180                 owner.setCaretPosition(offset);
181                 lastCommittedText = null;
182                 return canceled;
183             }
184             // Cleare last committed information to prevent
185
// accidental match.
186
lastCommittedText = null;
187         }
188         return null;
189     }
190
191     public AttributedCharacterIterator JavaDoc getSelectedText(AttributedCharacterIterator.Attribute JavaDoc[] attributes)
192     {
193         Selection selection_on_caret = owner.getSelectionAtOffset(owner.getCaretPosition());
194         if(selection_on_caret != null)
195         {
196             return (new AttributedString JavaDoc(owner.getSelectedText(selection_on_caret))).getIterator();
197         }
198         return null;
199     }
200     // }}}
201

202
203     // {{{ implements InputMethodListener
204
public void inputMethodTextChanged(InputMethodEvent JavaDoc event)
205     {
206         composedTextLayout = null;
207         AttributedCharacterIterator JavaDoc text = event.getText();
208         if(text != null)
209         {
210             int committed_count = event.getCommittedCharacterCount();
211             if(committed_count > 0)
212             {
213                 lastCommittedText = null;
214                 lastCommittedAt = owner.getCaretPosition();
215                 StringBuffer JavaDoc committed = new StringBuffer JavaDoc(committed_count);
216                 char c;
217                 int count;
218                 for(c = text.first(), count = committed_count
219                     ; c != AttributedCharacterIterator.DONE && count > 0
220                     ; c = text.next(), --count)
221                 {
222                     owner.userInput(c);
223                     committed.append(c);
224                 }
225                 lastCommittedText = committed.toString();
226             }
227             int end_index = text.getEndIndex();
228             if(committed_count < end_index)
229             {
230                 AttributedString JavaDoc composed = new AttributedString JavaDoc(text, committed_count, end_index);
231                 TextAreaPainter painter = owner.getPainter();
232                 composed.addAttribute(TextAttribute.FONT, painter.getFont());
233                 composedTextLayout = new TextLayout JavaDoc(composed.getIterator()
234                     , painter.getFontRenderContext());
235             }
236         }
237         // Also updates caret.
238
caretPositionChanged(event);
239     }
240
241     public void caretPositionChanged(InputMethodEvent JavaDoc event)
242     {
243         composedCaretX = 0;
244         if(composedTextLayout != null)
245         {
246             TextHitInfo JavaDoc caret = event.getCaret();
247             if(caret != null)
248             {
249                 composedCaretX = Math.round(composedTextLayout.getCaretInfo(caret)[0]);
250             }
251             // Adjust visiblity.
252
int insertion_x = owner.offsetToXY(owner.getCaretPosition()).x;
253             TextHitInfo JavaDoc visible = event.getVisiblePosition();
254             int composed_visible_x = (visible != null)
255                 ? Math.round(composedTextLayout.getCaretInfo(visible)[0])
256                 : composedCaretX;
257             int visible_x = insertion_x + composed_visible_x;
258             int painter_width = owner.getPainter().getWidth();
259             int adjustment = 0;
260             if(visible_x < 0)
261             {
262                 adjustment = visible_x;
263             }
264             if(visible_x >= painter_width)
265             {
266                 adjustment = visible_x - (painter_width - 1);
267             }
268             if(adjustment != 0)
269             {
270                 owner.setHorizontalOffset(owner.getHorizontalOffset() - adjustment);
271             }
272         }
273         else
274         {
275             /* Cancel horizontal adjustment for composed text.
276                FIXME:
277                  The horizontal offset may be beyond the max
278                  value of owner's horizontal scroll bar.
279             */

280             owner.scrollToCaret(false);
281         }
282         /* Invalidate one more line below the caret because
283            the underline for composed text goes beyond the caret
284            line in some font settings. */

285         int caret_line = owner.getCaretLine();
286         owner.invalidateLineRange(caret_line, caret_line + 1);
287         event.consume();
288     }
289     // }}}
290
}
291
Popular Tags