3 import jalview.bin.Cache;
4 import jalview.jbgui.GBlogReader;
6 import java.awt.BorderLayout;
7 import java.awt.Component;
8 import java.awt.Dimension;
10 import java.awt.Rectangle;
11 import java.awt.event.ActionEvent;
12 import java.awt.event.ActionListener;
13 import java.awt.event.KeyEvent;
14 import java.awt.event.MouseEvent;
15 import java.awt.event.WindowAdapter;
16 import java.awt.event.WindowEvent;
17 import java.beans.PropertyChangeListener;
18 import java.text.DateFormat;
19 import java.text.SimpleDateFormat;
20 import java.util.ArrayList;
21 import java.util.Calendar;
22 import java.util.Collections;
23 import java.util.Iterator;
24 import java.util.List;
27 import javax.swing.AbstractAction;
28 import javax.swing.AbstractButton;
29 import javax.swing.Action;
30 import javax.swing.DefaultListCellRenderer;
31 import javax.swing.DefaultListModel;
32 import javax.swing.Icon;
33 import javax.swing.ImageIcon;
34 import javax.swing.JButton;
35 import javax.swing.JLabel;
36 import javax.swing.JList;
37 import javax.swing.JMenuItem;
38 import javax.swing.JPanel;
39 import javax.swing.JPopupMenu;
40 import javax.swing.JScrollPane;
41 import javax.swing.JSplitPane;
42 import javax.swing.JToolBar;
43 import javax.swing.ListSelectionModel;
44 import javax.swing.SwingUtilities;
45 import javax.swing.event.HyperlinkEvent;
46 import javax.swing.event.HyperlinkListener;
47 import javax.swing.event.ListSelectionEvent;
48 import javax.swing.event.ListSelectionListener;
50 import org.robsite.jswingreader.action.MarkChannelAsRead;
51 import org.robsite.jswingreader.action.MarkChannelAsUnread;
52 import org.robsite.jswingreader.action.MarkItemAsRead;
53 import org.robsite.jswingreader.action.MarkItemAsUnread;
54 import org.robsite.jswingreader.action.UpdatableAction;
55 import org.robsite.jswingreader.model.Channel;
56 import org.robsite.jswingreader.model.ChannelListModel;
57 import org.robsite.jswingreader.model.Item;
58 import org.robsite.jswingreader.model.SimpleRSSParser;
59 import org.robsite.jswingreader.ui.BlogContentPane;
60 import org.robsite.jswingreader.ui.ItemReadTimer;
61 import org.robsite.jswingreader.ui.Main;
62 import org.robsite.jswingreader.ui.util.ContextMenuMouseAdapter;
65 * Blog reading window, adapted from JSwingReader's
66 * org.robsite.jswingreader.ui.MainWindow class
69 public class BlogReader extends GBlogReader
71 private JButton buttonRefresh = new JButton();
73 private JToolBar toolBar = new JToolBar();
75 private JLabel statusBar = new JLabel();
77 private JPanel panelMain = new JPanel();
79 private BorderLayout layoutMain = new BorderLayout();
81 private BorderLayout borderLayout1 = new BorderLayout();
83 private JPanel topPanel = new JPanel();
85 private JPanel bottomPanel = new JPanel();
87 private JSplitPane topBottomSplitPane = new JSplitPane();
89 private JList listItems = new JList(new DefaultListModel());
91 // SWITCH IN JALVIEW HTML VIEWER PANE HERE
92 private BlogContentPane textDescription = new BlogContentPane();
94 // ADD IN JALVIEW BANNER FOR PRETTINESS
95 private BorderLayout borderLayout4 = new BorderLayout();
97 private BorderLayout borderLayout5 = new BorderLayout();
99 private ChannelListModel _channelModel = null;
101 private JList listChannels = new JList();
103 private Action exitAction = new Action()
107 public void actionPerformed(ActionEvent arg0)
112 parent.showNews(false);
118 public void setEnabled(boolean arg0)
124 public void removePropertyChangeListener(PropertyChangeListener arg0)
126 // TODO Auto-generated method stub
131 public void putValue(String arg0, Object arg1)
133 // TODO Auto-generated method stub
138 public boolean isEnabled()
140 // TODO Auto-generated method stub
145 public Object getValue(String arg0)
147 // TODO Auto-generated method stub
152 public void addPropertyChangeListener(PropertyChangeListener arg0)
154 // TODO Auto-generated method stub
159 private JLabel lblChannels = new JLabel();
161 private List _updatableActions = new ArrayList();
163 private ItemReadTimer _itemTimer = null;
165 private JPopupMenu _popupItems = null;
167 private JPopupMenu _popupChannels = null;
169 private String lastm = "";
171 private boolean newsnew = false;
173 private Desktop parent = null;
180 // should we ignore fake gui events
181 private boolean updating = false;
183 public BlogReader(Desktop desktop)
188 this.setSize(new Dimension(550, 350));
192 Rectangle bounds = parent
193 .getLastKnownDimensions("JALVIEW_RSS_WINDOW_");
196 setBounds(parent.getX(), parent.getY(), 550, 350);
200 setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
203 _channelModel = new ChannelListModel();
204 // Construct our jalview news channel
205 Channel chan = new Channel();
206 chan.setURL(jalview.bin.Cache.getDefault(
208 jalview.bin.Cache.getDefault("www.jalview.org",
209 "http://www.jalview.org") + "/feeds/desktop/rss"));
211 _channelModel.addChannel(chan);
217 } catch (Exception e)
224 boolean setvisible = checkForNew(chan, true);
227 Cache.log.info("Will show jalview news automatically");
228 SwingUtilities.invokeLater(new Runnable()
235 parent.showNews(true);
247 * update hasnew flag and mark all new messages as unread.
249 private boolean checkForNew(Channel chan, boolean updateItems)
252 if (!updating || updateItems)
256 java.util.Date earliest=null;
258 earliest = new SimpleDateFormat("YYYY-MM-DD").parse(chan.getHTTPLastModified());
259 } catch (Exception x) {};
260 if (chan != null && chan.getItems() != null)
262 Cache.log.debug("Scanning news items: newsnew="+newsnew+" and lastDate is "+lastDate);
263 for (Item i : (List<Item>) chan.getItems())
265 boolean isread = lastDate==null ? false : (i.getPublishDate() != null && !lastDate
266 .before(i.getPublishDate()));
268 if (!updating || updateItems)
276 if (i.getPublishDate()!=null && !i.isRead())
278 if (earliest==null || earliest.after(i.getPublishDate()))
280 earliest=i.getPublishDate();
285 if (!updateItems && !updating && lastDate==null)
292 java.util.Date lastDate = null;
294 private void loadLastM()
296 lastDate = Cache.getDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED");
299 private void saveLastM(Item item)
303 if (item.getPublishDate() != null)
305 if (lastDate==null || item.getPublishDate().after(lastDate))
307 lastDate = item.getPublishDate();
311 if (_channelModel.getElementAt(0) != null)
313 checkForNew((Channel) _channelModel.getElementAt(0), false);
315 if (lastDate != null)
317 jalview.bin.Cache.setDateProperty(
318 "JALVIEW_NEWS_RSS_LASTMODIFIED", lastDate);
319 jalview.bin.Cache.log.info("Saved last read date as "
320 + jalview.bin.Cache.date_format.format(lastDate));
326 private void jbInit() throws Exception
328 this.setTitle("News from www.jalview.org");
329 this.getContentPane().setLayout(layoutMain);
330 panelMain.setLayout(borderLayout1);
331 topPanel.setLayout(borderLayout5);
332 bottomPanel.setLayout(borderLayout4);
333 topBottomSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
334 topBottomSplitPane.setDividerLocation(100);
335 topBottomSplitPane.setTopComponent(topPanel);
336 topBottomSplitPane.setBottomComponent(bottomPanel);
337 JScrollPane spTextDescription = new JScrollPane(textDescription);
338 textDescription.setText("");
339 statusBar.setText(" [Status] ");
340 buttonRefresh.addActionListener(new ActionListener()
344 public void actionPerformed(ActionEvent e)
349 this.getContentPane().add(statusBar, BorderLayout.SOUTH);
350 toolBar.add(buttonRefresh);
351 toolBar.addSeparator();
352 JLabel about=new JLabel("brought to you by JSwingReader (jswingreader.sourceforge.net)");
354 toolBar.setFloatable(false);
355 this.getContentPane().add(toolBar, BorderLayout.NORTH);
356 panelMain.add(topBottomSplitPane, BorderLayout.CENTER);
357 this.getContentPane().add(panelMain, BorderLayout.CENTER);
358 JScrollPane spListItems = new JScrollPane(listItems);
360 .setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
361 topPanel.add(spListItems, BorderLayout.CENTER);
362 bottomPanel.add(spTextDescription, BorderLayout.CENTER);
363 listChannels.setModel(_channelModel);
365 listItems.addMouseListener(new java.awt.event.MouseAdapter()
367 public void mouseClicked(MouseEvent e)
369 listItems_mouseClicked(e);
372 _popupItems = _buildItemsPopupMenu();
373 _popupChannels = _buildChannelsPopupMenu();
374 ContextMenuMouseAdapter popupAdapter = new ContextMenuMouseAdapter(
376 ContextMenuMouseAdapter popupChannelsAdapter = new ContextMenuMouseAdapter(
378 listItems.addMouseListener(popupAdapter);
379 listItems.setCellRenderer(new ItemsRenderer());
380 lblChannels.setText("Channels");
383 private void postInit()
385 // clear the default hyperlink listener and replace with our own.
386 for (HyperlinkListener hll : textDescription.getHyperlinkListeners())
388 textDescription.removeHyperlinkListener(hll);
390 textDescription.addHyperlinkListener(new HyperlinkListener()
392 public void hyperlinkUpdate(HyperlinkEvent e)
394 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
396 Desktop.showUrl(e.getURL().toExternalForm());
401 this.addWindowListener(new WindowAdapter()
403 public void windowClosing(WindowEvent e)
405 ActionEvent actionEvent = new ActionEvent(this,
406 ActionEvent.ACTION_FIRST, (String) exitAction
407 .getValue(Action.NAME));
408 exitAction.actionPerformed(actionEvent);
411 public void windowOpened(WindowEvent e)
416 listItems.addListSelectionListener(new ListSelectionListener()
418 public void valueChanged(ListSelectionEvent e)
420 if (e.getValueIsAdjusting() == false)
422 _itemsValueChanged(listItems);
426 listChannels.setSelectedIndex(1);
428 _updateToolbarButtons();
430 _itemTimer = new ItemReadTimer(listChannels, listItems);
431 _itemsValueChanged(listItems);
434 public class LaunchJvBrowserOnItem extends AbstractAction implements
437 JList _listItems = null;
439 public LaunchJvBrowserOnItem(JList listItems)
441 super("Open in Browser");
442 this.putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_O));
443 this.putValue(Action.LONG_DESCRIPTION, "Open in Browser");
444 _listItems = listItems;
447 public void actionPerformed(ActionEvent e)
449 Object o = _listItems.getSelectedValue();
450 if (o instanceof Item)
452 Item item = (Item) o;
454 _listItems.repaint();
456 Desktop.showUrl(item.getLink());
460 public void update(Object o)
463 if (_listItems == null || _listItems.getModel().getSize() == 0)
467 else if (_listItems.getSelectedIndex() == -1)
475 private JPopupMenu _buildItemsPopupMenu()
477 JPopupMenu popup = new JPopupMenu();
478 popup.add(new JMenuItem(new LaunchJvBrowserOnItem(listItems)));
479 popup.addSeparator();
480 popup.add(new JMenuItem(new MarkItemAsRead(listItems)));
481 popup.add(new JMenuItem(new MarkItemAsUnread(listItems)));
485 private JPopupMenu _buildChannelsPopupMenu()
487 JPopupMenu popup = new JPopupMenu();
488 popup.add(new JMenuItem(new MarkChannelAsRead(listChannels, listItems)));
489 popup.add(new JMenuItem(
490 new MarkChannelAsUnread(listChannels, listItems)));
494 private void initItems(Channel channel)
498 channel = new Channel();
500 if (!channel.isOpen() && channel.getURL() != null)
504 SimpleRSSParser.parse(channel);
505 } catch (Exception ex)
507 ex.printStackTrace();
510 DefaultListModel itemsModel = (DefaultListModel) listItems.getModel();
512 Iterator iter = (channel.getItems() != null) ? channel.getItems()
513 .iterator() : Collections.EMPTY_LIST.iterator();
514 while (iter.hasNext())
516 itemsModel.addElement(iter.next());
518 if (itemsModel.getSize() > 0)
520 listItems.setSelectedIndex(0);
521 _itemsValueChanged(listItems);
523 setStatusBarText(channel.getURL());
527 private void _itemsValueChanged(JList itemList)
529 Item item = (Item) itemList.getSelectedValue();
532 if (itemList.getModel().getSize() > 0)
534 item = (Item) itemList.getModel().getElementAt(0);
542 itemList.setSelectedIndex(0);
546 if (_itemTimer != null)
548 // prefer a shorter delay than 5s
549 _itemTimer.setDelay(300);
551 _itemTimer.setLastItem(item);
552 final Item lastitem = item;
553 _itemTimer.addActionListener(new ActionListener()
557 public void actionPerformed(ActionEvent e)
564 setStatusBarText(item.getLink());
565 textDescription.setBlogText(item);
569 public void setStatusBarText(String text)
571 statusBar.setText(text);
574 private void _updateAllActions()
576 Iterator iter = _updatableActions.iterator();
577 while (iter.hasNext())
579 UpdatableAction action = (UpdatableAction) iter.next();
584 private void _updateToolbarButtons()
586 Map general = (Map) Main.getPreferences().get("general");
592 Component[] components = toolBar.getComponents();
593 for (int i = 0; i < components.length; i++)
595 Component component = components[i];
596 if (component instanceof JButton)
598 JButton button = (JButton) component;
599 if (Boolean.toString(false).equals(general.get("useToolBarText")))
601 // Remove the text if preferences state no toolbar text
604 if (Boolean.toString(true).equals(general.get("radioTextBelow")))
606 button.setVerticalTextPosition(AbstractButton.BOTTOM);
607 button.setHorizontalTextPosition(AbstractButton.CENTER);
609 else if (Boolean.toString(true).equals(
610 general.get("radioTextRight")))
612 button.setVerticalTextPosition(AbstractButton.CENTER);
613 button.setHorizontalTextPosition(AbstractButton.RIGHT);
619 private void listItems_mouseClicked(MouseEvent e)
621 if (e.getClickCount() == 2 && e.getModifiersEx() == MouseEvent.NOBUTTON)
623 Item item = (Item) listItems.getSelectedValue();
626 if (_itemTimer != null)
631 Action action = new LaunchJvBrowserOnItem(listItems);
632 ActionEvent event = new ActionEvent(this,
633 ActionEvent.ACTION_PERFORMED, "LaunchBrowserOnItem");
634 action.actionPerformed(event);
639 * force the news panel to refresh
641 public void refreshNews()
644 initItems((Channel)_channelModel.getElementAt(0));
646 } catch (Exception x)
650 public static void main(String args[])
652 // this tests the detection of new news based on the last read date stored
653 // in jalview properties
654 jalview.bin.Cache.loadProperties(null);
655 jalview.bin.Cache.initLogger();
656 // test will advance read date each time
657 Calendar today = Calendar.getInstance(), lastread = Calendar
659 lastread.set(1983, 01, 01);
660 while (lastread.before(today))
662 Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED",
664 BlogReader me = new BlogReader();
665 System.out.println("Set last date to "
666 + jalview.bin.Cache.date_format.format(lastread.getTime()));
669 Cache.log.info("There is news to read.");
673 Cache.log.info("There is no new news.");
675 me.setTitle("Testing : Last read is " + me.lastDate);
678 while (me.isVisible())
683 } catch (InterruptedException x)
690 Cache.log.info("Still new news after reader displayed.");
692 if (lastread.getTime().before(me.lastDate))
694 Cache.log.info("The news was read.");
695 lastread.setTime(me.lastDate);
699 lastread.add(Calendar.MONTH, 1);
711 class ChannelsRenderer extends DefaultListCellRenderer
713 private final static Icon _icon = new ImageIcon(
714 Main.class.getResource("image/ComposeMail16.gif"));
716 public Component getListCellRendererComponent(JList list, Object value,
717 int index, boolean isSelected, boolean cellHasFocus)
719 JLabel component = (JLabel) super.getListCellRendererComponent(list,
720 value, index, isSelected, cellHasFocus);
721 component.setIcon(ChannelsRenderer._icon);
722 if (value instanceof Channel)
724 Channel channel = (Channel) value;
725 component.setText(channel.getTitle() + " ("
726 + channel.getUnreadItemCount() + ")");
727 component.setToolTipText(channel.getURL());
733 class ItemsRenderer extends DefaultListCellRenderer
735 private final static Icon _icon = new ImageIcon(
736 Main.class.getResource("image/ComposeMail16.gif"));
738 public Component getListCellRendererComponent(JList list, Object value,
739 int index, boolean isSelected, boolean cellHasFocus)
741 JLabel component = (JLabel) super.getListCellRendererComponent(list,
742 value, index, isSelected, cellHasFocus);
743 component.setIcon(ItemsRenderer._icon);
744 if (value instanceof Item)
746 Item item = (Item) value;
747 if (item.getPublishDate() != null)
749 component.setText(DateFormat.getDateInstance().format(
750 item.getPublishDate())
751 + " " + item.getTitle());
753 component.setToolTipText(item.getLink());
756 component.setFont(component.getFont().deriveFont(Font.BOLD));
760 component.setFont(component.getFont().deriveFont(Font.PLAIN));