Source: widgets/advCtrls/kekule.widget.configurators.js

/**
 * Created by ginger on 2015/1/28.
 */

/*
 * requires /lan/classes.js
 * requires /utils/kekule.utils.js
 * requires /utils/kekule.domUtils.js
 * requires /xbrowsers/kekule.x.js
 * requires /widgets/kekule.widget.base.js
 * requires /widgets/operation/kekule.actions.js
 * requires /widgets/commonCtrls/kekule.widget.container.js
 * requires /widgets/commonCtrls/kekule.widget.tabViews.js
 * requires /widgets/advCtrls/objInspector/kekule.widget.objInspector.js
 */


(function(){
"use strict";

/** @ignore */
Kekule.Widget.HtmlClassNames = Object.extend(Kekule.Widget.HtmlClassNames, {
	WIDGET_CONFIGURATOR: 'K-Widget-Configurator',
	WIDGET_CONFIGURATOR_CLIENT: 'K-Widget-Configurator-Client',

	ACTION_OPEN_CONFIGURATOR: 'K-Action-Open-Configurator'
});
var CNS = Kekule.Widget.HtmlClassNames;

/**
 * A special widget class to open a config widget for ChemObjDisplayer.
 * Do not use this widget alone.
 * @class
 * @augments Kekule.Widget.Panel
 *
 * @param {Kekule.Widget.BaseWidget} widget
 * @property {Bool} autoUpdate Whether load and save config values automatically when configurator is shown or hide.
 */
/**
 * Invoked when the config has been changed. Event param of it has fields: {object, propertyName, oldValue, newValue}.
 * @name Kekule.Widget.Configurator#configChange
 * @event
 */
Kekule.Widget.Configurator = Class.create(Kekule.Widget.Panel,
/** @lends Kekule.Widget.Configurator# */
{
	/** @private */
	CLASS_NAME: 'Kekule.Widget.Configurator',
	/** @private */
	TAB_BTN_DATA_FIELD: '__$data__',
	/** @private */
	DEF_TAB_POSITION: Kekule.Widget.Position.RIGHT,
	/** @construct */
	initialize: function($super, widget)
	{
		this.setPropStoreFieldValue('widget', widget);
		this._objInspector = null;
		this._tabGroup = null;
		$super(widget);
	},
	/** @private */
	initProperties: function()
	{
		this.defineProp('widget', {'dataType': 'Kekule.Widget.BaseWidget', 'serializable': false});
		this.defineProp('autoUpdate', {'dataType': DataType.BOOL});
		// TODO: tabPosition now is not totally workable
		this.defineProp('tabPosition', {'dataType': DataType.INT,
			'setter': function(value)
			{
				this.setPropStoreFieldValue('tabPosition', value);
				if (this._tabGroup)
					this._tabGroup.setTabButtonPosition(value || this.DEF_TAB_POSITION);
			}
		});
	},
	/** @ignore */
	initPropValues: function($super)
	{
		$super();
		this.setLayout(Kekule.Widget.Layout.HORIZONTAL);
	},
	/** @ignore */
	doGetWidgetClassName: function($super)
	{
		return $super() + ' ' + CNS.WIDGET_CONFIGURATOR;
	},
	/** @ignore */
	doCreateRootElement: function(doc)
	{
		var result = doc.createElement('div');
		return result;
	},
	/** @ignore */
	doCreateSubElements: function($super, doc, element)
	{
		var result = [];

		var rootElem = doc.createElement('div');
		rootElem.className = CNS.WIDGET_CONFIGURATOR_CLIENT;
		result.push(rootElem);

		// obj inspector
		var objInspector = new Kekule.Widget.ObjectInspector(this);
		objInspector.setShowObjsInfoPanel(false);
		objInspector.setSortField(null);
		objInspector.appendToElem(rootElem);
		this._objInspector = objInspector;
		objInspector.addEventListener('propertyChange', function(e){
			this.invokeEvent('configChange', {
				'obj': objInspector.getObjects()[0], 'propertyName': e.propertyInfo.name,
				'oldValue': e.oldValue, 'newValue': e.newValue
			});
			//console.log(objInspector.getObjects()[0]);
		}, this);

		// tab head
		var categories = this.getCategoryInfos();
		var tabBtnGroup = new Kekule.Widget.TabButtonGroup(this);
		this._tabGroup = tabBtnGroup;
		//console.log('tab position', this.getTabPosition());
		tabBtnGroup.setTabButtonPosition(this.getTabPosition() || this.DEF_TAB_POSITION/*Kekule.Widget.Position.RIGHT*/);
		var firstBtn;
		for (var i = 0, l = categories.length; i < l; ++i)
		{
			var c = categories[i];
			var btn = new Kekule.Widget.RadioButton(tabBtnGroup);
			btn.setText(c.title || c.name);
			btn.setHint(c.description || '');
			btn[this.TAB_BTN_DATA_FIELD] = c.obj;
			btn.appendToWidget(tabBtnGroup);
			if (i === 0)
			{
				firstBtn = btn;
			}
		}
		tabBtnGroup.addEventListener('execute', function(e){
			var btn = e.widget;
			if (btn instanceof Kekule.Widget.RadioButton)
				this._switchToTab(btn);
		}, this);
		tabBtnGroup.appendToElem(rootElem);
		if (categories.length <= 1)
			tabBtnGroup.setDisplayed('none');

		// switch
		firstBtn.setChecked(true);
		this._switchToTab(firstBtn);

		element.appendChild(rootElem);

		return result;
	},

	/** @ignore */
	doWidgetShowStateChanged: function($super, isShown)
	{
		$super(isShown);
		if (this.getAutoUpdate())
		{
			if (isShown)
				this.loadConfigValues();
			else
				this.saveConfigValues();
		}
	},

	/**
	 * Load config setting values from widget.
	 * Descendants may override this method.
	 */
	loadConfigValues: function()
	{
		// do nothing here
	},
	/**
	 * Save config setting values back to widget.
	 * Descendants may override this method.
	 */
	saveConfigValues: function()
	{
		// do nothing here
	},

	/**
	 * Get settings category, descendants need to override this method.
	 * @returns {Array}
	 */
	getCategoryInfos: function()
	{
		var widget = this.getWidget();
		var result = [];
		// configFacade
		var facade = widget.getSettingFacade();
		if (facade)
		{
			var propInfo = widget.getPropInfo('settingFacade');
			result.push({
				'obj': facade,
				'name': propInfo.name,
				'title': propInfo.title,
				'descrption': propInfo.description
			});
		}

		/*
		// renderConfigs and displayerConfigs
		var configObjs = [displayer.getDisplayerConfigs(), displayer.getRenderConfigs()];
		for (var j = 0, k = configObjs.length; j < k; ++j)
		{
			var config = configObjs[j];
			var props = config.getPropListOfScopes([Class.PropertyScope.PUBLISHED]);
			for (var i = 0, l = props.getLength(); i < l; ++i)
			{
				var propInfo = props.getPropInfoAt(i);
				var obj = config.getPropValue(propInfo.name);
				if (obj)
				{
					result.push({
						'obj': obj,
						'name': propInfo.name,
						'title': propInfo.title,
						'description': propInfo.description
					});
				}
			}
		}
		*/
		return result;
	},
	/** @private */
	_switchToTab: function(tabBtn)
	{
		var obj = tabBtn[this.TAB_BTN_DATA_FIELD];
		this._objInspector.setObjects(obj);
	}
});

/**
 * Action for open a widget to change widget configs.
 * @class
 * @augments Kekule.ActionDisplayerOpenConfigWidget
 */
Kekule.Widget.ActionOpenConfigWidget = Class.create(Kekule.Action,
/** @lends Kekule.Widget.ActionOpenConfigWidget# */
{
	/** @private */
	CLASS_NAME: 'Kekule.Widget.ActionOpenConfigWidget',
	/** @private */
	HTML_CLASSNAME: CNS.ACTION_OPEN_CONFIGURATOR,
	/** @constructs */
	initialize: function($super, widget)
	{
		$super();
		this.setWidget(widget);
		this.setText(/*Kekule.WidgetTexts.CAPTION_CONFIG*/Kekule.$L('WidgetTexts.CAPTION_CONFIG'));
		this.setHint(/*Kekule.WidgetTexts.HINT_CONFIG*/Kekule.$L('WidgetTexts.HINT_CONFIG'));
	},
	/** @private */
	initProperties: function()
	{
		this.defineProp('widget', {'dataType': 'Kekule.Widget.BaseWidget', 'serializable': false});
	},
	/** @private */
	doUpdate: function()
	{
		var w = this.getWidget();
		this.setEnabled(w && w.getEnabled());
	},
	/** @private */
	doExecute: function(target)
	{
		this.getWidget().openConfigurator(target);
	}
});

ClassEx.extend(Kekule.Widget.BaseWidget,
/** @lends Kekule.Widget.BaseWidget# */
{
	/** @private */
	getSettingFacadeClass: function()
	{
		var c = this.getClass();
		var result = null;
		do
		{
			var className = ClassEx.getClassName(c) + '.Settings';
			result = ClassEx.findClass(className);
			c = ClassEx.getSuperClass(c);
		}
		while (c && !result)

		return result;
	},

	/**
	 * Returns configurator class of displayer. Descendants may override this method.
	 * @returns {Class}
	 * @private
	 */
	getConfiguratorClass: function()
	{
		var c = this.getClass();
		var result = null;
		do
		{
			var className = ClassEx.getClassName(c) + '.Configurator';
			result = ClassEx.findClass(className);
			c = ClassEx.getSuperClass(c);
		}
		while (c && !result)

		return result;
	},
	/**
	 * Create a new configurator.
	 * @private
	 */
	createConfigurator: function()
	{
		var cclass = this.getConfiguratorClass();
		return new cclass(this);
	},
	/**
	 * Returns widget instance of configurator.
	 * @returns {Kekule.Widget.BaseWidget}
	 */
	getConfigurator: function()
	{
		if (!this._configurator)
		{
			this._configurator = this.createConfigurator();
		}
		return this._configurator;
	},
	/**
	 * Open a popup configurator to modify settings of displayer.
	 * @param {Kekule.Widget.BaseWidget} callerWidget Who invokes the action.
	 */
	openConfigurator: function(callerWidget)
	{
		var c = this.getConfigurator();
		//c.appendToWidget(this);
		c.show(callerWidget || this, null, Kekule.Widget.ShowHideType.DROPDOWN);
	}
});

ClassEx.defineProp(Kekule.Widget.BaseWidget, 'settingFacade', {'dataType': DataType.OBJECTEX, 'serializable': false, 'scope': Class.PropertyScope.PUBLIC,
	'setter': null,
	'getter': function()
	{
		var result = this.getPropStoreFieldValue('settingFacade');
		if (!result)
		{
			var c = this.getSettingFacadeClass();
			if (c)
			{
				result = new c(this);
				this.setPropStoreFieldValue('settingFacade', result);
			}
		}
		return result;
	}
});

/**
 * A special class to give a setting facade for BaseWidget.
 * Should use the following naming pattern: BaseClass.Settings (e.g. Kekule.ChemObject.Settings).
 * Do not use this class alone.
 * @class
 * @augments ObjectEx
 *
 * @param {Kekule.Widget.BaseWidget} widget
 * @ignore
 */
Kekule.Widget.BaseWidget.Settings = Class.create(ObjectEx,
/** @lends Kekule.Widget.BaseWidget.Settings# */
{
	/** @private */
	CLASS_NAME: 'Kekule.Widget.BaseWidget.Settings',
	/** @construct */
	initialize: function($super, widget)
	{
		this._basedClass = null;
		$super();
		this.setWidget(widget);
	},
	/** @private */
	initProperties: function()
	{
		this.defineProp('widget', {'dataType': 'Kekule.Widget.BaseWidget', 'serializable': false, 'scope': Class.PropertyScope.PUBLIC});
		//this.defineProp('widgetClass', {'dataType': DataType.CLASS, 'serializable': false, 'setter': null, 'scope': Class.PropertyScope.PUBLIC});
	},
	/** @private */
	getBasedClass: function()
	{
		if (!this.hasOwnProperty('_basedClass') || !this._basedClass) // important, must check own property to avoid conflict by parent classes
		{
			var className = this.getClassName();
			var cascadeNames = className.split('.');
			cascadeNames.pop();  // remove '.Settings'
			className = cascadeNames.join('.');
			this._basedClass = ClassEx.findClass(className);
		}
		return this._basedClass;
	},
	/**
	 * Define property that directly mapped to widget's property.
	 * @param {String} propName
	 * @param {String} widgetPropName Name of corresponding property in widget.
	 * @return {Object} Property info object added to property list.
	 * @private
	 */
	defineDelegatedProp: function(propName, widgetPropName)
	{
		if (!widgetPropName)
			widgetPropName = propName;
		var widgetPropInfo = ClassEx.getPropInfo(this.getBasedClass(), widgetPropName);
		/*
		 var propOptions = {
		 'serializable': widgetPropInfo.serializable,
		 'dataType': widgetPropInfo.dataType,
		 'title': widgetPropInfo.title,
		 'description': widgetPropInfo.description,
		 'getter': null,
		 'setter': null
		 };
		 */
		var propOptions = Object.create(widgetPropInfo);
		// clear getter and setter
		propOptions.setter = null;
		propOptions.getter = null;
		if (widgetPropInfo.getter)
		{
			propOptions.getter = function()
			{
				//console.log('get delegate value', widgetPropName, this.getWidget().getPropValue(widgetPropName));
				return this.getWidget().getPropValue(widgetPropName);
			};
		}
		if (widgetPropInfo.setter)
		{
			propOptions.setter = function(value)
			{
				this.getWidget().setPropValue(widgetPropName, value);
			}
		}
		//console.log('define delegate prop', propOptions);
		this.defineProp(propName, propOptions);
	},
	/**
	 * Define a series of property that directly mapped to widget's property.
	 * @param {Array} propNames
	 * @param {Array} widgetPropNames Names of corresponding property in widget.
	 * @private
	 */
	defineDelegatedProps: function(propNames, widgetPropNames)
	{
		if (!widgetPropNames)
			widgetPropNames = [];
		for (var i = 0, l = propNames.length; i < l; ++i)
		{
			var propName = propNames[i];
			var widgetPropName = widgetPropNames[i] || propName;
			this.defineDelegatedProp(propName, widgetPropName);
		}
	}
});


})();