Source code: echopoint/HidingSlidingPanel.java
1 package echopoint;
2
3 /*
4 * This file is part of the Echo Point Project. This project is a collection
5 * of Components that have extended the Echo Web Application Framework.
6 *
7 * EchoPoint is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * EchoPoint is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with Echo Point; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 import java.awt.Image;
23 import java.text.AttributedString;
24
25 import nextapp.echo.Color;
26 import nextapp.echo.EchoConstants;
27 import nextapp.echo.EchoInstance;
28 import nextapp.echo.Font;
29 import nextapp.echo.ImageReference;
30
31 import echopoint.image.ImageKit;
32 import echopoint.image.TextImageReference;
33 import echopoint.layout.LayoutManager;
34 import echopoint.stylesheet.CssStyleSheetHelper;
35 import echopoint.stylesheet.StyleAttrDescriptor;
36 import echopoint.stylesheet.StyleInfo;
37 import echopoint.ui.resource.ResourceNames;
38
39 /**
40 *
41 * The <code>HidingSlidingPanel</code> class provides a <code>Scrollable</code>
42 * component that can be hidden on the side of the client window
43 * ready to slide in and be used.
44 * <p>
45 * It is useful to provide quick access to a panel of other components, that
46 * the user can tuck away out of view. For example it could be used to
47 * hold a tool box of controls or a list of actions the user can perform.
48 * <p>
49 * The hidingAlignment property controls which side of the client window
50 * the HidingSlidingPanel will go to. This can be the following values :
51 * <ul>
52 * <li>EchoConstant.LEFT</li>
53 * <li>EchoConstant.TOP</li>
54 * </ul>
55 * <p>
56 * The XY property is the position along the client window that the
57 * panel will be placed. It is always the opposite of the alignment.
58 * <p>
59 * The hidingOnIcon and hidingOffIcon are used to provide a visual clue as
60 * to the presence of the HidingPanel. Clicking on these icons
61 * will move/remove the HidingPanel from view. You must provde an icon
62 * other wise the user will not have a visual cue with which to move the
63 * HidingSlidingPanel.
64 * <p>
65 * Note : the normal Positionable parameters are not adhered to by the
66 * HidingSlidingPanel. While they are used to size the panel initially,
67 * the panel will be moved to a place controlled by the XY property.
68 * <p>
69 * @author Brad Baker
70 */
71 public class HidingSlidingPanel extends ScrollableBox {
72
73 public static final String EXPANDED_CHANGED_PROPERTY = "expanded";
74
75 /**
76 * Property change name constants
77 */
78 public static final String HIDING_ALIGMENT_CHANGED_PROPERTY = "hidingAlignment";
79 private static final int imgW = 150, imgH = 18;
80 public static final String JUMP_CHANGED_PROPERTY = "jump";
81 public static final String OFF_ICON_CHANGED_PROPERTY = "offIcon";
82 private static final Image offLeftImgDefault;
83 private static final Image offTopImgDefault;
84 public static final String ON_ICON_CHANGED_PROPERTY = "onIcon";
85 private static final Image onLeftImgDefault;
86
87 /** preload our default images so we only have one memory copy*/
88 private static final Image onTopImgDefault;
89
90 /**
91 * A style constant for the Expanded property.
92 * Values of this key must be of type <code>boolean</code>
93 */
94 public static final String STYLE_EXPANDED = "expanded";
95 /**
96 * A style constant for the HidingAlignment property.
97 * Values of this key must be of type <code>int</code>
98 */
99 public static final String STYLE_HIDING_ALIGNMENT = "hidingAlignment";
100 /**
101 * A style constant for the Off Icon property.
102 * Values of this key must be of type <code>ImageReference</code>
103 */
104 public static final String STYLE_OFF_ICON = "offIcon";
105 /**
106 * A style constant for the On Icon property.
107 * Values of this key must be of type <code>ImageReference</code>
108 */
109 public static final String STYLE_ON_ICON = "onIcon";
110 /**
111 * A style constant for the XY property.
112 * Values of this key must be of type <code>int</code>
113 */
114 public static final String STYLE_XY = "xy";
115
116 /**
117 * Nested public static StyleInfo class. For more info:
118 * @see echopoint.stylesheet.StyleInfo
119 */
120 public static class NestedStyleInfo implements StyleInfo {
121 private static StyleAttrDescriptor[] styleDescriptors = {
122 new StyleAttrDescriptor(STYLE_EXPANDED,Boolean.class,"expanded"),
123 new StyleAttrDescriptor(STYLE_HIDING_ALIGNMENT,Integer.class,"hidingAlignment",CssStyleSheetHelper.ecLeftTop),
124 new StyleAttrDescriptor(STYLE_OFF_ICON,ImageReference.class,"offIcon"),
125 new StyleAttrDescriptor(STYLE_ON_ICON,ImageReference.class,"onIcon"),
126 new StyleAttrDescriptor(STYLE_XY,Integer.class,"XY"),
127 };
128 /**
129 * @see echopoint.stylesheet.StyleInfo#getStyleDescriptors()
130 */
131 public StyleAttrDescriptor[] getStyleDescriptors() {
132 return styleDescriptors;
133 }
134 }
135
136 public static final String XY_CHANGED_PROPERTY = "xy";
137 private boolean expanded = false;
138 private int hidingAlignment = EchoConstants.LEFT;
139 private boolean iconsByMe = true;
140 private boolean jump = false;
141 private ImageReference offIcon = null;
142 private String offTitle = "";
143 private Font offTitleFont = EchoInstance.DEFAULT_FONT;
144 private Color offTitleForeground = EchoInstance.DEFAULT_FOREGROUND;
145 private ImageReference onIcon = null;
146 private String onTitle = "";
147 private Font onTitleFont = EchoInstance.DEFAULT_FONT;
148 private Color onTitleForeground = EchoInstance.DEFAULT_FOREGROUND;
149 private int xy = 0;
150 static {
151 onTopImgDefault = ImageKit.loadResourceImage(ResourceNames.HSP_T_IMAGE_ON,imgW,imgH);
152 offTopImgDefault = ImageKit.loadResourceImage(ResourceNames.HSP_T_IMAGE_OFF,imgW,imgH);
153 onLeftImgDefault = ImageKit.loadResourceImage(ResourceNames.HSP_L_IMAGE_ON,imgH,imgW);
154 offLeftImgDefault = ImageKit.loadResourceImage(ResourceNames.HSP_L_IMAGE_OFF,imgH,imgW);
155 }
156
157 /**
158 * Constructs a HidingPanel with the hiding alignment site to EchoConstants.LEFT
159 * and the XY property set to 10.
160 */
161 public HidingSlidingPanel() {
162 this(EchoConstants.LEFT);
163 }
164
165 /**
166 * Constructs a <code>HidingSlidingPanel</code> with a LayoutManager and
167 * with the hiding alignment site to EchoConstants.LEFT
168 * and the XY property set to 10.
169 */
170 public HidingSlidingPanel(LayoutManager layoutManager) {
171 super(layoutManager);
172 }
173
174 /**
175 * Constructs a HidingPanel with the specified hiding alignment
176 * and the XY property set to 10.
177 * <p>
178 * The hisding alignment can be the following values :
179 * <ul>
180 * <li>EchoConstant.LEFT</li>
181 * <li>EchoConstant.TOP</li>
182 * </ul>
183 */
184 public HidingSlidingPanel(int newHidingAlignment) {
185 super();
186 setXY(10);
187 setLeft(0);
188 setTop(0);
189 setzIndex(32000);
190 setPositioning(POSITIONING_ABSOLUTE);
191 this.hidingAlignment = newHidingAlignment;
192 _setUpIcons(true);
193 }
194
195 private void _setOffIcon(ImageReference newOffIcon, boolean iconsByMe) {
196 ImageReference oldValue = offIcon;
197 if (newOffIcon != null && (newOffIcon.getWidth() == 0 || newOffIcon.getHeight() == 0))
198 throw new IllegalArgumentException("Off icon must have a width and height");
199 offIcon = newOffIcon;
200 firePropertyChange(OFF_ICON_CHANGED_PROPERTY, oldValue, newOffIcon);
201 this.iconsByMe = iconsByMe;
202 }
203
204 private void _setOnIcon(ImageReference newOnIcon, boolean iconsByMe) {
205 ImageReference oldValue = onIcon;
206 if (newOnIcon != null && (newOnIcon.getWidth() == 0 || newOnIcon.getHeight() == 0))
207 throw new IllegalArgumentException("On icon must have a width and height");
208 onIcon = newOnIcon;
209 firePropertyChange(ON_ICON_CHANGED_PROPERTY, oldValue, newOnIcon);
210 this.iconsByMe = iconsByMe;
211 }
212
213 /**
214 * Called to setup the on/off icons to use accroding to the current alignment
215 * This checks to ensure that the user has not "set" in its own custom
216 * ImageReferences. We only want to use out icons if they user
217 * has not specified their own.
218 */
219 private void _setUpIcons(boolean newAlignmentInPlace) {
220 if (! iconsByMe)
221 return;
222
223 // TextImageReference onImgRef = (TextImageReference) this.offIcon;
224 // TextImageReference offImgRef = (TextImageReference) this.onIcon;
225 TextImageReference onImgRef = (TextImageReference) this.onIcon;
226 TextImageReference offImgRef = (TextImageReference) this.offIcon;
227
228 if (onImgRef == null || offImgRef == null || newAlignmentInPlace) {
229 if (hidingAlignment == EchoConstants.TOP) {
230 onImgRef = new TextImageReference(null,onTopImgDefault);
231 offImgRef = new TextImageReference(null,offTopImgDefault);
232 } else if (hidingAlignment == EchoConstants.LEFT) {
233 onImgRef = new TextImageReference(null,onLeftImgDefault);
234 offImgRef = new TextImageReference(null,offLeftImgDefault);
235 }
236
237
238 }
239
240 int x = 0;
241 int y = 0;
242 int hAlignment = EchoConstants.LEFT;
243 int vAlignment = EchoConstants.CENTER;
244 int textAngle = 0;
245 if (hidingAlignment == EchoConstants.TOP) {
246 textAngle = 0;
247 x = 35; y = 9;
248 } else if (hidingAlignment == EchoConstants.LEFT) {
249 textAngle = 90;
250 x = 9; y = 10;
251 }
252 onImgRef.setX(x);
253 onImgRef.setY(y);
254 onImgRef.setHorizontalAlignment(hAlignment);
255 onImgRef.setVerticalAlignment(vAlignment);
256 onImgRef.setTextAngle(textAngle);
257
258 offImgRef.setX(x);
259 offImgRef.setY(y);
260 offImgRef.setHorizontalAlignment(hAlignment);
261 offImgRef.setVerticalAlignment(vAlignment);
262 offImgRef.setTextAngle(textAngle);
263
264 AttributedString as;
265
266 as = TextImageReference.getAttributedString(onTitle,onTitleForeground,onTitleFont);
267 onImgRef.setString(as);
268
269 as = TextImageReference.getAttributedString(offTitle,offTitleForeground,offTitleFont);
270 offImgRef.setString(as);
271
272 _setOnIcon(onImgRef,true);
273 _setOffIcon(offImgRef,true);
274 }
275
276 /**
277 * Applies the provided style to the component. The base <code>nextapp.echo.Component</code>
278 * style names can be used as well.
279 */
280 public void applyStyle(nextapp.echo.Style style) {
281 super.applyStyle(style);
282
283 if (style.hasAttribute(STYLE_EXPANDED))
284 setExpanded(style.getBooleanAttribute(STYLE_EXPANDED));
285
286 if (style.hasAttribute(STYLE_HIDING_ALIGNMENT))
287 setHidingAlignment(style.getIntegerAttribute(STYLE_HIDING_ALIGNMENT));
288
289 if (style.hasAttribute(STYLE_OFF_ICON))
290 setOffIcon((ImageReference) style.getAttribute(STYLE_OFF_ICON));
291
292 if (style.hasAttribute(STYLE_ON_ICON))
293 setOnIcon((ImageReference) style.getAttribute(STYLE_ON_ICON));
294
295 if (style.hasAttribute(STYLE_XY))
296 setXY(style.getIntegerAttribute(STYLE_XY));
297
298 if (style.hasAttribute(STYLE_TOOL_TIP_TEXT))
299 setToolTipText(style.getStringAttribute(STYLE_TOOL_TIP_TEXT));
300 }
301 /**
302 * Returns the hiding alignment in place. This can be :
303 * <p>
304 * <ul>
305 * <li>EchoConstant.LEFT</li>
306 * <li>EchoConstant.TOP</li>
307 * </ul>
308 *
309 */
310 public int getHidingAlignment() {
311 return hidingAlignment;
312 }
313 /**
314 * Returns the icon to be used when the panel is hidden
315 *
316 * @return nextapp.echo.ImageReference
317 */
318 public nextapp.echo.ImageReference getOffIcon() {
319 return offIcon;
320 }
321 /**
322 * Returns the Off Title used on the expansion icons.
323 * <p>
324 * Note that this take effect if the default internal
325 * TextImageReference icons are used. if you set your own
326 * on and off icons, then this property has no effect.
327 *
328 * @return - the offTitle of the HisingSlidingPanel
329 */
330 public String getOffTitle() {
331 return offTitle;
332 }
333
334 /**
335 * Returns the Off Title font used on the expansion icons.
336 * <p>
337 * Note that this take effect if the default internal
338 * TextImageReference icons are used. if you set your own
339 * on and off icons, then this property has no effect.
340 *
341 * @return Font - the font of the Title
342 */
343 public Font getOffTitleFont() {
344 return offTitleFont;
345 }
346
347 /**
348 * Returns the Off Title foreground used on the expansion icons.
349 * <p>
350 * Note that this take effect if the default internal
351 * TextImageReference icons are used. if you set your own
352 * on and off icons, then this property has no effect.
353 *
354 * @return Color the color of the title
355 */
356 public Color getOffTitleForeground() {
357 return offTitleForeground;
358 }
359 /**
360 * Returns the icon to be used when the panel is visible
361 *
362 * @return nextapp.echo.ImageReference
363 */
364 public nextapp.echo.ImageReference getOnIcon() {
365 return onIcon;
366 }
367
368 /**
369 * Returns the On Title used on the expansion icons.
370 * <p>
371 * Note that this take effect if the default internal
372 * TextImageReference icons are used. if you set your own
373 * on and off icons, then this property has no effect.
374 *
375 * @return - the offTitle of the HisingSlidingPanel
376 */
377 public String getOnTitle() {
378 return onTitle;
379 }
380
381 /**
382 * Returns the On Title font used on the expansion icons.
383 * <p>
384 * Note that this take effect if the default internal
385 * TextImageReference icons are used. if you set your own
386 * on and off icons, then this property has no effect.
387 *
388 * @return Font
389 */
390 public Font getOnTitleFont() {
391 return onTitleFont;
392 }
393
394 /**
395 * Returns the On Title foreground used on the expansion icons.
396 * <p>
397 * Note that this take effect if the default internal
398 * TextImageReference icons are used. if you set your own
399 * on and off icons, then this property has no effect.
400 *
401 * @return Color
402 */
403 public Color getOnTitleForeground() {
404 return onTitleForeground;
405 }
406
407 /**
408 * Returns the XY property
409 *
410 */
411 public int getXY() {
412 return xy;
413 }
414 /**
415 * Returns true of the panel is currently expanded
416 */
417 public boolean isExpanded() {
418 return expanded;
419 }
420
421 /**
422 * Gets whether the <code>HidingSlidingPanel</code> will jump
423 * directly to its final position or slide there.
424 * <p>
425 * By default this is <code>false</code>.
426 *
427 * @return whether it will jump directly to its final position
428 */
429 public boolean isJump() {
430 return jump;
431 }
432 /**
433 * Sets the expansion state of the panel. If its true then the
434 * panel will shown expanded on the client window. If its false
435 * then the panel will be hidden.
436 *
437 */
438 public void setExpanded(boolean newState) {
439 boolean oldValue = expanded;
440 expanded = newState;
441 firePropertyChange(EXPANDED_CHANGED_PROPERTY, oldValue, newState);
442 }
443
444 /**
445 * Sets the hiding alignment of the panel. This can be one of
446 * <p>
447 * <ul>
448 * <li>EchoConstant.LEFT</li>
449 * <li>EchoConstant.TOP</li>
450 * </ul>
451 *
452 *
453 * @exception IllegalArgumentException if the hiding alighment is not one of the above
454 *
455 */
456 public void setHidingAlignment(int newHidingAlignment) {
457
458 if (newHidingAlignment != EchoConstants.LEFT && newHidingAlignment != EchoConstants.TOP)
459 throw new IllegalArgumentException("Hiding alignment must be either EchoConstants.LEFT or EchoConstants.TOP");
460
461 int oldValue = hidingAlignment;
462 hidingAlignment = newHidingAlignment;
463 firePropertyChange(HIDING_ALIGMENT_CHANGED_PROPERTY, oldValue, newHidingAlignment);
464
465 _setUpIcons(oldValue != hidingAlignment);
466 }
467
468 /**
469 * Sets whether the <code>HidingSlidingPanel</code> will jump
470 * directly to its final position or slide there.
471 * <p>
472 * By default this is <code>false</code>.
473 *
474 * @param newValue
475 */
476 public void setJump(boolean newValue) {
477 boolean oldValue = jump;
478 jump = newValue;
479 firePropertyChange(JUMP_CHANGED_PROPERTY,oldValue,newValue);
480 }
481
482 /**
483 * Sets the icon to be used when the panel is hidden (ie not expanded).
484 * <p>
485 * The icon may null in which case a default one will be rendered. If it
486 * is not null then it must have a width and height > 0,
487 * otherwise an IllegalArgumentException is thrown.
488 *
489 * @exception IllegalArgumentException if the width and height are <= 0
490 */
491 public void setOffIcon(ImageReference newOffIcon) {
492 _setOffIcon(newOffIcon,false);
493 }
494
495 /**
496 * Sets the Off Title used on the expansion icons.
497 * <p>
498 * Note that this take effect if the default internal
499 * TextImageReference icons are used. if you set your own
500 * on and off icons, then this property has no effect.
501 *
502 *
503 * @param string
504 */
505 public void setOffTitle(String string) {
506 offTitle = string;
507 _setUpIcons(false);
508 }
509
510 /**
511 * Sets the Off Title font used on the expansion icons.
512 * <p>
513 * Note that this take effect if the default internal
514 * TextImageReference icons are used. if you set your own
515 * on and off icons, then this property has no effect.
516 *
517 * @param font
518 */
519 public void setOffTitleFont(Font font) {
520 offTitleFont = font;
521 _setUpIcons(false);
522 }
523
524 /**
525 * Sets the Off Title foreground used on the expansion icons.
526 * <p>
527 * Note that this take effect if the default internal
528 * TextImageReference icons are used. if you set your own
529 * on and off icons, then this property has no effect.
530 *
531 * @param color
532 */
533 public void setOffTitleForeground(Color color) {
534 offTitleForeground = color;
535 _setUpIcons(false);
536 }
537 /**
538 * Sets the icon to be used when the panel is visible (ie is expanded).
539 * <p>
540 * The icon may null in which case a default one will be rendered. If it
541 * is not null then it must have a width and height > 0,
542 * otherwise an IllegalArgumentException is thrown.
543 *
544 * @exception IllegalArgumentException if the width and height are <= 0
545 */
546 public void setOnIcon(ImageReference newOnIcon) {
547 _setOnIcon(newOnIcon,false);
548 }
549
550 /**
551 * Sets the On Title used on the expansion icons.
552 * <p>
553 * Note that this take effect if the default internal
554 * TextImageReference icons are used. if you set your own
555 * on and off icons, then this property has no effect.
556 *
557 *
558 * @param string
559 */
560 public void setOnTitle(String string) {
561 onTitle = string;
562 _setUpIcons(false);
563 }
564
565 /**
566 * Sets the On Title font used on the expansion icons.
567 * <p>
568 * Note that this take effect if the default internal
569 * TextImageReference icons are used. if you set your own
570 * on and off icons, then this property has no effect.
571 *
572 * @param font
573 */
574 public void setOnTitleFont(Font font) {
575 onTitleFont = font;
576 _setUpIcons(false);
577 }
578
579 /**
580 * Sets the On Title foreground used on the expansion icons.
581 * <p>
582 * Note that this take effect if the default internal
583 * TextImageReference icons are used. if you set your own
584 * on and off icons, then this property has no effect.
585 *
586 * @param color
587 */
588 public void setOnTitleForeground(Color color) {
589 onTitleForeground = color;
590 _setUpIcons(false);
591 }
592 /**
593 * Sets the XY value to be used by the panel. This is always
594 * opposite to the hidingAlignment.
595 * <p>
596 * For example if the hiding alignment is LEFT, then xy will
597 * represent the y co-ordinate to place the panel.
598 * <p>
599 * if the hiding alignment is TOP, then xy will
600 * represent the x co-ordinate to place the panel.
601 *
602 * @param newXy int
603 */
604 public void setXY(int newXy) {
605 int oldValue = xy;
606 xy = newXy;
607 firePropertyChange(XY_CHANGED_PROPERTY, oldValue, newXy);
608 }
609
610 /** @see echopoint.util.ReflectionSetter#set(Field, Object) */
611 public Object set(java.lang.reflect.Field field, Object newValue) throws Exception {
612 Object oldValue = field.get(this); field.set(this,newValue); return oldValue;
613 }
614
615 }