/* Copyright (C) 2003-2011 JabRef contributors. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package net.sf.jabref; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import net.sf.jabref.groups.*; import net.sf.jabref.specialfields.Priority; import net.sf.jabref.specialfields.Quality; import net.sf.jabref.specialfields.Rank; import net.sf.jabref.specialfields.Relevance; import net.sf.jabref.specialfields.SpecialField; import net.sf.jabref.specialfields.SpecialFieldValue; import net.sf.jabref.specialfields.SpecialFieldsUtils; public class RightClickMenu extends JPopupMenu implements PopupMenuListener { BasePanel panel; MetaData metaData; JMenu groupAddMenu = new JMenu(Globals.lang("Add to group")), groupRemoveMenu = new JMenu(Globals.lang("Remove from group")), groupMoveMenu = new JMenu(Globals.lang("Assign exclusively to group")), // JZTODO lyrics rankingMenu = new JMenu(), priorityMenu = new JMenu(), typeMenu = new JMenu(Globals.lang("Change entry type")); JCheckBoxMenuItem floatMarked = new JCheckBoxMenuItem(Globals.lang("Float marked entries"), Globals.prefs.getBoolean("floatMarkedEntries")); public RightClickMenu(BasePanel panel_, MetaData metaData_) { panel = panel_; metaData = metaData_; // Are multiple entries selected? boolean multiple = (panel.mainTable.getSelectedRowCount() > 1); // If only one entry is selected, get a reference to it for adapting the menu. BibtexEntry be = null; if (panel.mainTable.getSelectedRowCount() == 1) be = panel.mainTable.getSelected().get(0); addPopupMenuListener(this); add(new AbstractAction(Globals.lang("Copy"), GUIGlobals.getImage("copy")) { public void actionPerformed(ActionEvent e) { try { panel.runCommand("copy"); } catch (Throwable ex) {} } }); add(new AbstractAction(Globals.lang("Paste"), GUIGlobals.getImage("paste")) { public void actionPerformed(ActionEvent e) { try { panel.runCommand("paste"); } catch (Throwable ex) {} } }); add(new AbstractAction(Globals.lang("Cut"), GUIGlobals.getImage("cut")) { public void actionPerformed(ActionEvent e) { try { panel.runCommand("cut"); } catch (Throwable ex) {} } }); add(new AbstractAction(Globals.lang("Delete"), GUIGlobals.getImage("delete")) { public void actionPerformed(ActionEvent e) { /*SwingUtilities.invokeLater(new Runnable () { public void run() {*/ try { panel.runCommand("delete"); } catch (Throwable ex) {} /*} }); */ } }); addSeparator(); add(new AbstractAction(Globals.lang("Export to clipboard")) { public void actionPerformed(ActionEvent e) { try { panel.runCommand("exportToClipboard"); } catch (Throwable ex) {} } }); add(new AbstractAction(Globals.lang("Send as email")) { public void actionPerformed(ActionEvent e) { try { panel.runCommand("sendAsEmail"); } catch (Throwable ex) {} } }); addSeparator(); JMenu markSpecific = JabRefFrame.subMenu("Mark specific color"); JabRefFrame frame = panel.frame; for (int i=0; i<Util.MAX_MARKING_LEVEL; i++) markSpecific.add(new MarkEntriesAction(frame, i).getMenuItem()); if (multiple) { add(new AbstractAction(Globals.lang("Mark entries"), GUIGlobals.getImage("markEntries")) { public void actionPerformed(ActionEvent e) { try { panel.runCommand("markEntries"); } catch (Throwable ex) {} } }); add(markSpecific); add(new AbstractAction(Globals.lang("Unmark entries"), GUIGlobals.getImage("unmarkEntries")) { public void actionPerformed(ActionEvent e) { try { panel.runCommand("unmarkEntries"); } catch (Throwable ex) {} } }); addSeparator(); } else if (be != null) { if (be.getField(BibtexFields.MARKED) == null) { add(new AbstractAction(Globals.lang("Mark entry"), GUIGlobals.getImage("markEntries")) { public void actionPerformed(ActionEvent e) { try { panel.runCommand("markEntries"); } catch (Throwable ex) {} } }); add(markSpecific); } else { add(markSpecific); add(new AbstractAction(Globals.lang("Unmark entry"), GUIGlobals.getImage("unmarkEntries")) { public void actionPerformed(ActionEvent e) { try { panel.runCommand("unmarkEntries"); } catch (Throwable ex) {} } }); } addSeparator(); } if (Globals.prefs.getBoolean(SpecialFieldsUtils.PREF_SPECIALFIELDSENABLED)) { if (Globals.prefs.getBoolean(SpecialFieldsUtils.PREF_SHOWCOLUMN_RANKING)) { populateSpecialFieldMenu(this.rankingMenu, Rank.getInstance(), panel.frame); add(this.rankingMenu); } // TODO: multiple handling for relevance and quality-assurance // if multiple values are selected ("if (multiple)"), two options (set / clear) should be offered // if one value is selected either set or clear should be offered if (Globals.prefs.getBoolean(SpecialFieldsUtils.PREF_SHOWCOLUMN_RELEVANCE)) { add(Relevance.getInstance().getValues().get(0).getMenuAction(panel.frame)); } if (Globals.prefs.getBoolean(SpecialFieldsUtils.PREF_SHOWCOLUMN_QUALITY)) { add(Quality.getInstance().getValues().get(0).getMenuAction(panel.frame)); } if (Globals.prefs.getBoolean(SpecialFieldsUtils.PREF_SHOWCOLUMN_PRIORITY)) { populateSpecialFieldMenu(this.priorityMenu, Priority.getInstance(), panel.frame); add(this.priorityMenu); } addSeparator(); } add(new AbstractAction(Globals.lang("Open file"), GUIGlobals.getImage("openExternalFile")) { public void actionPerformed(ActionEvent e) { try { panel.runCommand("openExternalFile"); } catch (Throwable ex) {} } }); add(new AbstractAction(Globals.lang("Attach file"), GUIGlobals.getImage("open")) { public void actionPerformed(ActionEvent e) { try { panel.runCommand("addFileLink"); } catch (Throwable ex) {} } }); /*add(new AbstractAction(Globals.lang("Open PDF or PS"), GUIGlobals.getImage("openFile")) { public void actionPerformed(ActionEvent e) { try { panel.runCommand("openFile"); } catch (Throwable ex) {} } });*/ add(new AbstractAction(Globals.lang("Open URL or DOI"), GUIGlobals.getImage("www")) { public void actionPerformed(ActionEvent e) { try { panel.runCommand("openUrl"); } catch (Throwable ex) {} } }); add(new AbstractAction(Globals.lang("Copy BibTeX key")) { public void actionPerformed(ActionEvent e) { try { panel.runCommand("copyKey"); } catch (Throwable ex) {} } }); add(new AbstractAction(Globals.lang("Copy")+" \\cite{"+Globals.lang("BibTeX key")+"}") { public void actionPerformed(ActionEvent e) { try { panel.runCommand("copyCiteKey"); } catch (Throwable ex) {} } }); addSeparator(); populateTypeMenu(); add(typeMenu); add(new AbstractAction(Globals.lang("Plain text import")) { public void actionPerformed(ActionEvent e) { try { panel.runCommand("importPlainText"); } catch (Throwable ex) {} } }); add(JabRef.jrf.massSetField); add(JabRef.jrf.manageKeywords); addSeparator(); // for "add/move/remove to/from group" entries (appended here) floatMarked.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Globals.prefs.putBoolean("floatMarkedEntries", floatMarked.isSelected()); panel.mainTable.refreshSorting(); // Bad remote access } }); } /** * Remove all types from the menu. Then cycle through all available * types, and add them. */ public void populateTypeMenu() { typeMenu.removeAll(); for (String key : BibtexEntryType.ALL_TYPES.keySet()){ typeMenu.add(new ChangeTypeAction (BibtexEntryType.getType(key), panel)); } } /** * Remove all types from the menu. * Then cycle through all available values, and add them. */ public static void populateSpecialFieldMenu(JMenu menu, SpecialField field, JabRefFrame frame) { //menu.removeAll(); menu.setText(field.getMenuString()); menu.setIcon(field.getRepresentingIcon()); for (SpecialFieldValue val: field.getValues()) { menu.add(val.getMenuAction(frame)); } } /** * Set the dynamic contents of "Add to group ..." submenu. */ public void popupMenuWillBecomeVisible(PopupMenuEvent e) { BibtexEntry[] bes = panel.getSelectedEntries(); panel.storeCurrentEdit(); GroupTreeNode groups = metaData.getGroups(); if (groups == null) { groupAddMenu.setEnabled(false); groupMoveMenu.setEnabled(false); groupRemoveMenu.setEnabled(false); return; } groupAddMenu.setEnabled(true); groupMoveMenu.setEnabled(true); groupRemoveMenu.setEnabled(true); groupAddMenu.removeAll(); groupMoveMenu.removeAll(); groupRemoveMenu.removeAll(); if (bes == null) return; add(groupAddMenu); add(groupMoveMenu); add(groupRemoveMenu); groupAddMenu.setEnabled(false); groupMoveMenu.setEnabled(false); groupRemoveMenu.setEnabled(false); insertNodes(groupAddMenu,metaData.getGroups(),bes,true,false); insertNodes(groupMoveMenu,metaData.getGroups(),bes,true,true); insertNodes(groupRemoveMenu,metaData.getGroups(),bes,false,false); addSeparator(); floatMarked.setSelected(Globals.prefs.getBoolean("floatMarkedEntries")); add(floatMarked); } /** * @param move For add: if true, remove from previous groups */ public void insertNodes(JMenu menu, GroupTreeNode node, BibtexEntry[] selection, boolean add, boolean move) { final AbstractAction action = getAction(node,selection,add,move); if (node.getChildCount() == 0) { JMenuItem menuItem = new JMenuItem(action); setGroupFontAndIcon(menuItem, node.getGroup()); menu.add(menuItem); if (action.isEnabled()) menu.setEnabled(true); return; } JMenu submenu = null; if (node.getGroup() instanceof AllEntriesGroup) { for (int i = 0; i < node.getChildCount(); ++i) { insertNodes(menu,(GroupTreeNode) node.getChildAt(i), selection, add, move); } } else { submenu = new JMenu("["+node.getGroup().getName()+"]"); setGroupFontAndIcon(submenu, node.getGroup()); // setEnabled(true) is done above/below if at least one menu // entry (item or submenu) is enabled submenu.setEnabled(action.isEnabled()); JMenuItem menuItem = new JMenuItem(action); setGroupFontAndIcon(menuItem, node.getGroup()); submenu.add(menuItem); submenu.add(new Separator()); for (int i = 0; i < node.getChildCount(); ++i) insertNodes(submenu,(GroupTreeNode) node.getChildAt(i), selection, add, move); menu.add(submenu); if (submenu.isEnabled()) menu.setEnabled(true); } } /** Sets the font and icon to be used, depending on the group */ private void setGroupFontAndIcon(JMenuItem menuItem, AbstractGroup group) { if (Globals.prefs.getBoolean("groupShowDynamic")) { menuItem.setFont(menuItem.getFont().deriveFont(group.isDynamic() ? Font.ITALIC : Font.PLAIN)); } if (Globals.prefs.getBoolean("groupShowIcons")) { switch (group.getHierarchicalContext()) { case AbstractGroup.INCLUDING: menuItem.setIcon(GUIGlobals.getImage("groupIncluding")); break; case AbstractGroup.REFINING: menuItem.setIcon(GUIGlobals.getImage("groupRefining")); break; default: menuItem.setIcon(GUIGlobals.getImage("groupRegular")); break; } } } /** * @param move For add: if true, remove from all previous groups */ private AbstractAction getAction(GroupTreeNode node, BibtexEntry[] selection, boolean add, boolean move) { AbstractAction action = add ? (AbstractAction) new AddToGroupAction(node, move, panel) : (AbstractAction) new RemoveFromGroupAction(node, panel); AbstractGroup group = node.getGroup(); if (!move) { action.setEnabled(add ? group.supportsAdd() && !group.containsAll(selection) : group.supportsRemove() && group.containsAny(selection)); } else { action.setEnabled(group.supportsAdd()); } return action; } public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { remove(groupAddMenu); remove(groupMoveMenu); remove(groupRemoveMenu); } public void popupMenuCanceled(PopupMenuEvent e) { // nothing to do } class ChangeTypeAction extends AbstractAction { BibtexEntryType type; BasePanel panel; public ChangeTypeAction(BibtexEntryType type, BasePanel bp) { super(type.getName()); this.type = type; panel = bp; } public void actionPerformed(ActionEvent evt) { panel.changeType(type); } } }