3b92c8d3e9c0ceb2051d214f722931327579b2bb
[debian/jabref.git] / src / java / net / sf / jabref / external / PushToApplicationButton.java
1 package net.sf.jabref.external;
2
3 import com.jgoodies.forms.builder.ButtonBarBuilder;
4 import net.sf.jabref.GUIGlobals;
5 import net.sf.jabref.Globals;
6 import net.sf.jabref.JabRefFrame;
7 import net.sf.jabref.MnemonicAwareAction;
8 import net.sf.jabref.plugin.PluginCore;
9 import net.sf.jabref.plugin.core.JabRefPlugin;
10 import net.sf.jabref.plugin.core.generated._JabRefPlugin;
11
12 import javax.swing.*;
13 import java.awt.*;
14 import java.awt.event.ActionEvent;
15 import java.awt.event.ActionListener;
16 import java.awt.event.MouseAdapter;
17 import java.awt.event.MouseEvent;
18 import java.net.URL;
19 import java.util.ArrayList;
20 import java.util.Comparator;
21 import java.util.HashMap;
22 import java.util.List;
23
24 /**
25  * Customized UI component for pushing to external applications. Has a selection popup
26  * menu to change the selected external application.
27  * This class implements the ActionListener interface. When actionPerformed() is
28  * invoked, the currently selected PushToApplication is activated. The actionPerformed()
29  * method can be called with a null argument.
30  */
31 public class PushToApplicationButton implements ActionListener {
32
33     public static List<PushToApplication> applications;
34
35     private JabRefFrame frame;
36     private List<PushToApplication> pushActions;
37     private JPanel comp;
38     private JButton pushButton, menuButton;
39     private int selected = 0;
40     private JPopupMenu popup = null;
41     private HashMap<PushToApplication, PushToApplicationAction> actions = new HashMap<PushToApplication, PushToApplicationAction>();
42     private final Dimension buttonDim = new Dimension(23, 23);
43     private static final URL ARROW_ICON = GUIGlobals.class.getResource("/images/secondary_sorted_reverse.png");
44     private MenuAction mAction = new MenuAction();
45     private JPopupMenu optPopup = new JPopupMenu();
46     private JMenuItem settings = new JMenuItem(Globals.lang("Settings"));
47     private boolean settingsOkPressed = false;
48
49     /**
50      * Set up the current available choices:
51      */
52     static {
53
54         applications = new ArrayList<PushToApplication>();
55
56         JabRefPlugin jabrefPlugin = JabRefPlugin.getInstance(PluginCore.getManager());
57         List<_JabRefPlugin.PushToApplicationExtension> plugins = jabrefPlugin.getPushToApplicationExtensions();
58         for (_JabRefPlugin.PushToApplicationExtension extension : plugins) {
59             applications.add(extension.getPushToApp());
60         }
61
62         applications.add(new PushToLyx());
63         applications.add(new PushToEmacs());
64         applications.add(new PushToWinEdt());
65         applications.add(new PushToLatexEditor());
66         applications.add(new PushToVim());
67
68         // Finally, sort the entries:
69         //Collections.sort(applications, new PushToApplicationComparator());
70     }
71
72
73     public PushToApplicationButton(JabRefFrame frame, List<PushToApplication> pushActions) {
74         this.frame = frame;
75         this.pushActions = pushActions;
76         init();
77     }
78
79     private void init() {
80         comp = new JPanel();
81         comp.setLayout(new BorderLayout());
82
83         menuButton = new JButton(new ImageIcon(ARROW_ICON));
84         menuButton.setMargin(new Insets(0,0,0,0));
85         menuButton.setPreferredSize(new Dimension(menuButton.getIcon().getIconWidth(),
86                 menuButton.getIcon().getIconHeight()));
87         menuButton.addActionListener(new MenuButtonActionListener());
88         menuButton.setToolTipText(Globals.lang("Select external application"));
89         pushButton = new JButton();
90         if (Globals.prefs.hasKey("pushToApplication")) {
91             String appSelected = Globals.prefs.get("pushToApplication");
92             for (int i=0; i<pushActions.size(); i++) {
93                 PushToApplication toApp = pushActions.get(i);
94                 if (toApp.getName().equals(appSelected)) {
95                     selected = i;
96                     break;
97                 }
98             }
99         }
100
101         setSelected(selected);
102         pushButton.addActionListener(this);
103         pushButton.addMouseListener(new PushButtonMouseListener());
104
105         comp.add(pushButton, BorderLayout.CENTER);
106         comp.add(menuButton, BorderLayout.EAST);
107         comp.setBorder(BorderFactory.createLineBorder(Color.gray));
108         comp.setMaximumSize(comp.getPreferredSize());
109
110         optPopup.add(settings);
111         settings.addActionListener(new ActionListener() {
112             public void actionPerformed(ActionEvent event) {
113                 PushToApplication toApp = pushActions.get(selected);
114                 JPanel options = toApp.getSettingsPanel();
115                 if (options != null) {
116                     showSettingsDialog(toApp, options);
117                 }
118
119             }
120         });
121     }
122
123     /**
124      * Create a selection menu for the available "Push" options.
125      */
126     private void buildPopupMenu() {
127         popup = new JPopupMenu();
128         int j=0;
129         for (PushToApplication application : pushActions){
130             JMenuItem item = new JMenuItem(application.getApplicationName(),
131                     application.getIcon());
132             item.addActionListener(new PopupItemActionListener(j));
133             popup.add(item);
134             j++;
135         }
136     }
137
138     /**
139      * Update the PushButton to default to the given application.
140      * @param i The List index of the application to default to.
141      */
142     private void setSelected(int i) {
143         this.selected = i;
144         PushToApplication toApp = pushActions.get(i);
145         pushButton.setIcon(toApp.getIcon());
146         pushButton.setToolTipText(toApp.getTooltip());
147         pushButton.setPreferredSize(buttonDim);
148         Globals.prefs.put("pushToApplication", toApp.getName());
149         mAction.setTitle(toApp.getApplicationName());
150     }
151
152     /**
153      * Get the toolbar component for the push button.
154      * @return The component.
155      */
156     public Component getComponent() {
157         return comp;
158     }
159
160     public Action getMenuAction() {
161         return mAction;
162     }
163
164     public void actionPerformed(ActionEvent e) {
165         PushToApplication toApp = pushActions.get(selected);
166
167         // Lazy initialization of the push action:
168         PushToApplicationAction action = actions.get(toApp);
169         if (action == null) {
170             action = new PushToApplicationAction(frame, toApp);
171             actions.put(toApp, action);
172         }
173         action.actionPerformed(new ActionEvent(toApp, 0, "push"));
174     }
175
176     private void showSettingsDialog(PushToApplication toApp, JPanel options) {
177         final JDialog diag = new JDialog(frame, Globals.lang("Settings"), true);
178         options.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
179         diag.getContentPane().add(options, BorderLayout.CENTER);
180         ButtonBarBuilder bb = new ButtonBarBuilder();
181         JButton ok = new JButton(Globals.lang("Ok"));
182         JButton cancel = new JButton(Globals.lang("Cancel"));
183         bb.addGlue();
184         bb.addGridded(ok);
185         bb.addGridded(cancel);
186         bb.addGlue();
187         bb.getPanel().setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
188         diag.getContentPane().add(bb.getPanel(), BorderLayout.SOUTH);
189         ok.addActionListener(new ActionListener() {
190             public void actionPerformed(ActionEvent event) {
191                 settingsOkPressed = true;
192                 diag.dispose();
193             }
194         });
195         cancel.addActionListener(new ActionListener() {
196             public void actionPerformed(ActionEvent event) {
197                 diag.dispose();
198             }
199         });
200         // Key bindings:
201         ActionMap am = bb.getPanel().getActionMap();
202         InputMap im = bb.getPanel().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
203         im.put(Globals.prefs.getKey("Close dialog"), "close");
204         am.put("close", new AbstractAction() {
205             public void actionPerformed(ActionEvent e) {
206                 diag.dispose();
207             }
208         });
209         settingsOkPressed = false;
210         diag.pack();
211         diag.setLocationRelativeTo(frame);
212         // Show the dialog:
213         diag.setVisible(true);
214         // If the user pressed Ok, ask the PushToApplication implementation
215         // to store its settings:
216         if (settingsOkPressed) {
217             toApp.storeSettings();
218         }
219     }
220
221     class PopupItemActionListener implements ActionListener {
222         private int index;
223         public PopupItemActionListener(int index) {
224             this.index = index;
225         }
226
227         public void actionPerformed(ActionEvent e) {
228             // Change the selection:
229             setSelected(index);
230             // Invoke the selected operation (is that expected behaviour?):
231             //PushToApplicationButton.this.actionPerformed(null);
232             // It makes sense to transfer focus to the push button after the
233             // menu closes:
234             pushButton.requestFocus();
235         }
236     }
237
238
239     class MenuButtonActionListener implements ActionListener {
240
241         public void actionPerformed(ActionEvent e) {
242             // Lazy initialization of the popup menu:
243             if (popup == null)
244                 buildPopupMenu();
245             popup.show(comp, 0, menuButton.getHeight());
246         }
247     }
248
249     class MenuAction extends MnemonicAwareAction {
250
251         public MenuAction() {
252             putValue(ACCELERATOR_KEY, Globals.prefs.getKey("Push to application"));
253         }
254
255         public void setTitle(String appName) {
256             putValue(NAME, Globals.lang("Push entries to external application (%0)",
257                     appName));
258         }
259
260         public void actionPerformed(ActionEvent e) {
261             PushToApplicationButton.this.actionPerformed(null);
262         }
263     }
264
265     class PushButtonMouseListener extends MouseAdapter {
266         public void mousePressed(MouseEvent event) {
267             if (event.isPopupTrigger())
268                 processPopupTrigger(event);
269         }
270
271         public void mouseClicked(MouseEvent event) {
272             if (event.isPopupTrigger())
273                 processPopupTrigger(event);
274         }
275
276         public void mouseReleased(MouseEvent event) {
277             if (event.isPopupTrigger())
278                 processPopupTrigger(event);
279         }
280
281         private void processPopupTrigger(MouseEvent e) {
282             // We only want to show the popup if a settings panel exists for the selected
283             // item:
284             PushToApplication toApp = pushActions.get(selected);
285             if (toApp.getSettingsPanel() != null)
286                 optPopup.show(pushButton, e.getX(), e.getY());
287
288         }
289     }
290
291     /**
292      * Comparator for sorting the selection according to name.
293      */
294     static class PushToApplicationComparator implements Comparator<PushToApplication> {
295
296         public int compare(PushToApplication one, PushToApplication two) {
297             return one.getName().compareTo(two.getName());
298         }
299     }
300 }