Skip to content

Commit 52b511c

Browse files
author
kasemir
committed
Databrowser: Add Excel export...
1 parent 20dd0cc commit 52b511c

File tree

13 files changed

+424
-45
lines changed

13 files changed

+424
-45
lines changed

app/databrowser/pom.xml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,37 @@
7575
<artifactId>commons-math3</artifactId>
7676
<version>${apache.commons.math.version}</version>
7777
</dependency>
78+
<!-- Lib to read/write MS Office (Excel, ..) files, fetching only POI itself -->
79+
<dependency>
80+
<groupId>org.apache.poi</groupId>
81+
<artifactId>poi</artifactId>
82+
<exclusions>
83+
<exclusion>
84+
<groupId>com.zaxxer</groupId>
85+
<artifactId>SparseBitSet</artifactId>
86+
</exclusion>
87+
<exclusion>
88+
<groupId>org.slf4j</groupId>
89+
<artifactId>slf4j-api</artifactId>
90+
</exclusion>
91+
<exclusion>
92+
<groupId>org.slf4j</groupId>
93+
<artifactId>jcl-over-slf4j</artifactId>
94+
</exclusion>
95+
<exclusion>
96+
<groupId>commons-codec</groupId>
97+
<artifactId>commons-codec</artifactId>
98+
</exclusion>
99+
<exclusion>
100+
<groupId>org.apache.commons</groupId>
101+
<artifactId>commons-collections4</artifactId>
102+
</exclusion>
103+
<exclusion>
104+
<groupId>org.apache.commons</groupId>
105+
<artifactId>commons-math3</artifactId>
106+
</exclusion>
107+
</exclusions>
108+
<version>5.0.0</version>
109+
</dependency>
78110
</dependencies>
79111
</project>

app/databrowser/src/main/java/org/csstudio/trends/databrowser3/Messages.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ public class Messages
118118
ExportStartExport,
119119
ExportTabular,
120120
ExportTabularTT,
121+
ExportTypeExcel,
122+
ExportTypeExcelFilenamePrompt,
123+
ExportTypeExcelTT,
121124
ExportTypeMatlab,
122125
ExportTypeMatlabTT,
123126
ExportTypeSpreadsheet,
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Oak Ridge National Laboratory.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
******************************************************************************/
8+
package org.csstudio.trends.databrowser3.export;
9+
10+
import java.io.PrintStream;
11+
import java.text.MessageFormat;
12+
import java.time.Instant;
13+
import java.time.LocalDateTime;
14+
import java.time.ZoneId;
15+
import java.util.ArrayList;
16+
import java.util.List;
17+
import java.util.Objects;
18+
import java.util.function.Consumer;
19+
20+
import org.csstudio.trends.databrowser3.Messages;
21+
import org.csstudio.trends.databrowser3.model.ArchiveDataSource;
22+
import org.csstudio.trends.databrowser3.model.Model;
23+
import org.csstudio.trends.databrowser3.model.ModelItem;
24+
import org.csstudio.trends.databrowser3.model.PVItem;
25+
import org.epics.vtype.VEnum;
26+
import org.epics.vtype.VNumber;
27+
import org.epics.vtype.VString;
28+
import org.epics.vtype.VType;
29+
import org.phoebus.archive.reader.SpreadsheetIterator;
30+
import org.phoebus.archive.reader.ValueIterator;
31+
import org.phoebus.framework.jobs.JobMonitor;
32+
import org.phoebus.util.time.SecondsParser;
33+
import org.phoebus.util.time.TimestampFormats;
34+
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
35+
import org.apache.poi.ss.usermodel.Cell;
36+
import org.apache.poi.ss.usermodel.CellStyle;
37+
import org.apache.poi.ss.usermodel.CellType;
38+
import org.apache.poi.ss.usermodel.FillPatternType;
39+
import org.apache.poi.ss.usermodel.Font;
40+
import org.apache.poi.ss.usermodel.IndexedColors;
41+
import org.apache.poi.ss.usermodel.Row;
42+
import org.apache.poi.ss.usermodel.Sheet;
43+
import org.apache.poi.ss.usermodel.Workbook;
44+
45+
/** Export Job for exporting data from Model as Excel file
46+
* @author Kay Kasemir
47+
*/
48+
@SuppressWarnings("nls")
49+
public class ExcelExportJob extends ExportJob
50+
{
51+
private Workbook wb = null;
52+
private CellStyle comment_style, header_style, timestamp_style;
53+
private Sheet sheet;
54+
private Row row;
55+
private ZoneId zone = ZoneId.systemDefault();
56+
private final boolean tabular, min_max, sevr_stat;
57+
58+
/** @param model Model
59+
* @param start Start time
60+
* @param end End time
61+
* @param source Data source
62+
* @param optimize_parameter Bin count
63+
* @param filename Export file name
64+
* @param error_handler Error handler
65+
* @param unixTimeStamp Use UNIX time stamp epoch?
66+
*/
67+
public ExcelExportJob(final Model model,
68+
final Instant start, final Instant end, final Source source,
69+
final boolean tabular, final boolean min_max, final boolean sevr_stat,
70+
final double optimize_parameter,
71+
final String filename,
72+
final Consumer<Exception> error_handler,
73+
final boolean unixTimeStamp)
74+
{
75+
super("", model, start, end, source, optimize_parameter, filename, error_handler, unixTimeStamp);
76+
this.tabular = tabular;
77+
this.min_max = min_max;
78+
this.sevr_stat = sevr_stat;
79+
}
80+
81+
private void addComment(final Row row, final String label, final String text)
82+
{
83+
Cell cell = row.createCell(0, CellType.STRING);
84+
cell.setCellValue(label);
85+
cell.setCellStyle(comment_style);
86+
if (text != null)
87+
{
88+
cell = row.createCell(1, CellType.STRING);
89+
cell.setCellValue(text);
90+
cell.setCellStyle(comment_style);
91+
}
92+
}
93+
94+
@Override
95+
protected void printExportInfo(final PrintStream out) throws Exception
96+
{
97+
wb = new HSSFWorkbook();
98+
99+
comment_style = wb.createCellStyle();
100+
Font font = wb.createFont();
101+
font.setBold(true);
102+
font.setColor(IndexedColors.DARK_BLUE.getIndex());
103+
comment_style.setFont(font);
104+
105+
header_style = wb.createCellStyle();
106+
font = wb.createFont();
107+
font.setItalic(true);
108+
header_style.setFont(font);
109+
header_style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
110+
header_style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
111+
112+
timestamp_style = wb.createCellStyle();
113+
timestamp_style.setDataFormat(
114+
wb.getCreationHelper()
115+
.createDataFormat()
116+
.getFormat("yyyy-mm-dd hh:mm:ss.000"));
117+
118+
sheet = wb.createSheet("Archive Data");
119+
120+
addComment(row = sheet.createRow(0), "Created by CS-Studio Data Browser", null);
121+
addComment(row = sheet.createRow(row.getRowNum() + 2), "Start time", TimestampFormats.MILLI_FORMAT.format(start));
122+
addComment(row = sheet.createRow(row.getRowNum() + 1), "End time", TimestampFormats.MILLI_FORMAT.format(end));
123+
addComment(row = sheet.createRow(row.getRowNum() + 1), "Source", source.toString());
124+
125+
if (source == Source.OPTIMIZED_ARCHIVE)
126+
addComment(row = sheet.createRow(row.getRowNum() + 1), "Desired Value Count", Double.toString(optimize_parameter));
127+
else if (source == Source.LINEAR_INTERPOLATION)
128+
addComment(row = sheet.createRow(row.getRowNum() + 1), "Interpolation Interval", SecondsParser.formatSeconds(optimize_parameter));
129+
}
130+
131+
private Cell createCell(final Row row, final int column, final VType value)
132+
{
133+
final Cell cell;
134+
if (value instanceof VNumber v)
135+
{
136+
cell = row.createCell(column, CellType.NUMERIC);
137+
cell.setCellValue(v.getValue().doubleValue());
138+
}
139+
else if (value instanceof VEnum v)
140+
{
141+
cell = row.createCell(column, CellType.NUMERIC);
142+
cell.setCellValue(v.getIndex());
143+
}
144+
else if (value instanceof VString v)
145+
{
146+
cell = row.createCell(column, CellType.STRING);
147+
cell.setCellValue(v.getValue());
148+
}
149+
else if (value == null)
150+
cell = row.createCell(column, CellType.BLANK);
151+
else
152+
{
153+
cell = row.createCell(column, CellType.STRING);
154+
cell.setCellValue(Objects.toString(value));
155+
}
156+
return cell;
157+
}
158+
159+
@Override
160+
protected void performExport(final JobMonitor monitor,
161+
final PrintStream out) throws Exception
162+
{
163+
// Item header
164+
for (ModelItem item : model.getItems())
165+
{
166+
addComment(row = sheet.createRow(row.getRowNum() + 2), "Channel", item.getResolvedName());
167+
if (! item.getName().equals(item.getDisplayName()))
168+
addComment(row = sheet.createRow(row.getRowNum() + 1), "Name", item.getResolvedDisplayName());
169+
170+
if (item instanceof PVItem)
171+
{
172+
final PVItem pv = (PVItem) item;
173+
addComment(row = sheet.createRow(row.getRowNum() + 1), "Archives:", null);
174+
175+
int i=1;
176+
for (ArchiveDataSource archive : pv.getArchiveDataSources())
177+
{
178+
addComment(row = sheet.createRow(row.getRowNum() + 1),
179+
i + ") " + archive.getName(),
180+
"URL " + archive.getUrl());
181+
++i;
182+
}
183+
}
184+
}
185+
186+
// Spreadsheet data header
187+
row = sheet.createRow(row.getRowNum() + 2);
188+
Cell cell = row.createCell(0, CellType.STRING);
189+
cell.setCellStyle(header_style);
190+
cell.setCellValue(Messages.TimeColumn);
191+
for (ModelItem item : model.getItems())
192+
{
193+
cell = row.createCell(cell.getColumnIndex()+1, CellType.STRING);
194+
cell.setCellStyle(header_style);
195+
cell.setCellValue(item.getResolvedName());
196+
}
197+
198+
// Create spreadsheet interpolation
199+
final List<ValueIterator> iters = new ArrayList<>();
200+
for (ModelItem item : model.getItems())
201+
{
202+
monitor.beginTask(MessageFormat.format("Fetching data for {0}", item.getName()));
203+
iters.add(createValueIterator(item));
204+
}
205+
final SpreadsheetIterator iter = new SpreadsheetIterator(iters.toArray(new ValueIterator[iters.size()]));
206+
// Dump the spreadsheet lines
207+
long line_count = 0;
208+
while (iter.hasNext() && !monitor.isCanceled())
209+
{
210+
final Instant time = iter.getTime();
211+
final VType line[] = iter.next();
212+
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+
223+
for (int i=0; i<line.length; ++i)
224+
{
225+
cell = createCell(row, cell.getColumnIndex()+1, line[i]);
226+
}
227+
++line_count;
228+
if ((line_count % PROGRESS_UPDATE_LINES) == 0)
229+
monitor.beginTask(MessageFormat.format("Wrote {0} samples", line_count));
230+
if (monitor.isCanceled())
231+
break;
232+
}
233+
iter.close();
234+
235+
wb.write(out);
236+
}
237+
}

app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/ExportJob.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,11 @@ public final void run(final JobMonitor monitor)
155155
monitor.done();
156156
}
157157

158-
/** Print file header, gets invoked before <code>performExport</code> */
159-
protected void printExportInfo(final PrintStream out)
158+
/** Print file header, gets invoked before <code>performExport</code>
159+
* @param out PrintStream for output
160+
* @throws Exception on error
161+
*/
162+
protected void printExportInfo(final PrintStream out) throws Exception
160163
{
161164
out.println(comment + "Created by CS-Studio Data Browser");
162165
out.println(comment);

app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/MatlabScriptExportJob.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public MatlabScriptExportJob(final Model model, final Instant start,
4848

4949
/** {@inheritDoc} */
5050
@Override
51-
protected void printExportInfo(final PrintStream out)
51+
protected void printExportInfo(final PrintStream out) throws Exception
5252
{
5353
super.printExportInfo(out);
5454
out.println(comment);

app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/PlainExportJob.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public PlainExportJob(final Model model,
5353
}
5454

5555
@Override
56-
protected void printExportInfo(final PrintStream out)
56+
protected void printExportInfo(final PrintStream out) throws Exception
5757
{
5858
super.printExportInfo(out);
5959
out.println(comment + "Format : " + formatter.toString());

app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/SpreadsheetExportJob.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ protected void performExport(final JobMonitor monitor,
6666
out.print(Messages.Export_Delimiter + item.getResolvedName() + " " + formatter.getHeader());
6767
out.println();
6868

69-
// Create speadsheet interpolation
69+
// Create spreadsheet interpolation
7070
final List<ValueIterator> iters = new ArrayList<>();
7171
for (ModelItem item : model.getItems())
7272
{

0 commit comments

Comments
 (0)