• R/O
  • SSH
  • HTTPS

sweep: Commit


Commit MetaInfo

Revision50 (tree)
Time2022-08-13 16:00:00
Authoriwao

Log Message

日本語テキストの入力がインラインで行われるように調整

Change Summary

Incremental Difference

--- branches/client/kfc2/src/main/java/jp/kyasu/awt/AWTResources.java (nonexistent)
+++ branches/client/kfc2/src/main/java/jp/kyasu/awt/AWTResources.java (revision 50)
@@ -0,0 +1,340 @@
1+/*
2+ * AWTResources.java
3+ *
4+ * Copyright (c) 1997, 1998, 1999 Kazuki YASUMATSU. All Rights Reserved.
5+ *
6+ * Permission to use, copy, modify, and distribute this software and its
7+ * documentation for any purpose and without fee or royalty is hereby
8+ * granted, provided that both the above copyright notice and this
9+ * permission notice appear in all copies of the software and
10+ * documentation or portions thereof, including modifications, that you
11+ * make.
12+ *
13+ * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO
14+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE,
15+ * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR
16+ * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
17+ * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
18+ * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
19+ * COPYRIGHT HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE
20+ * OR DOCUMENTATION.
21+ */
22+
23+package jp.kyasu.awt;
24+
25+import jp.kyasu.graphics.VImage;
26+
27+import java.awt.Color;
28+import java.awt.Component;
29+import java.awt.Container;
30+import java.awt.Font;
31+
32+/**
33+ * The <code>AWTResources</code> class provides the resources shared in
34+ * this package.
35+ *
36+ * @version 20 Nov 1999
37+ * @author Kazuki YASUMATSU
38+ */
39+public class AWTResources {
40+
41+ // ======== Resource Handling ========
42+
43+ static final protected jp.kyasu.util.Resources Resources =
44+ new jp.kyasu.util.Resources("jp.kyasu.awt.resources.awt");
45+
46+ /**
47+ * Returns the resource string indicated by the specified key.
48+ *
49+ * @param key the name of the resource.
50+ * @return the string value of the resource, or <code>null</code>
51+ * if there is no resource with that key.
52+ */
53+ static public String getResourceString(String key) {
54+ return Resources.getResourceString(key);
55+ }
56+
57+ /**
58+ * Returns the resource string indicated by the specified key.
59+ *
60+ * @param key the name of the resource.
61+ * @param def a default value.
62+ * @return the string value of the resource, or the default value
63+ * if there is no resource with that key.
64+ */
65+ static public String getResourceString(String key, String def) {
66+ return Resources.getResourceString(key, def);
67+ }
68+
69+ /**
70+ * Returns the resource integer indicated by the specified key.
71+ *
72+ * @param key the name of the resource.
73+ * @param def a default integer.
74+ * @return the integer value of the resource, or the default integer
75+ * if there is no resource with that key.
76+ */
77+ static public int getResourceInteger(String key, int def) {
78+ return Resources.getResourceInteger(key, def);
79+ }
80+
81+ /**
82+ * Returns the resource boolean indicated by the specified key.
83+ *
84+ * @param key the name of the resource.
85+ * @param def a default boolean.
86+ * @return the boolean value of the resource, or the default boolean
87+ * if there is no resource with that key.
88+ */
89+ static public boolean getResourceBoolean(String key, boolean def) {
90+ return Resources.getResourceBoolean(key, def);
91+ }
92+
93+ /**
94+ * Returns the resource color indicated by the specified key.
95+ *
96+ * @param key the name of the resource.
97+ * @param def a default color.
98+ * @return the color value of the resource, or the default color
99+ * if there is no resource with that key.
100+ */
101+ static public Color getResourceColor(String key, Color def) {
102+ return Resources.getResourceColor(key, def);
103+ }
104+
105+ /** The default null icon. */
106+ static protected VImage NULL_ICON = new VImage(new byte[]{
107+ (byte)0x47, (byte)0x49, (byte)0x46, (byte)0x38, (byte)0x39,
108+ (byte)0x61, (byte)0x10, (byte)0x00, (byte)0x10, (byte)0x00,
109+ (byte)0x80, (byte)0x00, (byte)0x00, (byte)0xFF, (byte)0xFF,
110+ (byte)0xFF, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x21,
111+ (byte)0xF9, (byte)0x04, (byte)0x01, (byte)0x00, (byte)0x00,
112+ (byte)0x00, (byte)0x00, (byte)0x2C, (byte)0x00, (byte)0x00,
113+ (byte)0x00, (byte)0x00, (byte)0x10, (byte)0x00, (byte)0x10,
114+ (byte)0x00, (byte)0x00, (byte)0x02, (byte)0x0E, (byte)0x84,
115+ (byte)0x8F, (byte)0xA9, (byte)0xCB, (byte)0xED, (byte)0x0F,
116+ (byte)0xA3, (byte)0x9C, (byte)0xB4, (byte)0xDA, (byte)0x8B,
117+ (byte)0xB3, (byte)0x3E, (byte)0x05, (byte)0x00, (byte)0x3B
118+ });
119+
120+ /**
121+ * Returns the resource icon indicated by the specified class and file.
122+ *
123+ * @param baseClass the base class.
124+ * @param file a file name.
125+ * @return the icon of the resource, or the default null icon
126+ * if there is no resource with that key.
127+ */
128+ static public VImage getIcon(Class baseClass, String file) {
129+ if (baseClass == null || file == null)
130+ return NULL_ICON;
131+
132+ /*
133+ java.net.URL url = baseClass.getResource(file);
134+ if (url == null) {
135+ return NULL_ICON;
136+ }
137+ return new VImage(url);
138+ */
139+
140+ /* Copy resource into a byte array. This is necessary because
141+ * several browsers consider Class.getResource a security risk
142+ * because it can be used to load additional classes.
143+ * Class.getResourceAsStream just returns raw bytes, which we
144+ * can convert to an image.
145+ */
146+ try {
147+ java.io.InputStream resource =
148+ baseClass.getResourceAsStream(file);
149+ if (resource == null) {
150+ return NULL_ICON;
151+ }
152+ java.io.BufferedInputStream in =
153+ new java.io.BufferedInputStream(resource);
154+ java.io.ByteArrayOutputStream out =
155+ new java.io.ByteArrayOutputStream(1024);
156+ byte[] buffer = new byte[1024];
157+ int n;
158+ while ((n = in.read(buffer)) > 0) {
159+ out.write(buffer, 0, n);
160+ }
161+ in.close();
162+ out.flush();
163+ buffer = out.toByteArray();
164+ if (buffer.length == 0) {
165+ return NULL_ICON;
166+ }
167+ return new VImage(buffer);
168+ }
169+ catch (java.io.IOException e) {
170+ return NULL_ICON;
171+ }
172+ }
173+
174+
175+ // ======== Default Color ========
176+
177+ /**
178+ * The default foreground color.
179+ */
180+ static public final Color FOREGROUND_COLOR =
181+ getResourceColor("kfc.foreground", Color.black);
182+
183+ /**
184+ * The default background color.
185+ */
186+ static public final Color BACKGROUND_COLOR =
187+ getResourceColor("kfc.background", Color.lightGray);
188+
189+
190+ // ======== Double Buffer ========
191+
192+ /**
193+ * The default double buffer policy.
194+ */
195+ static public boolean USE_DOUBLE_BUFFER =
196+ (System.getProperty("java.version").compareTo("1.2") >= 0);
197+
198+
199+ /*if[JDK1.2]*/
200+
201+ // ======== Default Rendering Hint Map ========
202+
203+ /**
204+ * The default rendering hint map.
205+ */
206+ /*if[JDK1.2]*/
207+ static public final java.util.Map RENDERING_HINTS = new java.util.HashMap();
208+
209+ /*end[JDK1.2]*/
210+
211+
212+ // ======== Event Dispatching for Notifying Listeners ========
213+
214+ /**
215+ * If true, notifies listeners directly without using the event queue.
216+ */
217+ static public boolean IS_DIRECT_NOTIFICATION =
218+ (System.getProperty("java.version").compareTo("1.1.5") >= 0) ||
219+ getResourceBoolean("kfc.directNotification", false);
220+
221+
222+ // ======== JDK Bug Workaround ========
223+
224+ /** True if the JVM runs on Windows 95/NT. */
225+ static protected final boolean ON_WINDOWS =
226+ System.getProperty("os.name").startsWith("Windows");
227+
228+ /**
229+ * True if the JDK has the
230+ * <code>sun.awt.windows.WWindowPeer#getFocusPeer()</code> bug.
231+ * <p>
232+ * Because of this bug, if a lightwight component is focus traversable,
233+ * an application will be hung up.
234+ * <p>
235+ * This bug has been fixed from JDK1.1.5.
236+ */
237+ static public boolean HAS_FOCUS_BUG =
238+ ON_WINDOWS &&
239+ (System.getProperty("java.version").compareTo("1.1.4") <= 0);
240+
241+ /**
242+ * True if a pop-up window can receive the events even when the pop-up
243+ * window is opend within a modal dialog.
244+ */
245+ static public boolean CAN_OPEN_POPUP_IN_MODAL_DIALOG = ON_WINDOWS;
246+
247+ /**
248+ * True if the JDK has the <code>java.awt.Graphics#copyArea()</code> bug.
249+ * <p>
250+ * This bug has arised from JDK1.2.
251+ */
252+ static public boolean HAS_COPY_AREA_BUG =
253+ (System.getProperty("java.version").compareTo("1.2") >= 0);
254+
255+ /**
256+ * Checks the component state for the specified component.
257+ * <p>
258+ * If <code>HAS_FOCUS_BUG</code> is true, an application should use
259+ * jp.kyasu.awt.{Dialog,Frame,Window} instead of
260+ * java.awt.{Dialog,Frame,Window}.
261+ * <p>
262+ * If a top frame has a menu bar on windows, an application should
263+ * wrap a lightweight component in a native component, so that pop-up
264+ * menu and <code>getLocationOnScreen()</code> work correctly.
265+ *
266+ * @exception java.awt.IllegalComponentStateException if the component
267+ * state is illegal.
268+ */
269+ static public void checkComponentState(Component comp) {
270+ if (!ON_WINDOWS)
271+ return;
272+ boolean inNativeContainer = false;
273+ for (Container c = comp.getParent(); c != null; c = c.getParent()) {
274+ if (c instanceof java.awt.Window) {
275+ if (HAS_FOCUS_BUG) {
276+ if (!(c instanceof jp.kyasu.awt.Dialog ||
277+ c instanceof jp.kyasu.awt.Frame ||
278+ c instanceof jp.kyasu.awt.Window))
279+ {
280+ /* Make applets happy.
281+ throw new java.awt.IllegalComponentStateException(
282+ "jp.kyasu.awt.{Dialog,Frame,Window} should be used instead of java.awt.{Dialog,Frame,Window} for the AWT focusing bug.");
283+ */
284+ }
285+ }
286+ if (c instanceof java.awt.Frame) {
287+ if (!inNativeContainer &&
288+ ((java.awt.Frame)c).getMenuBar() != null)
289+ {
290+ throw new java.awt.IllegalComponentStateException(
291+ "A lightweight component should be wrappend in a native component for the AWT menu bar bug.");
292+ }
293+ }
294+ return;
295+ }
296+ if (!(c.getPeer() instanceof java.awt.peer.LightweightPeer)) {
297+ inNativeContainer = true;
298+ }
299+ }
300+ }
301+
302+ /** The lock for the foucusing bug workaround. */
303+ static protected final Object FOCUS_LOCK = new Object();
304+
305+ /** The state for the foucusing bug workaround. */
306+ static protected boolean IN_REQUEST_FOCUS = false;
307+
308+ /**
309+ * The <code>Window#getFocusOwner()</code> workaround.
310+ *
311+ * @see jp.kyasu.awt.KComponent#requestFocus()
312+ * @see jp.kyasu.awt.KContainer#requestFocus()
313+ */
314+ static protected Component getFocusOwnerWorkaround(Component focus) {
315+ synchronized (FOCUS_LOCK) {
316+ if (focus == null) {
317+ return null;
318+ }
319+ else if (IN_REQUEST_FOCUS) {
320+ return focus;
321+ }
322+ else {
323+ return getNativeComponent(focus);
324+ }
325+ }
326+ }
327+
328+ /**
329+ * Returns the native component for the specified component.
330+ */
331+ static protected Component getNativeComponent(Component c) {
332+ if (!(c.getPeer() instanceof java.awt.peer.LightweightPeer))
333+ return c;
334+ for (Container p = c.getParent(); p != null; p = p.getParent()) {
335+ if (!(p.getPeer() instanceof java.awt.peer.LightweightPeer))
336+ return p;
337+ }
338+ return null;
339+ }
340+}
--- branches/client/kfc2/src/main/java/jp/kyasu/awt/KComponent.java (nonexistent)
+++ branches/client/kfc2/src/main/java/jp/kyasu/awt/KComponent.java (revision 50)
@@ -0,0 +1,662 @@
1+/*
2+ * KComponent.java
3+ *
4+ * Copyright (c) 1997, 1998, 1999 Kazuki YASUMATSU. All Rights Reserved.
5+ *
6+ * Permission to use, copy, modify, and distribute this software and its
7+ * documentation for any purpose and without fee or royalty is hereby
8+ * granted, provided that both the above copyright notice and this
9+ * permission notice appear in all copies of the software and
10+ * documentation or portions thereof, including modifications, that you
11+ * make.
12+ *
13+ * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO
14+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE,
15+ * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR
16+ * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
17+ * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
18+ * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
19+ * COPYRIGHT HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE
20+ * OR DOCUMENTATION.
21+ */
22+
23+package jp.kyasu.awt;
24+
25+import jp.kyasu.graphics.Text;
26+import jp.kyasu.graphics.Visualizable;
27+
28+import java.awt.AWTEvent;
29+import java.awt.Color;
30+import java.awt.Component;
31+import java.awt.Container;
32+import java.awt.Dimension;
33+import java.awt.Event;
34+import java.awt.Graphics;
35+import java.awt.Image;
36+import java.awt.Point;
37+import java.awt.Rectangle;
38+import java.awt.Toolkit;
39+import java.awt.event.ActionEvent;
40+import java.awt.event.AdjustmentEvent;
41+import java.awt.event.ItemEvent;
42+import java.awt.event.MouseEvent;
43+
44+/**
45+ * A KComponent is an object having a graphical representation
46+ * that can be displayed on the screen and that can interact with the
47+ * user.
48+ * <p>
49+ * The KComponent class is the abstract base class for all components
50+ * in this package.
51+ *
52+ * @version 20 Nov 1999
53+ * @author Kazuki YASUMATSU
54+ */
55+public abstract class KComponent extends java.awt.Component {
56+ /** The double buffering. */
57+ protected boolean doubleBuffered;
58+ transient protected Image offscreenBuffer;
59+
60+ /** True if the keyboard focus traversal is enabled. */
61+ protected boolean focusTraversable;
62+
63+ static protected Toolkit DefaultToolkit = Toolkit.getDefaultToolkit();
64+
65+
66+ protected KComponent() {
67+ setForeground(AWTResources.FOREGROUND_COLOR);
68+ setBackground(AWTResources.BACKGROUND_COLOR);
69+ doubleBuffered = AWTResources.USE_DOUBLE_BUFFER;
70+ offscreenBuffer = null;
71+ focusTraversable = true;
72+ }
73+
74+
75+ /**
76+ * Checks if this component should use a buffer to paint.
77+ */
78+ public boolean isDoubleBuffered() {
79+ return doubleBuffered;
80+ }
81+
82+ /**
83+ * Set whether this component should use a buffer to paint.
84+ * If set to true, all the drawing from this component will be done in
85+ * an offscreen painting buffer. The offscreen painting buffer will the
86+ * be copied onto the screen.
87+ */
88+ public void setDoubleBuffered(boolean b) {
89+ if (doubleBuffered == b)
90+ return;
91+ doubleBuffered = b;
92+ offscreenBuffer = null;
93+ }
94+
95+ /**
96+ * Checks if the keyboard focus traversal is enabled.
97+ */
98+ public boolean isFocusTraversable() {
99+ if (focusTraversable) {
100+ return super.isFocusTraversable();
101+ }
102+ return false;
103+ }
104+
105+ /**
106+ * Enables or disables the keyboard focus traversal.
107+ */
108+ public void setFocusTraversable(boolean b) {
109+ focusTraversable = b;
110+ }
111+
112+ /**
113+ * If true, notifies listeners directly without using the event queue.
114+ */
115+ public boolean isDirectNotification() {
116+ return AWTResources.IS_DIRECT_NOTIFICATION;
117+ }
118+
119+
120+ /**
121+ * Enables or disables this component.
122+ */
123+ public void setEnabled(boolean b) {
124+ if (b) {
125+ super.enable();
126+ }
127+ else {
128+ super.disable();
129+ }
130+ }
131+
132+ /** Enables this component. */
133+ public void enable() { setEnabled(true); }
134+
135+ /* Enables or disables this component. */
136+ public void enable(boolean b) { setEnabled(b); }
137+
138+ /** Disables this component. */
139+ public void disable() { setEnabled(false); }
140+
141+
142+ /**
143+ * Shows or hides this component.
144+ */
145+ public void setVisible(boolean b) {
146+ if (b) {
147+ super.show();
148+ }
149+ else {
150+ super.hide();
151+ }
152+ }
153+
154+ /* Shows this component. */
155+ public void show() { setVisible(true); }
156+
157+ /* Shows or hides this component. */
158+ public void show(boolean b) { setVisible(b); }
159+
160+ /* Hides this component. */
161+ public void hide() { setVisible(false); }
162+
163+
164+ /**
165+ * Returns the location of this component.
166+ */
167+ public Point getLocation() {
168+ return super.location();
169+ }
170+
171+ /** Returns the location of this component. */
172+ public Point location() { return getLocation(); }
173+
174+
175+ /**
176+ * Returns the size of this component.
177+ */
178+ public Dimension getSize() {
179+ return super.size();
180+ }
181+
182+ /** Returns the size of this component. */
183+ public Dimension size() { return getSize(); }
184+
185+
186+ /**
187+ * Returns the bounds of this component.
188+ */
189+ public Rectangle getBounds() {
190+ return super.bounds();
191+ }
192+
193+ /* Returns the bounds of this component. */
194+ public Rectangle bounds() { return getBounds(); }
195+
196+
197+ /**
198+ * Moves and resizes this component.
199+ */
200+ public void setBounds(int x, int y, int width, int height) {
201+ super.reshape(x, y, width, height);
202+ }
203+
204+ /** Moves and resizes this component. */
205+ public void reshape(int x, int y, int width, int height) {
206+ setBounds(x, y, width, height);
207+ }
208+
209+
210+ /**
211+ * Returns the preferred size of this component.
212+ */
213+ public Dimension getPreferredSize() {
214+ return super.preferredSize();
215+ }
216+
217+ /** Returns the preferred size of this component. */
218+ public Dimension preferredSize() { return getPreferredSize(); }
219+
220+
221+ /**
222+ * Returns the minimum size of this component.
223+ */
224+ public Dimension getMinimumSize() {
225+ return super.minimumSize();
226+ }
227+
228+ /** Returns the minimum size of this component. */
229+ public Dimension minimumSize() { return getMinimumSize(); }
230+
231+
232+ /**
233+ * Lays out this component.
234+ */
235+ public void doLayout() {
236+ super.layout();
237+ }
238+
239+ /** Lays out this component. */
240+ public void layout() { doLayout(); }
241+
242+
243+ /**
244+ * Sets the foreground color of this component.
245+ */
246+ public void setForeground(Color c) {
247+ super.setForeground(c);
248+ offscreenBuffer = null;
249+ }
250+
251+ /**
252+ * Sets the background color of this component.
253+ */
254+ public void setBackground(Color c) {
255+ super.setBackground(c);
256+ offscreenBuffer = null;
257+ }
258+
259+
260+ /**
261+ * Paints this component.
262+ */
263+ public void paint(Graphics g) {
264+ if (!isShowing())
265+ return;
266+
267+ Graphics pg = getPreferredGraphics(g);
268+ if (pg == null)
269+ return;
270+ paintOn(pg);
271+ if (pg != g) {
272+ pg.dispose();
273+ }
274+
275+ syncGraphics(g);
276+ }
277+
278+ /**
279+ * Paints this component on the specified graphics object.
280+ * All subclasses must override this method instead of paint().
281+ */
282+ protected void paintOn(Graphics g) {
283+ }
284+
285+ /**
286+ * Updates this component.
287+ */
288+ public void update(Graphics g) {
289+ paint(g);
290+ }
291+
292+ /**
293+ * Paints this component and all of its subcomponents immediately.
294+ */
295+ public void repaintNow() {
296+ if (isShowing()) {
297+ Graphics g = getGraphics();
298+ if (g == null)
299+ return;
300+ try {
301+ paint(g);
302+ }
303+ finally {
304+ g.dispose();
305+ }
306+ }
307+ }
308+
309+ /**
310+ * Synchronizes this graphics state.
311+ */
312+ public void syncGraphics() {
313+ if (offscreenBuffer != null && isShowing()) {
314+ Graphics g = getGraphics();
315+ //g.drawImage(offscreenBuffer, 0, 0, this);
316+ g.drawImage(offscreenBuffer, 0, 0, null);
317+ DefaultToolkit.sync();
318+ g.dispose();
319+ }
320+ }
321+
322+ /**
323+ * Synchronizes this graphics state with the specified clip rectangle.
324+ *
325+ * @param x the x coordinate of the rectangle to intersect the clip with
326+ * @param y the y coordinate of the rectangle to intersect the clip with
327+ * @param width the width of the rectangle to intersect the clip with
328+ * @param height the height of the rectangle to intersect the clip with
329+ */
330+ public void syncGraphics(int x, int y, int width, int height) {
331+ if (offscreenBuffer != null && isShowing()) {
332+ Graphics g = getGraphics();
333+ g.clipRect(x, y, width, height);
334+ //g.drawImage(offscreenBuffer, 0, 0, this);
335+ g.drawImage(offscreenBuffer, 0, 0, null);
336+ DefaultToolkit.sync();
337+ g.dispose();
338+ }
339+ }
340+
341+ /**
342+ * Synchronizes this graphics state on the specified graphics context.
343+ */
344+ public void syncGraphics(Graphics g) {
345+ if (offscreenBuffer != null) {
346+ //g.drawImage(offscreenBuffer, 0, 0, this);
347+ g.drawImage(offscreenBuffer, 0, 0, null);
348+ DefaultToolkit.sync();
349+ }
350+ }
351+
352+ /**
353+ * Creates a preferred graphics context for this component.
354+ */
355+ protected Graphics getPreferredGraphics() {
356+ return getPreferredGraphics(null);
357+ }
358+
359+ /**
360+ * Creates a preferred graphics context for this component with the
361+ * specified graphics context.
362+ */
363+ protected Graphics getPreferredGraphics(Graphics g) {
364+ Dimension d = getSize();
365+ if (d.width <= 0 || d.height <= 0)
366+ return null;
367+
368+ Graphics pg;
369+ if (!doubleBuffered) {
370+ if (g != null)
371+ pg = g;
372+ else
373+ pg = getGraphics();
374+ }
375+ else {
376+ if (offscreenBuffer == null ||
377+ offscreenBuffer.getWidth(null) != d.width ||
378+ offscreenBuffer.getHeight(null) != d.height)
379+ {
380+ offscreenBuffer = createImage(d.width, d.height);
381+ pg = offscreenBuffer.getGraphics();
382+ pg.setColor(getBackground());
383+ pg.fillRect(0, 0, d.width, d.height);
384+ }
385+ else {
386+ pg = offscreenBuffer.getGraphics();
387+ }
388+ }
389+
390+ Rectangle r = null;
391+ if (g != null)
392+ r = g.getClipBounds();
393+ if (r == null) {
394+ pg.setClip(0, 0, d.width, d.height);
395+ }
396+ else {
397+ if (r.x < 0) r.x = 0;
398+ if (r.y < 0) r.y = 0;
399+ if (r.width > d.width) r.width = d.width;
400+ if (r.height > d.height) r.height = d.height;
401+ pg.setClip(r.x, r.y, r.width, r.height);
402+ }
403+
404+ pg.setFont(getFont());
405+ pg.setColor(getForeground());
406+
407+ /*if[JDK1.2]
408+ if (!AWTResources.RENDERING_HINTS.isEmpty()) {
409+ java.awt.Graphics2D g2 = (java.awt.Graphics2D)pg;
410+ g2.setRenderingHints(AWTResources.RENDERING_HINTS);
411+ }
412+ /*end[JDK1.2]*/
413+
414+ return pg;
415+ }
416+
417+ /**
418+ * Requests that this component get the input focus.
419+ * <p>
420+ * For the <code>sun.awt.windows.WWindowPeer#getFocusPeer()</code> bug
421+ * (it exists in the JDK for Windows 95/NT version 1.1.4 or before),
422+ * if a lightwight component is focus traversable, an application will
423+ * be hung up.
424+ *
425+ * @see jp.kyasu.awt.AWTResources#HAS_FOCUS_BUG
426+ */
427+ public void requestFocus() {
428+ if (!AWTResources.HAS_FOCUS_BUG) {
429+ super.requestFocus();
430+ }
431+ else {
432+ synchronized (AWTResources.FOCUS_LOCK) {
433+ boolean save = AWTResources.IN_REQUEST_FOCUS;
434+ AWTResources.IN_REQUEST_FOCUS = true;
435+ super.requestFocus();
436+ AWTResources.IN_REQUEST_FOCUS = save;
437+ }
438+ }
439+ }
440+
441+ /**
442+ * Notifies this component that it has been added to a container
443+ * and if a peer is required, it should be created.
444+ * <p>
445+ * The component state is checked for avoiding the JDK bug.
446+ *
447+ * @see jp.kyasu.awt.AWTResources#checkComponentState(java.awt.Component)
448+ */
449+ public void addNotify() {
450+ super.addNotify();
451+ AWTResources.checkComponentState(this);
452+ }
453+
454+ /**
455+ * Returns the top fram of this component.
456+ */
457+ public java.awt.Frame getFrame() {
458+ for (Container c = getParent(); c != null; c = c.getParent()) {
459+ if (c instanceof java.awt.Frame)
460+ return (java.awt.Frame)c;
461+ }
462+ return null;
463+ }
464+
465+ /**
466+ * Posts a 1.0 style event.
467+ */
468+ protected void postOldEvent(AWTEvent e) {
469+ Object src = e.getSource();
470+ int newid = e.getID();
471+ Event oe = null;
472+
473+ switch(e.getID()) {
474+ case ActionEvent.ACTION_PERFORMED:
475+ ActionEvent ae = (ActionEvent)e;
476+ String cmd;
477+ if (src instanceof jp.kyasu.awt.Button) {
478+ cmd = ((jp.kyasu.awt.Button)src).getLabel();
479+ }
480+ else if (src instanceof java.awt.MenuItem) {
481+ cmd = ((java.awt.MenuItem)src).getLabel();
482+ }
483+ else {
484+ cmd = ae.getActionCommand();
485+ }
486+ oe = new Event(src, 0, newid, 0, 0, 0, ae.getModifiers(), cmd);
487+ break;
488+
489+ case ItemEvent.ITEM_STATE_CHANGED:
490+ ItemEvent ie = (ItemEvent)e;
491+ Object arg;
492+ if (src instanceof jp.kyasu.awt.List) {
493+ newid = (ie.getStateChange() == ItemEvent.SELECTED ?
494+ Event.LIST_SELECT : Event.LIST_DESELECT);
495+ arg = ie.getItem();
496+ }
497+ else {
498+ newid = Event.ACTION_EVENT;
499+ if (src instanceof jp.kyasu.awt.Choice) {
500+ arg = ie.getItem();
501+ }
502+ else { // Checkbox
503+ arg = new Boolean(ie.getStateChange()==ItemEvent.SELECTED);
504+ }
505+ }
506+ oe = new Event(src, newid, arg);
507+ break;
508+
509+ case AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED:
510+ AdjustmentEvent aje = (AdjustmentEvent)e;
511+ switch(aje.getAdjustmentType()) {
512+ case AdjustmentEvent.UNIT_INCREMENT:
513+ newid = Event.SCROLL_LINE_DOWN;
514+ break;
515+ case AdjustmentEvent.UNIT_DECREMENT:
516+ newid = Event.SCROLL_LINE_UP;
517+ break;
518+ case AdjustmentEvent.BLOCK_INCREMENT:
519+ newid = Event.SCROLL_PAGE_DOWN;
520+ break;
521+ case AdjustmentEvent.BLOCK_DECREMENT:
522+ newid = Event.SCROLL_PAGE_UP;
523+ break;
524+ case AdjustmentEvent.TRACK:
525+ newid = Event.SCROLL_ABSOLUTE;
526+ break;
527+ default:
528+ return;
529+ }
530+ oe = new Event(src, newid, new Integer(aje.getValue()));
531+ break;
532+ }
533+
534+ if (oe != null) {
535+ postEvent(oe);
536+ }
537+ }
538+
539+
540+ // ================ ToolTip ================
541+
542+ /**
543+ * The tooltip for this component.
544+ */
545+ protected ToolTip toolTip = null;
546+
547+
548+ /**
549+ * Return the tooltip string that has been set with
550+ * <code>setToolTipText()</code>.
551+ *
552+ * @return the string of the tool tip.
553+ */
554+ public String getToolTipText() {
555+ return (toolTip == null ? null : toolTip.getToolTipText());
556+ }
557+
558+ /**
559+ * Return the tooltip visual object that has been set with
560+ * <code>setToolTipVisual()</code>.
561+ *
562+ * @return the visual object of the tool tip.
563+ */
564+ public Visualizable getToolTipVisual() {
565+ return (toolTip == null ? null : toolTip.getToolTipVisual());
566+ }
567+
568+ /**
569+ * Registers the string to display in a ToolTip.
570+ *
571+ * @param string The string to display when the cursor lingers over the
572+ * component. If string is null, then it turns off tool tip
573+ * for this component.
574+ */
575+ public synchronized void setToolTipText(String string) {
576+ if (string == null) {
577+ toolTip.hidePopup();
578+ toolTip = null;
579+ }
580+ else {
581+ if (toolTip == null)
582+ toolTip = new ToolTip(string);
583+ else
584+ toolTip.setToolTipText(string);
585+ enableEvents(AWTEvent.MOUSE_EVENT_MASK);
586+ enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
587+ }
588+ }
589+
590+ /**
591+ * Registers the text object to display in a ToolTip.
592+ *
593+ * @param text The text object to display when the cursor lingers over
594+ * the component. If text is null, then it turns off tool
595+ * tip for this component.
596+ */
597+ public synchronized void setToolTipText(Text text) {
598+ if (text == null) {
599+ toolTip.hidePopup();
600+ toolTip = null;
601+ }
602+ else {
603+ if (toolTip == null)
604+ toolTip = new ToolTip(text);
605+ else
606+ toolTip.setToolTipText(text);
607+ enableEvents(AWTEvent.MOUSE_EVENT_MASK);
608+ enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
609+ }
610+ }
611+
612+ /**
613+ * Registers the visual object to display in a ToolTip.
614+ *
615+ * @param visual The visual object to display when the cursor lingers
616+ * over the component. If visual is null, then it turns
617+ * off tool tip for this component.
618+ */
619+ public synchronized void setToolTipVisual(Visualizable visual) {
620+ if (visual == null) {
621+ toolTip.hidePopup();
622+ toolTip = null;
623+ }
624+ else {
625+ if (toolTip == null)
626+ toolTip = new ToolTip(visual);
627+ else
628+ toolTip.setToolTipVisual(visual);
629+ enableEvents(AWTEvent.MOUSE_EVENT_MASK);
630+ enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
631+ }
632+ }
633+
634+
635+ protected void processMouseEvent(MouseEvent e) {
636+ if (toolTip != null) {
637+ switch (e.getID()) {
638+ case MouseEvent.MOUSE_ENTERED:
639+ toolTip.hidePopup();
640+ toolTip.showPopup(this, e.getX(), getSize().height + 2,
641+ ToolTip.TOOLTIP_DELAY);
642+ break;
643+ case MouseEvent.MOUSE_PRESSED:
644+ case MouseEvent.MOUSE_EXITED:
645+ toolTip.hidePopup();
646+ break;
647+ }
648+ }
649+ super.processMouseEvent(e);
650+ }
651+
652+ protected void processMouseMotionEvent(MouseEvent e) {
653+ if (toolTip != null) {
654+ switch (e.getID()) {
655+ case MouseEvent.MOUSE_MOVED:
656+ toolTip.setPopupLocationHint(e.getX(), getSize().height + 2);
657+ break;
658+ }
659+ }
660+ super.processMouseMotionEvent(e);
661+ }
662+}
--- branches/client/kfc2/src/main/java/jp/kyasu/awt/text/BasicTextEditController.java (nonexistent)
+++ branches/client/kfc2/src/main/java/jp/kyasu/awt/text/BasicTextEditController.java (revision 50)
@@ -0,0 +1,2745 @@
1+/*
2+ * BasicTextEditController.java
3+ *
4+ * Copyright (c) 1997, 1998 Kazuki YASUMATSU. All Rights Reserved.
5+ *
6+ * Permission to use, copy, modify, and distribute this software and its
7+ * documentation for any purpose and without fee or royalty is hereby
8+ * granted, provided that both the above copyright notice and this
9+ * permission notice appear in all copies of the software and
10+ * documentation or portions thereof, including modifications, that you
11+ * make.
12+ *
13+ * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO
14+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE,
15+ * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR
16+ * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
17+ * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
18+ * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
19+ * COPYRIGHT HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE
20+ * OR DOCUMENTATION.
21+ */
22+
23+package jp.kyasu.awt.text;
24+
25+import jp.kyasu.awt.Button;
26+import jp.kyasu.awt.Dialog;
27+import jp.kyasu.awt.Label;
28+import jp.kyasu.awt.Panel;
29+import jp.kyasu.awt.TextField;
30+import jp.kyasu.awt.TextEditModel;
31+import jp.kyasu.awt.Dialog;
32+import jp.kyasu.awt.Undo;
33+import jp.kyasu.graphics.ClickableTextAction;
34+import jp.kyasu.graphics.RichText;
35+import jp.kyasu.graphics.RichTextStyle;
36+import jp.kyasu.graphics.ParagraphStyle;
37+import jp.kyasu.graphics.ParagraphStyleModifier;
38+import jp.kyasu.graphics.Text;
39+import jp.kyasu.graphics.TextStyle;
40+import jp.kyasu.graphics.TextStyleModifier;
41+import jp.kyasu.graphics.text.TextPositionInfo;
42+import jp.kyasu.graphics.VActiveButton;
43+
44+import java.awt.BorderLayout;
45+import java.awt.Cursor;
46+import java.awt.Event;
47+import java.awt.Graphics;
48+import java.awt.GridBagLayout;
49+import java.awt.GridBagConstraints;
50+import java.awt.Insets;
51+import java.awt.Menu;
52+import java.awt.MenuItem;
53+import java.awt.MenuShortcut;
54+import java.awt.Point;
55+import java.awt.PopupMenu;
56+import java.awt.PrintJob;
57+import java.awt.event.*;
58+import java.text.BreakIterator;
59+import java.text.CharacterIterator;
60+import java.util.Enumeration;
61+
62+/*if[JDK1.2]*/
63+import jp.kyasu.graphics.BasicTSModifier;
64+import jp.kyasu.graphics.TextBuffer;
65+import java.awt.BasicStroke;
66+import java.awt.Color;
67+import java.awt.Graphics2D;
68+import java.awt.Stroke;
69+import java.awt.event.InputMethodEvent;
70+import java.awt.event.InputMethodListener;
71+import java.awt.font.TextAttribute;
72+import java.awt.font.TextHitInfo;
73+import java.awt.im.InputMethodHighlight;
74+import java.text.AttributedCharacterIterator;
75+import java.util.Map;
76+/*end[JDK1.2]*/
77+
78+/**
79+ * The <code>BasicTextEditController</code> class implements a controller
80+ * of a MVC model for the text editing. The model of the MVC model is a
81+ * <code>TextEditModel</code> object and the view of the MVC model is a
82+ * <code>TextEditView</code> object.
83+ * <p>
84+ * The <code>BasicTextEditController</code> class implements basic operations
85+ * for the text editing. The <code>TextEditController</code> class (a
86+ * subclass of this class) implements full operations for the text editing.
87+ * <p>
88+ * The principal editing operations on a <code>BasicTextEditController</code>
89+ * are the <code>replaceRange (replaceSelection)</code>,
90+ * <code>setRangeTextStyle (setSelectionTextStyle)</code>,
91+ * <code>modifyRangeTextStyle (modifySelectionTextStyle)</code>,
92+ * <code>setRangeParagraphStyle (setSelectionParagraphStyle)</code> and
93+ * <code>modifyRangeParagraphStyle (modifySelectionParagraphStyle)</code>
94+ * methods:
95+ * <ul>
96+ * <li>The <code>replaceRange (replaceSelection)</code> method replaces the
97+ * specified range (selection) of the text (model) with the specified
98+ * replacement text.
99+ * <li>The <code>setRangeTextStyle (setSelectionTextStyle)</code> method
100+ * sets the text style in the specified range (selection) of the text
101+ * (model) to be the specified text style.
102+ * <li>The <code>>modifyRangeTextStyle (modifySelectionTextStyle)</code>
103+ * method modifies the text style in the specified range (selection) of
104+ * the text (model) by using the specified <code>TextStyleModifier</code>
105+ * object.
106+ * <li>The <code>setRangeParagraphStyle (setSelectionParagraphStyle)</code>
107+ * method sets the paragraph style at the specified range (selection)
108+ * of the text (model) to be the specified paragraph style.
109+ * <li>The <code>modifyRangeParagraphStyle
110+ * (modifySelectionParagraphStyle)</code> method modifies the paragraph
111+ * style at the specified range (selection) of the text (model) by using
112+ * the specified <code>ParagraphStyleModifier</code> object.
113+ * </ul>
114+ *
115+ * @see jp.kyasu.awt.TextEditModel
116+ * @see jp.kyasu.awt.text.TextEditView
117+ * @see jp.kyasu.awt.text.TextEditController
118+ *
119+ * @version 18 Dec 1998
120+ * @author Kazuki YASUMATSU
121+ */
122+public class BasicTextEditController extends TextController
123+ implements ActionListener
124+ /*if[JDK1.2]*/
125+ , InputMethodListener
126+ /*end[JDK1.2]*/
127+{
128+ protected TextEditModel model;
129+ protected TextEditView view;
130+ protected KeyBinding keyBinding;
131+ protected boolean clickable;
132+ protected Text typeInText;
133+ protected TextStyle typeInStyle;
134+ protected Menu editMenu;
135+ protected PopupMenu popupMenu;
136+ transient protected TextPositionInfo dragOrigin;
137+ transient protected TextPositionInfo dragCurrent;
138+ transient protected Undo lastUndo;
139+
140+
141+ /**
142+ * Constructs a text edit controller with the specified text edit view.
143+ *
144+ * @param view the text edit view.
145+ */
146+ public BasicTextEditController(TextEditView view) {
147+ super();
148+ if (view == null)
149+ throw new NullPointerException();
150+ model = view.model;
151+ this.view = view;
152+
153+ keyBinding = new KeyBinding();
154+
155+ selectionVisibleAtFocus = false;
156+ /*
157+ if (selectionVisibleAtFocus) {
158+ view.setSelectionVisible(false);
159+ }
160+ */
161+
162+ clickable = false;
163+ typeInStyle = model.getRichText().getRichTextStyle().getTextStyle();
164+ typeInText = new Text(" ", typeInStyle);
165+
166+ editMenu = createEditMenu();
167+ setPopupMenu(createPopupMenu());
168+
169+ dragOrigin = dragCurrent = null;
170+ lastUndo = null;
171+ }
172+
173+
174+ /**
175+ * Returns the model of this controller.
176+ */
177+ public TextEditModel getModel() {
178+ return model;
179+ }
180+
181+ /**
182+ * Returns the view of this controller.
183+ */
184+ public TextView getView() {
185+ return view;
186+ }
187+
188+ /**
189+ * Tests if the selection becomes visible when the view is focused.
190+ */
191+ public boolean isSelectionVisibleAtFocus() {
192+ return selectionVisibleAtFocus && view.selectionIsCaret();
193+ }
194+
195+ /**
196+ * Returns the text in the clipboard.
197+ */
198+ public Text getClipboardText() {
199+ return getClipboardText(typeInStyle);
200+ }
201+
202+ /**
203+ * Returns the keymap of this controller.
204+ * @see #setKeymap(jp.kyasu.awt.text.Keymap)
205+ */
206+ public Keymap getKeymap() {
207+ return keyBinding.getKeymap();
208+ }
209+
210+ /**
211+ * Sets the keymap of this controller.
212+ * @see #getKeymap()
213+ */
214+ public synchronized void setKeymap(Keymap keymap) {
215+ keyBinding.setKeymap(keymap);
216+ }
217+
218+ /**
219+ * Returns the key binding of this controller.
220+ * @see #getKeyAction(java.lang.String)
221+ * @see #addKeyAction(jp.kyasu.awt.text.KeyAction)
222+ * @see #removeKeyAction(jp.kyasu.awt.text.KeyAction)
223+ * @see #removeKeyActionNamed(java.lang.String)
224+ */
225+ public KeyBinding getKeyBinding() {
226+ return keyBinding;
227+ }
228+
229+ /**
230+ * Returns the key action object associated with the specified name.
231+ * @param actionName the name of the key action.
232+ * @return the key action object, or <code>null</code> if no associated
233+ * action exists.
234+ * @see #addKeyAction(jp.kyasu.awt.text.KeyAction)
235+ * @see #removeKeyAction(jp.kyasu.awt.text.KeyAction)
236+ * @see #removeKeyActionNamed(java.lang.String)
237+ */
238+ public KeyAction getKeyAction(String actionName) {
239+ return keyBinding.getKeyAction(actionName);
240+ }
241+
242+ /**
243+ * Adds the key action to the key binding of this controller.
244+ * @param keyAction the key action object.
245+ * @see #getKeyAction(java.lang.String)
246+ * @see #removeKeyAction(jp.kyasu.awt.text.KeyAction)
247+ * @see #removeKeyActionNamed(java.lang.String)
248+ */
249+ public synchronized void addKeyAction(KeyAction keyAction) {
250+ keyBinding.addKeyAction(keyAction);
251+ }
252+
253+ /**
254+ * Removes the key action from the key binding of this controller.
255+ * @param keyAction the key action object.
256+ * @see #addKeyAction(jp.kyasu.awt.text.KeyAction)
257+ * @see #getKeyAction(java.lang.String)
258+ * @see #removeKeyActionNamed(java.lang.String)
259+ */
260+ public synchronized void removeKeyAction(KeyAction keyAction) {
261+ keyBinding.removeKeyAction(keyAction);
262+ }
263+
264+ /**
265+ * Removes the key action named the specified name from the key binding
266+ * of this controller.
267+ * @param actionName the name of the key action.
268+ * @see #addKeyAction(jp.kyasu.awt.text.KeyAction)
269+ * @see #getKeyAction(java.lang.String)
270+ * @see #removeKeyAction(jp.kyasu.awt.text.KeyAction)
271+ */
272+ public synchronized void removeKeyActionNamed(String actionName) {
273+ keyBinding.removeKeyActionNamed(actionName);
274+ }
275+
276+ /**
277+ * Performs the key action named the specified name.
278+ * @param actionName the name of the key action.
279+ * @see #performKeyAction(java.lang.String, char)
280+ */
281+ public void performKeyAction(String actionName) {
282+ performKeyAction(actionName, ' ');
283+ }
284+
285+ /**
286+ * Performs the key action named the specified name.
287+ * @param actionName the name of the key action.
288+ * @param keyChar the key character for the key action.
289+ * @see #performKeyAction(java.lang.String)
290+ */
291+ public synchronized void performKeyAction(String actionName, char keyChar)
292+ {
293+ KeyAction action = keyBinding.getKeyAction(actionName);
294+ if (action != null) {
295+ action.perform(keyChar);
296+ }
297+ }
298+
299+ /**
300+ * Tests if this controller handles <code>ClickableTextAction</code>.
301+ * @see #setClickable(boolean)
302+ * @see jp.kyasu.graphics.ClickableTextAction
303+ */
304+ public boolean isClickable() {
305+ return clickable;
306+ }
307+
308+ /**
309+ * Makes this controller handle <code>ClickableTextAction</code>.
310+ * @see #isClickable()
311+ * @see jp.kyasu.graphics.ClickableTextAction
312+ */
313+ public void setClickable(boolean b) {
314+ clickable = b;
315+ }
316+
317+ /**
318+ * Returns the edit menu of this controller.
319+ */
320+ public Menu getEditMenu() {
321+ return editMenu;
322+ }
323+
324+ /**
325+ * Returns the popup menu of this controller.
326+ * @see #setPopupMenu(java.awt.PopupMenu)
327+ */
328+ public synchronized PopupMenu getPopupMenu() {
329+ return popupMenu;
330+ }
331+
332+ /**
333+ * Sets the popup menu of this controller.
334+ * @see #getPopupMenu()
335+ */
336+ public void setPopupMenu(PopupMenu menu) {
337+ if (popupMenu != null)
338+ view.remove(popupMenu);
339+ popupMenu = menu;
340+ if (popupMenu != null)
341+ view.add(popupMenu);
342+ }
343+
344+
345+ // ================ TextComponent APIs ================
346+
347+ /**
348+ * Returns the string of the view of this controller.
349+ * @see #getString(java.awt.String)
350+ * @see #setString(java.awt.String)
351+ */
352+ public String getString() {
353+ return getString(System.getProperty("line.separator", "\n"));
354+ }
355+
356+ /**
357+ * Returns the string of the view of this controller.
358+ * @param separator the separator string.
359+ * @see #getString()
360+ * @see #setString(java.awt.String)
361+ * @see jp.kyasu.graphics.Text#getSystemString(java.awt.String, java.awt.String)
362+ */
363+ public String getString(String separator) {
364+ return Text.getSystemString(getText().toString(), separator);
365+ }
366+
367+ /**
368+ * Sets the string of the view of this controller.
369+ * @see #getString()
370+ */
371+ public synchronized void setString(String str) {
372+ if (str == null) str = "";
373+ setText(
374+ new Text(Text.getJavaString(str),
375+ model.getRichText().getRichTextStyle().getTextStyle()));
376+ }
377+
378+ /**
379+ * Returns the selected string from the view of this controller.
380+ */
381+ public String getSelectedString() {
382+ return Text.getSystemString(getSelectedText().toString());
383+ }
384+
385+ /**
386+ * Indicates whether or not the view of this controller is editable.
387+ * @see #setEditable(boolean)
388+ */
389+ public boolean isEditable() {
390+ return view.isEditable();
391+ }
392+
393+ /**
394+ * Sets the flag that determines whether or not the view this controller
395+ * is editable.
396+ * @see #isEditable()
397+ */
398+ public synchronized void setEditable(boolean b) {
399+ view.setEditable(b);
400+ setMenuEnabled(editMenu, b);
401+ setMenuEnabled(popupMenu, b);
402+ }
403+
404+ /**
405+ * Returns the start position of the selected text.
406+ * @see #setSelectionStart(int)
407+ * @see #getSelectionEnd()
408+ */
409+ public int getSelectionStart() {
410+ TextPositionInfo posInfo = view.getSelectionBegin();
411+ return (posInfo != null ? posInfo.textIndex : 0);
412+ }
413+
414+ /**
415+ * Sets the selection start for the view of this controller to the
416+ * specified position.
417+ * @see #getSelectionStart()
418+ * @see #setSelectionEnd(int)
419+ */
420+ public void setSelectionStart(int selectionStart) {
421+ select(selectionStart, getSelectionEnd());
422+ }
423+
424+ /**
425+ * Returns the end position of the selected text.
426+ * @see #setSelectionEnd(int)
427+ * @see #getSelectionStart()
428+ */
429+ public int getSelectionEnd() {
430+ TextPositionInfo posInfo = view.getSelectionEnd();
431+ return (posInfo != null ? posInfo.textIndex : 0);
432+ }
433+
434+ /**
435+ * Sets the selection end for the view of this controller to the
436+ * specified position.
437+ * @see #getSelectionEnd()
438+ * @see #setSelectionStart(int)
439+ */
440+ public void setSelectionEnd(int selectionEnd) {
441+ select(getSelectionStart(), selectionEnd);
442+ }
443+
444+ /**
445+ * Selects the text between the specified start and end positions.
446+ * @param selectionStart the start position of the text to select.
447+ * @param selectionEnd the end position of the text to select.
448+ * @see #setSelectionStart(int)
449+ * @see #setSelectionEnd(int)
450+ * @see #select(int, int, boolean, boolean)
451+ * @see #selectAll()
452+ */
453+ public void select(int selectionStart, int selectionEnd) {
454+ select(selectionStart, selectionEnd, true, false);
455+ }
456+
457+ /**
458+ * Selects all the text.
459+ * @see #select(int, int)
460+ */
461+ public void selectAll() {
462+ select(0, model.getRichText().length());
463+ }
464+
465+ /**
466+ * Returns the position of the text insertion caret.
467+ * @see #setCaretPosition(int)
468+ */
469+ public int getCaretPosition() {
470+ return getSelectionStart();
471+ }
472+
473+ /**
474+ * Sets the position of the text insertion caret.
475+ * @see #getCaretPosition()
476+ * @see #setCaretPosition(int, boolean)
477+ */
478+ public void setCaretPosition(int position) {
479+ setCaretPosition(position, false);
480+ }
481+
482+ /**
483+ * Tests if the selection is caret, i.e., null selection.
484+ */
485+ public boolean selectionIsCaret() {
486+ return view.selectionIsCaret();
487+ }
488+
489+
490+ // ================ TextArea APIs ================
491+
492+ /**
493+ * Inserts the specified string at the specified position in the view
494+ * of this controller.
495+ * @param str the string to insert.
496+ * @param pos the position at which to insert.
497+ * @see #replaceRange(java.lang.String, int, int)
498+ */
499+ public void insert(String str, int pos) {
500+ if (str == null) str = "";
501+ replaceRange(str, pos, pos);
502+ }
503+
504+ /**
505+ * Appends the given string to the current text.
506+ * @param str the string to append.
507+ * @see #insert(java.lang.String, int)
508+ */
509+ public void append(String str) {
510+ if (str == null) str = "";
511+ insert(str, model.getRichText().length());
512+ }
513+
514+ /**
515+ * Replaces string between the indicated start and end positions
516+ * with the specified replacement string.
517+ * @param str the string to use as the replacement.
518+ * @param start the start position, inclusive.
519+ * @param end the end position, exclusive.
520+ * @see #replaceRange(jp.kyasu.graphics.Text, int, int)
521+ */
522+ public void replaceRange(String str, int start, int end) {
523+ if (str == null) str = "";
524+ replaceRange(new Text(str, typeInStyle), start, end);
525+ }
526+
527+ /**
528+ * Returns the number of rows in the view of this controller.
529+ * @see #getColumns()
530+ */
531+ public int getRows() {
532+ return view.getRows();
533+ }
534+
535+ /**
536+ * Returns the number of columns in the view of this controller.
537+ * @see #getRows()
538+ */
539+ public int getColumns() {
540+ return view.getColumns();
541+ }
542+
543+
544+ // ================ TextField APIs ================
545+
546+ /**
547+ * Returns the character that is to be used for echoing.
548+ * @see #setEchoChar(char)
549+ * @see #echoCharIsSet()
550+ */
551+ public char getEchoChar() {
552+ return view.layout.getEchoChar();
553+ }
554+
555+ /**
556+ * Sets the echo character for the view of this controller.
557+ * @see #getEchoChar()
558+ * @see #echoCharIsSet()
559+ */
560+ public synchronized void setEchoChar(char c) {
561+ view.layout.setEchoChar(c);
562+ model.setRichText(model.getRichText());
563+ }
564+
565+ /**
566+ * Indicates whether or not the view of this controller has a character
567+ * set for echoing.
568+ * @see #getEchoChar()
569+ * @see #setEchoChar(char)
570+ */
571+ public boolean echoCharIsSet() {
572+ return view.layout.echoCharIsSet();
573+ }
574+
575+
576+ // ================ Enhanced APIs ================
577+
578+ /**
579+ * Returns the current text style of this controller.
580+ */
581+ public TextStyle getCurrentTextStyle() {
582+ return typeInStyle;
583+ }
584+
585+ /**
586+ * Returns the text style at the specified index in the view of this
587+ * controller.
588+ * @return the text style at the specified index, or <code>null</code>
589+ * if the index is out of range.
590+ */
591+ public TextStyle getTextStyleAt(int index) {
592+ RichText richText = model.getRichText();
593+ if (index < 0 || index >= richText.length())
594+ return null;
595+ return richText.getTextStyleAt(index);
596+ }
597+
598+ /**
599+ * Returns the number of the text styles in the text of the view of
600+ * this controller.
601+ */
602+ public int getTextStyleCount() {
603+ return model.getRichText().getText().getTextStyleCount();
604+ }
605+
606+ /**
607+ * Returns all text styles in the text of the view of this controller.
608+ */
609+ public TextStyle[] getTextStyles() {
610+ return model.getRichText().getText().getTextStyles();
611+ }
612+
613+ /**
614+ * Returns the text styles in the text of the view of this controller.
615+ *
616+ * @param begin the beginning index to get text styles, inclusive.
617+ * @param end the ending index to get text styles, exclusive.
618+ */
619+ public TextStyle[] getTextStyles(int begin, int end) {
620+ return model.getRichText().getText().getTextStyles(begin, end);
621+ }
622+
623+ /**
624+ * Returns an enumeration of the text styles of text of the view of
625+ * this controller.
626+ */
627+ public Enumeration textStyles() {
628+ return model.getRichText().getText().textStyles();
629+ }
630+
631+ /**
632+ * Returns an enumeration of the text styles of text of the view of
633+ * this controller.
634+ *
635+ * @param begin the beginning index to get styles, inclusive.
636+ * @param end the ending index to get styles, exclusive.
637+ */
638+ public Enumeration textStyles(int begin, int end) {
639+ return model.getRichText().getText().textStyles(begin, end);
640+ }
641+
642+ /**
643+ * Returns the paragraph style at the specified index in the view of
644+ * this controller.
645+ * @return the paragraph style at the specified index, or <code>null</code>
646+ * if the index is out of range.
647+ */
648+ public ParagraphStyle getParagraphStyleAt(int index) {
649+ RichText richText = model.getRichText();
650+ if (index < 0 || index > richText.length())
651+ return null;
652+ return richText.getParagraphStyleAt(index);
653+ }
654+
655+ /**
656+ * Returns the number of the paragraph styles in the text of the view
657+ * of this controller.
658+ */
659+ public int getParagraphStyleCount() {
660+ return model.getRichText().getParagraphStyleCount();
661+ }
662+
663+ /**
664+ * Returns all paragraph styles in the text of the view of this controller.
665+ */
666+ public ParagraphStyle[] getParagraphStyles() {
667+ return model.getRichText().getParagraphStyles();
668+ }
669+
670+ /**
671+ * Returns the paragraph styles in the text of the view of this controller.
672+ *
673+ * @param begin the beginning index of the text to get paragraph styles,
674+ * inclusive.
675+ * @param end the ending index of the text to get paragraph styles,
676+ * exclusive.
677+ */
678+ public ParagraphStyle[] getParagraphStyles(int begin, int end) {
679+ return model.getRichText().getParagraphStyles(begin, end);
680+ }
681+
682+ /**
683+ * Returns an enumeration of the paragraph styles of the text of the
684+ * view of this controller.
685+ */
686+ public Enumeration paragraphStyles() {
687+ return model.getRichText().paragraphStyles();
688+ }
689+
690+ /**
691+ * Returns an enumeration of the paragraph styles of the text of the
692+ * view of this controller.
693+ *
694+ * @param begin the beginning index to get styles, inclusive.
695+ * @param end the ending index to get styles, exclusive.
696+ */
697+ public Enumeration paragraphStyles(int begin, int end) {
698+ return model.getRichText().paragraphStyles(begin, end);
699+ }
700+
701+ /**
702+ * Returns the text of the view of this controller.
703+ * @see #setText(jp.kyasu.graphics.Text)
704+ */
705+ public Text getText() {
706+ return model.getRichText().getText();
707+ }
708+
709+ /**
710+ * Sets the text of the view of this controller.
711+ * @see #getText()
712+ */
713+ public synchronized void setText(Text text) {
714+ view.setText(text);
715+ clearUndo();
716+ }
717+
718+ /**
719+ * Returns the rich text of the view of this controller.
720+ * @see #setRichText(jp.kyasu.graphics.RichText)
721+ */
722+ public RichText getRichText() {
723+ return model.getRichText();
724+ }
725+
726+ /**
727+ * Sets the rich text of the view of this controller.
728+ * @see #getRichText()
729+ */
730+ public synchronized void setRichText(RichText richText) {
731+ view.setRichText(richText);
732+ clearUndo();
733+ }
734+
735+ /**
736+ * Returns the selected text from the view of this controller.
737+ */
738+ public Text getSelectedText() {
739+ return view.getSelectedText();
740+ }
741+
742+ /**
743+ * Selects the text between the specified start and end positions.
744+ * @param selectionStart the start position of the text to select.
745+ * @param selectionEnd the end position of the text to select.
746+ * @param scroll if true, scrolls the view after selection done.
747+ * @see #select(int, int, boolean, boolean)
748+ */
749+ public void select(int selectionStart, int selectionEnd, boolean scroll) {
750+ select(selectionStart, selectionEnd, scroll, false);
751+ }
752+
753+ /**
754+ * Selects the text between the specified start and end positions.
755+ * @param selectionStart the start position of the text to select.
756+ * @param selectionEnd the end position of the text to select.
757+ * @param scroll if true, scrolls the view after selection done.
758+ * @param top if true, scrolls to the top of the view.
759+ * @see #select(int, int)
760+ * @see #select(int, int, boolean)
761+ */
762+ public void select(int selectionStart, int selectionEnd,
763+ boolean scroll, boolean top)
764+ {
765+ int len = model.getRichText().length();
766+ if (selectionStart < 0) {
767+ selectionStart = 0;
768+ }
769+ if (selectionEnd > len) {
770+ selectionEnd = len;
771+ }
772+ if (selectionEnd < selectionStart) {
773+ selectionEnd = selectionStart;
774+ }
775+ if (selectionStart > selectionEnd) {
776+ selectionStart = selectionEnd;
777+ }
778+ TextPositionInfo begin = view.getTextPositionAt(selectionStart);
779+ TextPositionInfo end = view.getTextPositionNearby(begin, selectionEnd);
780+ select(begin, end, scroll, top);
781+ }
782+
783+ protected synchronized void select(TextPositionInfo begin,
784+ TextPositionInfo end,
785+ boolean scroll, boolean top)
786+ {
787+ view.hideSelection();
788+ setSelectionBeginEnd(begin, end);
789+ if (scroll) {
790+ if (top) {
791+ view.scrollTo(new Point(0, -view.getSelectionBegin().y));
792+ }
793+ else {
794+ view.scrollTo(view.getSelectionBegin());
795+ }
796+ }
797+ view.showSelection();
798+ notifyTextPositionListeners();
799+ }
800+
801+ /**
802+ * Sets the position of the text insertion caret.
803+ * @param position the position of the caret.
804+ * @param top if true, scrolls to the top of the view.
805+ * @see #setCaretPosition(int)
806+ */
807+ public void setCaretPosition(int position, boolean top) {
808+ if (position < 0) {
809+ throw new IllegalArgumentException("position less than zero.");
810+ }
811+ int len = model.getRichText().length();
812+ if (position > len) {
813+ position = len;
814+ }
815+ select(position, position, true, top);
816+ }
817+
818+ /**
819+ * Inserts the specified text at the specified position in the view
820+ * of this controller.
821+ * @param text the text to insert.
822+ * @param pos the position at which to insert.
823+ * @see #insert(jp.kyasu.graphics.Text, int, boolean)
824+ */
825+ public void insert(Text text, int pos) {
826+ insert(text, pos, true);
827+ }
828+
829+ /**
830+ * Inserts the specified text at the specified position in the view
831+ * of this controller.
832+ * @param text the text to insert.
833+ * @param pos the position at which to insert.
834+ * @param scroll if true, scrolls the view after the insertion.
835+ * @see #insert(jp.kyasu.graphics.Text, int)
836+ * @see #replaceRange(jp.kyasu.graphics.Text, int, int, boolean)
837+ */
838+ public void insert(Text text, int pos, boolean scroll) {
839+ replaceRange(text, pos, pos, scroll);
840+ }
841+
842+ /**
843+ * Appends the given text to the current text.
844+ * @param text the text to append.
845+ * @see #append(jp.kyasu.graphics.Text, boolean)
846+ */
847+ public void append(Text text) {
848+ append(text, true);
849+ }
850+
851+ /**
852+ * Appends the given text to the current text.
853+ * @param text the text to append.
854+ * @param scroll if true, scrolls the view after the appending.
855+ * @see #insert(jp.kyasu.graphics.Text, int, boolean)
856+ */
857+ public void append(Text text, boolean scroll) {
858+ insert(text, model.getRichText().length(), scroll);
859+ }
860+
861+ /**
862+ * Replaces text between the indicated start and end positions
863+ * with the specified replacement text.
864+ * @param text the text to use as the replacement.
865+ * @param start the start position, inclusive.
866+ * @param end the end position, exclusive.
867+ * @see #replaceRange(jp.kyasu.graphics.Text, int, int, boolean)
868+ */
869+ public void replaceRange(Text text, int start, int end) {
870+ replaceRange(text, start, end, true);
871+ }
872+
873+ /**
874+ * Replaces text between the indicated start and end positions
875+ * with the specified replacement text.
876+ * @param text the text to use as the replacement.
877+ * @param start the start position, inclusive.
878+ * @param end the end position, exclusive.
879+ * @param scroll if true, scrolls the view after replace done.
880+ * @see #replaceRange(java.lang.String, int, int)
881+ * @see #replaceRange(jp.kyasu.graphics.Text, int, int)
882+ * @see #replaceSelection(jp.kyasu.graphics.Text, boolean)
883+ */
884+ public void replaceRange(Text text, int start, int end, boolean scroll) {
885+ if (start > end) {
886+ int i = start;
887+ start = end;
888+ end = i;
889+ }
890+ replaceRange(text,
891+ view.getTextPositionAt(start),
892+ view.getTextPositionAt(end),
893+ scroll);
894+ }
895+
896+ /**
897+ * Replaces string in the range of the current selection with the
898+ * specified replacement string.
899+ * @param str the string to use as the replacement.
900+ * @see #replaceSelection(jp.kyasu.graphics.Text)
901+ */
902+ public void replaceSelection(String str) {
903+ if (str == null) str = "";
904+ replaceSelection(new Text(str, typeInStyle));
905+ }
906+
907+ /**
908+ * Replaces text in the range of the current selection with the
909+ * specified replacement text.
910+ * @param text the text to use as the replacement.
911+ * @see #replaceSelection(jp.kyasu.graphics.Text, boolean)
912+ */
913+ public void replaceSelection(Text text) {
914+ replaceSelection(text, true);
915+ }
916+
917+ /**
918+ * Replaces text in the range of the current selection with the
919+ * specified replacement text.
920+ * @param text the text to use as the replacement.
921+ * @param scroll if true, scrolls the view after replace done.
922+ * @see #replaceSelection(java.lang.String)
923+ * @see #replaceSelection(jp.kyasu.graphics.Text)
924+ * @see #replaceRange(jp.kyasu.graphics.Text, int, int, boolean)
925+ */
926+ public void replaceSelection(Text text, boolean scroll) {
927+ replaceRange(text,
928+ view.getSelectionBegin(),
929+ view.getSelectionEnd(),
930+ scroll);
931+ }
932+
933+ /**
934+ * Sets the text style between the indicated start and end positions
935+ * to the specified text style.
936+ * @param style the text style to be set.
937+ * @param start the start position, inclusive.
938+ * @param end the end position, exclusive.
939+ * @see #setRangeTextStyle(jp.kyasu.graphics.TextStyle, int, int, boolean)
940+ */
941+ public void setRangeTextStyle(TextStyle style, int start, int end) {
942+ setRangeTextStyle(style, start, end, true);
943+ }
944+
945+ /**
946+ * Sets the text style between the indicated start and end positions
947+ * to the specified text style.
948+ * @param style the text style to be set.
949+ * @param start the start position, inclusive.
950+ * @param end the end position, exclusive.
951+ * @param scroll if true, scrolls the view after set done.
952+ * @see #setRangeTextStyle(jp.kyasu.graphics.TextStyle, int, int)
953+ * @see #setSelectionTextStyle(jp.kyasu.graphics.TextStyle, boolean)
954+ */
955+ public void setRangeTextStyle(TextStyle style, int start, int end,
956+ boolean scroll)
957+ {
958+ if (style == null)
959+ return;
960+ if (start > end) {
961+ int i = start;
962+ start = end;
963+ end = i;
964+ }
965+ changeTextStyle(style, null,
966+ view.getTextPositionAt(start),
967+ view.getTextPositionAt(end),
968+ scroll);
969+ }
970+
971+ /**
972+ * Sets the text style in the range of the current selection to the
973+ * specified text style.
974+ * @param style the text style to be set.
975+ * @see #setSelectionTextStyle(jp.kyasu.graphics.TextStyle, boolean)
976+ */
977+ public void setSelectionTextStyle(TextStyle style) {
978+ setSelectionTextStyle(style, true);
979+ }
980+
981+ /**
982+ * Sets the text style in the range of the current selection to the
983+ * specified text style.
984+ * @param style the text style to be set.
985+ * @param scroll if true, scrolls the view after set done.
986+ * @see #setSelectionTextStyle(jp.kyasu.graphics.TextStyle)
987+ * @see #setRangeTextStyle(jp.kyasu.graphics.TextStyle, int, int, boolean)
988+ */
989+ public void setSelectionTextStyle(TextStyle style, boolean scroll) {
990+ if (style == null)
991+ return;
992+ changeTextStyle(style, null,
993+ view.getSelectionBegin(),
994+ view.getSelectionEnd(),
995+ scroll);
996+ }
997+
998+
999+ /**
1000+ * Modifies the text style between the indicated start and end positions
1001+ * by the specified text style modifier.
1002+ * @param modifier the text style modifier.
1003+ * @param start the start position, inclusive.
1004+ * @param end the end position, exclusive.
1005+ * @see #modifyRangeTextStyle(jp.kyasu.graphics.TextStyleModifier, int, int, boolean)
1006+ */
1007+ public void modifyRangeTextStyle(TextStyleModifier modifier,
1008+ int start, int end)
1009+ {
1010+ modifyRangeTextStyle(modifier, start, end, true);
1011+ }
1012+
1013+ /**
1014+ * Modifies the text style between the indicated start and end positions
1015+ * by the specified text style modifier.
1016+ * @param modifier the text style modifier.
1017+ * @param start the start position, inclusive.
1018+ * @param end the end position, exclusive.
1019+ * @param scroll if true, scrolls the view after set done.
1020+ * @see #modifyRangeTextStyle(jp.kyasu.graphics.TextStyleModifier, int, int)
1021+ * @see #modifySelectionTextStyle(jp.kyasu.graphics.TextStyleModifier, boolean)
1022+ */
1023+ public void modifyRangeTextStyle(TextStyleModifier modifier,
1024+ int start, int end, boolean scroll)
1025+ {
1026+ if (modifier == null)
1027+ return;
1028+ if (start > end) {
1029+ int i = start;
1030+ start = end;
1031+ end = i;
1032+ }
1033+ changeTextStyle(null, modifier,
1034+ view.getTextPositionAt(start),
1035+ view.getTextPositionAt(end),
1036+ scroll);
1037+ }
1038+
1039+ /**
1040+ * Modifies the text style in the range of the current selection by the
1041+ * specified text style modifier.
1042+ * @param modifier the text style modifier.
1043+ * @see #modifySelectionTextStyle(jp.kyasu.graphics.TextStyleModifier, boolean)
1044+ */
1045+ public void modifySelectionTextStyle(TextStyleModifier modifier) {
1046+ modifySelectionTextStyle(modifier, true);
1047+ }
1048+
1049+ /**
1050+ * Modifies the text style in the range of the current selection by the
1051+ * specified text style modifier.
1052+ * @param modifier the text style modifier.
1053+ * @param scroll if true, scrolls the view after set done.
1054+ * @see #modifySelectionTextStyle(jp.kyasu.graphics.TextStyleModifier)
1055+ * @see #modifyRangeTextStyle(jp.kyasu.graphics.TextStyleModifier, int, int, boolean)
1056+ */
1057+ public void modifySelectionTextStyle(TextStyleModifier modifier,
1058+ boolean scroll)
1059+ {
1060+ if (modifier == null)
1061+ return;
1062+ changeTextStyle(null, modifier,
1063+ view.getSelectionBegin(),
1064+ view.getSelectionEnd(),
1065+ scroll);
1066+ }
1067+
1068+ /**
1069+ * Sets the paragraph style between the indicated start and end positions
1070+ * to the specified paragraph style.
1071+ * @param style the paragraph style to be set.
1072+ * @param start the start position, inclusive.
1073+ * @param end the end position, exclusive.
1074+ * @see #setRangeParagraphStyle(jp.kyasu.graphics.ParagraphStyle, int, int, boolean)
1075+ */
1076+ public void setRangeParagraphStyle(ParagraphStyle style, int start, int end)
1077+ {
1078+ setRangeParagraphStyle(style, start, end, true);
1079+ }
1080+
1081+ /**
1082+ * Sets the paragraph style between the indicated start and end positions
1083+ * to the specified paragraph style.
1084+ * @param style the paragraph style to be set.
1085+ * @param start the start position, inclusive.
1086+ * @param end the end position, exclusive.
1087+ * @param scroll if true, scrolls the view after set done.
1088+ * @see #setRangeParagraphStyle(jp.kyasu.graphics.ParagraphStyle, int, int)
1089+ * @see #setSelectionParagraphStyle(jp.kyasu.graphics.ParagraphStyle, boolean)
1090+ */
1091+ public void setRangeParagraphStyle(ParagraphStyle style,
1092+ int start, int end, boolean scroll)
1093+ {
1094+ if (style == null)
1095+ return;
1096+ if (start > end) {
1097+ int i = start;
1098+ start = end;
1099+ end = i;
1100+ }
1101+ changeParagraphStyle(style, null,
1102+ view.getTextPositionAt(start),
1103+ view.getTextPositionAt(end),
1104+ scroll);
1105+ }
1106+
1107+ /**
1108+ * Sets the paragraph style in the range of the current selection to the
1109+ * specified paragraph style.
1110+ * @param style the paragraph style to be set.
1111+ * @see #setSelectionParagraphStyle(jp.kyasu.graphics.ParagraphStyle, boolean)
1112+ */
1113+ public void setSelectionParagraphStyle(ParagraphStyle style) {
1114+ setSelectionParagraphStyle(style, true);
1115+ }
1116+
1117+ /**
1118+ * Sets the paragraph style in the range of the current selection to the
1119+ * specified paragraph style.
1120+ * @param style the paragraph style to be set.
1121+ * @param scroll if true, scrolls the view after set done.
1122+ * @see #setSelectionParagraphStyle(jp.kyasu.graphics.ParagraphStyle)
1123+ * @see #setRangeParagraphStyle(jp.kyasu.graphics.ParagraphStyle, int, int, boolean)
1124+ */
1125+ public void setSelectionParagraphStyle(ParagraphStyle style, boolean scroll)
1126+ {
1127+ if (style == null)
1128+ return;
1129+ changeParagraphStyle(style, null,
1130+ view.getSelectionBegin(),
1131+ view.getSelectionEnd(),
1132+ scroll);
1133+ }
1134+
1135+
1136+ /**
1137+ * Modifies the paragraph style between the indicated start and end
1138+ * positions by the specified paragraph style modifier.
1139+ * @param modifier the paragraph style modifier.
1140+ * @param start the start position, inclusive.
1141+ * @param end the end position, exclusive.
1142+ * @see #modifyRangeParagraphStyle(jp.kyasu.graphics.ParagraphStyleModifier, int, int, boolean)
1143+ */
1144+ public void modifyRangeParagraphStyle(ParagraphStyleModifier modifier,
1145+ int start, int end)
1146+ {
1147+ modifyRangeParagraphStyle(modifier, start, end, true);
1148+ }
1149+
1150+ /**
1151+ * Modifies the paragraph style between the indicated start and end
1152+ * positions by the specified paragraph style modifier.
1153+ * @param modifier the paragraph style modifier.
1154+ * @param start the start position, inclusive.
1155+ * @param end the end position, exclusive.
1156+ * @param scroll if true, scrolls the view after set done.
1157+ * @see #modifyRangeParagraphStyle(jp.kyasu.graphics.ParagraphStyleModifier, int, int)
1158+ * @see #modifySelectionParagraphStyle(jp.kyasu.graphics.ParagraphStyleModifier, boolean)
1159+ */
1160+ public void modifyRangeParagraphStyle(ParagraphStyleModifier modifier,
1161+ int start, int end, boolean scroll)
1162+ {
1163+ if (modifier == null)
1164+ return;
1165+ if (start > end) {
1166+ int i = start;
1167+ start = end;
1168+ end = i;
1169+ }
1170+ changeParagraphStyle(null, modifier,
1171+ view.getTextPositionAt(start),
1172+ view.getTextPositionAt(end),
1173+ scroll);
1174+ }
1175+
1176+ /**
1177+ * Modifies the paragraph style in the range of the current selection by
1178+ * the specified paragraph style modifier.
1179+ * @param modifier the paragraph style modifier.
1180+ * @see #modifySelectionParagraphStyle(jp.kyasu.graphics.ParagraphStyleModifier, boolean)
1181+ */
1182+ public void modifySelectionParagraphStyle(ParagraphStyleModifier modifier)
1183+ {
1184+ modifySelectionParagraphStyle(modifier, true);
1185+ }
1186+
1187+ /**
1188+ * Modifies the paragraph style in the range of the current selection by
1189+ * the specified paragraph style modifier.
1190+ * @param modifier the paragraph style modifier.
1191+ * @param scroll if true, scrolls the view after set done.
1192+ * @see #modifySelectionParagraphStyle(jp.kyasu.graphics.ParagraphStyleModifier)
1193+ * @see #modifyRangeParagraphStyle(jp.kyasu.graphics.ParagraphStyleModifier, int, int, boolean)
1194+ */
1195+ public void modifySelectionParagraphStyle(ParagraphStyleModifier modifier,
1196+ boolean scroll)
1197+ {
1198+ if (modifier == null)
1199+ return;
1200+ changeParagraphStyle(null, modifier,
1201+ view.getSelectionBegin(),
1202+ view.getSelectionEnd(),
1203+ scroll);
1204+ }
1205+
1206+ /**
1207+ * Prints the text in the view of this controller with the specified
1208+ * flag determining to print a page number in footer.
1209+ *
1210+ * @param printPageNum if true, prints a page number in footer.
1211+ */
1212+ public void print(boolean printPageNum) {
1213+ print(RichText.DEFAULT_PRINT_INSETS, null, printPageNum);
1214+ }
1215+
1216+ /**
1217+ * Prints the text in the view of this controller with the specified
1218+ * header string and flag determining to print a page number in footer.
1219+ *
1220+ * @param header the header string.
1221+ * @param printPageNum if true, prints a page number in footer.
1222+ */
1223+ public void print(String header, boolean printPageNum) {
1224+ print(RichText.DEFAULT_PRINT_INSETS, header, printPageNum);
1225+ }
1226+
1227+ /**
1228+ * Prints the text in the view of this controller with the specified
1229+ * insets, header string, and flag determining to print a page number
1230+ * in footer.
1231+ *
1232+ * @param insets the insets of a printing medium (paper).
1233+ * @param header the header string.
1234+ * @param printPageNum if true, prints a page number in footer.
1235+ */
1236+ public void print(Insets insets, String header, boolean printPageNum) {
1237+ PrintJob job =
1238+ view.getToolkit().getPrintJob(view.getFrame(), "Print", null);
1239+ if (job == null)
1240+ return;
1241+ print(job, insets, header, printPageNum);
1242+ }
1243+
1244+ /**
1245+ * Prints the text in the view of this controller to a print device
1246+ * provided from the specified print job, with the specified header string
1247+ * and flag determining to print a page number in footer.
1248+ *
1249+ * @param job the print job.
1250+ * @param header the header string.
1251+ * @param printPageNum if true, prints a page number in footer.
1252+ */
1253+ public void print(PrintJob job, String header, boolean printPageNum) {
1254+ print(job, RichText.DEFAULT_PRINT_INSETS, header, printPageNum);
1255+ }
1256+
1257+ /**
1258+ * Prints the text in the view of this controller to a print device
1259+ * provided from the specified print job, with the specified insets,
1260+ * header string, and flag determining to print a page number in footer.
1261+ *
1262+ * @param job the print job.
1263+ * @param insets the insets of a printing medium (paper).
1264+ * @param header the header string.
1265+ * @param printPageNum if true, prints a page number in footer.
1266+ */
1267+ public synchronized void print(PrintJob job, Insets insets,
1268+ String header, boolean printPageNum)
1269+ {
1270+ if (job == null || insets == null)
1271+ return;
1272+
1273+ Cursor save = view.getCursor();
1274+ try {
1275+ view.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1276+ model.getRichText().print(job, insets, view.getLineWrap(),
1277+ header, printPageNum);
1278+ }
1279+ finally { view.setCursor(save); }
1280+ }
1281+
1282+
1283+ // ================ Listener ================
1284+
1285+ /**
1286+ * Invoked when the mouse has been clicked on a component.
1287+ * @see java.awt.event.MouseListener
1288+ */
1289+ public void mouseClicked(MouseEvent e) {
1290+ // mousePressed -> mouseReleased -> mouseClicked
1291+
1292+ if (!view.isEnabled())
1293+ return;
1294+
1295+ if (e.isConsumed())
1296+ return;
1297+
1298+ int clickCount = e.getClickCount();
1299+ if (clickCount < 2)
1300+ return;
1301+
1302+ e.consume();
1303+
1304+ TextPositionInfo posInfo = view.getTextPositionNearby(
1305+ view.getVisibleBegin(),
1306+ e.getPoint());
1307+
1308+ if (clickCount == 2) {
1309+ if (posInfo.textIndex == 0 ||
1310+ posInfo.textIndex >= model.getRichText().length())
1311+ {
1312+ select_all();
1313+ return;
1314+ }
1315+ if (select_braces(posInfo)) {
1316+ return;
1317+ }
1318+ select_word(posInfo);
1319+ return;
1320+ }
1321+ else if (clickCount == 3) {
1322+ select_line(posInfo);
1323+ return;
1324+ }
1325+ else {
1326+ if (view.selectionIsCaret() &&
1327+ view.getSelectionBegin().textIndex == posInfo.textIndex)
1328+ {
1329+ return;
1330+ }
1331+ view.scrollTo(posInfo);
1332+ view.hideSelection();
1333+ setSelectionBeginEnd(posInfo);
1334+ view.showSelection();
1335+ notifyTextPositionListeners();
1336+ dragOrigin = dragCurrent = posInfo;
1337+ }
1338+ }
1339+
1340+ /**
1341+ * Invoked when the mouse has been pressed on a component.
1342+ * @see java.awt.event.MouseListener
1343+ */
1344+ public void mousePressed(MouseEvent e) {
1345+ if (!view.isEnabled())
1346+ return;
1347+
1348+ if (e.isConsumed())
1349+ return;
1350+
1351+ //if (clickToFocus) {
1352+ if (view.isEditable()) {
1353+ view.requestFocus();
1354+ view.startTextCaret();
1355+ e.consume();
1356+ }
1357+
1358+ if (e.getClickCount() > 1)
1359+ return;
1360+
1361+ e.consume();
1362+
1363+ //if (view.isEditable() && (e.isPopupTrigger() || e.isMetaDown())) {
1364+ if (e.isPopupTrigger() || e.isMetaDown()) {
1365+ if (popupMenu != null) {
1366+ popupMenu.show(e.getComponent(), e.getX(), e.getY());
1367+ }
1368+ return;
1369+ }
1370+
1371+ TextPositionInfo posInfo = view.getTextPositionNearby(
1372+ view.getVisibleBegin(),
1373+ e.getPoint());
1374+
1375+ if (e.isShiftDown()) {
1376+ TextPositionInfo begin = view.getSelectionBegin();
1377+ TextPositionInfo end = view.getSelectionEnd();
1378+ if (begin == null || end == null) {
1379+ view.scrollTo(posInfo);
1380+ view.hideSelection();
1381+ setSelectionBeginEnd(posInfo);
1382+ view.showSelection();
1383+ dragOrigin = dragCurrent = posInfo;
1384+ }
1385+ else if (begin.textIndex <= posInfo.textIndex) {
1386+ dragOrigin = begin;
1387+ dragCurrent = end;
1388+ }
1389+ else {
1390+ dragOrigin = end;
1391+ dragCurrent = begin;
1392+ }
1393+ dragSelectionTo(posInfo);
1394+ return;
1395+ }
1396+
1397+ view.scrollTo(posInfo);
1398+ view.hideSelection();
1399+ setSelectionBeginEnd(posInfo);
1400+ view.showSelection();
1401+ dragOrigin = dragCurrent = posInfo;
1402+
1403+ /*
1404+ if (clickable && !e.isControlDown()) {
1405+ int textIndex = posInfo.textIndex;
1406+ if ((e.getX() - view.offset.x) < posInfo.x) {
1407+ --textIndex;
1408+ }
1409+ Text text = model.getRichText().getText();
1410+ if (textIndex >= 0 && textIndex < text.length()) {
1411+ TextStyle ts = text.getTextStyleAt(textIndex);
1412+ ClickableTextAction action = ts.getClickableTextAction();
1413+ if (action != null) {
1414+ view.performClickableTextAction(action);
1415+ }
1416+ }
1417+ }
1418+ */
1419+ }
1420+
1421+ /**
1422+ * Invoked when the mouse has been released on a component.
1423+ * @see java.awt.event.MouseListener
1424+ */
1425+ public void mouseReleased(MouseEvent e) {
1426+ if (!view.isEnabled())
1427+ return;
1428+
1429+ if (e.isConsumed())
1430+ return;
1431+
1432+ e.consume();
1433+
1434+ dragOrigin = dragCurrent = null;
1435+
1436+ if (e.getClickCount() < 2)
1437+ notifyTextPositionListeners();
1438+
1439+ if (clickable && !e.isControlDown() && view.selectionIsCaret()) {
1440+ if (e.getClickCount() > 1)
1441+ return;
1442+ if (e.isPopupTrigger() || e.isMetaDown())
1443+ return;
1444+ if (e.isShiftDown())
1445+ return;
1446+
1447+ TextPositionInfo posInfo = view.getSelectionBegin();
1448+ int textIndex = posInfo.textIndex;
1449+ if ((e.getX() - view.offset.x) < posInfo.x) {
1450+ --textIndex;
1451+ }
1452+ Text text = model.getRichText().getText();
1453+ if (textIndex >= 0 && textIndex < text.length()) {
1454+ TextStyle ts = text.getTextStyleAt(textIndex);
1455+ ClickableTextAction action = ts.getClickableTextAction();
1456+ if (action != null) {
1457+ view.performClickableTextAction(action);
1458+ }
1459+ }
1460+ }
1461+ }
1462+
1463+ /**
1464+ * Invoked when the mouse enters a component.
1465+ * @see java.awt.event.MouseListener
1466+ */
1467+ public void mouseEntered(MouseEvent e) {
1468+ if (!view.isEnabled())
1469+ return;
1470+ if (!view.isEditable())
1471+ return;
1472+ if (!clickToFocus) {
1473+ view.requestFocus();
1474+ }
1475+ }
1476+
1477+ /**
1478+ * Invoked when the mouse button is pressed on a component and then dragged.
1479+ * @see java.awt.event.MouseMotionListener
1480+ */
1481+ public void mouseDragged(MouseEvent e) {
1482+ // mousePressed -> mouseDragged* -> mouseReleased
1483+
1484+ if (!view.isEnabled())
1485+ return;
1486+
1487+ if (e.isConsumed())
1488+ return;
1489+
1490+ e.consume();
1491+
1492+ dragSelectionTo(view.getTextPositionNearby(
1493+ view.getVisibleBegin(),
1494+ e.getPoint()));
1495+ }
1496+
1497+ /**
1498+ * Invoked when a key has been typed.
1499+ * @see java.awt.event.KeyListener
1500+ */
1501+ public void keyTyped(KeyEvent e) {
1502+ // keyPressed -> keyTyped -> keyReleased
1503+ // This method is NOT invoked by the special keys (CTL, SHIFT, etc.).
1504+
1505+ if (!view.isEnabled())
1506+ return;
1507+
1508+ if (e.isConsumed())
1509+ return;
1510+
1511+ if (!view.isEditable()) {
1512+ e.consume();
1513+ return;
1514+ }
1515+
1516+ /*
1517+ if (e.getKeyCode() != KeyEvent.VK_UNDEFINED)
1518+ return;
1519+ */
1520+
1521+ KeyAction a = keyBinding.getKeyAction(e);
1522+ if (a != null) {
1523+ a.perform(e.getKeyChar());
1524+ e.consume();
1525+ }
1526+ }
1527+
1528+ /**
1529+ * Invoked when a key has been pressed.
1530+ * @see java.awt.event.KeyListener
1531+ */
1532+ public void keyPressed(KeyEvent e) {
1533+ // This method is invoked by the special keys (CTL, SHIFT, etc.).
1534+
1535+ if (!view.isEnabled())
1536+ return;
1537+
1538+ if (e.isConsumed())
1539+ return;
1540+
1541+ if (!view.isEditable()) {
1542+ //view.getToolkit().beep();
1543+ e.consume();
1544+ return;
1545+ }
1546+
1547+ /*
1548+ if (e.getKeyChar() != KeyEvent.CHAR_UNDEFINED)
1549+ return;
1550+ */
1551+
1552+ KeyAction a = keyBinding.getKeyAction(e);
1553+ if (a != null) {
1554+ a.perform(e.getKeyChar());
1555+ e.consume();
1556+ }
1557+ }
1558+
1559+ /**
1560+ * Invoked when a component gains the keyboard focus.
1561+ * @see java.awt.event.FocusListener
1562+ */
1563+ public void focusGained(FocusEvent e) {
1564+ //synchronized (view) {
1565+ if (!view.isEnabled())
1566+ return;
1567+ //if (e.isTemporary()) return;
1568+ super.focusGained(e);
1569+ view.startTextCaret();
1570+ //}
1571+ }
1572+
1573+ /**
1574+ * Invoked when a component loses the keyboard focus.
1575+ * @see java.awt.event.FocusListener
1576+ */
1577+ public void focusLost(FocusEvent e) {
1578+ //synchronized (view) {
1579+ if (!view.isEnabled())
1580+ return;
1581+ //if (e.isTemporary()) return;
1582+ super.focusLost(e);
1583+ view.stopTextCaret();
1584+ //}
1585+ }
1586+
1587+ /**
1588+ * Invoked when an action occurs.
1589+ * @see java.awt.event.ActionListener
1590+ */
1591+ public void actionPerformed(ActionEvent e) {
1592+ if (!view.isEnabled())
1593+ return;
1594+
1595+ String command = e.getActionCommand();
1596+ boolean isShiftDown = ((e.getModifiers() & Event.SHIFT_MASK) != 0);
1597+ if (command.equals(A_COPY)) {
1598+ copy_clipboard();
1599+ }
1600+ else if (command.equals(A_CUT)) {
1601+ cut_clipboard();
1602+ }
1603+ else if (command.equals(A_PASTE)) {
1604+ if (!isShiftDown)
1605+ paste_clipboard();
1606+ else
1607+ paste_cutbuffer();
1608+ }
1609+ else if (command.equals(A_FIND)) {
1610+ find_word();
1611+ }
1612+ else if (command.equals(A_UNDO)) {
1613+ undo();
1614+ }
1615+ else if (command.equals(A_PRINT)) {
1616+ print(true);
1617+ }
1618+ }
1619+
1620+
1621+ // ================ Functions ================
1622+
1623+ static protected final String OPEN_BRACES = "({[<\"'";
1624+ static protected final String CLOSE_BRACES = ")}]>\"'";
1625+
1626+ /**
1627+ * If the cursor is inside the selection, deletes the entire selection.
1628+ * Inserts character at the insertion cursor.
1629+ */
1630+ public void insert_character(char c) {
1631+ if (c == Text.LINE_BREAK_CHAR &&
1632+ !model.getRichText().getRichTextStyle().
1633+ isJavaLineSeparatorWithBreak())
1634+ {
1635+ return;
1636+ }
1637+ typeInText.setChar(0, c);
1638+ replaceSelection(typeInText);
1639+ }
1640+
1641+ /**
1642+ * Undo the last change.
1643+ */
1644+ public void undo() {
1645+ if (lastUndo != null) {
1646+ lastUndo = lastUndo.undo();
1647+ }
1648+ }
1649+
1650+ /**
1651+ * Clears the undo of the last change.
1652+ */
1653+ public void clearUndo() {
1654+ lastUndo = null;
1655+ }
1656+
1657+ /**
1658+ * Sets the undo.
1659+ */
1660+ public void setUndo(Undo undo) {
1661+ lastUndo = undo;
1662+ }
1663+
1664+ /**
1665+ * Copies the current selection to the clipboard.
1666+ */
1667+ public void copy_clipboard() {
1668+ Text text = view.getSelectedText();
1669+ if (!text.isEmpty()) {
1670+ setCutBuffer(text);
1671+ setClipboardText(text);
1672+ }
1673+ }
1674+
1675+ /**
1676+ * Cuts the current selection to the clipboard.
1677+ */
1678+ public void cut_clipboard() {
1679+ Text text = view.getSelectedText();
1680+ if (!text.isEmpty()) {
1681+ setCutBuffer(text);
1682+ setClipboardText(text);
1683+ replaceSelection(new Text());
1684+ }
1685+ }
1686+
1687+ /**
1688+ * Pastes the the cut buffer before the insertion cursor.
1689+ */
1690+ public void paste_cutbuffer() {
1691+ Text text = getCutBufferText();
1692+ if (text != null) {
1693+ replaceSelection(text);
1694+ }
1695+ }
1696+
1697+ /**
1698+ * Pastes the the clipboard before the insertion cursor.
1699+ */
1700+ public void paste_clipboard() {
1701+ if (lostClipboardOwnership) {
1702+ Text text = getClipboardText();
1703+ if (text != null) {
1704+ replaceSelection(text);
1705+ }
1706+ }
1707+ else {
1708+ paste_cutbuffer();
1709+ }
1710+ }
1711+
1712+ /**
1713+ * Select all text.
1714+ */
1715+ public void select_all() {
1716+ view.hideSelection();
1717+ setSelectionBeginEnd(
1718+ view.getTextPositionAt(0),
1719+ view.getTextPositionAt(model.getRichText().length()));
1720+ view.showSelection();
1721+ view.scrollTo(view.getSelectionBegin());
1722+ notifyTextPositionListeners();
1723+ }
1724+
1725+ /**
1726+ * Select braces at the selection start position.
1727+ * @see #select_braces(jp.kyasu.graphics.text.TextPositionInfo)
1728+ */
1729+ public boolean select_braces() {
1730+ return select_braces(view.getSelectionBegin());
1731+ }
1732+
1733+ /**
1734+ * Select braces at the specified text position.
1735+ * @see #select_braces()
1736+ */
1737+ public boolean select_braces(TextPositionInfo posInfo) {
1738+ int index = posInfo.textIndex;
1739+ Text text = model.getRichText().getText();
1740+ int bIndex;
1741+ if (index > 0 &&
1742+ (bIndex = OPEN_BRACES.indexOf(text.getChar(index - 1))) >= 0)
1743+ {
1744+ int matchCount = 0;
1745+ char ob = OPEN_BRACES.charAt(bIndex);
1746+ char cb = CLOSE_BRACES.charAt(bIndex);
1747+ CharacterIterator iterator = text.getCharacterIterator(index);
1748+ for (char c = iterator.current();
1749+ c != CharacterIterator.DONE;
1750+ c = iterator.next())
1751+ {
1752+ if (c == cb) {
1753+ if (matchCount == 0) {
1754+ view.hideSelection();
1755+ setSelectionBeginEnd(
1756+ posInfo,
1757+ view.getTextPositionNearby(posInfo,
1758+ iterator.getIndex()));
1759+ view.showSelection();
1760+ view.scrollTo(view.getSelectionBegin());
1761+ notifyTextPositionListeners();
1762+ return true;
1763+ }
1764+ --matchCount;
1765+ }
1766+ else if (c == ob) {
1767+ matchCount++;
1768+ }
1769+ }
1770+ }
1771+ if (index > 0 && index < text.length() &&
1772+ (bIndex = CLOSE_BRACES.indexOf(text.getChar(index))) >= 0)
1773+ {
1774+ int matchCount = 0;
1775+ char ob = OPEN_BRACES.charAt(bIndex);
1776+ char cb = CLOSE_BRACES.charAt(bIndex);
1777+ CharacterIterator iterator = text.getCharacterIterator(index - 1);
1778+ for (char c = iterator.current();
1779+ c != CharacterIterator.DONE;
1780+ c = iterator.previous())
1781+ {
1782+ if (c == ob) {
1783+ if (matchCount == 0) {
1784+ view.hideSelection();
1785+ setSelectionBeginEnd(
1786+ view.getTextPositionNearby(posInfo,
1787+ iterator.getIndex() + 1),
1788+ posInfo);
1789+ view.showSelection();
1790+ view.scrollTo(view.getSelectionBegin());
1791+ notifyTextPositionListeners();
1792+ return true;
1793+ }
1794+ --matchCount;
1795+ }
1796+ else if (c == cb) {
1797+ matchCount++;
1798+ }
1799+ }
1800+ }
1801+ return false;
1802+ }
1803+
1804+ /**
1805+ * Select a line at the selection start position.
1806+ * @see #select_line(jp.kyasu.graphics.text.TextPositionInfo)
1807+ */
1808+ public void select_line() {
1809+ select_line(view.getSelectionBegin());
1810+ }
1811+
1812+ /**
1813+ * Select a line at the specified text position.
1814+ * @see #select_line()
1815+ */
1816+ public void select_line(TextPositionInfo posInfo) {
1817+ int paraBegin =
1818+ model.getRichText().paragraphBeginIndexOf(posInfo.textIndex);
1819+ int paraEnd =
1820+ model.getRichText().paragraphEndIndexOf(posInfo.textIndex);
1821+ view.hideSelection();
1822+ setSelectionBeginEnd(
1823+ view.getTextPositionNearby(posInfo, paraBegin),
1824+ view.getTextPositionNearby(posInfo, paraEnd));
1825+ view.showSelection();
1826+ view.scrollTo(view.getSelectionBegin());
1827+ notifyTextPositionListeners();
1828+ }
1829+
1830+ /**
1831+ * Select a word at the selection start position.
1832+ * @see #select_word(jp.kyasu.graphics.text.TextPositionInfo)
1833+ */
1834+ public void select_word() {
1835+ select_word(view.getSelectionBegin());
1836+ }
1837+
1838+ /**
1839+ * Select a word at the specified text position.
1840+ * @see #select_word()
1841+ */
1842+ public void select_word(TextPositionInfo posInfo) {
1843+ Text text = model.getRichText().getText();
1844+ int index = posInfo.textIndex;
1845+ if (index >= text.length())
1846+ index = text.length() - 1;
1847+ BreakIterator boundary= BreakIterator.getWordInstance(view.getLocale());
1848+ boundary.setText(text.getCharacterIterator(index));
1849+ int end = boundary.following(index);
1850+ int begin = boundary.previous();
1851+ if (begin != BreakIterator.DONE &&
1852+ end != BreakIterator.DONE &&
1853+ begin <= index && index < end)
1854+ {
1855+ view.hideSelection();
1856+ setSelectionBeginEnd(
1857+ view.getTextPositionNearby(posInfo, begin),
1858+ view.getTextPositionNearby(posInfo, end));
1859+ view.showSelection();
1860+ view.scrollTo(view.getSelectionBegin());
1861+ notifyTextPositionListeners();
1862+ }
1863+ }
1864+
1865+ /**
1866+ * Finds the word and move the insertion cursor to the founded word.
1867+ * @see #find_word(java.lang.String)
1868+ * @see #find_word(java.lang.String, java.lang.String)
1869+ * @see #find_word(java.lang.String, java.lang.String, int)
1870+ */
1871+ public void find_word() {
1872+ String sel = view.getSelectedText().toString();
1873+ if (sel.length() > 32)
1874+ sel = sel.substring(0, 32);
1875+ Dialog dialog = createFindDialog(sel);
1876+ dialog.setVisible(true);
1877+ }
1878+
1879+ /**
1880+ * Finds the word and move the insertion cursor to the founded word.
1881+ * @param find the word to be found.
1882+ * @return true if the word has been found, false otherwise.
1883+ * @see #find_word()
1884+ * @see #find_word(java.lang.String, java.lang.String)
1885+ * @see #find_word(java.lang.String, java.lang.String, int)
1886+ */
1887+ public boolean find_word(String find) {
1888+ return find_word(find, null);
1889+ }
1890+
1891+ /**
1892+ * Finds the word and move the insertion cursor to the founded word.
1893+ * @param find the word to be found.
1894+ * @param rep the replacement string.
1895+ * @return true if the word has been found, false otherwise.
1896+ * @see #find_word()
1897+ * @see #find_word(java.lang.String)
1898+ * @see #find_word(java.lang.String, java.lang.String, int)
1899+ */
1900+ public boolean find_word(String find, String rep) {
1901+ return find_word(find, rep, view.getSelectionBegin().textIndex + 1);
1902+ }
1903+
1904+ /**
1905+ * Finds the word and move the insertion cursor to the founded word.
1906+ * @param find the word to be found.
1907+ * @param rep the replacement string.
1908+ * @param startIndex the starting index to find.
1909+ * @return true if the word has been found, false otherwise.
1910+ * @see #find_word(java.lang.String)
1911+ * @see #find_word(java.lang.String, java.lang.String)
1912+ * @see #find_word(java.lang.String, java.lang.String, int)
1913+ */
1914+ public boolean find_word(String find, String rep, int startIndex) {
1915+ if (find == null || find.length() == 0)
1916+ return false;
1917+ Text text = model.getRichText().getText();
1918+ if (startIndex >= text.length()) {
1919+ startIndex = 0;
1920+ }
1921+ int textIndex = text.indexOf(find, startIndex);
1922+ if (textIndex >= 0) {
1923+ TextPositionInfo posInfo = view.getTextPositionAt(textIndex);
1924+ view.hideSelection();
1925+ setSelectionBeginEnd(
1926+ posInfo,
1927+ view.getTextPositionNearby(posInfo, textIndex + find.length()));
1928+ if (rep != null) {
1929+ view.showSelection();
1930+ replaceSelection(rep);
1931+ }
1932+ else {
1933+ view.scrollTo(view.getSelectionBegin());
1934+ view.showSelection();
1935+ notifyTextPositionListeners();
1936+ }
1937+ return true;
1938+ }
1939+ else {
1940+ if (Dialog.confirm(view.getFrame(),
1941+ getResourceString(
1942+ "kfc.text.findContinueLabel",
1943+ "End of text reached; continue from beggining?")))
1944+ {
1945+ return find_word(find, rep, 0);
1946+ }
1947+ }
1948+ return false;
1949+ }
1950+
1951+ /**
1952+ * Creates a dialog for finding a word.
1953+ * @param initStr the initial string to prompt.
1954+ * @see #find_word()
1955+ */
1956+ protected Dialog createFindDialog(String initStr) {
1957+ final Dialog dialog = new Dialog(
1958+ view.getFrame(),
1959+ getResourceString("kfc.text.findTitle", "Find"),
1960+ true);
1961+ GridBagLayout gridbag = new GridBagLayout();
1962+ GridBagConstraints c = new GridBagConstraints();
1963+ Panel p1 = new Panel();
1964+ p1.setLayout(gridbag);
1965+ Label label = new Label(
1966+ getResourceString("kfc.text.findFieldLabel", "Find:"));
1967+ c.gridwidth = GridBagConstraints.RELATIVE;
1968+ gridbag.setConstraints(label, c);
1969+ p1.add(label);
1970+ final TextField ffield = new TextField(30);
1971+ // Do not transfer focus.
1972+ Keymap keymap = ffield.getKeymap();
1973+ keymap.setKeyCodeMap(KeyEvent.VK_TAB, "tab");
1974+ ffield.setKeymap(keymap);
1975+ if (initStr != null) {
1976+ ffield.setText(initStr);
1977+ }
1978+ c.gridwidth = GridBagConstraints.REMAINDER;
1979+ gridbag.setConstraints(ffield, c);
1980+ p1.add(ffield);
1981+ label = new Label(
1982+ getResourceString("kfc.text.replaceFieldLabel", "Replace:"));
1983+ if (!view.isEditable()) label.setEnabled(false);
1984+ c.gridwidth = GridBagConstraints.RELATIVE;
1985+ gridbag.setConstraints(label, c);
1986+ p1.add(label);
1987+ final TextField rfield = new TextField(30);
1988+ // Do not transfer focus.
1989+ keymap = rfield.getKeymap();
1990+ keymap.setKeyCodeMap(KeyEvent.VK_TAB, "tab");
1991+ rfield.setKeymap(keymap);
1992+ if (!view.isEditable()) rfield.setEditable(false);
1993+ c.gridwidth = GridBagConstraints.REMAINDER;
1994+ gridbag.setConstraints(rfield, c);
1995+ p1.add(rfield);
1996+ dialog.add(p1, BorderLayout.CENTER);
1997+
1998+ Panel p2 = new Panel();
1999+ Button b = new Button(
2000+ getResourceString("kfc.text.findStartLabel", "Find"));
2001+ ActionListener al = new ActionListener() {
2002+ public void actionPerformed(ActionEvent e) {
2003+ view.setSelectionVisible(true);
2004+ find_word(ffield.getText(), null);
2005+ }
2006+ };
2007+ ffield.addActionListener(al);
2008+ b.addActionListener(al);
2009+ p2.add(b);
2010+ /*
2011+ Button repB = new Button(
2012+ getResourceString("kfc.text.replaceStartLabel", "Replace"));
2013+ */
2014+ Button repB = new Button(new VActiveButton(
2015+ getResourceString("kfc.text.replaceStartLabel", "Replace")));
2016+ repB.addActionListener(new ActionListener() {
2017+ public void actionPerformed(ActionEvent e) {
2018+ view.setSelectionVisible(true);
2019+ find_word(ffield.getText(), rfield.getText());
2020+ }
2021+ });
2022+ if (!view.isEditable()) repB.setEnabled(false);
2023+ p2.add(repB);
2024+ /*
2025+ Button repAllB = new Button(
2026+ getResourceString("kfc.text.replaceAllLabel", "Replace All"));
2027+ */
2028+ Button repAllB = new Button(new VActiveButton(
2029+ getResourceString("kfc.text.replaceAllLabel", "Replace All")));
2030+ repAllB.addActionListener(new ActionListener() {
2031+ public void actionPerformed(ActionEvent e) {
2032+ view.setSelectionVisible(true);
2033+ while (find_word(ffield.getText(), rfield.getText()))
2034+ view.setSelectionVisible(true);
2035+ }
2036+ });
2037+ if (!view.isEditable()) repAllB.setEnabled(false);
2038+ p2.add(repAllB);
2039+ b = new Button(
2040+ getResourceString("kfc.text.findEndLabel", "Close"));
2041+ b.addActionListener(new ActionListener() {
2042+ public void actionPerformed(ActionEvent e) {
2043+ dialog.setVisible(false);
2044+ dialog.dispose();
2045+ }
2046+ });
2047+ p2.add(b);
2048+
2049+ dialog.add(p2, BorderLayout.SOUTH);
2050+ dialog.pack();
2051+ return dialog;
2052+ }
2053+
2054+
2055+ // ================ Protected ================
2056+
2057+ /**
2058+ * Creates a menu for the editing.
2059+ */
2060+ protected Menu createEditMenu() {
2061+ Menu menu = new Menu(L_EDIT);
2062+ menu.add(createMenuItem(L_COPY, A_COPY, null));
2063+ menu.add(createMenuItem(L_CUT, A_CUT, null));
2064+ menu.add(createMenuItem(L_PASTE, A_PASTE, null));
2065+ menu.addSeparator();
2066+ menu.add(createMenuItem(L_FIND, A_FIND, null));
2067+ menu.addSeparator();
2068+ menu.add(createMenuItem(L_UNDO, A_UNDO, null));
2069+ menu.addSeparator();
2070+ menu.add(createMenuItem(L_PRINT, A_PRINT, null));
2071+ return menu;
2072+ }
2073+
2074+ /**
2075+ * Creates a popup menu.
2076+ */
2077+ protected PopupMenu createPopupMenu() {
2078+ PopupMenu menu = new PopupMenu();
2079+ menu.add(createMenuItem(L_COPY, A_COPY, null));
2080+ menu.add(createMenuItem(L_CUT, A_CUT, null));
2081+ menu.add(createMenuItem(L_PASTE, A_PASTE, null));
2082+ menu.addSeparator();
2083+ menu.add(createMenuItem(L_FIND, A_FIND, null));
2084+ menu.addSeparator();
2085+ menu.add(createMenuItem(L_UNDO, A_UNDO, null));
2086+ menu.addSeparator();
2087+ menu.add(createMenuItem(L_PRINT, A_PRINT, null));
2088+ return menu;
2089+ }
2090+
2091+ /**
2092+ * Creates a menu item.
2093+ */
2094+ protected MenuItem createMenuItem(String label, String action,
2095+ String shortcut)
2096+ {
2097+ MenuItem mi = new MenuItem(label);
2098+ if (shortcut != null && shortcut.length() > 0) {
2099+ mi.setShortcut(new MenuShortcut(shortcut.charAt(0)));
2100+ }
2101+ mi.setActionCommand(action);
2102+ mi.addActionListener(this);
2103+ return mi;
2104+ }
2105+
2106+ /**
2107+ * Enables or disaples the specified menu.
2108+ */
2109+ protected void setMenuEnabled(Menu menu, boolean b) {
2110+ int count = menu.getItemCount();
2111+ for (int i = 0; i < count; i++) {
2112+ MenuItem item = menu.getItem(i);
2113+ /*
2114+ if (!L_COPY.equals(item.getLabel()) &&
2115+ !L_FIND.equals(item.getLabel()) &&
2116+ !L_PRINT.equals(item.getLabel()))
2117+ */
2118+ if (!A_COPY.equals(item.getActionCommand()) &&
2119+ !A_FIND.equals(item.getActionCommand()) &&
2120+ !A_PRINT.equals(item.getActionCommand()))
2121+ {
2122+ item.setEnabled(b);
2123+ }
2124+ }
2125+ }
2126+
2127+ /**
2128+ * Sets the beginning position of the selection.
2129+ */
2130+ protected void setSelectionBegin(TextPositionInfo posInfo) {
2131+ view.selectionBegin = posInfo;
2132+ setCurrentTypeIn(posInfo);
2133+ }
2134+
2135+ /**
2136+ * Sets the ending position of the selection.
2137+ */
2138+ protected void setSelectionEnd(TextPositionInfo posInfo) {
2139+ view.selectionEnd = posInfo;
2140+ }
2141+
2142+ /**
2143+ * Sets the beginning and ending positions of the selection.
2144+ */
2145+ protected void setSelectionBeginEnd(TextPositionInfo posInfo) {
2146+ view.selectionBegin = view.selectionEnd = posInfo;
2147+ setCurrentTypeIn(posInfo);
2148+ }
2149+
2150+ /**
2151+ * Sets the beginning and ending positions of the selection.
2152+ */
2153+ protected void setSelectionBeginEnd(TextPositionInfo begin,
2154+ TextPositionInfo end)
2155+ {
2156+ view.selectionBegin = begin;
2157+ view.selectionEnd = end;
2158+ setCurrentTypeIn(begin);
2159+ }
2160+
2161+ /**
2162+ * Notifies the text position event to the text position listeners.
2163+ */
2164+ protected void notifyTextPositionListeners() {
2165+ if (selectionVisibleAtFocus && !view.selectionIsCaret() &&
2166+ !view.isSelectionVisible())
2167+ {
2168+ view.setSelectionVisible(true);
2169+ }
2170+ view.notifyTextPositionListeners();
2171+ }
2172+
2173+ /**
2174+ * Sets the current (type in) text style from the specified text position.
2175+ */
2176+ protected void setCurrentTypeIn(TextPositionInfo posInfo) {
2177+ Text text = model.getRichText().getText();
2178+ int length = text.length();
2179+ if (posInfo == null || length == 0) {
2180+ typeInStyle = model.getRichText().getRichTextStyle().getTextStyle();
2181+ typeInText = new Text(" ", typeInStyle);
2182+ return;
2183+ }
2184+ int index = posInfo.textIndex;
2185+ if (index > 0) --index;
2186+ typeInStyle = text.getTextStyleAt(index);
2187+ typeInText = new Text(" ", typeInStyle);
2188+ }
2189+
2190+ /**
2191+ * Expands and moves the selection according to the specified text position.
2192+ */
2193+ protected void dragSelectionTo(TextPositionInfo posInfo) {
2194+ if (dragOrigin == null || dragCurrent == null) {
2195+ // not happen
2196+ dragOrigin = dragCurrent = posInfo;
2197+ view.scrollTo(posInfo);
2198+ view.hideSelection();
2199+ setSelectionBeginEnd(posInfo);
2200+ view.showSelection();
2201+ return;
2202+ }
2203+ if (dragCurrent.textIndex == posInfo.textIndex) {
2204+ return;
2205+ }
2206+
2207+ view.scrollTo(posInfo);
2208+
2209+ if (dragOrigin.textIndex == posInfo.textIndex) {
2210+ dragCurrent = posInfo;
2211+ view.hideSelection();
2212+ setSelectionBeginEnd(posInfo);
2213+ view.showSelection();
2214+ return;
2215+ }
2216+ if (dragOrigin.textIndex == dragCurrent.textIndex) {
2217+ view.hideSelection();
2218+ dragCurrent = posInfo;
2219+ if (dragOrigin.textIndex < dragCurrent.textIndex)
2220+ setSelectionBeginEnd(dragOrigin, dragCurrent);
2221+ else
2222+ setSelectionBeginEnd(dragCurrent, dragOrigin);
2223+ view.showSelection();
2224+ return;
2225+ }
2226+ if (dragOrigin.textIndex < dragCurrent.textIndex) {
2227+ if (posInfo.textIndex < dragOrigin.textIndex) {
2228+ view.hideSelection();
2229+ setSelectionBeginEnd(posInfo, dragOrigin);
2230+ view.showSelection();
2231+ dragCurrent = posInfo;
2232+ }
2233+ else if (dragCurrent.textIndex < posInfo.textIndex) {
2234+ view.paintSelection(dragCurrent,
2235+ posInfo,
2236+ view.getSelectionForeground(),
2237+ view.getSelectionBackground());
2238+ setSelectionBeginEnd(dragOrigin, posInfo);
2239+ dragCurrent = posInfo;
2240+ }
2241+ else { // dragOrigin < posInfo < dragCurrent
2242+ view.paintSelection(posInfo,
2243+ dragCurrent,
2244+ view.getForeground(),
2245+ view.getBackground());
2246+ setSelectionBeginEnd(dragOrigin, posInfo);
2247+ dragCurrent = posInfo;
2248+ }
2249+ }
2250+ else { // dragCurrent.textIndex < dragOrigin.textIndex
2251+ if (posInfo.textIndex < dragCurrent.textIndex) {
2252+ view.paintSelection(posInfo,
2253+ dragCurrent,
2254+ view.getSelectionForeground(),
2255+ view.getSelectionBackground());
2256+ setSelectionBeginEnd(posInfo, dragOrigin);
2257+ dragCurrent = posInfo;
2258+ }
2259+ else if (dragOrigin.textIndex < posInfo.textIndex) {
2260+ view.hideSelection();
2261+ setSelectionBeginEnd(dragOrigin, posInfo);
2262+ view.showSelection();
2263+ dragCurrent = posInfo;
2264+ }
2265+ else { // dragCurrent < posInfo < dragOrigin
2266+ view.paintSelection(dragCurrent,
2267+ posInfo,
2268+ view.getForeground(),
2269+ view.getBackground());
2270+ setSelectionBeginEnd(posInfo, dragOrigin);
2271+ dragCurrent = posInfo;
2272+ }
2273+ }
2274+ }
2275+
2276+ /**
2277+ * Replaces the text of the model with the specified text.
2278+ *
2279+ * @param text the replacement text.
2280+ * @param begin the beginning position to replace, inclusive.
2281+ * @param end the endign position to replace, exclusive.
2282+ * @param scroll if true, scrolls the view after replace done.
2283+ */
2284+ protected synchronized void replaceRange(Text text,
2285+ TextPositionInfo begin,
2286+ TextPositionInfo end,
2287+ boolean scroll)
2288+ {
2289+ if (!view.isEditable() || begin == null || end == null)
2290+ return;
2291+ if (begin.textIndex == end.textIndex && text.length() == 0)
2292+ return;
2293+
2294+ lastUndo = model.replace(begin.textIndex, end.textIndex, text);
2295+
2296+ if (view.isShowing()) {
2297+ if (scroll) {
2298+ view.scrollTo(view.getSelectionBegin());
2299+ }
2300+ }
2301+
2302+ /*
2303+ int newIndex = begin.textIndex + text.length();
2304+ if (newIndex < 0)
2305+ newIndex = 0;
2306+ else if (newIndex > model.getRichText().length)
2307+ newIndex = model.getRichText().length;
2308+ TextPositionInfo newPos = null;
2309+ if (view.getSelectionBegin().textIndex != newIndex) {
2310+ if (view.getSelectionEnd().textIndex == newIndex)
2311+ newPos = view.getSelectionEnd();
2312+ else
2313+ newPos = view.getTextPositionAt(newIndex);
2314+ }
2315+ else if (view.getSelectionEnd().textIndex != newIndex) {
2316+ // view.getSelectionBegin().textIndex == newIndex
2317+ newPos = view.getSelectionBegin();
2318+ }
2319+
2320+ if (!view.isShowing()) {
2321+ if (newPos != null) {
2322+ setSelectionBeginEnd(newPos);
2323+ }
2324+ }
2325+ else {
2326+ if (newPos != null) {
2327+ view.hideSelection();
2328+ setSelectionBeginEnd(newPos);
2329+ view.showSelection(); // show caret
2330+ }
2331+ if (scroll) {
2332+ view.scrollTo(view.getSelectionBegin());
2333+ }
2334+ }
2335+ */
2336+ }
2337+
2338+ /**
2339+ * Changes the text style of the model with the specified style or modifier.
2340+ *
2341+ * @param style the new text style or <code>null</code>.
2342+ * @param modifier the text style modifier or <code>null</code>.
2343+ * @param begin the beginning position to change, inclusive.
2344+ * @param end the endign position to change, exclusive.
2345+ * @param scroll if true, scrolls the view after change done.
2346+ */
2347+ protected synchronized void changeTextStyle(TextStyle style,
2348+ TextStyleModifier modifier,
2349+ TextPositionInfo begin,
2350+ TextPositionInfo end,
2351+ boolean scroll)
2352+ {
2353+ if (!view.isEditable() || begin == null || end == null)
2354+ return;
2355+ if (begin.textIndex == end.textIndex)
2356+ return;
2357+
2358+ /*
2359+ int selBegin = view.getSelectionBegin().textIndex;
2360+ int selEnd = view.getSelectionEnd().textIndex;
2361+ */
2362+
2363+ if (style != null) {
2364+ lastUndo =
2365+ model.setTextStyle(begin.textIndex, end.textIndex, style);
2366+ }
2367+ else if (modifier != null) {
2368+ lastUndo =
2369+ model.modifyTextStyle(begin.textIndex, end.textIndex, modifier);
2370+ }
2371+ else {
2372+ return;
2373+ }
2374+
2375+ if (view.isShowing()) {
2376+ if (scroll) {
2377+ view.scrollTo(view.getSelectionBegin());
2378+ }
2379+ }
2380+
2381+ /*
2382+ TextPositionInfo selBeginPos = null;
2383+ TextPositionInfo selEndPos = null;
2384+ if (view.getSelectionBegin().textIndex != selBegin) {
2385+ selBeginPos = view.getTextPositionAt(selBegin);
2386+ }
2387+ if (view.getSelectionEnd().textIndex != selEnd) {
2388+ selEndPos = view.getTextPositionAt(selEnd);
2389+ }
2390+
2391+ if (!view.isShowing()) {
2392+ if (selBeginPos != null || selEndPos != null) {
2393+ setSelectionBeginEnd(selBeginPos, selEndPos);
2394+ }
2395+ }
2396+ else {
2397+ if (selBeginPos != null || selEndPos != null) {
2398+ view.hideSelection();
2399+ setSelectionBeginEnd(selBeginPos, selEndPos);
2400+ view.showSelection();
2401+ }
2402+ if (scroll) {
2403+ view.scrollTo(view.getSelectionBegin());
2404+ }
2405+ }
2406+ */
2407+ }
2408+
2409+ /**
2410+ * Changes the paragraph style of the model with the specified style or
2411+ * modifier.
2412+ *
2413+ * @param style the new paragraph style or <code>null</code>.
2414+ * @param modifier the paragraph style modifier or <code>null</code>.
2415+ * @param begin the beginning position to change, inclusive.
2416+ * @param end the endign position to change, exclusive.
2417+ * @param scroll if true, scrolls the view after change done.
2418+ */
2419+ protected synchronized void changeParagraphStyle(ParagraphStyle style,
2420+ ParagraphStyleModifier modifier,
2421+ TextPositionInfo begin,
2422+ TextPositionInfo end,
2423+ boolean scroll)
2424+ {
2425+ if (!view.isEditable() || begin == null || end == null)
2426+ return;
2427+
2428+ /*
2429+ int selBegin = view.getSelectionBegin().textIndex;
2430+ int selEnd = view.getSelectionEnd().textIndex;
2431+ */
2432+
2433+ if (style != null) {
2434+ lastUndo =
2435+ model.setParagraphStyle(begin.textIndex, end.textIndex, style);
2436+ }
2437+ else if (modifier != null) {
2438+ lastUndo = model.modifyParagraphStyle(begin.textIndex,
2439+ end.textIndex, modifier);
2440+ }
2441+ else {
2442+ return;
2443+ }
2444+
2445+ if (view.isShowing()) {
2446+ if (scroll) {
2447+ view.scrollTo(view.getSelectionBegin());
2448+ }
2449+ }
2450+
2451+ /*
2452+ TextPositionInfo selBeginPos = null;
2453+ TextPositionInfo selEndPos = null;
2454+ if (view.getSelectionBegin().textIndex != selBegin) {
2455+ selBeginPos = view.getTextPositionAt(selBegin);
2456+ }
2457+ if (view.getSelectionEnd().textIndex != selEnd) {
2458+ if (selBegin == selEnd && selBeginPos != null)
2459+ selEndPos = selBeginPos;
2460+ else
2461+ selEndPos = view.getTextPositionAt(selEnd);
2462+ }
2463+
2464+ if (!view.isShowing()) {
2465+ if (selBeginPos != null || selEndPos != null) {
2466+ setSelectionBeginEnd(selBeginPos, selEndPos);
2467+ }
2468+ }
2469+ else {
2470+ if (selBeginPos != null || selEndPos != null) {
2471+ view.hideSelection();
2472+ setSelectionBeginEnd(selBeginPos, selEndPos);
2473+ view.showSelection();
2474+ }
2475+ if (scroll) {
2476+ view.scrollTo(view.getSelectionBegin());
2477+ }
2478+ }
2479+ */
2480+ }
2481+
2482+ /*if[JDK1.2]*/
2483+
2484+ /**
2485+ * Adds this controller to the view.
2486+ */
2487+ /*if[JDK1.2]*/
2488+ protected void addToView() {
2489+ super.addToView();
2490+ getView().addInputMethodListener(this);
2491+ }
2492+
2493+ /**
2494+ * Invoked when the text entered through an input method has changed.
2495+ */
2496+ /*if[JDK1.2]*/
2497+ public void inputMethodTextChanged(InputMethodEvent e) {
2498+ if (!view.isEnabled())
2499+ return;
2500+
2501+ if (e.isConsumed())
2502+ return;
2503+
2504+ if (!view.isEditable()) {
2505+ //view.getToolkit().beep();
2506+ e.consume();
2507+ return;
2508+ }
2509+
2510+ replaceInputMethodText(e);
2511+ setInputMethodCaretPosition(e);
2512+
2513+ e.consume();
2514+ }
2515+
2516+ /**
2517+ * Invoked when the caret within composed text has changed.
2518+ */
2519+ /*if[JDK1.2]*/
2520+ public void caretPositionChanged(InputMethodEvent e) {
2521+ if (!view.isEnabled())
2522+ return;
2523+
2524+ if (e.isConsumed())
2525+ return;
2526+
2527+ if (!view.isEditable()) {
2528+ //view.getToolkit().beep();
2529+ e.consume();
2530+ return;
2531+ }
2532+
2533+ setInputMethodCaretPosition(e);
2534+
2535+ e.consume();
2536+ }
2537+
2538+
2539+ protected TextStyle savedTypeInStyle;
2540+ protected TextPositionInfo composedTextBegin;
2541+ protected TextPositionInfo composedTextEnd;
2542+
2543+
2544+ //
2545+ // Replaces the current input method (composed) text according to
2546+ // the passed input method event. This method also inserts the
2547+ // committed text into the document.
2548+ //
2549+ protected void replaceInputMethodText(InputMethodEvent e) {
2550+ int commitCount = e.getCommittedCharacterCount();
2551+ AttributedCharacterIterator text = e.getText();
2552+
2553+ if (text == null) {
2554+ // old composed text deletion
2555+ if (composedTextBegin != null) {
2556+ replaceRange(new Text("", savedTypeInStyle),
2557+ composedTextBegin, composedTextEnd, true);
2558+ composedTextBegin = composedTextEnd = null;
2559+ }
2560+ if (savedTypeInStyle != null) {
2561+ typeInStyle = savedTypeInStyle;
2562+ typeInText = new Text(" ", typeInStyle);
2563+ savedTypeInStyle = null;
2564+ }
2565+ }
2566+ else {
2567+ if (savedTypeInStyle == null) {
2568+ savedTypeInStyle = typeInStyle;
2569+ }
2570+ TextBuffer buffer = new TextBuffer();
2571+ buffer.setTextStyle(savedTypeInStyle);
2572+
2573+ // committed text insertion
2574+ if (commitCount > 0) {
2575+ for (char c = text.first();
2576+ commitCount > 0;
2577+ c = text.next(), commitCount--)
2578+ {
2579+ buffer.append(c);
2580+ }
2581+ }
2582+
2583+ int composedTextIndex = text.getIndex();
2584+ if (composedTextIndex >= text.getEndIndex()) {
2585+ if (composedTextBegin != null) {
2586+ replaceRange(buffer.toText(),
2587+ composedTextBegin, composedTextEnd, true);
2588+ composedTextBegin = composedTextEnd = null;
2589+ }
2590+ else {
2591+ replaceSelection(buffer.toText());
2592+ }
2593+ if (savedTypeInStyle != null) {
2594+ typeInStyle = savedTypeInStyle;
2595+ typeInText = new Text(" ", typeInStyle);
2596+ savedTypeInStyle = null;
2597+ }
2598+ }
2599+ else { // composedTextIndex < text.getEndIndex()
2600+ // new composed text insertion
2601+ ComposedTextStyle composedStyle =
2602+ new ComposedTextStyle(savedTypeInStyle, null);
2603+ BasicTSModifier modifier = new BasicTSModifier();
2604+ modifier.put(BasicTSModifier.COLOR,
2605+ view.getSelectionForeground());
2606+ ComposedTextStyle selectedStyle =
2607+ new ComposedTextStyle(
2608+ modifier.modify(savedTypeInStyle),
2609+ view.getSelectionBackground());
2610+ buffer.setTextStyle(composedStyle);
2611+
2612+ int commitLen = buffer.length();
2613+ char c = text.setIndex(composedTextIndex);
2614+ while (c != CharacterIterator.DONE) {
2615+ Map attrs = text.getAttributes();
2616+ InputMethodHighlight hl =
2617+ (InputMethodHighlight)attrs.get(
2618+ TextAttribute.INPUT_METHOD_HIGHLIGHT);
2619+ if (hl == null) {
2620+ buffer.setTextStyle(composedStyle);
2621+ }
2622+ else {
2623+ if (hl.isSelected()) {
2624+ buffer.setTextStyle(selectedStyle);
2625+ }
2626+ else {
2627+ buffer.setTextStyle(composedStyle);
2628+ }
2629+ switch (hl.getState()) {
2630+ case InputMethodHighlight.RAW_TEXT:
2631+ case InputMethodHighlight.CONVERTED_TEXT:
2632+ }
2633+ }
2634+ int runLimit = text.getRunLimit();
2635+ while (text.getIndex() < runLimit) {
2636+ buffer.append(c);
2637+ c = text.next();
2638+ }
2639+ c = text.setIndex(runLimit);
2640+ }
2641+
2642+ if (composedTextBegin != null) {
2643+ replaceRange(buffer.toText(),
2644+ composedTextBegin, composedTextEnd, true);
2645+ composedTextEnd =
2646+ view.getTextPositionAt(
2647+ composedTextBegin.textIndex + buffer.length());
2648+ }
2649+ else {
2650+ replaceSelection(buffer.toText());
2651+ composedTextEnd = view.getSelectionEnd();
2652+ }
2653+ composedTextBegin =
2654+ view.getTextPositionNearby(composedTextEnd,
2655+ composedTextEnd.textIndex -
2656+ (buffer.length() - commitLen));
2657+ }
2658+ }
2659+ }
2660+
2661+ //
2662+ // Sets the caret position according to the passed input method
2663+ // event. Also, sets/resets composed text caret appropriately.
2664+ //
2665+ protected void setInputMethodCaretPosition(InputMethodEvent e) {
2666+ if (composedTextBegin != null) {
2667+ int index = composedTextBegin.textIndex;
2668+ TextHitInfo caretPos = e.getCaret();
2669+ if (caretPos != null) {
2670+ index += caretPos.getInsertionIndex();
2671+ }
2672+ TextPositionInfo pos =
2673+ view.getTextPositionNearby(composedTextBegin, index);
2674+ select(pos, pos, true, false);
2675+ }
2676+ }
2677+
2678+
2679+ static class ComposedTextStyle extends TextStyle {
2680+ static Stroke DashedStroke =
2681+ new BasicStroke(1.0f,
2682+ BasicStroke.CAP_SQUARE,
2683+ BasicStroke.JOIN_MITER,
2684+ 10.0f,
2685+ new float[]{ 2.0f, 2.0f },
2686+ 0.0f);
2687+
2688+ Color selectionColor;
2689+
2690+ public ComposedTextStyle(TextStyle textStyle, Color selectionColor) {
2691+ super(textStyle.getFont(),
2692+ textStyle.getExtendedFont().getColor(),
2693+ false);
2694+ this.selectionColor = selectionColor;
2695+ }
2696+
2697+ public void drawText(Graphics g, char text[], int offset, int length,
2698+ boolean isRunStart, boolean isRunEnd,
2699+ int x, int y, int width, int height,
2700+ int baseLine)
2701+ {
2702+ if (selectionColor != null) {
2703+ Color color = g.getColor();
2704+ g.setColor(selectionColor);
2705+ g.fillRect(x, y, width, height);
2706+ g.setColor(color);
2707+ }
2708+
2709+ super.drawText(g, text, offset, length, isRunStart, isRunEnd,
2710+ x, y, width, height, baseLine);
2711+
2712+ Graphics2D g2 = (Graphics2D)g;
2713+ Stroke s = g2.getStroke();
2714+ g2.setStroke(DashedStroke);
2715+ g2.drawLine(x, y + height - 1, x + width, y + height - 1);
2716+ g2.setStroke(s);
2717+ }
2718+
2719+ public int hashCode() {
2720+ int hash = super.hashCode();
2721+ if (selectionColor != null) {
2722+ hash ^= selectionColor.hashCode();
2723+ }
2724+ return hash;
2725+ }
2726+
2727+ public boolean equals(Object anObject) {
2728+ if (this == anObject)
2729+ return true;
2730+ if (anObject == null)
2731+ return false;
2732+ if (getClass() == anObject.getClass()) {
2733+ ComposedTextStyle style = (ComposedTextStyle)anObject;
2734+ return equalsFontAndAction(style) &&
2735+ (selectionColor == null ?
2736+ style.selectionColor == null :
2737+ selectionColor.equals(style.selectionColor));
2738+ }
2739+ return false;
2740+ }
2741+ }
2742+
2743+ /*end[JDK1.2]*/
2744+
2745+}
--- branches/client/kfc2/src/main/java/jp/kyasu/awt/text/TextEditView.java (nonexistent)
+++ branches/client/kfc2/src/main/java/jp/kyasu/awt/text/TextEditView.java (revision 50)
@@ -0,0 +1,1156 @@
1+/*
2+ * TextEditView.java
3+ *
4+ * Copyright (c) 1997, 1998 Kazuki YASUMATSU. All Rights Reserved.
5+ *
6+ * Permission to use, copy, modify, and distribute this software and its
7+ * documentation for any purpose and without fee or royalty is hereby
8+ * granted, provided that both the above copyright notice and this
9+ * permission notice appear in all copies of the software and
10+ * documentation or portions thereof, including modifications, that you
11+ * make.
12+ *
13+ * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO
14+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE,
15+ * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR
16+ * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
17+ * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
18+ * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
19+ * COPYRIGHT HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE
20+ * OR DOCUMENTATION.
21+ */
22+
23+package jp.kyasu.awt.text;
24+
25+import jp.kyasu.awt.AWTResources;
26+import jp.kyasu.awt.TextModel;
27+import jp.kyasu.awt.TextEditModel;
28+import jp.kyasu.awt.event.TextModelEvent;
29+import jp.kyasu.awt.event.TextModelListener;
30+import jp.kyasu.awt.event.TextPositionEvent;
31+import jp.kyasu.awt.event.TextPositionListener;
32+import jp.kyasu.graphics.ClickableTextAction;
33+import jp.kyasu.graphics.RichText;
34+import jp.kyasu.graphics.Text;
35+import jp.kyasu.graphics.TextLayout;
36+import jp.kyasu.graphics.TextStyle;
37+import jp.kyasu.graphics.text.TextChange;
38+import jp.kyasu.graphics.text.TextLayoutChange;
39+import jp.kyasu.graphics.text.TextPositionInfo;
40+
41+import java.awt.AWTEvent;
42+import java.awt.Color;
43+import java.awt.Cursor;
44+import java.awt.Dimension;
45+import java.awt.Font;
46+import java.awt.Graphics;
47+import java.util.Enumeration;
48+import java.util.Vector;
49+
50+/*if[JDK1.2]*/
51+import java.awt.Point;
52+import java.awt.Rectangle;
53+import java.awt.im.InputMethodRequests;
54+import java.text.AttributedCharacterIterator;
55+import java.text.AttributedCharacterIterator.Attribute;
56+import java.text.AttributedString;
57+import java.awt.font.TextHitInfo;
58+/*end[JDK1.2]*/
59+
60+/**
61+ * The <code>TextEditView</code> class implements a view of a MVC model for
62+ * the text editing. The model of the MVC model is a <code>TextEditModel</code>
63+ * object and the controller of the MVC model is a
64+ * <code>TextEditController</code> object.
65+ *
66+ * @see jp.kyasu.awt.TextEditModel
67+ * @see jp.kyasu.awt.text.TextEditController
68+ *
69+ * @version 12 Dec 1998
70+ * @author Kazuki YASUMATSU
71+ */
72+public class TextEditView extends TextView implements TextModelListener {
73+ protected TextEditModel model;
74+ protected TextEditController controller;
75+ protected boolean editable;
76+ protected Color caretColor;
77+ protected TextCaret textCaret;
78+ transient protected TextPositionInfo selectionBegin;
79+ transient protected TextPositionInfo selectionEnd;
80+
81+ transient protected Vector textPositionListeners;
82+
83+
84+ /**
85+ * The default cursor.
86+ */
87+ static public final Cursor DEFAULT_CURSOR =
88+ Cursor.getPredefinedCursor(AWTResources.getResourceInteger(
89+ "kfc.text.cursor", Cursor.TEXT_CURSOR));
90+
91+
92+ /**
93+ * Constructs a text edit view with the specified text edit model.
94+ *
95+ * @param textEditModel the text edit model.
96+ */
97+ public TextEditView(TextEditModel textEditModel) {
98+ super(textEditModel.getRichText().getRichTextStyle().getLineWrap());
99+ if (textEditModel == null)
100+ throw new NullPointerException();
101+
102+ model = textEditModel;
103+ model.addTextModelListener(this);
104+ controller = new TextEditController(this);
105+ controller.addToView();
106+
107+ editable = true;
108+
109+ caretColor = TextCaret.DEFAULT_CARET_COLOR;
110+ setTextCaret(new TextCaret());
111+
112+ setCursor(DEFAULT_CURSOR);
113+
114+ setTextLayout(createTextLayout());
115+
116+ //enableInputMethods(true);
117+ }
118+
119+
120+ /**
121+ * Returns the <code>RichText</code> object being viewed.
122+ */
123+ public RichText getRichText() {
124+ return model.getRichText();
125+ }
126+
127+ /**
128+ * Returns the model of this view.
129+ */
130+ public TextEditModel getModel() {
131+ return model;
132+ }
133+
134+ /**
135+ * Returns the controller of this view.
136+ */
137+ public TextEditController getController() {
138+ return controller;
139+ }
140+
141+ /**
142+ * Sets the controller of this view.
143+ */
144+ public synchronized void setController(TextEditController controller) {
145+ if (controller == null)
146+ throw new NullPointerException();
147+ if (controller.view != this)
148+ throw new IllegalArgumentException("view of controller is not valid");
149+ this.controller.removeFromView();
150+ this.controller = controller;
151+ this.controller.addToView();
152+ }
153+
154+ /**
155+ * Invoked when the text model has been changed.
156+ * @see jp.kyasu.awt.event.TextModelListener
157+ */
158+ public void textModelChanged(TextModelEvent event) {
159+ switch (event.getID()) {
160+ case TextModelEvent.TEXT_MODEL_UPDATED:
161+ setTextLayout(createTextLayout());
162+ controller.lastUndo = null;
163+ controller.setCurrentTypeIn(getSelectionBegin());
164+ break;
165+ case TextModelEvent.TEXT_MODEL_EDITED:
166+ updateAfterEdited(event);
167+ break;
168+ }
169+ }
170+
171+ /**
172+ * Sets the <code>TextLayout</code> object of this view.
173+ */
174+ protected synchronized void setTextLayout(TextLayout layout) {
175+ if (layout == null)
176+ throw new NullPointerException();
177+ if (isShowing() && needsToRedrawSelection()) {
178+ hideSelection();
179+ }
180+
181+ selectionBegin = selectionEnd = null;
182+
183+ super.setTextLayout(layout);
184+
185+ if (isValid()) {
186+ selectionBegin = selectionEnd = layout.getTextPositionAt(0);
187+ }
188+ }
189+
190+ /**
191+ * Sets the <code>Text</code> object of this view.
192+ * @param text the <code>Text</code> object.
193+ */
194+ public void setText(Text text) {
195+ if (text == null)
196+ throw new NullPointerException();
197+ setRichText(new RichText(text, model.getRichText().getRichTextStyle()));
198+ }
199+
200+ /**
201+ * Sets the <code>RichText</code> object of this view.
202+ * @param richText the <code>RichText</code> object.
203+ */
204+ public void setRichText(RichText richText) {
205+ if (richText == null)
206+ throw new NullPointerException();
207+ model.setRichText(richText);
208+ }
209+
210+ /**
211+ * Returns the beginning text position of the selection, inclusive.
212+ */
213+ public TextPositionInfo getSelectionBegin() {
214+ return selectionBegin;
215+ }
216+
217+ /**
218+ * Sets the beginning text position of the selection, inclusive.
219+ */
220+ protected void setSelectionBegin(TextPositionInfo posInfo) {
221+ selectionBegin = posInfo;
222+ }
223+
224+ /**
225+ * Returns the ending text position of the selection, exclusive.
226+ */
227+ public TextPositionInfo getSelectionEnd() {
228+ return selectionEnd;
229+ }
230+
231+ /**
232+ * Sets the ending text position of the selection, exclusive.
233+ */
234+ protected void setSelectionEnd(TextPositionInfo posInfo) {
235+ selectionEnd = posInfo;
236+ }
237+
238+ /**
239+ * Sets the text position of the selection.
240+ */
241+ protected void setSelectionBeginEnd(TextPositionInfo posInfo) {
242+ selectionBegin = selectionEnd = posInfo;
243+ }
244+
245+ /**
246+ * Sets the range of the selection.
247+ */
248+ protected void setSelectionBeginEnd(TextPositionInfo begin,
249+ TextPositionInfo end)
250+ {
251+ selectionBegin = begin;
252+ selectionEnd = end;
253+ }
254+
255+ /**
256+ * Tests if this view is editable.
257+ */
258+ public boolean isEditable() {
259+ return editable;
260+ }
261+
262+ /**
263+ * Makes this view editable.
264+ */
265+ public void setEditable(boolean b) {
266+ editable = b;
267+ }
268+
269+ /**
270+ * Enables or disables this view.
271+ */
272+ public synchronized void setEnabled(boolean b) {
273+ if (isEnabled() == b)
274+ return;
275+ super.setEnabled(b);
276+ if (isEnabled()) {
277+ startTextCaret();
278+ }
279+ else {
280+ stopTextCaret();
281+ }
282+ }
283+
284+ /**
285+ * Returns the caret color.
286+ * @see #setCaretColor(java.awt.Color)
287+ */
288+ public Color getCaretColor() {
289+ return caretColor;
290+ }
291+
292+ /**
293+ * Sets the caret color.
294+ * @see #getCaretColor()
295+ */
296+ public synchronized void setCaretColor(Color c) {
297+ if (c == null)
298+ return;
299+
300+ if (caretColor.equals(c)) {
301+ return;
302+ }
303+
304+ boolean showing =
305+ isShowing() && selectionShowing && selectionIsCaret();
306+ if (showing) hideSelection();
307+ caretColor = c;
308+ if (showing) showSelection();
309+ }
310+
311+ /**
312+ * Returns the text caret of this view.
313+ * @see #setTextCaret(jp.kyasu.awt.text.TextCaret)
314+ */
315+ public TextCaret getTextCaret() {
316+ return textCaret;
317+ }
318+
319+ /**
320+ * Sets the text caret of this view.
321+ * @see #getTextCaret()
322+ */
323+ public synchronized void setTextCaret(TextCaret textCaret) {
324+ if (textCaret == null)
325+ throw new NullPointerException();
326+ boolean showing =
327+ isShowing() && selectionShowing && selectionIsCaret();
328+ boolean blinking =
329+ this.textCaret != null && this.textCaret.isBlinking();
330+ if (showing) hideSelection();
331+ if (blinking) stopTextCaret();
332+
333+ if (this.textCaret != null) this.textCaret.setTarget(null);
334+ this.textCaret = textCaret;
335+ this.textCaret.setTarget(this);
336+
337+ if (blinking) startTextCaret();
338+ if (showing) showSelection();
339+ }
340+
341+ /**
342+ * Starts the text caret of this view.
343+ * @see #stopTextCaret()
344+ */
345+ protected synchronized void startTextCaret() {
346+ if (textCaret != null) {
347+ boolean showing =
348+ isShowing() && selectionShowing && selectionIsCaret();
349+ if (showing) hideSelection();
350+ textCaret.start();
351+ if (showing) showSelection();
352+ }
353+ }
354+
355+ /**
356+ * Stops the text caret of this view.
357+ * @see #startTextCaret()
358+ */
359+ protected synchronized void stopTextCaret() {
360+ if (textCaret != null) {
361+ boolean showing =
362+ isShowing() && selectionShowing && selectionIsCaret();
363+ if (showing) hideSelection();
364+ textCaret.stop();
365+ if (showing) showSelection();
366+ }
367+ }
368+
369+ /**
370+ * Returns the selected text.
371+ */
372+ public Text getSelectedText() {
373+ if (selectionBegin == null || selectionEnd == null ||
374+ selectionBegin.textIndex == selectionEnd.textIndex)
375+ {
376+ return new Text();
377+ }
378+ return model.getRichText().getText().subtext(selectionBegin.textIndex,
379+ selectionEnd.textIndex);
380+ }
381+
382+ /**
383+ * Resets the location of the layout text.
384+ * This method is called from setBounds().
385+ */
386+ protected void resetLocationOfText() {
387+ if (selectionBegin == null || selectionEnd == null) {
388+ selectionBegin = selectionEnd = layout.getTextPositionAt(0);
389+ offset.x = offset.y = 0;
390+ }
391+ else {
392+ selectionBegin = layout.getTextPositionAt(selectionBegin.textIndex);
393+ selectionEnd = layout.getTextPositionAt(selectionEnd.textIndex);
394+ offset.x = getScrollXTo(selectionBegin);
395+ offset.y = getScrollYTo(selectionBegin);
396+ }
397+ }
398+
399+ /**
400+ * Notifies this view that it has been added to a container.
401+ */
402+ public void addNotify() {
403+ /*
404+ if (textCaret != null) {
405+ textCaret.start();
406+ }
407+ */
408+ super.addNotify();
409+ }
410+
411+ /**
412+ * Notifies this view that it has been removed from its container.
413+ */
414+ public void removeNotify() {
415+ if (textCaret != null) {
416+ textCaret.stop();
417+ }
418+ super.removeNotify();
419+ }
420+
421+ /**
422+ * Sets the font of this view.
423+ */
424+ public void setFont(Font f) {
425+ super.setFont(f);
426+ RichText richText = model.getRichText();
427+ richText.setBaseTextStyle(new TextStyle(f));
428+ model.setRichText(richText);
429+ }
430+
431+ /**
432+ * Add a listener to recieve text position events when the selection
433+ * of the text view changes.
434+ * @param l the listener to recieve events.
435+ */
436+ public void addTextPositionListener(TextPositionListener l) {
437+ if (l == null)
438+ return;
439+ if (textPositionListeners == null)
440+ textPositionListeners = new Vector();
441+ textPositionListeners.addElement(l);
442+ }
443+
444+ /**
445+ * Removes an text position listener.
446+ * @param l the listener being removed.
447+ */
448+ public void removeTextPositionListener(TextPositionListener l) {
449+ if (textPositionListeners == null)
450+ return;
451+ textPositionListeners.removeElement(l);
452+ if (textPositionListeners.size() == 0)
453+ textPositionListeners = null;
454+ }
455+
456+ /**
457+ * Notifies the text position event to the text position listeners.
458+ */
459+ protected void notifyTextPositionListeners() {
460+ if (textPositionListeners == null)
461+ return;
462+ if (selectionBegin == null || selectionEnd == null)
463+ return;
464+ TextPositionEvent event =
465+ new TextPositionEvent(this,
466+ TextPositionEvent.TEXT_POSITION_CHANGED,
467+ selectionBegin, selectionEnd);
468+ for (Enumeration e = textPositionListeners.elements();
469+ e.hasMoreElements();
470+ )
471+ {
472+ ((TextPositionListener)e.nextElement()).textPositionChanged(event);
473+ }
474+ }
475+
476+ /**
477+ * Paints this component.
478+ */
479+ public void paint(Graphics g) {
480+ if (!isShowing())
481+ return;
482+
483+ super.paint(g);
484+
485+ if (needsToRedrawSelection())
486+ showSelection();
487+ }
488+
489+ /**
490+ * Paints this view with the specified range.
491+ */
492+ protected void paint(Graphics g,
493+ TextPositionInfo begin, TextPositionInfo end)
494+ {
495+ if (!selectionVisible || selectionBegin == null || selectionEnd == null)
496+ {
497+ selectionShowing = false;
498+ g.setColor(getForeground());
499+ layout.draw(g, offset, begin, end);
500+ return;
501+ }
502+
503+ if (selectionBegin.textIndex == selectionEnd.textIndex) {
504+ hideSelection(); // hide caret
505+ g.setColor(getForeground());
506+ layout.draw(g, offset, begin, end);
507+ if (!doubleBuffered) {
508+ showSelection(); // show caret
509+ }
510+ return;
511+ }
512+
513+ selectionShowing = true;
514+
515+ if (selectionBegin.textIndex > end.textIndex ||
516+ selectionEnd.textIndex < begin.textIndex)
517+ {
518+ g.setColor(getForeground());
519+ layout.draw(g, offset, begin, end);
520+ return;
521+ }
522+
523+ // begin <= selectionEnd && selectionBegin <= end
524+ TextPositionInfo newBegin;
525+ if (selectionBegin.textIndex <= begin.textIndex)
526+ newBegin = begin;
527+ else { // begin.textIndex < selectionBegin.textIndex
528+ g.setColor(getForeground());
529+ layout.draw(g, offset, begin, selectionBegin);
530+ newBegin = selectionBegin;
531+ }
532+ if (end.textIndex <= selectionEnd.textIndex) {
533+ g.setColor(selectionForeground);
534+ layout.draw(g, offset, newBegin, end,
535+ selectionBackground,
536+ selectionBegin.lineIndex < newBegin.lineIndex,
537+ (end.textIndex == end.lineBegin ?
538+ false : end.lineIndex < selectionEnd.lineIndex));
539+ g.setColor(getForeground());
540+ }
541+ else {
542+ g.setColor(selectionForeground);
543+ layout.draw(g, offset, newBegin, selectionEnd,
544+ selectionBackground,
545+ selectionBegin.lineIndex < newBegin.lineIndex,
546+ false);
547+ g.setColor(getForeground());
548+ layout.draw(g, offset, selectionEnd, end);
549+ }
550+ }
551+
552+ /**
553+ * Shows the selection.
554+ */
555+ protected synchronized void showSelection() {
556+ if (!isShowing())
557+ return;
558+ if (!selectionVisible || selectionShowing)
559+ return;
560+ if (selectionBegin == null || selectionEnd == null)
561+ return;
562+ /*
563+ if (!selectionVisible) {
564+ return;
565+ if (selectionIsCaret())
566+ return;
567+ selectionVisible = true;
568+ }
569+ */
570+ selectionShowing = !selectionShowing;
571+ if (selectionBegin.textIndex == selectionEnd.textIndex) {
572+ if (textCaret != null) {
573+ Graphics g = getGraphics();
574+ if (g != null) {
575+ textCaret.showCaret(g,
576+ offset,
577+ selectionBegin,
578+ caretColor);
579+ g.dispose();
580+ }
581+ }
582+ }
583+ else
584+ paintSelection(selectionForeground, selectionBackground);
585+ }
586+
587+ /**
588+ * Hides the selection.
589+ */
590+ protected synchronized void hideSelection() {
591+ if (!isShowing())
592+ return;
593+ if (!selectionVisible || !selectionShowing)
594+ return;
595+ if (selectionBegin == null || selectionEnd == null)
596+ return;
597+ selectionShowing = !selectionShowing;
598+ if (selectionBegin.textIndex == selectionEnd.textIndex) {
599+ if (textCaret != null) {
600+ Graphics g = getGraphics();
601+ if (g != null) {
602+ textCaret.hideCaret(g,
603+ offset,
604+ selectionBegin,
605+ caretColor);
606+ g.dispose();
607+ }
608+ }
609+ }
610+ else
611+ paintSelection(getForeground(), getBackground());
612+ }
613+
614+ /**
615+ * Paints the selection with the specified colors.
616+ */
617+ protected void paintSelection(Color foreColor, Color backColor) {
618+ paintSelection(selectionBegin, selectionEnd,
619+ foreColor, backColor, true);
620+ }
621+
622+ /**
623+ * Paints the selection of the specified range with the specified colors.
624+ */
625+ protected void paintSelection(TextPositionInfo selBegin,
626+ TextPositionInfo selEnd,
627+ Color foreColor, Color backColor)
628+ {
629+ paintSelection(selBegin, selEnd, foreColor, backColor, false);
630+ }
631+
632+ /**
633+ * Paints the selection of the specified range with the specified colors
634+ * and flag indicating that the specified range is a entire selection.
635+ */
636+ protected void paintSelection(TextPositionInfo selBegin,
637+ TextPositionInfo selEnd,
638+ Color foreColor, Color backColor,
639+ boolean fullSelection)
640+ {
641+ if (selBegin.textIndex == selEnd.textIndex)
642+ return;
643+ TextPositionInfo begin, end;
644+ begin = getVisibleBegin();
645+ end = getVisibleEnd();
646+ if (selBegin.textIndex > end.textIndex ||
647+ selEnd.textIndex < begin.textIndex)
648+ {
649+ return;
650+ }
651+ if (begin.textIndex < selBegin.textIndex)
652+ begin = selBegin;
653+ if (selEnd.textIndex < end.textIndex)
654+ end = selEnd;
655+
656+ Graphics g = getPreferredGraphics();
657+ if (g == null)
658+ return;
659+
660+ g.setColor(foreColor);
661+ if (fullSelection)
662+ layout.draw(g, offset, begin, end, backColor,
663+ selectionBegin.lineIndex < begin.lineIndex,
664+ end.lineIndex < selectionEnd.lineIndex);
665+ else
666+ layout.draw(g, offset, begin, end, backColor);
667+
668+ g.dispose();
669+ syncGraphics(0,
670+ begin.y + offset.y,
671+ getSize().width,
672+ end.y + end.lineSkip - begin.y);
673+ }
674+
675+ /**
676+ * Updates this view after the text edit model has been edited.
677+ */
678+ protected synchronized void updateAfterEdited(TextModelEvent event) {
679+ TextChange change = event.getTextChange();
680+
681+ if (isShowing()) {
682+ if (needsToRedrawSelection()) {
683+ hideSelection();
684+ }
685+ else {
686+ selectionShowing = false;
687+ }
688+ }
689+
690+ Dimension oldSize = layout.getSize();
691+ TextLayoutChange layoutChange = layout.updateLayout(change,
692+ selectionBegin,
693+ selectionEnd);
694+
695+ if (layoutChange.isNoRepaint()) {
696+ // do nothing
697+ }
698+ else if (selectionBegin == null || selectionEnd == null) {
699+ setSelectionBeginEnd(getTextPositionAt(0));
700+ notifyTextPositionListeners();
701+ }
702+ else {
703+ int begin = selectionBegin.textIndex;
704+ int end = selectionEnd.textIndex;
705+ if (change.textReplaced) {
706+ if (change.begin <= begin) {
707+ if (begin < change.end) {
708+ begin = change.end + change.lengthChanged;
709+ }
710+ else {
711+ begin += change.lengthChanged;
712+ }
713+ }
714+ if (change.begin <= end) {
715+ if (end < change.end) {
716+ end = change.end + change.lengthChanged;
717+ }
718+ else {
719+ end += change.lengthChanged;
720+ }
721+ }
722+ }
723+ if (layoutChange.isFullRepaint()) {
724+ if (begin == end) {
725+ setSelectionBeginEnd(getTextPositionAt(begin));
726+ }
727+ else {
728+ setSelectionBegin(getTextPositionAt(begin));
729+ setSelectionEnd(getTextPositionAt(end));
730+ }
731+ }
732+ else if (begin == end) {
733+ if (begin < layoutChange.paintBegin.textIndex) {
734+ if (begin == selectionBegin.textIndex) {
735+ setSelectionBeginEnd(selectionBegin);
736+ }
737+ else if (begin == selectionEnd.textIndex) {
738+ setSelectionBeginEnd(selectionEnd);
739+ }
740+ else {
741+ setSelectionBeginEnd(getTextPositionNearby(
742+ layoutChange.paintBegin, begin));
743+ }
744+ }
745+ else {
746+ setSelectionBeginEnd(
747+ getTextPositionNearby(layoutChange.paintBegin, begin));
748+ }
749+ }
750+ else {
751+ if (begin < layoutChange.paintBegin.textIndex &&
752+ begin == selectionBegin.textIndex)
753+ {
754+ setSelectionBegin(selectionBegin);
755+ }
756+ else {
757+ setSelectionBegin(
758+ getTextPositionNearby(layoutChange.paintBegin, begin));
759+ }
760+ if (end < layoutChange.paintBegin.textIndex &&
761+ end == selectionEnd.textIndex)
762+ {
763+ setSelectionEnd(selectionEnd);
764+ }
765+ else {
766+ setSelectionEnd(
767+ getTextPositionNearby(layoutChange.paintBegin, end));
768+ }
769+ }
770+ notifyTextPositionListeners();
771+ }
772+
773+ if (doubleBuffered || isShowing()) {
774+ if (layoutChange.isPartialRepaint()) {
775+ int paintBegin = event.getPaintBegin();
776+ int paintEnd = event.getPaintEnd();
777+ if (paintBegin >= 0 &&
778+ paintBegin < layoutChange.paintBegin.textIndex)
779+ {
780+ layoutChange.paintBegin =
781+ layout.getTextPositionNearby(layoutChange.paintBegin,
782+ paintBegin);
783+ }
784+ if (paintEnd >= 0 && paintEnd <= model.getRichText().length() &&
785+ paintEnd > layoutChange.paintEnd.textIndex)
786+ {
787+ layoutChange.paintEnd =
788+ layout.getTextPositionNearby(layoutChange.paintEnd,
789+ paintEnd);
790+ }
791+ }
792+ paintAfterEdited(layoutChange);
793+ if (isShowing()) {
794+ showSelection(); // show caret
795+ }
796+ }
797+ if (layoutChange.isFullRepaint())
798+ layoutResized(-1, -1);
799+ else
800+ layoutResized(oldSize.width, oldSize.height);
801+ }
802+
803+ /**
804+ * Paints this view after the text edit model has been edited.
805+ */
806+ protected synchronized void paintAfterEdited(TextLayoutChange change) {
807+ if (change.isNoRepaint())
808+ return;
809+
810+ Graphics g = getPreferredGraphics();
811+ if (g == null)
812+ return;
813+
814+ if (change.isFullRepaint()) {
815+ _visibleBegin = _visibleEnd = null;
816+ Dimension d = getSize();
817+ Dimension ld = layout.getSize();
818+ if (ld.width > d.width && ld.width + offset.x < d.width)
819+ offset.x = d.width - ld.width;
820+ if (ld.height > d.height && ld.height + offset.y < d.height)
821+ offset.y = d.height - ld.height;
822+ paintOn(g);
823+ g.dispose();
824+ syncGraphics();
825+ return;
826+ }
827+
828+ TextPositionInfo paintBegin = change.paintBegin;
829+ TextPositionInfo paintEnd = change.paintEnd;
830+ TextPositionInfo vBegin = null;
831+ TextPositionInfo vEnd = null;
832+ int newCleanTop = paintEnd.y + offset.y;
833+ int oldCleanTop = newCleanTop - change.heightChanged;
834+ int drawWidth = (change.widthChanged < 0 ?
835+ layout.getSize().width - change.widthChanged :
836+ layout.getSize().width);
837+ Dimension d = getSize();
838+ if (change.heightChanged < 0) { // view up
839+ TextPositionInfo pBegin = paintEnd;
840+ if (oldCleanTop < d.height && newCleanTop >=0) {
841+ // copyArea() may be fail.
842+ scrolledUp = true;
843+ g.copyArea(0, oldCleanTop, d.width, d.height - oldCleanTop,
844+ 0, change.heightChanged);
845+ pBegin = layout.getLineBeginPositionOver(
846+ paintEnd,
847+ -offset.y+newCleanTop+d.height-oldCleanTop-1);
848+ }
849+ if (newCleanTop < d.height) {
850+ vEnd = layout.getLineBeginPositionUnder(
851+ paintEnd,
852+ -offset.y + d.height - 1);
853+ layout.draw(g, offset, pBegin, vEnd,
854+ getBackground(),
855+ true,
856+ (vEnd.textIndex >= getRichText().length()),
857+ true,
858+ drawWidth);
859+ int endY = offset.y + vEnd.y + vEnd.lineSkip;
860+ if (endY < d.height) {
861+ g.setColor(getBackground());
862+ g.fillRect(0, endY, d.width, d.height - endY);
863+ g.setColor(getForeground());
864+ }
865+ }
866+ }
867+ else if (change.heightChanged > 0) { // view down
868+ if (oldCleanTop >= 0 && newCleanTop < d.height) {
869+ if (!AWTResources.HAS_COPY_AREA_BUG &&
870+ paintEnd.textIndex < getRichText().length())
871+ {
872+ // copyArea() may be fail.
873+ scrolledDown = true;
874+ g.copyArea(0, oldCleanTop, d.width, d.height - newCleanTop,
875+ 0, change.heightChanged);
876+ }
877+ else {
878+ vBegin = layout.getLineBeginPositionOver(paintEnd.y);
879+ vEnd = layout.getLineBeginPositionUnder(
880+ vBegin,
881+ -offset.y + d.height - 1);
882+ layout.draw(g, offset,
883+ (vBegin.textIndex > paintEnd.textIndex ?
884+ vBegin : paintEnd),
885+ vEnd,
886+ getBackground(),
887+ true,
888+ (vEnd.textIndex >= getRichText().length()),
889+ true,
890+ drawWidth);
891+ vBegin = vEnd = null;
892+ }
893+ }
894+ else if (newCleanTop < d.height) {
895+ vBegin = layout.getLineBeginPositionOver(-offset.y);
896+ vEnd = layout.getLineBeginPositionUnder(
897+ vBegin,
898+ -offset.y + d.height - 1);
899+ layout.draw(g, offset,
900+ (vBegin.textIndex > paintEnd.textIndex ?
901+ vBegin : paintEnd),
902+ vEnd,
903+ getBackground(),
904+ true,
905+ (vEnd.textIndex >= getRichText().length()),
906+ true,
907+ drawWidth);
908+ int endY = offset.y + vEnd.y + vEnd.lineSkip;
909+ if (endY < d.height) {
910+ g.setColor(getBackground());
911+ g.fillRect(0, endY, d.width, d.height - endY);
912+ g.setColor(getForeground());
913+ }
914+ }
915+ }
916+ else { // change.heightChanged == 0
917+ // do nothing
918+ }
919+
920+ _visibleBegin = vBegin;
921+ _visibleEnd = vEnd;
922+ vBegin = getVisibleBegin();
923+ vEnd = getVisibleEnd();
924+
925+ if (paintEnd.textIndex < vBegin.textIndex ||
926+ vEnd.textIndex < paintBegin.textIndex)
927+ {
928+ g.dispose();
929+ if (change.heightChanged != 0) {
930+ syncGraphics();
931+ }
932+ return;
933+ }
934+
935+ TextPositionInfo drawBegin =
936+ (vBegin.textIndex > paintBegin.textIndex ? vBegin : paintBegin);
937+ TextPositionInfo drawEnd =
938+ (vEnd.textIndex < paintEnd.textIndex ? vEnd : paintEnd);
939+
940+ layout.draw(g, offset, drawBegin, drawEnd,
941+ getBackground(),
942+ (vBegin.textIndex > paintBegin.textIndex ?
943+ true : change.paintFromLineBegin),
944+ (vEnd.textIndex < paintEnd.textIndex ?
945+ true : change.paintToLineEnd),
946+ true,
947+ drawWidth);
948+
949+ g.dispose();
950+ if (change.heightChanged == 0) {
951+ syncGraphics(0,
952+ drawBegin.y + offset.y,
953+ d.width,
954+ drawEnd.y + drawEnd.lineSkip - drawBegin.y);
955+ }
956+ else {
957+ syncGraphics();
958+ }
959+ }
960+
961+ /**
962+ * Tests if the selection is caret, i.e., null selection.
963+ */
964+ public boolean selectionIsCaret() {
965+ return (selectionBegin != null && selectionEnd != null &&
966+ selectionBegin.textIndex == selectionEnd.textIndex);
967+ }
968+
969+ /**
970+ * Tests if the selection is needed to be redrawn.
971+ */
972+ protected boolean needsToRedrawSelection() {
973+ //return selectionVisible && selectionIsCaret();
974+ return selectionIsCaret();
975+ }
976+
977+ protected void performClickableTextAction(ClickableTextAction action) {
978+ if (!action.hasActionListener())
979+ return;
980+
981+ if (isDirectNotification()) {
982+ action.performClickableAction();
983+ }
984+ else {
985+ enableEvents(0); // mark newEventsOnly
986+ ClickableTextActionEvent ce =
987+ new ClickableTextActionEvent(this, action);
988+ jp.kyasu.awt.EventPoster.postEvent(ce);
989+ }
990+ }
991+
992+ protected void processEvent(AWTEvent e) {
993+ if (e instanceof ClickableTextActionEvent) {
994+ ClickableTextActionEvent ce = (ClickableTextActionEvent)e;
995+ ClickableTextAction action = ce.getClickableTextAction();
996+ action.performClickableAction();
997+ }
998+ super.processEvent(e);
999+ }
1000+
1001+
1002+ /**
1003+ * Called by the garbage collector on an object when garbage collection
1004+ * determines that there are no more references to the object.
1005+ * @exception java.lang.Throwable if an error was occurred.
1006+ */
1007+ protected void finalize() throws Throwable {
1008+ if (textCaret != null) {
1009+ textCaret.stop();
1010+ }
1011+ }
1012+
1013+ private void writeObject(java.io.ObjectOutputStream s)
1014+ throws java.io.IOException
1015+ {
1016+ s.defaultWriteObject();
1017+
1018+ if (selectionBegin == null) {
1019+ s.writeInt(-1);
1020+ }
1021+ else {
1022+ s.writeInt(selectionBegin.textIndex);
1023+ }
1024+ if (selectionEnd == null) {
1025+ s.writeInt(-1);
1026+ }
1027+ else {
1028+ s.writeInt(selectionEnd.textIndex);
1029+ }
1030+
1031+ if (textPositionListeners != null) {
1032+ for (Enumeration e = textPositionListeners.elements();
1033+ e.hasMoreElements();
1034+ )
1035+ {
1036+ TextPositionListener l = (TextPositionListener)e.nextElement();
1037+ if (l instanceof java.io.Serializable) {
1038+ s.writeObject(l);
1039+ }
1040+ }
1041+ }
1042+ s.writeObject(null);
1043+ }
1044+
1045+ private void readObject(java.io.ObjectInputStream s)
1046+ throws java.io.IOException, ClassNotFoundException
1047+ {
1048+ s.defaultReadObject();
1049+
1050+ int begin = s.readInt();
1051+ if (begin < 0) {
1052+ selectionBegin = null;
1053+ }
1054+ else {
1055+ selectionBegin = getTextPositionAt(begin);
1056+ }
1057+ int end = s.readInt();
1058+ if (end < 0) {
1059+ selectionEnd = null;
1060+ }
1061+ else {
1062+ selectionEnd = getTextPositionAt(end);
1063+ }
1064+ stopTextCaret();
1065+
1066+ Object listenerOrNull;
1067+ while ((listenerOrNull = s.readObject()) != null) {
1068+ addTextPositionListener((TextPositionListener)listenerOrNull);
1069+ }
1070+ }
1071+
1072+
1073+ /*if[JDK1.2]*/
1074+ protected InputMethodRequests inputMethodRequestsHandler;
1075+
1076+ //
1077+ // Overrides this method to become an active input method client.
1078+ //
1079+ public InputMethodRequests getInputMethodRequests() {
1080+ if (inputMethodRequestsHandler == null) {
1081+ inputMethodRequestsHandler =
1082+ (InputMethodRequests)new InputMethodRequestsHandler();
1083+ }
1084+
1085+ return inputMethodRequestsHandler;
1086+ }
1087+
1088+ //
1089+ // An implementation of the InputMethodRequests interface.
1090+ //
1091+ class InputMethodRequestsHandler implements InputMethodRequests {
1092+ public AttributedCharacterIterator cancelLatestCommittedText(
1093+ Attribute[] attributes) {
1094+ return new AttributedString("").getIterator();
1095+ }
1096+
1097+ public AttributedCharacterIterator getCommittedText(int beginIndex,
1098+ int endIndex, Attribute[] attributes) {
1099+ return new AttributedString("").getIterator();
1100+ }
1101+
1102+ public int getCommittedTextLength() {
1103+ return 0;
1104+ }
1105+
1106+ public int getInsertPositionOffset() {
1107+ return 0;
1108+ }
1109+
1110+ public TextHitInfo getLocationOffset(int x, int y) {
1111+ return TextHitInfo.leading(0);
1112+ }
1113+
1114+ public Rectangle getTextLocation(TextHitInfo hitInfo) {
1115+ Rectangle r;
1116+
1117+ TextPositionInfo pos = getSelectionBegin();
1118+ if (pos != null) {
1119+ r = new Rectangle(pos.x + offset.x, pos.y + offset.y,
1120+ 1, pos.lineHeight);
1121+ }
1122+ else {
1123+ r = new Rectangle();
1124+ }
1125+ Point p = getLocationOnScreen();
1126+ r.translate(p.x, p.y);
1127+
1128+ return r;
1129+ }
1130+
1131+ public AttributedCharacterIterator getSelectedText(
1132+ Attribute[] attributes) {
1133+ return new AttributedString("").getIterator();
1134+ }
1135+ }
1136+
1137+ /*end[JDK1.2]*/
1138+
1139+}
1140+
1141+
1142+/**
1143+ * The ClickableTextAction event that is originated from a TextEditView.
1144+ */
1145+class ClickableTextActionEvent extends AWTEvent {
1146+ ClickableTextAction action;
1147+
1148+ ClickableTextActionEvent(Object source, ClickableTextAction action) {
1149+ super(source, AWTEvent.RESERVED_ID_MAX + 1);
1150+ this.action = action;
1151+ }
1152+
1153+ ClickableTextAction getClickableTextAction() {
1154+ return action;
1155+ }
1156+}
Show on old repository browser