/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.reporting.designer.core.actions.report;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Arrays;
import javax.swing.Action;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import org.pentaho.reporting.designer.core.ReportDesignerContext;
import org.pentaho.reporting.designer.core.actions.AbstractReportContextAction;
import org.pentaho.reporting.designer.core.actions.ActionMessages;
import org.pentaho.reporting.designer.core.editor.ReportDocumentContext;
import org.pentaho.reporting.designer.core.editor.ReportRenderContext;
import org.pentaho.reporting.designer.core.inspections.Inspection;
import org.pentaho.reporting.designer.core.inspections.InspectionResult;
import org.pentaho.reporting.designer.core.inspections.InspectionResultListener;
import org.pentaho.reporting.designer.core.inspections.InspectionsMessageDialog;
import org.pentaho.reporting.designer.core.inspections.InspectionsRegistry;
import org.pentaho.reporting.designer.core.util.exceptions.UncaughtExceptionsModel;
import org.pentaho.reporting.engine.classic.core.AbstractReportDefinition;
import org.pentaho.reporting.engine.classic.core.Element;
import org.pentaho.reporting.engine.classic.core.MasterReport;
import org.pentaho.reporting.engine.classic.core.RootLevelBand;
import org.pentaho.reporting.engine.classic.core.Section;
import org.pentaho.reporting.engine.classic.core.SubReport;
import org.pentaho.reporting.libraries.designtime.swing.LibSwingUtil;
import org.pentaho.reporting.libraries.designtime.swing.background.BackgroundCancellableProcessHelper;
import org.pentaho.reporting.libraries.designtime.swing.background.CancelEvent;
import org.pentaho.reporting.libraries.designtime.swing.background.CancelListener;
import org.pentaho.reporting.libraries.designtime.swing.background.ProgressFeed;
public class ValidateReportAction extends AbstractReportContextAction
{
private static class InspectionResultCollector implements InspectionResultListener
{
private ArrayList<InspectionResult> results;
private InspectionResultCollector()
{
results = new ArrayList<InspectionResult>();
}
public void notifyInspectionStarted()
{
}
public void notifyInspectionResult(final InspectionResult result)
{
results.add(result);
}
public InspectionResult[] toArray()
{
return results.toArray(new InspectionResult[results.size()]);
}
}
private static class RunInspectionTask implements Runnable, ProgressFeed, CancelListener
{
private ReportDesignerContext reportDesignerContext;
private InspectionResultCollector collector;
private volatile double progress;
private volatile boolean cancelled;
private RunInspectionTask(final ReportDesignerContext reportDesignerContext)
{
this.collector = new InspectionResultCollector();
this.reportDesignerContext = reportDesignerContext;
}
public void cancelProcessing(final CancelEvent event)
{
cancelled = true;
}
public double queryProgress()
{
return progress;
}
public void run()
{
final ReportDocumentContext activeContext = reportDesignerContext.getActiveContext();
final MasterReport report = activeContext.getContextRoot();
final int numberReports = countReports(report);
runInspection(report, report, reportDesignerContext, null, collector, 1, numberReports);
if (cancelled == false)
{
SwingUtilities.invokeLater(new ShowResultTask(reportDesignerContext, collector));
}
}
private int runInspection(final AbstractReportDefinition def,
final MasterReport master,
final ReportDesignerContext reportDesignerContext,
final ReportRenderContext parentContext,
final InspectionResultCollector collector,
final int currentReport,
final int maxReports)
{
final ReportRenderContext r = new ReportRenderContext
(master, def, parentContext, reportDesignerContext.getGlobalAuthenticationStore(), true);
final Inspection[] inspections = InspectionsRegistry.getInstance().getInspections();
if (cancelled)
{
return currentReport;
}
int counter = currentReport;
progress = ((double) counter / (double) maxReports);
for (int i = 0; i < inspections.length; i++)
{
final Inspection inspection = inspections[i];
try
{
inspection.inspect(reportDesignerContext, r, collector);
}
catch (Exception e)
{
UncaughtExceptionsModel.getInstance().addException(e);
}
}
final ArrayList<SubReport> subreports = new ArrayList<SubReport>();
findLocalSubreports(def, subreports);
for (final SubReport subreport : subreports)
{
counter = runInspection(subreport, master, reportDesignerContext, r, collector, counter + 1, maxReports);
if (cancelled)
{
return counter;
}
}
r.dispose();
return counter;
}
}
private static class ShowResultTask implements Runnable
{
private InspectionResultCollector collector;
private ReportDesignerContext reportDesignerContext;
private ShowResultTask(final ReportDesignerContext reportDesignerContext,
final InspectionResultCollector collector)
{
this.reportDesignerContext = reportDesignerContext;
this.collector = collector;
}
public void run()
{
if (collector.results.isEmpty())
{
reportDesignerContext.setStatusText(ActionMessages.getString("ValidateReportAction.ValidationRunNoResults"));
}
else
{
final Window window = LibSwingUtil.getWindowAncestor(reportDesignerContext.getView().getParent());
final InspectionsMessageDialog dialog;
if (window instanceof JDialog)
{
dialog = new InspectionsMessageDialog((JDialog) window);
}
else if (window instanceof JFrame)
{
dialog = new InspectionsMessageDialog((JFrame) window);
}
else
{
dialog = new InspectionsMessageDialog();
}
dialog.performShowResult(reportDesignerContext, collector.toArray());
}
}
}
public ValidateReportAction()
{
putValue(Action.NAME, ActionMessages.getString("ValidateReportAction.Text"));
putValue(Action.SHORT_DESCRIPTION, ActionMessages.getString("ValidateReportAction.Description"));
putValue(Action.MNEMONIC_KEY, ActionMessages.getOptionalMnemonic("ValidateReportAction.Mnemonic"));
putValue(Action.ACCELERATOR_KEY, ActionMessages.getOptionalKeyStroke("ValidateReportAction.Accelerator"));
}
public void actionPerformed(final ActionEvent e)
{
final ReportDesignerContext reportDesignerContext = getReportDesignerContext();
final RunInspectionTask task = new RunInspectionTask(reportDesignerContext);
final Thread t = new Thread(task);
t.setDaemon(true);
BackgroundCancellableProcessHelper.executeProcessWithCancelDialog(t, task, reportDesignerContext.getView().getParent(),
"Running Inspections ..", task);
}
private static void findLocalSubreports(final Section section, final ArrayList<SubReport> result)
{
final int elementCount = section.getElementCount();
for (int i = 0; i < elementCount; i += 1)
{
final Element element = section.getElement(i);
if (element instanceof SubReport)
{
result.add((SubReport) element);
continue;
}
if (element instanceof RootLevelBand)
{
final RootLevelBand rlb = (RootLevelBand) element;
final SubReport[] subReports = rlb.getSubReports();
result.addAll(Arrays.asList(subReports));
}
if (element instanceof Section)
{
findLocalSubreports((Section) element, result);
}
}
}
private static int countReports(final AbstractReportDefinition def)
{
final ArrayList<SubReport> result = new ArrayList<SubReport>();
findLocalSubreports(def, result);
int count = 1;
for (final SubReport subReport : result)
{
count += countReports(subReport);
}
return count;
}
}