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