View Javadoc

1   /*
2    * Copyright (c) 2007 Creative Sphere Limited.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v10.html
7    *
8    * Contributors:
9    *
10   *   Creative Sphere - initial API and implementation
11   *
12   */
13  package org.abstracthorizon.aequo.action;
14  
15  import java.awt.event.ActionEvent;
16  import java.net.URL;
17  import java.text.MessageFormat;
18  
19  import javax.swing.AbstractAction;
20  import javax.swing.Action;
21  import javax.swing.Icon;
22  import javax.swing.ImageIcon;
23  import javax.swing.JOptionPane;
24  import javax.swing.ProgressMonitor;
25  
26  import org.abstracthorizon.aequo.GlobalContext;
27  import org.abstracthorizon.aequo.util.TaskUtilities;
28  
29  /**
30   * Base action to be extended. It provides {@link ProgressMonitor} and confirmation facilities to
31   * subclasses.
32   *
33   * @author Daniel Sendula
34   */
35  public abstract class BaseAction extends AbstractAction {
36  
37      /** Message to be displayed while progressing through the operation */
38      protected Object message;
39      
40      /** Global context */
41      protected GlobalContext context;
42      
43      /** Is confirmation required before operation is to start */
44      protected boolean confirmRequired;
45      
46      /** Action is directional - it performs operation on source and destination column */
47      protected boolean directionalAction;
48      
49      /** Column this operation is supposed to be invoked on */
50      protected int column = 0;
51      
52      /** Destination column for the action */
53      protected int destColumn = -1;
54      
55      /** Empty icon for aligning icons in the menus */
56      public static final Icon EMPTY_ICON = new ImageIcon(BaseAction.class.getResource("Empty.png"));
57      
58      /** <-- */
59      public static final String PREFIX = "<--";
60      
61      /** --&gt; */
62      public static final String SUFFIX = "-->";
63      
64      
65      
66      /**
67       * Constructor
68       */
69      public BaseAction() {
70          autoloadIcon();
71      }
72      
73      /**
74       * Loads icon from the url obtained from {@link #getIconURL()} method
75       */
76      protected void autoloadIcon() {
77          URL url = getIconURL();
78          if (url != null) {
79              Icon icon = new ImageIcon(url);
80              putValue(Action.SMALL_ICON, icon);
81          } else {
82              putValue(Action.SMALL_ICON, EMPTY_ICON);
83          }
84      }
85      
86      /**
87       * This method checks if resource with the name of the class exists in the classes directory 
88       * 
89       * @return URL or <code>null</code>
90       */
91      protected URL getIconURL() {
92          String name = getClass().getName();
93          int i = name.lastIndexOf('.');
94          if (i > 0) {
95              name = name.substring(i + 1);
96          }
97          if (name.endsWith("Action")) {
98              name = name.substring(0, name.length() - 6);
99          }
100         URL url = getClass().getResource(name + ".png");
101         
102         if (directionalAction && (url == null)) {
103             url = getClass().getResource(name + "_" + column + ".png");
104         }
105         return url;
106     }
107 
108     /**
109      * Sets name of the action
110      * @param name name
111      */
112     public void setName(String name) {
113         putValue(Action.NAME, name);
114     }
115     
116     /**
117      * Sets description of the action
118      * @param description description
119      */
120     public void setDescription(String description) {
121         putValue(Action.SHORT_DESCRIPTION, description);
122         putValue(Action.LONG_DESCRIPTION, description);
123     }
124     
125     /**
126      * Sets the global context
127      * @param context
128      */
129     public void setGlobalContext(GlobalContext context) {
130         this.context = context;
131     }
132     
133     /**
134      * Returns global context
135      * @return global context
136      */
137     public GlobalContext getGlobalContext() {
138         return context;
139     }
140     
141     /**
142      * Sets if confirmation is required
143      * @param confirmRequired is confirmation required
144      */
145     public void setConfirmRequired(boolean confirmRequired) {
146         this.confirmRequired = confirmRequired;
147     }
148     
149     /**
150      * Returns if confirmation is required
151      * @return <code>true</code> if confirmation is required
152      */
153     public boolean isConfirmRequired() {
154         return confirmRequired;
155     }
156     
157     /**
158      * Sets if action is directional.
159      * @param directional is action directional.
160      */
161     public void setDirectionalAction(boolean directional) {
162         this.directionalAction = directional;
163     }
164     
165     /**
166      * Returns if action is directional.
167      * 
168      * @return <code>true</code> if action is directional.
169      * @see #directionalAction
170      */
171     public boolean isDirectionalAction() {
172         return directionalAction;
173     }
174     
175     /**
176      * Sets message
177      * @param message message
178      * @see #message
179      */
180     public void setMessage(Object message) {
181         this.message = message;
182     }
183     
184     /**
185      * Returns message
186      * @return message
187      * @see #message
188      */
189     public Object getMessage() {
190         return message;
191     }
192 
193     /**
194      * Sets column
195      * @param column column
196      * @see #column
197      */
198     public void setColumn(int column) {
199         this.column = column;
200         if (directionalAction) {
201             destColumn = 1 - column;
202             autoloadIcon();
203             Object name = super.getValue(Action.NAME);
204             if ((name != null) && (changeSupport != null)) {
205                 changeSupport.firePropertyChange(Action.NAME, name, getValue(Action.NAME));
206             }
207         }
208     }
209     
210     /**
211      * Returns column
212      * @return column
213      * @see #column
214      */
215     public int getColumn() {
216         return column;
217     }
218 
219 
220     /**
221      * Sets destination column 
222      * @param column destination column
223      */
224     public void setDestinationColumn(int column) {
225         this.destColumn = column;
226     }
227     
228     /**
229      * Returns destination column
230      * @return destination column
231      */
232     public int getDestinationColumn() {
233         return destColumn;
234     }
235 
236     /**
237      * Returns value as per {@link Action} interface but replaces name on the fly with
238      * message formatted with prefix and suffix as first and second parameter.
239      * 
240      * @param key key
241      * 
242      * @return value
243      */
244     public Object getValue(String key) {
245         Object value = super.getValue(key);
246         
247         if (directionalAction && key.equals(Action.NAME) && (value != null)) {
248             String prefix = "";
249             if (isEnabled() && (column > destColumn)) {
250                 prefix = PREFIX;
251             }
252             String suffix = "";
253             if (isEnabled() && (destColumn > column)) {
254                 suffix = SUFFIX;
255             }
256             value = MessageFormat.format(value.toString(), new Object[]{prefix, suffix});
257         }
258         return value;
259     }
260     
261 
262     /**
263      * Invoken by the framework (system). This method checks if action is enabled and then invokes it.
264      * @param e event
265      */
266     public void actionPerformed(final ActionEvent e) {
267         if (isEnabled()) {
268             invokeAction(e);
269         }
270     }
271     
272     /**
273      * Invokes action. This method checks if confirmation is required and if so
274      * it invokes it in separate thread. 
275      * @param e event
276      */
277     protected void invokeAction(final ActionEvent e) {
278         int res = 0;
279         if (isConfirmRequired()) {
280             res = showConfirmDialog();
281         }
282         if (!confirmRequired || (res == JOptionPane.OK_OPTION)) {
283             final ProgressMonitor progressMonitor = new ProgressMonitor(null, message, "", 0, 1);
284             progressMonitor.setProgress(0);
285             progressMonitor.setMillisToDecideToPopup(500);
286             progressMonitor.setMillisToPopup(1000);
287             Runnable task = new Runnable() {
288                 public void run() {
289                     try {
290                         perform(e, progressMonitor);
291                     } finally {
292                         progressMonitor.close();
293                     }
294                 }
295             };
296             TaskUtilities.invokeLater(task);
297         }
298     }
299 
300     /**
301      * This method shows confirmation dialog
302      * @return result as in {@link JOptionPane#showConfirmDialog(java.awt.Component, Object)}
303      */
304     protected int showConfirmDialog() {
305         int res = JOptionPane.showConfirmDialog(null, updateMessage(), "Confirm", JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, null);
306         return res;
307     }
308     
309     /** 
310      * This method allows sub-classes to update message with, for instance, 
311      * list of selected files, before being displayed on the dialog.
312      * 
313      * @return message
314      */
315     protected Object updateMessage() {
316         return message;
317     }
318 
319     /**
320      * <p>
321      * This method is to be called for action to be invoked. This method
322      * is called from {@link #perform(ActionEvent, ProgressMonitor).
323      * </p>
324      * <p>
325      * Subclasses are supposed to override this method if no progress is
326      * to be monitored during the action. Otherwise they should override
327      * {@link #perform(ActionEvent, ProgressMonitor)}
328      * </p>
329      * 
330      * @param e event
331      */
332     public void perform(final ActionEvent e) {
333     }
334     
335     /**
336      * <p>
337      * This method is called from {@link #invokeAction(ActionEvent)} method.
338      * </p>
339      * <p>
340      * Subclasses are supposed to override this method if progress is to be 
341      * monitored. Otherwise override {@link #perform(ActionEvent)}
342      * </p>
343      * 
344      * @param e event
345      * @param monitor monitor
346      */
347     public void perform(final ActionEvent e, ProgressMonitor monitor) {
348         perform(e);
349     }
350 }