001: package com.xoetrope.swing;
002:
003: import com.xoetrope.event.XClickListener;
004: import com.xoetrope.event.XStateListener;
005: import java.awt.BasicStroke;
006: import java.awt.BorderLayout;
007: import java.awt.Color;
008: import java.awt.Component;
009: import java.awt.Dimension;
010: import java.awt.Graphics;
011: import java.awt.Graphics2D;
012: import java.awt.Insets;
013: import java.awt.Stroke;
014: import java.awt.event.MouseEvent;
015: import java.awt.event.MouseListener;
016: import java.net.URL;
017: import java.util.ArrayList;
018: import java.util.Hashtable;
019: import net.xoetrope.optional.svg.svgsalamander.XSvgPainter;
020: import net.xoetrope.swing.XImage;
021: import net.xoetrope.swing.XLabel;
022: import net.xoetrope.swing.XPanel;
023: import net.xoetrope.xui.XAttributedComponent;
024: import net.xoetrope.xui.XContentHolder;
025: import net.xoetrope.xui.XProject;
026: import net.xoetrope.xui.XProjectManager;
027: import net.xoetrope.xui.helper.XuiUtilities;
028:
029: /**
030: * An extension of the XImage component that adds a caption to the image and
031: * an optional border
032: *
033: * <p> Copyright (c) Xoetrope Ltd., 2001-2006, This software is licensed under
034: * the GNU Public License (GPL), please see license.txt for more details. If
035: * you make commercial use of this software you must purchase a commercial
036: * license from Xoetrope.</p>
037: * <p> $Revision: 1.21 $</p>
038: */
039: public class XCaptionedImage extends XPanel implements
040: XAttributedComponent, XContentHolder, XStateListener,
041: MouseListener {
042: protected XImage image;
043: protected XLabel caption;
044: protected String imgName;
045: protected int padding;
046: protected int minWidth, minHeight, maxWidth, maxHeight, prefWidth,
047: prefHeight;
048: protected int borders;
049: protected boolean shadow, tooltipSet;
050: protected XClickListener clickListener;
051: protected ArrayList listeners;
052:
053: /**
054: * The owner project and the context in which this object operates.
055: */
056: protected XProject currentProject = XProjectManager
057: .getCurrentProject();
058:
059: /**
060: * Creates a new instance of XCaptionedImage
061: */
062: public XCaptionedImage() {
063: BorderLayout bl = new BorderLayout();
064: bl.setHgap(padding);
065: bl.setVgap(padding);
066: setLayout(bl);
067: setBackground(Color.white);
068: image = new XImage();
069: image.setBackground(Color.white);
070: caption = new XLabel();
071: padding = 4;
072: shadow = false;
073: minWidth = 50;
074: minHeight = 50;
075:
076: add(image, BorderLayout.CENTER);
077: add(caption, BorderLayout.SOUTH);
078:
079: clickListener = new XClickListener(this , 0);
080: clickListener.setCancelOnDrag(true);
081: addMouseListener(clickListener);
082: addMouseMotionListener(clickListener);
083: image.addMouseListener(clickListener);
084: image.addMouseMotionListener(clickListener);
085:
086: listeners = new ArrayList();
087: }
088:
089: /**
090: * Setup the container
091: * @param name set the container name
092: * @param preferredWidth the desired width
093: * @param preferredHeight the desired height
094: * @param params a table of extra properties
095: */
096: public void setup(String name, int preferredWidth,
097: int preferredHeight, Hashtable params) {
098: }
099:
100: /**
101: * Get a child component
102: * @param i the index of the child within the container
103: * @return the child component
104: */
105: public Object getChildComponent(int i) {
106: return super .getComponent(i);
107: }
108:
109: /**
110: * Add a child component
111: * @param c the child component
112: * @param constraint the layout constraint
113: */
114: public void add(Object c, Object constraint) {
115: super .add((Component) c, constraint);
116: }
117:
118: /**
119: * Remove a child component
120: * @param c the child component
121: */
122: public void remove(Object c) {
123: super .remove((Component) c);
124: }
125:
126: /**
127: * Repaint the responses
128: */
129: public void paintStates() {
130: repaint();
131: }
132:
133: /**
134: * Find a response
135: * @param x the x coordinate of the mouse click
136: * @param y the y coordinate of the mouse click
137: * @param defResponse the default response
138: * @return true if a response was found
139: */
140: public boolean setState(int x, int y, int defResponse) {
141: return true;
142: }
143:
144: /**
145: * Find the response corresponding to the current point
146: * @param x the x coordinate of the mouse click
147: * @param y the y coordinate of the mouse click
148: * @return the response value if the mouse were click at the specified location,
149: * or -1 if not selection is available
150: */
151: public int findCurrentResponse(int x, int y) {
152: return 1;
153: }
154:
155: /**
156: * Does nothing in this instance
157: */
158: public void updateSelectedState() {
159: }
160:
161: /**
162: * Called by XClickListener to check if a response event should be sent to the
163: * parent form. The control can also use this event to do post click processing
164: * @return true if the parent is to be notified
165: */
166: public boolean respond() {
167: return false;
168: }
169:
170: /**
171: * Get the minimum component size
172: * @return the minimum size
173: */
174: public Dimension getMinimumSize() {
175: Dimension dim = super .getMaximumSize();
176: return new Dimension(Math.max(dim.width, minWidth), Math.max(
177: dim.height, minHeight));
178: }
179:
180: /**
181: * Get the maximum component size
182: * @return the maximum size
183: */
184: public Dimension getMaximumSize() {
185: Dimension dim = super .getMaximumSize();
186: return new Dimension(Math.max(dim.width, maxWidth), Math.max(
187: dim.height, maxHeight));
188: }
189:
190: /**
191: * Get the minimum width of the component
192: * @return the minimum width
193: */
194: public int getMinWidth() {
195: return minWidth;
196: }
197:
198: /**
199: * Get the minimum height of the component
200: * @return the minimum height
201: */
202: public int getMinHeight() {
203: return minHeight;
204: }
205:
206: /**
207: * Set the minimum width of the component
208: * @param value the minimum width
209: */
210: public void setMinWidth(int value) {
211: minWidth = value;
212: }
213:
214: /**
215: * Set the minimum height of the component
216: * @param value the minimum height
217: */
218: public void setMinHeight(int value) {
219: minHeight = value;
220: }
221:
222: /**
223: * Get the preferred component size
224: * @return the preferrd size
225: */
226: public Dimension getPreferredSize() {
227: Dimension dim = super .getPreferredSize();
228: if (minWidth > 0)
229: dim.width = Math.max(dim.width, minWidth);
230: if (minHeight > 0)
231: dim.height = Math.max(dim.height, minHeight);
232:
233: return dim;
234: }
235:
236: /**
237: * Get the opaque property
238: * @return the opaque flag
239: */
240: public boolean getOpaque() {
241: return isOpaque();
242: }
243:
244: /**
245: * Set the component content - the image name
246: * @param the content value
247: */
248: public void setContent(String content) {
249: image.setAttribute("content", content);
250: }
251:
252: /**
253: * Get the insets
254: * @return the insets
255: */
256: public Insets getInsets() {
257: int shadowSize = (shadow ? (image.getShadowSize() / 2) : 0);
258: return new Insets(padding, shadowSize + padding, padding,
259: padding - shadowSize);
260: }
261:
262: /**
263: * Set the enabled state
264: * @boolean state true to enable the component, false to disable the component
265: * in which case the image is partially faded out
266: */
267: public void setEnabled(boolean state) {
268: image.setEnabled(state);
269: caption.setEnabled(state);
270: super .setEnabled(state);
271: }
272:
273: public void paintComponent(Graphics g) {
274: super .paintComponent(g);
275:
276: Graphics2D g2d = (Graphics2D) g;
277: Stroke oldStroke = g2d.getStroke();
278: if (clickListener.getIsSelected()) {
279: BasicStroke stroke = new BasicStroke(2.0F);
280: g2d.setStroke(stroke);
281: g2d.setColor(new Color(255, 0, 0, 128));
282: g2d.drawRoundRect(1, 1, getWidth() - 2, getHeight() - 2,
283: arc, arc);
284: } else if (clickListener.getIsEntered()) {
285: BasicStroke stroke = new BasicStroke(3.0F);
286: g2d.setStroke(stroke);
287: g2d.setColor(new Color(255, 233, 0, 192));
288: g2d.drawRoundRect(1, 1, getWidth() - 2, getHeight() - 2,
289: arc, arc);
290: }
291: g2d.setStroke(oldStroke);
292: }
293:
294: /**
295: * Get the padding
296: * @return the padding
297: */
298: public int getPadding() {
299: return padding;
300: }
301:
302: /**
303: * Set the padding
304: * @param the padding
305: */
306: public void setPadding(int pad) {
307: padding = pad;
308: BorderLayout bl = (BorderLayout) getLayout();
309: bl.setHgap(padding);
310: bl.setVgap(padding);
311: bl.layoutContainer(this );
312: }
313:
314: /**
315: * Get the alignment style constant
316: * @return the alignment value
317: */
318: public int getAlignment() {
319: return caption.getAlignment();
320: }
321:
322: /**
323: * Set the alignment attribute
324: * @param align 1 to right align the text, 0 for left alignment and 2 for centered text
325: */
326: public void setAlignment(int align) {
327: caption.setAlignment(align);
328: }
329:
330: /**
331: * Get the caption style
332: * @return the style name
333: */
334: public String getCaptionStyle() {
335: return "caption";
336: }
337:
338: /**
339: * Set the caption style
340: * @param newStyle the style name
341: */
342: public void setCaptionStyle(String newStyle) {
343: XuiUtilities.applyStyle(currentProject, caption, newStyle);
344: }
345:
346: /**
347: * Get the image style
348: * @return the style name
349: */
350: public String getImageStyle() {
351: return "image";
352: }
353:
354: /**
355: * Set the image style
356: * @param newStyle the style name
357: */
358: public void setImageStyle(String newStyle) {
359: XuiUtilities.applyStyle(currentProject, image, newStyle);
360: }
361:
362: /**
363: * Get the caption
364: * @return the caption text
365: */
366: public String getCaption() {
367: return caption.getText();
368: }
369:
370: /**
371: * Set the caption
372: * @param s the caption text
373: */
374: public void setCaption(String s) {
375: caption.setText(s);
376: }
377:
378: /**
379: * Gets the shadow flag value.
380: * @return true if he shadow is drawn
381: */
382: public boolean getShadow() {
383: return image.getDrawShadow();
384: }
385:
386: /**
387: * Gets the name of the image being displayed.
388: * @return the image name
389: */
390: public String getImageName() {
391: return imgName;
392: }
393:
394: /**
395: * Gets the name of the image being displayed.
396: * @return the image name
397: */
398: public void setImageName(String name) {
399: imgName = name;
400: image.setImage(currentProject.getImage(imgName));
401: }
402:
403: /**
404: * Gets the fill border flag value.
405: * @return true if the area within the border is filled
406: */
407: public boolean getFillBorder() {
408: return image.getFillBorder();
409: }
410:
411: /**
412: * Gets the border flag value.
413: * @return the border property
414: */
415: public int getBorders() {
416: return borders;
417: }
418:
419: /**
420: * Sets the border flag value.
421: * @param bv the border property
422: */
423: public void setBorders(int bv) {
424: borders = bv;
425: if (borders == 0) {
426: image.setAttribute("border", "0");
427: super .setAttribute("border", "0");
428: } else if (borders == 1) {
429: image.setAttribute("border", "1");
430: super .setAttribute("border", "0");
431: } else if (borders == 2) {
432: image.setAttribute("border", "0");
433: super .setAttribute("border", "1");
434: } else if (borders == 3) {
435: image.setAttribute("border", "1");
436: super .setAttribute("border", "1");
437: }
438: }
439:
440: /**
441: * Set one or more attributes of the component. Currently this handles the
442: * attributes
443: * <OL>
444: * <LI>align (left|right|center ) or</LI>
445: * <LI>alignment (left|right|center )</LI>
446: * <LI>buffered (true|false) double buffering</LI>
447: * <LI>tooltip, value=the tooltip text</LI>
448: * <LI>caption, value=the text of the caption</LI>
449: * <LI>captionStyle, value=style for the caption</LI>
450: * <LI>imageStyle, value=style for the image</LI>
451: * <LI>border, value=0 for none, 1 for an outer border, 2 for an inner and outer border</LI>
452: * <LI>imagename value=the name of a background image to use as a watermark</LI>
453: * <LI>painter value=the class name of an XPainter class for painting the panel backgrounds</LI>
454: * <LI>arc value=the radius for teh panel corners</LI>
455: * <LI>pad value=the amount of padding around the image</LI>
456: * <LI>minWidth value=the minimum width</LI>
457: * <LI>minHeight value=the minimum height</LI>
458: * <LI>tooltip, value=the tooltip text</LI>
459: * <LI>opaque, value=true for an opaque image (fills the entire client area)</LI>
460: * </OL>
461: * @param attribName the attribute name
462: * @param attribValue the attribute value
463: * @return 0 for success
464: */
465: public int setAttribute(String attribName, Object attribValue) {
466: String attribNameLwr = attribName.toLowerCase();
467: String attribValueStr = (String) attribValue;
468: String attribValueLwr = attribValueStr.toLowerCase();
469:
470: if (attribValueLwr == null)
471: return 0;
472:
473: if (attribNameLwr.equals("caption"))
474: caption.setText(attribValueStr);
475: else if (attribNameLwr.equals("minwidth")) {
476: Dimension dim = getMinimumSize();
477: dim.width = Math.min(dim.width, minWidth = Integer
478: .parseInt(attribValueStr));
479: setMinimumSize(dim);
480: } else if (attribNameLwr.equals("minheight")) {
481: Dimension dim = getMinimumSize();
482: dim.height = Math.min(dim.height, minHeight = Integer
483: .parseInt(attribValueStr));
484: setMinimumSize(dim);
485: } else if (attribNameLwr.equals("maxwidth")) {
486: Dimension dim = getMaximumSize();
487: dim.width = Math.max(dim.width, maxWidth = Integer
488: .parseInt(attribValueStr));
489: setMaximumSize(dim);
490: } else if (attribNameLwr.equals("maxheight")) {
491: Dimension dim = getMaximumSize();
492: dim.height = Math.max(dim.height, maxHeight = Integer
493: .parseInt(attribValueStr));
494: setMaximumSize(dim);
495: } else if (attribNameLwr.equals("prefwidth")) {
496: Dimension dim = getPreferredSize();
497: dim.width = Math.min(dim.width, prefWidth = Integer
498: .parseInt(attribValueStr));
499: setPreferredSize(dim);
500: } else if (attribNameLwr.equals("prefheight")) {
501: Dimension dim = getPreferredSize();
502: dim.height = Math.min(dim.height, prefHeight = Integer
503: .parseInt(attribValueStr));
504: setPreferredSize(dim);
505: } else if (attribNameLwr.equals("pad")
506: || attribNameLwr.equals("padding"))
507: setPadding(Integer.parseInt(attribValueStr));
508: else if (attribNameLwr.equals("align")
509: || attribNameLwr.equals("alignment")
510: || attribNameLwr.equals("buffered")
511: || attribNameLwr.equals("align")) {
512: // Forward attributes to the caption
513: caption.setAttribute(attribName, attribValue);
514: } else if (attribNameLwr.equals("shadow")) {
515: shadow = attribValue.equals("true");
516: image.setAttribute(attribName, attribValue);
517: } else if (attribNameLwr.equals("shadow")
518: || attribNameLwr.equals("fill")) {
519: image.setAttribute(attribName, attribValue);
520: } else if (attribNameLwr.equals("content")
521: || attribNameLwr.equals("imagename")) {
522: if (((String) attribValue).endsWith(".svg")) {
523: image.setAttribute(attribName, attribValue);
524: XSvgPainter p = new XSvgPainter(image);
525: p.setImage(currentProject
526: .findResource((String) attribValue));
527: image.setPainter(p);
528: } else {
529: setImageName((String) attribValue);
530: }
531: } else if (attribNameLwr.equals("captionstyle"))
532: XuiUtilities.applyStyle(currentProject, caption,
533: attribValueStr);
534: else if (attribNameLwr.equals("imagestyle"))
535: XuiUtilities.applyStyle(currentProject, image,
536: attribValueStr);
537: else if (attribNameLwr.equals("borders")) {
538: borders = Integer.parseInt(attribValueStr);
539: setBorders(borders);
540: } else if (attribNameLwr.equals("arc")
541: || attribNameLwr.equals("opaque")
542: || attribNameLwr.equals("enabled")
543: || attribNameLwr.equals("tooltip")) {
544: image.setAttribute(attribName, attribValue);
545: super .setAttribute(attribName, attribValue);
546: } else if (attribNameLwr.equals("dragenabled")) {
547: image.setAttribute(attribName, attribValue);
548: } else if (attribNameLwr.equals("draginfo")) {
549: image.setAttribute(attribName, attribValue);
550: } else if (attribNameLwr.equals("stretch")) {
551: image.setAttribute(attribName, attribValue);
552: } else if (attribNameLwr.equals("antialias"))
553: caption.setAttribute(attribName, attribValue);
554: else
555: super .setAttribute(attribName, attribValue);
556:
557: if (tooltipSet == false && super .getToolTipText() != null) {
558: image.setAttribute("tooltip", super .getToolTipText());
559: tooltipSet = true;
560: }
561:
562: return 0;
563: }
564:
565: /**
566: * Sets the XImage instance to have the same name as the instansiating class.
567: * @param value <CODE>String</CODE> specifying the name given tos this class.
568: */
569: public void setName(String value) {
570: image.setName(value);
571: }
572:
573: /**
574: * Returns the XImage instance used by ths class.
575: * @return <CODE>XImage</CODE> instance returned.
576: */
577: public XImage getImage() {
578: return image;
579: }
580:
581: /**
582: * Adds a mouse listener to this component to listen for mouse events.
583: * @param l the <CODE>MouseListener</CODE> that is to be added.
584: */
585: public void addCaptionListener(MouseListener l) {
586: addMouseListener(l);
587: super .addMouseListener(this );
588: image.addMouseListener(this );
589:
590: listeners.add(l);
591: listeners.add(this );
592: }
593:
594: /**
595: * Removes a mouse listener to this component.
596: * @param l the <CODE>MouseListener</CODE> that is to be removed.
597: */
598: public void removeCaptionListener(MouseListener l) {
599: removeMouseListener(l);
600: super .removeMouseListener(this );
601: image.removeMouseListener(this );
602:
603: listeners.remove(l);
604: listeners.remove(this );
605: }
606:
607: /**
608: * Set the attributes for the next component being added
609: * @param attribs a table of attributes
610: */
611: public void setNextAttributes(Object attribs) {
612: }
613:
614: /**
615: * Fired when a mouse is clicked on this component.
616: * @param e the passed <CODE>MouseEvent</CODE> instance.
617: */
618: public void mouseClicked(MouseEvent e) {
619: fireActionPerformed(e);
620: }
621:
622: /**
623: * Fired when a mouse is pressed on this component.
624: * @param e the passed <CODE>MouseEvent</CODE> instance.
625: */
626: public void mousePressed(MouseEvent e) {
627: fireActionPerformed(e);
628: }
629:
630: /**
631: * Fired when a mouse is released on this component.
632: * @param e the passed <CODE>MouseEvent</CODE> instance.
633: */
634: public void mouseReleased(MouseEvent e) {
635: fireActionPerformed(e);
636: }
637:
638: /**
639: * Fired when a mouse enters this component.
640: * @param e the passed <CODE>MouseEvent</CODE> instance.
641: */
642: public void mouseEntered(MouseEvent e) {
643: fireActionPerformed(e);
644: }
645:
646: /**
647: * Fired when a mouse exited this component.
648: * @param e the passed <CODE>MouseEvent</CODE> instance.
649: */
650: public void mouseExited(MouseEvent e) {
651: fireActionPerformed(e);
652: }
653:
654: /**
655: * Notifies all mouse listeners that have registered interest for
656: * notification on mouse event types. The event instance
657: * is lazily created using the <code>event</code>
658: * parameter.
659: *
660: * @param event the <code>MouseEvent</code> object
661: */
662: protected void fireActionPerformed(MouseEvent event) {
663: // Guaranteed to return a non-null array
664: MouseEvent e = null;
665: // Process the listeners last to first, notifying
666: // those that are interested in this event
667: for (int i = 0; i < listeners.size(); i++) {
668: if (listeners.get(i) instanceof MouseListener) {
669: // Lazily create the event:
670: if (e == null) {
671: switch (event.getID()) {
672: case MouseEvent.MOUSE_ENTERED:
673: e = new MouseEvent(XCaptionedImage.this ,
674: MouseEvent.MOUSE_ENTERED, 0, 0, 0, 0,
675: 0, false);
676: ((MouseListener) listeners.get(i))
677: .mouseEntered(e);
678: case MouseEvent.MOUSE_EXITED:
679: e = new MouseEvent(XCaptionedImage.this ,
680: MouseEvent.MOUSE_EXITED, 0, 0, 0, 0, 0,
681: false);
682: ((MouseListener) listeners.get(i))
683: .mouseExited(e);
684: case MouseEvent.MOUSE_RELEASED:
685: e = new MouseEvent(XCaptionedImage.this ,
686: MouseEvent.MOUSE_RELEASED, 0, 0, 0, 0,
687: 0, false);
688: ((MouseListener) listeners.get(i))
689: .mouseReleased(e);
690: case MouseEvent.MOUSE_PRESSED:
691: e = new MouseEvent(XCaptionedImage.this ,
692: MouseEvent.MOUSE_PRESSED, 0, 0, 0, 0,
693: 0, false);
694: ((MouseListener) listeners.get(i))
695: .mousePressed(e);
696: case MouseEvent.MOUSE_CLICKED:
697: e = new MouseEvent(XCaptionedImage.this ,
698: MouseEvent.MOUSE_CLICKED, 0, 0, 0, 0,
699: 0, false);
700: ((MouseListener) listeners.get(i))
701: .mouseClicked(e);
702: }
703: }
704: }
705: }
706: }
707: }
|