jalview rss reader based on jswingreader (JAL-943)
authorjprocter <jprocter@compbio.dundee.ac.uk>
Thu, 22 Sep 2011 15:50:56 +0000 (16:50 +0100)
committerjprocter <jprocter@compbio.dundee.ac.uk>
Thu, 22 Sep 2011 15:50:56 +0000 (16:50 +0100)
THIRDPARTYLIBS
lib/jswingreader-0.3.jar [new file with mode: 0644]
src/jalview/bin/Cache.java
src/jalview/gui/BlogReader.java [new file with mode: 0644]
src/jalview/gui/Desktop.java
src/jalview/jbgui/GBlogReader.java [new file with mode: 0644]
src/jalview/jbgui/GDesktop.java

index 2671d8c..5918fc2 100644 (file)
@@ -19,6 +19,7 @@ httpcore-4.0.1.jar
 httpmime-4.0.3.jar
 jaxrpc.jar
 jhall.jar
+jswingreader-0.3.jar : Apache license - built from http://jswingreader.sourceforge.net/ svn/trunk v12
 log4j-1.2.8.jar
 mail.jar
 miglayout-4.0-swing.jar        BSD http://www.migcalendar.com/miglayout/versions/4.0/license.txt
diff --git a/lib/jswingreader-0.3.jar b/lib/jswingreader-0.3.jar
new file mode 100644 (file)
index 0000000..c8a4fff
Binary files /dev/null and b/lib/jswingreader-0.3.jar differ
index ab08140..fab075e 100755 (executable)
@@ -19,6 +19,8 @@ package jalview.bin;
 
 import java.awt.Color;
 import java.io.*;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
 import java.util.*;
 
 import org.apache.log4j.*;
@@ -767,4 +769,36 @@ public class Cache
     setProperty(property, jalview.util.Format
           .getHexString(colour));
   }
+
+  public static final DateFormat  date_format = SimpleDateFormat.getDateTimeInstance();
+
+  /**
+   * store a date in a jalview property
+   * @param string
+   * @param time
+   */
+  public static void setDateProperty(String property, Date time)
+  {
+    setProperty(property, date_format.format(time));
+  }
+  /**
+   * read a date stored in a jalview property
+   * @param property
+   * @return valid date as stored by setDateProperty, or null
+   * 
+   */
+  public static Date getDateProperty(String property)
+  {
+    String val = getProperty(property);
+    if (val!=null)
+    {
+      try {
+        return date_format.parse(val);
+      } catch (Exception ex)
+      {
+        System.err.println("Invalid or corrupt date in property '"+property+"' : value was '"+val+"'");
+      }
+    }
+    return null;
+  }
 }
diff --git a/src/jalview/gui/BlogReader.java b/src/jalview/gui/BlogReader.java
new file mode 100644 (file)
index 0000000..3b7df48
--- /dev/null
@@ -0,0 +1,754 @@
+package jalview.gui;
+
+import jalview.bin.Cache;
+import jalview.jbgui.GBlogReader;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.beans.PropertyChangeListener;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.AbstractAction;
+import javax.swing.AbstractButton;
+import javax.swing.Action;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.DefaultListModel;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JToolBar;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingUtilities;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.text.DateFormatter;
+
+import org.robsite.jswingreader.action.AboutAction;
+import org.robsite.jswingreader.action.MarkChannelAsRead;
+import org.robsite.jswingreader.action.MarkChannelAsUnread;
+import org.robsite.jswingreader.action.MarkItemAsRead;
+import org.robsite.jswingreader.action.MarkItemAsUnread;
+import org.robsite.jswingreader.action.RefreshChannelAction;
+import org.robsite.jswingreader.action.UpdatableAction;
+import org.robsite.jswingreader.model.Channel;
+import org.robsite.jswingreader.model.ChannelListModel;
+import org.robsite.jswingreader.model.Item;
+import org.robsite.jswingreader.model.SimpleRSSParser;
+import org.robsite.jswingreader.ui.BlogContentPane;
+import org.robsite.jswingreader.ui.ItemReadTimer;
+import org.robsite.jswingreader.ui.Main;
+import org.robsite.jswingreader.ui.util.ContextMenuMouseAdapter;
+import org.robsite.jswingreader.util.BrowserUtils;
+
+import quicktime.std.movies.media.TextDescription;
+
+/**
+ * Blog reading window, adapted from JSwingReader's
+ * org.robsite.jswingreader.ui.MainWindow class
+ */
+
+public class BlogReader extends GBlogReader
+{
+  private JButton buttonAbout = new JButton();
+
+  private JButton buttonRefresh = new JButton();
+
+  private JToolBar toolBar = new JToolBar();
+
+  private JLabel statusBar = new JLabel();
+
+  private JPanel panelMain = new JPanel();
+
+  private BorderLayout layoutMain = new BorderLayout();
+
+  private BorderLayout borderLayout1 = new BorderLayout();
+
+  private JPanel topPanel = new JPanel();
+
+  private JPanel bottomPanel = new JPanel();
+
+  private BorderLayout borderLayout2 = new BorderLayout();
+
+  private BorderLayout borderLayout3 = new BorderLayout();
+
+  private JSplitPane topBottomSplitPane = new JSplitPane();
+
+  private JList listItems = new JList(new DefaultListModel());
+
+  // SWITCH IN JALVIEW HTML VIEWER PANE HERE
+  private BlogContentPane textDescription = new BlogContentPane();
+
+  // ADD IN JALVIEW BANNER FOR PRETTINESS
+  private BorderLayout borderLayout4 = new BorderLayout();
+
+  private BorderLayout borderLayout5 = new BorderLayout();
+
+  private ChannelListModel _channelModel = null;
+
+  private JList listChannels = new JList();
+
+  private Action exitAction = new Action()
+  {
+
+    @Override
+    public void actionPerformed(ActionEvent arg0)
+    {
+      setVisible(false);
+      if (parent != null)
+      {
+        parent.showNews(false);
+      }
+
+    }
+
+    @Override
+    public void setEnabled(boolean arg0)
+    {
+
+    }
+
+    @Override
+    public void removePropertyChangeListener(PropertyChangeListener arg0)
+    {
+      // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public void putValue(String arg0, Object arg1)
+    {
+      // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public boolean isEnabled()
+    {
+      // TODO Auto-generated method stub
+      return true;
+    }
+
+    @Override
+    public Object getValue(String arg0)
+    {
+      // TODO Auto-generated method stub
+      return null;
+    }
+
+    @Override
+    public void addPropertyChangeListener(PropertyChangeListener arg0)
+    {
+      // TODO Auto-generated method stub
+
+    }
+  };
+
+  private JLabel lblChannels = new JLabel();
+
+  private List _updatableActions = new ArrayList();
+
+  private ItemReadTimer _itemTimer = null;
+
+  private JPopupMenu _popupItems = null;
+
+  private JPopupMenu _popupChannels = null;
+
+  private String lastm = "";
+
+  private boolean newsnew = false;
+
+  private Desktop parent = null;
+
+  BlogReader()
+  {
+    this(null);
+  }
+
+  // should we ignore fake gui events
+  private boolean updating = false;
+
+  public BlogReader(Desktop desktop)
+  {
+    parent = desktop;
+    if (parent == null)
+    {
+      this.setSize(new Dimension(550, 350));
+    }
+    else
+    {
+      Rectangle bounds = parent
+              .getLastKnownDimensions("JALVIEW_RSS_WINDOW_");
+      if (bounds == null)
+      {
+        setBounds(parent.getX(), parent.getY(), 550, 350);
+      }
+      else
+      {
+        setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
+      }
+    }
+    _channelModel = new ChannelListModel();
+    // Construct our jalview news channel
+    Channel chan = new Channel();
+    chan.setURL(jalview.bin.Cache.getDefault(
+            "JALVIEW_NEWS_RSS",
+            jalview.bin.Cache.getDefault("www.jalview.org",
+                    "http://www.jalview.org") + "/feeds/desktop/rss"));
+    loadLastM();
+    _channelModel.addChannel(chan);
+    updating = true;
+    try
+    {
+      jbInit();
+      postInit();
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+
+    initItems(chan);
+    updating = false;
+    boolean setvisible = checkForNew(chan, true);
+    if (setvisible)
+    {
+      Cache.log.info("Will show jalview news automatically");
+      SwingUtilities.invokeLater(new Runnable()
+      {
+        @Override
+        public void run()
+        {
+          if (parent != null)
+          {
+            parent.showNews(true);
+          }
+          else
+          {
+            setVisible(true);
+          }
+        }
+      });
+    }
+  }
+
+  /**
+   * update hasnew flag and mark all new messages as unread.
+   */
+  private boolean checkForNew(Channel chan, boolean updateItems)
+  {
+    if (!updating || updateItems)
+    {
+      newsnew = false;
+    }
+    if (chan != null && chan.getItems() != null)
+    {
+      for (Item i : (List<Item>) chan.getItems())
+      {
+        boolean isread = (lastDate != null && i.getPublishDate() != null && !lastDate
+                .before(i.getPublishDate()));
+
+        if (i.getPublishDate() != null && (!updating || updateItems))
+        {
+          newsnew |= !isread;
+        }
+        if (updateItems)
+        {
+          i.setRead(isread);
+        }
+      }
+    }
+    return newsnew;
+  }
+
+  java.util.Date lastDate = null;
+
+  private void loadLastM()
+  {
+    lastDate = Cache.getDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED");
+  }
+
+  private void saveLastM(Item item)
+  {
+    if (item != null && item.getPublishDate() != null
+            && (lastDate == null || item.getPublishDate().after(lastDate)))
+    {
+      lastDate = item.getPublishDate();
+      if (lastDate != null)
+      {
+        jalview.bin.Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED",
+                lastDate);
+        jalview.bin.Cache.log.info("Saved last read date as "
+                + jalview.bin.Cache.date_format.format(lastDate));
+
+      }
+      if (_channelModel.getElementAt(0) != null)
+      {
+        checkForNew((Channel) _channelModel.getElementAt(0), false);
+      }
+    }
+  }
+
+  private void jbInit() throws Exception
+  {
+    this.setTitle("News from www.jalview.org");
+    this.getContentPane().setLayout(layoutMain);
+    panelMain.setLayout(borderLayout1);
+    topPanel.setLayout(borderLayout5);
+    bottomPanel.setLayout(borderLayout4);
+    topBottomSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
+    topBottomSplitPane.setDividerLocation(100);
+    topBottomSplitPane.setTopComponent(topPanel);
+    topBottomSplitPane.setBottomComponent(bottomPanel);
+    JScrollPane spTextDescription = new JScrollPane(textDescription);
+    textDescription.setText("");
+    statusBar.setText(" [Status] ");
+    buttonRefresh.addActionListener(new ActionListener()
+    {
+      
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        refreshNews();
+      }
+    });
+    this.getContentPane().add(statusBar, BorderLayout.SOUTH);
+    toolBar.add(buttonRefresh);
+    toolBar.addSeparator();
+    JLabel about=new JLabel("brought to you by JSwingReader (jswingreader.sourceforge.net)");
+    toolBar.add(about);
+    toolBar.setFloatable(false);
+    this.getContentPane().add(toolBar, BorderLayout.NORTH);
+    panelMain.add(topBottomSplitPane, BorderLayout.CENTER);
+    this.getContentPane().add(panelMain, BorderLayout.CENTER);
+    JScrollPane spListItems = new JScrollPane(listItems);
+    listItems
+            .setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
+    topPanel.add(spListItems, BorderLayout.CENTER);
+    bottomPanel.add(spTextDescription, BorderLayout.CENTER);
+    listChannels.setModel(_channelModel);
+
+    listItems.addMouseListener(new java.awt.event.MouseAdapter()
+    {
+      public void mouseClicked(MouseEvent e)
+      {
+        listItems_mouseClicked(e);
+      }
+    });
+    _popupItems = _buildItemsPopupMenu();
+    _popupChannels = _buildChannelsPopupMenu();
+    ContextMenuMouseAdapter popupAdapter = new ContextMenuMouseAdapter(
+            _popupItems);
+    ContextMenuMouseAdapter popupChannelsAdapter = new ContextMenuMouseAdapter(
+            _popupChannels);
+    listItems.addMouseListener(popupAdapter);
+    listItems.setCellRenderer(new ItemsRenderer());
+    lblChannels.setText("Channels");
+  }
+
+  private void postInit()
+  {
+    // clear the default hyperlink listener and replace with our own.
+    for (HyperlinkListener hll : textDescription.getHyperlinkListeners())
+    {
+      textDescription.removeHyperlinkListener(hll);
+    }
+    textDescription.addHyperlinkListener(new HyperlinkListener()
+    {
+      public void hyperlinkUpdate(HyperlinkEvent e)
+      {
+        if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
+        {
+          Desktop.showUrl(e.getURL().toExternalForm());
+        }
+      }
+    });
+
+    this.addWindowListener(new WindowAdapter()
+    {
+      public void windowClosing(WindowEvent e)
+      {
+        ActionEvent actionEvent = new ActionEvent(this,
+                ActionEvent.ACTION_FIRST, (String) exitAction
+                        .getValue(Action.NAME));
+        exitAction.actionPerformed(actionEvent);
+      }
+
+      public void windowOpened(WindowEvent e)
+      {
+      }
+    });
+
+    listItems.addListSelectionListener(new ListSelectionListener()
+    {
+      public void valueChanged(ListSelectionEvent e)
+      {
+        if (e.getValueIsAdjusting() == false)
+        {
+          _itemsValueChanged(listItems);
+        }
+      }
+    });
+    listChannels.setSelectedIndex(1);
+    _updateAllActions();
+    _updateToolbarButtons();
+
+    _itemTimer = new ItemReadTimer(listChannels, listItems);
+    _itemsValueChanged(listItems);
+  }
+
+  public class LaunchJvBrowserOnItem extends AbstractAction implements
+          UpdatableAction
+  {
+    JList _listItems = null;
+
+    public LaunchJvBrowserOnItem(JList listItems)
+    {
+      super("Open in Browser");
+      this.putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_O));
+      this.putValue(Action.LONG_DESCRIPTION, "Open in Browser");
+      _listItems = listItems;
+    }
+
+    public void actionPerformed(ActionEvent e)
+    {
+      Object o = _listItems.getSelectedValue();
+      if (o instanceof Item)
+      {
+        Item item = (Item) o;
+        item.setRead(true);
+        _listItems.repaint();
+
+        Desktop.showUrl(item.getLink());
+      }
+    }
+
+    public void update(Object o)
+    {
+      setEnabled(true);
+      if (_listItems == null || _listItems.getModel().getSize() == 0)
+      {
+        setEnabled(false);
+      }
+      else if (_listItems.getSelectedIndex() == -1)
+      {
+        setEnabled(false);
+      }
+    }
+
+  }
+
+  private JPopupMenu _buildItemsPopupMenu()
+  {
+    JPopupMenu popup = new JPopupMenu();
+    popup.add(new JMenuItem(new LaunchJvBrowserOnItem(listItems)));
+    popup.addSeparator();
+    popup.add(new JMenuItem(new MarkItemAsRead(listItems)));
+    popup.add(new JMenuItem(new MarkItemAsUnread(listItems)));
+    return popup;
+  }
+
+  private JPopupMenu _buildChannelsPopupMenu()
+  {
+    JPopupMenu popup = new JPopupMenu();
+    popup.add(new JMenuItem(new MarkChannelAsRead(listChannels, listItems)));
+    popup.add(new JMenuItem(
+            new MarkChannelAsUnread(listChannels, listItems)));
+    return popup;
+  }
+
+  private void initItems(Channel channel)
+  {
+    if (channel == null)
+    {
+      channel = new Channel();
+    }
+    if (!channel.isOpen() && channel.getURL() != null)
+    {
+      try
+      {
+        SimpleRSSParser.parse(channel);
+      } catch (Exception ex)
+      {
+        ex.printStackTrace();
+      }
+    }
+    DefaultListModel itemsModel = (DefaultListModel) listItems.getModel();
+    itemsModel.clear();
+    Iterator iter = (channel.getItems() != null) ? channel.getItems()
+            .iterator() : Collections.EMPTY_LIST.iterator();
+    while (iter.hasNext())
+    {
+      itemsModel.addElement(iter.next());
+    }
+    if (itemsModel.getSize() > 0)
+    {
+      listItems.setSelectedIndex(0);
+      _itemsValueChanged(listItems);
+    }
+    setStatusBarText(channel.getURL());
+    _updateAllActions();
+  }
+
+  private void _itemsValueChanged(JList itemList)
+  {
+    Item item = (Item) itemList.getSelectedValue();
+    if (item == null)
+    {
+      if (itemList.getModel().getSize() > 0)
+      {
+        item = (Item) itemList.getModel().getElementAt(0);
+      }
+      if (item == null)
+      {
+        item = new Item();
+      }
+      else
+      {
+        itemList.setSelectedIndex(0);
+      }
+    }
+
+    if (_itemTimer != null)
+    {
+      // prefer a shorter delay than 5s
+      _itemTimer.setDelay(300);
+      _itemTimer.start();
+      _itemTimer.setLastItem(item);
+      final Item lastitem = item;
+      _itemTimer.addActionListener(new ActionListener()
+      {
+
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          saveLastM(lastitem);
+        }
+      });
+    }
+
+    setStatusBarText(item.getLink());
+    textDescription.setBlogText(item);
+    _updateAllActions();
+  }
+
+  public void setStatusBarText(String text)
+  {
+    statusBar.setText(text);
+  }
+
+  private void _updateAllActions()
+  {
+    Iterator iter = _updatableActions.iterator();
+    while (iter.hasNext())
+    {
+      UpdatableAction action = (UpdatableAction) iter.next();
+      action.update(this);
+    }
+  }
+
+  private void _updateToolbarButtons()
+  {
+    Map general = (Map) Main.getPreferences().get("general");
+    if (general == null)
+    {
+      return;
+    }
+
+    Component[] components = toolBar.getComponents();
+    for (int i = 0; i < components.length; i++)
+    {
+      Component component = components[i];
+      if (component instanceof JButton)
+      {
+        JButton button = (JButton) component;
+        if (Boolean.toString(false).equals(general.get("useToolBarText")))
+        {
+          // Remove the text if preferences state no toolbar text
+          button.setText("");
+        }
+        if (Boolean.toString(true).equals(general.get("radioTextBelow")))
+        {
+          button.setVerticalTextPosition(AbstractButton.BOTTOM);
+          button.setHorizontalTextPosition(AbstractButton.CENTER);
+        }
+        else if (Boolean.toString(true).equals(
+                general.get("radioTextRight")))
+        {
+          button.setVerticalTextPosition(AbstractButton.CENTER);
+          button.setHorizontalTextPosition(AbstractButton.RIGHT);
+        }
+      }
+    }
+  }
+
+  private void listItems_mouseClicked(MouseEvent e)
+  {
+    if (e.getClickCount() == 2 && e.getModifiersEx() == MouseEvent.NOBUTTON)
+    {
+      Item item = (Item) listItems.getSelectedValue();
+      item.setRead(true);
+      saveLastM(item);
+      if (_itemTimer != null)
+      {
+        _itemTimer.stop();
+      }
+
+      Action action = new LaunchJvBrowserOnItem(listItems);
+      ActionEvent event = new ActionEvent(this,
+              ActionEvent.ACTION_PERFORMED, "LaunchBrowserOnItem");
+      action.actionPerformed(event);
+    }
+  }
+
+  /**
+   * force the news panel to refresh
+   */
+  public void refreshNews()
+  {
+    try {
+      initItems((Channel)_channelModel.getElementAt(0));
+      
+    } catch (Exception x)
+    {}
+  }
+
+  public static void main(String args[])
+  {
+    // this tests the detection of new news based on the last read date stored
+    // in jalview properties
+    jalview.bin.Cache.loadProperties(null);
+    jalview.bin.Cache.initLogger();
+    // test will advance read date each time
+    Calendar today = Calendar.getInstance(), lastread = Calendar
+            .getInstance();
+    lastread.set(1983, 01, 01);
+    while (lastread.before(today))
+    {
+      Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED",
+              lastread.getTime());
+      BlogReader me = new BlogReader();
+      System.out.println("Set last date to "
+              + jalview.bin.Cache.date_format.format(lastread.getTime()));
+      if (me.isNewsNew())
+      {
+        Cache.log.info("There is news to read.");
+      }
+      else
+      {
+        Cache.log.info("There is no new news.");
+      }
+      me.setTitle("Testing : Last read is " + me.lastDate);
+      me.setVisible(true);
+      me.toFront();
+      while (me.isVisible())
+      {
+        try
+        {
+          Thread.sleep(100);
+        } catch (InterruptedException x)
+        {
+        }
+        ;
+      }
+      if (me.isNewsNew())
+      {
+        Cache.log.info("Still new news after reader displayed.");
+      }
+      if (lastread.getTime().before(me.lastDate))
+      {
+        Cache.log.info("The news was read.");
+        lastread.setTime(me.lastDate);
+      }
+      else
+      {
+        lastread.add(Calendar.MONTH, 1);
+      }
+      me.dispose();
+    }
+  }
+
+  boolean isNewsNew()
+  {
+    return newsnew;
+  }
+}
+
+class ChannelsRenderer extends DefaultListCellRenderer
+{
+  private final static Icon _icon = new ImageIcon(
+          Main.class.getResource("image/ComposeMail16.gif"));
+
+  public Component getListCellRendererComponent(JList list, Object value,
+          int index, boolean isSelected, boolean cellHasFocus)
+  {
+    JLabel component = (JLabel) super.getListCellRendererComponent(list,
+            value, index, isSelected, cellHasFocus);
+    component.setIcon(ChannelsRenderer._icon);
+    if (value instanceof Channel)
+    {
+      Channel channel = (Channel) value;
+      component.setText(channel.getTitle() + " ("
+              + channel.getUnreadItemCount() + ")");
+      component.setToolTipText(channel.getURL());
+    }
+    return component;
+  }
+}
+
+class ItemsRenderer extends DefaultListCellRenderer
+{
+  private final static Icon _icon = new ImageIcon(
+          Main.class.getResource("image/ComposeMail16.gif"));
+
+  public Component getListCellRendererComponent(JList list, Object value,
+          int index, boolean isSelected, boolean cellHasFocus)
+  {
+    JLabel component = (JLabel) super.getListCellRendererComponent(list,
+            value, index, isSelected, cellHasFocus);
+    component.setIcon(ItemsRenderer._icon);
+    if (value instanceof Item)
+    {
+      Item item = (Item) value;
+      if (item.getPublishDate() != null)
+      {
+        component.setText(DateFormat.getDateInstance().format(
+                item.getPublishDate())
+                + " " + item.getTitle());
+      }
+      component.setToolTipText(item.getLink());
+      if (!item.isRead())
+      {
+        component.setFont(component.getFont().deriveFont(Font.BOLD));
+      }
+      else
+      {
+        component.setFont(component.getFont().deriveFont(Font.PLAIN));
+      }
+    }
+    return component;
+  }
+}
index 3796b08..a5778a7 100644 (file)
@@ -57,6 +57,11 @@ public class Desktop extends jalview.jbgui.GDesktop implements
   private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
 
   /**
+   * news reader - null if it was never started.
+   */
+  private BlogReader jvnews=null;
+
+  /**
    * @param listener
    * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
    */
@@ -267,6 +272,18 @@ public class Desktop extends jalview.jbgui.GDesktop implements
 
     showConsole(showjconsole);
 
+    showNews.setVisible(false);
+    final Desktop me = this;
+    // Thread off the news reader, in case there are connection problems.
+    new Thread( new Runnable() {
+      @Override
+      public void run()
+      {
+        jvnews = new BlogReader(me);
+        showNews.setVisible(true);
+      }
+    }).start();
+    
     this.addWindowListener(new WindowAdapter()
     {
       public void windowClosing(WindowEvent evt)
@@ -328,6 +345,22 @@ public class Desktop extends jalview.jbgui.GDesktop implements
             });
   }
 
+  protected void showNews_actionPerformed(ActionEvent e)
+  {
+    showNews(showNews.isSelected());
+  }
+  void showNews(boolean default1)
+  {
+    {
+      jvnews.setVisible(default1);
+      if (default1)
+      {
+        jvnews.refreshNews();
+        jvnews.toFront();
+      }
+    }
+  }
+
   /**
    * recover the last known dimensions for a jalview window
    * 
@@ -914,6 +947,12 @@ public class Desktop extends jalview.jbgui.GDesktop implements
       storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
       jconsole.stopConsole();
     }
+    if (jvnews!=null)
+    {
+      storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
+      
+    }
+      
     System.exit(0);
   }
 
diff --git a/src/jalview/jbgui/GBlogReader.java b/src/jalview/jbgui/GBlogReader.java
new file mode 100644 (file)
index 0000000..c27f4b1
--- /dev/null
@@ -0,0 +1,8 @@
+package jalview.jbgui;
+
+import javax.swing.JFrame;
+
+public class GBlogReader extends JFrame
+{
+
+}
index 5effdbd..fc3f358 100755 (executable)
@@ -88,6 +88,8 @@ public class GDesktop extends JFrame
 
   protected JCheckBoxMenuItem showConsole = new JCheckBoxMenuItem();
 
+  protected JCheckBoxMenuItem showNews = new JCheckBoxMenuItem();
+
   /**
    * Creates a new GDesktop object.
    */
@@ -306,6 +308,14 @@ public class GDesktop extends JFrame
         showConsole_actionPerformed(e);
       }
     });
+    showNews.setText("Show Jalview News");
+    showNews.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        showNews_actionPerformed(e);
+      }
+    });
     desktopMenubar.add(FileMenu);
     desktopMenubar.add(toolsMenu);
     VamsasMenu.setVisible(false);
@@ -330,6 +340,7 @@ public class GDesktop extends JFrame
     toolsMenu.add(preferences);
     toolsMenu.add(showMemusage);
     toolsMenu.add(showConsole);
+    toolsMenu.add(showNews);
     toolsMenu.add(garbageCollect);
     inputMenu.add(inputLocalFileMenuItem);
     inputMenu.add(inputURLMenuItem);
@@ -346,7 +357,11 @@ public class GDesktop extends JFrame
     // TODO Auto-generated method stub
 
   }
+  protected void showNews_actionPerformed(ActionEvent e)
+  {
+    // TODO Auto-generated method stub
 
+  }
   protected void showMemusage_actionPerformed(ActionEvent e)
   {
     // TODO Auto-generated method stub