X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.charts%2Fsrc%2Forg%2Fsimantics%2Fcharts%2Fexport%2FExportChartPDF.java;fp=bundles%2Forg.simantics.charts%2Fsrc%2Forg%2Fsimantics%2Fcharts%2Fexport%2FExportChartPDF.java;h=645fb50ea62884a5af8bdb535f42e72acc5065bb;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.charts/src/org/simantics/charts/export/ExportChartPDF.java b/bundles/org.simantics.charts/src/org/simantics/charts/export/ExportChartPDF.java new file mode 100644 index 000000000..645fb50ea --- /dev/null +++ b/bundles/org.simantics.charts/src/org/simantics/charts/export/ExportChartPDF.java @@ -0,0 +1,301 @@ +package org.simantics.charts.export; + +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.preferences.DefaultScope; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.osgi.service.prefs.Preferences; +import org.simantics.Simantics; +import org.simantics.charts.preference.ChartPreferences; +import org.simantics.charts.query.MilestoneSpecQuery; +import org.simantics.charts.query.TrendSpecQuery; +import org.simantics.databoard.Accessors; +import org.simantics.databoard.accessor.RecordAccessor; +import org.simantics.databoard.accessor.error.AccessorConstructionException; +import org.simantics.databoard.accessor.reference.ChildReference; +import org.simantics.databoard.binding.mutable.Variant; +import org.simantics.databoard.type.RecordType; +import org.simantics.databoard.type.UnionType; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.request.PossibleModel; +import org.simantics.export.core.ExportContext; +import org.simantics.export.core.error.ExportException; +import org.simantics.export.core.manager.Content; +import org.simantics.export.core.pdf.ExportPdfWriter; +import org.simantics.export.core.pdf.ExportPdfWriter.Page; +import org.simantics.export.core.util.ExportQueries; +import org.simantics.export.core.util.ExporterUtils; +import org.simantics.g2d.canvas.impl.CanvasContext; +import org.simantics.history.History; +import org.simantics.history.HistoryException; +import org.simantics.history.HistoryManager; +import org.simantics.simulation.experiment.IExperiment; +import org.simantics.simulation.experiment.IHistoryExperiment; +import org.simantics.simulation.export.ExperimentExportClass; +import org.simantics.simulation.project.ExperimentManager; +import org.simantics.simulation.project.IExperimentManager; +import org.simantics.trend.TrendInitializer; +import org.simantics.trend.configuration.ItemPlacement; +import org.simantics.trend.configuration.TimeFormat; +import org.simantics.trend.configuration.TrendSpec; +import org.simantics.trend.impl.MilestoneSpec; +import org.simantics.trend.impl.TrendNode; +import org.simantics.utils.datastructures.MapList; +import org.simantics.utils.format.ValueFormat; +import org.simantics.utils.threads.ThreadUtils; +import org.simantics.utils.threads.WorkerThread; + +public class ExportChartPDF extends ExperimentExportClass { + + public static final RecordType chartOptions; + + public static String S_CHART = "Chart"; + public static ChildReference P_ITEMPLACEMENT = ChildReference.parsePath(S_CHART+"/Item Placement"); + public static ChildReference P_TIMEFORMAT = ChildReference.parsePath(S_CHART+"/Time Format"); + public static ChildReference P_VALUEFORMAT = ChildReference.parsePath(S_CHART+"/Value Format"); + + static { + chartOptions = new RecordType(); + chartOptions.addComponent("Item Placement", UnionType.newEnum("Stacked", "Overlapping")); + chartOptions.addComponent("Time Format", UnionType.newEnum("Decimal", "Time")); + chartOptions.addComponent("Value Format", UnionType.newEnum("Currency", "Scientific", "Engineering", "Default")); + } + + @Override + public void export(List contents, + Object handle, + ExportContext ctx, + Variant options, + IProgressMonitor monitor, + MapList attachmentMap + ) throws ExportException { + + // Flush all experiments, just in case. + IExperimentManager em = Simantics.getProject().getHint( ExperimentManager.KEY_EXPERIMENT_MANAGER ); + if ( em != null ) { + for (IExperiment exp : em.getExperiments()) { + if ( exp instanceof IHistoryExperiment ) { + IHistoryExperiment he = (IHistoryExperiment) exp; + try { + he.flushHistory(); + } catch (HistoryException e) { + } + } + } + } + + final ExportPdfWriter writer = (ExportPdfWriter) handle; + final WorkerThread workerThread = new WorkerThread("Chart PDF Painter"); + workerThread.start(); + try { + + final RecordAccessor ra = Accessors.getAccessor( options ); + + // Get a list of the history managers the user has selected. + List modelRefs = ExperimentExportClass.getResult(ctx, options, true); + List charts = new ArrayList(); + + for ( Content content : contents ) { + if (monitor.isCanceled()) + throw new OperationCanceledException(); + + Resource chartRes = ctx.session.syncRequest( ExportQueries.toResource(content.url) ); + Resource model = ctx.session.syncRequest( new PossibleModel( chartRes ) ); + for (ModelRef modelRef : modelRefs) { + if ( !modelRef.resource.equals(model) ) continue; + for (ExperimentRef experimentRef : modelRef.experiments) { + for (RunRef runRef : experimentRef.runs) { + if ( runRef.historyFolder == null || !runRef.historyFolder.exists() ) continue; + HistoryManager history = History.openFileHistory( runRef.historyFolder ); + + ChartSettings cs = new ChartSettings(); + cs.history = history; + cs.modelRef = modelRef; + cs.experimentRef = experimentRef; + cs.runRef = runRef; + cs.chartRes = chartRes; + charts.add( cs ); + } + } + } + } + + + for ( final ChartSettings cs : charts ) { + UUID id = UUID.randomUUID(); + final TrendSpec trendSpec = ctx.session.syncRequest( new TrendSpecQuery( id, cs.chartRes ) ); + if ( cs.modelRef.enabledRunCount() > 1 ) { + // Add run ref to the label + trendSpec.name += " / " + cs.runRef.label; + } + + + final MilestoneSpec milestones = ctx.session.syncRequest( new MilestoneSpecQuery( cs.experimentRef.resource ) ); + //final CanvasContext cctx = new CanvasContext( workerThread ); + final ExportException[] error = new ExportException[1]; + + ThreadUtils.syncExec(workerThread, new Runnable() { + @Override + public void run() { + CanvasContext cctx = TrendInitializer.createDefaultCanvas(workerThread, cs.history, null, null, trendSpec); + Page pdfPage = null; + try { + TrendNode trend = TrendInitializer.getTrendNode( cctx ); + trend.printing = true; + + String s = ExporterUtils.getUnionValue(ra, P_ITEMPLACEMENT); + if ( s!=null ) trend.itemPlacement = ItemPlacement.valueOf(s); + s = ExporterUtils.getUnionValue(ra, P_TIMEFORMAT); + if ( s!=null ) trend.timeFormat = TimeFormat.valueOf(s); + s = ExporterUtils.getUnionValue(ra, P_VALUEFORMAT); + if ( s!=null ) trend.valueFormat = ValueFormat.valueOf(s); + + if (milestones!=null) trend.setMilestones(milestones); + + pdfPage = writer.createPage( null ); + Graphics2D g2d = pdfPage.createGraphics( true ); + try { + Rectangle2D clip = new Rectangle2D.Double(0, 0, pdfPage.getWidth(), pdfPage.getHeight()); + g2d.setClip( clip ); + g2d.scale(0.25, 0.25); + trend.autoscale(true, true); + trend.zoomOut(); + trend.layout(); + trend.render( g2d ); + } finally { + trend.cleanup(); + g2d.dispose(); + cs.history.close(); + } + } catch (ExportException e) { + error[0] = e; + } finally { + cctx.dispose(); + if ( pdfPage != null ) + try { + pdfPage.close(); + } catch (ExportException e) { + if ( error[0]==null ) error[0] = e; + } + } + } + }); + if ( error[0] != null ) throw error[0]; + + } + } catch (DatabaseException e) { + throw new ExportException( e ); + } catch (AccessorConstructionException e) { + throw new ExportException( e ); + } finally { + workerThread.stopDispatchingEvents(true); + } + + } + + + @Override + public RecordType options(ExportContext context, Collection content) throws ExportException { + RecordType options = super.options(context, content); + options.addComponent(S_CHART, chartOptions); + return options; + } + + @Override + public void fillDefaultPrefs(ExportContext ctx, Variant options) throws ExportException { + super.fillDefaultPrefs(ctx, options); + // Read from eclipse preferences + try { + RecordAccessor ra = Accessors.getAccessor(options); + Preferences instPrefs = InstanceScope.INSTANCE.getNode( ChartPreferences.P_NODE ); + Preferences defaultPrefs = DefaultScope.INSTANCE.getNode( ChartPreferences.P_NODE ); + + String s; + s = ExporterUtils.getPrefString(instPrefs, defaultPrefs, ChartPreferences.P_ITEMPLACEMENT); + ExporterUtils.setUnionValue(ra, P_ITEMPLACEMENT, s); + + s = ExporterUtils.getPrefString(instPrefs, defaultPrefs, ChartPreferences.P_TIMEFORMAT); + ExporterUtils.setUnionValue(ra, P_TIMEFORMAT, s); + + s = ExporterUtils.getPrefString(instPrefs, defaultPrefs, ChartPreferences.P_VALUEFORMAT); + ExporterUtils.setUnionValue(ra, P_VALUEFORMAT, s); + + } catch (AccessorConstructionException e) { + throw new ExportException(e); + } + } + + @Override + public void savePref(Variant options, Preferences contentScopeNode, Preferences workbenchScopeNode) throws ExportException { + super.savePref(options, contentScopeNode, workbenchScopeNode); + try { + RecordAccessor ra = Accessors.getAccessor(options); + String s; + + s = ExporterUtils.getUnionValue(ra, P_ITEMPLACEMENT); + ExporterUtils.setPrefString(contentScopeNode, ChartPreferences.P_ITEMPLACEMENT, s); + ExporterUtils.setPrefString(workbenchScopeNode, ChartPreferences.P_ITEMPLACEMENT, s); + + s = ExporterUtils.getUnionValue(ra, P_TIMEFORMAT); + ExporterUtils.setPrefString(contentScopeNode, ChartPreferences.P_TIMEFORMAT, s); + ExporterUtils.setPrefString(workbenchScopeNode, ChartPreferences.P_TIMEFORMAT, s); + + s = ExporterUtils.getUnionValue(ra, P_VALUEFORMAT); + ExporterUtils.setPrefString(contentScopeNode, ChartPreferences.P_VALUEFORMAT, s); + ExporterUtils.setPrefString(workbenchScopeNode, ChartPreferences.P_VALUEFORMAT, s); + + } catch (AccessorConstructionException e) { + throw new ExportException(e); + } + + } + + @Override + public void loadPref(Variant options, Preferences contentScopeNode, Preferences workbenchScopeNode) throws ExportException { + super.loadPref(options, contentScopeNode, workbenchScopeNode); + try { + RecordAccessor ra = Accessors.getAccessor(options); + + String s; + s = ExporterUtils.getPrefString(contentScopeNode, ChartPreferences.P_ITEMPLACEMENT); + if ( s==null ) s = ExporterUtils.getPrefString(workbenchScopeNode, ChartPreferences.P_ITEMPLACEMENT); + ExporterUtils.setUnionValue(ra, P_ITEMPLACEMENT, s); + + s = ExporterUtils.getPrefString(contentScopeNode, ChartPreferences.P_TIMEFORMAT); + if ( s==null ) s = ExporterUtils.getPrefString(workbenchScopeNode, ChartPreferences.P_TIMEFORMAT); + ExporterUtils.setUnionValue(ra, P_TIMEFORMAT, s); + + s = ExporterUtils.getPrefString(contentScopeNode, ChartPreferences.P_VALUEFORMAT); + if ( s==null ) s = ExporterUtils.getPrefString(workbenchScopeNode, ChartPreferences.P_VALUEFORMAT); + ExporterUtils.setUnionValue(ra, P_VALUEFORMAT, s); + + } catch (AccessorConstructionException e) { + throw new ExportException(e); + } + } + + @Override + public List validate(String contentUri, ExportContext context, Variant options) { + return Collections.emptyList(); + } + + static class ChartSettings { + + Resource chartRes; + ModelRef modelRef; + ExperimentRef experimentRef; + RunRef runRef; + HistoryManager history; + + } + +}