7f2e8a811ef4d63a21406ccc83b6905314b3e55d
[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
50     public RightClickMenu(BasePanel panel_, MetaData metaData_) {
51         panel = panel_;
52         metaData = metaData_;
53
54         // Are multiple entries selected?
55         boolean multiple = (panel.mainTable.getSelectedRowCount() > 1);
56
57         // If only one entry is selected, get a reference to it for adapting the menu.
58         BibtexEntry be = null;
59         if (panel.mainTable.getSelectedRowCount() == 1)
60           be = (BibtexEntry)panel.mainTable.getSelected().get(0);
61
62         addPopupMenuListener(this);
63
64         add(new AbstractAction(Globals.lang("Copy"), new ImageIcon(GUIGlobals.copyIconFile)) {
65                 public void actionPerformed(ActionEvent e) {
66                     try {
67                         panel.runCommand("copy");
68                     } catch (Throwable ex) {}
69                 }
70             });
71         add(new AbstractAction(Globals.lang("Paste"), new ImageIcon(GUIGlobals.pasteIconFile)) {
72                 public void actionPerformed(ActionEvent e) {
73                     try {
74                         panel.runCommand("paste");
75                     } catch (Throwable ex) {}
76                 }
77             });
78         add(new AbstractAction(Globals.lang("Cut"), new ImageIcon(GUIGlobals.cutIconFile)) {
79                 public void actionPerformed(ActionEvent e) {
80                     try {
81                         panel.runCommand("cut");
82                     } catch (Throwable ex) {}
83                 }
84             });
85
86         add(new AbstractAction(Globals.lang("Delete"), new ImageIcon(GUIGlobals.removeIconFile)) {
87                 public void actionPerformed(ActionEvent e) {
88                     /*SwingUtilities.invokeLater(new Runnable () {
89                         public void run() {*/
90                             try {
91                                 panel.runCommand("delete");
92                             } catch (Throwable ex) {}
93                         /*}
94                     }); */
95
96                 }
97             });
98             addSeparator();
99
100         add(new AbstractAction(Globals.lang("Export to clipboard")) {
101                 public void actionPerformed(ActionEvent e) {
102                     try {
103                         panel.runCommand("exportToClipboard");
104                     } catch (Throwable ex) {}
105                 }
106             });
107             addSeparator();
108
109         if (multiple) {
110           add(new AbstractAction(Globals.lang("Mark entries"), new ImageIcon(GUIGlobals.markIcon)) {
111             public void actionPerformed(ActionEvent e) {
112               try {
113                 panel.runCommand("markEntries");
114               } catch (Throwable ex) {}
115             }
116           });
117           add(new AbstractAction(Globals.lang("Unmark entries"), new ImageIcon(GUIGlobals.unmarkIcon)) {
118             public void actionPerformed(ActionEvent e) {
119               try {
120                 panel.runCommand("unmarkEntries");
121               } catch (Throwable ex) {}
122             }
123           });
124           addSeparator();
125         } else if (be != null) {
126           if (be.getField(BibtexFields.MARKED) == null)
127             add(new AbstractAction(Globals.lang("Mark entry"), new ImageIcon(GUIGlobals.markIcon)) {
128                public void actionPerformed(ActionEvent e) {
129                  try {
130                    panel.runCommand("markEntries");
131                  } catch (Throwable ex) {}
132                }
133              });
134            else
135              add(new AbstractAction(Globals.lang("Unmark entry"), new ImageIcon(GUIGlobals.unmarkIcon)) {
136                public void actionPerformed(ActionEvent e) {
137                  try {
138                    panel.runCommand("unmarkEntries");
139                  } catch (Throwable ex) {}
140                }
141              });
142            addSeparator();
143         }
144
145         add(new AbstractAction(Globals.lang("Open PDF or PS"), new ImageIcon(GUIGlobals.pdfIcon)) {
146                 public void actionPerformed(ActionEvent e) {
147                     try {
148                         panel.runCommand("openFile");
149                     } catch (Throwable ex) {}
150                 }
151             });
152
153             add(new AbstractAction(Globals.lang("Open URL or DOI"), new ImageIcon(GUIGlobals.wwwIcon)) {
154               public void actionPerformed(ActionEvent e) {
155                 try {
156                   panel.runCommand("openUrl");
157                 } catch (Throwable ex) {}
158               }
159             });
160
161         add(new AbstractAction(Globals.lang("Copy BibTeX key"), new ImageIcon(GUIGlobals.copyKeyIconFile)) {
162                 public void actionPerformed(ActionEvent e) {
163                     try {
164                         panel.runCommand("copyKey");
165                     } catch (Throwable ex) {}
166                 }
167             });
168
169         add(new AbstractAction(Globals.lang("Copy")+" \\cite{"+Globals.lang("BibTeX key")+"}", new ImageIcon(GUIGlobals.copyKeyIconFile)) {
170                 public void actionPerformed(ActionEvent e) {
171                     try {
172                         panel.runCommand("copyCiteKey");
173                     } catch (Throwable ex) {}
174                 }
175             });
176
177         addSeparator();
178         populateTypeMenu();
179
180         add(typeMenu);
181         add(new AbstractAction(Globals.lang("Plain text import"))
182         {
183                 public void actionPerformed(ActionEvent e) {
184                     try {
185                         panel.runCommand("importPlainText");
186                     } catch (Throwable ex) {}
187                 }
188             });
189         addSeparator(); // for "add/move/remove to/from group" entries (appended here)
190     }
191
192     /**
193      * Remove all types from the menu. Then cycle through all available
194      * types, and add them.
195      */
196     public void populateTypeMenu() {
197         typeMenu.removeAll();
198         for (Iterator i=BibtexEntryType.ALL_TYPES.keySet().iterator();
199              i.hasNext();) {
200             typeMenu.add(new ChangeTypeAction
201                              (BibtexEntryType.getType((String)i.next()), panel));
202         }
203     }
204
205     /**
206      * Set the dynamic contents of "Add to group ..." submenu.
207      */
208     public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
209       BibtexEntry[] bes = panel.getSelectedEntries();
210       panel.storeCurrentEdit();
211       GroupTreeNode groups = metaData.getGroups();
212       if (groups == null) {
213         groupAddMenu.setEnabled(false);
214         groupMoveMenu.setEnabled(false);
215         groupRemoveMenu.setEnabled(false);
216         return;
217       }
218
219       groupAddMenu.setEnabled(true);
220       groupMoveMenu.setEnabled(true);
221       groupRemoveMenu.setEnabled(true);
222       groupAddMenu.removeAll();
223       groupMoveMenu.removeAll();
224       groupRemoveMenu.removeAll();
225
226       if (bes == null)
227         return;
228       add(groupAddMenu);
229       add(groupMoveMenu);
230       add(groupRemoveMenu);
231
232       groupAddMenu.setEnabled(false);
233       groupMoveMenu.setEnabled(false);
234       groupRemoveMenu.setEnabled(false);
235       insertNodes(groupAddMenu,metaData.getGroups(),bes,true,false);
236       insertNodes(groupMoveMenu,metaData.getGroups(),bes,true,true);
237       insertNodes(groupRemoveMenu,metaData.getGroups(),bes,false,false);
238     }
239
240     /**
241      * @param move For add: if true, remove from previous groups
242      */
243     public void insertNodes(JMenu menu, GroupTreeNode node, BibtexEntry[] selection,
244                     boolean add, boolean move) {
245         final AbstractAction action = getAction(node,selection,add,move);
246
247         if (node.getChildCount() == 0) {
248             JMenuItem menuItem = new JMenuItem(action);
249             setGroupFontAndIcon(menuItem, node.getGroup());
250             menu.add(menuItem);
251             if (action.isEnabled())
252                     menu.setEnabled(true);
253             return;
254         }
255
256         JMenu submenu = null;
257         if (node.getGroup() instanceof AllEntriesGroup) {
258             for (int i = 0; i < node.getChildCount(); ++i) {
259                 insertNodes(menu,(GroupTreeNode) node.getChildAt(i), selection, add, move);
260             }
261         } else {
262             submenu = new JMenu("["+node.getGroup().getName()+"]");
263             setGroupFontAndIcon(submenu, node.getGroup());
264             // setEnabled(true) is done above/below if at least one menu
265             // entry (item or submenu) is enabled
266             submenu.setEnabled(action.isEnabled());
267             JMenuItem menuItem = new JMenuItem(action);
268             setGroupFontAndIcon(menuItem, node.getGroup());
269             submenu.add(menuItem);
270             submenu.add(new Separator());
271             for (int i = 0; i < node.getChildCount(); ++i)
272                 insertNodes(submenu,(GroupTreeNode) node.getChildAt(i), selection, add, move);
273             menu.add(submenu);
274             if (submenu.isEnabled())
275                 menu.setEnabled(true);
276         }
277     }
278
279     /** Sets the font and icon to be used, depending on the group */
280     private void setGroupFontAndIcon(JMenuItem menuItem, AbstractGroup group) {
281         if (Globals.prefs.getBoolean("groupShowDynamic")) {
282                 menuItem.setFont(menuItem.getFont().deriveFont(group.isDynamic() ?
283                                 Font.ITALIC : Font.PLAIN));
284         }
285             if (Globals.prefs.getBoolean("groupShowIcons")) {
286                     switch (group.getHierarchicalContext()) {
287                     case AbstractGroup.INCLUDING:
288                             menuItem.setIcon(GUIGlobals.groupIncludingIcon);
289                             break;
290                     case AbstractGroup.REFINING:
291                             menuItem.setIcon(GUIGlobals.groupRefiningIcon);
292                             break;
293                     default:
294                             menuItem.setIcon(GUIGlobals.groupRegularIcon);
295                                 break;
296                     }
297             }
298     }
299
300     /**
301      * @param move For add: if true, remove from all previous groups
302      */
303     private AbstractAction getAction(GroupTreeNode node, BibtexEntry[] selection,
304                     boolean add, boolean move) {
305         AbstractAction action = add ? (AbstractAction) new AddToGroupAction(node, move,
306                 panel) : (AbstractAction) new RemoveFromGroupAction(node, panel);
307         AbstractGroup group = node.getGroup();
308         if (!move) {
309                 action.setEnabled(add ? group.supportsAdd() && !group.containsAll(selection)
310                         : group.supportsRemove() && group.containsAny(selection));
311         } else {
312                 action.setEnabled(group.supportsAdd());
313         }
314         return action;
315     }
316
317     public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
318       remove(groupAddMenu);
319       remove(groupMoveMenu);
320       remove(groupRemoveMenu);
321     }
322
323     public void popupMenuCanceled(PopupMenuEvent e) {
324         // nothing to do
325     }
326
327     class ChangeTypeAction extends AbstractAction {
328       BibtexEntryType type;
329       BasePanel panel;
330
331       public ChangeTypeAction(BibtexEntryType type, BasePanel bp) {
332         super(type.getName());
333         this.type = type;
334         panel = bp;
335       }
336       public void actionPerformed(ActionEvent evt) {
337         panel.changeType(type);
338       }
339     }
340 }