home *** CD-ROM | disk | FTP | other *** search
/ Palm Utilities / Palm_Utilities_CD-ROM_2001_2001.iso / files / utils text / ReadDocJ 1.1 / ReadDocJ.exe / Source / ReadDocJ.java < prev    next >
Encoding:
Java Source  |  2000-01-21  |  23.9 KB  |  932 lines

  1. /*
  2.  * ReadDocJ
  3.  *
  4.  * Used to read PilotDocs.
  5.  *
  6.  */
  7.  
  8. import java.io.*;
  9. import java.util.*;
  10. import java.awt.*;
  11. import java.awt.event.*;
  12.  
  13. import javax.swing.*;
  14. import javax.swing.event.*;
  15. import javax.swing.text.*;
  16.  
  17. import gnu.regexp.*;
  18.  
  19. /**
  20.  * <code>BookMarkHelperRD</code> class is used to add the necessary support for ReadDocJ
  21.  * @author Jeffrey A. Krzysztow
  22.  * @version 1.1
  23.  */
  24. class BookMarkHelperRD extends BookMark {
  25.  
  26.     BookMarkHelperRD() {
  27.         super();
  28.         ok2Save = true;
  29.     }
  30.  
  31.     BookMarkHelperRD(boolean ok2Save) {
  32.         super();
  33.         this.ok2Save = ok2Save;
  34.     }
  35.  
  36.     /**
  37.      * returns whether it is ok to save this bookmark to the external bookmark file
  38.      * @returns true if ok to save bookmark
  39.      * @since 1.1
  40.      */
  41.     public boolean isOk2Save() {
  42.         return ok2Save;
  43.     }
  44.  
  45.     /**
  46.      * sets whether it is ok to save this bookmark
  47.      * @param ok2Save whether it is ok to save this bookmark
  48.      * @since 1.1
  49.      */
  50.     public void setOk2Save(boolean ok2Save) {
  51.         this.ok2Save = ok2Save;
  52.     }
  53.  
  54.     /**
  55.      * returns the string representation "we" want
  56.      * used by JList for holding bookmarks
  57.      * @returns the name of the bookmark
  58.      * @since 1.0
  59.      */
  60.     public String toString() {
  61.         return name;
  62.     }
  63.  
  64.     private boolean ok2Save = false;
  65. }
  66.  
  67. /**
  68.  * <code>ReadDocJ</code> is the main application to read PilotDoc files
  69.  * @author Jeffrey A. Krzysztow
  70.  * @version 1.2
  71.  */
  72. public final class ReadDocJ extends JFrame {
  73.     private final static float version = (float) 1.2;
  74.  
  75.     /**
  76.      * <code>SearchDlg</code> class maintains the search (find) dialog
  77.      * @author Jeffrey A. Krzysztow
  78.      * @since 1.0
  79.      */
  80.     class SearchDlg extends JDialog implements ItemListener, KeyListener {
  81.         HorizontalButtons buttons = new HorizontalButtons();
  82.         JTextField searchFor = new JTextField(30);
  83.         JCheckBox regex = new JCheckBox("Regular expression");
  84.         JCheckBox nocase = new JCheckBox("Case insensitive");
  85.  
  86.         /**
  87.          * Constructs the search dialog
  88.          * @param frame the parent frame
  89.          * @since 1.0
  90.          */
  91.         SearchDlg(JFrame frame) {
  92.             super(frame, false);
  93.  
  94.             setTitle("Search");
  95.  
  96.             GridBagLayout gbl = new GridBagLayout();
  97.             GridBagConstraints gbc = new GridBagConstraints();
  98.             Container contentPane = getContentPane();
  99.  
  100.             contentPane.setLayout(gbl);
  101.  
  102.             addWindowListener(new WindowAdapter() {
  103.                     public void windowClosing(WindowEvent e) {
  104.                         dispose();
  105.                     }
  106.                 }
  107.             );
  108.  
  109.             setResizable(false);
  110.  
  111.             JButton button = null;
  112.  
  113.             button = new JButton("Find");
  114.             button.addActionListener(new ActionListener() {
  115.                     public void actionPerformed(ActionEvent ae) {
  116.                         find();
  117.                     }
  118.                 }
  119.             );
  120.             button.addKeyListener(this);
  121.             buttons.add(button);
  122.  
  123.             regex.addItemListener(this);
  124.             buttons.add(regex);
  125.  
  126.             nocase.addItemListener(this);
  127.             buttons.add(nocase);
  128.  
  129.             searchFor.addKeyListener(this);
  130.             gbc.gridx = GridBagConstraints.REMAINDER;
  131.             gbl.setConstraints(searchFor, gbc);
  132.             contentPane.add(searchFor);
  133.  
  134.             gbc.gridx = GridBagConstraints.REMAINDER;
  135.             gbl.setConstraints(buttons, gbc);
  136.             contentPane.add(buttons);
  137.  
  138.             pack();
  139.  
  140.             // Center dialog to parent frame
  141.             Point location = frame.getLocation();
  142.             Dimension outerSize = frame.getSize();
  143.             Dimension size = getSize();
  144.             location.x = location.x + (outerSize.width - size.width) / 2;
  145.             location.y = location.y + (outerSize.height - size.height) / 2;
  146.             setLocation(location);
  147.         }
  148.  
  149.         /**
  150.          * handles to find button to search for text
  151.          * @since 1.0
  152.          */
  153.         final void find() {
  154.             String text = searchFor.getText();
  155.             if(text != null) {
  156.                 if(regex.isSelected()) {
  157.                     try {
  158.                         RE searchRegex = new RE(text, RE.REG_MULTILINE | (nocase.isSelected() ? RE.REG_ICASE : 0));
  159.                         try {
  160.                             REMatch reMatch = searchRegex.getMatch(docText, doc.getCaretPosition() + 1);
  161.                             if(reMatch.getStartIndex() > -1) {
  162.                                 doc.setCaretPosition(reMatch.getStartIndex());
  163.                                 doc.select(reMatch.getStartIndex(), reMatch.getEndIndex() - reMatch.getStartIndex());
  164.                             }
  165.                         }
  166.                         catch(IllegalArgumentException e) {
  167.                         }
  168.                     }
  169.                     catch(REException e) {
  170.                     }
  171.                 }
  172.                 else {
  173.                     int pos = docText.indexOf(text);
  174.                     if(pos > 0) {
  175.                         doc.setCaretPosition(pos);
  176.                         doc.select(pos, pos + text.length());
  177.                     }
  178.                 }
  179.             }
  180.         }
  181.  
  182.         /**
  183.          * implements ItemListener interface
  184.          * @param e ItemEvent
  185.          * @see java.event.ItemListener#itemStateChanged
  186.          * @since 1.0
  187.          */
  188.         public void itemStateChanged(ItemEvent e) {
  189. /*
  190.             if(e.getSource() == regex) {
  191.                 if(e.getStateChange() == ItemEvent.SELECTED) {
  192.                     nocase.setEnabled(true);
  193.                 }
  194.                 else if(e.getStateChange() == ItemEvent.DESELECTED) {
  195.                     nocase.setEnabled(false);
  196.                 }
  197.             }
  198.             else if(e.getSource() == nocase) {
  199.                 if(e.getStateChange() == ItemEvent.SELECTED) {
  200.                     regex.setEnabled(true);
  201.                 }
  202.                 else if(e.getStateChange() == ItemEvent.DESELECTED) {
  203.                     regex.setEnabled(true);
  204.                 }
  205.             }
  206. */
  207.         }
  208.  
  209.         /**
  210.          * implements KeyListener interface
  211.          * @param e KeyEvent
  212.          * @see java.event.KeyListener#keyPressed
  213.          * @since 1.0
  214.          */
  215.         public void keyPressed(KeyEvent e) {
  216.             if(e.getKeyCode() == KeyEvent.VK_ENTER) {
  217.                 find();
  218.             }
  219.         }
  220.  
  221.         /**
  222.          * implements KeyListener interface
  223.          * @param e KeyEvent
  224.          * @see java.event.KeyListener#keyReleased
  225.          * @since 1.0
  226.          */
  227.         public void keyReleased(KeyEvent e) {
  228.         }
  229.  
  230.         /**
  231.          * implements KeyListener interface
  232.          * @param e KeyEvent
  233.          * @see java.event.KeyListener#keyTyped
  234.          * @since 1.0
  235.          */
  236.         public void keyTyped(KeyEvent e) {
  237.         }
  238.  
  239.     }
  240.  
  241.     /**
  242.      * <code>BookMarkDlg</code> class maintains the bookmark dialog
  243.      * @author Jeffrey A. Krzysztow
  244.      * @version 1.1
  245.      */
  246.     class BookMarkDlg extends JDialog implements MouseListener, KeyListener {
  247.         HorizontalButtons buttons = new HorizontalButtons();
  248.         JList list = new JList();
  249.         JTextField bookmarkName = new JTextField(16);
  250.  
  251.         /**
  252.          * Constructs the bookmark dialog
  253.          * @param frame the parent frame
  254.          * @since 1.0
  255.          */
  256.         BookMarkDlg(JFrame frame) {
  257.             super(frame, false);
  258.  
  259.             setTitle("Bookmarks");
  260.  
  261.             GridBagLayout gbl = new GridBagLayout();
  262.             GridBagConstraints gbc = new GridBagConstraints();
  263.             Container contentPane = getContentPane();
  264.  
  265.             contentPane.setLayout(gbl);
  266.  
  267.             addWindowListener(new WindowAdapter() {
  268.                     public void windowClosing(WindowEvent e) {
  269.                         dispose();
  270.                     }
  271.                 }
  272.             );
  273.             setResizable(false);
  274.  
  275.             JButton button = null;
  276.  
  277.             button = new JButton("Go");
  278.             button.addActionListener(new ActionListener() {
  279.                     public void actionPerformed(ActionEvent ae) {
  280.                         go();
  281.                     }
  282.                 }
  283.             );
  284.             buttons.add(button);
  285.  
  286.             button = new JButton("Add");
  287.             button.addActionListener(new ActionListener() {
  288.                     public void actionPerformed(ActionEvent ae) {
  289.                         add();
  290.                     }
  291.                 }
  292.             );
  293.             buttons.add(button);
  294.  
  295.             button = new JButton("Delete");
  296.             button.addActionListener(new ActionListener() {
  297.                     public void actionPerformed(ActionEvent ae) {
  298.                         delete();
  299.                     }
  300.                 }
  301.             );
  302.             buttons.add(button);
  303.  
  304.             bookmarkName.addKeyListener(this);
  305.             gbc.gridx = GridBagConstraints.REMAINDER;
  306.             gbl.setConstraints(bookmarkName, gbc);
  307.             contentPane.add(bookmarkName);
  308.  
  309.             gbc.gridx = GridBagConstraints.REMAINDER;
  310.             gbl.setConstraints(buttons, gbc);
  311.             contentPane.add(buttons);
  312.  
  313.             list.setPrototypeCellValue("MMMMMMMMMMMMMMMM");
  314.             list.setVisibleRowCount(10);
  315.             list.addKeyListener(this);
  316.             list.addMouseListener(this);
  317.             JScrollPane scrollList = new JScrollPane(list);
  318.             gbc.gridx = GridBagConstraints.REMAINDER;
  319.             gbl.setConstraints(scrollList, gbc);
  320.             contentPane.add(scrollList);
  321.  
  322.             pack();
  323.  
  324.             // Center dialog to parent frame
  325.             Point location = frame.getLocation();
  326.             Dimension outerSize = frame.getSize();
  327.             Dimension size = getSize();
  328.             location.x = location.x + (outerSize.width - size.width) / 2;
  329.             location.y = location.y + (outerSize.height - size.height) / 2;
  330.             setLocation(location);
  331.         }
  332.  
  333.         /**
  334.          * handles the go button to go to the bookmark specified
  335.          * @since 1.0
  336.          */
  337.         final void go() {
  338.             BookMarkHelperRD bm = null;
  339.             String lookingFor = bookmarkName.getText();
  340.             int t = list.getModel().getSize();
  341.             for(int i = 0; i < t; i++) {
  342.                 bm = (BookMarkHelperRD)bookmarks.elementAt(i);
  343.                 if(lookingFor.equals(bm.name)) {
  344.                     try {
  345.                         int offset = doc.getLineStartOffset(doc.getLineOfOffset(bm.fileOffset));
  346.                         Rectangle startLocation = doc.modelToView(offset);
  347.                         JViewport viewPort = scrollDoc.getViewport();
  348.                         viewPort.setViewPosition(new Point(startLocation.x, startLocation.y));
  349.                     }
  350.                     catch(BadLocationException e) {
  351.                         System.err.println(e);
  352.                     }
  353.                     getParent().requestFocus();
  354.                     break;
  355.                 }
  356.             }
  357.         }
  358.  
  359.         /**
  360.          * handles to add button to add the specified bookmark
  361.          * @since 1.0
  362.          */
  363.         final void add() {
  364.             String lookingFor = bookmarkName.getText();
  365.             BookMarkHelperRD bm = null;
  366.             int t = bookmarks.size();
  367.             boolean addBookmark = true;
  368.             for(int i = 0; i < t; i++) {
  369.                 bm = (BookMarkHelperRD)bookmarks.elementAt(i);
  370.                 if(lookingFor.equals(bm.name)) {
  371.                     addBookmark = false;
  372.                     break;
  373.                 }
  374.             }
  375.             if(addBookmark) {
  376.                 bm = new BookMarkHelperRD();
  377.                 bm.name = lookingFor;
  378.                 bm.fileOffset = doc.getCaretPosition();
  379.                 bookmarks.addElement(bm);
  380.             }
  381.             else {
  382.                 status.setText("Bookmark name already in use");
  383.             }
  384.         }
  385.  
  386.         /**
  387.          * handles the delete button to delete the specified bookmark
  388.          * @since 1.0
  389.          */
  390.         final void delete() {
  391.             BookMarkHelperRD bm = null;
  392.             String lookingFor = bookmarkName.getText();
  393.             int t = bookmarks.size();
  394.             for(int i = 0; i < t; i++) {
  395.                 bm = (BookMarkHelperRD)bookmarks.elementAt(i);
  396.                 if(lookingFor.equals(bm.name)) {
  397.                     bookmarks.removeElement(bm);
  398.                     bookmarkName.setText("");
  399.                     break;
  400.                 }
  401.             }
  402.         }
  403.  
  404.         /**
  405.          * updates the list of bookmarks
  406.          * @since 1.0
  407.          */
  408.         public void updateBookmarks() {
  409.             list.setModel(bookmarks);
  410.         }
  411.  
  412.         /**
  413.          * implements MouseListener interface
  414.          * @param e MouseEvent
  415.          * @see java.event.MouseListerner#mouseClicked
  416.          * @since 1.0
  417.          */
  418.         public void mouseClicked(MouseEvent e) {
  419.             if(e.getClickCount() == 2) {
  420.                 bookmarkName.setText(((BookMarkHelperRD)list.getSelectedValue()).name);
  421.                 go();
  422.             }
  423.         }
  424.  
  425.         /**
  426.          * implements MouseListener interface
  427.          * @param e MouseEvent
  428.          * @see java.event.MouseListerner#mouseEntered
  429.          * @since 1.0
  430.          */
  431.         public void mouseEntered(MouseEvent e) {
  432.         }
  433.  
  434.         /**
  435.          * implements MouseListener interface
  436.          * @param e MouseEvent
  437.          * @see java.event.MouseListerner#mouseExited
  438.          * @since 1.0
  439.          */
  440.         public void mouseExited(MouseEvent e) {
  441.         }
  442.  
  443.         /**
  444.          * implements MouseListener interface
  445.          * @param e MouseEvent
  446.          * @see java.event.MouseListerner#mousePressed
  447.          * @since 1.0
  448.          */
  449.         public void mousePressed(MouseEvent e) {
  450.         }
  451.  
  452.         /**
  453.          * implements MouseListener interface
  454.          * @param e MouseEvent
  455.          * @see java.event.MouseListerner#mouseReleased
  456.          * @since 1.0
  457.          */
  458.         public void mouseReleased(MouseEvent e) {
  459.         }
  460.  
  461.         /**
  462.          * implements KeyListener interface
  463.          * @param e KeyEvent
  464.          * @see java.event.KeyListener#keyPressed
  465.          * @since 1.0
  466.          */
  467.         public void keyPressed(KeyEvent e) {
  468.             if(e.getKeyCode() == KeyEvent.VK_ENTER) {
  469.                 go();
  470.             }
  471.         }
  472.  
  473.         /**
  474.          * implements KeyListener interface
  475.          * @param e KeyEvent
  476.          * @see java.event.KeyListener#keyReleased
  477.          * @since 1.0
  478.          */
  479.         public void keyReleased(KeyEvent e) {
  480.         }
  481.  
  482.         /**
  483.          * implements KeyListener interface
  484.          * @param e KeyEvent
  485.          * @see java.event.KeyListener#keyTyped
  486.          * @since 1.0
  487.          */
  488.         public void keyTyped(KeyEvent e) {
  489.         }
  490.  
  491.     }
  492.  
  493.     HorizontalButtons buttons = new HorizontalButtons();
  494.     JTextArea doc = new JTextArea(20, 40);
  495.     JScrollPane scrollDoc = new JScrollPane(doc) {
  496.         Dimension preferredSize;
  497.         public Dimension getPreferredSize() {
  498.             return getViewport().getPreferredSize();
  499.         }
  500.     };
  501.     JLabel status = new JLabel();
  502.  
  503.     String docText = null;
  504.     DefaultListModel bookmarks = new DefaultListModel();
  505.     int embeddedBookmarks = 0;
  506.     File pilotDoc = new File(".");
  507.     File pilotDocBM = null;
  508.     DatabaseHeader dbHeader = new DatabaseHeader();
  509.  
  510.     SearchDlg searchDlg = null;
  511.     BookMarkDlg bookmarkDlg = null;
  512.  
  513.     /**
  514.      * Constructs the main frame of the application
  515.      * @param s title
  516.      * @since 1.0
  517.      */
  518.     ReadDocJ(String s) {
  519.         super(s);
  520.  
  521.         addWindowListener(new WindowAdapter() {
  522.                 public void windowClosing(WindowEvent e) {
  523.                     shutdown();
  524.                 }
  525.             }
  526.         );
  527.  
  528.         setResizable(false);
  529.  
  530.         GridBagLayout gbl = new GridBagLayout();
  531.         GridBagConstraints gbc = new GridBagConstraints();
  532.         Container contentPane = getContentPane();
  533.  
  534.         contentPane.setLayout(gbl);
  535.  
  536.         JButton button = null;
  537.  
  538.         button = new JButton("Open");
  539.         button.addActionListener(new ActionListener() {
  540.                 public void actionPerformed(ActionEvent ae) {
  541.                     open();
  542.                 }
  543.             }
  544.         );
  545.         button.setMnemonic('o');
  546.         buttons.add(button);
  547.  
  548.         button = new JButton("Search");
  549.         button.addActionListener(new ActionListener() {
  550.                 public void actionPerformed(ActionEvent ae) {
  551.                     search();
  552.                 }
  553.             }
  554.         );
  555.         button.setMnemonic('s');
  556.         buttons.add(button);
  557.  
  558.         button = new JButton("Bookmarks");
  559.         button.addActionListener(new ActionListener() {
  560.                 public void actionPerformed(ActionEvent ae) {
  561.                     bookmarks();
  562.                 }
  563.             }
  564.         );
  565.         button.setMnemonic('b');
  566.         buttons.add(button);
  567.  
  568.         button = new JButton("Top");
  569.         button.addActionListener(new ActionListener() {
  570.                 public void actionPerformed(ActionEvent ae) {
  571.                     top();
  572.                 }
  573.             }
  574.         );
  575.         button.setMnemonic('t');
  576.         buttons.add(button);
  577.  
  578.         button = new JButton("Bottom");
  579.         button.addActionListener(new ActionListener() {
  580.                 public void actionPerformed(ActionEvent ae) {
  581.                     bottom();
  582.                 }
  583.             }
  584.         );
  585.         button.setMnemonic('m');
  586.         buttons.add(button);
  587.  
  588.         gbc.gridx = GridBagConstraints.REMAINDER;
  589.         gbc.fill = GridBagConstraints.BOTH;
  590.         gbl.setConstraints(buttons, gbc);
  591.         contentPane.add(buttons);
  592.  
  593.         doc.setEditable(false);
  594.         doc.setWrapStyleWord(true);
  595.         doc.setLineWrap(true);
  596.         gbc.gridx = GridBagConstraints.REMAINDER;
  597.         gbc.fill = GridBagConstraints.BOTH;
  598.         gbl.setConstraints(scrollDoc, gbc);
  599.         contentPane.add(scrollDoc);
  600.  
  601.         status.setText("ReadDocJ v" + version);
  602.         gbc.gridx = GridBagConstraints.REMAINDER;
  603.         gbc.fill = GridBagConstraints.BOTH;
  604.         gbl.setConstraints(status, gbc);
  605.         contentPane.add(status);
  606.  
  607.         pack();
  608.         show();
  609.  
  610.         // Center frame to screen
  611.         Point location = getLocation();
  612.         Dimension outerSize = getToolkit().getScreenSize();
  613.         Dimension size = getSize();
  614.         location.x = location.x + (outerSize.width - size.width) / 2;
  615.         location.y = location.y + (outerSize.height - size.height) / 2;
  616.         setLocation(location);
  617.  
  618.         searchDlg = new SearchDlg(this);
  619.  
  620.         bookmarkDlg = new BookMarkDlg(this);
  621.     }
  622.  
  623.     /**
  624.      * application start
  625.      * @param args command line arguments
  626.      * @since 1.0
  627.      */
  628.     public static void main(String[] args) {
  629.         ReadDocJ rdj = new ReadDocJ("ReadDocJ v" + version + " - no document");
  630.     }
  631.  
  632.     /**
  633.      * shuts downs the application
  634.      * @since 1.0
  635.      */
  636.     final void shutdown() {
  637.         saveExternalBookmarks();
  638.         System.exit(0);
  639.     }
  640.  
  641.     /**
  642.      * handles the open button to open a PilotDoc file
  643.      * @since 1.0
  644.      */
  645.     final void open() {
  646.         status.setText(" ");
  647.         saveExternalBookmarks();
  648.         JFileChooser fc = new JFileChooser(pilotDoc);
  649.         ExampleFileFilter filter = new ExampleFileFilter(new String [] { "prc", "pdb" }, "PilotDoc Files");
  650.         fc.setFileFilter(filter);
  651.         if(fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
  652.               setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
  653.             pilotDoc = fc.getSelectedFile();
  654.             pilotDocBM = new File(pilotDoc.getParent(), pilotDoc.getName() + ".bm");
  655.             try {
  656.                 RandomAccessFile fin = null;
  657.                 fin = new RandomAccessFile(pilotDoc, "r");
  658.                 byte[] buffer = decode(fin, pilotDoc, dbHeader);
  659.                 fin.close();
  660.                 if(null != buffer) {
  661.                     docText = new String(buffer);
  662.  
  663.                     processEmbeddedBookmarks();
  664.  
  665.                     loadExternalBookmarks();
  666.  
  667.                     bookmarkDlg.updateBookmarks();
  668.  
  669.                     doc.setText(docText);
  670.                     doc.setCaretPosition(0);
  671.                     setTitle("ReadDocJ v" + version +" - " + dbHeader.name);
  672.                 }
  673.             }
  674.             catch(FileNotFoundException e) {
  675.                 status.setText("The file " + pilotDoc.getName() + " could not be found");
  676.                 JOptionPane.showMessageDialog(this, "The file " + pilotDoc.getName() + " could not be found\n" + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
  677.                 return;
  678.             }
  679.             catch(IOException e) {
  680.                 status.setText("Error accessing file " + pilotDoc.getName());
  681.                 JOptionPane.showMessageDialog(this, "Error accessing file " + pilotDoc.getName() + "\n" + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
  682.             }
  683.               setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
  684.         }
  685.     }
  686.  
  687.     /**
  688.      * handles the search button to present the search dialog
  689.      * @since 1.0
  690.      */
  691.     final void search() {
  692.         if(searchDlg != null) {
  693.             searchDlg.show();
  694.         }
  695.     }
  696.  
  697.     /**
  698.      * handles the bookmark button to present the bookmark dialog
  699.      * @since 1.0
  700.      */
  701.     final void bookmarks() {
  702.         if(bookmarkDlg != null) {
  703.             bookmarkDlg.show();
  704.         }
  705.     }
  706.  
  707.     /**
  708.      * handles the top button to go to the top of the PilotDoc
  709.      * @since 1.1
  710.      */
  711.     final void top() {
  712.         if(docText != null) {
  713.             doc.setCaretPosition(0);
  714.         }
  715.     }
  716.  
  717.     /**
  718.      * handles the bottom button to go to the bottom of the PilotDoc
  719.      * @since 1.1
  720.      */
  721.     final void bottom() {
  722.         if(docText != null) {
  723.             doc.setCaretPosition(docText.length());
  724.         }
  725.     }
  726.  
  727.     /**
  728.      * decodes the PilotDoc file
  729.      * @param fin      RandomAccessFile to the PilotDoc file
  730.      * @param file     File to the PilotDocs file
  731.      * @param dbHeader returns the DatabaseHeader record, must be created by caller
  732.      * @returns byte array of PilotDoc decoded
  733.      * @throws IOException to the caller can handle any I/O errors
  734.      * @since 1.0
  735.      */
  736.     final byte[] decode(final RandomAccessFile fin, final File file, DatabaseHeader dbHeader) throws IOException {
  737.         status.setText("Processing database header");
  738.         dbHeader.read(fin);
  739.  
  740.         if(dbHeader.creatorID != DatabaseHeader.ReaderID
  741.             && dbHeader.creatorID != DatabaseHeader.TealDocID
  742.             || dbHeader.typeID != DatabaseHeader.TEXt) {
  743.             status.setText(file.getName() + "is unknown format");
  744.             return null;
  745.         }
  746.  
  747.         RecordIndex[] ri = new RecordIndex[dbHeader.numRecords];
  748.         for(int i = 0; i < dbHeader.numRecords; i++) {
  749.             status.setText("Processing record index " + i + " of " + dbHeader.numRecords);
  750.             ri[i] = new RecordIndex();
  751.             ri[i].read(fin);
  752.         }
  753.  
  754.         short unknown = fin.readShort();
  755.  
  756.         DocumentHeader docHeader = new DocumentHeader();
  757.         status.setText("Processing document header");
  758.         fin.seek(ri[0].fileOffset);
  759.         docHeader.read(fin);
  760.  
  761.         if(docHeader.version != DocumentHeader.UNCOMPRESSED && docHeader.version != DocumentHeader.COMPRESSED) {
  762.             status.setText(file.getName() + " unknown file compression type: " + docHeader.version);
  763.             return null;
  764.         }
  765.  
  766.         byte[] buffer = new byte[docHeader.numRecords * DocumentHeader.textRecordSize];
  767.             // the DocumentHeader.storyLen is not always correct, so this is over-kill
  768.  
  769.         boolean compressed = (docHeader.version == DocumentHeader.COMPRESSED);
  770.  
  771.         PilotDocRecord textBuf;
  772.  
  773.         int dwRecLen;
  774.         int bufferPos = 0;
  775.         for(int i = 1; i <= docHeader.numRecords; i++) {
  776.             status.setText("Decoding " + i + " of " + docHeader.numRecords);
  777.             if(i == ri.length - 1) {
  778.                 // for the last, use the file len
  779.                 dwRecLen = (int) fin.length() - ri[i].fileOffset;
  780.             }
  781.             else {
  782.                 dwRecLen = ri[i + 1].fileOffset - ri[i].fileOffset;
  783.             }
  784.             fin.seek(ri[i].fileOffset);
  785.             textBuf = new PilotDocRecord(dwRecLen);
  786.             fin.read(textBuf.buf);
  787.             if(compressed) {
  788.                 textBuf.decompress();
  789.             }
  790.             System.arraycopy(textBuf.buf, 0, buffer, bufferPos, textBuf.length());
  791.             bufferPos += textBuf.length();
  792.         }
  793.  
  794.         byte[] newbuffer = new byte[bufferPos];
  795.         System.arraycopy(buffer, 0, newbuffer, 0, bufferPos);
  796.  
  797.         /////////////////////////////////////////////////////////////
  798.         // Handle encoded bookmarks if any
  799.         bookmarks = new DefaultListModel();
  800.         if(docHeader.numRecords + 1 < dbHeader.numRecords) {
  801.             int bmn = 1;
  802.             int bmt = dbHeader.numRecords - docHeader.numRecords - 1;
  803.             for(int i = docHeader.numRecords + 1; i < dbHeader.numRecords; i++, bmn++) {
  804.                 status.setText("Processing internal bookmark " + bmn + " of " + bmt);
  805.                 fin.seek(ri[i].fileOffset);
  806.                 BookMarkHelperRD bm = new BookMarkHelperRD();
  807.                 bm.read(fin);
  808.                 bookmarks.addElement(bm);
  809.             }
  810.         }
  811.  
  812.         return newbuffer;
  813.     }
  814.  
  815.     /**
  816.      * processes the auto-bookmarks if present
  817.      * @since 1.1
  818.      */
  819.     final void processEmbeddedBookmarks() {
  820.         embeddedBookmarks = 0;
  821.         char curChar;
  822.         int startPos = -1;
  823.         int endPos = -1;
  824.         for(int curCharPos = docText.length() - 1; curCharPos > -1; curCharPos--) {
  825.             curChar = docText.charAt(curCharPos);
  826.             if(curChar == '<') {    // start sequence
  827.                 startPos = curCharPos;
  828.                 break;    // we are done looking
  829.             }
  830.             else if(curChar == '>') {    // end sequence
  831.                 endPos = curCharPos;
  832.             }
  833.             else if(!Character.isWhitespace(curChar) && endPos == -1) {
  834.                 break;
  835.             }
  836.         }
  837.         if(startPos > -1 && endPos > -1) {
  838.             String lookFor = docText.substring(startPos + 1, endPos);
  839.             int found = 0;
  840.             while((found = docText.indexOf(lookFor, found)) > 0) {
  841.                 if(docText.charAt(found - 1) == '\n') {
  842.                     BookMarkHelperRD bm = new BookMarkHelperRD(false);
  843.                     bm.fileOffset = found;
  844.                     int curCharPos = found += lookFor.length();
  845.                     for(; curCharPos < docText.length(); curCharPos++) {
  846.                         if(docText.charAt(curCharPos) == '\n') {
  847.                             while(Character.isWhitespace(docText.charAt(found))) {
  848.                                 found++;
  849.                             }
  850.                             bm.name = docText.substring(found, curCharPos);
  851.                             bookmarks.addElement(bm);
  852.                             embeddedBookmarks++;
  853.                             break;
  854.                         }
  855.                     }
  856.                     found = curCharPos;
  857.                 }
  858.                 else {
  859.                     found++;
  860.                 }
  861.             }
  862.         }
  863.     }
  864.  
  865.     final private int bookmarkID = 0x4252534b;    // BRSK, so we "know" it's a "valid" bookmark file
  866.  
  867.     /**
  868.      * saves the bookmarks to a file
  869.      * @since 1.0
  870.      */
  871.     final void saveExternalBookmarks() {
  872.         if(pilotDocBM != null && bookmarks.size() - embeddedBookmarks > 0) {
  873.             try {
  874.                 pilotDocBM.delete();
  875.                 RandomAccessFile bout = new RandomAccessFile(pilotDocBM, "rw");
  876.                 BookMarkHelperRD bm = null;
  877.                 bout.writeInt(bookmarkID);
  878.                 bout.writeInt(bookmarks.size() - embeddedBookmarks);
  879.                 int t = bookmarks.size();
  880.                 for(int i = 0; i < t; i++) {
  881.                     status.setText("Processing external bookmark " + i + " of " + t);
  882.                     bm = (BookMarkHelperRD)bookmarks.elementAt(i);
  883.                     if(bm.isOk2Save()) {
  884.                         bm.write(bout);
  885.                     }
  886.                 }
  887.                 bout.close();
  888.             }
  889.             catch(IOException e) {
  890.                 status.setText("Error accessing file " + pilotDocBM.getName());
  891.                 JOptionPane.showMessageDialog(this, "Error accessing file " + pilotDocBM.getName() + "\n" + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
  892.             }
  893.         }
  894.     }
  895.  
  896.     /**
  897.      * loads the bookmarks from a file
  898.      * @since 1.0
  899.      */
  900.     final void loadExternalBookmarks() {
  901.         if(pilotDocBM != null) {
  902.             if(pilotDocBM.exists()) {
  903.                 if(pilotDocBM.lastModified() >= pilotDoc.lastModified()) {
  904.                     try {
  905.                         RandomAccessFile bout = new RandomAccessFile(pilotDocBM, "rw");
  906.                         if(bout.readInt() == bookmarkID) {
  907.                             bookmarks = new DefaultListModel();
  908.                             BookMarkHelperRD bm = null;
  909.                             int count = bout.readInt();
  910.                             for(int x = 0; x < count; x++) {
  911.                                 status.setText("Processing external bookmark " + x + " of " + count);
  912.                                 bm = new BookMarkHelperRD();
  913.                                 bm.read(bout);
  914.                                 bookmarks.addElement(bm);
  915.                             }
  916.                         }
  917.                         bout.close();
  918.                     }
  919.                     catch(IOException e) {
  920.                         status.setText("Error accessing file " + pilotDocBM.getName());
  921.                         JOptionPane.showMessageDialog(this, "Error accessing file " + pilotDocBM.getName() + "\n" + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
  922.                     }
  923.                 }
  924.                 else {
  925.                     status.setText("External bookmark file will not be loaded");
  926.                 }
  927.             }
  928.         }
  929.     }
  930.  
  931. }
  932.