/*
* SmartGWT (GWT for SmartClient)
* Copyright 2008 and beyond, Isomorphic Software, Inc.
*
* SmartGWT is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version 3
* as published by the Free Software Foundation. SmartGWT is also
* available under typical commercial license terms - see
* http://smartclient.com/license
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package com.smartgwt.client.data;
import java.util.Map;
import com.smartgwt.client.core.RefDataClass;
import com.smartgwt.client.util.JSOHelper;
import com.google.gwt.core.client.JavaScriptObject;
/**
* A Record contains attributes that are displayed and edited by a {@link com.smartgwt.client.widgets.DataBoundComponent}.
* <p/>
* DataBoundComponents have a concept of named fields, where values for each field are found
* under the same-named attribute in a Record.
* <p/>
* The concept of working with Records is common to all DataBoundComponents, although individual
* DataBoundComponents may work with singular records ({@link com.smartgwt.client.widgets.form.DynamicForm}) or may work with lists
* ({@link com.smartgwt.client.widgets.grid.ListGrid}), trees ({@link com.smartgwt.client.widgets.tree.TreeGrid}), or cubes
* (CubeGrid) of records.
* <p/>
* A Record is always the same type of Java object regardless of how the record is loaded (static
* data, java server, XML web service, etc). However, individual DataBoundComponents may also
* look for special attributes on Records which control styling or behavior. For convenience,
* there are subclasses of Record with type-safe setters for such attributes (such as {@link
* com.smartgwt.client.widgets.grid.ListGrid#setRecordEditProperty(String)}). In reality, all
* such subclasses are wrappers over the same underlying data object, and you can convert to
* whichever wrapper is most convenient via:
* <pre>
* new ListGridRecord(recordInstance.getJsObj());
* </pre>
* You can also create your own subclass of Record with type-specific getters and setters,
* however, if you do so, you should store values via setAttribute() and retrieve them via
* getAttribute() rather than keeping values as normal Java properties. Only attributes will
* be visible to DataBoundComponents, ordinary Java properties will not.
* <p/>
* Note that directly changing an attribute of a Record via setAttribute() will not notify any
* DataBoundComponents that the Record has changed or cause any kind of persistence operation
* to occur. Instead, use component-specific methods such as DynamicForm.setValue() or
* ListGrid.setEditValue() to explicitly tell the components about a change that should be
* saved.
*/
public class Record extends RefDataClass {
public static boolean isARecord(Object obj) {
return obj instanceof Record;
}
/**
* Creates a shallow copy of <code>record</code> containing its attributes for properties
* named in <code>properties</code>.
*
* @param record the record to copy attributes from.
* @param properties an array of properties to copy.
* @return a copy of <code>record</code> containing only the attributes for properties
* named in <code>properties</code>.
*/
public static Record copyAttributes(Record record, String... properties) {
Record copyOfRecord = new Record();
copyAttributesInto(copyOfRecord, record, properties);
return copyOfRecord;
}
/**
* Shallow copies the attributes of <code>record</code> to <code>destRecord</code> for
* properties named in <code>properties</code>.
*
* @param destRecord (out) destination record into which attributes are copied.
* @param record the record to copy attributes from.
* @param properties an array of properties to copy.
*/
public static void copyAttributesInto(Record destRecord, Record record, String... properties) {
for (String property : properties) {
if (property == null) continue;
Object attr = record.getAttributeAsObject(property);
destRecord.setAttribute(property, attr);
}
}
public Record() {
}
public Record(JavaScriptObject jsObj) {
super(jsObj);
}
public Record(Map recordProperties) {
JavaScriptObject jsObj = JSOHelper.convertMapToJavascriptObject(recordProperties);
this.setJsObj(jsObj);
}
public static Record getOrCreateRef(JavaScriptObject jsObj) {
if (jsObj == null) return null;
RefDataClass obj = RefDataClass.getRef(jsObj);
if (obj != null) {
obj.setJsObj(jsObj);
return (Record) obj;
} else {
return new Record(jsObj);
}
}
/**
* Returns the nested structure as Record array.
*
* @param property the record property
* @return array of records
*/
public Record[] getAttributeAsRecordArray(String property) {
return convertToRecordArray(getAttributeAsJavaScriptObject(property));
}
/**
* Returns the nested structure as a RecordList.
*
* @param property the record property
* @return the RecordList
*/
public RecordList getAttributeAsRecordList(String property) {
JavaScriptObject jsObject = getAttributeAsJavaScriptObject(property);
return jsObject == null ? null : new RecordList(jsObject);
}
public static Record[] convertToRecordArray(JavaScriptObject nativeArray) {
if (nativeArray == null) {
return new Record[]{};
}
if (JSOHelper.isArray(nativeArray)) {
JavaScriptObject[] componentsj = JSOHelper.toArray(nativeArray);
Record[] objects = new Record[componentsj.length];
for (int i = 0; i < componentsj.length; i++) {
JavaScriptObject componentJS = componentsj[i];
Record obj = (Record) RefDataClass.getRef(componentJS);
if (obj == null) obj = new Record(componentJS);
objects[i] = obj;
}
return objects;
} else {
Record[] ret = new Record[1];
ret[0] = Record.getOrCreateRef(nativeArray);
return ret;
}
}
/**
* Convert this record to a Map. This is a recursive conversion so if an attribute on this
* record is set to another Record instance it will also be converted to a Map.
* @return the Map
*/
public native Map toMap() /*-{
$wnd.SmartGWT._cleanSgwtProperties = true;
var jsObj = this.@com.smartgwt.client.data.Record::getJsObj()(),
map = @com.smartgwt.client.util.JSOHelper::convertToMap(Lcom/google/gwt/core/client/JavaScriptObject;)(jsObj);
delete $wnd.SmartGWT._cleanSgwtProperties;
return map;
}-*/;
}