Back to index

wims  3.65+svn20090927
DataWindow.java
Go to the documentation of this file.
00001 /*
00002     WIMSchem Elements: Chemistry molecular diagram drawing tool.
00003     
00004     (c) 2008 Dr. Alex M. Clark
00005     
00006     Released as GNUware, under the Gnu Public License (GPL)
00007     
00008     See www.gnu.org for details.
00009 */
00010 
00011 package WIMSchem.ds;
00012 
00013 import WIMSchem.*;
00014 
00015 import java.io.*;
00016 import java.awt.*;
00017 import java.util.*;
00018 import java.awt.image.*;
00019 import java.awt.event.*;
00020 import java.awt.datatransfer.*;
00021 import javax.swing.*;
00022 import javax.swing.event.*;
00023 import javax.swing.table.*;
00024 
00025 /*
00026     Main window for datasheet viewing & editing.
00027 */
00028 
00029 public class DataWindow extends JFrame implements ActionListener, WindowListener, KeyListener
00030 {
00031     public static final boolean ALLOW=true; // temporary: disable DataSheet use while development is in-progress
00032 
00033     String filename=null;
00034     JSplitPane splitter=null;
00035     DataSheet ds=null;
00036     DataSheetCache cache=null;
00037     DataTableModel model=null;
00038     JTable sheet=null;
00039     MainPanel editor=null;
00040     int molEdRow=-1,molEdCol=-1;
00041     
00042     ImageIcon mainIcon=null,mainLogo=null;
00043 
00044     int unitRowHeight,curRowMag;
00045     
00046     public DataWindow(String LoadFN) 
00047     {
00048        super("WIMSchem DataSheet");
00049 
00050        JFrame.setDefaultLookAndFeelDecorated(false); 
00051        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
00052 
00053        mainIcon=new ImageIcon(getClass().getResource("/images/MainIcon.png"));
00054        mainLogo=new ImageIcon(getClass().getResource("/images/MainLogo.png"));
00055 
00056        setIconImage(mainIcon.getImage());
00057 
00058        filename=LoadFN;
00059        if (filename==null) 
00060        {
00061            ds=new DataSheet();
00062            cache=new DataSheetCache();
00063            ds.AppendColumn("Molecule",DataSheet.COLTYPE_MOLECULE,"Molecular structure");
00064        } 
00065        else LoadDataSheet(filename);
00066 
00067        setLayout(new BorderLayout());
00068 
00069        JMenuBar menubar=CreateMenuBar();
00070 
00071        model=new DataTableModel(ds,cache);
00072        sheet=new JTable(model);
00073        sheet.setPreferredScrollableViewportSize(new Dimension(720,530));
00074        sheet.setDefaultRenderer(Molecule.class,model.NewMoleculeRenderer());
00075        sheet.setDefaultEditor(Molecule.class,model.NewMoleculeEditor(this));
00076        sheet.setRowSelectionAllowed(true);
00077        sheet.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
00078        sheet.addKeyListener(this);
00079               
00080        unitRowHeight=sheet.getRowHeight();
00081        UpdateRowHeight(2);
00082        
00083        editor=null;
00084 
00085        splitter=new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,new JScrollPane(sheet),editor);
00086        splitter.setOneTouchExpandable(true);
00087 
00088        add(menubar,BorderLayout.NORTH);
00089        add(splitter,BorderLayout.CENTER);
00090        
00091        pack();
00092        
00093        addWindowListener(this);
00094     }
00095 
00096     // ------------------ utility functions --------------------
00097 
00098     // loads a new datasheet and replaces the old one, without question
00099     private void LoadDataSheet(String FN)
00100     {
00101        DataSheet newDS=null;
00102        FileInputStream istr=null;
00103        try
00104        {
00105            istr=new FileInputStream(FN);
00106            if (DataSheetStream.ExamineIsXMLDS(istr))
00107            {
00108               newDS=DataSheetStream.ReadXML(istr);
00109               SetFilename(FN);
00110            }
00111            else if (DataSheetStream.ExamineIsMDLSDF(istr))
00112            {
00113               newDS=DataSheetStream.ReadSDF(istr);
00114               SetFilename(null);
00115            }
00116            else
00117            {
00118               String msg="["+FN+"]\n"+
00119                         "The file does not appear to be of the XML\n"+
00120                         "WIMSchem DataSheet format, an MDL SD file.";
00121               JOptionPane.showMessageDialog(null,msg,"Open Failed",JOptionPane.ERROR_MESSAGE);
00122            }
00123            cache=new DataSheetCache();
00124        }
00125        catch (IOException e) 
00126        {
00127            e.printStackTrace();
00128            JOptionPane.showMessageDialog(null,e.toString(),"Open Failed",JOptionPane.ERROR_MESSAGE);
00129        }
00130        finally 
00131        {
00132            try {if (istr!=null) istr.close();} catch (IOException e) {}
00133        }
00134 
00135        if (newDS==null) 
00136        {
00137            ds=new DataSheet(); // blank
00138            return;
00139        }
00140 
00141        ds=newDS;
00142        
00143        if (model!=null)
00144        {
00145            model.SetDataSheet(ds,cache);
00146            model.fireTableStructureChanged();
00147        }
00148     }
00149     
00150     // assembles the menu items
00151     private JMenuBar CreateMenuBar()
00152     {
00153        JMenuBar menubar=new JMenuBar();
00154        
00155        JMenu menufile=new JMenu("File");
00156        menufile.setMnemonic(KeyEvent.VK_F);
00157        menufile.add(MenuItem("New",KeyEvent.VK_N,null,KeyStroke.getKeyStroke('N',InputEvent.CTRL_MASK)));
00158        menufile.add(MenuItem("Open",KeyEvent.VK_O,null,KeyStroke.getKeyStroke('O',InputEvent.CTRL_MASK)));
00159        menufile.add(MenuItem("Save",KeyEvent.VK_S,null,KeyStroke.getKeyStroke('S',InputEvent.CTRL_MASK)));
00160        menufile.add(MenuItem("Save As",KeyEvent.VK_A));
00161        JMenu menuexport=new JMenu("Export");
00162        menuexport.setMnemonic(KeyEvent.VK_X);
00163        menuexport.add(MenuItem("as MDL SDF",KeyEvent.VK_S,null,KeyStroke.getKeyStroke('S',InputEvent.CTRL_MASK+InputEvent.SHIFT_MASK)));
00164        menufile.add(menuexport);
00165        menufile.addSeparator();
00166        menufile.add(MenuItem("Quit",KeyEvent.VK_Q,null,KeyStroke.getKeyStroke('Q',InputEvent.CTRL_MASK)));
00167 
00168        JMenu menumol=new JMenu("Molecule");
00169        menumol.setMnemonic(KeyEvent.VK_M);
00170        menumol.add(MenuItem("Edit Molecule",KeyEvent.VK_E,null,KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,0)));
00171        menumol.add(MenuItem("Keep Edit",KeyEvent.VK_K,null,KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,InputEvent.CTRL_MASK)));
00172        menumol.add(MenuItem("Abandon Edit",KeyEvent.VK_A));
00173 
00174        JMenu menuedit=new JMenu("Edit");
00175        menuedit.setMnemonic(KeyEvent.VK_E);
00176        menuedit.add(MenuItem("Undo",KeyEvent.VK_U,null,KeyStroke.getKeyStroke('Z',InputEvent.CTRL_MASK)));
00177        menuedit.add(MenuItem("Redo",KeyEvent.VK_R,null,KeyStroke.getKeyStroke('Z',InputEvent.CTRL_MASK+InputEvent.SHIFT_MASK)));
00178        menuedit.addSeparator();
00179        menuedit.add(MenuItem("Add Row",KeyEvent.VK_A,null,KeyStroke.getKeyStroke(KeyEvent.VK_INSERT,0)));
00180        menuedit.add(MenuItem("Delete Rows",KeyEvent.VK_D));
00181        menuedit.addSeparator();
00182        menuedit.add(MenuItem("Copy Rows",KeyEvent.VK_C,null,KeyStroke.getKeyStroke('C',InputEvent.CTRL_MASK+InputEvent.SHIFT_MASK)));
00183        menuedit.add(MenuItem("Cut Rows",KeyEvent.VK_T,null,KeyStroke.getKeyStroke('X',InputEvent.CTRL_MASK+InputEvent.SHIFT_MASK)));
00184        menuedit.add(MenuItem("Paste Rows",KeyEvent.VK_P,null,KeyStroke.getKeyStroke('V',InputEvent.CTRL_MASK+InputEvent.SHIFT_MASK)));
00185        menuedit.addSeparator();
00186        menuedit.add(MenuItem("Edit Columns",KeyEvent.VK_C));
00187        
00188        JMenu menuview=new JMenu("View");
00189        menuview.setMnemonic(KeyEvent.VK_V);
00190        menuview.add(MenuItem("Single Line",KeyEvent.VK_L,null,KeyStroke.getKeyStroke('1',InputEvent.CTRL_MASK)));
00191        menuview.add(MenuItem("Small Height",KeyEvent.VK_S,null,KeyStroke.getKeyStroke('2',InputEvent.CTRL_MASK)));
00192        menuview.add(MenuItem("Medium Height",KeyEvent.VK_M,null,KeyStroke.getKeyStroke('3',InputEvent.CTRL_MASK)));
00193        menuview.add(MenuItem("Large Height",KeyEvent.VK_L,null,KeyStroke.getKeyStroke('4',InputEvent.CTRL_MASK)));
00194 
00195        JMenu menuhelp=new JMenu("Help");
00196        menuhelp.setMnemonic(KeyEvent.VK_H);
00197        menuhelp.add(MenuItem("About",KeyEvent.VK_A));
00198 
00199        menubar.add(menufile);
00200        menubar.add(menumol);
00201        menubar.add(menuedit);
00202        menubar.add(menuview);
00203        menubar.add(Box.createHorizontalGlue());
00204        menubar.add(menuhelp);
00205        
00206        return menubar;
00207     }
00208 
00209     private JMenuItem MenuItem(String txt,int key) {return MenuItem(txt,key,null,null);}
00210     private JMenuItem MenuItem(String txt,int key,Icon icon) {return MenuItem(txt,key,icon,null);}
00211     private JMenuItem MenuItem(String txt,int key,Icon icon,KeyStroke accel)
00212     {
00213        JMenuItem mi=new JMenuItem(txt,key);
00214        mi.addActionListener(this);
00215        if (icon!=null) mi.setIcon(icon);
00216        if (accel!=null) mi.setAccelerator(accel);
00217        return mi;
00218     }
00219     private JRadioButtonMenuItem RadioMenuItem(String txt,int key,boolean sel,ButtonGroup bg)
00220     {
00221        JRadioButtonMenuItem mi=new JRadioButtonMenuItem(txt,sel);
00222        mi.addActionListener(this);
00223        mi.setMnemonic(key);
00224        bg.add(mi);
00225        return mi;
00226     }
00227 
00228     private void UpdateRowHeight(int Mag)
00229     {
00230        curRowMag=Mag;
00231        sheet.setRowHeight(unitRowHeight*(curRowMag==2 ? 3 : curRowMag==3 ? 6 : curRowMag==4 ? 12 : 1));
00232     }
00233     
00234     private void SetFilename(String FN)
00235     {
00236        filename=FN;
00237        String title="WIMSchem DataSheet";
00238        if (filename!=null) title+=" - "+new File(filename).getName();
00239        setTitle(title);
00240     }
00241     
00242     private void SaveCurrent()
00243     {
00244        if (filename==null) return;
00245        try
00246        {
00247            FileOutputStream ostr=new FileOutputStream(filename);
00248            DataSheetStream.WriteXML(ostr,ds);
00249            ostr.close();
00250            ds.ClearDirty();
00251        }
00252        catch (IOException e)
00253        {
00254            Utils.errmsg("Save Failed",e.toString());
00255        }
00256     }
00257 
00258     // returns true if two datasheets have the same columns
00259     boolean SameColumns(DataSheet DS1,DataSheet DS2)
00260     {
00261        if (DS1.NumCols()!=DS2.NumCols()) return false;
00262        for (int n=0;n<DS1.NumCols();n++)
00263        {
00264            if (DS1.ColName(n).compareTo(DS2.ColName(n))!=0) return false;
00265            if (DS1.ColType(n)!=DS2.ColType(n)) return false;
00266            if (DS1.ColDescr(n).compareTo(DS2.ColDescr(n))!=0) return false;
00267        }
00268        return true;
00269     }
00270 
00271     // ------------------ user responses --------------------
00272 
00273     private void FileQuit()
00274     {
00275        if (ds.IsDirty())
00276        {
00277            String opt[]={"Yes","No"};
00278            if (JOptionPane.showOptionDialog(null,"Current datasheet has been modified. Exit without saving?","Quit",
00279                   JOptionPane.YES_NO_OPTION,JOptionPane.YES_NO_OPTION,null,opt,opt[0])!=JOptionPane.YES_OPTION) return;
00280        }
00281        dispose();
00282     }
00283     
00284     private void FileNew()
00285     {
00286        //if (ds.NumRows()==0 && !ds.IsDirty() && filename==null) return; // no point
00287        new DataWindow(null).setVisible(true);
00288     }
00289     
00290     private void FileOpen()
00291     {
00292        JFileChooser chooser=new JFileChooser(System.getenv().get("PWD"));
00293        chooser.setDragEnabled(false);
00294        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
00295        chooser.setFileFilter(new FileExtFilter("DataSheet Formats",".xml;.sdf"));
00296        // !! chooser.setAccessory(new FileMolPreview(chooser));
00297        if (chooser.showOpenDialog(this)!=JFileChooser.APPROVE_OPTION) return;
00298        String newfn=chooser.getSelectedFile().getPath();
00299        
00300        if (ds.NumRows()==0 && !ds.IsDirty())
00301            LoadDataSheet(newfn); // replace blank with new thing
00302        else 
00303            new DataWindow(newfn).setVisible(true); // pop up a new window
00304     }
00305     
00306     private void FileSave()
00307     {
00308        if (filename==null) {FileSaveAs(); return;}
00309        SaveCurrent();
00310     }
00311     
00312     private void FileSaveAs()
00313     {
00314        JFileChooser chooser=new JFileChooser(System.getenv().get("PWD"));
00315        chooser.setDragEnabled(false);
00316        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
00317        chooser.setFileFilter(new FileExtFilter("WIMSchem DataSheets",".xml"));
00318        if (chooser.showSaveDialog(this)!=JFileChooser.APPROVE_OPTION) return;
00319     
00320        String fn=chooser.getSelectedFile().getPath();
00321        if (chooser.getSelectedFile().getName().indexOf('.')<0) fn=fn+".xml";
00322     
00323        File newf=new File(fn);
00324        if (newf.exists())
00325        {
00326            String opt[]={"Yes","No"};
00327            if (JOptionPane.showOptionDialog(null,"Overwrite existing file ["+newf.getName()+"]?","Save As",
00328                   JOptionPane.YES_NO_OPTION,JOptionPane.YES_NO_OPTION,null,opt,opt[0])!=JOptionPane.YES_OPTION) return;
00329        }      
00330     
00331        SetFilename(fn);
00332        SaveCurrent();
00333     }
00334     
00335     private void FileExportSDF()
00336     {
00337        JFileChooser chooser=new JFileChooser(System.getenv().get("PWD"));
00338        chooser.setDragEnabled(false);
00339        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
00340        chooser.setFileFilter(new FileExtFilter("MDL SD files",".sdf"));
00341        if (chooser.showSaveDialog(this)!=JFileChooser.APPROVE_OPTION) return;
00342     
00343        String fn=chooser.getSelectedFile().getPath();
00344        if (chooser.getSelectedFile().getName().indexOf('.')<0) fn=fn+".sdf";
00345     
00346        File newf=new File(fn);
00347        if (newf.exists())
00348        {
00349            String opt[]={"Yes","No"};
00350            if (JOptionPane.showOptionDialog(null,"Overwrite existing file ["+newf.getName()+"]?","Save As",
00351                   JOptionPane.YES_NO_OPTION,JOptionPane.YES_NO_OPTION,null,opt,opt[0])!=JOptionPane.YES_OPTION) return;
00352        }
00353        
00354        // !! perhaps a warning if there are multiple molecule fields?
00355        
00356        try
00357        {
00358            FileOutputStream ostr=new FileOutputStream(fn);
00359            DataSheetStream.WriteSDF(ostr,ds);
00360            ostr.close();
00361        }
00362        catch (IOException e)
00363        {
00364            Utils.errmsg("Export Failed",e.toString());
00365        }
00366     }
00367 
00368     private void MoleculeEditMol()
00369     {
00370        if (editor!=null) return;
00371        int row=sheet.getSelectedRow(),col=sheet.getSelectedColumn();
00372        
00373        if (row<0 || col<0 || col>=ds.NumCols()) return;
00374        
00375        if (ds.ColType(col)!=DataSheet.COLTYPE_MOLECULE) return;
00376 
00377        // make sure this is the only way to trigger the molecule editor (otherwise is really annoying)
00378        model.SetTemporaryEdit(col);
00379        sheet.editCellAt(row,col);
00380        model.ClearTemporaryEdit();
00381     }
00382     
00383     private void MoleculeKeepEdit()
00384     {
00385        if (editor==null) return;
00386        Molecule mol=editor.MolData();
00387        if (mol.NumAtoms()==0) mol=null;
00388        cache.CacheUndo(ds);
00389        ds.SetMolecule(molEdRow,molEdCol,mol);
00390        ds.SetDirty();
00391        model.fireTableCellUpdated(molEdRow,molEdCol); 
00392        editor=null;
00393        splitter.setRightComponent(editor);
00394        sheet.requestFocusInWindow();
00395     }
00396     
00397     private void MoleculeAbandonEdit()
00398     {
00399        if (editor==null) return;
00400        if (sheet.getCellEditor()!=null) sheet.getCellEditor().stopCellEditing();
00401        editor=null;
00402        splitter.setRightComponent(editor);
00403        sheet.requestFocusInWindow();
00404     }
00405 
00406     private void EditUndo()
00407     {
00408        if (!cache.CanUndo()) return;
00409 
00410        DataSheet newds=cache.PerformUndo(ds);
00411        boolean colmod=!SameColumns(ds,newds);
00412        ds=newds;
00413 
00414        ds.SetDirty();
00415        model.SetDataSheet(ds,cache);
00416        if (colmod) model.fireTableStructureChanged(); else model.fireTableDataChanged();
00417     }
00418     
00419     private void EditRedo()
00420     {
00421        if (!cache.CanRedo()) return;
00422 
00423        DataSheet newds=cache.PerformRedo(ds);
00424        boolean colmod=!SameColumns(ds,newds);
00425        ds=newds;
00426        
00427        ds.SetDirty();
00428        model.SetDataSheet(ds,cache);
00429        if (colmod) model.fireTableStructureChanged(); else model.fireTableDataChanged();
00430     }
00431 
00432     private void EditColumns()
00433     {
00434        DialogEditColumns edcols=new DialogEditColumns(this,ds);
00435        if (!edcols.Execute()) return;
00436        
00437        ModifyColumns(edcols.ResultOldPos(),edcols.ResultNewPos(),edcols.ResultName(),edcols.ResultType(),edcols.ResultDescr());
00438        ds.SetDirty();
00439        
00440        model.fireTableStructureChanged();
00441     }
00442     
00443     private void AddRow()
00444     {
00445        cache.CacheUndo(ds);
00446        ds.AppendRow();
00447        model.fireTableChanged(new TableModelEvent(model));
00448        sheet.setRowSelectionInterval(ds.NumRows()-1,ds.NumRows()-1);
00449     }
00450     
00451     private void DeleteRows()
00452     {
00453        if (sheet.getSelectedRowCount()==0) return;
00454        cache.CacheUndo(ds);
00455        int[] todel=sheet.getSelectedRows();
00456        for (int i=0;i<todel.length;i++)
00457        {
00458            ds.DeleteRow(i);
00459            for (int j=i+1;j<todel.length;j++) if (todel[j]>todel[i]) todel[j]--;
00460        }
00461        model.fireTableChanged(new TableModelEvent(model));
00462     }
00463 
00464     private void CopyRows()
00465     {
00466        if (sheet.getSelectedRowCount()==0) return;
00467        int[] rn=sheet.getSelectedRows();
00468     
00469        DataSheet copy=new DataSheet();
00470        for (int n=0;n<ds.NumCols();n++) 
00471        {
00472            copy.AppendColumn(ds.ColName(n),ds.ColType(n),ds.ColDescr(n));
00473        }
00474        for (int i=0;i<rn.length;i++)
00475        {
00476            copy.AppendRow();
00477            for (int j=0;j<ds.NumCols();j++) copy.SetObject(i,j,ds.GetObject(rn[i],j));
00478        }
00479        
00480        StringWriter sw=new StringWriter();
00481        try
00482        {
00483            DataSheetStream.WriteXML(new BufferedWriter(sw),copy);
00484            //System.out.println(sw.toString());
00485             Clipboard clip=Toolkit.getDefaultToolkit().getSystemClipboard();
00486            clip.setContents(new StringSelection(sw.toString()),null);
00487        }
00488        catch (IOException e)
00489        {
00490            e.printStackTrace();
00491            JOptionPane.showMessageDialog(null,e.toString(),"Copy Failed",JOptionPane.ERROR_MESSAGE);
00492        }
00493     }
00494     
00495     private void CutRows()
00496     {
00497        CopyRows();
00498        DeleteRows();
00499     }
00500     
00501     private void PasteRows()
00502     {
00503        String cliptext="";
00504     
00505        try
00506        {
00507            Clipboard clip=Toolkit.getDefaultToolkit().getSystemClipboard();
00508            Transferable contents=clip.getContents(null);
00509            if (contents!=null && contents.isDataFlavorSupported(DataFlavor.stringFlavor))
00510               cliptext=(String)contents.getTransferData(DataFlavor.stringFlavor);
00511        }
00512        catch (UnsupportedFlavorException e) 
00513        {
00514            JOptionPane.showMessageDialog(null,e.toString(),"Clipboard Read Failed",JOptionPane.ERROR_MESSAGE);
00515        }
00516        catch (IOException e) 
00517        {
00518            JOptionPane.showMessageDialog(null,e.toString(),"Paste Failed",JOptionPane.ERROR_MESSAGE);
00519        }
00520 
00521        DataSheet paste=null;
00522        try
00523        {
00524            if (DataSheetStream.ExamineIsXMLDS(new BufferedReader(new StringReader(cliptext))))
00525               paste=DataSheetStream.ReadXML(new BufferedReader(new StringReader(cliptext)));
00526            else if (DataSheetStream.ExamineIsMDLSDF(new BufferedReader(new StringReader(cliptext))))
00527               paste=DataSheetStream.ReadSDF(new BufferedReader(new StringReader(cliptext)));
00528        }
00529        catch (IOException e) {e.printStackTrace(); return;}
00530 
00531        if (paste==null) 
00532        {
00533            JOptionPane.showMessageDialog(null,
00534               "Unknown format: must be DataSheet XML or MDL SDF","Paste Failed",JOptionPane.ERROR_MESSAGE);
00535            return;
00536        }
00537        
00538        cache.CacheUndo(ds);
00539        
00540        //System.out.println("R="+paste.NumRows()+",C="+paste.NumCols());
00541        
00542        // handle columns first: find mapping index for each, based on name
00543        int[] newcolpos=new int[paste.NumCols()];
00544        for (int i=0;i<paste.NumCols();i++)
00545        {
00546            newcolpos[i]=-1;
00547            for (int j=0;j<ds.NumCols();j++) if (ds.ColName(j).compareTo(paste.ColName(i))==0) {newcolpos[i]=j; break;}
00548            if (newcolpos[i]<0) newcolpos[i]=ds.AppendColumn(paste.ColName(i),paste.ColType(i),paste.ColDescr(i));
00549        }
00550        
00551        // now paste the new rows
00552        for (int i=0;i<paste.NumRows();i++)
00553        {
00554            int rn=ds.AppendRow();
00555            for (int j=0;j<paste.NumCols();j++)
00556            {
00557               int cn=newcolpos[j];
00558               int ptype=paste.ColType(j),dtype=ds.ColType(j);
00559               String strval="";
00560               
00561               if (ptype==DataSheet.COLTYPE_MOLECULE && dtype==DataSheet.COLTYPE_MOLECULE)
00562               {
00563                   ds.SetMolecule(rn,cn,paste.GetMolecule(i,j));
00564               }
00565               else if (ptype==DataSheet.COLTYPE_MOLECULE || dtype==DataSheet.COLTYPE_MOLECULE) {} // not possible
00566               else 
00567               {
00568                   String val="";
00569                   if (ptype==DataSheet.COLTYPE_STRING) val=paste.GetString(i,j);
00570                   else if (ptype==DataSheet.COLTYPE_INTEGER) val=String.valueOf(paste.GetInteger(i,j));
00571                   else if (ptype==DataSheet.COLTYPE_REAL) val=String.valueOf(paste.GetReal(i,j));
00572                   else if (ptype==DataSheet.COLTYPE_BOOLEAN) val=paste.GetBoolean(i,j) ? "true" : "false";
00573                   
00574                   try
00575                   {
00576                      if (dtype==DataSheet.COLTYPE_STRING) ds.SetString(rn,cn,val);
00577                      else if (dtype==DataSheet.COLTYPE_INTEGER) ds.SetInteger(rn,cn,new Integer(val).intValue());
00578                      else if (dtype==DataSheet.COLTYPE_REAL) ds.SetReal(rn,cn,new Double(val).doubleValue());
00579                      else if (dtype==DataSheet.COLTYPE_BOOLEAN) 
00580                          ds.SetBoolean(rn,cn,val.toLowerCase().compareTo("true")==0 ? true : false);
00581                   }
00582                   catch (NumberFormatException e) {} // stays null
00583               }
00584            }
00585        }
00586 
00587        model.fireTableChanged(new TableModelEvent(model));
00588     }
00589 
00590     private void HelpAbout()
00591     {
00592        String msg="WIMSchem v"+MainPanel.VERSION+"\n"+
00593                  "Molecule drawing tool\n"+
00594                  " 2005-2008 Dr. Alex M. Clark\n"+
00595                  "Released under the Gnu Public\n"+
00596                  "License (GPL), see www.gnu.org\n"+
00597                  "Home page and documentation:\n"+
00598                  "http://sketchel.sf.net\n";
00599        JOptionPane.showMessageDialog(null,msg,"About WIMSchem",JOptionPane.INFORMATION_MESSAGE,mainLogo);
00600     }
00601  
00602     private void EditMolecule(int RN,int CN)
00603     {
00604        if (editor!=null)
00605        {
00606            /*editor=null;
00607            splitter.setRightComponent(editor);*/
00608            // !! offer to save, or something?
00609        }
00610        
00611        editor=new MainPanel(null,false,true,null,null,null,null,null,null,true,true);
00612        molEdRow=RN;
00613        molEdCol=CN;
00614        Molecule mol=ds.GetMolecule(RN,CN);
00615        if (mol!=null) editor.SetMolecule(mol.Clone());
00616        
00617        splitter.setRightComponent(editor);
00618        int pos=splitter.getWidth()-560;
00619        splitter.setDividerLocation(pos<0 ? 50 : pos);
00620        editor.requestFocusInWindow();
00621     }
00622 
00623     private void ModifyColumns(int[] OldPos,int[] NewPos,String[] Name,int[] Type,String[] Descr)
00624     {
00625        int sz=OldPos.length;
00626        
00627        // delete those which need to be chopped out
00628        for (int n=0;n<sz;n++) if (NewPos[n]<0)
00629        {
00630            ds.DeleteColumn(OldPos[n]);
00631            for (int i=0;i<sz;i++) if (OldPos[i]>OldPos[n]) OldPos[i]--;
00632            for (int i=n;i<sz-1;i++) 
00633            {
00634               OldPos[i]=OldPos[i+1];
00635               NewPos[i]=NewPos[i+1];
00636               Name[i]=Name[i+1];
00637               Type[i]=Type[i+1];
00638               Descr[i]=Descr[i+1];
00639            }
00640            n--;
00641            sz--;
00642        }
00643        
00644        // add the new ones
00645        for (int n=0;n<sz;n++) if (OldPos[n]<0)
00646        {
00647            OldPos[n]=ds.AppendColumn(Name[n],Type[n],Descr[n]);
00648        }
00649        
00650        // modify any existing content
00651        for (int n=0;n<sz;n++)
00652        {
00653            ds.ChangeColumnName(OldPos[n],Name[n],Descr[n]);
00654            ds.ChangeColumnType(OldPos[n],Type[n],true);
00655        }
00656        
00657        // now redefine the column order
00658        int[] reord=new int[sz];
00659        for (int n=0;n<sz;n++) reord[NewPos[n]]=OldPos[n];
00660        cache.CacheUndo(ds);
00661        ds.ReorderColumns(reord);
00662     }
00663 
00664     // ------------------ event functions --------------------
00665     
00666     public void actionPerformed(ActionEvent e)
00667     {
00668        String cmd=e.getActionCommand();
00669 
00670        //System.out.println("CMD:["+cmd+"]");
00671 
00672        if (e.getSource()==sheet)
00673        {
00674            String[] rc=cmd.split(",");
00675            EditMolecule(Integer.parseInt(rc[0]),Integer.parseInt(rc[1]));
00676        }
00677        else if (cmd=="Quit") FileQuit();
00678        else if (cmd=="New") FileNew();
00679        else if (cmd=="Open") FileOpen();
00680        else if (cmd=="Save") FileSave();
00681        else if (cmd=="Save As") FileSaveAs();
00682        else if (cmd=="as MDL SDF") FileExportSDF();
00683        else if (cmd=="Edit Molecule") MoleculeEditMol();
00684        else if (cmd=="Keep Edit") MoleculeKeepEdit();
00685        else if (cmd=="Abandon Edit") MoleculeAbandonEdit();
00686        else if (cmd=="Undo") EditUndo();
00687        else if (cmd=="Redo") EditRedo();
00688        else if (cmd=="Add Row") AddRow();
00689        else if (cmd=="Delete Rows") DeleteRows();
00690        else if (cmd=="Copy Rows") CopyRows();
00691        else if (cmd=="Cut Rows") CutRows();
00692        else if (cmd=="Paste Rows") PasteRows();
00693        else if (cmd=="Edit Columns") EditColumns();
00694        else if (cmd=="Single Line") UpdateRowHeight(1);
00695        else if (cmd=="Small Height") UpdateRowHeight(2);
00696        else if (cmd=="Medium Height") UpdateRowHeight(3);
00697        else if (cmd=="Large Height") UpdateRowHeight(4);
00698        else if (cmd=="About") HelpAbout();
00699     }
00700     
00701     public void windowActivated(WindowEvent e) {}
00702     public void windowClosed(WindowEvent e) {}
00703     public void windowClosing(WindowEvent e) 
00704     {
00705        FileQuit();
00706     }
00707     public void windowDeactivated(WindowEvent e) {}
00708     public void windowDeiconified(WindowEvent e) {}
00709     public void windowIconified(WindowEvent e) {}
00710     public void windowOpened(WindowEvent e) {}
00711 
00712     public void keyPressed(KeyEvent e) {}
00713     public void keyReleased(KeyEvent e) {}
00714     public void keyTyped(KeyEvent e) 
00715     {
00716        if (e.getSource()==sheet)
00717        {
00718            if (sheet.isEditing()) return;
00719        
00720            //System.out.println("key caught: ["+(int)e.getKeyChar()+"]");
00721 
00722            // decide which keys are permitted to activate editing of a cell (other than molecules, which are handled
00723            // by the menu item)
00724            boolean shouldEdit=false;
00725            if (e.getKeyChar()>=32 && e.getKeyChar()<=126) shouldEdit=true;
00726            if (e.getKeyChar()=='\b') shouldEdit=true;
00727            if (e.getModifiers()!=0) shouldEdit=false; 
00728            int row=sheet.getSelectedRow(),col=sheet.getSelectedColumn();
00729            if (row<0 || col<0) shouldEdit=false;
00730            else if (ds.ColType(col)==DataSheet.COLTYPE_MOLECULE) shouldEdit=false; // mols have their own way
00731            
00732            if (shouldEdit)
00733            {
00734               model.SetTemporaryEdit(col);
00735               sheet.editCellAt(row,col);
00736               model.ClearTemporaryEdit();
00737            }
00738        }
00739     }
00740 }