com.jaspersoft.studio.data.querydesigner.xpath.XPathQueryDesigner.java Source code

Java tutorial

Introduction

Here is the source code for com.jaspersoft.studio.data.querydesigner.xpath.XPathQueryDesigner.java

Source

/*******************************************************************************
 * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com.
 * 
 * Unless you have purchased  a commercial license agreement from Jaspersoft,
 * the following license terms  apply:
 * 
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 ******************************************************************************/
package com.jaspersoft.studio.data.querydesigner.xpath;

import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilderFactory;

import net.sf.jasperreports.data.DataFile;
import net.sf.jasperreports.data.DataFileStream;
import net.sf.jasperreports.data.DataFileUtils;
import net.sf.jasperreports.data.xml.XmlDataAdapter;
import net.sf.jasperreports.eclipse.ui.util.UIUtils;
import net.sf.jasperreports.engine.util.JRXmlUtils;

import org.apache.commons.io.IOUtils;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.MenuEvent;
import org.eclipse.swt.events.MenuListener;
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.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.ui.part.PluginTransfer;
import org.eclipse.ui.progress.UIJob;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

import com.jaspersoft.studio.data.DataAdapterDescriptor;
import com.jaspersoft.studio.data.designer.AQueryDesignerContainer;
import com.jaspersoft.studio.data.designer.tree.NodeBoldStyledLabelProvider;
import com.jaspersoft.studio.data.designer.tree.TreeBasedQueryDesigner;
import com.jaspersoft.studio.data.messages.Messages;
import com.jaspersoft.studio.dnd.NodeDragListener;
import com.jaspersoft.studio.dnd.NodeTransfer;
import com.jaspersoft.studio.model.datasource.xml.XMLAttributeNode;
import com.jaspersoft.studio.model.datasource.xml.XMLNode;
import com.jaspersoft.studio.utils.XMLUtils;
import com.jaspersoft.studio.wizards.ContextHelpIDs;

/**
 * Query designer for the XPath language.
 * 
 * @author Massimo Rabbi (mrabbi@users.sourceforge.net)
 * 
 */
public class XPathQueryDesigner extends TreeBasedQueryDesigner {

    private static final int JOB_DELAY = 300;
    private XMLDocumentManager documentManager;
    private DecorateTreeViewerJob decorateJob;
    private XMLLoaderJob xmlLoaderJob;
    private NodeBoldStyledLabelProvider<XMLNode> treeLabelProvider;
    private Composite toolbarComposite;

    public XPathQueryDesigner() {
        super();
        this.documentManager = new XMLDocumentManager();
        this.decorateJob = new DecorateTreeViewerJob();
        this.xmlLoaderJob = new XMLLoaderJob();
        this.treeLabelProvider = new NodeBoldStyledLabelProvider<XMLNode>();
    }

    @Override
    public Control createToolbar(Composite parent) {
        if (showAdditionalInfo()) {
            toolbarComposite = new Composite(parent, SWT.NONE);
            toolbarComposite.setBackgroundMode(SWT.INHERIT_FORCE);
            GridLayout layout = new GridLayout(1, false);
            layout.marginHeight = 0;
            layout.marginWidth = 0;
            toolbarComposite.setLayout(layout);
            toolbarComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

            Button btn = new Button(toolbarComposite, SWT.PUSH);
            btn.setText(Messages.XPathQueryDesigner_ReadFieldsButton);
            btn.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, false));
            btn.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    container.doGetFields();
                }

            });
            return toolbarComposite;
        } else {
            return null;
        }
    }

    @Override
    public Control getToolbarControl() {
        return this.toolbarComposite;
    }

    @Override
    protected void createTitleBar(Composite parent) {
        if (showAdditionalInfo()) {
            Label titleLabel = new Label(parent, SWT.WRAP);
            titleLabel.setText(Messages.XPathQueryDesigner_InfoTitle);
            titleLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
        }
    }

    private boolean showAdditionalInfo() {
        return container.getContainerType() == AQueryDesignerContainer.CONTAINER_WITH_INFO_TABLES;
    }

    @Override
    protected void decorateTreeUsingQueryText() {
        if (documentManager.isDocumentSet()) {
            decorateJob.cancel();
            decorateJob.schedule(JOB_DELAY);
        }
    }

    @Override
    protected void createTreeViewer(Composite parent) {
        super.createTreeViewer(parent);
        if (showAdditionalInfo()) {
            addDragSupport();
            createContextualMenu();
        }
        addDoubleClickSupport();
    }

    @Override
    protected IBaseLabelProvider getTreeLabelProvider() {
        return this.treeLabelProvider;
    }

    @Override
    protected IContentProvider getTreeContentProvider() {
        return new XPathTreeViewerContentProvider();
    }

    /*
     * Adds support for generating the Xpath query expression, using the current
     * selected node as input.
     */
    private void addDoubleClickSupport() {
        treeViewer.addDoubleClickListener(new IDoubleClickListener() {
            @Override
            public void doubleClick(DoubleClickEvent event) {
                TreeSelection s = (TreeSelection) treeViewer.getSelection();
                if (s.getFirstElement() instanceof XMLNode) {
                    XMLNode xmlNode = (XMLNode) s.getFirstElement();
                    String xPathExpression = documentManager.getXPathExpression(null, xmlNode);
                    queryTextArea.setText((xPathExpression != null) ? xPathExpression : ""); //$NON-NLS-1$
                }
            }
        });
    }

    /*
     * Adds drag support to the xml tree viewer.
     */
    private void addDragSupport() {
        int ops = DND.DROP_COPY | DND.DROP_MOVE;
        Transfer[] transfers = new Transfer[] { NodeTransfer.getInstance(), PluginTransfer.getInstance() };
        treeViewer.addDragSupport(ops, transfers, new NodeDragListener(treeViewer) {
            @Override
            public void dragStart(DragSourceEvent event) {
                TreeSelection s = (TreeSelection) treeViewer.getSelection();
                if (s.getFirstElement() instanceof XMLNode) {
                    XMLNode xmlNode = (XMLNode) s.getFirstElement();
                    xmlNode.setXPathExpression(
                            documentManager.getXPathExpression(queryTextArea.getText(), xmlNode));
                    event.doit = !s.isEmpty();
                } else {
                    event.doit = false;
                }
            }

            @Override
            public void dragFinished(DragSourceEvent event) {
                if (!event.doit)
                    return;
            }
        });
    }

    /*
     * Creates the contextual menu for the tree representing the XML document.
     */
    private void createContextualMenu() {
        Menu contextMenu = new Menu(treeViewer.getTree());
        final MenuItem setRecordNodeItem = new MenuItem(contextMenu, SWT.PUSH);
        setRecordNodeItem.setText(Messages.XPathQueryDesigner_SetRecordItem);
        setRecordNodeItem.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                Object sel = ((IStructuredSelection) treeViewer.getSelection()).getFirstElement();
                if (sel instanceof XMLNode) {
                    String xPathExpression = documentManager.getXPathExpression(null, (XMLNode) sel);
                    queryTextArea.setText((xPathExpression != null) ? xPathExpression : ""); //$NON-NLS-1$
                }
            }
        });
        final MenuItem setDocumentRootItem = new MenuItem(contextMenu, SWT.PUSH);
        setDocumentRootItem.setText(Messages.XPathQueryDesigner_SetDocRootItem);
        setDocumentRootItem.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                Object sel = ((IStructuredSelection) treeViewer.getSelection()).getFirstElement();
                try {
                    Document newDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
                    Node originalNode = documentManager.getDocumentNodesMap().get(sel);
                    Node importedNode = newDocument.importNode(originalNode, true);
                    newDocument.appendChild(importedNode);
                    documentManager.setDocument(newDocument);
                    treeViewer.setInput(documentManager.getXMLDocumentModel());
                } catch (Exception e1) {
                    UIUtils.showError(e1);
                }
            }
        });
        new MenuItem(contextMenu, SWT.SEPARATOR);
        final MenuItem addNodeAsFieldItem1 = new MenuItem(contextMenu, SWT.PUSH);
        addNodeAsFieldItem1.setText(Messages.XPathQueryDesigner_AddAsFieldItem);
        addNodeAsFieldItem1.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                Object sel = ((IStructuredSelection) treeViewer.getSelection()).getFirstElement();
                if (sel instanceof XMLNode) {
                    String xPathExpression = documentManager.getXPathExpression(queryTextArea.getText(),
                            (XMLNode) sel);
                    ((XMLNode) sel).setXPathExpression(xPathExpression);
                    createField((XMLNode) sel);
                }
            }
        });
        final MenuItem addNodeAsFieldItem2 = new MenuItem(contextMenu, SWT.PUSH);
        addNodeAsFieldItem2.setText(Messages.XPathQueryDesigner_AddAsFieldAbsoluteItem);
        addNodeAsFieldItem2.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                Object sel = ((IStructuredSelection) treeViewer.getSelection()).getFirstElement();
                if (sel instanceof XMLNode) {
                    String xPathExpression = documentManager.getXPathExpression(null, (XMLNode) sel);
                    ((XMLNode) sel).setXPathExpression(xPathExpression);
                    createField((XMLNode) sel);
                }
            }
        });
        new MenuItem(contextMenu, SWT.SEPARATOR);
        final MenuItem expandAllItem = new MenuItem(contextMenu, SWT.PUSH);
        expandAllItem.setText(Messages.XPathQueryDesigner_ExpandAllItem);
        expandAllItem.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                treeViewer.expandAll();
            }
        });
        final MenuItem collapseAllItem = new MenuItem(contextMenu, SWT.PUSH);
        collapseAllItem.setText(Messages.XPathQueryDesigner_CollapseAllItem);
        collapseAllItem.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                treeViewer.collapseAll();
            }
        });
        final MenuItem resetRefreshDocItem = new MenuItem(contextMenu, SWT.PUSH);
        resetRefreshDocItem.setText(Messages.XPathQueryDesigner_RefreshItem);
        resetRefreshDocItem.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                refreshTreeViewerContent(container.getDataAdapter());
            }
        });
        treeViewer.getTree().setMenu(contextMenu);

        contextMenu.addMenuListener(new MenuListener() {
            @Override
            public void menuShown(MenuEvent e) {
                Object selEl = ((IStructuredSelection) treeViewer.getSelection()).getFirstElement();
                if (selEl instanceof XMLNode) {
                    addNodeAsFieldItem1.setEnabled(true);
                    addNodeAsFieldItem2.setEnabled(true);
                    if (selEl instanceof XMLAttributeNode) {
                        setRecordNodeItem.setEnabled(false);
                        setDocumentRootItem.setEnabled(false);
                    } else {
                        setRecordNodeItem.setEnabled(true);
                        setDocumentRootItem.setEnabled(true);
                    }
                } else {
                    setRecordNodeItem.setEnabled(false);
                    setDocumentRootItem.setEnabled(false);
                    addNodeAsFieldItem1.setEnabled(false);
                    addNodeAsFieldItem2.setEnabled(false);
                }
            }

            @Override
            public void menuHidden(MenuEvent e) {

            }
        });
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.jaspersoft.studio.data.designer.TreeBasedQueryDesigner#
     * refreshTreeViewerContent
     * (com.jaspersoft.studio.data.DataAdapterDescriptor)
     */
    protected void refreshTreeViewerContent(final DataAdapterDescriptor da) {
        if (!isRefreshing) {
            isRefreshing = true;
            this.container.getQueryStatus().showInfo(""); //$NON-NLS-1$
            treeViewer.setInput(XMLTreeCustomStatus.LOADING_XML);
            if (da != null && da.getDataAdapter() instanceof XmlDataAdapter) {
                XmlDataAdapter xda = (XmlDataAdapter) da.getDataAdapter();
                boolean namespaceAware = XMLUtils.isNamespaceAware(xda, jConfig.getJasperDesign());
                DataFile df = xda.getDataFile();
                xmlLoaderJob.setDataFile(df);
                xmlLoaderJob.setNamespaceAware(namespaceAware);
                xmlLoaderJob.schedule();
            } else {
                treeViewer.getTree().removeAll();
                treeViewer.setInput(XMLTreeCustomStatus.FILE_NOT_FOUND);
                isRefreshing = false;
            }
        }
    }

    /*
     * Job that is responsible to update the treeviewer presentation depending
     * on the nodes selected by the XPath query.
     */
    private final class DecorateTreeViewerJob extends UIJob {

        public DecorateTreeViewerJob() {
            super(Messages.XPathQueryDesigner_RefreshJobTitle);
            setSystem(true);
        }

        @Override
        public IStatus runInUIThread(IProgressMonitor monitor) {
            if (control != null && !control.isDisposed()) {
                monitor.beginTask(Messages.XPathQueryDesigner_RefreshTaskTitle, IProgressMonitor.UNKNOWN);
                String query = queryTextArea.getText();
                treeLabelProvider.setSelectedNodes(documentManager.getSelectableNodes(query));
                treeViewer.refresh();
                monitor.done();
                return Status.OK_STATUS;
            } else {
                return Status.CANCEL_STATUS;
            }
        }

    }

    /*
     * Job responsible to load the XML resource and properly update 
     * the tree content with the read data.
     */
    private final class XMLLoaderJob extends Job {

        private DataFile dataFile;
        private boolean namespaceAware;

        public XMLLoaderJob() {
            super(Messages.XPathQueryDesigner_XmlLoaderJobName);
            addJobChangeListener(new JobChangeAdapter() {
                @Override
                public void done(IJobChangeEvent event) {
                    IStatus result = event.getResult();
                    if (Status.OK_STATUS.equals(result)) {
                        UIUtils.getDisplay().asyncExec(new Runnable() {
                            @Override
                            public void run() {
                                if (treeViewer != null && !treeViewer.getTree().isDisposed()) {
                                    treeViewer.setInput(documentManager.getXMLDocumentModel());
                                    treeViewer.expandToLevel(2);
                                    decorateTreeUsingQueryText();
                                }
                                isRefreshing = false;
                            }
                        });
                    }
                }
            });
        }

        public void setNamespaceAware(boolean namespaceAware) {
            this.namespaceAware = namespaceAware;
        }

        public void setDataFile(DataFile dataFile) {
            this.dataFile = dataFile;
        }

        @Override
        protected IStatus run(IProgressMonitor monitor) {
            DataFileStream ins = null;
            try {
                if (dataFile != null) {
                    Document doc = null;
                    Map<String, Object> parameters = new HashMap<String, Object>();
                    // FIXME - We need to proper populate the map!!!
                    ins = DataFileUtils.instance(jConfig).getDataStream(dataFile, parameters);
                    doc = JRXmlUtils.parse(ins, namespaceAware);
                    documentManager.setDocument(doc);
                    documentManager.setJasperConfiguration(XPathQueryDesigner.this.container.getjConfig());

                    return Status.OK_STATUS;
                }
            } catch (final Exception e) {
                UIUtils.getDisplay().asyncExec(new Runnable() {
                    @Override
                    public void run() {
                        if (treeViewer != null && !treeViewer.getTree().isDisposed()) {
                            XPathQueryDesigner.this.container.getQueryStatus().showError(e);
                            treeViewer.getTree().removeAll();
                            treeViewer.setInput(XMLTreeCustomStatus.ERROR_LOADING_XML);
                        }
                        isRefreshing = false;
                    }
                });
            } finally {
                IOUtils.closeQuietly(ins);
            }
            return null;
        }

    }

    @Override
    public void dispose() {
        if (decorateJob != null) {
            decorateJob.cancel();
            decorateJob = null;
        }
        if (xmlLoaderJob != null) {
            xmlLoaderJob.cancel();
            xmlLoaderJob = null;
        }
        super.dispose();
    }

    @Override
    public String getContextHelpId() {
        return ContextHelpIDs.WIZARD_QUERY_DIALOG;
    }

}