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
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
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
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
416
417 }
418
419 }