/*
* � Copyright IBM Corp. 2011
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.ibm.xsp.extlib.designer.tooling.palette.view;
import static com.ibm.xsp.extlib.designer.tooling.constants.IExtLibAttrNames.EXT_LIB_ATTR_DATA;
import static com.ibm.xsp.extlib.designer.tooling.constants.IExtLibAttrNames.EXT_LIB_ATTR_VALUE;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import com.ibm.commons.iloader.node.DataNode;
import com.ibm.commons.iloader.node.DataNodeAdapter;
import com.ibm.commons.iloader.node.IAttribute;
import com.ibm.commons.iloader.node.IClassDef;
import com.ibm.commons.iloader.node.ILoader;
import com.ibm.commons.iloader.node.IMember;
import com.ibm.commons.iloader.node.NodeException;
import com.ibm.commons.iloader.node.collections.SingleCollection;
import com.ibm.commons.iloader.node.views.DataNodeBinding;
import com.ibm.commons.swt.SWTLayoutUtils;
import com.ibm.commons.swt.SWTUtils;
import com.ibm.commons.swt.controls.LookupComboBox;
import com.ibm.commons.swt.data.controls.DCPanel;
import com.ibm.commons.swt.data.controls.DCUtils;
import com.ibm.commons.swt.data.dialog.LWPDCommonDialog;
import com.ibm.commons.util.StringUtil;
import com.ibm.commons.xml.DOMUtil;
import com.ibm.designer.domino.scripting.api.IScriptData.PublishedObject;
import com.ibm.designer.domino.scripting.api.published.PublishedUtil;
import com.ibm.designer.domino.xsp.api.panels.IPanelExtraData;
import com.ibm.designer.domino.xsp.api.panels.PanelExtraData;
import com.ibm.designer.domino.xsp.api.panels.complex.ComplexPanelComposite;
import com.ibm.designer.domino.xsp.api.util.XPagesDOMUtil;
import com.ibm.designer.domino.xsp.api.util.XPagesDataUtil;
import com.ibm.designer.domino.xsp.api.util.XPagesKey;
import com.ibm.designer.domino.xsp.api.util.XPagesPropertiesViewUtils;
import com.ibm.designer.domino.xsp.registry.ComplexDesignerExtension;
import com.ibm.designer.domino.xsp.registry.DesignerExtensionUtil;
import com.ibm.designer.prj.resources.commons.DesignerProjectException;
import com.ibm.xsp.extlib.designer.tooling.constants.IExtLibAttrNames;
import com.ibm.xsp.extlib.designer.tooling.utils.ExtLibToolingLogger;
import com.ibm.xsp.extlib.designer.tooling.utils.XPagesKeyLookup;
import com.ibm.xsp.registry.FacesComplexDefinition;
import com.ibm.xsp.registry.FacesDefinition;
/**
* @author doconnor
*
*/
public class GenericViewDropDialog extends LWPDCommonDialog {
private IPanelExtraData extraData = null;
private IPanelExtraData realData = null;
private Node originalXPageViewNode = null;
private Node clonedXPageViewElement = null;
private DCPanel _mainPanel = null;
private Element viewDOMElement = null;
private DataNode viewDataNode = null;
private XPagesKeyLookup _dataSources = null;
private ComplexPanelComposite dynamicComposite;
private final static String PAGE_DS_NS = "p.d.s.n.s"; // $NON-NLS-1$
private LookupComboBox picker;
private DataNode childDataSourceDataNode;
private String title;
private String ns;
private String tag;
private DataNodeAdapter dataNodeAdapter = new DataNodeAdapter(){
/* (non-Javadoc)
* @see com.ibm.commons.iloader.node.DataNodeAdapter#onValueChanged(com.ibm.commons.iloader.node.DataNode, int, java.lang.Object, com.ibm.commons.iloader.node.IAttribute)
*/
@Override
public void onValueChanged(DataNode source, int record, Object object, IAttribute attribute) {
super.onValueChanged(source, record, object, attribute);
}
};
/**
* @param parentShell
*/
public GenericViewDropDialog(Shell parentShell, IPanelExtraData data, String title, String ns, String tag, Document doc) {
super(parentShell);
this.title = title;
this.ns = ns;
this.tag = tag;
if (data != null) {
realData = data;
// If doc is null then try to get it from the current node
if(doc == null) {
Node currentNode = data.getNode();
if (currentNode != null) {
doc = currentNode.getOwnerDocument();
}
}
// First find the <view> node on the page that we are dealing with..
originalXPageViewNode = XPagesDOMUtil.getViewNode(doc);
if (originalXPageViewNode != null) {
clonedXPageViewElement = originalXPageViewNode.cloneNode(false);
}
//clone the paneldata
extraData = new PanelExtraData();
((PanelExtraData) extraData).setDesignerProject(data.getDesignerProject());
((PanelExtraData) extraData).setNode(clonedXPageViewElement);
((PanelExtraData) extraData).setDocument(clonedXPageViewElement.getOwnerDocument());
((PanelExtraData) extraData).setHostWorkbenchPart(data.getHostWorkbenchPart());
((PanelExtraData) extraData).setWorkbenchPart(data.getWorkbenchPart());
}
}
/* (non-Javadoc)
* @see com.ibm.commons.swt.data.dialog.LWPDCommonDialog#getDialogTitle()
*/
@Override
protected String getDialogTitle() {
return StringUtil.isNotEmpty(title) ? title : "Select Data Source for Data View"; // $NLX-GenericViewDropDialog.Selectdatasourcefordataview-1$
}
/* (non-Javadoc)
* @see com.ibm.commons.swt.data.dialog.LWPDCommonDialog#fillClientArea(org.eclipse.swt.widgets.Composite)
*/
@Override
protected void fillClientArea(Composite parent) {
if (parent.getLayout() instanceof GridLayout) {
((GridLayout) parent.getLayout()).marginWidth = 7;
((GridLayout) parent.getLayout()).marginHeight = 0;
}
_mainPanel = new DCPanel(parent, SWT.NONE);
GridLayout layout = SWTLayoutUtils.createLayoutDefaultSpacing(1);
_mainPanel.setLayout(layout);
GridData data = SWTLayoutUtils.createGDFill();
data.horizontalSpan = 2;
_mainPanel.setLayoutData(data);
viewDataNode = initData(_mainPanel);
if(viewDataNode != null){
viewDataNode.addDataNodeListener(dataNodeAdapter);
}
Composite pickerParent = new Composite(_mainPanel, SWT.NONE);
pickerParent.setLayout(SWTLayoutUtils.createLayoutNoMarginDefaultSpacing(2));
pickerParent.setLayoutData(SWTLayoutUtils.createGDFillHorizontal());
new Label(pickerParent, SWT.NONE).setText("&Show data from:"); // $NLX-AddViewControlDialog.Showdatafrom-1$
picker = new LookupComboBox(pickerParent, SWT.DROP_DOWN | SWT.READ_ONLY, "datasource.id"); // $NON-NLS-1$
picker.setLayoutData(SWTLayoutUtils.createGDFillHorizontal());
picker.setFirstBlankLine(false);
picker.setEditableLabels(false);
picker.setLookup(_dataSources);
dynamicComposite = new ComplexPanelComposite(_mainPanel, SWT.NONE);
dynamicComposite.setLayoutData(GridDataFactory.copyData(data));
dynamicComposite.updatePanelData(realData);
picker.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
super.widgetSelected(event);
updateUI();
dynamicComposite.getDisplay().asyncExec(new Runnable() {
public void run() {
if (dynamicComposite.isDisposed()) {
return;
}
dynamicComposite.pack();
dynamicComposite.layout();
Composite parent = dynamicComposite.getParent();
Composite prevParent = parent;
while (parent != null && !parent.isDisposed()) {
try {
if (parent instanceof ScrolledComposite) {
((ScrolledComposite) parent).setMinSize(prevParent.computeSize(SWT.DEFAULT, SWT.DEFAULT));
break;
}
if(parent.isDisposed()){
return;
}
parent.pack();
parent.layout();
}
catch (Throwable t) {
if(ExtLibToolingLogger.EXT_LIB_TOOLING_LOGGER.isErrorEnabled()){
ExtLibToolingLogger.EXT_LIB_TOOLING_LOGGER.errorp(this, "widgetSelected", t, "Error encountered when refreshing UI"); // $NON-NLS-1$ $NLE-DataViewDataPanel.ErrorencounteredwhenrefeshingUI-2$
}
}
prevParent = parent;
parent = parent.getParent();
}
}
});
}
});
picker.select(0);
updateUI();
setMessage("Select the kind of data (the data source) to show in the view. You can also select the data source later in the Data properties for this view control.", // $NLX-AddViewControlDialog.Selectthekindofdatathedatasourcet-1$
IMessageProvider.INFORMATION);
Composite columns = new Composite(_mainPanel, SWT.NONE);
columns.setLayout(SWTLayoutUtils.createLayoutNoMarginDefaultSpacing(2));
Label l = new Label(columns, SWT.NONE);
l.setText("");
SWTUtils.setBackgroundColor(parent, parent.getBackground(), true);
parent.layout(true);
parent.pack();
}
private IClassDef getClassDef(ILoader xpagesDOMLoader, String ns, String tagName) {
try {
IClassDef classDef = xpagesDOMLoader.loadClass(ns, tagName);
return classDef;
}
catch (NodeException e) {
if(ExtLibToolingLogger.EXT_LIB_TOOLING_LOGGER.isErrorEnabled()){
String errMsg = "Internal error, failed to create an element for: {0}:{1}"; // $NLE-GenericViewDropDialog.Internalerrorfailedtocreateanelem-1$
ExtLibToolingLogger.EXT_LIB_TOOLING_LOGGER.errorp(this, "getClassDef", e, errMsg, ns, tagName); //$NON-NLS-1$
}
}
return null;
}
private DataNode initData(Composite parent) {
DataNode dn = DCUtils.findDataNode(parent, true); //modify the DataNode to refer to our dataView tag!!
ILoader xpagesDOMLoader = XPagesPropertiesViewUtils.getXPagesMultiDomLoader(extraData.getDesignerProject());
IClassDef classDef = getClassDef(xpagesDOMLoader, ns, tag);
dn.setClassDef(classDef);
try {
viewDOMElement = (Element) classDef.newInstance(clonedXPageViewElement);
}
catch (NodeException e) {
if(ExtLibToolingLogger.EXT_LIB_TOOLING_LOGGER.isErrorEnabled()){
String msg = "Failed to create a new instance of dataView tag"; // $NLE-GenericViewDropDialog.FailedtocreateanewinstanceofdataV-1$
ExtLibToolingLogger.EXT_LIB_TOOLING_LOGGER.errorp(this, "initData", e, msg); // $NON-NLS-1$
}
}
dn.setDataProvider(new SingleCollection(viewDOMElement));
updateLookup();
return dn;
}
/* (non-Javadoc)
* @see com.ibm.commons.swt.data.dialog.LWPDCommonDialog#needsProgressMonitor()
*/
@Override
protected boolean needsProgressMonitor() {
return false;
}
/* (non-Javadoc)
* @see com.ibm.commons.swt.data.dialog.LWPDCommonDialog#performDialogOperation(org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected boolean performDialogOperation(IProgressMonitor progressMonitor) {
return true;
}
private void updateDataNode(String value, XPagesKey key) throws NodeException{
try{
IMember dataAttr = viewDataNode.getMember(EXT_LIB_ATTR_DATA);
IMember valueAttr = viewDataNode.getMember(EXT_LIB_ATTR_VALUE);
//get the loader that is used to generate new Elements on the page
ILoader loader = viewDataNode.getLoader();
if(StringUtil.isEmpty(value)){ //probably not going to happen
//Clear all attribute values.. set everything back to null!
loader.setValue(viewDOMElement, (IAttribute)dataAttr, null, null);
viewDataNode.setValue((IAttribute)valueAttr, null, null);
if(childDataSourceDataNode != null){
childDataSourceDataNode.removeDataNodeListener(dataNodeAdapter);
}
return;
}
else{
//figure out which data source was selected from the combo box
if(StringUtil.equals(key.getNamespaceUri(), PAGE_DS_NS)){
if(childDataSourceDataNode != null){
childDataSourceDataNode.removeDataNodeListener(dataNodeAdapter);
}
//This means the user has picked a data source that is defined at the page level
if(valueAttr instanceof IAttribute){
String newVal = "#{" + value + "}";
viewDataNode.setValue((IAttribute)valueAttr, newVal, null);
//clear the data attribute also!
loader.setValue(viewDOMElement, (IAttribute)dataAttr, null, null);
dynamicComposite.getParent().setData(DCUtils.DATANODE_KEY,new DataNodeBinding(viewDataNode));
if(childDataSourceDataNode != null){
childDataSourceDataNode.removeDataNodeListener(this.dataNodeAdapter);
childDataSourceDataNode = null;
}
}
}else{
//need to clear the value attribute in case it was previously set
viewDataNode.setValue((IAttribute)valueAttr, null, null);
//Get a class defintion for a new instance of the given tag (probably xp:dominoView)
IClassDef def = loader.loadClass(key.getNamespaceUri(), key.getTagName());
Object o = def.newInstance(viewDOMElement); //create a new tag
//in this case we know that 'data' is a 'complex attribute'.. but lets make sure
if(dataAttr instanceof IAttribute && dataAttr.getType() == IMember.TYPE_OBJECT){
//add a <xp:this.data> to the current viewData tag and add the data source as a child of that!
viewDataNode.setObject(viewDOMElement, (IAttribute)dataAttr, o, null);
if(o instanceof Element && StringUtil.isEmpty(DOMUtil.getAttributeValue((Element)o, IExtLibAttrNames.EXT_LIB_ATTR_VAR))){
String[] vars = XPagesDOMUtil.getVars(((Element)o).getOwnerDocument(), null);
String var = XPagesDOMUtil.generateUniqueVar(Arrays.asList(vars), (Element)o, "view"); // $NON-NLS-1$
XPagesDOMUtil.setAttribute((Element)o, IExtLibAttrNames.EXT_LIB_ATTR_VAR, var);
}
}
DCUtils.initDataBinding(dynamicComposite.getParent());
DataNode dataNode = DCUtils.findDataNode(dynamicComposite.getParent(), true);
childDataSourceDataNode = dataNode;
if(childDataSourceDataNode != null){
dataNode.setClassDef(def);
dataNode.setDataProvider(new SingleCollection(o));
childDataSourceDataNode.addDataNodeListener(this.dataNodeAdapter);
}
}
}
}finally{
//Format the tag and update the UI
XPagesDOMUtil.formatNode(viewDOMElement, null);
}
}
private void updateLookup(){
//Get all of the data sources that support view data
List<FacesDefinition> defs = XPagesDataUtil.getViewPanelDataSources(extraData.getDesignerProject().getFacesRegistry());
if(defs != null){
ArrayList<String>names = new ArrayList<String>();
ArrayList<XPagesKey>keys = new ArrayList<XPagesKey>();
for(FacesDefinition def : defs){
String name = def.getTagName();
if(def instanceof FacesComplexDefinition){
//Get the display name for the data sources
ComplexDesignerExtension extsn = DesignerExtensionUtil.getComplexExtension((FacesComplexDefinition) def);
if (extsn != null) {
name = StringUtil.getNonNullString(extsn.getDisplayName());
}
}
names.add(name);
keys.add(new XPagesKey(def.getNamespaceUri(), def.getTagName()));
}
Map <String, PublishedObject> map = new HashMap<String, PublishedObject>();
try {
//Get all of the view data sources already defined in the XSP hierarchy
PublishedUtil.getAllPublishedObjects(map, originalXPageViewNode, extraData.getDesignerProject(), false);
} catch (DesignerProjectException e) {
if(ExtLibToolingLogger.EXT_LIB_TOOLING_LOGGER.isErrorEnabled()){
ExtLibToolingLogger.EXT_LIB_TOOLING_LOGGER.errorp(this, "updateLookup", e,//$NON-NLS-1$
"Failed to find any data sources defined on the page.. An error was encountered by the published object utilities"); // $NLE-GenericViewDropDialog.Failedtofindanydatasourcesdefined-1$
}
}
if(!map.isEmpty()){
Set<String> dsNames = map.keySet();
for(String name : dsNames){
PublishedObject po = map.get(name);
if(PublishedUtil.isViewDataSupported(po)){
names.add(name);
//These are special data sources.. Page level data sources.. We will use a complex panel to display the information
//to be displayed in the event of one of these being used..
//See: com.ibm.xsp.extlib.designer.tooling.panels.complex.PageDataSourcePanel
keys.add(new XPagesKey(PAGE_DS_NS, "pageDataSource")); // $NON-NLS-1$
}
}
}
_dataSources = new XPagesKeyLookup(keys.toArray(new XPagesKey[0]), names.toArray(new String[0]));
}
}
private void updateUI(){
if (!picker.isDisposed()) {
String value = picker.getValue();
if(StringUtil.isNotEmpty(value)){
for(int i = 0; i < _dataSources.size(); i++){
if(StringUtil.equals(_dataSources.getCode(i), value)){
XPagesKey key = _dataSources.getKey(i);
if(key != null){
try {
updateDataNode(value, key);
} catch (NodeException e) {
ExtLibToolingLogger.EXT_LIB_TOOLING_LOGGER.error(e, e.toString());
}
dynamicComposite.updatePanel(key.getNamespaceUri(), key.getTagName());
SWTUtils.setBackgroundColor(dynamicComposite.getParent(), dynamicComposite.getParent().getBackground(), true);
}
}
}
}
}
}
/* (non-Javadoc)
* @see com.ibm.commons.swt.data.dialog.LWPDCommonDialog#useScrollableContents()
*/
@Override
protected boolean useScrollableContents() {
return false;
}
public Element getElementToInsert(){
return viewDOMElement;
}
}