/**
* @fileoverview
* A tree widget to display the internal structure of chem object (such as ChemSpace, Molecule and so on).
* @author Partridge Jiang
*/
/*
* requires /lan/classes.js
* requires /utils/kekule.utils.js
* requires /widgets/kekule.widget.nestedContainers.js
* requires /widgets/commonCtrls/kekule.widget.treeViews.js
* requires /widgets/chem/kekule.chemWidget.base.js
*/
(function(){
"use strict";
var CCNS = Kekule.ChemWidget.HtmlClassNames;
/** @ignore */
Kekule.ChemWidget.HtmlClassNames = Object.extend(Kekule.ChemWidget.HtmlClassNames, {
CHEM_STRUCT_TREE_VIEW: 'K-Chem-Struct-TreeView',
CHEM_STRUCT_TREE_VIEW_ITEM_TITLE: 'K-Chem-Struct-TreeView-ItemTitle',
CHEM_STRUCT_TREE_VIEW_ITEM_TYPE: 'K-Chem-Struct-TreeView-ItemType'
});
/**
* An tree view widget to display internal relationship of chem objects.
* @class
* @augments Kekule.Widget.TreeView
*
* @param {Variant} parentOrElementOrDocument
* @param {Kekule.ChemObject} rootObj
*
* @property {Kekule.ChemObject} rootObj Root chem object to be displayed in tree view.
* @property {Bool} enableLiveUpdate If set to true, the tree view will automatically updated when chem objects changed.
*/
Kekule.ChemWidget.StructureTreeView = Class.create(Kekule.Widget.TreeView,
/** @lends Kekule.ChemWidget.StructureTreeView# */
{
/** @private */
CLASS_NAME: 'Kekule.ChemWidget.StructureTreeView',
/** @construct */
initialize: function($super, parentOrElementOrDocument, rootObj)
{
$super(parentOrElementOrDocument);
this.setPropStoreFieldValue('objMap', new Kekule.MapEx(true));
this.setEnableLiveUpdate(true);
this.setEnableMultiSelected(true);
this.setRootObj(rootObj);
this._pauseLiveUpdateFlag = 0;
this._changedObjects = [];
},
/** @private */
initProperties: function()
{
this.defineProp('rootObj', {'dataType': 'Kekule.ChemObject', 'serializable': false,
'setter': function(value)
{
var oldObj = this.getPropStoreFieldValue('rootObj');
this.setPropStoreFieldValue('rootObj', value);
this.rootObjChanged(value, oldObj);
}
});
this.defineProp('enableLiveUpdate', {'dataType': DataType.BOOL});
this.defineProp('objMap', {'dataType': 'Kekule.MapEx', 'setter': null, 'serializable': false}); // private property
},
/** @ignore */
doGetWidgetClassName: function($super)
{
return $super() + ' ' + CCNS.CHEM_STRUCT_TREE_VIEW;
},
/** @private */
rootObjChanged: function(newValue, oldValue)
{
this.clearChildItems();
this.getObjMap().clear();
if (oldValue)
this._uninstallRootEventHandler(oldValue);
if (newValue)
{
this._fillTree(newValue);
this._installRootEventHandler(newValue);
}
},
/**
* Pause the live update process.
* Changed objects will be stored and the corresponding tree items will be refreshed
* after the live update is resumed.
*/
pauseLiveUpdate: function()
{
if (this._pauseLiveUpdateFlag >= 0)
{
this._pauseLiveUpdateFlag = 0;
this._changedObjects = [];
}
--this._pauseLiveUpdateFlag;
return this;
},
/**
* Resume the live update process.
*/
resumeLiveUpdate: function()
{
++this._pauseLiveUpdateFlag;
if (this._pauseLiveUpdateFlag >= 0) // do actual resume
{
this._pauseLiveUpdateFlag = 0;
for (var i = 0, l = this._changedObjects.length; i < l; ++i)
{
this.refreshObject(this._changedObjects[i]);
}
}
},
isLiveUpdatePaused: function()
{
return (this._pauseLiveUpdateFlag < 0);
},
/** @private */
_installRootEventHandler: function(root)
{
root.addEventListener('change', this.reactChemObjChange, this);
},
/** @private */
_uninstallRootEventHandler: function(root)
{
root.removeEventListener('change', this.reactChemObjChange, this);
},
/** @private */
reactChemObjChange: function(e)
{
if (this.getEnableLiveUpdate())
{
if (this.isLiveUpdatePaused())
{
if (this.getObjMap().get(e.target))
Kekule.ArrayUtils.pushUnique(this._changedObjects, e.target);
}
else
{
this.refreshObject(e.target);
}
}
},
/**
* Refresh tree item on chemObj.
* @param {Kekule.ChemObject} chemObj
*/
refreshObject: function(chemObj)
{
// get corresponding tree node
var treeItem = this.getObjMap().get(chemObj);
if (treeItem)
{
this._updateTreeItem(treeItem, chemObj);
}
return this;
},
/**
* Fill tree with rootObj data.
* @param {Kekule.ChemObject} rootObj
* @private
*/
_fillTree: function(rootObj)
{
if (rootObj)
{
this.clearChildItems();
this._updateTreeItem(this.appendChildItem(), rootObj);
}
},
/**
* Update tree item properties according to chemObj data.
* @param {HTMLElement} treeItem
* @param {Kekule.ChemObject} chemObj
* @private
*/
_updateTreeItem: function(treeItem, chemObj)
{
//console.log('update tree', chemObj.getClassName());
var title = this._getChemObjDisplayTitle(chemObj);
var data = {'text': title, 'obj': chemObj};
this.setItemData(treeItem, data);
this.getObjMap().set(chemObj, treeItem);
//this.clearChildItems(treeItem);
var oldChildItemCount = this.getChildItemCount(treeItem);
var l = chemObj.getChildCount();
for (var i = 0; i < l; ++i)
{
var child = chemObj.getChildAt(i);
/*
if (!child.isSelectable())
continue;
*/
//var childItem = this.appendChildItem(treeItem);
var childItem;
if (i < oldChildItemCount)
childItem = this.getChildItemAt(treeItem, i);
else
childItem = this.appendChildItem(treeItem);
this._updateTreeItem(childItem, child);
}
// remove extra tree nodes
if (oldChildItemCount > l)
{
for (var i = oldChildItemCount - 1; i >= l; --i)
{
this.removeChildItemAt(treeItem, i);
}
}
},
/** @private */
_getChemObjDisplayTitle: function(chemObj)
{
var result = '';
var id = chemObj.getId();
if (id)
result += '<span class="' + CCNS.CHEM_STRUCT_TREE_VIEW_ITEM_TITLE + '">' + id + '</span>';
var className = chemObj.getClassName();
// get last part of className
var cnameParts = className.split('.');
var cname = cnameParts.length? cnameParts[cnameParts.length - 1]: className;
var stype = '<span class="' + CCNS.CHEM_STRUCT_TREE_VIEW_ITEM_TYPE + '">(' + cname + ')</span>';
//return result + '(' + cname + ')';
return result + stype;
},
/**
* Make tree items corresponding to chemObjs to be selected.
* @param {Array} chemObjs
*/
selectChemObjs: function(chemObjs)
{
var items = [];
for (var i = 0, l = chemObjs.length; i < l; ++i)
{
var obj = chemObjs[i];
var item = this.getObjMap().get(obj);
if (item)
items.push(item);
}
this.select(items);
return this;
},
/**
* Returns corresponding chemObjs linked to selected tree items.
* @returns {Array}
*/
getSelectedChemObjs: function()
{
var result = [];
var items = this.getSelection();
if (items && items.length)
{
for (var i = 0, l = items.length; i < l; ++i)
{
var data = this.getItemData(items[i]);
if (data && data.obj)
result.push(data.obj);
}
}
return result;
}
});
})();