View Javadoc

1   package org.robsite.extension.rss;
2   
3   import java.awt.GridBagConstraints;
4   import java.awt.GridBagLayout;
5   import java.awt.Insets;
6   import java.awt.Toolkit;
7   import java.awt.event.ActionEvent;
8   import java.awt.event.ActionListener;
9   
10  import java.util.ArrayList;
11  import java.util.Iterator;
12  import java.util.List;
13  
14  import javax.swing.BorderFactory;
15  import javax.swing.DefaultListModel;
16  import javax.swing.JButton;
17  import javax.swing.JCheckBox;
18  import javax.swing.JLabel;
19  import javax.swing.JList;
20  import javax.swing.JTextField;
21  import javax.swing.SwingConstants;
22  import javax.swing.SwingUtilities;
23  import javax.swing.event.ListSelectionEvent;
24  import javax.swing.event.ListSelectionListener;
25  import javax.swing.text.AttributeSet;
26  import javax.swing.text.BadLocationException;
27  import javax.swing.text.PlainDocument;
28  
29  import oracle.bali.ewt.button.ButtonBar;
30  import oracle.bali.ewt.shuttle.ListPicker;
31  import oracle.bali.ewt.shuttle.Shuttle;
32  
33  import oracle.ide.panels.DefaultTraversablePanel;
34  import oracle.ide.panels.TraversableContext;
35  import oracle.ide.panels.TraversalException;
36  
37  import org.robsite.extension.rss.model.Channel;
38  
39  /***
40   * The preferences panel for the RSS reader extension.
41   * 
42   * @author brian_duff@sourceforge.net
43   * @version $Revision: 1.1.1.1 $
44   */
45  public class NewsFeedPreferencesPanel extends DefaultTraversablePanel 
46  {
47    private NewsFeedPreferences _preferences;
48  
49    private final GridBagLayout _layout = new GridBagLayout();
50    private final Shuttle _channelsShuttle = new Shuttle();
51    private final JCheckBox _checkOnStartup = new JCheckBox();
52  
53    private final JCheckBox _checkEvery = new JCheckBox();
54    private final JTextField _checkSeconds = new JTextField();
55    private final JLabel _seconds = new JLabel();
56    
57    private final JList _availableList = new JList();
58    private final JList _selectedList = new JList();
59    
60    private final JLabel _availableLabel = new JLabel();
61    private final JLabel _selectedLabel = new JLabel();
62    
63    private final JButton _newChannelButton = new JButton();
64    private final JButton _editChannelButton = new JButton();
65    private final JButton _deleteChannelButton = new JButton();
66    
67    private final ButtonBar _buttonBar = new ButtonBar();
68    private final JLabel _httpTimeout = new JLabel();
69    private final JTextField _tfHTTPTimeout = new JTextField();
70    private final JLabel _milliseconds = new JLabel();
71    
72    private final JLabel _notificationTime = new JLabel();
73    private final JTextField _notificationField = new JTextField();
74    private final JLabel _notificationSeconds = new JLabel();
75    
76    private final ResHelper _res = new ResHelper( "Preferences." );
77  
78    public NewsFeedPreferencesPanel()
79    {
80      jbInit();
81      initListeners();
82    }
83  
84    private void jbInit()
85    {
86      this.setLayout(_layout);
87      _res.resButton( "CheckOnStartup", _checkOnStartup );
88      _res.resButton( "CheckNewsEvery", _checkEvery );
89      
90      _checkSeconds.setText("10");
91      _checkSeconds.setColumns(5);
92      _checkSeconds.setHorizontalAlignment(JTextField.TRAILING);
93      _checkSeconds.setEnabled( false );
94      
95      _seconds.setText( _res.getRes( "Seconds" ) );
96      
97      _res.resLabel( "AvailableChannels", _availableLabel, _availableList );
98      _res.resLabel( "SelectedChannels", _selectedLabel, _selectedList );
99      _availableLabel.setBorder( BorderFactory.createEmptyBorder( 0, 0, 5, 0 ) );
100     _selectedLabel.setBorder( BorderFactory.createEmptyBorder( 0, 0, 5, 0 ) );
101     _res.resButton( "New", _newChannelButton );
102     _res.resButton( "Edit", _editChannelButton );
103     _res.resButton( "Delete", _deleteChannelButton );
104     
105     _res.resLabel( "HTTPTimeout", _httpTimeout, _tfHTTPTimeout );
106     _tfHTTPTimeout.setText("3000");
107     _tfHTTPTimeout.setHorizontalAlignment(JTextField.TRAILING);
108     _milliseconds.setText(_res.getRes( "Milliseconds" ));
109     
110     _res.resLabel( "StatusTime", _notificationTime, _notificationField );
111     _notificationField.setText("300");
112     _notificationField.setColumns( 5 );
113     _notificationField.setHorizontalAlignment( JTextField.TRAILING );
114     _notificationSeconds.setText( _res.getRes( "Seconds" ) );
115     
116     _channelsShuttle.setFromPicker( new ListPicker( _availableList ) );
117     _channelsShuttle.setToPicker( new ListPicker( _selectedList ) );
118     
119     _channelsShuttle.add( _availableLabel, Shuttle.FROM_HEADER_COMPONENT );
120     _channelsShuttle.add( _selectedLabel, Shuttle.TO_HEADER_COMPONENT );
121 
122     _buttonBar.setAlignment( SwingConstants.LEFT );
123     _buttonBar.add( _newChannelButton );
124     _buttonBar.add( _editChannelButton );
125     _buttonBar.add( _deleteChannelButton );
126 
127     
128     _channelsShuttle.add( _buttonBar, Shuttle.TO_FOOTER_COMPONENT );
129     
130     
131     _editChannelButton.setEnabled( false );
132     _deleteChannelButton.setEnabled( false );
133     
134     this.add(_channelsShuttle, new GridBagConstraints(0, 0, 3, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0));
135     this.add(_checkOnStartup, new GridBagConstraints(0, 1, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 5, 0), 0, 0));
136     this.add(_checkEvery, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0));
137     this.add(_checkSeconds, new GridBagConstraints(1, 2, 1, 1, 0.3, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
138     this.add(_seconds, new GridBagConstraints(2, 2, 1, 1, 0.7, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 0), 0, 0));
139     this.add(_httpTimeout, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0));
140     this.add(_tfHTTPTimeout, new GridBagConstraints(1, 4, 1, 1, 0.3, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
141     this.add(_milliseconds, new GridBagConstraints(2, 4, 1, 1, 0.7, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 0, 0), 0, 0));
142     this.add(_notificationTime, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 5, 0), 0, 0));
143     this.add(_notificationField, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 5, 0), 0, 0));
144     this.add(_notificationSeconds, new GridBagConstraints(2, 3, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 5, 0), 0, 0));
145   }
146   
147   private void initListeners()
148   {
149     ActionListener al = new ActionListener() 
150     {
151       public void actionPerformed( ActionEvent ae )
152       {
153         if ( ae.getSource() == _checkEvery )
154         {
155           _checkSeconds.setEnabled( _checkEvery.isSelected() );
156         }
157         else if ( ae.getSource() == _newChannelButton )
158         {
159           addNewChannel();      
160         }
161         else if ( ae.getSource() == _deleteChannelButton )
162         {
163           deleteChannel();
164         }
165         else if ( ae.getSource() == _editChannelButton )
166         {
167           editChannel();
168         }
169       }
170     };
171     
172     ListSelectionListener lsl = new ListSelectionListener()
173     {
174       public void valueChanged( ListSelectionEvent lse )
175       {
176         JList list = (JList) lse.getSource();
177         Channel selectedChannel = (Channel) list.getSelectedValue();
178         
179         if ( selectedChannel != null )
180         {          
181           _deleteChannelButton.setEnabled( selectedChannel.isUserChannel() );
182           _editChannelButton.setEnabled( selectedChannel.isUserChannel() );
183         }
184       }
185     };
186     
187     _selectedList.addListSelectionListener( lsl );
188     
189     _checkEvery.addActionListener( al );
190     _newChannelButton.addActionListener( al );
191     _editChannelButton.addActionListener( al );
192     _deleteChannelButton.addActionListener( al );
193     
194     /***
195      * A text field document that restricts to integer values only.
196      */
197     class NumericDocument extends PlainDocument
198     {
199       public void insertString(int offset, String str, AttributeSet ats) 
200         throws BadLocationException
201       { 
202         try 
203         {
204           Integer.parseInt( str );
205         }
206         catch ( NumberFormatException nfe )
207         {
208           Toolkit.getDefaultToolkit().beep();
209           return;
210         }
211         
212         super.insertString( offset, str, ats );
213       }
214     };
215     
216     _checkSeconds.setDocument( new NumericDocument() );
217     _tfHTTPTimeout.setDocument( new NumericDocument() );
218     _notificationField.setDocument( new NumericDocument() );
219   }
220   
221   
222   
223   private void addNewChannel()
224   {
225     NewChannelPanel panel = new NewChannelPanel();
226     
227     if ( panel.runCreateDialog( this ) )
228     {
229       String url = panel.getURL();
230       Channel channel = new Channel();
231       channel.setURL( url );
232       channel.setUserChannel( true );
233       ((DefaultListModel)_selectedList.getModel()).addElement( channel );
234       _selectedList.setSelectedIndex( _selectedList.getModel().getSize() - 1 );
235     }
236   }
237   
238   private void deleteChannel()
239   {
240     Channel c = (Channel) _selectedList.getSelectedValue();
241     if ( c != null )
242     {
243       ((DefaultListModel)_selectedList.getModel()).removeElement( c );
244     }
245   }
246   
247   private void editChannel()
248   {
249     Channel c = (Channel) _selectedList.getSelectedValue();
250     if ( c != null )
251     {
252       NewChannelPanel panel = new NewChannelPanel();
253       if ( panel.runEditDialog( this, c.getURL() ) )
254       {
255         c.setURL( panel.getURL() );
256       }
257     }
258   }
259   
260 ///////////////////////////////////////////////////////////////////////////////
261 // DefaultTraversablePanel overrides
262 ///////////////////////////////////////////////////////////////////////////////
263 
264   public void onEntry( final TraversableContext context )
265   {
266     final NewsFeedPreferences prefs = (NewsFeedPreferences) 
267       context.get( NewsFeedExtension.PREFS_KEY );
268     
269     _checkSeconds.setText( String.valueOf( prefs.getCheckDelaySeconds() ) );
270     _checkEvery.setSelected( prefs.isCheckAutomatically() );
271     _checkSeconds.setEnabled( prefs.isCheckAutomatically() );    
272     _checkOnStartup.setSelected( prefs.isCheckOnStartup() );
273     _tfHTTPTimeout.setText( String.valueOf( prefs.getHTTPTimeout() ) );
274     _notificationField.setText( String.valueOf( 
275       prefs.getStatusMessageDuration() ) );
276     // Asynchronously request a refresh of the pre-populated feeds.
277     context.getDialogCallbacks().enableOKButton( false );
278     setShuttleEnabled( false );
279     ((DefaultListModel)_availableList.getModel()).addElement( 
280       _res.getRes( "UpdatingChannels" ) );
281     
282     Runnable checkRunnable = new Runnable() 
283     {
284       public void run()
285       {
286         try
287         {
288           HTTPUtil.setHTTPTimeout( prefs.getHTTPTimeout() );
289           
290           NewsCheckRunnable.checkDirectory( prefs );
291         }
292         catch ( Exception e )
293         {
294           // TODO Report error properly.
295           e.printStackTrace();
296         }
297         finally
298         {
299           HTTPUtil.resetHTTPTimeout();
300           
301           SwingUtilities.invokeLater( new Runnable() 
302           {
303             public void run()
304             {
305               ((DefaultListModel)_availableList.getModel()).removeAllElements();
306               setShuttleEnabled( true );
307               context.getDialogCallbacks().enableOKButton( true );
308               
309               List subscribed = prefs.getChannels().getSubscribedChannels();
310               List unsubscribed = prefs.getChannels().getUnsubscribedChannels();
311               
312               for ( Iterator i = subscribed.iterator(); i.hasNext(); )
313               {
314                 ((DefaultListModel) _selectedList.getModel()).addElement( i.next() );
315               }
316               
317               for ( Iterator i = unsubscribed.iterator(); i.hasNext(); )
318               {
319                 ((DefaultListModel) _availableList.getModel()).addElement( i.next() );
320               }                  
321             }
322           });
323         }
324       }
325     };
326     
327     Thread t = new Thread( checkRunnable );
328     t.start();
329   }
330   
331   private void setShuttleEnabled( boolean enabled )
332   {
333     _channelsShuttle.setEnabled( enabled );
334     _availableList.setEnabled( enabled );
335     _availableLabel.setEnabled( enabled );
336     _selectedList.setEnabled( enabled );
337     _selectedLabel.setEnabled( enabled );
338     _newChannelButton.setEnabled( enabled );
339   }
340   
341   public void onExit( TraversableContext context ) throws TraversalException
342   {
343     if ( _checkSeconds.getText().trim().length() == 0 )
344     {
345       if ( _checkEvery.isSelected() )
346       {
347         _checkSeconds.requestFocus();
348         throw new TraversalException(
349           _res.getRes( "NeedCheckInterval" )
350         );
351       }
352       else
353       {
354         _checkSeconds.setText( "0" );
355       }
356     }
357     
358     
359     if ( _checkEvery.isSelected() )
360     {
361       String checkDelay = _checkSeconds.getText().trim();
362       int val = Integer.parseInt( checkDelay );
363       if ( val < NewsFeedPreferences.MIN_CHECK_DELAY )
364       {
365         _checkSeconds.requestFocus();
366         throw new TraversalException(
367           _res.getRes( "MinimumCheckInterval", 
368             String.valueOf( NewsFeedPreferences.MIN_CHECK_DELAY ) )
369         );
370       }
371     }
372     
373     if ( _tfHTTPTimeout.getText().trim().length() == 0 )
374     {
375       _tfHTTPTimeout.requestFocus();
376       throw new TraversalException(
377         _res.getRes( "NeedHTTPTimeout" )
378       );
379     }
380   
381   
382     if ( _notificationField.getText().trim().length() == 0 )
383     {
384       _notificationField.requestFocus();
385       throw new TraversalException(
386         _res.getRes( "NeedStatusTime" )
387       );
388     }  
389   
390     NewsFeedPreferences prefs = (NewsFeedPreferences) 
391       context.get( NewsFeedExtension.PREFS_KEY );
392       
393     prefs.setCheckDelaySeconds( Integer.parseInt( _checkSeconds.getText() ) );
394     prefs.setCheckAutomatically( _checkEvery.isSelected() );
395     prefs.setCheckOnStartup( _checkOnStartup.isSelected() );
396     
397     List subscribed = new ArrayList();
398     for ( int i = 0; i < _selectedList.getModel().getSize(); i++ )
399     {
400       subscribed.add( _selectedList.getModel().getElementAt( i ) );
401     }
402     prefs.getChannels().setSubscribedChannels( subscribed );
403 
404     List unsubscribed = new ArrayList();
405     for ( int i = 0; i < _availableList.getModel().getSize(); i++ )
406     {
407       unsubscribed.add( _availableList.getModel().getElementAt( i ) );
408     }
409     prefs.getChannels().setUnsubscribedChannels( unsubscribed );
410     
411     prefs.setHTTPTimeout( Integer.parseInt( _tfHTTPTimeout.getText() ) );
412     
413     prefs.setStatusMessageDuration( Integer.parseInt( _notificationField.getText() ));
414     
415     // Force any visible dockable to update its list of channels.
416 
417   }
418 
419 }