2424import org .csstudio .trends .databrowser3 .model .PVItem ;
2525import org .epics .vtype .VEnum ;
2626import org .epics .vtype .VNumber ;
27+ import org .epics .vtype .VStatistics ;
2728import org .epics .vtype .VString ;
2829import org .epics .vtype .VType ;
2930import org .phoebus .archive .reader .SpreadsheetIterator ;
3031import org .phoebus .archive .reader .ValueIterator ;
32+ import org .phoebus .archive .vtype .VTypeHelper ;
3133import org .phoebus .framework .jobs .JobMonitor ;
3234import org .phoebus .util .time .SecondsParser ;
3335import org .phoebus .util .time .TimestampFormats ;
@@ -59,6 +61,9 @@ public class ExcelExportJob extends ExportJob
5961 * @param start Start time
6062 * @param end End time
6163 * @param source Data source
64+ * @param tabular Create one combined table? Otherwise one table per channel
65+ * @param min_max Show min/max info (error) for statistical data?
66+ * @param sevr_stat Include alarm severity and status?
6267 * @param optimize_parameter Bin count
6368 * @param filename Export file name
6469 * @param error_handler Error handler
@@ -128,14 +133,32 @@ else if (source == Source.LINEAR_INTERPOLATION)
128133 addComment (row = sheet .createRow (row .getRowNum () + 1 ), "Interpolation Interval" , SecondsParser .formatSeconds (optimize_parameter ));
129134 }
130135
131- private Cell createCell (final Row row , final int column , final VType value )
136+ private Cell createTimeCell (final Row row , final Instant time )
137+ {
138+ Cell cell = row .createCell (0 , CellType .NUMERIC );
139+ if (unixTimeStamp )
140+ cell .setCellValue (time .toEpochMilli ());
141+ else
142+ {
143+ cell .setCellValue (LocalDateTime .ofInstant (time , zone ));
144+ cell .setCellStyle (timestamp_style );
145+ }
146+ return cell ;
147+ }
148+
149+ private Cell createValueCell (final Row row , final int column , final VType value )
132150 {
133151 final Cell cell ;
134152 if (value instanceof VNumber v )
135153 {
136154 cell = row .createCell (column , CellType .NUMERIC );
137155 cell .setCellValue (v .getValue ().doubleValue ());
138156 }
157+ else if (value instanceof VStatistics v )
158+ {
159+ cell = row .createCell (column , CellType .NUMERIC );
160+ cell .setCellValue (v .getAverage ());
161+ }
139162 else if (value instanceof VEnum v )
140163 {
141164 cell = row .createCell (column , CellType .NUMERIC );
@@ -156,9 +179,38 @@ else if (value == null)
156179 return cell ;
157180 }
158181
182+ private Cell createValueCells (final Row row , final int column , final VType value )
183+ {
184+ Cell cell = createValueCell (row , column , value );
185+ if (min_max )
186+ {
187+ if (value instanceof VStatistics stats )
188+ { // Turn min..max into negative & positive error
189+ cell = row .createCell (cell .getColumnIndex ()+1 , CellType .NUMERIC );
190+ cell .setCellValue (stats .getAverage () - stats .getMin ());
191+ cell = row .createCell (cell .getColumnIndex ()+1 , CellType .NUMERIC );
192+ cell .setCellValue (stats .getMax () - stats .getAverage ());
193+ }
194+ else
195+ {
196+ cell = row .createCell (cell .getColumnIndex ()+1 , CellType .BLANK );
197+ cell = row .createCell (cell .getColumnIndex ()+1 , CellType .BLANK );
198+ }
199+ }
200+ if (sevr_stat )
201+ {
202+ cell = row .createCell (cell .getColumnIndex ()+1 , CellType .STRING );
203+ cell .setCellValue (Objects .toString (org .phoebus .core .vtypes .VTypeHelper .getSeverity (value )));
204+
205+ cell = row .createCell (cell .getColumnIndex ()+1 , CellType .STRING );
206+ cell .setCellValue (VTypeHelper .getMessage (value ));
207+ }
208+ return cell ;
209+ }
210+
211+
159212 @ Override
160- protected void performExport (final JobMonitor monitor ,
161- final PrintStream out ) throws Exception
213+ protected void performExport (final JobMonitor monitor , final PrintStream out ) throws Exception
162214 {
163215 // Item header
164216 for (ModelItem item : model .getItems ())
@@ -183,6 +235,16 @@ protected void performExport(final JobMonitor monitor,
183235 }
184236 }
185237
238+ if (tabular )
239+ exportTable (monitor );
240+ else
241+ exportList (monitor );
242+
243+ wb .write (out );
244+ }
245+
246+ private void exportTable (final JobMonitor monitor ) throws Exception
247+ {
186248 // Spreadsheet data header
187249 row = sheet .createRow (row .getRowNum () + 2 );
188250 Cell cell = row .createCell (0 , CellType .STRING );
@@ -193,6 +255,27 @@ protected void performExport(final JobMonitor monitor,
193255 cell = row .createCell (cell .getColumnIndex ()+1 , CellType .STRING );
194256 cell .setCellStyle (header_style );
195257 cell .setCellValue (item .getResolvedName ());
258+
259+ if (min_max )
260+ {
261+ cell = row .createCell (cell .getColumnIndex ()+1 , CellType .STRING );
262+ cell .setCellStyle (header_style );
263+ cell .setCellValue (Messages .NegErrColumn );
264+
265+ cell = row .createCell (cell .getColumnIndex ()+1 , CellType .STRING );
266+ cell .setCellStyle (header_style );
267+ cell .setCellValue (Messages .PosErrColumn );
268+ }
269+ if (sevr_stat )
270+ {
271+ cell = row .createCell (cell .getColumnIndex ()+1 , CellType .STRING );
272+ cell .setCellStyle (header_style );
273+ cell .setCellValue (Messages .SeverityColumn );
274+
275+ cell = row .createCell (cell .getColumnIndex ()+1 , CellType .STRING );
276+ cell .setCellStyle (header_style );
277+ cell .setCellValue (Messages .StatusColumn );
278+ }
196279 }
197280
198281 // Create spreadsheet interpolation
@@ -210,28 +293,72 @@ protected void performExport(final JobMonitor monitor,
210293 final Instant time = iter .getTime ();
211294 final VType line [] = iter .next ();
212295
213- row = sheet .createRow (row .getRowNum () + 1 );
214- cell = row .createCell (0 , CellType .NUMERIC );
215- if (unixTimeStamp )
216- cell .setCellValue (time .toEpochMilli ());
217- else
218- {
219- cell .setCellValue (LocalDateTime .ofInstant (time , zone ));
220- cell .setCellStyle (timestamp_style );
221- }
222-
296+ cell = createTimeCell (row = sheet .createRow (row .getRowNum () + 1 ), time );
223297 for (int i =0 ; i <line .length ; ++i )
224- {
225- cell = createCell (row , cell .getColumnIndex ()+1 , line [i ]);
226- }
298+ cell = createValueCells (row , cell .getColumnIndex ()+1 , line [i ]);
227299 ++line_count ;
228300 if ((line_count % PROGRESS_UPDATE_LINES ) == 0 )
229301 monitor .beginTask (MessageFormat .format ("Wrote {0} samples" , line_count ));
230302 if (monitor .isCanceled ())
231303 break ;
232304 }
233305 iter .close ();
306+ }
234307
235- wb .write (out );
308+ private void exportList (final JobMonitor monitor ) throws Exception
309+ {
310+ for (ModelItem item : model .getItems ())
311+ {
312+ // Item data header
313+ row = sheet .createRow (row .getRowNum () + 2 );
314+ Cell cell = row .createCell (0 , CellType .STRING );
315+ cell .setCellStyle (header_style );
316+ cell .setCellValue (Messages .TimeColumn );
317+ cell = row .createCell (cell .getColumnIndex ()+1 , CellType .STRING );
318+ cell .setCellStyle (header_style );
319+ cell .setCellValue (item .getResolvedName ());
320+
321+ if (min_max )
322+ {
323+ cell = row .createCell (cell .getColumnIndex ()+1 , CellType .STRING );
324+ cell .setCellStyle (header_style );
325+ cell .setCellValue (Messages .NegErrColumn );
326+
327+ cell = row .createCell (cell .getColumnIndex ()+1 , CellType .STRING );
328+ cell .setCellStyle (header_style );
329+ cell .setCellValue (Messages .PosErrColumn );
330+ }
331+ if (sevr_stat )
332+ {
333+ cell = row .createCell (cell .getColumnIndex ()+1 , CellType .STRING );
334+ cell .setCellStyle (header_style );
335+ cell .setCellValue (Messages .SeverityColumn );
336+
337+ cell = row .createCell (cell .getColumnIndex ()+1 , CellType .STRING );
338+ cell .setCellStyle (header_style );
339+ cell .setCellValue (Messages .StatusColumn );
340+ }
341+
342+ // Dump data lines
343+ monitor .beginTask (MessageFormat .format ("Fetching data for {0}" , item .getName ()));
344+ final ValueIterator iter = createValueIterator (item );
345+ long line_count = 0 ;
346+ while (iter .hasNext () && !monitor .isCanceled ())
347+ {
348+ final VType value = iter .next ();
349+ final Instant time = org .phoebus .core .vtypes .VTypeHelper .getTimestamp (value );
350+
351+ cell = createTimeCell (row = sheet .createRow (row .getRowNum () + 1 ), time );
352+ cell = createValueCells (row , cell .getColumnIndex ()+1 , value );
353+ ++line_count ;
354+ if ((line_count % PROGRESS_UPDATE_LINES ) == 0 )
355+ monitor .beginTask (MessageFormat .format ("Wrote {0} samples" , line_count ));
356+ if (monitor .isCanceled ())
357+ break ;
358+ }
359+ iter .close ();
360+ if (monitor .isCanceled ())
361+ break ;
362+ }
236363 }
237364}
0 commit comments