/*******************************************************************************
* Copyright (c) 2009 STMicroelectronics.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Marzia Maugeri <marzia.maugeri@st.com> - initial API and implementation
*******************************************************************************/
package org.eclipse.linuxtools.dataviewers.abstractviewers;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.linuxtools.dataviewers.STDataViewersActivator;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Item;
/**
* This comparator is used to export the data of a STViewer to CSV format file
*/
public class STDataViewersCSVExporter {
private final AbstractSTViewer stViewer;
private PrintStream ps = null;
private ISTDataViewersField[] fields = null;
private List<Object> expandedElts = null;
private Comparator<Object> comparator;
private Object input = null;
private IContentProvider contentProvider = null;
private IDialogSettings state = null;
private IProgressMonitor monitor;
private String filePath = null;
private String csvSeparator = null;
private String csvChildMarker = null;
private String csvLastChildMarker = null;
private String csvChildLink = null;
private String csvNoChildLink = null;
private String csvLeafMarker = null;
private String csvNodeMarker = null;
private boolean expandAll = false;
private boolean showHiddenColumns = false;
private boolean exportTreePrefix = false;
/**
* It creates a new instance of exporter
*
* @param stViewer
*/
public STDataViewersCSVExporter(AbstractSTViewer stViewer) {
this.stViewer = stViewer;
this.ps = System.out;
this.state = stViewer.getViewerSettings()
.getSection(STDataViewersCSVExporterConstants.TAG_SECTION_CSV_EXPORTER);
restoreState();
}
/**
* Gets from the .setting the export parameters
*/
public void restoreState() {
if (state == null) {
resetState();
return;
}
try {
filePath = state.get(STDataViewersCSVExporterConstants.TAG_EXPORTER_OUTPUT_FILE_PATH);
if (filePath == null) {
resetState();
return;
}
csvSeparator = state.get(STDataViewersCSVExporterConstants.TAG_EXPORTER_SEPARATOR);
if (csvSeparator == null) {
resetState();
return;
}
csvChildMarker = state.get(STDataViewersCSVExporterConstants.TAG_EXPORTER_CHILD_MARKER);
if (csvChildMarker == null) {
resetState();
return;
}
csvLastChildMarker = state.get(STDataViewersCSVExporterConstants.TAG_EXPORTER_LAST_CHILD_MARKER);
if (csvLastChildMarker == null) {
resetState();
return;
}
csvChildLink = state.get(STDataViewersCSVExporterConstants.TAG_EXPORTER_CHILD_LINK);
if (csvChildLink == null) {
resetState();
return;
}
csvNoChildLink = state.get(STDataViewersCSVExporterConstants.TAG_EXPORTER_NO_CHILD_LINK);
if (csvNoChildLink == null) {
resetState();
return;
}
csvLeafMarker = state.get(STDataViewersCSVExporterConstants.TAG_EXPORTER_LEAF_MARKER);
if (csvLeafMarker == null) {
resetState();
return;
}
csvNodeMarker = state.get(STDataViewersCSVExporterConstants.TAG_EXPORTER_NODE_MARKER);
if (csvNodeMarker == null) {
resetState();
return;
}
String temp = state.get(STDataViewersCSVExporterConstants.TAG_EXPORTER_EXPAND_ALL);
if (temp == null) {
resetState();
return;
} else {
expandAll = Boolean.parseBoolean(temp);
}
temp = state.get(STDataViewersCSVExporterConstants.TAG_EXPORTER_SHOW_HIDDEN_COLUMNS);
if (temp == null) {
resetState();
return;
} else {
showHiddenColumns = Boolean.parseBoolean(temp);
}
if (isTreeViewerExporter()) {
temp = state.get(STDataViewersCSVExporterConstants.TAG_EXPORTER_TREE_PREFIX);
if (temp == null) {
resetState();
return;
} else {
exportTreePrefix = Boolean.parseBoolean(temp);
}
} else {
exportTreePrefix = false;
}
} catch (NumberFormatException nfe) {
IStatus s = new Status(IStatus.WARNING, STDataViewersActivator.PLUGIN_ID,
"Invalid parameter, resetting configuration!\n" + nfe.getMessage(), nfe);
logStatus(s);
resetState();
}
}
/**
* Save into the .setting the export parameters
*/
public void saveState() {
if (state == null) {
state = stViewer.getViewerSettings().addNewSection(
STDataViewersCSVExporterConstants.TAG_SECTION_CSV_EXPORTER);
}
state.put(STDataViewersCSVExporterConstants.TAG_EXPORTER_OUTPUT_FILE_PATH, filePath);
state.put(STDataViewersCSVExporterConstants.TAG_EXPORTER_SEPARATOR, csvSeparator);
state.put(STDataViewersCSVExporterConstants.TAG_EXPORTER_CHILD_MARKER, csvChildMarker);
state.put(STDataViewersCSVExporterConstants.TAG_EXPORTER_LAST_CHILD_MARKER, csvLastChildMarker);
state.put(STDataViewersCSVExporterConstants.TAG_EXPORTER_CHILD_LINK, csvChildLink);
state.put(STDataViewersCSVExporterConstants.TAG_EXPORTER_NO_CHILD_LINK, csvNoChildLink);
state.put(STDataViewersCSVExporterConstants.TAG_EXPORTER_LEAF_MARKER, csvLeafMarker);
state.put(STDataViewersCSVExporterConstants.TAG_EXPORTER_NODE_MARKER, csvNodeMarker);
state.put(STDataViewersCSVExporterConstants.TAG_EXPORTER_EXPAND_ALL, expandAll);
state.put(STDataViewersCSVExporterConstants.TAG_EXPORTER_SHOW_HIDDEN_COLUMNS, showHiddenColumns);
if (isTreeViewerExporter()) {
state.put(STDataViewersCSVExporterConstants.TAG_EXPORTER_TREE_PREFIX, exportTreePrefix);
} else {
state.put(STDataViewersCSVExporterConstants.TAG_EXPORTER_TREE_PREFIX, false);
}
}
/**
* Sets to default the parameters used during the export
*/
public void resetState() {
filePath = STDataViewersCSVExporterConstants.DEFAULT_EXPORTER_OUTPUT_FILE_PATH;
csvSeparator = STDataViewersCSVExporterConstants.DEFAULT_EXPORTER_SEPARATOR;
csvChildMarker = STDataViewersCSVExporterConstants.DEFAULT_EXPORTER_CHILD_MARKER;
csvLastChildMarker = STDataViewersCSVExporterConstants.DEFAULT_EXPORTER_LAST_CHILD_MARKER;
csvChildLink = STDataViewersCSVExporterConstants.DEFAULT_EXPORTER_CHILD_LINK;
csvNoChildLink = STDataViewersCSVExporterConstants.DEFAULT_EXPORTER_NO_CHILD_LINK;
csvLeafMarker = STDataViewersCSVExporterConstants.DEFAULT_EXPORTER_LEAF_MARKER;
csvNodeMarker = STDataViewersCSVExporterConstants.DEFAULT_EXPORTER_NODE_MARKER;
expandAll = STDataViewersCSVExporterConstants.DEFAULT_EXPORTER_EXPAND_ALL;
showHiddenColumns = STDataViewersCSVExporterConstants.DEFAULT_EXPORTER_SHOW_HIDDEN_COLUMNS;
if (isTreeViewerExporter()) {
exportTreePrefix = STDataViewersCSVExporterConstants.DEFAULT_EXPORTER_TREE_PREFIX;
} else {
exportTreePrefix = false;
}
}
private void logStatus(IStatus s) {
STDataViewersActivator.getDefault().getLog().log(s);
}
public void exportTo(String filePath) {
setFilePath(filePath);
export();
}
public void exportTo(String filePath, IProgressMonitor monitor) {
setFilePath(filePath);
export(monitor);
}
public void export() {
export(new NullProgressMonitor());
}
public void export(IProgressMonitor monitor) {
// monitoring
this.monitor = monitor;
monitor.beginTask("Exporting to CSV (file: " + getFilePath() + ")", IProgressMonitor.UNKNOWN);
// save this configuration
saveState();
// init the printStream
initPrintStream(filePath);
// get the viewer's parameters
monitor.subTask("collecting viewer's parameters...");
collectViewerParameters();
// start dumping to csv file
dumpColumnHeaders();
if (input != null) {
if (contentProvider instanceof ITreeContentProvider) {
ITreeContentProvider treeContentProvider = (ITreeContentProvider) contentProvider;
Object[] topElements = treeContentProvider.getElements(input);
if (topElements != null) {
// monitoring
int work = topElements.length;
for (Object element : topElements) {
if (treeContentProvider.hasChildren(element)) {
work += treeContentProvider.getChildren(element).length;
}
}
monitor.beginTask("Exporting to CSV (file: " + getFilePath() + ")", work);
monitor.subTask("exporting tree data...");
// monitoring stuff
int tempWork = 0;
int workFloor = topElements.length / 100;
if (workFloor == 0) {
workFloor = 1;
}
// exporting tree
Arrays.sort(topElements, comparator);
for (int i = 0; i < topElements.length; i++) {
dumpTreeData(treeContentProvider, topElements[i], "", i == topElements.length - 1, true);
// monitoring
tempWork++;
if (tempWork >= workFloor) {
if (monitor.isCanceled()) {
ps.close();
return;
}
monitor.worked(tempWork);
tempWork = 0;
}
}
// monitoring
monitor.worked(tempWork);
}
} else if (contentProvider instanceof IStructuredContentProvider) {
IStructuredContentProvider structContentProvider = (IStructuredContentProvider) contentProvider;
Object[] topElements = structContentProvider.getElements(input);
if (topElements != null) {
// monitoring
monitor.beginTask("Exporting to CSV (file: " + getFilePath() + ")", topElements.length);
monitor.subTask("exporting table data...");
// monitoring stuff
int tempWork = 0;
int workFloor = topElements.length / 100;
if (workFloor == 0) {
workFloor = 1;
}
// exporting table
Arrays.sort(topElements, comparator);
for (int n = 0; n < topElements.length; n++) {
if (n < topElements.length - 1) {
dumpNodeData(topElements[n], csvChildMarker);
} else {
dumpNodeData(topElements[n], csvLastChildMarker);
}
// monitoring
tempWork++;
if (tempWork >= workFloor) {
if (monitor.isCanceled()) {
ps.close();
return;
}
monitor.worked(tempWork);
tempWork = 0;
}
}
// monitoring
monitor.worked(tempWork);
}
}
}
// close the stream
ps.close();
// end monitoring
monitor.done();
IFile c = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(new Path(getFilePath()));
if (c != null) {
try {
c.refreshLocal(1, new NullProgressMonitor());
} catch (CoreException e) {
STDataViewersActivator.getDefault().getLog().log(e.getStatus());
}
}
}
private void initPrintStream(String filePath) {
try {
File outputFile = new File(filePath);
if (outputFile.exists())
outputFile.delete();
outputFile.createNewFile();
this.ps = new PrintStream(outputFile);
} catch (IOException e) {
Status s = new Status(IStatus.ERROR, STDataViewersActivator.PLUGIN_ID,
"Invalid file! Dumping to stdout...\n" + e.getMessage(), e);
logStatus(s);
this.ps = System.out;
} catch (NullPointerException e) {
Status s = new Status(IStatus.ERROR, STDataViewersActivator.PLUGIN_ID,
"File has not been set! Dumping to stdout...\n" + e.getMessage(), e);
logStatus(s);
this.ps = System.out;
}
}
private void collectViewerParameters() {
Display.getDefault().syncExec(() -> {
// getting columns with the right order
Item[] unOrdColumns = stViewer.getColumns();
Item[] columns = new Item[unOrdColumns.length];
int[] columnOrder = stViewer.getColumnOrder();
for (int i1 = 0; i1 < unOrdColumns.length; i1++) {
columns[i1] = unOrdColumns[columnOrder[i1]];
}
// getting fields mapping
// (before removing hidden columns)
Map<Item, ISTDataViewersField> fieldsMap = new HashMap<>();
for (Item column : columns) {
fieldsMap.put(column, (ISTDataViewersField) column.getData());
}
// creating a GUI-thread-independent comparator
comparator = new CSVDataComparator(stViewer.getTableSorter(), fieldsMap);
// getting only visible columns, using the column order
if (!showHiddenColumns) {
int[] columnsState = stViewer.getHideShowManager().getColumnsState();
List<Item> enabledColumns = new ArrayList<>();
for (int i2 = 0; i2 < columnsState.length; i2++) {
if (columnsState[columnOrder[i2]] == STDataViewersHideShowManager.STATE_SHOWN) {
enabledColumns.add(columns[i2]);
}
}
columns = enabledColumns.toArray(new Item[enabledColumns.size()]);
}
// collecting fields from columns (ordered & shown)
fields = new ISTDataViewersField[columns.length];
for (int i3 = 0; i3 < columns.length; i3++) {
fields[i3] = (ISTDataViewersField) columns[i3].getData();
}
// getting input object
input = stViewer.getViewer().getInput();
// getting content provider
contentProvider = stViewer.getViewer().getContentProvider();
// getting expanded elements if necessary
expandedElts = new ArrayList<>();
if (!expandAll && stViewer.getViewer() instanceof TreeViewer) {
TreeViewer tv = (TreeViewer) stViewer.getViewer();
expandedElts = Arrays.asList(tv.getExpandedElements());
}
});
}
private void dumpColumnHeaders() {
printPrefix("Hierarchy");
for (int i = 0; i < fields.length; i++) {
ps.print(fields[i].getColumnHeaderText());
printSeparator(i, fields.length);
}
}
private void dumpTreeData(ITreeContentProvider tcp, Object element, String prefix, boolean isLastChild,
boolean monitoring) {
String childMarker = isLastChild ? csvLastChildMarker : csvChildMarker;
boolean isLeaf = !tcp.hasChildren(element);
String leafMarker = (isLeaf ? csvLeafMarker : csvNodeMarker);
dumpNodeData(element, prefix + childMarker + leafMarker);
if ((expandAll || expandedElts.contains(element)) && !isLeaf) {
Object[] children = tcp.getChildren(element);
if (children != null) {
// monitoring stuff
int tempWork = 0;
int workFloor = children.length / 100;
if (workFloor == 0) {
workFloor = 1;
}
// exporting children
Arrays.sort(children, comparator);
for (int i = 0; i < children.length; i++) {
String prefixAdd = isLastChild ? csvNoChildLink : csvChildLink;
dumpTreeData(tcp, children[i], prefix + prefixAdd, i == children.length - 1, false);
// monitoring
if (monitor != null && monitoring) {
tempWork++;
if (tempWork >= workFloor) {
monitor.worked(tempWork);
tempWork = 0;
}
}
}
// monitoring
if (monitor != null && monitoring && tempWork > 0) {
monitor.worked(tempWork);
}
}
}
}
private void dumpNodeData(Object element, String prefix) {
for (int i = 0; i < fields.length; i++) {
printNode(i, prefix, getText(i, element));
printSeparator(i, fields.length);
}
}
private void printNode(int col, String prefix, String text) {
if (col == 0) {
printPrefix(prefix);
}
ps.print(text);
}
private void printPrefix(String prefix) {
if (exportTreePrefix) {
ps.print(prefix);
ps.print(csvSeparator);
}
}
private void printSeparator(int i, int length) {
if (i == length - 1) {
ps.print("\n");
} else {
ps.print(csvSeparator);
}
}
private String getText(int i, Object obj) {
return fields[i].getValue(obj);
}
public String getFilePath() {
return filePath;
}
public String getCSVSeparator() {
return csvSeparator;
}
public String getCSVChildMarker() {
return csvChildMarker;
}
public String getCSVLastChildMarker() {
return csvLastChildMarker;
}
public String getCSVChildLink() {
return csvChildLink;
}
public String getCSVNoChildLink() {
return csvNoChildLink;
}
public String getCSVLeafMarker() {
return csvLeafMarker;
}
public String getCSVNodeMarker() {
return csvNodeMarker;
}
public boolean getExpandAll() {
return expandAll;
}
public boolean getShowHiddenColumns() {
return showHiddenColumns;
}
public boolean getExportTreePrefix() {
return exportTreePrefix;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public void setCSVSeparator(String separator) {
csvSeparator = separator;
}
public void setCSVChildMarker(String childMarker) {
csvChildMarker = childMarker;
}
public void setCSVLastChildMarker(String lastChildMarker) {
csvLastChildMarker = lastChildMarker;
}
public void setCSVChildLink(String childLink) {
csvChildLink = childLink;
}
public void setCSVNoChildLink(String noChildLink) {
csvNoChildLink = noChildLink;
}
public void setCSVLeafMarker(String leafMarker) {
csvLeafMarker = leafMarker;
}
public void setCSVNodeMarker(String nodeMarker) {
csvNodeMarker = nodeMarker;
}
public void setExpandAll(boolean expandAll) {
this.expandAll = expandAll;
}
public void setShowHiddenColumns(boolean showHiddenColumns) {
this.showHiddenColumns = showHiddenColumns;
}
public void setExportTreePrefix(boolean exportTreePrefix) {
if (isTreeViewerExporter()) {
this.exportTreePrefix = exportTreePrefix;
} else {
this.exportTreePrefix = false;
}
}
private static class CSVDataComparator extends STDataViewersComparator {
private final Map<Item, ISTDataViewersField> fieldsMap;
public CSVDataComparator(STDataViewersComparator other, Map<Item, ISTDataViewersField> fieldsMap) {
super(other);
this.fieldsMap = fieldsMap;
}
@Override
protected ISTDataViewersField getField(Item column) {
return fieldsMap.get(column);
}
}
public boolean isTreeViewerExporter() {
return stViewer instanceof AbstractSTTreeViewer;
}
}