001: /*
002: * Copyright 1995-2003 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.awt.motif;
027:
028: import java.awt.*;
029: import java.awt.peer.*;
030: import java.awt.datatransfer.*;
031: import java.awt.event.ActionEvent;
032: import java.awt.event.TextEvent;
033: import java.awt.im.InputMethodRequests;
034:
035: public class MTextFieldPeer extends MComponentPeer implements
036: TextFieldPeer {
037: native void pCreate(MComponentPeer parent);
038:
039: private boolean firstChangeSkipped;
040:
041: /**
042: * Initialize JNI field and method IDs
043: */
044: private static native void initIDs();
045:
046: static {
047: initIDs();
048: }
049:
050: void create(MComponentPeer parent) {
051: firstChangeSkipped = false;
052: pCreate(parent);
053: }
054:
055: void initialize() {
056: int start, end;
057:
058: TextField txt = (TextField) target;
059:
060: setText(txt.getText());
061: if (txt.echoCharIsSet()) {
062: setEchoChar(txt.getEchoChar());
063: }
064:
065: start = txt.getSelectionStart();
066: end = txt.getSelectionEnd();
067:
068: if (end > start) {
069: select(start, end);
070: } else {
071: setCaretPosition(start);
072: }
073:
074: if (!target.isBackgroundSet()) {
075: // This is a way to set the background color of the TextArea
076: // without calling setBackground - go through native C code
077: setTargetBackground(SystemColor.text);
078: }
079: if (!target.isForegroundSet()) {
080: target.setForeground(SystemColor.textText);
081: }
082:
083: setEditable(txt.isEditable());
084:
085: // oldSelectionStart = -1; // accessibility support
086: // oldSelectionEnd = -1; // accessibility support
087:
088: super .initialize();
089: }
090:
091: public MTextFieldPeer(TextField target) {
092: super (target);
093: }
094:
095: public void setEditable(boolean editable) {
096: pSetEditable(editable);
097:
098: /* 4136955 - Calling setBackground() here works around an Xt
099: * bug by forcing Xt to flush an internal widget cache
100: */
101: setBackground(target.getBackground());
102: }
103:
104: public native void pSetEditable(boolean editable);
105:
106: public native void select(int selStart, int selEnd);
107:
108: public native int getSelectionStart();
109:
110: public native int getSelectionEnd();
111:
112: public native void setText(String l);
113:
114: public native void insertReplaceText(String l);
115:
116: public native void preDispose();
117:
118: public native String getText();
119:
120: public native void setEchoChar(char c);
121:
122: public native void setFont(Font f);
123:
124: public native void setCaretPosition(int pos);
125:
126: public native int getCaretPosition();
127:
128: // CDE/Motif defaults: margin=5, shadow=2, highlight=1 -- times 2.
129: // Should have asked the widgets for correct values (see MTextAreaPeer).
130: private static final int padding = 16;
131:
132: public Dimension getMinimumSize() {
133: FontMetrics fm = getFontMetrics(target.getFont());
134: return new Dimension(fm.stringWidth(((TextField) target)
135: .getText()) + 20, fm.getMaxDescent()
136: + fm.getMaxAscent() + padding);
137: }
138:
139: public Dimension getPreferredSize(int cols) {
140: return getMinimumSize(cols);
141: }
142:
143: public Dimension getMinimumSize(int cols) {
144: FontMetrics fm = getFontMetrics(target.getFont());
145: return new Dimension(fm.charWidth('0') * cols + 20, fm
146: .getMaxDescent()
147: + fm.getMaxAscent() + padding);
148: }
149:
150: public boolean isFocusable() {
151: return true;
152: }
153:
154: // NOTE: This method is called by privileged threads.
155: // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
156: public void action(final long when, final int modifiers) {
157: MToolkit.executeOnEventHandlerThread(target, new Runnable() {
158: public void run() {
159: postEvent(new ActionEvent(target,
160: ActionEvent.ACTION_PERFORMED,
161: ((TextField) target).getText(), when, modifiers));
162: }
163: });
164: }
165:
166: protected void disposeImpl() {
167: preDispose();
168: super .disposeImpl();
169: }
170:
171: /*
172: * Post a new TextEvent when the value of a text component changes.
173: */
174: public void valueChanged() {
175: postEvent(new TextEvent(target, TextEvent.TEXT_VALUE_CHANGED));
176: }
177:
178: // Called from native widget when paste key is pressed and we
179: // already own the selection (prevents Motif from hanging while
180: // waiting for the selection)
181: //
182: // NOTE: This method is called by privileged threads.
183: // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
184: public void pasteFromClipboard() {
185: Clipboard clipboard = target.getToolkit().getSystemClipboard();
186:
187: Transferable content = clipboard.getContents(this );
188: if (content != null) {
189: try {
190: String data = (String) (content
191: .getTransferData(DataFlavor.stringFlavor));
192: insertReplaceText(data);
193:
194: } catch (Exception e) {
195: }
196: }
197: }
198:
199: /*
200: * Print the native component by rendering the Motif look ourselves.
201: * ToDo(aim): needs to query native motif for more accurate size and
202: * color information, left text offset, and selected text.
203: */
204: public final static int BORDER = 2;
205: public final static int MARGIN = 4;
206:
207: public void print(Graphics g) {
208: TextField txt = (TextField) target;
209: Dimension d = txt.size();
210: int w = d.width - (2 * BORDER);
211: int h = d.height - (2 * BORDER);
212: Color bg = txt.getBackground();
213: Color fg = txt.getForeground();
214: Color highlight = bg.brighter();
215: String text = txt.getText();
216: int moved = 0;
217: int selStart = 0;
218: int selEnd = 0;
219:
220: g.setFont(txt.getFont());
221: g.setColor(txt.isEditable() ? highlight : bg);
222: g.fillRect(BORDER, BORDER, w, h);
223:
224: g.setColor(bg);
225: //g.drawRect(0, 0, d.width-1, d.height-1);
226: draw3DRect(g, bg, 1, 1, d.width - 3, d.height - 3, false);
227:
228: if (text != null) {
229: g.clipRect(BORDER, MARGIN, w, d.height - (2 * MARGIN));
230: FontMetrics fm = g.getFontMetrics();
231:
232: w = d.width - BORDER;
233: h = d.height - (2 * MARGIN);
234: int xs = pos2x(selStart) - moved;
235: int xe = pos2x(selEnd) - moved;
236:
237: if ((xs < MARGIN) && (xe > w)) {
238: g.setColor(highlight);
239: g.fillRect(BORDER, MARGIN, w - BORDER, h);
240: } else {
241: g.setColor(bg);
242: //g.fillRect(BORDER, MARGIN, w - BORDER, h);
243:
244: if ((xs >= MARGIN) && (xs <= w)) {
245: g.setColor(highlight); // selected text
246:
247: if (xe > w) {
248: g.fillRect(xs, MARGIN, w - xs, h);
249: } else if (xs == xe) {
250: //g.fillRect(xs, MARGIN, 1, h);
251: } else {
252: g.fillRect(xs, MARGIN, xe - xs, h);
253: }
254: } else if ((xe >= MARGIN) && (xe <= w)) {
255: g.setColor(highlight);
256: g.fillRect(BORDER, MARGIN, xe - BORDER, h);
257: }
258: }
259: g.setColor(fg);
260: int x = MARGIN - moved;
261: char echoChar = txt.getEchoChar();
262: if (echoChar == 0) {
263: g.drawString(text, x, BORDER + MARGIN
264: + fm.getMaxAscent());
265: } else {
266: char data[] = new char[text.length()];
267: for (int i = 0; i < data.length; i++) {
268: data[i] = echoChar;
269: }
270: g.drawChars(data, 0, data.length, x, BORDER + MARGIN
271: + fm.getMaxAscent());
272:
273: }
274: }
275:
276: target.print(g);
277: }
278:
279: int pos2x(int pos) {
280: TextField txt = (TextField) target;
281: FontMetrics fm = getFontMetrics(txt.getFont());
282: int x = MARGIN, widths[] = fm.getWidths();
283: String text = txt.getText();
284: char echoChar = txt.getEchoChar();
285: if (echoChar == 0) {
286: for (int i = 0; i < pos; i++) {
287: x += widths[text.charAt(i)];
288: }
289: } else {
290: x += widths[echoChar] * pos;
291: }
292: return x;
293: }
294:
295: /**
296: * DEPRECATED
297: */
298: public void setEchoCharacter(char c) {
299: setEchoChar(c);
300: }
301:
302: /**
303: * DEPRECATED
304: */
305: public Dimension minimumSize() {
306: return getMinimumSize();
307: }
308:
309: /**
310: * DEPRECATED
311: */
312: public Dimension minimumSize(int cols) {
313: return getMinimumSize(cols);
314: }
315:
316: /**
317: * DEPRECATED
318: */
319: public Dimension preferredSize(int cols) {
320: return getPreferredSize(cols);
321: }
322:
323: void pShow() {
324: super .pShow();
325: notifyTextComponentChange(true);
326: }
327:
328: void pHide() {
329: notifyTextComponentChange(false);
330: super .pHide();
331: }
332:
333: void pDispose() {
334: notifyTextComponentChange(false);
335: super .pDispose();
336: }
337:
338: public InputMethodRequests getInputMethodRequests() {
339: return null;
340: }
341:
342: //
343: // Accessibility support
344: //
345:
346: // stub functions: to be fully implemented in a future release
347: public int getIndexAtPoint(int x, int y) {
348: return -1;
349: }
350:
351: public Rectangle getCharacterBounds(int i) {
352: return null;
353: }
354:
355: public long filterEvents(long mask) {
356: return 0;
357: }
358:
359: /* To be fully implemented in a future release
360:
361: int oldSelectionStart;
362: int oldSelectionEnd;
363:
364: public native int getIndexAtPoint(int x, int y);
365: public native Rectangle getCharacterBounds(int i);
366: public native long filterEvents(long mask);
367:
368: /**
369: * Handle a change in the text selection endpoints
370: * (Note: could be simply a change in the caret location)
371: *
372: public void selectionValuesChanged(int start, int end) {
373: return; // Need to write implemetation of this.
374: }
375: */
376:
377: }
|