Subversion Repositories wimsdev

Rev

Rev 3662 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.     Sketch Elements: Chemistry molecular diagram drawing tool.
  3.    
  4.     (c) 2008 Dr. Alex M. Clark
  5.    
  6.     Released as GNUware, under the Gnu Public License (GPL)
  7.    
  8.     See www.gnu.org for details.
  9. */
  10.  
  11. package WIMSchem.ds;
  12.  
  13. import WIMSchem.*;
  14.  
  15. import java.io.*;
  16. import java.util.*;
  17.  
  18. /*
  19.     DataSheet is a container class for storing a row/column format collection of molecular data. This implementation stores the
  20.     entirety of the collection in memory, and is not intended to be used for large datasets. Its file format is expected to be
  21.     an XML format, or imported/exported from various others, such as SD files.
  22. */
  23.  
  24. public class DataSheet
  25. {
  26.     public static final int COLTYPE_MOLECULE=1;
  27.     public static final int COLTYPE_STRING=2;
  28.     public static final int COLTYPE_INTEGER=3;
  29.     public static final int COLTYPE_REAL=4;
  30.     public static final int COLTYPE_BOOLEAN=5;
  31.    
  32.     private String title="",descr="";
  33.    
  34.     class Column
  35.     {
  36.         String Name;
  37.         int Type;
  38.         String Descr;
  39.     }
  40.     private ArrayList<Column> cols=new ArrayList<Column>();
  41.     private ArrayList<Object[]> rows=new ArrayList<Object[]>();
  42.  
  43.     private boolean isDirty=false;
  44.  
  45.     public DataSheet()
  46.     {
  47.     }
  48.    
  49.     public int numCols() {return cols.size();}
  50.     public int numRows() {return rows.size();}
  51.    
  52.     public static String typeName(int Type)
  53.     {
  54.         return Type==DataSheet.COLTYPE_MOLECULE ? "molecule" :
  55.                Type==DataSheet.COLTYPE_STRING ? "string" :
  56.                Type==DataSheet.COLTYPE_REAL ? "real" :
  57.                Type==DataSheet.COLTYPE_INTEGER ? "integer" :
  58.                Type==DataSheet.COLTYPE_BOOLEAN ? "boolean" : "?";
  59.     }
  60.    
  61.     public boolean isDirty() {return isDirty;}
  62.     public void setDirty() {isDirty=true;}
  63.     public void clearDirty() {isDirty=false;}
  64.    
  65.     // summary info, for the database overall
  66.     public String getTitle() {return title;}
  67.     public String getDescription() {return descr;}
  68.     public void setTitle(String title) {this.title=title.trim();} // (whitespace removed)
  69.     public void setDescription(String descr) {this.descr=descr;} // (whitespace allowed)
  70.    
  71.     // reading column info
  72.     public String colName(int N) {return cols.get(N).Name;}
  73.     public int colType(int N) {return cols.get(N).Type;}
  74.     public String colDescr(int N) {return cols.get(N).Descr;}
  75.    
  76.     // returns whether a cell is null; should always be checked for primitive types
  77.     public boolean isNull(int RN,int CN) {return (rows.get(RN))[CN]==null;}
  78.  
  79.     // fetching row data; note that the correct type must be use, else exception
  80.     public Molecule getMolecule(int RN,int CN) {return (Molecule)(rows.get(RN))[CN];}
  81.     public String getString(int RN,int CN) {return (String)(rows.get(RN))[CN];}
  82.     public int getInteger(int RN,int CN) {return ((Integer)(rows.get(RN))[CN]).intValue();}
  83.     public double getReal(int RN,int CN) {return ((Double)(rows.get(RN))[CN]).doubleValue();}
  84.     public boolean getBoolean(int RN,int CN) {return ((Boolean)(rows.get(RN))[CN]).booleanValue();}
  85.  
  86.     // gets the untyped object for a cell; use with care
  87.     public Object getObject(int RN,int CN) {return (rows.get(RN))[CN];}
  88.  
  89.     // sets a cell to null, which is valid for all types
  90.     public void setToNull(int RN,int CN) {(rows.get(RN))[CN]=null;}
  91.  
  92.     // setting row data; fails silently if the type is wrong
  93.     public void setMolecule(int RN,int CN,Molecule V) {if (colType(CN)==COLTYPE_MOLECULE) (rows.get(RN))[CN]=V==null ? V : V.clone();}
  94.     public void setString(int RN,int CN,String V) {if (colType(CN)==COLTYPE_STRING) (rows.get(RN))[CN]=V;}
  95.     public void setInteger(int RN,int CN,int V) {if (colType(CN)==COLTYPE_INTEGER) (rows.get(RN))[CN]=new Integer(V);}
  96.     public void setReal(int RN,int CN,double V) {if (colType(CN)==COLTYPE_REAL) (rows.get(RN))[CN]=new Double(V);}
  97.     public void setBoolean(int RN,int CN,boolean V) {if (colType(CN)==COLTYPE_BOOLEAN) (rows.get(RN))[CN]=new Boolean(V);}
  98.  
  99.     // sets the object for a cell, without any type checking; use with care
  100.     public void setObject(int RN,int CN,Object V) {(rows.get(RN))[CN]=V;}
  101.  
  102.     // each return true if the current data is equal to that being compared to
  103.     public boolean isEqualMolecule(int RN,int CN,Molecule V)
  104.     {
  105.         Molecule v=(Molecule)(rows.get(RN))[CN];
  106.         if (v==null && V==null) return true;
  107.         if (v==null || V==null) return false;
  108.         return v.compareTo(V)==0;
  109.     }
  110.     public boolean isEqualString(int RN,int CN,String V)
  111.     {
  112.         String v=(String)(rows.get(RN))[CN];
  113.         if (v==null && V==null) return true;
  114.         if (v==null || V==null) return false;
  115.         return v.equals(V);
  116.     }
  117.     public boolean isEqualInteger(int RN,int CN,int V)
  118.     {
  119.         Integer v=(Integer)(rows.get(RN))[CN];
  120.         if (v==null) return false;
  121.         return v.intValue()==V;
  122.     }
  123.     public boolean isEqualReal(int RN,int CN,double V)
  124.     {
  125.         Double v=(Double)(rows.get(RN))[CN];
  126.         if (v==null) return false;
  127.         return v.doubleValue()==V;
  128.     }
  129.     public boolean isEqualBoolean(int RN,int CN,boolean V)
  130.     {
  131.         Boolean v=(Boolean)(rows.get(RN))[CN];
  132.         if (v==null) return false;
  133.         return v.booleanValue()==V;
  134.     }
  135.    
  136.     // appends a new column to the end of the list, and updates the underlying data accordingly
  137.     public int appendColumn(String Name,int Type,String Descr)
  138.     {
  139.         Column c=new Column();
  140.         c.Name=Name;
  141.         c.Type=Type;
  142.         c.Descr=Descr;
  143.         cols.add(c);
  144.         for (int n=0;n<rows.size();n++)
  145.         {
  146.             Object[] d1=rows.get(n);
  147.             Object[] d2=new Object[d1.length+1];
  148.             for (int i=0;i<d1.length;i++) d2[i]=d1[i];
  149.             d2[d1.length]=null;
  150.             rows.set(n,d2);
  151.         }
  152.         return cols.size()-1;
  153.     }
  154.    
  155.     // appends a row containing all-nulls to the end of the list, and returns the new index position
  156.     public int appendRow()
  157.     {
  158.         rows.add(new Object[cols.size()]);
  159.         return rows.size()-1;
  160.     }
  161.    
  162.     public void deleteRow(int RN) {rows.remove(RN);}
  163.    
  164.     // removes a column, and adjusts all the data accordingly
  165.     public void deleteColumn(int CN)
  166.     {
  167.         cols.remove(CN);
  168.         for (int n=0;n<rows.size();n++)
  169.         {
  170.             Object[] prev=rows.get(n),cur=new Object[cols.size()-1];
  171.             for (int i=0,j=0;i<prev.length;i++) if (i!=CN) cur[j++]=prev[i];
  172.             rows.set(n,cur);
  173.         }
  174.     }
  175.    
  176.     // modifies name and/or description (null=do nothing)
  177.     public void changeColumnName(int CN,String Name,String Descr)
  178.     {
  179.         Column c=cols.get(CN);
  180.         if (Name!=null) c.Name=Name;
  181.         if (Descr!=null) c.Descr=Descr;
  182.     }
  183.    
  184.     // dynamically modifies the column type, correcting the existing data and reformulating; returns true if the conversion was
  185.     // successful (for example, can't switch between molecule & other); if Force is set, then incompatible conversions will result
  186.     // in null, otherwise the operation will fail
  187.     public boolean changeColumnType(int CN,int NewType,boolean Force)
  188.     {
  189.         if (CN<0 || CN>=numCols()) return false;
  190.         if (colType(CN)==NewType) return true;
  191.        
  192.         boolean incompatible=colType(CN)==COLTYPE_MOLECULE || NewType==COLTYPE_MOLECULE;
  193.         if (incompatible && !Force) return false;
  194.        
  195.         Column col=cols.get(CN);
  196.         int prevType=col.Type;
  197.         col.Type=NewType;
  198.        
  199.         for (int n=0,nrows=rows.size();n<nrows;n++)
  200.         {
  201.             Object[] row=rows.get(n);
  202.            
  203.             if (row[CN]==null) continue;
  204.             if (incompatible) {row[CN]=null; continue;}
  205.            
  206.             String val="";
  207.             if (prevType==COLTYPE_STRING) val=(String)row[CN];
  208.             else if (prevType==COLTYPE_INTEGER) val=String.valueOf(((Integer)row[CN]).intValue());
  209.             else if (prevType==COLTYPE_REAL) val=String.valueOf(((Double)row[CN]).intValue());
  210.             else if (prevType==COLTYPE_BOOLEAN) val=((Boolean)row[CN]).booleanValue() ? "true" : "false";
  211.            
  212.             row[CN]=null;
  213.            
  214.             try
  215.             {
  216.                 if (NewType==COLTYPE_STRING) row[CN]=val;
  217.                 else if (NewType==COLTYPE_INTEGER) row[CN]=new Integer(val);
  218.                 else if (NewType==COLTYPE_REAL) row[CN]=new Double(val);
  219.                 else if (NewType==COLTYPE_BOOLEAN) row[CN]=val.toLowerCase().compareTo("true")==0 ? Boolean.TRUE : Boolean.FALSE;
  220.             }
  221.             catch (NumberFormatException e) {} // stays null
  222.         }
  223.        
  224.         return true;
  225.     }
  226.    
  227.     // reorders the columns; each value of Order[n] defines the index into the original list which this should now be
  228.     public void reorderColumns(int[] Order)
  229.     {
  230.         boolean identity=true;
  231.         for (int n=0;n<Order.length-1;n++) if (Order[n]!=Order[n+1]+1) {identity=false; break;}
  232.         if (identity) return; // nothing to do
  233.        
  234.         ArrayList<Column> newcols=new ArrayList<Column>();
  235.         for (int n=0;n<cols.size();n++) newcols.add(cols.get(Order[n]));
  236.         cols=newcols;
  237.        
  238.         for (int n=0;n<rows.size();n++)
  239.         {
  240.             Object[] row=rows.get(n),newrow=new Object[row.length];
  241.             for (int i=0;i<row.length;i++) newrow[i]=row[Order[i]];
  242.             rows.set(n,newrow);
  243.         }
  244.     }
  245.    
  246.     // shuffles a single row upward
  247.     public void moveRowUp(int RN)
  248.     {
  249.         if (RN==0 || RN>=rows.size()) return;
  250.         Object[] o=rows.get(RN-1);
  251.         rows.set(RN-1,rows.get(RN));
  252.         rows.set(RN,o);
  253.     }
  254.    
  255.     // shuffles a single row upward
  256.     public void moveRowDown(int RN)
  257.     {
  258.         if (RN<0 || RN>=rows.size()-1) return;
  259.         Object[] o=rows.get(RN+1);
  260.         rows.set(RN+1,rows.get(RN));
  261.         rows.set(RN,o);
  262.     }
  263. }
  264.  
  265.  
  266.