package com.openMap1.mapper.views;
import java.io.InputStream;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.Vector;
import com.openMap1.mapper.presentation.FileSaverWizard;
import com.openMap1.mapper.util.EclipseFileUtil;
import com.openMap1.mapper.util.XMLUtil;
import com.openMap1.mapper.core.MapperException;
import com.openMap1.mapper.core.XMLException;
import org.eclipse.core.resources.IFile;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.ui.PlatformUI;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Helper class for any tabular view whose contents may
* need to be saved as XML or a csv file.
*
* @author robert
*
*/
public class ViewSaver {
private boolean tracing = false;
private String wizardTitle;
private String pageTitle;
private SaveableView view;
/**
* Any saveable view must create one of these in order to save itself
* @param view the view which creates this ViewSaver
* @param wizardTitle title of the wizard which asks for a save file name
* @param pageTitle title of the page which asks for a save file name (may be more detailed)
*/
public ViewSaver(SaveableView view, String wizardTitle, String pageTitle)
{
this.wizardTitle = wizardTitle;
this.pageTitle = pageTitle;
this.view = view;
}
/**
* constructor for when you only need the DOM of the saved view, and you do not need
* to save it in a separate file
* @param view
*/
public ViewSaver(SaveableView view)
{
this.view = view;
}
/**
* called to save the contents of a view - first asking the user for a destination file
* The extension must be 'xml' to make an xml file, or 'csv' to make a comma-separated value file
*/
public void saveResults()
{
FileSaverWizard wizard = new FileSaverWizard(wizardTitle,pageTitle);
wizard.init(PlatformUI.getWorkbench(), null);
WizardDialog dialog = new WizardDialog(WorkBenchUtil.getShell(),wizard);
dialog.open();
IFile viewSaveFile = wizard.getViewSaveFile();
if (viewSaveFile != null) try
{
String extension = viewSaveFile.getFileExtension();
if (extension == null) throw new MapperException("No file extension");
// csv (comma separated values, for Excel)
else if (extension.equals("csv"))
{
writeViewContents(viewSaveFile,false);
}
else // any other extension is saved as an XML file
{
Document doc = XMLUtil.makeOutDoc();
// prepare the DOM
Element root = resultDOM(doc);
doc.appendChild(root);
// write out the XML. true = with formatting
EclipseFileUtil.writeOutputResource(doc, viewSaveFile, true);
}
}
catch (Exception ex)
{
System.out.println(ex.getMessage());
ex.printStackTrace();
WorkBenchUtil.showMessage("Failed to write view contents" , ex.getMessage());
}
}
/**
* @param doc XML Document used for creating Elements
* @return Element tree describing the view contents
*/
public Element resultDOM(Document doc)
{
Vector<Vector<String>> sRes = sortedResults();
Element root = null;
try{
// root of the document
root = XMLUtil.newElement(doc, "ViewContents");
root.setAttribute("view",view.getTitle());
// view-specific header
Element header = XMLUtil.newElement(doc, "HeaderInformation");
view.fillHeaderElement(doc, header);
root.appendChild(header);
// definition of column headers
Element columns = XMLUtil.newElement(doc, "TableColumns");
root.appendChild(columns);
for (Iterator<String> ic = view.columnHeaders().iterator();ic.hasNext();)
columns.appendChild(XMLUtil.textElement(doc, "column", XMLUtil.legalTagName(ic.next())));
// rows of the view table
Element content = XMLUtil.newElement(doc, "TableContent");
root.appendChild(content);
for (Iterator <Vector<String>> ir = sRes.iterator(); ir.hasNext();)
{
Element rowEl = XMLUtil.newElement(doc, "row");
content.appendChild(rowEl);
Vector<String> row = ir.next();
for (int c = 0; c < row.size(); c++)
{
String tagName = XMLUtil.legalTagName(view.columnHeaders().get(c));
rowEl.appendChild(XMLUtil.textElement(doc, tagName, row.get(c)));
}
}
}
catch (XMLException ex) {System.out.println("Failed to construct view contents XML: " + ex.getMessage());}
return root;
}
/**
* Comma-separated value output of the contents of a view
*/
public void writeViewContents(IFile file, boolean createFile) throws MapperException
{
String separator = ",";
Vector<Vector<String>> sRes = sortedResults();
String headerString = "";
for (Iterator<String> ic = view.columnHeaders().iterator();ic.hasNext();)
{
String header = noSeparators(ic.next(),separator);
headerString = headerString + header ;
if (ic.hasNext())headerString = headerString + separator ;
}
if (createFile)
{
InputStream firstLine = EclipseFileUtil.textStream(headerString);
try {file.create(firstLine, false, null);}
catch (Exception ex) {throw new MapperException("Failed to create IFile: " + ex.getMessage());}
}
else EclipseFileUtil.appendLine(headerString, file);
trace(headerString);
for (Iterator <Vector<String>> ir = sRes.iterator();ir.hasNext();)
{
Vector<String> row = ir.next();
String rowString = "";
for (Iterator<String> ic = row.iterator();ic.hasNext();)
{
String field = ic.next();
String cell = noSeparators(field,separator);
rowString = rowString + cell;
if (ic.hasNext()) rowString = rowString + separator ;
}
EclipseFileUtil.appendLine(rowString, file);
trace(rowString);
}
}
/**
* @param s any string
* @param separator the character used to separate cells
* @return s with separators replaced by spaces
*/
private String noSeparators(String s, String separator)
{
String res = "";
if (s != null)
{
StringTokenizer st = new StringTokenizer(s,separator);
while (st.hasMoreTokens())
{
res = res + st.nextToken();
if (st.hasMoreTokens()) res = res + " ";
}
}
else trace("null field when saving view");
return res;
}
/**
* @return a Vector with one element for each row of the view,
* in correct sort order.
* The element for each row is a Vector
* with a String for the contents of each cell
*/
public Vector<Vector<String>> sortedResults()
{
Vector<Vector<String>> sRes = new Vector<Vector<String>>();
int index = 0;
boolean moreRows = true;
while (moreRows)
{
Object row = view.tableViewer().getElementAt(index);
index++;
if (row != null)
{
Vector<String> rowVector = new Vector<String>();
for (int col = 0; col < view.columnHeaders().size(); col++)
rowVector.add(view.labelProvider().getColumnText(row, col));
sRes.add(rowVector);
}
else moreRows = false;
}
return sRes;
}
private void trace(String s) {if (tracing) System.out.println(s);}
}