1   /**
2    * Distribution License:
3    * BibleDesktop is free software; you can redistribute it and/or modify it under
4    * the terms of the GNU General Public License, version 2 as published by
5    * the Free Software Foundation. This program is distributed in the hope
6    * that it will be useful, but WITHOUT ANY WARRANTY; without even the
7    * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8    * See the GNU General Public License for more details.
9    *
10   * The License is available on the internet at:
11   *       http://www.gnu.org/copyleft/gpl.html
12   * or by writing to:
13   *      Free Software Foundation, Inc.
14   *      59 Temple Place - Suite 330
15   *      Boston, MA 02111-1307, USA
16   *
17   * Copyright: 2005
18   *     The copyright to this program is held by it's authors.
19   *
20   * ID: $Id: ViewSourcePane.java 2105 2011-03-07 21:13:31Z dmsmith $
21   */
22  package org.crosswire.bibledesktop.desktop;
23  
24  import java.awt.BorderLayout;
25  import java.awt.Dimension;
26  import java.awt.FlowLayout;
27  import java.awt.Font;
28  import java.awt.Frame;
29  import java.awt.Toolkit;
30  import java.awt.datatransfer.StringSelection;
31  import java.io.IOException;
32  import java.io.ObjectInputStream;
33  import java.net.URI;
34  
35  import javax.swing.BorderFactory;
36  import javax.swing.JButton;
37  import javax.swing.JDialog;
38  import javax.swing.JPanel;
39  import javax.swing.JTabbedPane;
40  import javax.swing.JTextArea;
41  import javax.swing.WindowConstants;
42  import javax.swing.text.JTextComponent;
43  import javax.xml.transform.TransformerException;
44  
45  import org.crosswire.bibledesktop.BDMsg;
46  import org.crosswire.bibledesktop.book.install.BookFont;
47  import org.crosswire.bibledesktop.util.ConfigurableSwingConverter;
48  import org.crosswire.common.swing.ActionFactory;
49  import org.crosswire.common.swing.CWAction;
50  import org.crosswire.common.swing.CWScrollPane;
51  import org.crosswire.common.swing.GuiConvert;
52  import org.crosswire.common.swing.GuiUtil;
53  import org.crosswire.common.util.Reporter;
54  import org.crosswire.common.xml.Converter;
55  import org.crosswire.common.xml.FormatType;
56  import org.crosswire.common.xml.PrettySerializingContentHandler;
57  import org.crosswire.common.xml.SAXEventProvider;
58  import org.crosswire.common.xml.TransformingSAXEventProvider;
59  import org.crosswire.jsword.book.Book;
60  import org.crosswire.jsword.book.BookCategory;
61  import org.crosswire.jsword.book.BookData;
62  import org.crosswire.jsword.book.BookException;
63  import org.crosswire.jsword.book.BookMetaData;
64  import org.crosswire.jsword.passage.Key;
65  import org.crosswire.jsword.util.ConverterFactory;
66  import org.xml.sax.ContentHandler;
67  import org.xml.sax.SAXException;
68  
69  /**
70   * ViewSourcePane allow viewing of some text in its own standalone frame. The
71   * text to be viewed can be grabbed from a String, a URI, or a file.
72   * 
73   * @see gnu.gpl.License for license details.<br>
74   *      The copyright to this program is held by it's authors.
75   * @author Joe Walker [joe at eireneh dot com]
76   * @author DM Smith [dmsmith555 at yahoo dot com]
77   */
78  public class ViewSourcePane extends JPanel {
79      public ViewSourcePane(Book[] books, Key key) {
80          try {
81              StringBuilder buf = new StringBuilder();
82  
83              for (Key currentKey : key) {
84                  String osisID = currentKey.getOsisID();
85                  for (int i = 0; i < books.length; i++) {
86                      Book book = books[i];
87                      if (buf.length() > 0) {
88                          buf.append('\n');
89                      }
90                      buf.append(book.getInitials());
91                      buf.append(':');
92                      buf.append(osisID);
93                      buf.append(" - ");
94                      buf.append(book.getRawText(currentKey));
95                  }
96              }
97  
98              // TODO(DMS): handle comparison
99              BookData bdata = new BookData(books, key, false);
100 
101             Book book = bdata.getFirstBook();
102             BookMetaData bmd = book.getBookMetaData();
103 
104             String fontSpec = GuiConvert.font2String(BookFont.instance().getFont(book));
105 
106             SAXEventProvider osissep = bdata.getSAXEventProvider();
107 
108             // This really looks nice but its performance was terrible.
109             // ContentHandler osis = new
110             // HTMLSerializingContentHandler(FormatType.CLASSIC_INDENT);
111             ContentHandler osis = new PrettySerializingContentHandler(FormatType.CLASSIC_INDENT);
112             osissep.provideSAXEvents(osis);
113 
114             TransformingSAXEventProvider htmlsep = (TransformingSAXEventProvider) converter.convert(osissep);
115 
116             XSLTProperty.DIRECTION.setState(bmd.isLeftToRight() ? "ltr" : "rtl");
117 
118             URI loc = bmd.getLocation();
119             XSLTProperty.BASE_URL.setState(loc == null ? "" : loc.getPath());
120 
121             if (bmd.getBookCategory() == BookCategory.BIBLE) {
122                 XSLTProperty.setProperties(htmlsep);
123             } else {
124                 XSLTProperty.CSS.setProperty(htmlsep);
125                 XSLTProperty.BASE_URL.setProperty(htmlsep);
126                 XSLTProperty.DIRECTION.setProperty(htmlsep);
127             }
128             // Override the default if needed
129             htmlsep.setParameter(XSLTProperty.FONT.getName(), fontSpec);
130 
131             // This really looks nice but its performance was terrible.
132             // ContentHandler html = new
133             // HTMLSerializingContentHandler(FormatType.CLASSIC_INDENT);
134             ContentHandler html = new PrettySerializingContentHandler(FormatType.CLASSIC_INDENT);
135             htmlsep.provideSAXEvents(html);
136 
137             init(buf.toString(), osis.toString(), html.toString());
138         } catch (SAXException e) {
139             Reporter.informUser(null, e);
140         } catch (TransformerException e) {
141             Reporter.informUser(null, e);
142         } catch (BookException e) {
143             Reporter.informUser(null, e);
144         }
145     }
146 
147     /**
148      * Actually create the GUI
149      */
150     private void init(String orig, String osis, String html) {
151         actions = new ActionFactory(this);
152 
153         Font userRequestedFont = ConfigurableSwingConverter.toFont();
154 
155         JTextArea txtOrig = new JTextArea(orig, 24, 80);
156         txtOrig.setFont(userRequestedFont);
157         txtOrig.setLineWrap(true);
158         txtOrig.setWrapStyleWord(true);
159         txtOrig.setTabSize(2);
160         txtOrig.setEditable(false);
161         JPanel pnlOrig = new JPanel(new BorderLayout());
162         pnlOrig.add(new CWScrollPane(txtOrig), BorderLayout.CENTER);
163         pnlOrig.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
164 
165         // This really looks nice but its performance was terrible.
166         // JTextPane txtOsis = new AntiAliasedTextPane();
167         // txtOsis.setFont(userRequestedFont);
168         // txtOsis.setEditable(false);
169         // txtOsis.setEditorKit(new HTMLEditorKit());
170         // txtOsis.setText(osis);
171         // txtOsis.setCaretPosition(0);
172         JTextArea txtOsis = new JTextArea(osis, 24, 80);
173         txtOsis.setFont(userRequestedFont);
174         txtOsis.setLineWrap(true);
175         txtOsis.setWrapStyleWord(true);
176         txtOsis.setTabSize(2);
177         txtOsis.setEditable(false);
178         JPanel pnlOsis = new JPanel(new BorderLayout());
179         pnlOsis.add(new CWScrollPane(txtOsis), BorderLayout.CENTER);
180         pnlOsis.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
181 
182         // This really looks nice but its performance was terrible.
183         // JTextPane txtHtml = new AntiAliasedTextPane();
184         // txtHtml.setFont(userRequestedFont);
185         // txtHtml.setEditable(false);
186         // txtHtml.setEditorKit(new HTMLEditorKit());
187         // txtHtml.setText(html);
188         // txtHtml.setCaretPosition(0);
189         JTextArea txtHtml = new JTextArea(html, 24, 80);
190         txtHtml.setFont(userRequestedFont);
191         txtHtml.setLineWrap(true);
192         txtHtml.setWrapStyleWord(true);
193         txtHtml.setTabSize(2);
194         txtHtml.setEditable(false);
195         JPanel pnlHtml = new JPanel(new BorderLayout());
196         pnlHtml.add(new CWScrollPane(txtHtml), BorderLayout.CENTER);
197         pnlHtml.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
198 
199         textAreas = new JTextComponent[] {
200                 txtOrig, txtOsis, txtHtml
201         };
202 
203         pnlButtons = new JPanel(new FlowLayout(FlowLayout.TRAILING));
204         pnlButtons.add(new JButton(actions.addAction("SourceClip", BDMsg.gettext("Copy")).setTooltip(BDMsg.gettext("Copy the source to the clipboard."))), null);
205 
206         tabMain = new JTabbedPane();
207         // TRANSLATOR: Label for the View Source tab holding the raw content
208         // of the passage in the active Bible View.
209         tabMain.add(pnlOrig, BDMsg.gettext("Original"));
210         // TRANSLATOR: Label for the View Source tab holding the OSIS transformation
211         // of the raw content in the prior tab for the passage in the active Bible View.
212         tabMain.add(pnlOsis, BDMsg.gettext("OSIS"));
213         // TRANSLATOR: Label for the View Source tab holding the HTML transformation
214         // of the OSIS in the prior tab for the passage in the active Bible View.
215         tabMain.add(pnlHtml, BDMsg.gettext("HTML"));
216 
217         this.setLayout(new BorderLayout());
218         this.add(tabMain, BorderLayout.CENTER);
219         this.add(pnlButtons, BorderLayout.SOUTH);
220         GuiUtil.applyDefaultOrientation(this);
221     }
222 
223     /**
224      * Display this Panel in a new JFrame
225      */
226     public void showInFrame(Frame parent) {
227         // TRANSLATOR: title for the Source View dialog
228         frame = new JDialog(parent, BDMsg.gettext("Source Viewer"));
229 
230         // TRANSLATOR: This is the text of an "OK" button that dismisses the dialog
231         CWAction action = actions.addAction("SourceOK", BDMsg.gettext("OK"));
232         // TRANSLATOR: This is the tooltip for an "OK" button that dismisses the dialog
233         action.setTooltip(BDMsg.gettext("Close this window"));
234         pnlButtons.add(new JButton(action), null);
235 
236         this.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
237 
238         frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
239         frame.getContentPane().setLayout(new BorderLayout());
240         frame.getContentPane().add(this, BorderLayout.CENTER);
241 
242         GuiUtil.setSize(frame, new Dimension(750, 500));
243         GuiUtil.centerOnScreen(frame);
244         frame.setVisible(true);
245     }
246 
247     /**
248      * Copy the current text into the system clipboard
249      */
250     public void doSourceClip() {
251         int i = tabMain.getSelectedIndex();
252         JTextComponent tc = textAreas[i];
253         StringSelection ss = new StringSelection(tc.getText());
254         Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, null);
255     }
256 
257     /**
258      *
259      */
260     public void doSourceOK() {
261         frame.setVisible(false);
262         frame.dispose();
263     }
264 
265     /**
266      * Serialization support.
267      * 
268      * @param is
269      * @throws IOException
270      * @throws ClassNotFoundException
271      */
272     private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
273         actions = new ActionFactory(this);
274         is.defaultReadObject();
275     }
276 
277     /*
278      * GUI Components
279      */
280     private JTabbedPane tabMain;
281     private JTextComponent[] textAreas;
282     private JPanel pnlButtons;
283     private JDialog frame;
284     private transient ActionFactory actions;
285 
286     private static Converter converter = ConverterFactory.getConverter();
287 
288     /**
289      * Serialization ID
290      */
291     private static final long serialVersionUID = 3257281435579985975L;
292 }
293