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: 1.3
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.util.*;
045:
046: public class Notebook extends Panel implements LayoutManager {
047: public static final int TOP = 0;
048: public static final int BOTTOM = 1;
049: public static final int ROUNDED = 0;
050: public static final int SQUARE = 1;
051:
052: private final int IMAGE_SIZE = 16;
053:
054: private int TF_LEFT = 0; // old 9
055: private int TF_RIGHT = 0; // old -9
056: private int TF_TOP = 23; // old 30
057: private int TF_BOTTOM = 0; // old -9
058:
059: private int TF_BTN_HEIGHT = 20;
060:
061: protected int curIndex = -1;
062:
063: private Font fReg;
064: private Font fSel;
065: private Color caption = Color.black;
066:
067: private int iTabsPosition = TOP;
068: private int iTabsStyle = SQUARE;//BOTTOM; //TOP; //ROUNDED;
069:
070: private int firstVisibleTab = 0;
071: private Button dbLeft;
072: private Button dbRight;
073:
074: private Polygon nullPoly;
075: private int lastWidth = -1;
076:
077: private Vector pages = null;
078: private Panel oobj = null;
079: private CardLayout card = null;
080: private ImageResolver imgres;
081: private boolean mark = false;
082:
083: public Notebook() {
084: this (TOP, ROUNDED);
085: }
086:
087: public Notebook(boolean bTabsOnTop) {
088: this (bTabsOnTop ? TOP : BOTTOM, bTabsOnTop ? ROUNDED : SQUARE);
089: }
090:
091: public void setImageResolver(ImageResolver r) {
092: imgres = r;
093: }
094:
095: public void setFont(Font norm, Font sel, Color c) {
096: fReg = norm;
097: if (sel == null)
098: sel = new Font(norm.getName(), norm.getStyle() | Font.BOLD,
099: norm.getSize());
100: fSel = sel;
101: caption = c;
102: }
103:
104: public Notebook(int tabsPostion, int tabsStyle) {
105: pages = new Vector();
106: setTabsInfo(tabsPostion, tabsStyle);
107:
108: fReg = new Font("Helvetica", Font.PLAIN, 12);
109: fSel = new Font("Helvetica", Font.BOLD, 12);
110: setLayout(this );
111:
112: dbLeft = new Button("<<");
113: dbRight = new Button(">>");
114: add(dbLeft);
115: add(dbRight);
116: oobj = new Panel();
117: oobj.setLayout(card = new CardLayout());
118: add(oobj);
119:
120: nullPoly = new Polygon();
121: nullPoly.addPoint(0, 0);
122: nullPoly.addPoint(1, 1);
123: nullPoly.addPoint(0, 0);
124:
125: iTabsStyle = TOP;
126: }
127:
128: public void setTabsInfo(int tabsPosition, int tabsStyle) {
129: iTabsPosition = tabsPosition;
130: if (iTabsPosition == TOP)
131: iTabsStyle = ROUNDED;
132: else
133: iTabsStyle = tabsStyle;
134:
135: if (iTabsStyle == ROUNDED)
136: TF_BTN_HEIGHT = 20;
137: else
138: TF_BTN_HEIGHT = 17;
139: }
140:
141: public int getTabIndex() {
142: return curIndex;
143: }
144:
145: public void addPanel(String caption, Component comp) {
146: int pos = pages.size();
147: NotebookPage np = new NotebookPage();
148: np.setImageResolver(imgres);
149:
150: np.comp = comp;
151: np.label = caption;
152: np.hidden = false;
153: np.poly = null;
154: np.color = Color.gray;
155: np.name = Integer.toString(pos);
156:
157: if (curIndex < 0)
158: curIndex = pos;
159: pages.addElement(np);
160:
161: oobj.add(np.name, np.comp);
162: repaint();
163: }
164:
165: public void removePanel(int pos) {
166: NotebookPage np = (NotebookPage) pages.elementAt(pos);
167: pages.removeElementAt(pos);
168: oobj.remove(np.comp);
169: showPanel(curIndex);
170: }
171:
172: public boolean isHidden(int pos) {
173: NotebookPage np = (NotebookPage) pages.elementAt(pos);
174: return np.hidden;
175: }
176:
177: public Component getPanel(int pos) {
178: NotebookPage np = (NotebookPage) pages.elementAt(pos);
179: return np.comp;
180: }
181:
182: public void showPanel(int pos) {
183: NotebookPage np = (NotebookPage) pages.elementAt(pos);
184: card.show(oobj, np.name);
185: curIndex = pos;
186: repaint();
187: }
188:
189: public void setColor(int pos, Color color) {
190: NotebookPage np = (NotebookPage) pages.elementAt(pos);
191: np.color = color;
192: repaint();
193: }
194:
195: public void layoutContainer(Container obj) {
196: Rectangle r = obj.bounds();
197: int width = r.width - TF_LEFT + TF_RIGHT;
198: if (width < 0)
199: return;
200:
201: int height = r.height - TF_TOP + TF_BOTTOM;
202: if (height < 0)
203: return;
204:
205: int col = TF_LEFT;
206: int row = 0;
207:
208: if (iTabsPosition == TOP)
209: row = TF_TOP;
210: else
211: row = TF_TOP - TF_BTN_HEIGHT;
212:
213: oobj.move(col + 1, row + 1);
214:
215: //oobj.move(0,0);
216: oobj.resize(width - 3, height - 3);
217:
218: if (iTabsPosition == TOP) {
219:
220: dbLeft.move(r.width - 33 + TF_RIGHT, TF_TOP - 16);
221: dbRight.move(r.width - 16 + TF_RIGHT, TF_TOP - 16);
222: dbLeft.resize(16, 15);
223: dbRight.resize(16, 15);
224: } else {
225: dbLeft.move(r.width - 33 + TF_RIGHT, r.height + TF_BOTTOM
226: - TF_BTN_HEIGHT);
227: dbRight.move(r.width - 16 + TF_RIGHT, r.height + TF_BOTTOM
228: - TF_BTN_HEIGHT);
229: dbLeft.resize(16, 15);
230: dbRight.resize(16, 15);
231: }
232: repaint();
233: }
234:
235: public Point location(int xx, int yy) {
236: return new Point(0, 0);
237: }
238:
239: public void addLayoutComponent(String name, Component comp) {
240: }
241:
242: public void removeLayoutComponent(Component comp) {
243: }
244:
245: public Dimension preferredLayoutSize(Container parent) {
246: return getSize(parent, true);
247: }
248:
249: public Dimension minimumLayoutSize(Container parent) {
250: return getSize(parent, false);
251: }
252:
253: private Dimension getSize(Container obj, boolean max) {
254: int width = TF_LEFT - TF_RIGHT;
255: int height = TF_TOP - TF_BOTTOM;
256: int col = TF_LEFT;
257: int row = 0;
258:
259: if (iTabsPosition == TOP)
260: row = TF_TOP;
261: else
262: row = TF_TOP - TF_BTN_HEIGHT;
263:
264: Dimension d = max ? oobj.preferredSize() : oobj.minimumSize();
265: return new Dimension(d.width + width, d.height + height);
266: }
267:
268: public void setVisible(int pos, boolean vis) {
269: NotebookPage np = (NotebookPage) pages.elementAt(pos);
270: np.hidden = !vis;
271: layout();
272: repaint();
273: }
274:
275: public void paint(Graphics g) {
276: Rectangle r = bounds();
277:
278: // paint the box
279: int width = r.width - TF_LEFT + TF_RIGHT;
280: if (width < 0)
281: width = 0;
282: int height = r.height - TF_TOP + TF_BOTTOM;
283: if (height < 0)
284: height = 0;
285:
286: if (r.width > lastWidth)
287: firstVisibleTab = 0;
288: lastWidth = r.width;
289:
290: int col = TF_LEFT;
291: int row;
292:
293: Color c = g.getColor();
294: g.setColor(getBackground());
295: g.fillRect(0, 0, r.width, r.height);
296:
297: if (iTabsPosition == TOP)
298: row = TF_TOP;
299: else
300: row = TF_TOP - TF_BTN_HEIGHT;
301:
302: // draw border
303: g.setColor(Color.white);
304: g.drawLine(col, row, (col + width - 1), row);
305: g.drawLine(col, row, col, (row + height - 1));
306:
307: g.setColor(Color.gray);
308: g.drawLine((col + 2), (row + height - 2), (col + width - 2),
309: (row + height - 2));
310: g.drawLine((col + width - 2), (row + 2), (col + width - 2),
311: (row + height - 2));
312:
313: g.setColor(Color.black);
314: g.drawLine((col + 1), (row + height - 1), (col + width - 1),
315: (row + height - 1));
316: g.drawLine((col + width - 1), (row + 1), (col + width - 1),
317: (row + height - 1));
318:
319: // paint the tabs, and record areas
320: int x1;
321: int x2 = TF_LEFT + 8;
322: int y1;
323: int y2;
324: int x3 = 0;
325: int x4 = TF_LEFT;
326:
327: int sze = pages.size();
328: String sLabel;
329:
330: Font f = g.getFont();
331: FontMetrics fm = getFontMetrics(fReg);
332: FontMetrics fms = getFontMetrics(fSel);
333: int labelWidth = 0;
334: Polygon p;
335:
336: int w;
337: NotebookPage[] npages = new NotebookPage[sze];
338: for (w = 0; w < sze; ++w) {
339: npages[w] = (NotebookPage) pages.elementAt(w);
340: npages[w].poly = nullPoly;
341: }
342:
343: // make sure there is a polygon for each tab
344: if (firstVisibleTab > 0)
345: x4 += 2;
346: int xStep = 1;
347:
348: for (w = firstVisibleTab; w < sze; w++) {
349: int fheight = fm.getHeight() - fms.getDescent();
350: if (w == curIndex)
351: fheight = fms.getHeight() - fms.getDescent();
352:
353: p = new Polygon();
354: if (npages[w].hidden) {
355: y1 = TF_TOP - TF_BTN_HEIGHT;
356: y2 = TF_TOP - 1;
357: x1 = x4 - 1;
358: x2 = x1 + 1;
359: x3 = x1;
360: x4 = x2;
361: p.addPoint(x1, y1);
362: p.addPoint(x1, y2);
363: p.addPoint(x2, y2);
364: p.addPoint(x2, y1);
365: npages[w].poly = p;
366: // xStep++;
367: continue;
368: }
369: try {
370: sLabel = npages[w].label;
371: if (w == curIndex)
372: labelWidth = fms.stringWidth(sLabel);
373: else
374: labelWidth = fm.stringWidth(sLabel);
375:
376: if (npages[w].img != null)
377: labelWidth += IMAGE_SIZE;
378:
379: if (iTabsPosition == TOP) {
380: y1 = TF_TOP - TF_BTN_HEIGHT;
381: y2 = TF_TOP - 1;
382: } else {
383: y1 = r.height + TF_BOTTOM + 1;
384: y2 = r.height + TF_BOTTOM - TF_BTN_HEIGHT;
385: }
386:
387: if (iTabsStyle == ROUNDED) {
388: x1 = x4 + 2;
389: x2 = x1 + labelWidth + 13;
390: } else {
391: x1 = x2 - 7;
392: x2 = x1 + labelWidth + 28;
393: }
394:
395: // check to see if this tab would draw too far
396: if ((x2 + 36 - TF_RIGHT) > r.width)
397: break;
398:
399: // draw the outside edge of the tab
400: if (iTabsPosition == TOP) {
401: // if current tab, it extends further
402: if (w == curIndex) {
403: y1 -= 3;
404: x1 -= 2;
405: }
406: g.setColor(Color.white);
407: g.drawLine(x1 + 2, y1, x2, y1);
408:
409: // draw the border between tabs if not covered by the current one
410: g.drawLine(x1, y1 + 2, x1, y2);
411: x3 = x1;
412:
413: g.drawLine(x1 + 1, y1 + 1, x1 + 1, y1 + 1);
414:
415: g.setColor(Color.gray);
416: g.drawLine(x2, y1, x2, y2);
417: g.setColor(Color.black);
418: g.drawLine(x2 + 1, y1 + 2, x2 + 1, y2);
419: x4 = x2;
420: } else {
421: if (iTabsStyle == SQUARE) {
422: g.setColor(Color.gray);
423: g.drawLine(x1 + 9, y1, x2 - 9, y1);
424:
425: g.setColor(Color.black);
426: // left \ slanted line
427: if (w == 0 || w == curIndex) {
428: g.drawLine(x1, y2, x1 + 9, y1);
429: p.addPoint(x1, y2);
430: } else {
431: g.drawLine(x1 + 4, y1 - 9, x1 + 9, y1);
432: p.addPoint(x1 + 9, y2);
433: p.addPoint(x1 + 4, y1 - 9);
434: }
435: p.addPoint(x1 + 9, y1);
436: p.addPoint(x2 - 9, y1);
437:
438: if ((w + xStep) == curIndex) {
439: g.drawLine(x2 - 5, y1 - 9, x2 - 9, y1);
440: p.addPoint(x2 - 5, y1);
441: p.addPoint(x2 - 9, y2);
442: } else {
443: g.drawLine(x2, y2, x2 - 9, y1);
444: p.addPoint(x2, y2);
445: }
446:
447: if (w == 1 || w == curIndex)
448: p.addPoint(x1, y2);
449: else
450: p.addPoint(x1 + 9, y2);
451: } else {
452: // if current tab, it extends further
453: if (w == curIndex) {
454: y1 += 3;
455: x1 -= 2;
456: }
457: g.setColor(Color.white);
458: if (curIndex == (w + xStep))
459: g.drawLine(x1 + 2, y1, x2 - 2, y1);
460: else
461: g.drawLine(x1 + 2, y1, x2, y1);
462:
463: // draw the border between tabs if not covered by the current one
464: if (curIndex != (w - xStep)) {
465: g.drawLine(x1, y1 - 2, x1, y2);
466: x3 = x1;
467: } else
468: x3 = x1 + 1;
469:
470: g.drawLine(x1 + 1, y1 - 1, x1 + 1, y1 - 1);
471:
472: if (curIndex != (w + xStep)) {
473: g.setColor(Color.gray);
474: g.drawLine(x2, y1, x2, y2);
475: g.setColor(Color.black);
476: g.drawLine(x2 + 1, y1 - 2, x2 + 1, y2);
477: x4 = x2;
478: } else
479: x4 = x2 - 1;
480: }
481: }
482:
483: // draw the inside edge of the tab
484: if (w == curIndex) {
485: if (iTabsPosition == TOP)
486: ++y2;
487: else
488: --y2;
489: g.setColor(getBackground());
490: g.drawLine(x1 + 1, y2, x2, y2);
491: if (iTabsPosition == BOTTOM)
492: g.drawLine(x1 + 1, y2 - 1, x2, y2 - 1);
493:
494: g.setFont(fSel);
495: } else
496: g.setFont(fReg);
497:
498: // if (iTabsPosition == TOP)
499: if (iTabsStyle == ROUNDED) {
500: p.addPoint(x3 - 1, y2 + 1);
501: p.addPoint(x4 + 1, y2 + 1);
502: p.addPoint(x4 + 1, y1 - 1);
503: p.addPoint(x3 + 2, y1 - 1);
504: p.addPoint(x3 - 1, y1 + 2);
505: p.addPoint(x3 - 1, y2 + 1);
506: }
507: npages[w].poly = p;
508:
509: g.setColor(npages[w].color);
510: Polygon p2 = justPolygon(p, iTabsPosition == TOP);
511: g.fillPolygon(p2);
512:
513: // Boolean bool = (Boolean) vEnabled.elementAt(w);
514: // if (bool.booleanValue())
515: g.setColor(caption);
516: // else
517: // g.setColor(Color.gray);
518:
519: int dx = (npages[w].img == null) ? 0 : IMAGE_SIZE;
520:
521: int xx = x1 + 8 + dx;
522: int yy = y1 + 15;
523:
524: if (iTabsStyle == TOP) {
525: } else if (iTabsStyle == ROUNDED) {
526: yy = y1 - 6;
527: } else {
528: xx = x1 + 14 + dx;
529: yy = y1 - 4;
530: }
531:
532: int imgy = yy - fheight / 2;
533:
534: if (npages[w].img != null) {
535: int imgH = npages[w].img.getHeight(this );
536: int imgW = npages[w].img.getWidth(this );
537: imgy = imgy - imgH / 2 + 1;
538: g.drawImage(npages[w].img, xx - IMAGE_SIZE - 2,
539: imgy, imgW, imgH, this );
540: }
541:
542: g.drawString(sLabel, xx, yy);
543: } catch (ArrayIndexOutOfBoundsException e) {
544: }
545: xStep = 1;
546: }
547:
548: // do I need to show arrows because there are too many tabs???
549: if ((firstVisibleTab > 0) || (w < sze)) {
550: dbLeft.show();
551: dbRight.show();
552: if (firstVisibleTab > 0)
553: dbLeft.enable();
554: else
555: dbLeft.disable();
556:
557: if (w < sze)
558: dbRight.enable();
559: else
560: dbRight.disable();
561: } else {
562: dbLeft.hide();
563: dbRight.hide();
564: }
565: g.setFont(f);
566: g.setColor(c);
567:
568: if (mark && curIndex >= 0)
569: drawMark(g, npages[curIndex].poly);
570:
571: npages = null;
572: }
573:
574: private void drawMark(Graphics g, Polygon r) {
575: g.setColor(Color.black);
576: Rectangle rr = r.getBoundingBox();
577: rr.x += 3;
578: rr.y += 3;
579: rr.height -= 5;
580: rr.width -= 6;
581:
582: drawRect(g, rr.x, rr.y, rr.width, rr.height);
583: }
584:
585: private Polygon justPolygon(Polygon p, boolean isTop) {
586: Polygon p2 = new Polygon();
587: Rectangle r = p.getBoundingBox();
588: int x, y, i;
589: for (i = 0; i < p.npoints; ++i) {
590: x = p.xpoints[i];
591: if (p.xpoints[i] >= r.x + r.width - 1)
592: x = p.xpoints[i] - 1;
593: if (p.xpoints[i] == r.x)
594: x = p.xpoints[i] + 2;
595:
596: y = p.ypoints[i];
597: if (!isTop && p.ypoints[i] >= r.y + r.height - 1)
598: y = p.ypoints[i] - 1;
599: if (isTop && p.ypoints[i] == r.y)
600: y = p.ypoints[i] + 2;
601: p2.addPoint(x, y);
602: }
603: return p2;
604: }
605:
606: public boolean keyDown(Event e, int key) {
607: switch (key) {
608: case Event.LEFT: {
609: int x = curIndex;
610: if (x > 0 && mark)
611: x--;
612: else
613: return false;
614: for (; x >= 0; x--)
615: try {
616: NotebookPage np = (NotebookPage) pages.elementAt(x);
617: if (isHidden(x))
618: continue;
619: sendActionEvent(x, 0);
620: requestFocus();
621: break;
622: } catch (ArrayIndexOutOfBoundsException ex) {
623: }
624: }
625: break;
626: case Event.RIGHT: {
627: int size = pages.size(), x = curIndex;
628: if (x < (size - 1) && mark)
629: x++;
630: else
631: return false;
632: for (; x < size; x++)
633: try {
634: NotebookPage np = (NotebookPage) pages.elementAt(x);
635: if (isHidden(x))
636: continue;
637: sendActionEvent(x, 0);
638: requestFocus();
639: break;
640: } catch (ArrayIndexOutOfBoundsException ex) {
641: }
642: }
643: break;
644: }
645: return super .keyDown(e, key);
646: }
647:
648: boolean isHandle = true;
649:
650: public void setHandleEvent(boolean b) {
651: isHandle = b;
652: }
653:
654: public boolean handleEvent(Event evt) {
655: switch (evt.id) {
656: case Event.MOUSE_MOVE:
657: case Event.MOUSE_DOWN:
658: case Event.MOUSE_ENTER:
659: case Event.MOUSE_EXIT:
660: case Event.MOUSE_DRAG:
661: return true;
662: case Event.MOUSE_UP:
663: if (!isHandle)
664: return true;
665: int sizeR = pages.size();
666: NotebookPage np = null;
667: for (int x = 0; x < sizeR; x++)
668: try {
669: np = (NotebookPage) pages.elementAt(x);
670: if ((np.poly != nullPoly)
671: && np.poly.inside(evt.x, evt.y)) {
672: if (isHidden(x))
673: continue;
674: if (x == curIndex) {
675: requestFocus();
676: return true;
677: }
678: sendActionEvent(x, 1);
679: break;
680: }
681: } catch (ArrayIndexOutOfBoundsException e) {
682: }
683: break;
684:
685: case Event.ACTION_EVENT:
686: if (evt.target == dbLeft) {
687: if (--firstVisibleTab < 0)
688: firstVisibleTab = 0;
689: else
690: repaint();
691: return true;
692: } else if (evt.target == dbRight) {
693: int sze = pages.size();
694: if (++firstVisibleTab == sze)
695: firstVisibleTab--;
696: else
697: repaint();
698: return true;
699: }
700: break;
701: }
702:
703: return super .handleEvent(evt);
704: }
705:
706: public boolean lostFocus(Event e, Object o) {
707: if (!(e.target instanceof Notebook))
708: return super .lostFocus(e, o);
709: mark = false;
710: repaint();
711: return super .lostFocus(e, o);
712: }
713:
714: public void setImage(int pos, String image) {
715: NotebookPage np = (NotebookPage) pages.elementAt(pos);
716: np.setImage(image);
717: repaint();
718: }
719:
720: private void sendActionEvent(int page, int mod) {
721: Event e = new Event(this , System.currentTimeMillis(),
722: Event.ACTION_EVENT, page, 0, 0, mod, Integer
723: .toString(page));
724: mark = false;
725: getParent().postEvent(e);
726: repaint();
727: }
728:
729: public void requestFocus() {
730: super .requestFocus();
731: mark = true;
732: repaint();
733: }
734:
735: public boolean mouseMove(Event e, int x, int y) {
736: return true;
737: }
738:
739: public boolean mouseExit(Event e, int x, int y) {
740: return true;
741: }
742:
743: public boolean mouseEnter(Event e, int x, int y) {
744: return true;
745: }
746:
747: public int countPages() {
748: return pages.size();
749: }
750:
751: public static void drawRect(Graphics gr, int x, int y, int w, int h) {
752: drawVLine(gr, y, y + h, x);
753: drawVLine(gr, y, y + h, x + w);
754: drawHLine(gr, x, x + w, y);
755: drawHLine(gr, x, x + w, y + h);
756: }
757:
758: public static void drawHLine(Graphics gr, int x1, int x2, int y1) {
759: int dx = x2 - x1;
760: int count = dx / 2 + dx % 2;
761: for (int i = 0; i < count; i++) {
762: gr.drawLine(x1, y1, x1, y1);
763: x1 += 2;
764: }
765: gr.drawLine(x2, y1, x2, y1);
766: }
767:
768: public static void drawVLine(Graphics gr, int y1, int y2, int x1) {
769: int dy = y2 - y1;
770: int count = dy / 2 + dy % 2;
771: ;
772: for (int i = 0; i < count; i++) {
773: gr.drawLine(x1, y1, x1, y1);
774: y1 += 2;
775: }
776: gr.drawLine(x1, y2, x1, y2);
777: }
778: }
|