fdfcced16b10e52399c1c415edd6884d34a04b6a
[debian/jabref.git] / src / java / net / sf / jabref / RightClickMenu.java
1 /*
2 Copyright (C) 2003 Morten O. Alver, Nizar N. Batada
3
4 All programs in this directory and
5 subdirectories are published under the GNU General Public License as
6 described below.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or (at
11 your option) any later version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 USA
22
23 Further information about the GNU GPL is available at:
24 http://www.gnu.org/copyleft/gpl.ja.html
25
26 */
27 package net.sf.jabref;
28
29 import java.awt.Font;
30 import java.awt.event.*;
31 import java.util.*;
32
33 import javax.swing.*;
34 import javax.swing.event.*;
35 import javax.swing.undo.AbstractUndoableEdit;
36
37 import net.sf.jabref.groups.*;
38 import net.sf.jabref.undo.NamedCompound;
39
40 public class RightClickMenu extends JPopupMenu
41     implements PopupMenuListener {
42
43     BasePanel panel;
44     MetaData metaData;
45     JMenu groupAddMenu = new JMenu(Globals.lang("Add to group")),
46         groupRemoveMenu = new JMenu(Globals.lang("Remove from group")),
47         groupMoveMenu = new JMenu("Assign exclusively to group"), // JZTODO lyrics
48         typeMenu = new JMenu(Globals.lang("Change entry type"));
49     JCheckBoxMenuItem
50         floatMarked = new JCheckBoxMenuItem(Globals.lang("Float marked entries"),
51             Globals.prefs.getBoolean("floatMarkedEntries"));
52
53     public RightClickMenu(BasePanel panel_, MetaData metaData_) {
54         panel = panel_;
55         metaData = metaData_;
56
57         // Are multiple entries selected?
58         boolean multiple = (panel.mainTable.getSelectedRowCount() > 1);
59
60         // If only one entry is selected, get a reference to it for adapting the menu.
61         BibtexEntry be = null;
62         if (panel.mainTable.getSelectedRowCount() == 1)
63           be = (BibtexEntry)panel.mainTable.getSelected().get(0);
64
65         addPopupMenuListener(this);
66
67         add(new AbstractAction(Globals.lang("Copy"), new ImageIcon(GUIGlobals.copyIconFile)) {
68                 public void actionPerformed(ActionEvent e) {
69                     try {
70                         panel.runCommand("copy");
71                     } catch (Throwable ex) {}
72                 }
73             });
74         add(new AbstractAction(Globals.lang("Paste"), new ImageIcon(GUIGlobals.pasteIconFile)) {
75                 public void actionPerformed(ActionEvent e) {
76                     try {
77                         panel.runCommand("paste");
78                     } catch (Throwable ex) {}
79                 }
80             });
81         add(new AbstractAction(Globals.lang("Cut"), new ImageIcon(GUIGlobals.cutIconFile)) {
82                 public void actionPerformed(ActionEvent e) {
83                     try {
84                         panel.runCommand("cut");
85                     } catch (Throwable ex) {}
86                 }
87             });
88
89         add(new AbstractAction(Globals.lang("Delete"), new ImageIcon(GUIGlobals.removeIconFile)) {
90                 public void actionPerformed(ActionEvent e) {
91                     /*SwingUtilities.invokeLater(new Runnable () {
92                         public void run() {*/
93                             try {
94                                 panel.runCommand("delete");
95                             } catch (Throwable ex) {}
96                         /*}
97                     }); */
98
99                 }
100             });
101             addSeparator();
102
103         add(new AbstractAction(Globals.lang("Export to clipboard")) {
104                 public void actionPerformed(ActionEvent e) {
105                     try {
106                         panel.runCommand("exportToClipboard");
107                     } catch (Throwable ex) {}
108                 }
109             });
110             addSeparator();
111
112         if (multiple) {
113           add(new AbstractAction(Globals.lang("Mark entries"), new ImageIcon(GUIGlobals.markIcon)) {
114             public void actionPerformed(ActionEvent e) {
115               try {
116                 panel.runCommand("markEntries");
117               } catch (Throwable ex) {}
118             }
119           });
120           add(new AbstractAction(Globals.lang("Unmark entries"), new ImageIcon(GUIGlobals.unmarkIcon)) {
121             public void actionPerformed(ActionEvent e) {
122               try {
123                 panel.runCommand("unmarkEntries");
124               } catch (Throwable ex) {}
125             }
126           });
127           addSeparator();
128         } else if (be != null) {
129           if (be.getField(BibtexFields.MARKED) == null)
130             add(new AbstractAction(Globals.lang("Mark entry"), new ImageIcon(GUIGlobals.markIcon)) {
131                public void actionPerformed(ActionEvent e) {
132                  try {
133                    panel.runCommand("markEntries");
134                  } catch (Throwable ex) {}
135                }
136              });
137            else
138              add(new AbstractAction(Globals.lang("Unmark entry"), new ImageIcon(GUIGlobals.unmarkIcon)) {
139                public void actionPerformed(ActionEvent e) {
140                  try {
141                    panel.runCommand("unmarkEntries");
142                  } catch (Throwable ex) {}
143                }
144              });
145            addSeparator();
146         }
147
148         add(new AbstractAction(Globals.lang("Open PDF or PS"), new ImageIcon(GUIGlobals.pdfIcon)) {
149                 public void actionPerformed(ActionEvent e) {
150                     try {
151                         panel.runCommand("openFile");
152                     } catch (Throwable ex) {}
153                 }
154             });
155
156             add(new AbstractAction(Globals.lang("Open URL or DOI"), new ImageIcon(GUIGlobals.wwwIcon)) {
157               public void actionPerformed(ActionEvent e) {
158                 try {
159                   panel.runCommand("openUrl");
160                 } catch (Throwable ex) {}
161               }
162             });
163
164         add(new AbstractAction(Globals.lang("Copy BibTeX key"), new ImageIcon(GUIGlobals.copyKeyIconFile)) {
165                 public void actionPerformed(ActionEvent e) {
166                     try {
167                         panel.runCommand("copyKey");
168                     } catch (Throwable ex) {}
169                 }
170             });
171
172         add(new AbstractAction(Globals.lang("Copy")+" \\cite{"+Globals.lang("BibTeX key")+"}", new ImageIcon(GUIGlobals.copyKeyIconFile)) {
173                 public void actionPerformed(ActionEvent e) {
174                     try {
175                         panel.runCommand("copyCiteKey");
176                     } catch (Throwable ex) {}
177                 }
178             });
179
180         addSeparator();
181         populateTypeMenu();
182
183         add(typeMenu);
184         add(new AbstractAction(Globals.lang("Plain text import"))
185         {
186                 public void actionPerformed(ActionEvent e) {
187                     try {
188                         panel.runCommand("importPlainText");
189                     } catch (Throwable ex) {}
190                 }
191             });
192         addSeparator(); // for "add/move/remove to/from group" entries (appended here)
193
194         floatMarked.addActionListener(new ActionListener() {
195             public void actionPerformed(ActionEvent e) {
196                 Globals.prefs.putBoolean("floatMarkedEntries", floatMarked.isSelected());
197                 panel.mainTable.refreshSorting(); // Bad remote access
198             }
199         });
200     }
201
202     /**
203      * Remove all types from the menu. Then cycle through all available
204      * types, and add them.
205      */
206     public void populateTypeMenu() {
207         typeMenu.removeAll();
208         for (Iterator i=BibtexEntryType.ALL_TYPES.keySet().iterator();
209              i.hasNext();) {
210             typeMenu.add(new ChangeTypeAction
211                              (BibtexEntryType.getType((String)i.next()), panel));
212         }
213     }
214
215     /**
216      * Set the dynamic contents of "Add to group ..." submenu.
217      */
218     public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
219       BibtexEntry[] bes = panel.getSelectedEntries();
220       panel.storeCurrentEdit();
221       GroupTreeNode groups = metaData.getGroups();
222       if (groups == null) {
223         groupAddMenu.setEnabled(false);
224         groupMoveMenu.setEnabled(false);
225         groupRemoveMenu.setEnabled(false);
226         return;
227       }
228
229       groupAddMenu.setEnabled(true);
230       groupMoveMenu.setEnabled(true);
231       groupRemoveMenu.setEnabled(true);
232       groupAddMenu.removeAll();
233       groupMoveMenu.removeAll();
234       groupRemoveMenu.removeAll();
235
236       if (bes == null)
237         return;
238       add(groupAddMenu);
239       add(groupMoveMenu);
240       add(groupRemoveMenu);
241
242       groupAddMenu.setEnabled(false);
243       groupMoveMenu.setEnabled(false);
244       groupRemoveMenu.setEnabled(false);
245       insertNodes(groupAddMenu,metaData.getGroups(),bes,true,false);
246       insertNodes(groupMoveMenu,metaData.getGroups(),bes,true,true);
247       insertNodes(groupRemoveMenu,metaData.getGroups(),bes,false,false);
248
249         addSeparator();
250         floatMarked.setSelected(Globals.prefs.getBoolean("floatMarkedEntries"));
251         add(floatMarked);
252     }
253
254     /**
255      * @param move For add: if true, remove from previous groups
256      */
257     public void insertNodes(JMenu menu, GroupTreeNode node, BibtexEntry[] selection,
258                     boolean add, boolean move) {
259         final AbstractAction action = getAction(node,selection,add,move);
260
261         if (node.getChildCount() == 0) {
262             JMenuItem menuItem = new JMenuItem(action);
263             setGroupFontAndIcon(menuItem, node.getGroup());
264             menu.add(menuItem);
265             if (action.isEnabled())
266                     menu.setEnabled(true);
267             return;
268         }
269
270         JMenu submenu = null;
271         if (node.getGroup() instanceof AllEntriesGroup) {
272             for (int i = 0; i < node.getChildCount(); ++i) {
273                 insertNodes(menu,(GroupTreeNode) node.getChildAt(i), selection, add, move);
274             }
275         } else {
276             submenu = new JMenu("["+node.getGroup().getName()+"]");
277             setGroupFontAndIcon(submenu, node.getGroup());
278             // setEnabled(true) is done above/below if at least one menu
279             // entry (item or submenu) is enabled
280             submenu.setEnabled(action.isEnabled());
281             JMenuItem menuItem = new JMenuItem(action);
282             setGroupFontAndIcon(menuItem, node.getGroup());
283             submenu.add(menuItem);
284             submenu.add(new Separator());
285             for (int i = 0; i < node.getChildCount(); ++i)
286                 insertNodes(submenu,(GroupTreeNode) node.getChildAt(i), selection, add, move);
287             menu.add(submenu);
288             if (submenu.isEnabled())
289                 menu.setEnabled(true);
290         }
291     }
292
293     /** Sets the font and icon to be used, depending on the group */
294     private void setGroupFontAndIcon(JMenuItem menuItem, AbstractGroup group) {
295         if (Globals.prefs.getBoolean("groupShowDynamic")) {
296                 menuItem.setFont(menuItem.getFont().deriveFont(group.isDynamic() ?
297                                 Font.ITALIC : Font.PLAIN));
298         }
299             if (Globals.prefs.getBoolean("groupShowIcons")) {
300                     switch (group.getHierarchicalContext()) {
301                     case AbstractGroup.INCLUDING:
302                             menuItem.setIcon(GUIGlobals.groupIncludingIcon);
303                             break;
304                     case AbstractGroup.REFINING:
305                             menuItem.setIcon(GUIGlobals.groupRefiningIcon);
306                             break;
307                     default:
308                             menuItem.setIcon(GUIGlobals.groupRegularIcon);
309                                 break;
310                     }
311             }
312     }
313
314     /**
315      * @param move For add: if true, remove from all previous groups
316      */
317     private AbstractAction getAction(GroupTreeNode node, BibtexEntry[] selection,
318                     boolean add, boolean move) {
319         AbstractAction action = add ? (AbstractAction) new AddToGroupAction(node, move,
320                 panel) : (AbstractAction) new RemoveFromGroupAction(node, panel);
321         AbstractGroup group = node.getGroup();
322         if (!move) {
323                 action.setEnabled(add ? group.supportsAdd() && !group.containsAll(selection)
324                         : group.supportsRemove() && group.containsAny(selection));
325         } else {
326                 action.setEnabled(group.supportsAdd());
327         }
328         return action;
329     }
330
331     public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
332       remove(groupAddMenu);
333       remove(groupMoveMenu);
334       remove(groupRemoveMenu);
335     }
336
337     public void popupMenuCanceled(PopupMenuEvent e) {
338         // nothing to do
339     }
340
341     class ChangeTypeAction extends AbstractAction {
342       BibtexEntryType type;
343       BasePanel panel;
344
345       public ChangeTypeAction(BibtexEntryType type, BasePanel bp) {
346         super(type.getName());
347         this.type = type;
348         panel = bp;
349       }
350       public void actionPerformed(ActionEvent evt) {
351         panel.changeType(type);
352       }
353     }
354 }