49501fbc8a1fca264208e17428c0789155b25843
[debian/jabref.git] / src / java / net / sf / jabref / PreviewPanel.java
1 package net.sf.jabref;
2
3 import java.awt.*;
4 import java.awt.event.ActionEvent;
5 import java.awt.print.PrinterException;
6 import java.beans.PropertyChangeEvent;
7 import java.beans.PropertyVetoException;
8 import java.beans.VetoableChangeListener;
9 import java.io.IOException;
10 import java.io.StringReader;
11
12 import javax.swing.*;
13 import javax.swing.event.HyperlinkEvent;
14 import javax.swing.event.HyperlinkListener;
15
16 import net.sf.jabref.export.layout.Layout;
17 import net.sf.jabref.export.layout.LayoutHelper;
18 import net.sf.jabref.util.DocumentPrinter;
19
20 /**
21  * Displays an BibtexEntry using the given layout format.
22  * 
23  * @author $Author: mortenalver $
24  * @version $Revision: 2597 $ ($Date: 2007-08-01 20:23:38 +0200 (Mi, 01 Aug
25  *          2007) $)
26  * 
27  */
28 public class PreviewPanel extends JPanel implements VetoableChangeListener {
29
30         /**
31          * The bibtex entry currently shown
32          */
33         BibtexEntry entry;
34
35         MetaData metaData;
36
37         /**
38          * If a database is set, the preview will attempt to resolve strings in the
39          * previewed entry using that database.
40          */
41         BibtexDatabase database;
42
43         Layout layout;
44
45         String layoutFile;
46
47         public JEditorPane previewPane;
48
49         JScrollPane scrollPane;
50
51         BasePanel panel;
52
53         /**
54          * 
55          * @param database
56          *            (may be null) Optionally used to resolve strings.
57          * @param entry
58          *            (may be null) If given this entry is shown otherwise you have
59          *            to call setEntry to make something visible.
60          * @param panel
61          *            (may be null) If not given no toolbar is shown on the right
62          *            hand side.
63          * @param metaData
64          *            (must be given) Used for resolving pdf directories for links.
65          * @param layoutFile
66          *            (must be given) Used for layout
67          */
68         public PreviewPanel(BibtexDatabase database, BibtexEntry entry,
69                 BasePanel panel, MetaData metaData, String layoutFile) {
70                 this(panel, metaData, layoutFile);
71                 this.database = database;
72                 setEntry(entry);
73         }
74
75         /**
76          * 
77          * @param panel
78          *            (may be null) If not given no toolbar is shown on the right
79          *            hand side.
80          * @param metaData
81          *            (must be given) Used for resolving pdf directories for links.
82          * @param layoutFile
83          *            (must be given) Used for layout
84          */
85         public PreviewPanel(BasePanel panel, MetaData metaData, String layoutFile) {
86                 super(new BorderLayout(), true);
87
88                 this.panel = panel;
89                 this.metaData = metaData;
90                 this.layoutFile = layoutFile;
91                 this.previewPane = createPreviewPane();
92
93                 // Set up scroll pane for preview pane
94                 scrollPane = new JScrollPane(previewPane,
95                         JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
96                         JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
97                 scrollPane.setBorder(null);
98                 
99                 /*
100                  * If we have been given a panel and the preference option
101                  * previewPrintButton is set, show the tool bar
102                  */
103                 if (panel != null
104                         && JabRefPreferences.getInstance().getBoolean("previewPrintButton")) {
105                         add(createToolBar(), BorderLayout.LINE_START);
106                 }
107
108                 add(scrollPane, BorderLayout.CENTER);
109         }
110
111         class PrintAction extends AbstractAction {
112
113                 public PrintAction() {
114                         super(Globals.lang("Print Preview"), GUIGlobals.getImage("psSmall"));
115                         putValue(SHORT_DESCRIPTION, Globals.lang("Print Preview"));
116                 }
117
118                 DocumentPrinter printerService;
119
120                 public void actionPerformed(ActionEvent arg0) {
121                         if (printerService == null)
122                                 printerService = new DocumentPrinter();
123
124                         // Background this, as it takes a while.
125                         new Thread() {
126                                 public void run() {
127                                         try {
128                                                 printerService.print(entry.getCiteKey(), previewPane);
129                                         } catch (PrinterException e) {
130
131                                                 // Inform the user... we don't know what to do.
132                                                 JOptionPane.showMessageDialog(PreviewPanel.this,
133                                                         Globals.lang("Could not print preview") + ".\n"
134                                                                 + e.getMessage(), Globals
135                                                                 .lang("Printing Entry Preview"),
136                                                         JOptionPane.ERROR_MESSAGE);
137                                         }
138                                 }
139                         }.start();
140                 }
141         }
142
143         Action printAction;
144
145         public Action getPrintAction() {
146                 if (printAction == null)
147                         printAction = new PrintAction();
148                 return printAction;
149         }
150
151         class CloseAction extends AbstractAction {
152                 public CloseAction() {
153                         super(Globals.lang("Close window"), GUIGlobals.getImage("close"));
154                         putValue(SHORT_DESCRIPTION, Globals.lang("Close window"));
155                 }
156
157                 public void actionPerformed(ActionEvent e) {
158                         panel.hideBottomComponent();
159                 }
160         }
161
162         Action closeAction;
163
164         public Action getCloseAction() {
165                 if (closeAction == null)
166                         closeAction = new CloseAction();
167                 return closeAction;
168         }
169
170         JPopupMenu createPopupMenu() {
171                 JPopupMenu menu = new JPopupMenu();
172                 menu.add(getPrintAction());
173
174                 return menu;
175         }
176
177         JToolBar createToolBar() {
178
179                 JToolBar tlb = new JToolBar(JToolBar.VERTICAL);
180                 JabRefPreferences prefs = JabRefPreferences.getInstance();
181                 Action printAction = getPrintAction();
182                 Action closeAction = getCloseAction();
183
184                 tlb.setMargin(new Insets(0, 0, 0, 2));
185
186                 // The toolbar carries all the key bindings that are valid for the whole
187                 // window.
188                 ActionMap am = tlb.getActionMap();
189                 InputMap im = tlb.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
190
191                 im.put(prefs.getKey("Close entry preview"), "close");
192                 am.put("close", closeAction);
193
194                 im.put(prefs.getKey("Print entry preview"), "print");
195                 am.put("print", printAction);
196
197                 tlb.setFloatable(false);
198
199                 // Add actions (and thus buttons)
200                 tlb.add(closeAction);
201
202                 tlb.addSeparator();
203
204                 tlb.add(printAction);
205
206                 Component[] comps = tlb.getComponents();
207
208                 for (int i = 0; i < comps.length; i++)
209                         ((JComponent) comps[i]).setOpaque(false);
210
211                 return tlb;
212         }
213
214         JEditorPane createPreviewPane() {
215                 JEditorPane previewPane = new JEditorPane() {
216                         public Dimension getPreferredScrollableViewportSize() {
217                                 return getPreferredSize();
218                         }
219
220                         public void paintComponent(Graphics g) {
221                                 Graphics2D g2 = (Graphics2D) g;
222                                 Object hint = g2
223                                         .getRenderingHint(RenderingHints.KEY_ANTIALIASING);
224                                 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
225                                         RenderingHints.VALUE_ANTIALIAS_ON);
226                                 g2.setRenderingHint(RenderingHints.KEY_RENDERING,
227                                         RenderingHints.VALUE_RENDER_QUALITY);
228                                 super.paintComponent(g2);
229                                 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, hint);
230                         }
231                 };
232                 previewPane.setMargin(new Insets(3, 3, 3, 3));
233
234                 previewPane.setComponentPopupMenu(createPopupMenu());
235                 
236                 previewPane.setEditable(false);
237                 previewPane.setContentType("text/html");
238                 previewPane.addHyperlinkListener(new HyperlinkListener() {
239                         public void hyperlinkUpdate(HyperlinkEvent hyperlinkEvent) {
240                                 if (hyperlinkEvent.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
241                                         try {
242                                                 String address = hyperlinkEvent.getURL().toString();
243                                                 Util.openExternalViewer(PreviewPanel.this.metaData,
244                                                         address, "url");
245                                         } catch (IOException e) {
246                                                 e.printStackTrace();
247                                         }
248                                 }
249                         }
250                 });
251                 
252                 return previewPane;
253         }
254
255         public void setDatabase(BibtexDatabase db) {
256                 database = db;
257         }
258
259     public void setMetaData(MetaData metaData) {
260         this.metaData = metaData;
261     }
262
263     public void readLayout(String layoutFormat) throws Exception {
264                 layoutFile = layoutFormat;
265                 readLayout();
266         }
267
268         public void readLayout() throws Exception {
269                 StringReader sr = new StringReader(layoutFile.replaceAll("__NEWLINE__",
270                         "\n"));
271                 layout = new LayoutHelper(sr)
272                         .getLayoutFromText(Globals.FORMATTER_PACKAGE);
273         }
274
275     public void setLayout(Layout layout) {
276         this.layout = layout;
277     }
278
279     public void setEntry(BibtexEntry newEntry) {
280                 if (newEntry != entry) {
281                         if (entry != null)
282                                 entry.removePropertyChangeListener(this);
283                         newEntry.addPropertyChangeListener(this);
284                 }
285                 entry = newEntry;
286                 try {
287                         readLayout();
288                         update();
289                 } catch (Exception ex) {
290                         ex.printStackTrace();
291                 }
292         }
293
294         public void update() {
295
296                 StringBuffer sb = new StringBuffer();
297                 if (entry != null)
298                         sb.append(layout.doLayout(entry, database));
299                 previewPane.setText(sb.toString());
300                 previewPane.invalidate();
301                 previewPane.revalidate();
302
303                 // Scroll to top:
304                 final JScrollBar bar = scrollPane.getVerticalScrollBar();
305                 SwingUtilities.invokeLater(new Runnable() {
306                         public void run() {
307                                 bar.setValue(0);
308                         }
309                 });
310         }
311
312         public boolean hasEntry() {
313                 return (entry != null);
314         }
315
316         /**
317          * The PreviewPanel has registered itself as an event listener with the
318          * currently displayed BibtexEntry. If the entry changes, an event is
319          * received here, and we can update the preview immediately.
320          */
321         public void vetoableChange(PropertyChangeEvent evt)
322                 throws PropertyVetoException {
323                 // TODO updating here is not really necessary isn't it?
324                 // Only if we are visible.
325                 update();
326         }
327 }