// ============================================================================
//
// Copyright (C) 2006-2016 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================
package com.amalto.workbench.dialogs;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.emf.common.util.EList;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.xsd.XSDComplexTypeDefinition;
import org.eclipse.xsd.XSDElementDeclaration;
import org.eclipse.xsd.XSDModelGroup;
import org.eclipse.xsd.XSDParticle;
import org.eclipse.xsd.XSDSchema;
import org.eclipse.xsd.XSDTerm;
import org.eclipse.xsd.XSDTypeDefinition;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.amalto.workbench.i18n.Messages;
import com.amalto.workbench.image.ImageCache;
import com.amalto.workbench.utils.Util;
import com.amalto.workbench.webservices.TMDMService;
import com.amalto.workbench.webservices.WSDataModel;
import com.amalto.workbench.webservices.WSDataModelPK;
import com.amalto.workbench.webservices.WSGetDataModel;
import com.amalto.workbench.widgets.xmlviewer.XMLConfiguration;
import com.amalto.workbench.widgets.xmlviewer.XMLSourceViewer;
import com.amalto.workbench.widgets.xmlviewer.XMLSourceViewerHelper;
import com.amalto.workbench.widgets.xmlviewer.contentassist.IKeyWordProvider;
public class DOMViewDialog extends Dialog implements IKeyWordProvider {
private static Log log = LogFactory.getLog(DOMViewDialog.class);
public final static int BUTTON_CLOSE = 10;
public final static int BUTTON_SAVE = 15;
public final static int BUTTON_CANCEL = 20;
public final static int TREE_VIEWER = 0;
public final static int SOURCE_VIEWER = 1;
protected Node node;
protected TreeViewer domViewer;
protected XMLSourceViewer sourceViewer;
protected Combo dataModelCombo;
protected TabFolder tabFolder;
protected int firstTab = TREE_VIEWER;
protected Label mcLable = null;
// protected boolean elementChanged = false;
private int buttonPressed = 0;
private boolean editable = false;
private Collection<String> dataModelNames;
private String selectedDataModel;
private String desc;
private Collection<Listener> listeners = new ArrayList<Listener>();
private final TMDMService port;
public DOMViewDialog(Shell parentShell, Node node) {
this(parentShell, null, node, false, null, TREE_VIEWER, null);
}
public DOMViewDialog(Shell parentShell, Node node, boolean editable, Collection<String> dataModelNames, int firstTab,
String selectedDataModel, String desc) {
this(parentShell, null, node, editable, dataModelNames, firstTab, selectedDataModel);
this.desc = desc;
}
public DOMViewDialog(Shell parentShell, TMDMService port, Node node, boolean editable, Collection<String> dataModelNames,
int firstTab, String selectedDataModel) {
super(parentShell);
this.port = port;
this.node = node;
this.editable = editable;
this.dataModelNames = new ArrayList<String>();
if (dataModelNames != null) {
this.dataModelNames.addAll(dataModelNames);
}
this.firstTab = firstTab;
this.selectedDataModel = selectedDataModel;
setShellStyle(getShellStyle() | SWT.RESIZE | SWT.MAX);
}
@Override
protected Control createDialogArea(Composite parent) {
try {
// Should not really be here but well,....
if (editable) {
parent.getShell().setText(Messages.DOMViewDialog_EditorViewer);
} else {
parent.getShell().setText(Messages.DOMViewDialog_Viewer);
}
Composite composite = new Composite(parent, SWT.NULL);
GridLayout layout = new GridLayout();
layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
composite.setLayout(layout);
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
applyDialogFont(composite);
if (desc != null && desc.length() > 0) {
new Label(composite, SWT.NONE).setText(desc);
}
tabFolder = new TabFolder(composite, SWT.TOP | SWT.H_SCROLL | SWT.V_SCROLL);
tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
((GridData) tabFolder.getLayoutData()).heightHint = 600;
((GridData) tabFolder.getLayoutData()).widthHint = 600;
tabFolder.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
}
public void widgetSelected(SelectionEvent e) {
if (tabFolder.getSelectionIndex() == 0) {
if (node == null) {
try {
if (sourceViewer == null || sourceViewer.getDocument() == null) {
return;
}
node = Util.parse(sourceViewer.getText());
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
tabFolder.setSelection(1);
MessageDialog.openError(DOMViewDialog.this.getShell(), Messages.DOMViewDialog_XMLInvalid,
Messages.bind(Messages.DOMViewDialog_XMLInvalidInfo, ex.getLocalizedMessage()));
return;
}
domViewer.setInput(node);
domViewer.expandAll();
}
} else if (tabFolder.getSelectionIndex() == 1) {
try {
sourceViewer.setText(Util.nodeToString(node));
node = null; // this should be better implemented in a change listener on the text
} catch (Exception ex) {
MessageDialog.openError(DOMViewDialog.this.getShell(), Messages.DOMViewDialog_ErrorTitle,
Messages.bind(Messages.DOMViewDialog_ErrorMsg, ex.getLocalizedMessage()));
sourceViewer.setText(""); //$NON-NLS-1$
}
}
}// widget Selected
});
TabItem tiDOM = new TabItem(tabFolder, SWT.NULL);
tiDOM.setText(Messages.DOMViewDialog_Tree);
tiDOM.setToolTipText(Messages.DOMViewDialog_DisplayAsDomTree);
domViewer = new TreeViewer(tabFolder, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
domViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
// ((GridData)domViewer.getControl().getLayoutData()).heightHint=300;
// ((GridData)domViewer.getControl().getLayoutData()).widthHint=300;
domViewer.setSorter(null);
domViewer.setLabelProvider(new DOMTreeLabelProvider());
domViewer.setContentProvider(new DOMTreeContentProvider());
domViewer.setInput(node);
domViewer.expandAll();
domViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
tiDOM.setControl(domViewer.getControl());
TabItem tiSource = new TabItem(tabFolder, SWT.NULL);
tiSource.setText(Messages.DOMViewDialog_TiSourceText);
tiSource.setToolTipText(Messages.DOMViewDialog_TiSourceTip);
XMLSourceViewerHelper sourceViewerHelper = XMLSourceViewerHelper.getInstance();
sourceViewer = new XMLSourceViewer(tabFolder, sourceViewerHelper.createVerticalRuler(),
sourceViewerHelper.createOverviewRuler(), true, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
XMLConfiguration sourceViewerConfiguration = new XMLConfiguration(this);
sourceViewer.configure(sourceViewerConfiguration);
sourceViewer.initilize();
sourceViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
sourceViewer.setText(Util.nodeToString(node));
sourceViewer.setEditable(this.editable);
/*
* sourceViewer.addTextListener( new ITextListener() { public void
* textChanged(org.eclipse.jface.text.TextEvent event) { if ((event.getText()==null) ||
* ("".equals(event.getText()))) return; node = null; elementChanged = true; } } );
*/
tiSource.setControl(sourceViewer.getControl());
tabFolder.setSelection(firstTab);
if (firstTab == SOURCE_VIEWER) {
node = null; // force refresh of tree
}
return composite;
} catch (Exception e) {
log.error(e.getMessage(), e);
MessageDialog.openError(this.getShell(), Messages._Error,
Messages.bind(Messages.DOMViewDialog_ErrorMsg1, e.getLocalizedMessage()));
return null;
}
}
public int getButtonPressed() {
return buttonPressed;
}
public String getDataModelName() {
return dataModelCombo.getText();
}
public Node getNode() {
return this.node;
}
public String getXML() {
return sourceViewer.getText();
}
private Map<String, String[]> keyWordMap = new HashMap<String, String[]>();
private void updateKeyMap(String dataModelName) {
if (dataModelName == null || port == null) {
return;
}
if (keyWordMap.get(dataModelName) == null) {
WSGetDataModel wsGetModel = new WSGetDataModel(new WSDataModelPK(dataModelName));
try {
WSDataModel dataModel = port.getDataModel(wsGetModel);
String xsdSchemaStr = dataModel.getXsdSchema();
if (xsdSchemaStr != null) {
XSDSchema schema = Util.getXSDSchema(xsdSchemaStr);
Set<String> allKeyWords = getAllKeyWords(schema);
if (!allKeyWords.isEmpty()) {
String[] keys = allKeyWords.toArray(new String[0]);
Arrays.sort(keys);
keyWordMap.put(dataModelName, keys);
}
}
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
}
}
}
public String[] getCurrentKeyWords() {
String dataModelName = dataModelCombo.getText();
if (dataModelName != null) {
return keyWordMap.get(dataModelName);
}
return null;
}
private Set<String> getAllKeyWords(XSDSchema schema) {
Set<String> keys = new HashSet<String>();
for (XSDElementDeclaration elementDecl : schema.getElementDeclarations()) {
collectKeyWords(elementDecl, keys);
}
return keys;
}
private void collectKeyWords(XSDElementDeclaration elementDeclaration, Set<String> keys) {
String elementName = elementDeclaration.getName();
keys.add(elementName);
XSDTypeDefinition typeDefinition = elementDeclaration.getType();
if (typeDefinition instanceof XSDComplexTypeDefinition) {
XSDParticle particle = (XSDParticle) ((XSDComplexTypeDefinition) typeDefinition).getContent();
XSDTerm term = particle.getTerm();
if (term instanceof XSDModelGroup) {
EList<XSDParticle> particles = ((XSDModelGroup) term).getContents();
for (XSDParticle p : particles) {
XSDTerm childTerm = p.getTerm();
if (childTerm instanceof XSDElementDeclaration) {
collectKeyWords((XSDElementDeclaration) childTerm, keys);
}
}
}
}
}
@Override
protected void createButtonsForButtonBar(Composite parent) {
if (!editable) {
createButton(parent, BUTTON_CLOSE, Messages.Close, true);
} else {
mcLable = new Label(parent, SWT.RIGHT);
mcLable.setText(Messages.DOMViewDialog_DataModel);
dataModelCombo = new Combo(parent, SWT.DROP_DOWN | SWT.READ_ONLY);
String[] dms = dataModelNames.toArray(new String[dataModelNames.size()]);
Arrays.sort(dms);
dataModelCombo.setItems(dms);
dataModelCombo.select(-1);
dataModelCombo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
String dataModelName = dataModelCombo.getText();
updateKeyMap(dataModelName);
}
});
if (selectedDataModel != null) {
for (int i = 0; i < dms.length; i++) {
String dm = dms[i];
if (dm.equals(selectedDataModel)) {
dataModelCombo.select(i);
updateKeyMap(dm);
break;
}
}
}
createButton(parent, BUTTON_SAVE, Messages.Save, false);
createButton(parent, BUTTON_CANCEL, Messages.Cancel, true);
}
}
@Override
protected void buttonPressed(int buttonId) {
this.buttonPressed = buttonId;
if (buttonId == BUTTON_SAVE) {
// check that Data Model is not nul
if (dataModelCombo.getSelectionIndex() == -1) {
MessageDialog.openError(DOMViewDialog.this.getShell(), Messages.DOMViewDialog_ErrorTitle2,
Messages.DOMViewDialog_ErrorMsg2);
return;
}
// if save and on DOM viewer get the XML String
if (tabFolder.getSelectionIndex() == 0) {
try {
sourceViewer.setText(Util.nodeToString(node));
} catch (Exception ex) {
tabFolder.setSelection(1);
MessageDialog.openError(DOMViewDialog.this.getShell(), Messages.DOMViewDialog_ErrorTitle3,
Messages.bind(Messages.DOMViewDialog_ErrorMsg3, ex.getLocalizedMessage()));
return;
}
}
}
Event e = new Event();
e.button = buttonId;
notifyListeners(e);
}
public void addListener(Listener listener) {
listeners.add(listener);
}
public void notifyListeners(Event e) {
for (Listener listener : listeners) {
listener.handleEvent(e);
}
}
/**
* DOM Tree Content Provider
*
* @author bgrieder
*
*/
class DOMTreeContentProvider implements IStructuredContentProvider, ITreeContentProvider {
public DOMTreeContentProvider() {
}
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
}
public void dispose() {
}
public Object[] getElements(Object parent) {
return getChildren(parent);
}
public Object getParent(Object child) {
// if (child instanceof Element) {
return ((Element) child).getParentNode();
// }
// return null;
}
public Object[] getChildren(Object parent) {
if (parent instanceof Document) {
return new Object[] { ((Document) parent).getDocumentElement() };
}
if (parent instanceof Element) {
Element e = (Element) parent;
ArrayList<Node> list = new ArrayList<Node>();
// Attributes
NamedNodeMap map = e.getAttributes();
for (int i = 0; i < map.getLength(); i++) {
list.add(map.item(i));
}
// Sub-Elements
NodeList nl = ((Element) parent).getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
if (nl.item(i) instanceof Element) {
list.add(nl.item(i));
}
}
if (list.size() == 0) {
return null;
} else {
return list.toArray(new Node[list.size()]);
}
}
return null;
}
public boolean hasChildren(Object parent) {
if (parent instanceof Document) {
return true;
}
if (parent instanceof Element) {
return (((Element) parent).getChildNodes().getLength() + ((Element) parent).getAttributes().getLength()) > 1;
}
return false;
}
}
/**
* DOM Tree Label Provider
*
* @author bgrieder
*
*/
class DOMTreeLabelProvider extends LabelProvider {
@Override
public String getText(Object obj) {
if (obj instanceof Node) {
Node e = (Node) obj;
if (e.getChildNodes().getLength() > 1) {
return e.getLocalName();
} else {
return e.getLocalName() + ": " + e.getTextContent();//$NON-NLS-1$
}
}
return "?? " + obj.getClass().getName() + " : " + obj.toString();//$NON-NLS-1$//$NON-NLS-2$
}
@Override
public Image getImage(Object obj) {
if (obj instanceof Element) {
if (((Element) obj).getChildNodes().getLength() > 1) {
return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER);
} else {
return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT);
}
} else if (obj instanceof Node) {
return ImageCache.getImage("icons/attribute.gif").createImage();//$NON-NLS-1$
}
return ImageCache.getImage("icons/small_warn.gif").createImage();//$NON-NLS-1$
}
}// Class DOM Tree Label Provider
}