001: /*
002: #IFNDEF ALT_LICENSE
003: ThinWire(R) RIA Ajax Framework
004: Copyright (C) 2003-2007 Custom Credit Systems
005:
006: This library is free software; you can redistribute it and/or modify it under
007: the terms of the GNU Lesser General Public License as published by the Free
008: Software Foundation; either version 2.1 of the License, or (at your option) any
009: later version.
010:
011: This library is distributed in the hope that it will be useful, but WITHOUT ANY
012: WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
013: PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
014:
015: You should have received a copy of the GNU Lesser General Public License along
016: with this library; if not, write to the Free Software Foundation, Inc., 59
017: Temple Place, Suite 330, Boston, MA 02111-1307 USA
018:
019: Users who would rather have a commercial license, warranty or support should
020: contact the following company who invented, built and supports the technology:
021:
022: Custom Credit Systems, Richardson, TX 75081, USA.
023: email: info@thinwire.com ph: +1 (888) 644-6405
024: http://www.thinwire.com
025: #ENDIF
026: [ v1.2_RC2 ]
027: */
028: package thinwire.render.web;
029:
030: import java.io.IOException;
031: import java.net.MalformedURLException;
032: import java.net.URI;
033: import java.net.URISyntaxException;
034: import java.net.URL;
035: import java.util.*;
036: import java.util.regex.Pattern;
037: import java.util.logging.Logger;
038: import java.util.logging.Level;
039:
040: import thinwire.render.*;
041: import thinwire.ui.event.*;
042: import thinwire.ui.*;
043: import thinwire.ui.style.*;
044:
045: /**
046: * @author Joshua J. Gertzen
047: */
048: abstract class ComponentRenderer implements Renderer,
049: WebComponentListener {
050: static final String SET_STYLE = "setStyle";
051: static final String SET_STYLES = "setStyles";
052: static final String REGISTER_EVENT_NOTIFIER = "registerEventNotifier";
053: static final String UNREGISTER_EVENT_NOTIFIER = "unregisterEventNotifier";
054: static final String SET_ENABLED = "setEnabled";
055: static final String SET_FOCUS = "setFocus";
056: static final String SET_FOCUS_CAPABLE = "setFocusCapable";
057: static final String SET_X = "setX";
058: static final String SET_Y = "setY";
059: static final String SET_WIDTH = "setWidth";
060: static final String SET_HEIGHT = "setHeight";
061: static final String SET_VISIBLE = "setVisible";
062: static final String SET_OPACITY = "setOpacity";
063: static final String SET_PROPERTY_WITH_EFFECT = "setPropertyWithEffect";
064:
065: //Shared by other renderers
066: static final String DESTROY = "destroy";
067: static final String SET_IMAGE = "setImage";
068: static final String SET_ALIGN_X = "setAlignX";
069:
070: static final String CLIENT_EVENT_DROP = "drop";
071:
072: static final Logger log = Logger.getLogger(ComponentRenderer.class
073: .getName());
074:
075: private static final Pattern REGEX_DOUBLE_SLASH = Pattern
076: .compile("\\\\");
077: private static final Pattern REGEX_DOUBLE_QUOTE = Pattern
078: .compile("\"");
079: private static final Pattern REGEX_CRLF = Pattern
080: .compile("\\r?\\n|\\r");
081:
082: private static final Object NO_VALUE = new Object();
083:
084: private List<String> remoteFiles;
085: private StringBuilder initProps = new StringBuilder();
086: private Map<String, Object> ignoredProperties = new HashMap<String, Object>(
087: 3);
088: private Map<String, String> clientSideProps = new HashMap<String, String>();
089: private RichTextParser richTextParser;
090:
091: String jsClass;
092: Component comp;
093: WindowRenderer wr;
094: ContainerRenderer cr;
095: Integer id;
096:
097: void init(String jsClass, WindowRenderer wr, Component comp,
098: ComponentRenderer container) {
099: this .jsClass = jsClass;
100: this .wr = wr;
101: this .cr = container instanceof ContainerRenderer ? (ContainerRenderer) container
102: : null;
103: this .comp = comp;
104: //this.initProps = new StringBuilder();
105: //ignoredProperties.clear();
106: //clientSideProps.clear();
107: }
108:
109: static String getSimpleClassName(Class type) {
110: String text = type.getName();
111: text = text.substring(text.lastIndexOf('.') + 1);
112: return text;
113: }
114:
115: void render(WindowRenderer wr, Component comp,
116: ComponentRenderer container) {
117: id = wr.addComponentId(comp);
118: if (this instanceof WebComponentListener)
119: wr.ai.setWebComponentListener(id, this );
120: Effect.Motion visibleChange = comp.getStyle().getFX()
121: .getVisibleChange();
122: addClientSideProperty(Component.PROPERTY_FOCUS);
123:
124: if (!isPropertyChangeIgnored(Component.PROPERTY_X))
125: addInitProperty(Component.PROPERTY_X, comp.getX());
126: if (!isPropertyChangeIgnored(Component.PROPERTY_Y))
127: addInitProperty(Component.PROPERTY_Y, comp.getY());
128: if (!isPropertyChangeIgnored(Component.PROPERTY_WIDTH))
129: addInitProperty(Component.PROPERTY_WIDTH, comp.getWidth());
130: if (!isPropertyChangeIgnored(Component.PROPERTY_HEIGHT))
131: addInitProperty(Component.PROPERTY_HEIGHT, comp.getHeight());
132: if (!isPropertyChangeIgnored(Style.PROPERTY_OPACITY)
133: && comp.getStyle().getOpacity() != 100)
134: addInitProperty(Style.PROPERTY_OPACITY, comp.getStyle()
135: .getOpacity());
136: if (!isPropertyChangeIgnored(Component.PROPERTY_VISIBLE))
137: addInitProperty(Component.PROPERTY_VISIBLE,
138: visibleChange != Effect.Motion.NONE && cr != null
139: && cr.isFullyRendered() ? Boolean.FALSE
140: : comp.isVisible());
141: if (!isPropertyChangeIgnored(Component.PROPERTY_ENABLED))
142: addInitProperty(Component.PROPERTY_ENABLED, comp
143: .isEnabled());
144: if (!comp.isFocusCapable())
145: addInitProperty(Component.PROPERTY_FOCUS_CAPABLE, false);
146:
147: Style defaultStyle = wr.ai.getDefaultStyle(comp.getClass());
148: addInitProperty("styleClass", wr.ai.styleToStyleClass
149: .get(defaultStyle));
150: StringBuilder styleProps = wr.ai.getStyleValues(this ,
151: new StringBuilder(), comp.getStyle(), defaultStyle);
152: if (styleProps.length() > 0)
153: addInitProperty("styleProps", styleProps);
154:
155: if (comp.isFocus())
156: addInitProperty(Component.PROPERTY_FOCUS, true);
157:
158: Object parent = comp.getParent();
159: if (parent instanceof Container)
160: addInitProperty("insertAtIndex", ((Container) parent)
161: .getChildren().indexOf(comp));
162:
163: if (jsClass != null) {
164: initProps.insert(0, '{');
165: initProps.setCharAt(initProps.length() - 1, '}');
166: wr.ai.clientSideFunctionCall("tw_newComponent", jsClass,
167: id, cr == null ? (container == null ? 0
168: : container.id) : cr.id, initProps);
169: //initProps = null;
170: initProps.setLength(0);
171: }
172:
173: if (visibleChange != Effect.Motion.NONE
174: && !isPropertyChangeIgnored(Component.PROPERTY_VISIBLE)
175: && comp.isVisible() && cr != null
176: && cr.isFullyRendered())
177: setPropertyWithEffect(Component.PROPERTY_VISIBLE,
178: Boolean.TRUE, Boolean.FALSE, SET_VISIBLE,
179: FX.PROPERTY_FX_VISIBLE_CHANGE);
180:
181: wr.ai.setPackagePrivateMember("renderer", comp, this );
182:
183: if (comp.isFocusCapable()
184: && comp.isEnabled()
185: && comp.getParent() instanceof Container
186: && ((Container) wr.comp).getComponentWithFocus() == null)
187: comp.setFocus(true);
188:
189: wr.ai.flushRenderCallbacks(comp, id);
190: }
191:
192: private void setStyle(String propertyName, Object oldValue) {
193: if (propertyName.startsWith("fx")
194: || isPropertyChangeIgnored(propertyName))
195: return;
196: Style s = comp.getStyle();
197: if (propertyName.equals(Border.PROPERTY_BORDER_TYPE)
198: && s.getBorder().getType() == Border.Type.IMAGE)
199: return;
200: Object value;
201:
202: if (propertyName.equals(Border.PROPERTY_BORDER_COLOR)) {
203: if (s.getBorder().getType() == Border.Type.NONE)
204: return;
205: value = s.getBorder().getColor();
206: } else if (propertyName.equals(Border.PROPERTY_BORDER_IMAGE)) {
207: value = s.getBorder().getImageInfo();
208: } else if (propertyName.equals(Font.PROPERTY_FONT_UNDERLINE)
209: || propertyName.equals(Font.PROPERTY_FONT_STRIKE)) {
210: value = new Boolean[] { s.getFont().isUnderline(),
211: s.getFont().isStrike() };
212: } else {
213: value = s.getProperty(propertyName);
214: }
215:
216: StringBuilder sb = new StringBuilder();
217: sb.append('{');
218:
219: if (value instanceof Border.Type) {
220: if (value == Border.Type.NONE) {
221: value = Border.Type.SOLID;
222: wr.ai.getStyleValue(this , sb,
223: Border.PROPERTY_BORDER_COLOR, s.getBackground()
224: .getColor());
225: } else if (oldValue == Border.Type.NONE) {
226: wr.ai.getStyleValue(this , sb,
227: Border.PROPERTY_BORDER_COLOR, s.getBorder()
228: .getColor());
229: }
230: }
231:
232: wr.ai.getStyleValue(this , sb, propertyName, value);
233: sb.setCharAt(sb.length() - 1, '}');
234: postClientEvent(SET_STYLES, sb);
235: }
236:
237: void destroy() {
238: wr.ai.setPackagePrivateMember("renderer", comp, null);
239: wr.ai.setWebComponentListener(id, null);
240: comp.removePropertyChangeListener(this );
241: wr.removeComponentId(comp);
242: comp = null;
243: wr = null;
244: id = null;
245: ignoredProperties.clear();
246: clientSideProps.clear();
247: initProps.setLength(0);
248:
249: if (remoteFiles != null) {
250: for (String s : remoteFiles) {
251: try {
252: RemoteFileMap.INSTANCE.remove(s);
253: } catch (IOException e) {
254: log.log(Level.WARNING,
255: "Local file no longer exists", e);
256: }
257: }
258: }
259: remoteFiles = null;
260: }
261:
262: void addInitProperty(String name, Object value) {
263: initProps.append(name).append(':');
264: initProps.append(stringValueOf(value));
265: initProps.append(',');
266: }
267:
268: void addClientSideProperty(String name) {
269: this .clientSideProps.put(name, name);
270: }
271:
272: void addClientSideProperty(String name, String clientName) {
273: this .clientSideProps.put(name, clientName);
274: }
275:
276: public void eventSubTypeListenerInit(
277: Class<? extends EventListener> clazz, Set<Object> subTypes) {
278: for (Object subType : subTypes) {
279: eventSubTypeListenerAdded(clazz, subType);
280: }
281: }
282:
283: private Map<Component, RenderStateListener> dragRenderListeners;
284:
285: public void eventSubTypeListenerAdded(
286: Class<? extends EventListener> clazz, Object subType) {
287: if (PropertyChangeListener.class.isAssignableFrom(clazz)) {
288: String prop = clientSideProps.get(subType);
289:
290: if (prop != null) {
291: if (!prop.equals(subType)) {
292: String count = clientSideProps.get(prop);
293:
294: if (count == null) {
295: clientSideProps.put(prop, "1");
296: postClientEvent(REGISTER_EVENT_NOTIFIER,
297: "propertyChange", prop);
298: } else {
299: clientSideProps.put(prop, String
300: .valueOf(Integer.parseInt(count) + 1));
301: }
302: } else {
303: postClientEvent(REGISTER_EVENT_NOTIFIER,
304: "propertyChange", prop);
305: }
306: }
307: } else if (ActionListener.class.isAssignableFrom(clazz)) {
308: postClientEvent(REGISTER_EVENT_NOTIFIER, "action", subType);
309: } else if (KeyPressListener.class.isAssignableFrom(clazz)) {
310: postClientEvent(REGISTER_EVENT_NOTIFIER, "keyPress",
311: subType);
312: } else if (DropListener.class.isAssignableFrom(clazz)) {
313: final Component dragComponent = (Component) subType;
314:
315: if (dragRenderListeners == null)
316: dragRenderListeners = new HashMap<Component, RenderStateListener>();
317:
318: final RenderStateListener dragRenderListener = new RenderStateListener() {
319: public void renderStateChange(RenderStateEvent ev) {
320:
321: if (wr == null) {
322: if (dragRenderListeners != null
323: && dragRenderListeners
324: .containsValue(this )) {
325: ((WebApplication) WebApplication.current())
326: .removeRenderStateListener(comp,
327: this );
328: dragRenderListeners.remove(this );
329: if (dragRenderListeners.size() == 0)
330: dragRenderListeners = null;
331: }
332: } else {
333: wr.ai.clientSideMethodCall(wr.ai
334: .getComponentId(dragComponent),
335: "addDragTarget", id);
336: }
337: }
338: };
339:
340: dragRenderListeners.put(dragComponent, dragRenderListener);
341: wr.ai.addRenderStateListener(dragComponent,
342: dragRenderListener);
343: }
344: }
345:
346: public void eventSubTypeListenerRemoved(
347: Class<? extends EventListener> clazz, Object subType) {
348: if (PropertyChangeListener.class.isAssignableFrom(clazz)) {
349: String prop = clientSideProps.get(subType);
350:
351: if (prop != null) {
352: if (!prop.equals(subType)) {
353: int cnt = Integer.parseInt(clientSideProps
354: .get(prop));
355:
356: if (cnt == 1) {
357: clientSideProps.remove(prop);
358: postClientEvent(UNREGISTER_EVENT_NOTIFIER,
359: "propertyChange", prop);
360: } else {
361: clientSideProps.put(prop, String
362: .valueOf(cnt - 1));
363: }
364: } else {
365: postClientEvent(UNREGISTER_EVENT_NOTIFIER,
366: "propertyChange", prop);
367: }
368: }
369: } else if (ActionListener.class.isAssignableFrom(clazz)) {
370: postClientEvent(UNREGISTER_EVENT_NOTIFIER, "action",
371: subType);
372: } else if (KeyPressListener.class.isAssignableFrom(clazz)) {
373: postClientEvent(UNREGISTER_EVENT_NOTIFIER, "keyPress",
374: subType);
375: } else if (DropListener.class.isAssignableFrom(clazz)) {
376: Integer dragComponentId = wr.ai
377: .getComponentId((Component) subType);
378: if (dragComponentId != null)
379: wr.ai.clientSideMethodCall(dragComponentId,
380: "removeDragTarget", id);
381: if (dragRenderListeners != null
382: && dragRenderListeners.get(subType) != null)
383: wr.ai.removeRenderStateListener((Component) subType,
384: dragRenderListeners.get(subType));
385: }
386: }
387:
388: public int getInt(String value) {
389: try {
390: return Integer.parseInt(value);
391: } catch (NumberFormatException e) {
392: return 0;
393: }
394: }
395:
396: public void componentChange(WebComponentEvent event) {
397: String name = event.getName();
398:
399: if (name.equals(Component.ACTION_CLICK)
400: || name.equals(Component.ACTION_DOUBLE_CLICK)) {
401: String actionIgnoreProperty;
402: String value = (String) event.getValue();
403: String[] vals = value.split(",", -1);
404: int x = getInt(vals[0]);
405: int y = getInt(vals[1]);
406: int srcX = x;
407: int srcY = y;
408:
409: if (vals.length == 5) {
410: srcX = getInt(vals[2]);
411: srcY = getInt(vals[3]);
412: value = vals[4];
413: } else {
414: value = vals[2];
415: }
416:
417: if (this .comp instanceof DateBox) {
418: actionIgnoreProperty = DateBox.PROPERTY_SELECTED_DATE;
419: } else if (this .comp instanceof GridBox) {
420: actionIgnoreProperty = GridBox.Row.PROPERTY_ROW_SELECTED;
421: } else if (comp instanceof Tree) {
422: actionIgnoreProperty = Tree.Item.PROPERTY_ITEM_SELECTED;
423: } else if (comp instanceof Container) {
424: actionIgnoreProperty = null;
425: value = "";
426: } else {
427: actionIgnoreProperty = null;
428: }
429:
430: if (actionIgnoreProperty != null)
431: setPropertyChangeIgnored(actionIgnoreProperty, true);
432: comp.fireAction(new ActionEvent(name, comp, getEventObject(
433: comp, value), x, y, srcX, srcY));
434: if (actionIgnoreProperty != null)
435: setPropertyChangeIgnored(actionIgnoreProperty, false);
436: } else if (event.getName().equals(CLIENT_EVENT_DROP)) {
437: String[] parts = ((String) event.getValue()).split(",", -1);
438: Component dragComponent = (Component) wr.ai
439: .getComponentFromId(Integer.parseInt(parts[1]));
440: int dragComponentX = getInt(parts[3]);
441: int dragComponentY = getInt(parts[4]);
442: int sourceComponentX = getInt(parts[5]);
443: int sourceComponentY = getInt(parts[6]);
444: comp.fireDrop(new DropEvent(comp, getEventObject(comp,
445: parts[0]), sourceComponentX, sourceComponentY,
446: sourceComponentX, sourceComponentY, dragComponent,
447: getEventObject(dragComponent, parts[2]),
448: dragComponentX, dragComponentY, dragComponentX,
449: dragComponentY));
450: } else if (name.equals("size")) {
451: this .setPropertyChangeIgnored(Component.PROPERTY_WIDTH,
452: true);
453: this .setPropertyChangeIgnored(Component.PROPERTY_HEIGHT,
454: true);
455: String[] args = ((String) event.getValue()).split(",");
456: comp.setSize(Integer.valueOf(args[0]), Integer
457: .valueOf(args[1]));
458: this .setPropertyChangeIgnored(Component.PROPERTY_WIDTH,
459: false);
460: this .setPropertyChangeIgnored(Component.PROPERTY_HEIGHT,
461: false);
462: } else if (name.equals("position")) {
463: this .setPropertyChangeIgnored(Component.PROPERTY_X, true);
464: this .setPropertyChangeIgnored(Component.PROPERTY_Y, true);
465: String[] args = ((String) event.getValue()).split(",");
466: comp.setPosition(Integer.valueOf(args[0]), Integer
467: .valueOf(args[1]));
468: this .setPropertyChangeIgnored(Component.PROPERTY_X, false);
469: this .setPropertyChangeIgnored(Component.PROPERTY_Y, false);
470: } else if (name.equals("bounds")) {
471: this .setPropertyChangeIgnored(Component.PROPERTY_X, true);
472: this .setPropertyChangeIgnored(Component.PROPERTY_Y, true);
473: this .setPropertyChangeIgnored(Component.PROPERTY_WIDTH,
474: true);
475: this .setPropertyChangeIgnored(Component.PROPERTY_HEIGHT,
476: true);
477: String[] args = ((String) event.getValue()).split(",");
478: comp.setBounds(Integer.valueOf(args[0]), Integer
479: .valueOf(args[1]), Integer.valueOf(args[2]),
480: Integer.valueOf(args[3]));
481: this .setPropertyChangeIgnored(Component.PROPERTY_WIDTH,
482: false);
483: this .setPropertyChangeIgnored(Component.PROPERTY_HEIGHT,
484: false);
485: this .setPropertyChangeIgnored(Component.PROPERTY_X, false);
486: this .setPropertyChangeIgnored(Component.PROPERTY_Y, false);
487: } else if (name.equals(Component.PROPERTY_VISIBLE)) {
488: this .setPropertyChangeIgnored(Component.PROPERTY_VISIBLE,
489: true);
490: comp.setVisible(((String) event.getValue()).toLowerCase()
491: .equals("true"));
492: this .setPropertyChangeIgnored(Component.PROPERTY_VISIBLE,
493: false);
494: } else if (name.equals(Component.PROPERTY_FOCUS)) {
495: setPropertyChangeIgnored(Component.PROPERTY_FOCUS, true);
496:
497: ContainerRenderer cr = this .cr;
498:
499: while (cr != null) {
500: cr.setPropertyChangeIgnored(Component.PROPERTY_FOCUS,
501: true);
502: cr = cr.cr;
503: }
504:
505: comp.setFocus(Boolean.valueOf((String) event.getValue())
506: .booleanValue());
507:
508: cr = this .cr;
509:
510: while (cr != null) {
511: cr.setPropertyChangeIgnored(Component.PROPERTY_FOCUS,
512: false);
513: cr = cr.cr;
514: }
515:
516: setPropertyChangeIgnored(Component.PROPERTY_FOCUS, false);
517: } else if (name.equals("keyPress")) {
518: comp.fireKeyPress(new KeyPressEvent((String) event
519: .getValue(), comp));
520: }
521: }
522:
523: void setPropertyWithEffect(String propertyName, Object newValue,
524: Object oldValue, String standardMethod, String styleProp) {
525: Effect.Motion type;
526: FX fx = comp.getStyle().getFX();
527:
528: if (styleProp.equals(FX.PROPERTY_FX_VISIBLE_CHANGE)) {
529: type = fx.getVisibleChange();
530: } else if (styleProp.equals(FX.PROPERTY_FX_OPACITY_CHANGE)) {
531: type = fx.getOpacityChange();
532: } else if (styleProp.equals(FX.PROPERTY_FX_POSITION_CHANGE)) {
533: type = fx.getPositionChange();
534: } else if (styleProp.equals(FX.PROPERTY_FX_SIZE_CHANGE)) {
535: type = fx.getSizeChange();
536: } else {
537: type = fx.getColorChange();
538: }
539:
540: Effect.Motion NONE = Effect.Motion.NONE;
541:
542: if (type == NONE || (type.getDuration() == NONE.getDuration())
543: && type.getFrames() == NONE.getFrames()) {
544: if (newValue instanceof Color) {
545: Color color = (Color) oldValue;
546: if (color.isSystemColor())
547: color = wr.ai.getSystemColor(color.toString());
548: oldValue = color.toHexString();
549:
550: color = (Color) newValue;
551: if (color.isSystemColor())
552: color = wr.ai.getSystemColor(color.toString());
553: newValue = color.toHexString();
554: }
555:
556: postClientEvent(standardMethod, newValue);
557: } else {
558: int time = type.getDuration();
559: StringBuffer seq = new StringBuffer();
560: Effect.Transition trans = type.getTransition();
561: int steps = (int) Math.floor(time / type.getFrames() + .5) - 1;
562: double step = Math.floor(1.0 / steps * 100000) / 100000; //percent of each step;
563:
564: if (styleProp.equals(FX.PROPERTY_FX_COLOR_CHANGE)) {
565: Color prev = (Color) oldValue;
566: if (prev.isSystemColor())
567: prev = wr.ai.getSystemColor(prev.toString());
568: Color next = (Color) newValue;
569: if (next.isSystemColor())
570: next = wr.ai.getSystemColor(next.toString());
571:
572: if (prev == null || next == null) {
573: postClientEvent(standardMethod, newValue);
574: } else {
575: int rChange = next.getRed() - prev.getRed();
576: if (rChange < 0)
577: rChange = ~rChange + 1;
578: int gChange = next.getGreen() - prev.getGreen();
579: if (gChange < 0)
580: gChange = ~gChange + 1;
581: int bChange = next.getBlue() - prev.getBlue();
582: if (bChange < 0)
583: bChange = ~bChange + 1;
584: seq.append('[');
585:
586: for (int i = 1; i <= steps; i++) {
587: int rSize = (int) Math.floor(trans.apply(step
588: * i)
589: * rChange);
590: rSize = next.getRed() < prev.getRed() ? prev
591: .getRed()
592: - rSize : prev.getRed() + rSize;
593: int gSize = (int) Math.floor(trans.apply(step
594: * i)
595: * gChange);
596: gSize = next.getGreen() < prev.getGreen() ? prev
597: .getGreen()
598: - gSize
599: : prev.getGreen() + gSize;
600: int bSize = (int) Math.floor(trans.apply(step
601: * i)
602: * bChange);
603: bSize = next.getBlue() < prev.getBlue() ? prev
604: .getBlue()
605: - bSize : prev.getBlue() + bSize;
606: seq.append("\"rgb(").append(rSize).append(',')
607: .append(gSize).append(',')
608: .append(bSize).append(")\"")
609: .append(',');
610: }
611:
612: seq.append('"').append(next.toHexString()).append(
613: '"').append(']');
614: wr.ai.clientSideMethodCall(id,
615: SET_PROPERTY_WITH_EFFECT, propertyName,
616: time, seq);
617: }
618: } else {
619: int prev, next;
620:
621: if (styleProp.equals(FX.PROPERTY_FX_VISIBLE_CHANGE)) {
622: int opacity = comp.getStyle().getOpacity();
623: prev = ((Boolean) oldValue).booleanValue() ? opacity
624: : 0;
625: next = ((Boolean) newValue).booleanValue() ? opacity
626: : 0;
627: } else {
628: prev = (Integer) oldValue;
629: next = (Integer) newValue;
630: }
631:
632: int change = next - prev;
633: if (change < 0)
634: change = ~change + 1;
635: seq.append('[');
636:
637: for (int i = 1; i <= steps; i++) {
638: int size = (int) Math.floor(trans.apply(step * i)
639: * change);
640: seq.append(next < prev ? prev - size : prev + size)
641: .append(',');
642: }
643:
644: seq.append(next).append(']');
645: wr.ai.clientSideMethodCall(id,
646: SET_PROPERTY_WITH_EFFECT, propertyName, time,
647: seq, newValue);
648: }
649: }
650: }
651:
652: public void propertyChange(PropertyChangeEvent pce) {
653: String name = pce.getPropertyName();
654: if (isPropertyChangeIgnored(name))
655: return;
656:
657: if (name.equals(Component.PROPERTY_ENABLED)) {
658: postClientEvent(SET_ENABLED, pce.getNewValue());
659: } else if (name.equals(Component.PROPERTY_FOCUS)) {
660: Object newValue = pce.getNewValue();
661: if (((Boolean) newValue).booleanValue())
662: postClientEvent(SET_FOCUS, newValue);
663: } else if (name.equals(Component.PROPERTY_FOCUS_CAPABLE)) {
664: postClientEvent(SET_FOCUS_CAPABLE, pce.getNewValue());
665: } else if (name.equals(Background.PROPERTY_BACKGROUND_COLOR)
666: || name.equals(Border.PROPERTY_BORDER_COLOR)
667: || name.equals(Font.PROPERTY_FONT_COLOR)) {
668: String setMethod = "set"
669: + Character.toUpperCase(name.charAt(0))
670: + name.substring(1);
671: setPropertyWithEffect(name, pce.getNewValue(), pce
672: .getOldValue(), setMethod,
673: FX.PROPERTY_FX_COLOR_CHANGE);
674: } else if (name.equals(Style.PROPERTY_OPACITY)) {
675: setPropertyWithEffect(name, pce.getNewValue(), pce
676: .getOldValue(), SET_OPACITY,
677: FX.PROPERTY_FX_OPACITY_CHANGE);
678: } else if (name.equals(Component.PROPERTY_X)) {
679: setPropertyWithEffect(name, pce.getNewValue(), pce
680: .getOldValue(), SET_X,
681: FX.PROPERTY_FX_POSITION_CHANGE);
682: } else if (name.equals(Component.PROPERTY_Y)) {
683: setPropertyWithEffect(name, pce.getNewValue(), pce
684: .getOldValue(), SET_Y,
685: FX.PROPERTY_FX_POSITION_CHANGE);
686: } else if (name.equals(Component.PROPERTY_WIDTH)) {
687: setPropertyWithEffect(name, pce.getNewValue(), pce
688: .getOldValue(), SET_WIDTH,
689: FX.PROPERTY_FX_SIZE_CHANGE);
690: } else if (name.equals(Component.PROPERTY_HEIGHT)) {
691: setPropertyWithEffect(name, pce.getNewValue(), pce
692: .getOldValue(), SET_HEIGHT,
693: FX.PROPERTY_FX_SIZE_CHANGE);
694: } else if (name.equals(Component.PROPERTY_VISIBLE)) {
695: setPropertyWithEffect(name, pce.getNewValue(), pce
696: .getOldValue(), SET_VISIBLE,
697: FX.PROPERTY_FX_VISIBLE_CHANGE);
698: } else {
699: Object source = pce.getSource();
700: if (source instanceof Background || source instanceof Font
701: || source instanceof Border)
702: setStyle(pce.getPropertyName(), pce.getOldValue());
703: }
704: }
705:
706: final void postClientEvent(String methodName, Object... args) {
707: wr.ai.clientSideMethodCall(id, methodName, args);
708: }
709:
710: final void setPropertyChangeIgnored(String name, boolean ignore) {
711: if (ignore) {
712: ignoredProperties.put(name, NO_VALUE);
713: } else {
714: ignoredProperties.remove(name);
715: }
716: }
717:
718: final boolean isPropertyChangeIgnored(String name, Object value) {
719: if (ignoredProperties.containsKey(name)) {
720: if (value == NO_VALUE) {
721: return true;
722: } else {
723: Object ignoredValue = ignoredProperties.get(name);
724: return ignoredValue == value
725: || (ignoredValue != null && ignoredValue
726: .equals(value));
727: }
728: } else {
729: return false;
730: }
731: }
732:
733: final boolean isPropertyChangeIgnored(String name) {
734: return isPropertyChangeIgnored(name, NO_VALUE);
735: }
736:
737: final boolean resetPropertyChangeIgnored(String name, Object value) {
738: boolean ret = isPropertyChangeIgnored(name, value);
739: if (ret)
740: ignoredProperties.remove(name);
741: return ret;
742: }
743:
744: final boolean resetPropertyChangeIgnored(String name) {
745: return resetPropertyChangeIgnored(name, NO_VALUE);
746: }
747:
748: static String stringValueOf(Object o) {
749: String ret;
750:
751: if (o == null) {
752: ret = "null";
753: } else if (o instanceof Integer) {
754: ret = String.valueOf(((Integer) o).intValue());
755: } else if (o instanceof Number) {
756: ret = String.valueOf(((Number) o).doubleValue());
757: } else if (o instanceof Boolean) {
758: ret = String.valueOf(((Boolean) o).booleanValue());
759: } else if (o instanceof StringBuilder) {
760: ret = o.toString();
761: } else if (o instanceof Color) {
762: ret = "\"" + ((Color) o).toHexString() + "\"";
763: } else {
764: ret = '"' + ComponentRenderer.getEscapedText(o.toString(),
765: false) + '"';
766: }
767:
768: return ret;
769: }
770:
771: static String getEscapedText(String s, boolean CRLFToSpace) {
772: s = s.replace('\0', ' ');
773: s = REGEX_DOUBLE_SLASH.matcher(s).replaceAll("\\\\\\\\");
774: s = REGEX_DOUBLE_QUOTE.matcher(s).replaceAll("\\\\\"");
775: s = REGEX_CRLF.matcher(s).replaceAll(
776: CRLFToSpace ? " " : "\\\\r\\\\n");
777: return s;
778: }
779:
780: Object parseRichText(String value) {
781: if (value == null)
782: return "";
783: if (this instanceof EditorComponentRenderer)
784: return value;
785: if (richTextParser == null)
786: richTextParser = new RichTextParser(this );
787: return richTextParser.parse(value);
788: }
789:
790: static Object getEventObject(Component comp, String data) {
791: Object o;
792:
793: if (comp instanceof GridBox) {
794: String[] values = data.split("@");
795: o = new GridBox.Range((GridBox) comp, Integer
796: .parseInt(values[0]), Integer.parseInt(values[1]));
797: } else if (comp instanceof Tree || comp instanceof Menu) {
798: o = TreeRenderer.fullIndexItem((HierarchyComponent) comp,
799: data);
800: } else if (comp instanceof DateBox) {
801: try {
802: o = DateBoxRenderer.dateBoxFormat.parse(data);
803: } catch (Exception e) {
804: throw new RuntimeException(e);
805: }
806: } else {
807: o = null;
808: }
809:
810: return o;
811: }
812:
813: final String getQualifiedURL(String location) {
814: if (location.trim().length() > 0) {
815: URI uri;
816: WindowRenderer wr = this instanceof WindowRenderer ? (WindowRenderer) this
817: : this .wr;
818:
819: if (location.startsWith("file")
820: || location.startsWith("class")
821: || wr.ai.getRelativeFile(location).exists()) {
822: if (!location.startsWith("class")) {
823: if (location.startsWith("file:///"))
824: location = location.substring(7);
825: location = wr.ai.getRelativeFile(location)
826: .getAbsolutePath();
827: }
828: if (remoteFiles == null)
829: remoteFiles = new ArrayList<String>(5);
830: remoteFiles.add(location);
831: location = "%SYSROOT%"
832: + RemoteFileMap.INSTANCE.add(location);
833: } else {
834: try {
835: location = new URL(location).toString();
836: } catch (MalformedURLException e) {
837: location = "";
838: }
839: }
840: } else {
841: location = "";
842: }
843:
844: return location;
845: }
846:
847: void removeFileFromMap(String location) {
848:
849: location = location.replaceAll("%SYSROOT%(.*)", "$1");
850:
851: try {
852: RemoteFileMap.INSTANCE.remove(location);
853: } catch (IOException e) {
854: log.log(Level.WARNING, "Local file no longer exists", e);
855: }
856:
857: remoteFiles.remove(location);
858: }
859: }
|