com.jaspersoft.studio.handlers.ResourcePage.java Source code

Java tutorial

Introduction

Here is the source code for com.jaspersoft.studio.handlers.ResourcePage.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.handlers;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import net.sf.jasperreports.eclipse.JasperReportsPlugin;
import net.sf.jasperreports.eclipse.ui.util.UIUtils;
import net.sf.jasperreports.engine.DefaultJasperReportsContext;
import net.sf.jasperreports.engine.JRExpression;
import net.sf.jasperreports.engine.JRImage;
import net.sf.jasperreports.engine.JRReportTemplate;
import net.sf.jasperreports.engine.JRSubreport;
import net.sf.jasperreports.engine.design.JRDesignElement;
import net.sf.jasperreports.engine.design.JRDesignExpression;
import net.sf.jasperreports.engine.design.JRDesignImage;
import net.sf.jasperreports.engine.design.JRDesignReportTemplate;
import net.sf.jasperreports.engine.design.JRDesignSubreport;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.util.SimpleFileResolver;

import org.apache.commons.io.FileUtils;
import org.eclipse.core.commands.operations.OperationStatus;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
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.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;

import com.jaspersoft.studio.compatibility.JRXmlWriterHelper;
import com.jaspersoft.studio.messages.Messages;
import com.jaspersoft.studio.preferences.StudioPreferencePage;
import com.jaspersoft.studio.property.dataset.dialog.DataQueryAdapters;
import com.jaspersoft.studio.swt.widgets.table.ListContentProvider;
import com.jaspersoft.studio.templates.JrxmlTemplateBundle;
import com.jaspersoft.studio.utils.ExpressionUtil;
import com.jaspersoft.studio.utils.ModelUtils;
import com.jaspersoft.studio.utils.jasper.JasperReportsConfiguration;
import com.jaspersoft.studio.wizards.ContextHelpIDs;
import com.jaspersoft.studio.wizards.JSSHelpWizardPage;
import com.jaspersoft.templates.TemplateBundle;

/**
 * 
 * This is the page of the Template Export wizard that handle the recognition of 
 * the resource used by the report and the save of them along with the report
 * 
 * @author Orlandin Marco
 *
 */
public class ResourcePage extends JSSHelpWizardPage {

    /**
     * The template bundle of the exported Report
     */
    private TemplateBundle bundle;

    /**
     * Table where the exported resources are listed
     */
    private TableViewer tableViewer;

    /**
     * Text field where the exporting path is shown
     */
    private Text pathText;

    /**
     * List of file where every file points a resource that must be exported
     */
    private List<File> resourceList;

    /**
     * The configuration of the report
     */
    private JasperReportsConfiguration jrContext;

    /**
     * The file of the exported report
     */
    private IFile reportFile;

    /**
     * Path inserted in the textarea when the dialog is advanced, this is done so the path
     * can be read even when the control are disposed
     */
    private String pathString;

    /**
     * Boolean flag, true if there are conflict on the resource names, otherwise false
     */
    private boolean conflictResources;

    /**
     * Build the class
     * 
     * @param reportFile file of the report exported as template
     */
    protected ResourcePage(IFile reportFile) {
        super("exportresources"); //$NON-NLS-1$
        setTitle(Messages.ResourcePage_pageTitle);
        setDescription(Messages.ResourcePage_pageDescription);
        conflictResources = false;
        this.reportFile = reportFile;
        setPageComplete(false);
        try {
            //Build the bundle and the jasper configuration
            this.jrContext = new JasperReportsConfiguration(DefaultJasperReportsContext.getInstance(), reportFile);
            this.bundle = new JrxmlTemplateBundle(reportFile.getLocationURI().toURL(), true, jrContext);
            jrContext.setJasperDesign(bundle.getJasperDesign());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Return the context name for the help of this page
     */
    @Override
    protected String getContextName() {
        return ContextHelpIDs.WIZARD_EXPORTED_RESOURCES;
    }

    /**
     * Return the jasperdesign of the exported report
     * 
     * @return a not null JasperDesign
     */
    public JasperDesign getDesign() {
        return bundle.getJasperDesign();
    }

    /**
     * Return a full path that represent the destination on the filesystem of the template
     * 
     * @return a string that represent the destination of the template, it's included also the template
     * name and extension
     */
    public String getDestinationPath() {
        return pathString;
    }

    @Override
    public IWizardPage getNextPage() {
        pathString = pathText.getText();
        return super.getNextPage();
    }

    @Override
    public void createControl(Composite parent) {
        Composite composite = new Composite(parent, SWT.NONE);
        setControl(composite);
        composite.setLayout(new GridLayout());

        Table table = new Table(composite, SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER);
        GridData gd = new GridData(GridData.FILL_BOTH);
        table.setLayoutData(gd);
        table.setHeaderVisible(true);

        TableColumn[] col = new TableColumn[1];
        col[0] = new TableColumn(table, SWT.NONE);
        col[0].setText(Messages.ResourcePage_exportedResourceLabel.trim());

        TableLayout tlayout = new TableLayout();
        tlayout.addColumnData(new ColumnWeightData(80, false));
        table.setLayout(tlayout);

        for (TableColumn c : col)
            c.pack();

        Composite pathComposite = new Composite(composite, SWT.NONE);
        pathComposite.setLayout(new GridLayout(3, false));
        gd = new GridData(GridData.FILL_BOTH);
        pathComposite.setLayoutData(gd);
        new Label(pathComposite, SWT.NONE).setText(Messages.ResourcePage_destinationFolderLabel);

        pathText = new Text(pathComposite, SWT.BORDER);
        pathText.setEditable(false);
        gd = new GridData(SWT.FILL, SWT.BOTTOM, true, false);
        pathText.setLayoutData(gd);

        Button browseButton = new Button(pathComposite, SWT.NONE);
        browseButton.setText(Messages.ResourcePage_browseButton);
        browseButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                FileDialog fd = new FileDialog(UIUtils.getShell(), SWT.SAVE);
                fd.setText(Messages.ExportImageAction_saveDialogTitle);
                String[] filterExt = { "*.jrxml" }; //$NON-NLS-1$
                fd.setFileName(bundle.getLabel());
                fd.setFilterExtensions(filterExt);
                String selected = fd.open();
                if (selected != null) {
                    pathText.setText(selected);
                    if (!conflictResources)
                        setPageComplete(true);
                }
            }
        });

        tableViewer = new TableViewer(table);
        tableViewer.setContentProvider(new ListContentProvider());
        tableViewer.setLabelProvider(new TLabelProvider());

        fillData();
    }

    /**
     * Display a error message when there are conflicts between the resources, in the detail
     * section are listed the conflicted resources
     * 
     * @param conflicts List of all the resource with conflicts. The list must have a even number of elements
     * and every element in a pair position is in conflict with the file in the following position
     */
    private void createErrorMessage(List<String> conflicts) {
        String conf = ""; //$NON-NLS-1$
        for (int i = 0; i < conflicts.size(); i += 2) {
            conf += conflicts.get(i).concat("\n").concat(conflicts.get(i + 1)).concat("\n\n"); //$NON-NLS-1$ //$NON-NLS-2$
        }

        IStatus status = new OperationStatus(IStatus.ERROR, JasperReportsPlugin.getDefault().getPluginID(),
                OperationStatus.NOTHING_TO_REDO, conf, null);
        new ConflictDetailsError(UIUtils.getShell(), Messages.ResourcePage_conflictTitle,
                Messages.ResourcePage_conflictMessage, status,
                IStatus.OK | IStatus.INFO | IStatus.WARNING | IStatus.ERROR) {
            protected void setShellStyle(int newShellStyle) {
                super.setShellStyle(newShellStyle | SWT.SHEET);
            }
        }.open();
    }

    /**
     * Read from the report the list of the resources that it use and show them into
     * a table. Search and identify also the conflicts between the resources
     */
    public void fillData() {
        resourceList = getResourceNames();
        HashMap<String, File> resourceMap = new HashMap<String, File>();
        List<String> conflicts = new ArrayList<String>();
        for (File actualResource : resourceList) {
            if (resourceMap.containsKey(actualResource.getName())) {
                File conflictFile = resourceMap.get(actualResource.getName());
                //Avoid to identify as a conflict the same resource used in different places
                if (!conflictFile.getAbsolutePath().equals(actualResource.getAbsolutePath())) {
                    conflicts.add(actualResource.getAbsolutePath());
                    conflicts.add(conflictFile.getAbsolutePath());
                }
            } else
                resourceMap.put(actualResource.getName(), actualResource);
        }

        List<File> exportedResource = new ArrayList<File>();
        exportedResource.add(reportFile.getLocation().toFile());
        exportedResource.addAll(resourceList);
        tableViewer.setInput(exportedResource);
        tableViewer.refresh();
        //If there are conflict show an error message and disable the next button
        if (conflicts.size() > 0) {
            conflictResources = true;
            createErrorMessage(conflicts);
        }
    }

    /**
     * Label provider for the table. Since the input are a list of file this extract 
     * from the file a string, the full path in the file system, as content of the cell
     * 
     * @author Orlandin Marco
     *
     */
    class TLabelProvider extends CellLabelProvider implements ITableLabelProvider {

        public Image getColumnImage(Object element, int columnIndex) {
            return null;
        }

        public String getColumnText(Object element, int columnIndex) {
            File fr = (File) element;
            return fr.getAbsolutePath();
        }

        @Override
        public void update(ViewerCell cell) {
            cell.setText(cell.getElement().toString());
        }

        public Point getToolTipShift(Object object) {
            return new Point(5, 5);
        }

        public int getToolTipDisplayDelayTime(Object object) {
            return 2000;
        }

        public int getToolTipTimeDisplayed(Object object) {
            return 5000;
        }
    }

    /**
     * Given a report in the workspace and a resource name
     * it return a file to that resource
     * 
     * @param file file of the report
     * @param str name of the resource
     * @return file to the resource in the filesystem
     */
    protected File findFile(IFile file, String str) {
        if (str == null)
            return null;
        SimpleFileResolver fr = new SimpleFileResolver(
                Arrays.asList(new File[] { new File(file.getParent().getLocationURI()), new File("."), //$NON-NLS-1$
                        new File(file.getProject().getLocationURI()) }));
        fr.setResolveAbsolutePath(true);
        return fr.resolveFile(str);
    }

    /**
     * This method check that an expression has a text of type:
     * 
     * "filename"
     * 
     * if the format is different, or if filename does not exist in
     * the current report directory, it returns null.
     * 
     * @param exp
     * @return the correct filename
     */
    private String evalResourceName(JRExpression exp) {
        return ExpressionUtil.cachedExpressionEvaluationString(exp, jrContext);
    }

    /**
     * Take the jasperdesign and then convert it into an XML string
     */
    private String model2xml() {
        String xml = null;
        try {
            JasperDesign report = bundle.getJasperDesign();
            report.removeProperty(DataQueryAdapters.DEFAULT_DATAADAPTER);
            String version = jrContext.getProperty(StudioPreferencePage.JSS_COMPATIBILITY_VERSION,
                    JRXmlWriterHelper.LAST_VERSION);
            xml = JRXmlWriterHelper.writeReport(jrContext, report,
                    net.sf.jasperreports.eclipse.util.FileUtils.UTF8_ENCODING, version); //$NON-NLS-1$
        } catch (Throwable e) {
            UIUtils.showError(e);
        }
        return xml;
    }

    /**
     * Copy a file from a source to a destination
     * 
     * @param inputFile Source File
     * @param outputFile Destination file
     * @throws IOException
     */
    private void copyFile(File inputFile, File outputFile) throws IOException {
        FileUtils.copyFile(inputFile, outputFile);
        //Files.copy(inputFile.toPath(), outputFile.toPath(), StandardCopyOption.REPLACE_EXISTING);

    }

    /**
     * Save the xml of the report on the disk
     */
    private void saveReport() {
        JasperDesign jd = bundle.getJasperDesign();
        if (jd != null) {
            rebindResources();
            try {
                File destination = new File(pathText.getText());
                FileUtils.writeStringToFile(destination, model2xml(),
                        net.sf.jasperreports.eclipse.util.FileUtils.UTF8_ENCODING); //$NON-NLS-1$
                String destinationPath = destination.getParent() + System.getProperty("file.separator"); //$NON-NLS-1$
                for (File resource : resourceList) {
                    copyFile(resource, new File(destinationPath.concat(resource.getName())));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Method called to export the report and its resources
     */
    public boolean finish() {
        saveReport();
        return true;
    }

    /**
     * Change all the report expression to a resource (like a subreport or an image) assuming that the resource is in the same folder
     * of the report. This can be an expensive operation, since the jrxml representing the template may be loaded in order locate all 
     * the referenced resources. 
     * 
     */
    private void rebindResources() {

        List<JRDesignElement> list = ModelUtils.getAllGElements(bundle.getJasperDesign());

        for (JRDesignElement el : list) {
            if (el instanceof JRDesignImage) {
                JRDesignImage im = (JRDesignImage) el;
                String res = evalResourceName(im.getExpression());
                File resFile = findFile(reportFile, res);
                if (resFile != null)
                    im.setExpression(new JRDesignExpression("\"" + resFile.getName() + "\""));
            }

            if (el instanceof JRDesignSubreport) {
                JRDesignSubreport sr = (JRDesignSubreport) el;
                String res = evalResourceName(sr.getExpression());
                if (res.endsWith(".jasper")) { //$NON-NLS-1$
                    res = res.substring(0, res.length() - ".jasper".length()) + ".jrxml"; //$NON-NLS-1$ //$NON-NLS-2$
                    File resFile = findFile(reportFile, res);
                    sr.setExpression(new JRDesignExpression("\"" + resFile.getName() + "\""));
                }
            }

        }

        List<JRReportTemplate> templates = bundle.getJasperDesign().getTemplatesList();
        for (JRReportTemplate t : templates) {
            String res = evalResourceName(t.getSourceExpression());
            if (res != null && t instanceof JRDesignReportTemplate) {
                File resFile = findFile(reportFile, res);
                ((JRDesignReportTemplate) t)
                        .setSourceExpression(new JRDesignExpression("\"" + resFile.getName() + "\""));
            }
        }
    }

    /**
     * Return the File to all the resources referenced by this template. This can be an expensive operation, since the
     * jrxml representing the template may be loaded in order locate all the referenced resources. In the returned list 
     * are avoided duplicated files to the same resource
     * 
     */
    public List<File> getResourceNames() {

        List<File> resourceNames = new ArrayList<File>();

        //This set is used to avoid duplicated resources
        HashSet<String> alredyAddedElements = new HashSet<String>();

        List<JRDesignElement> list = ModelUtils.getAllGElements(bundle.getJasperDesign());

        for (JRDesignElement el : list) {
            if (el instanceof JRImage) {
                JRImage im = (JRImage) el;
                String res = evalResourceName(im.getExpression());
                File resFile = findFile(reportFile, res);
                if (resFile != null && !alredyAddedElements.contains(resFile.getAbsolutePath())) {
                    resourceNames.add(resFile);
                    alredyAddedElements.add(resFile.getAbsolutePath());
                }
            }

            if (el instanceof JRSubreport) {
                JRSubreport sr = (JRSubreport) el;
                String res = evalResourceName(sr.getExpression());
                if (res != null && res.endsWith(".jasper")) { //$NON-NLS-1$
                    res = res.substring(0, res.length() - ".jasper".length()) + ".jrxml"; //$NON-NLS-1$ //$NON-NLS-2$
                    File resFile = findFile(reportFile, res);
                    if (!alredyAddedElements.contains(resFile.getAbsolutePath())) {
                        resourceNames.add(resFile);
                        alredyAddedElements.add(resFile.getAbsolutePath());
                    }
                }
            }

        }

        List<JRReportTemplate> templates = bundle.getJasperDesign().getTemplatesList();
        for (JRReportTemplate t : templates) {
            String res = evalResourceName(t.getSourceExpression());
            File resFile = findFile(reportFile, res);
            if (resFile != null && !alredyAddedElements.contains(resFile.getAbsolutePath())) {
                resourceNames.add(resFile);
                alredyAddedElements.add(resFile.getAbsolutePath());
            }
        }

        return resourceNames;
    }

}