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