/******************************************************************************* | |
* Copyright (c) 2006, 2010 Soyatec (http://www.soyatec.com) and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License v1.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/epl-v10.html | |
* | |
* Contributors: | |
* Soyatec - initial API and implementation | |
*******************************************************************************/ | |
package org.eclipse.xwt.javabean; | |
import java.io.File; | |
import java.lang.reflect.Array; | |
import java.lang.reflect.Constructor; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.Modifier; | |
import java.net.MalformedURLException; | |
import java.net.URL; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.Collections; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Set; | |
import java.util.StringTokenizer; | |
import org.eclipse.core.databinding.conversion.IConverter; | |
import org.eclipse.jface.viewers.TableViewerColumn; | |
import org.eclipse.swt.SWT; | |
import org.eclipse.swt.custom.ControlEditor; | |
import org.eclipse.swt.custom.TableEditor; | |
import org.eclipse.swt.layout.FillLayout; | |
import org.eclipse.swt.widgets.Composite; | |
import org.eclipse.swt.widgets.Control; | |
import org.eclipse.swt.widgets.Display; | |
import org.eclipse.swt.widgets.Event; | |
import org.eclipse.swt.widgets.Listener; | |
import org.eclipse.swt.widgets.Shell; | |
import org.eclipse.swt.widgets.Table; | |
import org.eclipse.swt.widgets.TableColumn; | |
import org.eclipse.swt.widgets.TableItem; | |
import org.eclipse.swt.widgets.Widget; | |
import org.eclipse.xwt.ICLRFactory; | |
import org.eclipse.xwt.IConstants; | |
import org.eclipse.xwt.IDataProvider; | |
import org.eclipse.xwt.IEventHandler; | |
import org.eclipse.xwt.IEventInvoker; | |
import org.eclipse.xwt.IIndexedElement; | |
import org.eclipse.xwt.ILoadingContext; | |
import org.eclipse.xwt.INamespaceHandler; | |
import org.eclipse.xwt.IStyle; | |
import org.eclipse.xwt.IXWTLoader; | |
import org.eclipse.xwt.ResourceDictionary; | |
import org.eclipse.xwt.Tracking; | |
import org.eclipse.xwt.XWT; | |
import org.eclipse.xwt.XWTException; | |
import org.eclipse.xwt.XWTLoader; | |
import org.eclipse.xwt.XWTMaps; | |
import org.eclipse.xwt.annotation.UI; | |
import org.eclipse.xwt.callback.ICreatedCallback; | |
import org.eclipse.xwt.callback.ILoadedCallback; | |
import org.eclipse.xwt.core.IBinding; | |
import org.eclipse.xwt.core.IDynamicBinding; | |
import org.eclipse.xwt.core.IDynamicValueBinding; | |
import org.eclipse.xwt.core.IRenderingContext; | |
import org.eclipse.xwt.core.IVisualElementLoader; | |
import org.eclipse.xwt.core.Setter; | |
import org.eclipse.xwt.core.Style; | |
import org.eclipse.xwt.core.ValidationStatus; | |
import org.eclipse.xwt.input.ICommand; | |
import org.eclipse.xwt.internal.core.Binding; | |
import org.eclipse.xwt.internal.core.Core; | |
import org.eclipse.xwt.internal.core.DataBindingTrack; | |
import org.eclipse.xwt.internal.core.IEventController; | |
import org.eclipse.xwt.internal.core.ScopeKeeper; | |
import org.eclipse.xwt.internal.utils.ClassLoaderUtil; | |
import org.eclipse.xwt.internal.utils.DocumentObjectSorter; | |
import org.eclipse.xwt.internal.utils.LoggerManager; | |
import org.eclipse.xwt.internal.utils.NamespaceHelper; | |
import org.eclipse.xwt.internal.utils.ObjectUtil; | |
import org.eclipse.xwt.internal.utils.TableEditorHelper; | |
import org.eclipse.xwt.internal.utils.UserData; | |
import org.eclipse.xwt.internal.xml.Attribute; | |
import org.eclipse.xwt.internal.xml.DocumentObject; | |
import org.eclipse.xwt.internal.xml.Element; | |
import org.eclipse.xwt.javabean.metadata.properties.PropertiesConstants; | |
import org.eclipse.xwt.javabean.metadata.properties.TableItemProperty; | |
import org.eclipse.xwt.jface.JFacesHelper; | |
import org.eclipse.xwt.metadata.IEvent; | |
import org.eclipse.xwt.metadata.IMetaclass; | |
import org.eclipse.xwt.metadata.IProperty; | |
import org.eclipse.xwt.metadata.IValueLoading; | |
import org.eclipse.xwt.utils.PathHelper; | |
/** | |
* @author jliu (jin.liu@soyatec.com) | |
*/ | |
public class ResourceLoader implements IVisualElementLoader { | |
static Map<String, Object> EMPTY_MAP = Collections.EMPTY_MAP; | |
static private String VALIDATION_STATUS_CONSTANT = "status"; | |
static final String RESOURCE_LOADER_PROPERTY = "XWT.ResourceLoader"; | |
private static final String COLUMN = "Column"; | |
private Map<String, Object> options; | |
private Collection<Binding> bindings; | |
private Collection<ValidationStatus> status; | |
public Collection<Binding> getBindings() { | |
return bindings; | |
} | |
protected ResourceLoader parentLoader; | |
protected IRenderingContext context; | |
protected IXWTLoader loader; | |
protected Object scopedObject; | |
protected ScopeKeeper nameScoped; | |
protected LoadingData loadData = new LoadingData(); | |
protected Event loadedEvent = new Event(); | |
class LoadingData { | |
protected LoadingData parent; | |
protected Object clr; | |
protected Collection<IStyle> styles = Collections.EMPTY_LIST; | |
private Object currentWidget = null; | |
private Object host = null; | |
private Object dataContext = null; | |
public Object getDataContext() { | |
return dataContext; | |
} | |
public void setDataContext(Object dataContext) { | |
this.dataContext = dataContext; | |
} | |
public Object getHost() { | |
return host; | |
} | |
public Object getCurrentWidget() { | |
return currentWidget; | |
} | |
public Object findElement(Class<?> type) { | |
if (type.isInstance(currentWidget)) { | |
return currentWidget; | |
} | |
if (parent != null) { | |
return parent.findElement(type); | |
} | |
return null; | |
} | |
public void setCurrentWidget(Object currentWidget) { | |
this.currentWidget = currentWidget; | |
} | |
public LoadingData getParent() { | |
return parent; | |
} | |
public LoadingData() { | |
} | |
public LoadingData(LoadingData loadingData, Object host) { | |
this.parent = loadingData; | |
this.styles = loadingData.styles; | |
this.clr = loadingData.clr; | |
this.currentWidget = loadingData.currentWidget; | |
this.dataContext = loadingData.dataContext; | |
this.host = host; | |
} | |
public Collection<IStyle> getStyles() { | |
return styles; | |
} | |
public void setStyles(Collection<IStyle> styles) { | |
this.styles = styles; | |
} | |
public Object getClr() { | |
return clr; | |
} | |
public void setClr(Object clr) { | |
this.clr = clr; | |
} | |
public void inject(Object targetObject, String name) { | |
doInject(targetObject, name, null); | |
} | |
protected void doInject(Object targetObject, String name, | |
Object previousClr) { | |
Class<?> filedType = targetObject.getClass(); | |
if (clr != null && (previousClr != clr || previousClr == null)) { | |
for (Field field : clr.getClass().getDeclaredFields()) { | |
UI annotation = field.getAnnotation(UI.class); | |
if (annotation != null) { | |
if (!field.getType().isAssignableFrom(filedType)) { | |
continue; | |
} | |
String annotationValue = annotation.value(); | |
if (annotationValue == null | |
|| annotationValue.length() == 0) { | |
if (field.getName().equals(name)) { | |
field.setAccessible(true); | |
try { | |
field.set(clr, targetObject); | |
return; | |
} catch (Exception e) { | |
} | |
} | |
} else if (annotationValue.equals(name)) { | |
field.setAccessible(true); | |
try { | |
field.set(clr, targetObject); | |
break; | |
} catch (Exception e) { | |
} | |
} | |
} | |
} | |
} | |
if (parent != null) { | |
parent.doInject(targetObject, name, clr); | |
} | |
} | |
public void updateEvent(IRenderingContext context, Widget control, | |
IEvent event, String handler) { | |
IEventController eventController = UserData | |
.updateEventController(control); | |
Method method = null; | |
Object clrObject = null; | |
LoadingData current = this; | |
ResourceLoader currentParentLoader = parentLoader; | |
while (current != null) { | |
Object receiver = current.getClr(); | |
if (receiver instanceof IEventHandler) { | |
IEventHandler eventManager = (IEventHandler) receiver; | |
IEventInvoker eventInvoker = eventManager.getEventInvoker( | |
handler, control.getClass(), Event.class); | |
if (eventInvoker != null) { | |
eventController.setEvent(event, control, control, | |
eventInvoker); | |
} | |
} else if (receiver != null) { | |
Class<?> clazz = receiver.getClass(); | |
method = ObjectUtil.findMethod(clazz, handler, | |
control.getClass(), Event.class); | |
if (method == null) { | |
method = ObjectUtil.findMethod(clazz, handler, | |
Event.class); | |
} | |
if (method == null) { | |
// Load again. | |
clazz = ClassLoaderUtil.loadClass( | |
context.getLoadingContext(), clazz.getName()); | |
method = ObjectUtil.findMethod(clazz, handler, | |
Event.class); | |
} | |
if (method == null) { | |
method = ObjectUtil.findMethod(clazz, handler); | |
} | |
if (method != null) { | |
clrObject = receiver; | |
eventController.setEvent(event, control, clrObject, | |
control, method); | |
break; | |
} | |
} | |
current = current.getParent(); | |
if (current == null && currentParentLoader != null) { | |
current = currentParentLoader.loadData; | |
currentParentLoader = currentParentLoader.parentLoader; | |
} | |
} | |
if (method == null) { | |
LoggerManager.log(new XWTException("Event handler \"" + handler | |
+ "\" is not found.")); | |
} | |
} | |
public void end() { | |
if (parent == null || clr != parent.getClr()) { | |
Method method = ObjectUtil.findDeclaredMethod(clr.getClass(), | |
"initializeComponent"); | |
if (method == null) { | |
method = ObjectUtil.findDeclaredMethod(clr.getClass(), | |
"InitializeComponent"); | |
} | |
if (method != null) { | |
try { | |
method.setAccessible(true); | |
method.invoke(clr); | |
} catch (Exception e) { | |
LoggerManager.log(e); | |
} | |
} | |
} | |
} | |
public void addStyle(IStyle style) { | |
if (styles == Collections.EMPTY_LIST) { | |
styles = new ArrayList<IStyle>(); | |
} | |
styles.add(style); | |
} | |
} | |
private DataBindingTrack dataBindingTrack; | |
/** | |
* @param context | |
*/ | |
public ResourceLoader(IRenderingContext context, IXWTLoader loader) { | |
this.context = context; | |
this.loader = loader; | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.xwt.IVisualElementLoader#createUIElement(org.eclipse. | |
* e4.xwt.Element, org.eclipse.xwt.ILoadData, | |
* org.eclipse.xwt.IResourceDictionary) | |
*/ | |
public Object createUIElement(Element element, Map<String, Object> options) { | |
try { | |
this.options = options; | |
Object container = options.get(IXWTLoader.CONTAINER_PROPERTY); | |
Widget parent = UserData.getWidget(container); | |
if (!loader.getTrackings().isEmpty()) { | |
dataBindingTrack = new DataBindingTrack(); | |
} | |
parentLoader = (ResourceLoader) options | |
.get(RESOURCE_LOADER_PROPERTY); | |
options.remove(RESOURCE_LOADER_PROPERTY); | |
ResourceDictionary resourceDictionary = (ResourceDictionary) options | |
.get(IXWTLoader.RESOURCE_DICTIONARY_PROPERTY); | |
if (resourceDictionary != null) { | |
Object styles = resourceDictionary.get(Core.DEFAULT_STYLES_KEY); | |
if (styles != null) { | |
loadData.setStyles((Collection<IStyle>) styles); | |
resourceDictionary.remove(Core.DEFAULT_STYLES_KEY); | |
} | |
} | |
if (!options.containsKey(IXWTLoader.CLASS_FACTORY_PROPERTY)) { | |
try { | |
options.put(IXWTLoader.CLASS_FACTORY_PROPERTY, | |
loader.getCLRFactory()); | |
} catch (UnsupportedOperationException e) { | |
if (options.isEmpty()) { | |
options = new HashMap<String, Object>(); | |
options.put(IXWTLoader.CLASS_FACTORY_PROPERTY, | |
loader.getCLRFactory()); | |
} else { | |
throw e; | |
} | |
} | |
} | |
Object control = doCreate(parent, element, null, options); | |
// get databinding messages and print into console view | |
if (dataBindingTrack != null) { | |
String dataBindingMessage = dataBindingTrack | |
.getDataBindMessage();// getDataBindMessage(); | |
org.eclipse.xwt.ILogger log = loader.getLogger(); | |
log.addMessage(dataBindingMessage, Tracking.DATABINDING); | |
log.printInfo(dataBindingMessage, Tracking.DATABINDING, | |
loader.getTrackings()); | |
} | |
if (control instanceof Composite) { | |
((Composite) control).layout(); | |
} | |
ILoadedCallback loadedAction = (ILoadedCallback) options | |
.get(IXWTLoader.LOADED_CALLBACK); | |
if (loadedAction != null) { | |
loadedAction.onLoaded(control); | |
} | |
return control; | |
} catch (Exception e) { | |
if (e instanceof RuntimeException) { | |
throw ((RuntimeException) e); | |
} | |
throw new XWTException(e); | |
} | |
} | |
protected Object doCreate(Object parent, Element element, | |
Class<?> constraintType, Map<String, Object> options) | |
throws Exception { | |
int styles = -1; | |
if (options.containsKey(IXWTLoader.INIT_STYLE_PROPERTY)) { | |
styles = (Integer) options.get(IXWTLoader.INIT_STYLE_PROPERTY); | |
} | |
ResourceDictionary dico = (ResourceDictionary) options | |
.get(IXWTLoader.RESOURCE_DICTIONARY_PROPERTY); | |
Object dataContext = options.get(IXWTLoader.DATACONTEXT_PROPERTY); | |
Object bindingContext = options | |
.get(IXWTLoader.BINDING_CONTEXT_PROPERTY); | |
String name = element.getName(); | |
String namespace = element.getNamespace(); | |
if (IConstants.XWT_X_NAMESPACE.equalsIgnoreCase(namespace)) { | |
if (IConstants.XAML_X_NULL.equalsIgnoreCase(name)) { | |
return null; | |
} | |
if (IConstants.XAML_X_TYPE.equalsIgnoreCase(name) | |
&& constraintType != null | |
&& constraintType instanceof Class<?>) { | |
DocumentObject[] children = element.getChildren(); | |
if (children != null && children.length > 0) { | |
if (children[0] instanceof Element) { | |
Element type = (Element) children[0]; | |
IMetaclass metaclass = loader.getMetaclass( | |
type.getName(), type.getNamespace()); | |
if (metaclass != null) { | |
return metaclass.getType(); | |
} | |
} | |
} else { | |
String content = element.getContent(); | |
return loader.convertFrom(Class.class, content); | |
} | |
} | |
return null; | |
} | |
IMetaclass metaclass = loader.getMetaclass(name, namespace); | |
if (constraintType != null | |
&& !(IBinding.class.isAssignableFrom(metaclass.getType())) | |
&& (!constraintType.isAssignableFrom(metaclass.getType()))) { | |
if (!constraintType.isArray() | |
|| !constraintType.getComponentType().isAssignableFrom( | |
metaclass.getType())) { | |
IConverter converter = XWT.findConvertor(metaclass.getType(), | |
constraintType); | |
if (converter == null) { | |
return null; | |
} | |
} | |
} | |
Object targetObject = null; | |
Integer styleValue = getStyleValue(element, styles); | |
if (parent == null || metaclass.getType() == Shell.class) { | |
if (dataBindingTrack != null) { | |
dataBindingTrack.addWidgetElement(element); | |
} | |
Shell shell = null; | |
if ((parent == null && metaclass.getType() != Shell.class) | |
|| styleValue == null || styleValue == -1) { | |
styleValue = SWT.SHELL_TRIM; | |
} | |
Display display = Display.getCurrent(); | |
shell = new Shell(display, styleValue); | |
targetObject = shell; | |
invokeCreatededAction(element, targetObject); | |
loadData.setCurrentWidget(shell); | |
if (metaclass.getType() != Shell.class) { | |
shell.setLayout(new FillLayout()); | |
return doCreate(targetObject, element, constraintType, options); | |
} else { | |
if (bindingContext != null) { | |
setBindingContext(metaclass, targetObject, dico, | |
bindingContext); | |
} | |
if (dataContext != null) { | |
setDataContext(metaclass, targetObject, dico, dataContext); | |
} | |
} | |
pushStack(parent); | |
// for Shell | |
Attribute classAttribute = element.getAttribute( | |
IConstants.XWT_X_NAMESPACE, IConstants.XAML_X_CLASS); | |
if (classAttribute != null) { | |
String className = classAttribute.getContent(); | |
loadShellCLR(className, shell); | |
} else { | |
Attribute classFactoryAttribute = element.getAttribute( | |
IConstants.XWT_X_NAMESPACE, | |
IConstants.XAML_X_CLASS_FACTORY); | |
ICLRFactory clrFactory = (ICLRFactory) options | |
.get(XWTLoader.CLASS_FACTORY_PROPERTY); | |
if (classFactoryAttribute != null) { | |
String content = classFactoryAttribute.getContent(); | |
Object clr = loadFactoryCLR(content, clrFactory); | |
loadData.setClr(clr); | |
UserData.setCLR(shell, clr); | |
} else { | |
if (clrFactory != null) { | |
Object clr = clrFactory.createCLR(null, options); | |
loadData.setClr(clr); | |
UserData.setCLR(shell, clr); | |
} | |
} | |
} | |
} else { | |
pushStack(parent); | |
// | |
// load the content in case of UserControl | |
// | |
Class<?> type = metaclass.getType(); | |
URL file = type.getResource(type.getSimpleName() | |
+ IConstants.XWT_EXTENSION_SUFFIX); | |
if (file != null && nameScoped != null) { | |
if (parent instanceof Composite) { | |
Object childDataContext = getDataContext(element, | |
(Widget) parent); | |
Object childBindingContext = getBindingContext(element, | |
(Widget) parent); | |
if (dataContext != null) { | |
childDataContext = dataContext; | |
} | |
if (bindingContext != null) { | |
childBindingContext = bindingContext; | |
} | |
Map<String, Object> nestedOptions = new HashMap<String, Object>(); | |
nestedOptions.put(IXWTLoader.CONTAINER_PROPERTY, parent); | |
if (styleValue != null) { | |
nestedOptions.put(IXWTLoader.INIT_STYLE_PROPERTY, | |
styleValue); | |
} | |
nestedOptions.put(IXWTLoader.DATACONTEXT_PROPERTY, | |
childDataContext); | |
nestedOptions.put(IXWTLoader.BINDING_CONTEXT_PROPERTY, | |
childBindingContext); | |
nestedOptions.put(RESOURCE_LOADER_PROPERTY, this); | |
nestedOptions.put(IXWTLoader.CLASS_FACTORY_PROPERTY, null); // disable | |
// the | |
// global | |
// setting | |
targetObject = loader.loadWithOptions(file, nestedOptions); | |
if (targetObject == null) { | |
return null; | |
} | |
invokeCreatededAction(element, targetObject); | |
} else | |
throw new XWTException( | |
"Cannot add user control: Parent is not a composite"); | |
} else { | |
Object[] parameters = null; | |
if (TableViewerColumn.class.isAssignableFrom(type)) { | |
int columnIndex = getColumnIndex(element); | |
parameters = (styleValue != null ? new Object[] { parent, | |
styleValue, columnIndex } : new Object[] { parent, | |
SWT.NONE, columnIndex }); | |
} else { | |
parameters = (styleValue != null ? new Object[] { parent, | |
styleValue } : new Object[] { parent }); | |
} | |
// x:Class | |
{ | |
boolean hasClass = false; | |
Attribute classAttribute = element | |
.getAttribute(IConstants.XWT_X_NAMESPACE, | |
IConstants.XAML_X_CLASS); | |
if (classAttribute != null) { | |
String className = classAttribute.getContent(); | |
targetObject = loadCLR(className, parameters, | |
metaclass.getType(), options); | |
hasClass = true; | |
} else { | |
Object clr = options.get(XWTLoader.CLASS_PROPERTY); | |
if (clr != null) { | |
loadData.setClr(clr); | |
hasClass = true; | |
} | |
} | |
if (!hasClass) { | |
Attribute classFactoryAttribute = element.getAttribute( | |
IConstants.XWT_X_NAMESPACE, | |
IConstants.XAML_X_CLASS_FACTORY); | |
ICLRFactory clrFactory = (ICLRFactory) options | |
.get(XWTLoader.CLASS_FACTORY_PROPERTY); | |
if (classFactoryAttribute != null) { | |
Object clr = loadFactoryCLR( | |
classFactoryAttribute.getContent(), | |
clrFactory); | |
if (clr != null) { | |
loadData.setClr(clr); | |
} | |
} else { | |
if (clrFactory != null) { | |
loadData.setClr(clrFactory.createCLR(null, | |
options)); | |
} | |
} | |
} | |
if (targetObject == null) { | |
targetObject = metaclass.newInstance(parameters); | |
invokeCreatededAction(element, targetObject); | |
Widget widget = UserData.getWidget(targetObject); | |
if (widget != null) { | |
Object clr = loadData.getClr(); | |
if (clr != null) { | |
UserData.setCLR(widget, clr); | |
} | |
} | |
} else { | |
metaclass = loader.getMetaclass(targetObject); | |
} | |
} | |
if (targetObject == null) { | |
return null; | |
} | |
} | |
} | |
Widget widget = UserData.getWidget(targetObject); | |
if (widget != null) { | |
loadData.setCurrentWidget(targetObject); | |
} | |
if (scopedObject == null && widget != null) { | |
scopedObject = widget; | |
nameScoped = new ScopeKeeper((parent == null ? null | |
: UserData.findScopeKeeper((Widget) parent)), widget); | |
UserData.bindNameContext((Widget) widget, nameScoped); | |
} | |
// set first data context and resource dictionary | |
setDataContext(metaclass, targetObject, dico, dataContext); | |
if (bindingContext != null) { | |
setBindingContext(metaclass, targetObject, dico, bindingContext); | |
} | |
if (dataBindingTrack != null) { | |
dataBindingTrack.tracking(targetObject, element, dataContext); | |
} | |
// set parent relationship and viewer | |
if (targetObject instanceof Widget) { | |
if (parent != null) { | |
UserData.setParent(targetObject, parent); | |
} | |
} else if (JFacesHelper.isViewer(targetObject)) { | |
UserData.setParent(targetObject, parent); | |
UserData.setViewer(targetObject, targetObject); | |
} else if (targetObject instanceof TableItemProperty.Cell) { | |
((TableItemProperty.Cell) targetObject) | |
.setParent((TableItem) parent); | |
} | |
applyStyles(element, targetObject); | |
for (Map.Entry<String, Object> entry : options.entrySet()) { | |
String key = entry.getKey(); | |
if (IXWTLoader.Utilities.isPropertyName(key)) { | |
continue; | |
} | |
IProperty property = metaclass.findProperty(key); | |
if (property == null) { | |
throw new XWTException("Property " + key + " not found."); | |
} | |
property.setValue(targetObject, entry.getValue()); | |
} | |
Map<String, IProperty> delayedAttributes = new HashMap<String, IProperty>(); | |
init(metaclass, targetObject, element, delayedAttributes); | |
if (targetObject instanceof Style && element.getChildren().length > 0) { | |
Collection<Setter> setters = new ArrayList<Setter>(); | |
for (DocumentObject doc : element.getChildren()) { | |
Object child = doCreate(targetObject, (Element) doc, null, | |
Collections.EMPTY_MAP); | |
if (!(child instanceof Setter)) { | |
throw new XWTException("Setter is expected in Style."); | |
} | |
setters.add((Setter) child); | |
} | |
((Style) targetObject).setSetters(setters | |
.toArray(new Setter[setters.size()])); | |
} else if (targetObject instanceof ControlEditor) { | |
for (DocumentObject doc : element.getChildren()) { | |
Object editor = doCreate(parent, (Element) doc, null, | |
Collections.EMPTY_MAP); | |
if (editor != null && editor instanceof Control) { | |
((ControlEditor) targetObject).setEditor((Control) editor); | |
((Control) editor).setData( | |
PropertiesConstants.DATA_CONTROLEDITOR_OF_CONTROL, | |
targetObject); | |
} | |
} | |
} else if (targetObject instanceof IDataProvider) { | |
for (DocumentObject doc : element.getChildren()) { | |
if (IConstants.XWT_X_NAMESPACE.equals(doc.getNamespace())) { | |
String content = doc.getContent(); | |
if (content != null) { | |
((IDataProvider) targetObject).setProperty( | |
doc.getName(), content); | |
} | |
} | |
} | |
} else { | |
for (DocumentObject doc : element.getChildren()) { | |
doCreate(targetObject, (Element) doc, null, | |
Collections.EMPTY_MAP); | |
} | |
} | |
iniDelayedAttribute(metaclass, targetObject, element, null, | |
delayedAttributes); | |
postCreation(targetObject); | |
popStack(); | |
return targetObject; | |
} | |
protected void iniDelayedAttribute(IMetaclass metaclass, | |
Object targetObject, Element element, String namespace, | |
Map<String, IProperty> delayedAttributes) throws Exception { | |
Set<String> keys = delayedAttributes.keySet(); | |
while (!keys.isEmpty()) { | |
for (String delayed : keys.toArray(new String[keys.size()])) { | |
IProperty property = delayedAttributes.get(delayed); | |
boolean hasDependency = false; | |
IProperty[] dependencies = property.getLoadingType() | |
.getDependencies(); | |
if (dependencies.length > 0) { | |
for (IProperty dependency : dependencies) { | |
if (delayedAttributes.containsValue(dependency)) { | |
hasDependency = true; | |
break; | |
} | |
} | |
} | |
if (!hasDependency) { | |
initAttribute(metaclass, targetObject, element, null, | |
delayed); | |
keys.remove(delayed); | |
} | |
} | |
} | |
} | |
/** | |
* This method is invoked directly after creation of component instance, but | |
* before applying its attributes and creating children. | |
* | |
* @param element | |
* the source element in XML. | |
* @param targetObject | |
* the created visual object. | |
*/ | |
protected void postCreation0(Element element, Object targetObject) { | |
if (targetObject instanceof IDynamicBinding) { | |
if (bindings == null) | |
bindings = new ArrayList<Binding>(); | |
bindings.add((Binding) targetObject); | |
} | |
} | |
private void invokeCreatededAction(Element element, Object targetObject) { | |
if (targetObject != null) { | |
postCreation0(element, targetObject); | |
} | |
if (options != null) { | |
ICreatedCallback createdAction = (ICreatedCallback) options | |
.get(IXWTLoader.CREATED_CALLBACK); | |
if (createdAction != null) { | |
createdAction.onCreated(targetObject); | |
} | |
} | |
} | |
/** | |
* This method is invoked after full creation of component, i.e. after | |
* creating its instance, applying its attributes and creating children. | |
*/ | |
protected void postCreation(Object target) { | |
// after create a binding with validationstatus tag, the datasource of | |
// the binding should be updated to the corresponding bindingcontext | |
Collection<ValidationStatus> removedStatus = new ArrayList<ValidationStatus>(); | |
if (status != null && !status.isEmpty()) { | |
for (ValidationStatus validationStatus : status) { | |
if (bindings != null && !bindings.isEmpty()) { | |
for (Binding binding : bindings) { | |
if (binding.getName() != null | |
&& validationStatus.getSourceName() != null | |
&& validationStatus.getSourceName().equals( | |
binding.getName())) { | |
removedStatus.add(validationStatus); | |
Control control = (Control) validationStatus | |
.getControl(); | |
if (binding.getControl().equals(control)) | |
if (binding != null) { | |
Binding targetBinding = (Binding) validationStatus | |
.getParent(); | |
targetBinding.setSource(binding | |
.getBindingContext()); | |
targetBinding | |
.setPath(VALIDATION_STATUS_CONSTANT); | |
} | |
} | |
} | |
} | |
} | |
if (removedStatus != null) { | |
status.removeAll(removedStatus); | |
removedStatus.clear(); | |
} | |
} | |
} | |
protected void setDataContext(IMetaclass metaclass, Object targetObject, | |
ResourceDictionary dico, Object dataContext) | |
throws IllegalAccessException, InvocationTargetException, | |
NoSuchFieldException { | |
Object control = null; | |
IMetaclass widgetMetaclass = metaclass; | |
if (JFacesHelper.isViewer(targetObject)) { | |
Widget widget = JFacesHelper.getControl(targetObject); | |
widgetMetaclass = loader.getMetaclass(widget.getClass()); | |
control = targetObject; | |
} else if (targetObject instanceof Widget) { | |
control = (Widget) targetObject; | |
} else { | |
control = loadData.getCurrentWidget(); | |
} | |
if (control != null) { | |
if (targetObject instanceof IDynamicBinding) { | |
IDynamicBinding dynamicBinding = (IDynamicBinding) targetObject; | |
dynamicBinding.setControl(control); | |
dynamicBinding.setHost(loadData.getHost()); | |
} | |
if (dico != null) { | |
UserData.setResources(control, dico); | |
} | |
if (dataContext != null) { | |
IProperty property = widgetMetaclass | |
.findProperty(IConstants.XAML_DATA_CONTEXT); | |
if (property != null) { | |
property.setValue(UserData.getWidget(control), dataContext); | |
} else { | |
throw new XWTException("DataContext is missing in " | |
+ widgetMetaclass.getType().getName()); | |
} | |
} | |
} | |
} | |
protected void setBindingContext(IMetaclass metaclass, Object targetObject, | |
ResourceDictionary dico, Object bindingContext) | |
throws IllegalAccessException, InvocationTargetException, | |
NoSuchFieldException { | |
Object control = null; | |
IMetaclass widgetMetaclass = metaclass; | |
if (JFacesHelper.isViewer(targetObject)) { | |
Widget widget = JFacesHelper.getControl(targetObject); | |
widgetMetaclass = loader.getMetaclass(widget.getClass()); | |
control = targetObject; | |
} else if (targetObject instanceof Widget) { | |
control = (Widget) targetObject; | |
} else { | |
control = loadData.getCurrentWidget(); | |
} | |
if (control != null) { | |
if (targetObject instanceof IDynamicBinding) { | |
IDynamicBinding dynamicBinding = (IDynamicBinding) targetObject; | |
dynamicBinding.setControl(control); | |
dynamicBinding.setHost(loadData.getHost()); | |
} | |
if (dico != null) { | |
UserData.setResources(control, dico); | |
} | |
if (bindingContext != null) { | |
IProperty property = widgetMetaclass | |
.findProperty(IConstants.XAML_BINDING_CONTEXT); | |
if (property != null) { | |
property.setValue(UserData.getWidget(control), | |
bindingContext); | |
} else { | |
throw new XWTException("DataContext is missing in " | |
+ widgetMetaclass.getType().getName()); | |
} | |
} | |
} | |
} | |
protected void applyStyles(Element element, Object targetObject) | |
throws Exception { | |
if (targetObject instanceof Widget) { | |
Widget widget = (Widget) targetObject; | |
Map<String, Object> dico = UserData.getLocalResources(widget); | |
Attribute attribute = element | |
.getAttribute(IConstants.XAML_RESOURCES); | |
if (attribute == null) { | |
attribute = element.getAttribute(IConstants.XWT_NAMESPACE, | |
IConstants.XAML_RESOURCES); | |
} | |
if (attribute != null) { | |
if (attribute.getChildren().length > 0) { | |
if (dico == null) { | |
dico = new ResourceDictionary(); | |
UserData.setResources(widget, dico); | |
} | |
for (DocumentObject doc : attribute.getChildren()) { | |
Element elem = (Element) doc; | |
Object doCreate = doCreate(widget, elem, null, | |
EMPTY_MAP); | |
Attribute keyAttribute = elem.getAttribute( | |
IConstants.XWT_X_NAMESPACE, | |
IConstants.XAML_X_KEY); | |
if (keyAttribute == null) { | |
keyAttribute = elem.getAttribute( | |
IConstants.XWT_X_NAMESPACE, | |
IConstants.XAML_X_TYPE); | |
} | |
if (keyAttribute != null) { | |
dico.put(keyAttribute.getContent(), doCreate); | |
} | |
if (doCreate instanceof IStyle) { | |
IStyle style = (IStyle) doCreate; | |
loadData.addStyle(style); | |
} | |
} | |
} | |
} | |
// apply the styles defined in parent's resources via TargetType | |
Widget current = widget; | |
while (current != null) { | |
dico = UserData.getLocalResources(current); | |
if (dico != null) { | |
for (Object value : dico.values()) { | |
if (value instanceof Style) { | |
Style style = (Style) value; | |
Class<?> targetType = style.getTargetType(); | |
if (targetType != null | |
&& targetType.isInstance(widget)) { | |
style.apply(targetObject); | |
} | |
} | |
} | |
} | |
current = UserData.getTreeParent(current); | |
} | |
} | |
for (IStyle style : loadData.getStyles()) { | |
style.applyStyle(targetObject); | |
} | |
} | |
protected int getColumnIndex(Element columnElement) { | |
String name = columnElement.getName(); | |
String namespace = columnElement.getNamespace(); | |
IMetaclass metaclass = loader.getMetaclass(name, namespace); | |
int index = -1; | |
Class<?> type = metaclass.getType(); | |
if (TableViewerColumn.class.isAssignableFrom(type)) { | |
DocumentObject parent = columnElement.getParent(); | |
List<DocumentObject> children = DocumentObjectSorter.sortWithAttr( | |
parent.getChildren(), "Index"); | |
index = children.indexOf(columnElement); | |
} | |
return index; | |
} | |
/** | |
* @param tableItem | |
*/ | |
protected void installTableEditors(TableItem tableItem) { | |
Table table = tableItem.getParent(); | |
TableColumn[] columns = table.getColumns(); | |
if (columns == null || columns.length == 0) { | |
return; | |
} | |
for (TableColumn tableColumn : columns) { | |
Object data = tableColumn | |
.getData(PropertiesConstants.DATA_DEFINED_EDITOR); | |
if (data == null || !(data instanceof Element)) { | |
continue; | |
} | |
int column = table.indexOf(tableColumn); | |
Element editor = (Element) data; | |
try { | |
TableEditor tableEditor = (TableEditor) doCreate(table, editor, | |
null, EMPTY_MAP); | |
if (tableEditor != null) { | |
tableEditor.setColumn(column); | |
tableEditor.setItem(tableItem); | |
} | |
} catch (Exception e) { | |
continue; | |
} | |
} | |
} | |
protected Object getDataContext(Element element, Widget swtObject) { | |
// x:DataContext | |
try { | |
Object dataContext = loadData.getDataContext(); | |
if (dataContext != null) { | |
return dataContext; | |
} | |
{ | |
Attribute dataContextAttribute = element | |
.getAttribute(IConstants.XAML_DATA_CONTEXT); | |
if (dataContextAttribute != null) { | |
Widget composite = (Widget) swtObject; | |
DocumentObject documentObject = dataContextAttribute | |
.getChildren()[0]; | |
if (IConstants.XAML_STATICRESOURCES.equals(documentObject | |
.getName()) | |
|| IConstants.XAML_DYNAMICRESOURCES | |
.equals(documentObject.getName())) { | |
String key = documentObject.getContent(); | |
dataContext = new StaticResourceBinding(composite, key); | |
loadData.setDataContext(dataContext); | |
return dataContext; | |
} else if (IConstants.XAML_BINDING.equals(documentObject | |
.getName())) { | |
dataContext = doCreate(swtObject, | |
(Element) documentObject, null, EMPTY_MAP); | |
loadData.setDataContext(dataContext); | |
return dataContext; | |
} else { | |
LoggerManager.log(new UnsupportedOperationException( | |
documentObject.getName())); | |
} | |
} | |
} | |
} catch (Exception e) { | |
LoggerManager.log(e); | |
} | |
return null; | |
} | |
protected Object getBindingContext(Element element, Widget swtObject) { | |
// x:DataContext | |
try { | |
{ | |
Attribute dataContextAttribute = element | |
.getAttribute(IConstants.XAML_BINDING_CONTEXT); | |
if (dataContextAttribute != null) { | |
Widget composite = (Widget) swtObject; | |
DocumentObject documentObject = dataContextAttribute | |
.getChildren()[0]; | |
if (IConstants.XAML_STATICRESOURCES.equals(documentObject | |
.getName()) | |
|| IConstants.XAML_DYNAMICRESOURCES | |
.equals(documentObject.getName())) { | |
String key = documentObject.getContent(); | |
return new StaticResourceBinding(composite, key); | |
} else if (IConstants.XAML_BINDING.equals(documentObject | |
.getName())) { | |
return doCreate(swtObject, (Element) documentObject, | |
null, EMPTY_MAP); | |
} else { | |
LoggerManager.log(new UnsupportedOperationException( | |
documentObject.getName())); | |
} | |
} | |
} | |
} catch (Exception e) { | |
LoggerManager.log(e); | |
} | |
return null; | |
} | |
protected void pushStack(Object host) { | |
loadData = new LoadingData(loadData, host); | |
} | |
protected void popStack() { | |
LoadingData previous = loadData; | |
loadData = previous.getParent(); | |
previous.end(); | |
} | |
protected Integer getStyleValue(Element element, int styles) { | |
Attribute attribute = element.getAttribute(IConstants.XWT_X_NAMESPACE, | |
IConstants.XAML_STYLE); | |
if (attribute == null) { | |
if (styles != -1) { | |
return styles; | |
} | |
return null; | |
} | |
if (styles == -1) { | |
return (Integer) loader.findConvertor(String.class, Integer.class) | |
.convert(attribute.getContent()); | |
} | |
return styles | |
| (Integer) loader.findConvertor(String.class, Integer.class) | |
.convert(attribute.getContent()); | |
} | |
protected void init(IMetaclass metaclass, Object targetObject, | |
Element element, Map<String, IProperty> delayedAttributes) | |
throws Exception { | |
// editors for TableItem, | |
if (targetObject instanceof TableItem) { | |
installTableEditors((TableItem) targetObject); | |
} | |
// x:DataContext | |
if (loadData.getDataContext() == null) { | |
Attribute dataContextAttribute = element | |
.getAttribute(IConstants.XAML_DATA_CONTEXT); | |
if (dataContextAttribute != null) { | |
IProperty property = metaclass | |
.findProperty(IConstants.XAML_DATA_CONTEXT); | |
Widget composite = (Widget) UserData.getWidget(targetObject); | |
DocumentObject documentObject = dataContextAttribute | |
.getChildren()[0]; | |
if (IConstants.XAML_STATICRESOURCES.equals(documentObject | |
.getName()) | |
|| IConstants.XAML_DYNAMICRESOURCES | |
.equals(documentObject.getName())) { | |
String key = documentObject.getContent(); | |
property.setValue(composite, new StaticResourceBinding( | |
composite, key)); | |
} else if (IConstants.XAML_BINDING.equals(documentObject | |
.getName())) { | |
Object object = doCreate(targetObject, | |
(Element) documentObject, null, EMPTY_MAP); | |
property.setValue(composite, object); | |
} else { | |
LoggerManager.log(new UnsupportedOperationException( | |
documentObject.getName())); | |
} | |
} | |
} | |
HashSet<String> done = new HashSet<String>(); | |
Attribute nameAttr = element.getAttribute(IConstants.XAML_X_NAME); | |
if (nameAttr == null) { | |
nameAttr = element.getAttribute(IConstants.XWT_X_NAMESPACE, | |
IConstants.XAML_X_NAME); | |
} | |
if (nameAttr != null && UserData.getWidget(targetObject) != null) { | |
String value = nameAttr.getContent(); | |
loadData.inject(targetObject, value); | |
nameScoped.addNamedObject(value, targetObject); | |
UserData.setElementName(targetObject, value, false); | |
done.add(IConstants.XAML_X_NAME); | |
} | |
for (String attrName : element.attributeNames()) { | |
IProperty property = metaclass.findProperty(attrName); | |
if (property == null) { | |
IMetaclass mc = XWT.getMetaclass(targetObject); | |
property = mc.findProperty(attrName); | |
if (property != null) { | |
metaclass = mc; | |
} | |
} | |
if (IConstants.XWT_X_NAMESPACE.equals(element | |
.getAttribute(attrName).getNamespace())) { | |
continue; | |
} else if (delayedAttributes != null | |
&& property != null | |
&& property.getLoadingType().getValueLoading() != IValueLoading.Normal) | |
delayedAttributes.put(attrName, property); | |
else { | |
if (!done.contains(attrName)) { | |
initAttribute(metaclass, targetObject, element, null, | |
attrName); | |
done.add(attrName); | |
} | |
} | |
} | |
for (String namespace : element.attributeNamespaces()) { | |
if (IConstants.XWT_X_NAMESPACE.equals(namespace)) { | |
for (String attrName : element.attributeNames(namespace)) { | |
if ("class".equalsIgnoreCase(attrName) | |
|| IConstants.XAML_STYLE.equalsIgnoreCase(attrName)) { | |
continue; // done before | |
} else if (IConstants.XAML_X_NAME | |
.equalsIgnoreCase(attrName)) { | |
nameScoped.addNamedObject( | |
element.getAttribute(namespace, attrName) | |
.getContent(), targetObject); | |
done.add(attrName); | |
} else if (IConstants.XAML_DATA_CONTEXT | |
.equalsIgnoreCase(attrName)) { | |
continue; // done before | |
} else if (IConstants.XAML_X_ARRAY | |
.equalsIgnoreCase(attrName)) { | |
IProperty property = metaclass.findProperty(attrName); | |
Class<?> type = property.getType(); | |
Object value = getArrayProperty(type, targetObject, | |
element, attrName); | |
if (value != null) { | |
property.setValue(targetObject, value); | |
} | |
} else if (IConstants.XAML_RESOURCES | |
.equalsIgnoreCase(attrName)) { | |
continue; | |
} else { | |
if (!done.contains(attrName)) { | |
initAttribute(metaclass, targetObject, element, | |
namespace, attrName); | |
done.add(attrName); | |
} | |
} | |
} | |
continue; | |
} | |
for (String attrName : element.attributeNames(namespace)) { | |
if (IConstants.XAML_X_NAME.equalsIgnoreCase(attrName) | |
&& (targetObject instanceof Widget)) { | |
continue; | |
} | |
if (!done.contains(attrName)) { | |
initAttribute(metaclass, targetObject, element, namespace, | |
attrName); | |
done.add(attrName); | |
} | |
} | |
} | |
for (String attrName : element.attributeNames()) { | |
if (IConstants.XAML_X_NAME.equalsIgnoreCase(attrName) | |
&& UserData.getWidget(targetObject) != null) { | |
continue; | |
} | |
if (!done.contains(attrName) | |
&& !delayedAttributes.containsKey(attrName)) { | |
initAttribute(metaclass, targetObject, element, null, attrName); | |
done.add(attrName); | |
} | |
} | |
// | |
// handle foreigner namespace | |
// | |
for (String namespace : element.attributeNamespaces()) { | |
if (XWT.isXWTNamespace(namespace)) { | |
continue; | |
} | |
INamespaceHandler namespaceHandler = loader | |
.getNamespaceHandler(namespace); | |
if (namespaceHandler != null) { | |
for (String attrName : element.attributeNames(namespace)) { | |
Attribute attribute = element.getAttribute(namespace, | |
attrName); | |
Widget widget = UserData.getWidget(loadData | |
.getCurrentWidget()); | |
namespaceHandler.handleAttribute(widget, targetObject, | |
attrName, attribute.getContent()); | |
} | |
} | |
} | |
} | |
protected Object getArrayProperty(Class<?> type, Object swtObject, | |
DocumentObject docObject, String attrName) | |
throws IllegalAccessException, InvocationTargetException, | |
NoSuchFieldException { | |
Class<?> arrayType = null; | |
if (type == Object.class) { | |
if (docObject instanceof Element) { | |
Element element = (Element) docObject; | |
Attribute attribute = element.getAttribute( | |
IConstants.XWT_NAMESPACE, IConstants.XAML_X_TYPE); | |
if (attribute == null) { | |
throw new XWTException( | |
"The type attribute is missing in the element x:Array."); | |
} | |
String value = attribute.getContent(); | |
IMetaclass metaclass = XWT.getMetaclass(value, | |
attribute.getNamespace()); | |
if (metaclass == null) { | |
throw new XWTException("The type \"" + value | |
+ "\" is not found."); | |
} | |
arrayType = metaclass.getType(); | |
} | |
} else { | |
if (!type.isArray()) { | |
throw new XWTException("Type mismatch: property " + attrName | |
+ " isn't an array."); | |
} | |
arrayType = type.getComponentType(); | |
} | |
if (arrayType != null) { | |
List<Object> list = new ArrayList<Object>(); | |
for (DocumentObject childModel : docObject.getChildren()) { | |
if (!(childModel instanceof Element)) { | |
continue; | |
} | |
Object child = createInstance(swtObject, (Element) childModel); | |
list.add(child); | |
} | |
Object[] array = (Object[]) Array.newInstance(arrayType, | |
list.size()); | |
list.toArray(array); | |
for (int i = 0; i < array.length; i++) { | |
if (array[i] instanceof IIndexedElement) { | |
((IIndexedElement) array[i]).setIndex(swtObject, i); | |
} | |
} | |
return array; | |
} | |
return null; | |
} | |
@SuppressWarnings("unchecked") | |
protected Object getCollectionProperty(Class<?> type, Object swtObject, | |
DocumentObject element, String attrName) | |
throws IllegalAccessException, InvocationTargetException, | |
NoSuchFieldException { | |
Collection<Object> collector = null; | |
if (type.isInterface()) { | |
collector = new ArrayList<Object>(); | |
} else { | |
if (Modifier.isAbstract(type.getModifiers())) { | |
LoggerManager.log(new XWTException("Collection " | |
+ type.getSimpleName() + " is abstract type")); | |
} | |
try { | |
collector = (Collection) type.newInstance(); | |
} catch (InstantiationException e) { | |
LoggerManager.log(new XWTException(e)); | |
} | |
} | |
for (DocumentObject childModel : element.getChildren()) { | |
if (!(childModel instanceof Element)) { | |
continue; | |
} | |
Object child = createInstance(swtObject, (Element) childModel); | |
collector.add(child); | |
if (child instanceof IIndexedElement) { | |
((IIndexedElement) child).setIndex(swtObject, | |
collector.size() - 1); | |
} | |
} | |
return collector; | |
} | |
protected String findNamespace(DocumentObject context, String prefix) { | |
while (context != null && !(context instanceof Element)) { | |
context = context.getParent(); | |
} | |
if (context == null) { | |
return null; | |
} | |
Element element = (Element) context; | |
if (prefix != null) { | |
prefix = (prefix.length() == 0 ? null : prefix); | |
} | |
String namespace = element.getXmlns(prefix); | |
if (namespace != null) { | |
return namespace; | |
} | |
DocumentObject parent = element.getParent(); | |
return findNamespace(parent, prefix); | |
} | |
protected Object createInstance(Object swtObject, Element element) { | |
String name = element.getName(); | |
String namespace = element.getNamespace(); | |
if (IConstants.XWT_X_NAMESPACE.equalsIgnoreCase(namespace) | |
&& IConstants.XAML_X_NULL.equalsIgnoreCase(name)) { | |
return null; | |
} | |
try { | |
Class<?> type = NamespaceHelper.loadCLRClass( | |
context.getLoadingContext(), name, namespace); | |
IMetaclass metaclass = loader.getMetaclass(name, namespace); | |
if (type == null) { | |
if (metaclass != null) | |
type = metaclass.getType(); | |
} | |
if (metaclass == null) { | |
throw new XWTException("Class for " + name + " is not found."); | |
} | |
// type = expected type; | |
// Need to support the | |
String content = element.getContent(); | |
Object instance = null; | |
if (content == null) { | |
instance = metaclass.newInstance(new Object[] { swtObject }); | |
invokeCreatededAction(element, instance); | |
if (instance instanceof TableEditor) { | |
// TODO should be moved into IMetaclass | |
TableEditor tableEditor = (TableEditor) instance; | |
if (swtObject instanceof TableItem) { | |
TableItem item = (TableItem) swtObject; | |
tableEditor.setItem(item); | |
for (DocumentObject doc : element.getChildren()) { | |
Control control = (Control) doCreate( | |
((TableItem) swtObject).getParent(), | |
(Element) doc, null, EMPTY_MAP); | |
tableEditor.setEditor(control); | |
int column = getColumnValue(element); | |
TableEditorHelper.initEditor(item, control, column); | |
} | |
} | |
} | |
} else { | |
Constructor<?> constructor = type.getConstructor(type); | |
if (constructor != null) { | |
instance = constructor.newInstance(loader.convertFrom(type, | |
content)); | |
invokeCreatededAction(element, instance); | |
} else { | |
LoggerManager.log(new XWTException("Constructor \"" + name | |
+ "(" + type.getSimpleName() + ")\" is not found")); | |
} | |
} | |
Map<String, IProperty> delayedAttributes = new HashMap<String, IProperty>(); | |
init(metaclass, instance, element, delayedAttributes); | |
iniDelayedAttribute(metaclass, instance, element, null, | |
delayedAttributes); | |
for (DocumentObject doc : element.getChildren()) { | |
doCreate(instance, (Element) doc, null, Collections.EMPTY_MAP); | |
} | |
return instance; | |
} catch (Exception e) { | |
LoggerManager.log(e); | |
} | |
return null; | |
} | |
static protected int getColumnValue(Element context) { | |
Attribute attribute = context.getAttribute(COLUMN); | |
if (attribute != null) { | |
String content = attribute.getContent(); | |
if (content != null) { | |
return Integer.parseInt(content); | |
} | |
} | |
return 0; | |
} | |
protected void loadShellCLR(String className, Shell shell) { | |
Class<?> type = ClassLoaderUtil.loadClass(context.getLoadingContext(), | |
className); | |
try { | |
Object instance = type.newInstance(); | |
loadData.setClr(instance); | |
UserData.setCLR(shell, instance); | |
} catch (Exception e) { | |
LoggerManager.log(e); | |
} | |
} | |
protected Object loadFactoryCLR(String value, ICLRFactory factory) { | |
String token; | |
String arg; | |
if (value.startsWith("+")) { | |
if (factory == null) { | |
throw new XWTException("ICLRFactory option is missing."); | |
} | |
arg = value.substring(1).trim(); | |
return factory.createCLR(arg, options); | |
} else { | |
StringTokenizer stringTokenizer = new StringTokenizer(value); | |
if (!stringTokenizer.hasMoreTokens()) { | |
throw new XWTException("x:ClassFactory is empty"); | |
} | |
token = stringTokenizer.nextToken(); | |
arg = value.substring(token.length()).trim(); | |
} | |
int index = token.lastIndexOf('.'); | |
if (index != -1) { | |
String memberName = token.substring(index + 1); | |
String typeName = token.substring(0, index); | |
Class<?> type = ClassLoaderUtil.loadClass( | |
context.getLoadingContext(), typeName); | |
if (type != null) { | |
Object member = ClassLoaderUtil.loadMember( | |
context.getLoadingContext(), type, memberName, false); | |
if (member instanceof ICLRFactory) { | |
factory = (ICLRFactory) member; | |
} | |
if (factory != null) { | |
return factory.createCLR(arg, options); | |
} | |
} | |
} | |
Class<?> type = ClassLoaderUtil.loadClass(context.getLoadingContext(), | |
token); | |
if (type != null && ICLRFactory.class.isAssignableFrom(type)) { | |
try { | |
ICLRFactory localFactory = (ICLRFactory) type.newInstance(); | |
return localFactory.createCLR(arg, options); | |
} catch (Exception e) { | |
throw new XWTException(e); | |
} | |
} | |
throw new XWTException(value + " ClassFactory not found."); | |
} | |
protected Object loadCLR(String className, Object[] parameters, | |
Class<?> currentTagType, Map<String, Object> options) { | |
Class<?> type = ClassLoaderUtil.loadClass(context.getLoadingContext(), | |
className); | |
if (type == null) { | |
return null; | |
} | |
try { | |
Object clr = options.get(XWTLoader.CLASS_PROPERTY); | |
if (clr != null && type.isInstance(clr)) { | |
loadData.setClr(clr); | |
if (clr instanceof Widget) { | |
UserData.setCLR((Widget) clr, clr); | |
} | |
} else if (currentTagType != null | |
&& currentTagType.isAssignableFrom(type)) { | |
IMetaclass metaclass = loader.getMetaclass(type); | |
Object instance = metaclass.newInstance(parameters); | |
loadData.setClr(instance); | |
// use x:Class's instance | |
if (instance instanceof Widget) { | |
UserData.setCLR((Widget) instance, instance); | |
} | |
return instance; | |
} else { | |
Object instance = type.newInstance(); | |
loadData.setClr(instance); | |
if (instance instanceof Widget) { | |
UserData.setCLR((Widget) instance, instance); | |
} | |
} | |
} catch (Exception e) { | |
LoggerManager.log(e); | |
} | |
return null; | |
} | |
protected void initAttribute(IMetaclass metaclass, Object targetObject, | |
Element element, String namespace, String attrName) | |
throws Exception { | |
if (attrName.indexOf('.') != -1) { | |
String[] segments = attrName.split("\\."); | |
IMetaclass currentMetaclass = metaclass; | |
Object target = targetObject; | |
for (int i = 0; i < segments.length - 1; i++) { | |
IProperty property = currentMetaclass.findProperty(segments[i]); | |
if (property != null) { | |
target = property.getValue(target); | |
if (target == null) { | |
LoggerManager.log(new XWTException("Property \"" | |
+ segments[i] + "\" is null.")); | |
} | |
currentMetaclass = loader.getMetaclass(target); | |
} else { | |
LoggerManager.log(new XWTException("Property \"" | |
+ segments[i] + "\" not found in " | |
+ element.getName() + ".")); | |
} | |
} | |
initSegmentAttribute(currentMetaclass, | |
segments[segments.length - 1], target, element, namespace, | |
attrName); | |
return; | |
} | |
initSegmentAttribute(metaclass, attrName, targetObject, element, | |
namespace, attrName); | |
} | |
protected void addCommandExecuteListener(String commandName, | |
final Widget targetButton) { | |
final ICommand commandObj = loader.getCommand(commandName); | |
if (commandObj != null) { | |
targetButton.addListener(SWT.Selection, new Listener() { | |
public void handleEvent(Event event) { | |
commandObj.execute(targetButton); | |
} | |
}); | |
} | |
} | |
protected void initSegmentAttribute(IMetaclass metaclass, | |
String propertyName, Object target, Element element, | |
String namespace, String attrName) throws Exception { | |
Attribute attribute = namespace == null ? element | |
.getAttribute(attrName) : element.getAttribute(namespace, | |
attrName); | |
if (attribute == null) { | |
attribute = element.getAttribute(attrName); | |
} | |
IProperty property = null; | |
boolean isAttached = false; | |
{ | |
String namePrefix = attribute.getNamePrefix(); | |
if (namePrefix == null) { | |
property = metaclass.findProperty(propertyName); | |
} else { | |
// | |
IMetaclass metaclassAttached = loader.getMetaclass(namePrefix, | |
attribute.getNamespace()); | |
if (metaclassAttached != null) { | |
property = metaclassAttached.findProperty(propertyName); | |
isAttached = true; | |
} else { | |
LoggerManager.log(attribute.getNamespace() + " -> " | |
+ namePrefix + " is not found."); | |
return; | |
} | |
} | |
} | |
if (propertyName.equals(IConstants.XAML_DATA_CONTEXT)) { | |
property = null; | |
} | |
if (IConstants.XAML_COMMAND.equalsIgnoreCase(propertyName) | |
&& ICommand.class.isAssignableFrom(property.getType()) | |
&& (target instanceof Widget)) { | |
addCommandExecuteListener(attribute.getContent(), (Widget) target); | |
} | |
if (property == null) { | |
if (options.get(IXWTLoader.DESIGN_MODE_PROPERTY) == Boolean.TRUE) { | |
return; | |
} | |
// prepare event | |
IEvent event = metaclass.findEvent(attrName); | |
if (event == null) { | |
return; | |
} | |
// add events for controls and items. | |
if (!(target instanceof Widget)) { | |
return; | |
} | |
loadData.updateEvent(context, (Widget) target, event, | |
attribute.getContent()); | |
return; | |
} | |
String contentValue = attribute.getContent(); | |
if ("MenuItem".equalsIgnoreCase(element.getName()) | |
&& "Text".equalsIgnoreCase(attrName)) { | |
Attribute attributeAccelerator = element | |
.getAttribute("Accelerator"); | |
if (attributeAccelerator != null) { | |
contentValue = contentValue + '\t' | |
+ getContentValue(attributeAccelerator.getContent()); | |
} | |
} | |
if (contentValue != null && "Accelerator".equalsIgnoreCase(attrName)) { | |
contentValue = XWTMaps.getCombAccelerator(contentValue); | |
if (contentValue.contains("'")) { | |
contentValue = removeSubString(contentValue, "'"); | |
} | |
} | |
if (contentValue != null | |
&& loader.isFileResolveType(property.getType())) { | |
contentValue = getImagePath(contentValue); | |
} | |
// if (contentValue != null | |
// && (URL.class.isAssignableFrom(property.getType()))) { | |
// contentValue = getSourceURL(contentValue); | |
// } | |
Object value = null; | |
DocumentObject[] children = attribute.getChildren(); | |
boolean usingExistingValue = false; | |
if (contentValue == null) { | |
Class<?> type = property.getType(); | |
if (Collection.class.isAssignableFrom(type)) { | |
value = getCollectionProperty(type, target, attribute, attrName); | |
} else { | |
Object directTarget = null; | |
if (TableViewerColumn.class.isAssignableFrom(type) | |
&& attrName.equalsIgnoreCase("columns")) { | |
children = DocumentObjectSorter.sortWithAttr(children, | |
"Index").toArray( | |
new DocumentObject[children.length]); | |
} else { | |
try { | |
Object propertyValue = property.getValue(target); | |
if (UserData.getWidget(propertyValue) != null) { | |
directTarget = propertyValue; | |
// use the existing property value as parent, | |
// not need to add the constraint | |
if (!property.isValueAsParent()) { | |
if (isChildTypeCompatible(attribute, type)) { | |
directTarget = null; | |
} else { | |
type = null; | |
usingExistingValue = true; | |
} | |
} | |
} | |
} catch (Exception e) { | |
} | |
} | |
if (directTarget == null) { | |
directTarget = target; | |
} | |
for (DocumentObject child : children) { | |
String name = child.getName(); | |
String ns = child.getNamespace(); | |
if (name.equalsIgnoreCase(IConstants.XAML_X_STATIC) | |
&& ns.equals(IConstants.XWT_X_NAMESPACE)) { | |
value = getStaticValue(child); | |
} else if (name | |
.equalsIgnoreCase(IConstants.XAML_STATICRESOURCES) | |
&& ns.equals(IConstants.XWT_NAMESPACE)) { | |
String key = child.getContent(); | |
value = new StaticResourceBinding( | |
loadData.getCurrentWidget(), key); | |
} else if ((IConstants.XWT_X_NAMESPACE.equals(ns) && IConstants.XAML_X_ARRAY | |
.equalsIgnoreCase(name))) { | |
value = getArrayProperty(property.getType(), | |
directTarget, child, name); | |
} else if (property.getType().isArray()) { | |
value = getArrayProperty(property.getType(), | |
directTarget, attribute, name); | |
break; | |
} else if (isAssignableFrom(element, TableColumn.class) | |
&& isAssignableFrom(child, TableEditor.class)) { | |
value = child; | |
} else if (TableViewerColumn.class | |
.isAssignableFrom(property.getType()) | |
&& attribute.getContent() != null) { | |
value = attribute.getContent(); | |
} else { | |
if ("Null".equals(child.getName()) | |
&& IConstants.XWT_X_NAMESPACE.equals(child | |
.getNamespace())) { | |
property.setValue(directTarget, null); | |
return; | |
} else { | |
value = doCreate(directTarget, (Element) child, | |
type, EMPTY_MAP); | |
if (value == null | |
&& type != null | |
&& !(type == Table.class | |
&& "TableColumn".equals(child | |
.getName()) && Table.class | |
.isInstance(directTarget))) { | |
throw new XWTException(child.getName() | |
+ " cannot be a content of " | |
+ type.getName() + " " | |
+ target.getClass().getName() + "." | |
+ property.getName()); | |
} | |
if (value instanceof IDynamicBinding) { | |
((IDynamicBinding) value).setType(attrName); | |
} | |
} | |
} | |
} | |
} | |
} | |
if (contentValue != null && value == null | |
&& !IConstants.XAML_COMMAND.equalsIgnoreCase(propertyName)) { | |
if (property.getType().isInstance(Class.class)) { | |
int index = contentValue.lastIndexOf(':'); | |
if (index != -1) { | |
String prefix = contentValue.substring(0, index); | |
contentValue = findNamespace(attribute, prefix) | |
+ contentValue.substring(index); | |
} | |
} | |
value = loader.convertFrom(property.getType(), contentValue); | |
} | |
if (!usingExistingValue) { | |
if (value != null) { | |
Class<?> propertyType = property.getType(); | |
if (!propertyType.isAssignableFrom(value.getClass()) | |
|| (value instanceof IBinding && !(IBinding.class | |
.isAssignableFrom(propertyType)))) { | |
Object orginalValue = value; | |
IConverter converter = loader.findConvertor( | |
value.getClass(), propertyType); | |
if (converter != null) { | |
value = converter.convert(value); | |
if (value != null | |
&& orginalValue instanceof IBinding | |
&& !propertyType.isAssignableFrom(value | |
.getClass())) { | |
converter = loader.findConvertor(value.getClass(), | |
propertyType); | |
if (converter != null) { | |
value = converter.convert(value); | |
} else { | |
LoggerManager.log(new XWTException("Convertor " | |
+ value.getClass().getSimpleName() | |
+ "->" + propertyType.getSimpleName() | |
+ " is not found")); | |
} | |
} | |
} else { | |
LoggerManager.log(new XWTException("Convertor " | |
+ value.getClass().getSimpleName() + "->" | |
+ propertyType.getSimpleName() | |
+ " is not found")); | |
} | |
} | |
if (isAttached) { | |
UserData.setLocalData(target, property, value); | |
} else { | |
if (value instanceof IDynamicValueBinding) { | |
IDynamicValueBinding dynamicValueBinding = (IDynamicValueBinding) value; | |
dynamicValueBinding.setControl(loadData | |
.findElement(Widget.class)); | |
dynamicValueBinding.setProperty(property); | |
dynamicValueBinding.setObject(target); | |
} | |
// deal with validation staus | |
if ((value instanceof ValidationStatus) | |
&& (property.getName().equals("source")) | |
&& (target instanceof Binding)) { | |
ValidationStatus validationStatus = (ValidationStatus) value; | |
validationStatus.setParent(target); | |
if (status == null) | |
status = new ArrayList<ValidationStatus>(); | |
status.add(validationStatus); | |
} else { | |
property.setValue(target, value); | |
} | |
} | |
} else { | |
if (value == null) { | |
value = property.getValue(target); | |
} | |
if (value != null) { | |
// create children. | |
for (DocumentObject child : children) { | |
String name = child.getName(); | |
String ns = child.getNamespace(); | |
if (!IConstants.XWT_X_NAMESPACE.equals(ns) | |
|| !IConstants.XAML_X_ARRAY | |
.equalsIgnoreCase(name)) { | |
Class<?> type = property.getType(); | |
if (!Collection.class.isAssignableFrom(type)) { | |
doCreate(value, (Element) child, null, | |
EMPTY_MAP); | |
} | |
} | |
} | |
} | |
} | |
} | |
if (attribute.attributeNames(IConstants.XWT_NAMESPACE).length > 0) { | |
IMetaclass propertyMetaclass = loader.getMetaclass(property | |
.getType()); | |
if (value == null) { | |
value = property.getValue(target); | |
} | |
if (value != null) { | |
Map<String, IProperty> delayedAttributes = new HashMap<String, IProperty>(); | |
init(propertyMetaclass, value, attribute, delayedAttributes); | |
iniDelayedAttribute(metaclass, target, element, namespace, | |
delayedAttributes); | |
} | |
} | |
} | |
protected boolean isChildTypeCompatible(Attribute attribute, Class<?> type) { | |
DocumentObject[] children = attribute.getChildren(); | |
if (children.length != 1) { | |
return false; | |
} | |
DocumentObject child = children[0]; | |
if (!(child instanceof Element)) { | |
return false; | |
} | |
Element childElement = (Element) child; | |
String name = childElement.getName(); | |
String namespace = childElement.getNamespace(); | |
IMetaclass metaclass = loader.getMetaclass(name, namespace); | |
if (metaclass == null) { | |
return false; | |
} | |
return type.isAssignableFrom(metaclass.getType()); | |
} | |
/** | |
* @param contentValue | |
* @return | |
*/ | |
protected String getSourceURL(String contentValue) { | |
URL url = null; | |
try { | |
url = new URL(contentValue); | |
} catch (MalformedURLException e) { | |
if (!contentValue.startsWith("/")) { | |
contentValue = "/" + contentValue; | |
} | |
ILoadingContext loadingContext = context.getLoadingContext(); | |
URL resource = loadingContext.getResource(contentValue); | |
if (resource == null) { | |
try { | |
resource = new URL(context.getResourcePath() + contentValue); | |
return resource.toString(); | |
} catch (MalformedURLException e1) { | |
} | |
} else { | |
return resource.toString(); | |
} | |
} | |
if (url != null) { | |
return url.toString(); | |
} | |
return contentValue; | |
} | |
protected Class<?> getJavaType(DocumentObject element) { | |
String name = element.getName(); | |
String namespace = element.getNamespace(); | |
if (IConstants.XWT_X_NAMESPACE.equalsIgnoreCase(namespace) | |
&& IConstants.XAML_X_NULL.equalsIgnoreCase(name)) { | |
return null; | |
} | |
IMetaclass metaclass = loader.getMetaclass(name, namespace); | |
if (metaclass == null) { | |
return null; | |
} | |
return metaclass.getType(); | |
} | |
protected boolean isAssignableFrom(DocumentObject element, Class<?> type) { | |
Class<?> targetType = getJavaType(element); | |
if (targetType == null) { | |
return false; | |
} | |
return targetType.isAssignableFrom(type); | |
} | |
protected Object getStaticValue(DocumentObject child) { | |
DocumentObject[] children = child.getChildren(); | |
if (children.length == 1) { | |
Element element = (Element) children[0]; | |
if (element != null) { | |
return ClassLoaderUtil.loadStaticMember( | |
context.getLoadingContext(), element); | |
} | |
} | |
return null; | |
} | |
protected String getImagePath(String contentValue) { | |
String value = contentValue; | |
try { | |
File file = new File(contentValue); | |
if (file.exists()) { | |
return file.toURI().toURL().toString(); | |
} | |
if (!contentValue.startsWith("/")) { | |
URL url = context.getResourcePath(); | |
if (url != null) { | |
return url.toString() + "/" + contentValue; | |
} | |
contentValue = "/" + contentValue; | |
} | |
ILoadingContext loadingContext = context.getLoadingContext(); | |
URL resource = loadingContext.getResource(contentValue); | |
if (resource == null) { | |
URL resourcePath = context.getResourcePath(); | |
String fPath = resourcePath.toString(); | |
String absolutePath = PathHelper.getAbsolutePath(fPath, | |
contentValue); | |
if ((file = new File(absolutePath)).exists()) { | |
return file.toURI().toURL().toString(); | |
} | |
resource = new URL(absolutePath); | |
} | |
return resource.toString(); | |
} catch (MalformedURLException e) { | |
return value; | |
} | |
} | |
protected String removeSubString(String str, String subString) { | |
StringBuffer stringBuffer = new StringBuffer(); | |
int lenOfsource = str.length(); | |
int i; | |
int posStart; | |
for (posStart = 0; (i = str.indexOf(subString, posStart)) >= 0; posStart = i | |
+ subString.length()) { | |
stringBuffer.append(str.substring(posStart, i)); | |
} | |
if (posStart < lenOfsource) { | |
stringBuffer.append(str.substring(posStart)); | |
} | |
return stringBuffer.toString(); | |
} | |
protected String getContentValue(String text) { | |
StringBuffer stringBuffer = new StringBuffer(); | |
String subString = "SWT."; | |
String str = XWTMaps.getCombAccelerator(text); | |
if (str.contains(subString)) { | |
str = removeSubString(str, subString); | |
} | |
if (str.contains("'")) { | |
str = removeSubString(str, "'"); | |
} | |
if (str.contains(" ")) { | |
str = removeSubString(str, " "); | |
} | |
if (str.contains("|")) { | |
str = str.replace('|', '+'); | |
} | |
stringBuffer.append(str); | |
return stringBuffer.toString(); | |
} | |
} |