001    /*
002     * Copyright 2007, 2012 Stephen Fisher and Junhyong Kim, University of
003     * Pennsylvania.
004     *
005     * This file is part of Glo-DB.
006     * 
007     * Glo-DB is free software: you can redistribute it and/or modify it
008     * under the terms of the GNU General Public License as published by
009     * the Free Software Foundation, either version 3 of the License, or
010     * (at your option) any later version.
011     * 
012     * Glo-DB is distributed in the hope that it will be useful, but
013     * WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015     * General Public License for more details.
016     * 
017     * You should have received a copy of the GNU General Public License
018     * along with Glo-DB. If not, see <http://www.gnu.org/licenses/>.
019     *
020     * @(#)ViewHTML.java
021     */
022    
023    package edu.upenn.gloDB.gui;
024    
025    import edu.upenn.gloDB.GloDBUtils;
026    import java.awt.*;
027    import java.awt.event.*;
028    import javax.swing.*;
029    import javax.swing.text.html.*;
030    import javax.swing.event.*;
031    import java.net.URL;
032    import java.io.*;
033    import javax.swing.filechooser.FileFilter;
034    
035    /**
036     * Browse HTML file or text.
037     *
038     * @author  Stephen Fisher
039     * @version $Id: ViewHTML.java,v 1.1.2.11 2007/03/01 21:17:33 fisher Exp $
040     */
041    
042    public class ViewHTML extends JFrame {
043             private final static int URL = 1;
044             private final static int TEXT = 2;
045             private final static int INPUTSTREAM = 3;
046    
047             ViewHTML thisFrame;
048             HTMLEditorPane htmlText = new HTMLEditorPane();
049             
050             public ViewHTML(URL source) {
051                      super("GLO-DB: HTML Viewer");
052                      setup(source, URL);
053             }
054    
055             public ViewHTML(String source) {
056                      super("GLO-DB: HTML Viewer");
057                      setup(source, TEXT);
058             }
059    
060             public ViewHTML(InputStream source) {
061                      super("GLO-DB: HTML Viewer");
062                      setup(source, INPUTSTREAM);
063             }
064    
065             private void setup(Object source, int type) {
066                      // keep pointer to self so can 'dispose' Frame below
067                      thisFrame = this;
068                      
069                      setDefaultCloseOperation(DISPOSE_ON_CLOSE);
070                      
071                      // setup text area to display data
072                      htmlText.setEditable(false);
073                      htmlText.addHyperlinkListener(new Hyperactive());
074                      switch (type) {
075                      case URL: 
076                                    try { 
077                                             htmlText.setPage((URL) source); 
078                                    } catch (IOException e) { 
079                                             GloDBUtils.printError("Invalid URL to be displayed"); 
080                                             return;
081                                    }
082                                    break;
083                      case TEXT: 
084                                    htmlText.setContentType("text/html");
085                                    htmlText.setText((String) source);
086                                    break;
087                      case INPUTSTREAM: 
088                                    htmlText.setContentType("text/html");
089                                    try {
090                                             htmlText.read((InputStream) source, null);
091                                    } catch (IOException e) { 
092                                             GloDBUtils.printError("Invalid InputStream to be displayed"); 
093                                             return;
094                                    }
095                                    break;
096                      }
097            JScrollPane htmlTextSP = new JScrollPane(htmlText);
098                      htmlTextSP.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
099                      
100                      // button panel
101                      JPanel buttonP = new JPanel(new GridLayout(1,0));
102                      buttonP.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
103                      // save button
104                      JButton saveB = new JButton("Save HTML");
105                      saveB.addActionListener(new ActionListener() {
106                                             public void actionPerformed(ActionEvent e) {
107                                                      String filename = saveFileChooser();
108                                                      if (filename.length() > 0) {
109                                                                    // set overwrite to 'true' because the user
110                                                                    // agreed to overwrite the file in the
111                                                                    // FileChooser
112                                                                    saveText(filename, true);
113                                                      }
114                                             }
115                                    });
116                      buttonP.add(saveB);
117                      // close button
118                      JButton closeB = new JButton("Close Viewer");
119                      closeB.addActionListener(new ActionListener() {
120                                             public void actionPerformed(ActionEvent e) {
121                                                      thisFrame.dispose();
122                                             }
123                                    });
124                      buttonP.add(closeB);
125                      
126                      getContentPane().setLayout(new BorderLayout());
127                      getContentPane().add(htmlTextSP, BorderLayout.CENTER);
128                      getContentPane().add(buttonP, BorderLayout.SOUTH);
129                      pack();
130                      
131                      // set the default window size
132                      setSize(800, 900);
133                      
134                      // display the window
135                      //              setVisible(true);
136                      show();
137             }
138    
139             private class Hyperactive implements HyperlinkListener {
140             public void hyperlinkUpdate(HyperlinkEvent e) {
141                      if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
142                          HTMLEditorPane pane = (HTMLEditorPane) e.getSource();
143                          if (e instanceof HTMLFrameHyperlinkEvent) {
144                              HTMLFrameHyperlinkEvent  evt = (HTMLFrameHyperlinkEvent)e;
145                              HTMLDocument doc = (HTMLDocument)pane.getDocument();
146                              doc.processHTMLFrameHyperlinkEvent(evt);
147                          } else {
148                              try {
149                                  pane.setPage(e.getURL());
150                              } catch (Throwable t) {
151                                  t.printStackTrace();
152                              }
153                          }
154                      }
155                  }
156         }
157    
158             /** 
159              * Use a JFileChooser the get the file info for saving HTML to a file.
160              */
161             public String saveFileChooser() {
162                      // use the current working directory
163                      JFileChooser fileChooser = new JFileChooser();
164    
165                      // set the title
166                      fileChooser.setDialogTitle("Save HTML File");
167                      // set the filter, if present
168                      fileChooser.setAcceptAllFileFilterUsed(true);
169                      FileFilter filter = new HTMLFilter();
170                      fileChooser.addChoosableFileFilter(filter);
171                      fileChooser.setFileFilter(filter);
172    
173                      // launch the file chooser
174                      int status = fileChooser.showSaveDialog(null);
175                      if (status == JFileChooser.APPROVE_OPTION) {
176                File file = fileChooser.getSelectedFile();
177                                    String filename = GUIUtils.getFilename(file);
178    
179                                    String[] ext = {".htm", ".html"};
180                                    boolean notFound = true;
181                                    int i = 0;
182                                    while (notFound && (i < ext.length)) {
183                                             if (filename.endsWith(ext[i])) notFound = false;
184                                             i++;
185                                    }
186    
187                                    // the filename doesn't end with a valid ext, so loop
188                                    // through the extensions to see if we can find a file
189                                    // with one of the valid extensions.  we could just take
190                                    // the first ext that isn't a valid file but it's assumed
191                                    // that users will be consistent in their use of
192                                    // extensions and thus if ".html" matches but ".htm"
193                                    // doesn't, we assume that ".html" is actually what the
194                                    // user wants to use.
195                                    if (notFound) {
196                                             i = 0; 
197                                             // we're overloading 'notFound' by using it
198                                             // here as well as above.
199                                             while (notFound && (i < ext.length)) {
200                                                      file = new File(filename + ext[i]);
201                                                      if (file.exists()) notFound = false;
202                                                      else i++;   // don't increment if found
203                                             }
204                                             // if no file extensions match a file, then
205                                             // just use the first one in the list.
206                                             if (notFound) filename += ext[0];
207                                             else filename += ext[i];
208                                    }
209    
210                                    if (! file.exists()) return filename;
211                                            
212                                    // the file exist, so check if want to overwrite the file
213                                    String msg = "The file \"" + file.getPath() + "\" already exists.\n";
214                                    msg += "Do you want to overwrite the file?";
215                                    Object[] options = {"Overwrite", "Cancel"};
216                                    int flag = JOptionPane.showOptionDialog(null, msg,
217                                                                                                                                             "Overwrite Confirmation",
218                                                                                                                                             JOptionPane.YES_NO_OPTION,
219                                                                                                                                             JOptionPane.QUESTION_MESSAGE,
220                                                                                                                                             null,
221                                                                                                                                             options,
222                                                                                                                                             options[1]);
223                                    if (flag == JOptionPane.YES_OPTION) { // "Overwrite"
224                                             return filename;
225                                    } else {
226                                             return saveFileChooser();
227                                    }
228                      }
229    
230                      return "";
231        }
232    
233             /**
234              * Save the html text to a file.
235              *
236              * @XXX need to throw FileIO exceptions, rather than just print
237              * errors.
238              */
239             public void saveText(String filename, boolean overwrite) {
240                      // add ".htm" filename extension, if necessary
241                      if ((! filename.endsWith(".html")) && (! filename.endsWith(".htm"))) {
242                                    filename += ".htm";
243                      }
244    
245                      File file = new File(filename);
246                      // if the file already exists and not supposed to overwrite
247                      // it, then return on error.
248                      if (file.exists() && (! overwrite)) {
249                                    GloDBUtils.printError("File \"" + filename + "\" already exists.");
250                                    return;
251                      }
252    
253                      try {
254                                    FileWriter fWriter = new FileWriter(file);
255                                    BufferedWriter bWriter = new BufferedWriter(fWriter);
256    
257                                    //                              bWriter.write(htmlText.getText());
258                                    bWriter.write(htmlText.getHTML());
259                                    //                              bWriter.newLine();
260                                    bWriter.flush();
261                                    bWriter.close();
262                      } catch (FileNotFoundException e) {
263                                    // problem with FileOutputStream
264                                    GloDBUtils.printError("File \"" + filename + "\" can not be opened.");
265                      } catch (IOException e) {
266                                    // problem with ObjectOutputStream.  XXX do we need to
267                                    // close bWriter()?
268                                    GloDBUtils.printError("Error writting html file \"" + filename + "\".");
269                      }
270             }
271    
272             /** 
273              * HTML FileFilter. 
274              */
275             private class HTMLFilter extends FileFilter {
276                      public boolean accept(File f) {
277                                    // accept directories
278                                    if (f.isDirectory()) return true;
279                                    
280                                    // accept all files
281                                    if ((f.getName()).endsWith(".html")) return true;
282                                    if ((f.getName()).endsWith(".htm")) return true;
283    
284                                    return false;
285                      }
286                      
287                      // set the filter's description
288                      public String getDescription() { return "HTML files (*.htm; *.html)"; }
289             }
290    
291             /**
292              * This class is meant to wrap the JEditorPane because the
293              * JEditorPane munges up the HTML source when it stores the text.
294              * When it stores HTML it looses tags that it doesn't know about
295              * and thus when we use getText() routine to get the original HTML
296              * text back it isn't correct.  So here we keep a copy of the
297              * original HTML.  
298              * @XXX This should also handle URLs and InputStreams.
299              */
300             private class HTMLEditorPane extends JEditorPane {
301                      private String origHTML = "";
302                      
303                      public void setText(String source) {
304                                    super.setText(source);
305                                    origHTML = source;
306                      }
307    
308                      public String getHTML() {
309                                    if (origHTML.length() > 0) return origHTML;
310                                    else return getText();
311                      }
312             }
313    
314    } // ViewHTML.java