com.actelion.research.chem.io.DWARFileCreator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openchemlib Show documentation
Show all versions of openchemlib Show documentation
Open Source Chemistry Library
/*
* Copyright (c) 1997 - 2016
* Actelion Pharmaceuticals Ltd.
* Gewerbestrasse 16
* CH-4123 Allschwil, Switzerland
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package com.actelion.research.chem.io;
import com.actelion.research.chem.Canonizer;
import com.actelion.research.chem.StereoMolecule;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Properties;
import java.util.TreeMap;
import static com.actelion.research.chem.io.CompoundTableConstants.NEWLINE_STRING;
import static com.actelion.research.chem.io.CompoundTableConstants.TAB_STRING;
public class DWARFileCreator {
private BufferedWriter mWriter;
private DWARFileParser mMasterCopyParser;
private String[] mRow;
private ArrayList mColumnTitleList;
private TreeMap mColumnPropertiesMap;
/**
* Use a DWARFileCreator for writing native DataWarrior files without a CompoundTableModel.
* (if you have a populated CompoundTableModel, use the CompoundTableSaver instead).
* You may provide a freshly instantiated DWARFileParser as master copy that will provide header,
* explanation text, macros, column properties, and runtime properties for the new file.
* To use the DWARFileCreator you need to follow these steps:
* - instantiate a new DWARFileCreator for a new output file
* - optionally call setMasterCopy()
* - define individual columns with addStructureColumn(), addDescriptorColumn(), and addAlphanumericalColumn()
* - add custom column properties, if you need to with addColumnProperty()
* - call writeHeader() once to create the file and write file & table headers
* - for every row call setRowStructure() and setRowValue() for cell values and then writeCurrentRow()
* - if you didn't call setMasterCopy(), then optionally call writeTemplate() to add runtime properties
* - call writeEnd() to close the file
* @param writer make sure that it encodes as UTF-8
*/
public DWARFileCreator(BufferedWriter writer) {
mWriter = writer;
mColumnTitleList = new ArrayList();
}
/**
* If the file to be created shall resemble another DataWarrior file regarding file
* explanation, macro content, columns names, column properties, runtime properties (template),
* then one may define a master copy with this method that serves as a blue print.
* @param parser DWARFileParser initialized with MODE_BUFFER_HEAD_AND_TAIL
*/
public void setMasterCopy(DWARFileParser parser) {
mMasterCopyParser = parser;
ArrayList headAndTail = mMasterCopyParser.getHeadOrTail();
for (String title:headAndTail.get(headAndTail.size()-1).split("\\t"))
mColumnTitleList.add(title);
}
/**
* This adds a column to host canonical structure representations (idcodes).
* This call allocates the column and defines proper column properties.
* If you want DataWarrior to show structure in this column with the original
* atom coordinates, you need to also add a column for the encoded atom coordinates.
* Otherwise DataWarrior would generate 2D-coordinates for the structures atoms
* on the fly.
* @param name
* @param idColumnName null or column title of other column that hold a compound identifier
* @return new structure column index
*/
public int addStructureColumn(String name, String idColumnName) {
int structureColumn = mColumnTitleList.size();
String title = makeUnique(name);
mColumnTitleList.add(title);
addColumnProperty(structureColumn, "specialType", "idcode");
if (idColumnName != null)
addColumnProperty(structureColumn, "idColumn", idColumnName);
return structureColumn;
}
/**
* Creates a new column to hold encoded 2-dimensional atom coordinates for the structures
* stored in the associated structure column. A structure column may not have more than one
* associated 2-dimensional atom coordinate column.
* This call allocates the column and defines proper column properties.
* @param structureColumn
* @return new coordinate column index
*/
public int add2DCoordinatesColumn(int structureColumn) {
return addStructureChildColumn("idcoordinates2D", "idcoordinates2D", structureColumn);
}
/**
* Creates a new column to hold encoded 3-dimensional atom coordinates for the structures
* stored in the associated structure column. A structure column may have multiple
* associated 3-dimensional atom coordinate columns.
* This call allocates the column and defines proper column properties.
* @param name 3D-coordinate column names are used to distinguish multiple 3D-coordinate sets
* @param structureColumn
* @return new coordinate column index
*/
public int add3DCoordinatesColumn(String name, int structureColumn) {
return addStructureChildColumn("idcoordinates3D", name, structureColumn);
}
/**
* Creates a new column to hold a chemical descriptor for the structures
* stored in the associated structure column. A structure column may have multiple
* associated descriptor columns, provided that these have distinct types.
* This call allocates the column and defines proper column properties.
* @param descriptorShortName name used to identify the descriptor type, e.g. 'FragFp'
* @param structureColumn
* @return new descriptor column index
*/
public int addDescriptorColumn(String descriptorShortName, String descriptorVersion, int structureColumn) {
int column = addStructureChildColumn(descriptorShortName, descriptorShortName, structureColumn);
addColumnProperty(column, "version", descriptorVersion);
return column;
}
private int addStructureChildColumn(String specialType, String name, int structureColumn) {
int column = mColumnTitleList.size();
mColumnTitleList.add(makeUnique(name));
addColumnProperty(column, "parent", mColumnTitleList.get(structureColumn));
addColumnProperty(column, "specialType", specialType);
return column;
}
/**
* Creates a new standard column to hold any alphanumerical content.
* @param name
* @return
*/
public int addAlphanumericalColumn(String name) {
mColumnTitleList.add(makeUnique(name));
return mColumnTitleList.size()-1;
}
/**
* This method may be used to define column properties, e.g. to associate the column
* with an URL for identifier lookups, to define a data range, or other special DataWarrior
* related features.
* @param column
* @param key
* @param value
*/
public void addColumnProperty(int column, String key, String value) {
if (mColumnPropertiesMap == null)
mColumnPropertiesMap = new TreeMap();
Properties cp = mColumnPropertiesMap.get(column);
if (cp == null) {
cp = new Properties();
mColumnPropertiesMap.put(column, cp);
}
cp.setProperty(key, value);
}
/**
* This method, when called after calling setMasterCopy() or after completing
* defining columns, returns the list of defined column names in the correct order.
* Especially, when using a master copy, this method informs about the expected columns
* and their order to be used for adding the data.
* @return manually defined column titles or from master copy, if used
*/
public String[] getColumnTitles() {
return mColumnTitleList.toArray(new String[0]);
}
/**
* This method, when called after calling setMasterCopy() or after completing
* defining columns, returns the column properties of the given column.
* @return manually defined column properties or from master copy, if used
*/
public Properties getColumnProperties(String columnTitle) {
if (mMasterCopyParser != null) {
return mMasterCopyParser.getColumnProperties(columnTitle);
}
else {
for (int i=0; i");
mWriter.newLine();
mWriter.write("");
mWriter.newLine();
if (rowCount > 0) {
mWriter.write("");
mWriter.newLine();
}
mWriter.write("");
mWriter.newLine();
writeColumnPropertiesAndTitles();
}
else {
for (String line:mMasterCopyParser.getHeadOrTail()) {
if (line.trim().matches("")) {
if (rowCount < 0)
continue;
line = "";
}
if (line.trim().matches("")) {
line = "";
}
mWriter.write(line);
mWriter.newLine();
}
}
mRow = new String[mColumnTitleList.size()];
}
private void writeColumnPropertiesAndTitles() throws IOException {
if (mColumnPropertiesMap != null) {
mWriter.write("");
mWriter.newLine();
for (int column:mColumnPropertiesMap.keySet()) {
mWriter.write("");
mWriter.newLine();
Properties cp = mColumnPropertiesMap.get(column);
for (String key:cp.stringPropertyNames()) {
String value = cp.getProperty(key);
mWriter.write("");
mWriter.newLine();
}
}
mWriter.write(" ");
mWriter.newLine();
}
boolean isFirst = true;
for (int i=0; i properties) throws IOException {
if (properties != null && properties.size() != 0) {
mWriter.write(CompoundTableConstants.cPropertiesStart);
mWriter.newLine();
for (String propertyLine:properties) {
mWriter.write(propertyLine);
mWriter.newLine();
}
mWriter.write(CompoundTableConstants.cPropertiesStart);
mWriter.newLine();
}
}
public void writeEnd() throws IOException {
if (mMasterCopyParser != null) {
while (mMasterCopyParser.advanceToNext());
for (String line:mMasterCopyParser.getHeadOrTail()) {
mWriter.write(line);
mWriter.newLine();
}
}
mWriter.close();
}
/**
* Checks column name for uniqueness and modifies it if needed to be unique.
* @param name desired column name
* @return
*/
private String makeUnique(String name) {
if (name == null || name.trim().length() == 0) {
name = "Column 1";
}
else {
name = name.trim().replaceAll("[\\x00-\\x1F]", "_");
}
while (columnNameExists(name)) {
int index = name.lastIndexOf(' ');
if (index == -1)
name = name + " 2";
else {
try {
int suffix = Integer.parseInt(name.substring(index+1));
name = name.substring(0, index+1) + (suffix+1);
}
catch (NumberFormatException nfe) {
name = name + " 2";
}
}
}
return name;
}
private boolean columnNameExists(String name) {
for (String existing:mColumnTitleList)
if (name.equalsIgnoreCase(existing))
return true;
return false;
}
}