001: /**
002: * Caption: Zaval Java Resource Editor
003: * $Revision: 0.37 $
004: * $Date: 2002/03/28 9:24:42 $
005: *
006: * @author: Victor Krapivin
007: * @version: 2.0
008: *
009: * Zaval JRC Editor is a visual editor which allows you to manipulate
010: * localization strings for all Java based software with appropriate
011: * support embedded.
012: *
013: * For more info on this product read Zaval Java Resource Editor User's Guide
014: * (It comes within this package).
015: * The latest product version is always available from the product's homepage:
016: * http://www.zaval.org/products/jrc-editor/
017: * and from the SourceForge:
018: * http://sourceforge.net/projects/zaval0002/
019: *
020: * Contacts:
021: * Support : support@zaval.org
022: * Change Requests : change-request@zaval.org
023: * Feedback : feedback@zaval.org
024: * Other : info@zaval.org
025: *
026: * Copyright (C) 2001-2002 Zaval Creative Engineering Group (http://www.zaval.org)
027: *
028: * This program is free software; you can redistribute it and/or
029: * modify it under the terms of the GNU General Public License
030: * (version 2) as published by the Free Software Foundation.
031: *
032: * This program is distributed in the hope that it will be useful,
033: * but WITHOUT ANY WARRANTY; without even the implied warranty of
034: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
035: * GNU General Public License for more details.
036: *
037: * You should have received a copy of the GNU General Public License
038: * along with this program; if not, write to the Free Software
039: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
040: *
041: */package org.zaval.awt;
042:
043: import java.awt.*;
044: import java.awt.event.*;
045: import java.util.*;
046:
047: public class EmulatedTextField extends Canvas implements KeyListener,
048: MouseListener, FocusListener, ActionListener {
049: protected static EmulatedTextField cursorOwner = null;
050:
051: public static final int LEFT = 1;
052: public static final int RIGHT = 2;
053:
054: protected StringBuffer buffer = new StringBuffer("");
055: Insets insets = new Insets(2, 5, 2, 5);
056: Point textLocation = new Point(0, 0);
057: Point cursorLocation = new Point(0, 0);
058: Dimension textSize = new Dimension(0, 0);
059: Dimension cursorSize = new Dimension(0, 0);
060: Point shift = new Point(0, 0);
061: Color cursorColor = Color.black;
062: int cursorPos = 0;
063: int align = LEFT;
064: boolean is3D = true;
065: protected int selPos = 0, selWidth = 0, startSel = 0;
066: private PopupMenu menu;
067: private int minSize = 0;
068:
069: public EmulatedTextField() {
070: this (null);
071: }
072:
073: public EmulatedTextField(int size) {
074: this (null);
075: minSize = size;
076: }
077:
078: public void actionPerformed(ActionEvent e) {
079: if (e.getActionCommand().equals("Cut")) {
080: blCopy();
081: removeBlock();
082: } else if (e.getActionCommand().equals("Copy"))
083: blCopy();
084: else if (e.getActionCommand().equals("Paste"))
085: blPaste();
086: }
087:
088: public EmulatedTextField(String s) {
089: if (s != null)
090: setText(s);
091: enableInputMethods(true);
092: addKeyListener(this );
093: addMouseListener(this );
094: addFocusListener(this );
095:
096: MenuItem mi1;
097: menu = new PopupMenu();
098: add(menu);
099: menu.add(mi1 = new MenuItem("Cut"));
100: mi1.addActionListener(this );
101: mi1.setActionCommand("Cut");
102: menu.add(mi1 = new MenuItem("Copy"));
103: mi1.addActionListener(this );
104: mi1.setActionCommand("Copy");
105: menu.add(mi1 = new MenuItem("Paste"));
106: mi1.addActionListener(this );
107: mi1.setActionCommand("Paste");
108: menu.addActionListener(this );
109: }
110:
111: public void setText(String s) {
112: buffer = new StringBuffer(s);
113: setPos(0);
114: }
115:
116: public String getText() {
117: return buffer.toString();
118: }
119:
120: public void setAlign(int a) {
121: align = a;
122: }
123:
124: public void getAlign(int a) {
125: align = a;
126: repaint();
127: }
128:
129: public void setCursorColor(Color c) {
130: cursorColor = c;
131: if (hasFocus())
132: repaint();
133: }
134:
135: public int getCursorPos() {
136: return cursorPos;
137: }
138:
139: public boolean hasFocus() {
140: return (this == cursorOwner);
141: }
142:
143: public void setInsets(Insets i) {
144: insets.top = i.top;
145: insets.left = i.left;
146: insets.right = i.right;
147: insets.bottom = i.bottom;
148: repaint();
149: }
150:
151: public void set3D(boolean b) {
152: if (b == is3D)
153: return;
154: is3D = b;
155: repaint();
156: }
157:
158: public boolean is3D() {
159: return is3D;
160: }
161:
162: public void keyTyped(KeyEvent ke) {
163: int key = ke.getKeyCode();
164: boolean isCtrl = (ke.getModifiers() & ke.CTRL_MASK) != 0;
165: boolean isShift = (ke.getModifiers() & ke.SHIFT_MASK) != 0;
166: if (controlKey(key, isShift))
167: return;
168:
169: if (ke.isActionKey())
170: return;
171: char c = ke.getKeyChar();
172: if (c == ke.CHAR_UNDEFINED)
173: return;
174:
175: if (c == 0x7F || c == 0x1B)
176: return;
177: if (ke.isControlDown())
178: return;
179: if (c != '\b' && c != '\t') {
180: removeBlock();
181: if (write(c))
182: seek(1, false);
183: }
184: }
185:
186: public void keyPressed(KeyEvent ke) {
187: int key = ke.getKeyCode();
188: boolean isCtrl = (ke.getModifiers() & ke.CTRL_MASK) != 0;
189: boolean isShift = (ke.getModifiers() & ke.SHIFT_MASK) != 0;
190: if (blockKey(key, isCtrl, isShift))
191: return;
192: if (controlKey(key, isShift))
193: return;
194: if (key == ke.VK_F12)
195: menu.show(this , 0, 0);
196: }
197:
198: public void keyReleased(KeyEvent ke) {
199: }
200:
201: protected boolean blockKey(int key, boolean isCtrlDown,
202: boolean isShiftDown) {
203: boolean shift = isShiftDown;
204: if (isCtrlDown
205: && (key == KeyEvent.VK_INSERT || key == KeyEvent.VK_C))
206: blCopy();
207: else if ((isShiftDown && key == KeyEvent.VK_INSERT)
208: || (isCtrlDown && key == KeyEvent.VK_V))
209: blPaste();
210: else if ((isShiftDown && key == KeyEvent.VK_DELETE)
211: || (isCtrlDown && key == KeyEvent.VK_X))
212: blDelete();
213: else if (isCtrlDown && key == KeyEvent.VK_RIGHT)
214: seek(nextSpace() - cursorPos, shift);
215: else if (isCtrlDown && key == KeyEvent.VK_LEFT)
216: seek(prevSpace() - cursorPos, shift);
217: else if (!isCtrlDown)
218: return false;
219: return true;
220: }
221:
222: protected int prevSpace() {
223: int j = cursorPos;
224: if (j >= buffer.length())
225: j = buffer.length() - 1;
226: for (; j > 0 && Character.isSpaceChar(buffer.charAt(j)); --j)
227: ;
228: for (; j > 0 && !Character.isSpaceChar(buffer.charAt(j)); --j)
229: ;
230: return j;
231: }
232:
233: protected int nextSpace() {
234: int j = cursorPos;
235: int k = buffer.length();
236: if (j >= k)
237: return cursorPos;
238: for (; j < k && Character.isSpaceChar(buffer.charAt(j)); ++j)
239: ;
240: for (; j < k && !Character.isSpaceChar(buffer.charAt(j)); ++j)
241: ;
242: return j;
243: }
244:
245: protected boolean controlKey(int key, boolean shift) {
246: boolean b = true;
247: switch (key) {
248: case KeyEvent.VK_DOWN:
249: case KeyEvent.VK_RIGHT:
250: seek(1, shift);
251: break;
252: case KeyEvent.VK_UP:
253: case KeyEvent.VK_LEFT:
254: seek(-1, shift);
255: break;
256: case KeyEvent.VK_END:
257: seek2end(shift);
258: break;
259: case KeyEvent.VK_HOME:
260: seek2beg(shift);
261: break;
262: case KeyEvent.VK_DELETE:
263: if (!isSelected())
264: remove(cursorPos, 1);
265: else
266: removeBlock();
267: break;
268: case KeyEvent.VK_BACK_SPACE:
269: if (!isSelected()) {
270: if (cursorPos > 0) {
271: seek(-1, shift);
272: remove(cursorPos, 1);
273: }
274: } else
275: removeBlock();
276: break;
277: case KeyEvent.VK_ENTER:
278: case KeyEvent.VK_PAGE_UP:
279: case KeyEvent.VK_PAGE_DOWN:
280: break;
281: case KeyEvent.VK_INSERT:
282: return false;
283: case KeyEvent.VK_TAB:
284: return true;
285: default:
286: return false;
287: }
288: if (!shift)
289: clear();
290: return b;
291: }
292:
293: public void blPaste() {
294: String s = readFromClipboard();
295: if (s != null) {
296: s = filterSymbols(s);
297: removeBlock();
298: insert(cursorPos, s);
299: setPos(cursorPos + s.length());
300: }
301: }
302:
303: protected String filterSymbols(String s) {
304: return s;
305: }
306:
307: public String getSelectedText() {
308: return buffer.toString().substring(selPos, selPos + selWidth);
309: }
310:
311: public void blCopy() {
312: if (!isSelected())
313: return;
314: writeToClipboard(buffer.toString().substring(selPos,
315: selPos + selWidth));
316: }
317:
318: public void blDelete() {
319: if (!isSelected())
320: return;
321: writeToClipboard(buffer.toString().substring(selPos,
322: selPos + selWidth));
323: removeBlock();
324: }
325:
326: protected boolean inputKey(int key) {
327: removeBlock();
328: char ch = (char) key;
329: if (write(key))
330: seek(1, false);
331: return true;
332: }
333:
334: protected void removeBlock() {
335: if (isSelected()) {
336: remove(selPos, selWidth);
337: setPos(selPos);
338: clear();
339: }
340: }
341:
342: public void paint(Graphics g) {
343: recalc();
344: drawBorder(g);
345: drawCursor(g);
346: drawText(g);
347: drawBlock(g);
348: }
349:
350: public Insets insets() {
351: return insets;
352: }
353:
354: protected void drawBlock(Graphics g) {
355: int len = buffer.length();
356: if (!isSelected())
357: return;
358: String s = buffer.toString();
359: FontMetrics fm = getFontMetrics(getFont());
360: int beg = fm.stringWidth(s.substring(0, selPos));
361: int end = fm.stringWidth(s.substring(0, selPos + selWidth));
362: g.setColor(Color.blue);
363: g.fillRect(textLocation.x + shift.x + beg, cursorLocation.y
364: + shift.y, end - beg, textSize.height);
365: g.setColor(Color.white);
366: g.drawString(s.substring(selPos, selPos + selWidth),
367: textLocation.x + shift.x + beg, textLocation.y
368: + shift.y);
369: }
370:
371: protected void drawText(Graphics g) {
372: Dimension d = size();
373: g.clipRect(insets.left, insets.top, d.width - insets.left
374: - insets.right, d.height - insets.top - insets.bottom);
375: g.setColor(getForeground());
376: g.drawString(buffer.toString(), textLocation.x + shift.x,
377: textLocation.y + shift.y);
378: }
379:
380: protected void drawCursor(Graphics g) {
381: if (cursorOwner != this )
382: return;
383: g.setColor(cursorColor);
384: g.fillRect(cursorLocation.x + shift.x, cursorLocation.y
385: + shift.y, cursorSize.width, cursorSize.height);
386: }
387:
388: public Rectangle getCursorShape() {
389: return new Rectangle(cursorLocation.x + shift.x,
390: cursorLocation.y + shift.y, cursorSize.width,
391: cursorSize.height);
392: }
393:
394: protected void drawBorder(Graphics g) {
395: Dimension d = size();
396: if (is3D) {
397: g.setColor(Color.gray);
398: g.drawLine(0, 0, d.width - 1, 0);
399: g.drawLine(0, 0, 0, d.height - 1);
400: g.setColor(Color.black);
401: g.drawLine(1, 1, d.width - 3, 1);
402: g.drawLine(1, 1, 1, d.height - 3);
403: g.setColor(Color.white);
404: g.drawLine(0, d.height - 1, d.width - 1, d.height - 1);
405: g.drawLine(d.width - 1, 0, d.width - 1, d.height - 1);
406: } else {
407: g.setColor(Color.black);
408: g.drawRect(0, 0, d.width - 1, d.height - 1);
409: }
410: }
411:
412: protected boolean seek(int shift, boolean b) {
413: int len = buffer.length();
414: int npos = getValidPos(shift);
415:
416: if (npos > len || npos < 0)
417: return false;
418:
419: if (!isSelected() && b)
420: startSel = cursorPos;
421:
422: setPos(npos);
423:
424: if (b) {
425: if (cursorPos < startSel)
426: select(cursorPos, startSel - cursorPos);
427: else
428: select(startSel, cursorPos - startSel);
429: }
430:
431: return true;
432: }
433:
434: protected int getValidPos(int shift) {
435: return cursorPos + shift;
436: }
437:
438: protected boolean seek2end(boolean b) {
439: seek(buffer.length() - cursorPos, b);
440: return true;
441: }
442:
443: protected boolean seek2beg(boolean b) {
444: seek(-cursorPos, b);
445: return true;
446: }
447:
448: protected boolean write(int key) {
449: buffer.insert(cursorPos, (char) key);
450: return true;
451: }
452:
453: protected boolean write(char key) {
454: buffer.insert(cursorPos, key);
455: return true;
456: }
457:
458: protected void remove(int pos, int size) {
459: if (pos > buffer.length() || pos < 0)
460: return;
461: if (pos + size > buffer.length())
462: size = buffer.length() - pos;
463: String s = buffer.toString();
464: s = s.substring(0, pos) + s.substring(pos + size);
465: buffer = new StringBuffer(s);
466: repaintPart();
467: }
468:
469: protected int getShift(int x, Dimension d, Insets i) {
470: if (x < i.left)
471: return (i.left - x);
472:
473: int w = d.width - i.right;
474: if (x > w)
475: return (w - x);
476:
477: return 0;
478: }
479:
480: public void insert(int pos, String str) {
481: if (pos > buffer.length() || pos < 0)
482: return;
483: String s = buffer.toString();
484: s = s.substring(0, pos) + str + s.substring(pos);
485: buffer = new StringBuffer(s);
486: repaintPart();
487: }
488:
489: private long clickTime = 0;
490:
491: public void mouseClicked(MouseEvent e) {
492: }
493:
494: public void mousePressed(MouseEvent e) {
495: }
496:
497: public void selectAll() {
498: select(0, buffer.length());
499: }
500:
501: public void mouseReleased(MouseEvent e) {
502: int x = e.getX();
503: int y = e.getY();
504:
505: if (cursorOwner != this )
506: requestFocus();
507: int pos = calcTextPos(x, y);
508: if (pos >= 0 && pos != cursorPos)
509: setPos(pos);
510:
511: if (e.isPopupTrigger() || e.isShiftDown()) {
512: menu.show(this , x, y);
513: return;
514: } else if (isSelected() && !e.isShiftDown())
515: clear();
516:
517: long t = System.currentTimeMillis();
518: if ((t - clickTime) < 300)
519: select(0, buffer.length());
520: clickTime = t;
521: }
522:
523: public void mouseEntered(MouseEvent e) {
524: }
525:
526: public void mouseExited(MouseEvent e) {
527: }
528:
529: protected int calcTextPos(int x, int y) {
530: if (buffer.length() == 0)
531: return 0;
532:
533: if (x > (shift.x + textSize.width + textLocation.x))
534: return buffer.length();
535:
536: if ((shift.x + textLocation.x) > x)
537: return 0;
538:
539: int w = x - shift.x;
540: int p = (w * 100) / textSize.width;
541: int l = buffer.length();
542: int s = (l * p) / 100;
543:
544: FontMetrics fm = getFontMetrics(getFont());
545: String ss = buffer.toString();
546: for (int i = s, j = s + 1, k = i; i >= 0 || j < l;) {
547: if (k >= 0 && k < l) {
548: char ch = buffer.charAt(k);
549: String sx = ss.substring(0, k);
550: int sl = fm.stringWidth(sx) + shift.x + textLocation.x;
551: int cl = fm.charWidth(ch);
552: if (x >= sl && x < sl + cl) {
553: if (x > (sl + cl / 2))
554: return k + 1;
555: else
556: return k;
557: //return 1;
558: }
559: }
560:
561: if (k == j) {
562: i--;
563: j++;
564: k = i;
565: } else
566: k = j;
567: }
568:
569: return -1;
570: }
571:
572: protected void setPos(int p) {
573: cursorPos = p;
574: repaintPart();
575: }
576:
577: protected Dimension calcSize() {
578: Font f = getFont();
579: if (f == null)
580: return new Dimension(0, 25);
581: FontMetrics m = getFontMetrics(f);
582: if (m == null) {
583: Toolkit k = Toolkit.getDefaultToolkit();
584: m = k.getFontMetrics(f);
585: if (m == null)
586: return new Dimension(0, 25);
587: }
588: Insets i = insets();
589: String t = buffer.toString();
590: return new Dimension(i.left
591: + i.right
592: + Math.max(minSize * m.stringWidth("W"), m
593: .stringWidth(t)), i.top + i.bottom
594: + Math.max(m.getHeight(), 17));
595: }
596:
597: protected boolean recalc() {
598: Dimension d = size();
599: if (d.width == 0 || d.height == 0)
600: return false;
601:
602: Insets i = insets();
603: FontMetrics m = getFontMetrics(getFont());
604: if (m == null)
605: return false;
606:
607: String s = buffer.toString();
608: String sub = s.substring(0, cursorPos);
609: int sl = m.stringWidth(sub);
610: int rh = d.height - i.top - i.bottom;
611:
612: textSize.height = m.getHeight();
613: textSize.width = m.stringWidth(s);
614: textLocation.y = i.top + (rh + textSize.height) / 2
615: - m.getDescent();
616:
617: cursorLocation.x = sl + i.left;
618: cursorLocation.y = textLocation.y - textSize.height
619: + m.getDescent();
620: if (cursorLocation.y < i.top)
621: cursorLocation.y = i.top;
622:
623: cursorSize.width = 1;
624: cursorSize.height = textSize.height;
625:
626: if ((cursorLocation.y + cursorSize.height) >= d.height
627: - i.bottom)
628: cursorSize.height = d.height - cursorLocation.y - i.bottom;
629:
630: switch (align) {
631: case LEFT: {
632: textLocation.x = i.left;
633: cursorLocation.x = sl + i.left;
634: }
635: break;
636: case RIGHT: {
637: textLocation.x = d.width - i.right - textSize.width;
638: cursorLocation.x = sl + textLocation.x;
639: }
640: break;
641: }
642:
643: if ((cursorLocation.x + shift.x) < i.left)
644: shift.x = i.left - cursorLocation.x;
645: else {
646: int w = d.width - i.right;
647: if ((cursorLocation.x + shift.x) > w)
648: shift.x = w - cursorLocation.x;
649: }
650:
651: return true;
652: }
653:
654: public void resize(int w, int h) {
655: shift.x = 0;
656: super .resize(w, h);
657: }
658:
659: protected void otdaiFocusTvojuMat() {
660: cursorOwner = null;
661: repaint();
662: }
663:
664: public void focusGained(FocusEvent e) {
665: if (cursorOwner != null)
666: cursorOwner.otdaiFocusTvojuMat();
667: cursorOwner = this ;
668: if (buffer != null) {
669: setPos(buffer.length());
670: select(0, buffer.length());
671: }
672: repaint();
673: }
674:
675: public void focusLost(FocusEvent e) {
676: if (cursorOwner == this ) {
677: cursorOwner = null;
678: clear();
679: repaint();
680: }
681: }
682:
683: protected void repaintPart() {
684: Insets i = insets();
685: Dimension d = size();
686: repaint(i.left, i.top, d.width - i.right - i.left + 1, d.height
687: - i.bottom - i.top + 1);
688: }
689:
690: public Dimension preferredSize() {
691: return calcSize();
692: }
693:
694: public void select(int pos, int w) {
695: if (selPos == pos && w == selWidth)
696: return;
697: selPos = pos;
698: selWidth = w;
699: repaintPart();
700: }
701:
702: public boolean isSelected() {
703: int len = buffer.length();
704: if (selPos < 0 || selPos >= len || (selPos + selWidth) > len
705: || selWidth == 0)
706: return false;
707: return true;
708: }
709:
710: protected void clear() {
711: selWidth = 0;
712: repaintPart();
713: }
714:
715: public boolean mouseDrag(Event e, int x, int y) {
716: int pos = calcTextPos(x, y);
717: if (pos >= 0) {
718: if (pos < cursorPos)
719: select(pos, cursorPos - pos);
720: else
721: select(cursorPos, pos - cursorPos);
722: }
723: return super .mouseDrag(e, x, y);
724: }
725:
726: private static String clipboard;
727:
728: /**
729: *
730: * Contributed by <a href="mailto:morten@bilpriser.dk">Morten Raahede Knudsen</a>.
731: */
732:
733: protected static synchronized void writeToClipboard(String s) {
734: java.awt.datatransfer.Clipboard c = java.awt.Toolkit
735: .getDefaultToolkit().getSystemClipboard();
736: java.awt.datatransfer.StringSelection s2 = new java.awt.datatransfer.StringSelection(
737: s);
738: c.setContents(s2, s2);
739: }
740:
741: protected static synchronized String readFromClipboard() {
742: java.awt.datatransfer.Clipboard c = java.awt.Toolkit
743: .getDefaultToolkit().getSystemClipboard();
744: java.awt.datatransfer.Transferable t = c.getContents("e");
745:
746: if (t
747: .isDataFlavorSupported(java.awt.datatransfer.DataFlavor.stringFlavor))
748: try {
749: return (String) t
750: .getTransferData(java.awt.datatransfer.DataFlavor.stringFlavor);
751: } catch (Exception ex) {
752: }
753: return "";
754: }
755: }
|