package net.sf.jabref;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.print.PrinterException;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.io.IOException;
import java.io.StringReader;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.JobName;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import net.sf.jabref.export.layout.Layout;
import net.sf.jabref.export.layout.LayoutHelper;
import net.sf.jabref.export.ExportFormats;
/**
* Displays an BibtexEntry using the given layout format.
*
* @author $Author: mortenalver $
* @version $Revision: 3152 $ ($Date: 2007-08-01 20:23:38 +0200 (Mi, 01 Aug
* 2007) $)
*
*/
public class PreviewPanel extends JPanel implements VetoableChangeListener {
/**
* The bibtex entry currently shown
*/
BibtexEntry entry;
MetaData metaData;
/**
* If a database is set, the preview will attempt to resolve strings in the
* previewed entry using that database.
*/
BibtexDatabase database;
Layout layout;
String layoutFile;
public JEditorPane previewPane;
JScrollPane scrollPane;
BasePanel panel;
/**
*
* @param database
* (may be null) Optionally used to resolve strings.
* @param entry
* (may be null) If given this entry is shown otherwise you have
* to call setEntry to make something visible.
* @param panel
* (may be null) If not given no toolbar is shown on the right
* hand side.
* @param metaData
* (must be given) Used for resolving pdf directories for links.
* @param layoutFile
* (must be given) Used for layout
*/
public PreviewPanel(BibtexDatabase database, BibtexEntry entry,
BasePanel panel, MetaData metaData, String layoutFile) {
this(panel, metaData, layoutFile);
this.database = database;
setEntry(entry);
}
/**
*
* @param panel
* (may be null) If not given no toolbar is shown on the right
* hand side.
* @param metaData
* (must be given) Used for resolving pdf directories for links.
* @param layoutFile
* (must be given) Used for layout
*/
public PreviewPanel(BasePanel panel, MetaData metaData, String layoutFile) {
super(new BorderLayout(), true);
this.panel = panel;
this.metaData = metaData;
this.layoutFile = layoutFile;
this.previewPane = createPreviewPane();
// Set up scroll pane for preview pane
scrollPane = new JScrollPane(previewPane,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setBorder(null);
/*
* If we have been given a panel and the preference option
* previewPrintButton is set, show the tool bar
*/
if (panel != null
&& JabRefPreferences.getInstance().getBoolean("previewPrintButton")) {
add(createToolBar(), BorderLayout.LINE_START);
}
add(scrollPane, BorderLayout.CENTER);
}
class PrintAction extends AbstractAction {
public PrintAction() {
super(Globals.lang("Print Preview"), GUIGlobals.getImage("psSmall"));
putValue(SHORT_DESCRIPTION, Globals.lang("Print Preview"));
}
//DocumentPrinter printerService;
public void actionPerformed(ActionEvent arg0) {
// Background this, as it takes a while.
new Thread() {
public void run() {
try {
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
pras.add(new JobName(entry.getCiteKey(), null));
previewPane.print(null, null, true, null, pras, false);
} catch (PrinterException e) {
// Inform the user... we don't know what to do.
JOptionPane.showMessageDialog(PreviewPanel.this,
Globals.lang("Could not print preview") + ".\n"
+ e.getMessage(), Globals
.lang("Printing Entry Preview"),
JOptionPane.ERROR_MESSAGE);
}
}
}.start();
}
}
Action printAction;
public Action getPrintAction() {
if (printAction == null)
printAction = new PrintAction();
return printAction;
}
class CloseAction extends AbstractAction {
public CloseAction() {
super(Globals.lang("Close window"), GUIGlobals.getImage("close"));
putValue(SHORT_DESCRIPTION, Globals.lang("Close window"));
}
public void actionPerformed(ActionEvent e) {
panel.hideBottomComponent();
}
}
Action closeAction;
public Action getCloseAction() {
if (closeAction == null)
closeAction = new CloseAction();
return closeAction;
}
JPopupMenu createPopupMenu() {
JPopupMenu menu = new JPopupMenu();
menu.add(getPrintAction());
return menu;
}
JToolBar createToolBar() {
JToolBar tlb = new JToolBar(JToolBar.VERTICAL);
JabRefPreferences prefs = JabRefPreferences.getInstance();
Action printAction = getPrintAction();
Action closeAction = getCloseAction();
tlb.setMargin(new Insets(0, 0, 0, 2));
// The toolbar carries all the key bindings that are valid for the whole
// window.
ActionMap am = tlb.getActionMap();
InputMap im = tlb.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(prefs.getKey("Close entry preview"), "close");
am.put("close", closeAction);
im.put(prefs.getKey("Print entry preview"), "print");
am.put("print", printAction);
tlb.setFloatable(false);
// Add actions (and thus buttons)
tlb.add(closeAction);
tlb.addSeparator();
tlb.add(printAction);
Component[] comps = tlb.getComponents();
for (int i = 0; i < comps.length; i++)
((JComponent) comps[i]).setOpaque(false);
return tlb;
}
JEditorPane createPreviewPane() {
JEditorPane previewPane = new JEditorPane() {
public Dimension getPreferredScrollableViewportSize() {
return getPreferredSize();
}
};
previewPane.setMargin(new Insets(3, 3, 3, 3));
previewPane.setComponentPopupMenu(createPopupMenu());
previewPane.setEditable(false);
previewPane.setContentType("text/html");
previewPane.addHyperlinkListener(new HyperlinkListener() {
public void hyperlinkUpdate(HyperlinkEvent hyperlinkEvent) {
if (hyperlinkEvent.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
try {
String address = hyperlinkEvent.getURL().toString();
Util.openExternalViewer(PreviewPanel.this.metaData,
address, "url");
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
return previewPane;
}
public void setDatabase(BibtexDatabase db) {
database = db;
}
public void setMetaData(MetaData metaData) {
this.metaData = metaData;
}
public void readLayout(String layoutFormat) throws Exception {
layoutFile = layoutFormat;
readLayout();
}
public void readLayout() throws Exception {
StringReader sr = new StringReader(layoutFile.replaceAll("__NEWLINE__",
"\n"));
layout = new LayoutHelper(sr)
.getLayoutFromText(Globals.FORMATTER_PACKAGE);
}
public void setLayout(Layout layout) {
this.layout = layout;
}
public void setEntry(BibtexEntry newEntry) {
if (newEntry != entry) {
if (entry != null)
entry.removePropertyChangeListener(this);
newEntry.addPropertyChangeListener(this);
}
entry = newEntry;
try {
readLayout();
update();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void update() {
StringBuffer sb = new StringBuffer();
ExportFormats.entryNumber = 1; // Set entry number in case that is included in the preview layout.
if (entry != null)
sb.append(layout.doLayout(entry, database));
previewPane.setText(sb.toString());
previewPane.invalidate();
previewPane.revalidate();
// Scroll to top:
final JScrollBar bar = scrollPane.getVerticalScrollBar();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
bar.setValue(0);
}
});
}
public boolean hasEntry() {
return (entry != null);
}
/**
* The PreviewPanel has registered itself as an event listener with the
* currently displayed BibtexEntry. If the entry changes, an event is
* received here, and we can update the preview immediately.
*/
public void vetoableChange(PropertyChangeEvent evt)
throws PropertyVetoException {
// TODO updating here is not really necessary isn't it?
// Only if we are visible.
update();
}
}