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;
49 import javax.swing.text.DateFormatter;
51 import org.robsite.jswingreader.action.AboutAction;
52 import org.robsite.jswingreader.action.MarkChannelAsRead;
53 import org.robsite.jswingreader.action.MarkChannelAsUnread;
54 import org.robsite.jswingreader.action.MarkItemAsRead;
55 import org.robsite.jswingreader.action.MarkItemAsUnread;
56 import org.robsite.jswingreader.action.RefreshChannelAction;
57 import org.robsite.jswingreader.action.UpdatableAction;
58 import org.robsite.jswingreader.model.Channel;
59 import org.robsite.jswingreader.model.ChannelListModel;
60 import org.robsite.jswingreader.model.Item;
61 import org.robsite.jswingreader.model.SimpleRSSParser;
62 import org.robsite.jswingreader.ui.BlogContentPane;
63 import org.robsite.jswingreader.ui.ItemReadTimer;
64 import org.robsite.jswingreader.ui.Main;
65 import org.robsite.jswingreader.ui.util.ContextMenuMouseAdapter;
66 import org.robsite.jswingreader.util.BrowserUtils;
68 import quicktime.std.movies.media.TextDescription;
71 * Blog reading window, adapted from JSwingReader's
72 * org.robsite.jswingreader.ui.MainWindow class
75 public class BlogReader extends GBlogReader
77 private JButton buttonAbout = new JButton();
79 private JButton buttonRefresh = new JButton();
81 private JToolBar toolBar = new JToolBar();
83 private JLabel statusBar = new JLabel();
85 private JPanel panelMain = new JPanel();
87 private BorderLayout layoutMain = new BorderLayout();
89 private BorderLayout borderLayout1 = new BorderLayout();
91 private JPanel topPanel = new JPanel();
93 private JPanel bottomPanel = new JPanel();
95 private BorderLayout borderLayout2 = new BorderLayout();
97 private BorderLayout borderLayout3 = new BorderLayout();
99 private JSplitPane topBottomSplitPane = new JSplitPane();
101 private JList listItems = new JList(new DefaultListModel());
103 // SWITCH IN JALVIEW HTML VIEWER PANE HERE
104 private BlogContentPane textDescription = new BlogContentPane();
106 // ADD IN JALVIEW BANNER FOR PRETTINESS
107 private BorderLayout borderLayout4 = new BorderLayout();
109 private BorderLayout borderLayout5 = new BorderLayout();
111 private ChannelListModel _channelModel = null;
113 private JList listChannels = new JList();
115 private Action exitAction = new Action()
119 public void actionPerformed(ActionEvent arg0)
124 parent.showNews(false);
130 public void setEnabled(boolean arg0)
136 public void removePropertyChangeListener(PropertyChangeListener arg0)
138 // TODO Auto-generated method stub
143 public void putValue(String arg0, Object arg1)
145 // TODO Auto-generated method stub
150 public boolean isEnabled()
152 // TODO Auto-generated method stub
157 public Object getValue(String arg0)
159 // TODO Auto-generated method stub
164 public void addPropertyChangeListener(PropertyChangeListener arg0)
166 // TODO Auto-generated method stub
171 private JLabel lblChannels = new JLabel();
173 private List _updatableActions = new ArrayList();
175 private ItemReadTimer _itemTimer = null;
177 private JPopupMenu _popupItems = null;
179 private JPopupMenu _popupChannels = null;
181 private String lastm = "";
183 private boolean newsnew = false;
185 private Desktop parent = null;
192 // should we ignore fake gui events
193 private boolean updating = false;
195 public BlogReader(Desktop desktop)
200 this.setSize(new Dimension(550, 350));
204 Rectangle bounds = parent
205 .getLastKnownDimensions("JALVIEW_RSS_WINDOW_");
208 setBounds(parent.getX(), parent.getY(), 550, 350);
212 setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
215 _channelModel = new ChannelListModel();
216 // Construct our jalview news channel
217 Channel chan = new Channel();
218 chan.setURL(jalview.bin.Cache.getDefault(
220 jalview.bin.Cache.getDefault("www.jalview.org",
221 "http://www.jalview.org") + "/feeds/desktop/rss"));
223 _channelModel.addChannel(chan);
229 } catch (Exception e)
236 boolean setvisible = checkForNew(chan, true);
239 Cache.log.info("Will show jalview news automatically");
240 SwingUtilities.invokeLater(new Runnable()
247 parent.showNews(true);
259 * update hasnew flag and mark all new messages as unread.
261 private boolean checkForNew(Channel chan, boolean updateItems)
263 if (!updating || updateItems)
267 if (chan != null && chan.getItems() != null)
269 for (Item i : (List<Item>) chan.getItems())
271 boolean isread = (lastDate != null && i.getPublishDate() != null && !lastDate
272 .before(i.getPublishDate()));
274 if (i.getPublishDate() != null && (!updating || updateItems))
287 java.util.Date lastDate = null;
289 private void loadLastM()
291 lastDate = Cache.getDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED");
294 private void saveLastM(Item item)
296 if (item != null && item.getPublishDate() != null
297 && (lastDate == null || item.getPublishDate().after(lastDate)))
299 lastDate = item.getPublishDate();
300 if (lastDate != null)
302 jalview.bin.Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED",
304 jalview.bin.Cache.log.info("Saved last read date as "
305 + jalview.bin.Cache.date_format.format(lastDate));
308 if (_channelModel.getElementAt(0) != null)
310 checkForNew((Channel) _channelModel.getElementAt(0), false);
315 private void jbInit() throws Exception
317 this.setTitle("News from www.jalview.org");
318 this.getContentPane().setLayout(layoutMain);
319 panelMain.setLayout(borderLayout1);
320 topPanel.setLayout(borderLayout5);
321 bottomPanel.setLayout(borderLayout4);
322 topBottomSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
323 topBottomSplitPane.setDividerLocation(100);
324 topBottomSplitPane.setTopComponent(topPanel);
325 topBottomSplitPane.setBottomComponent(bottomPanel);
326 JScrollPane spTextDescription = new JScrollPane(textDescription);
327 textDescription.setText("");
328 statusBar.setText(" [Status] ");
329 buttonRefresh.addActionListener(new ActionListener()
333 public void actionPerformed(ActionEvent e)
338 this.getContentPane().add(statusBar, BorderLayout.SOUTH);
339 toolBar.add(buttonRefresh);
340 toolBar.addSeparator();
341 JLabel about=new JLabel("brought to you by JSwingReader (jswingreader.sourceforge.net)");
343 toolBar.setFloatable(false);
344 this.getContentPane().add(toolBar, BorderLayout.NORTH);
345 panelMain.add(topBottomSplitPane, BorderLayout.CENTER);
346 this.getContentPane().add(panelMain, BorderLayout.CENTER);
347 JScrollPane spListItems = new JScrollPane(listItems);
349 .setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
350 topPanel.add(spListItems, BorderLayout.CENTER);
351 bottomPanel.add(spTextDescription, BorderLayout.CENTER);
352 listChannels.setModel(_channelModel);
354 listItems.addMouseListener(new java.awt.event.MouseAdapter()
356 public void mouseClicked(MouseEvent e)
358 listItems_mouseClicked(e);
361 _popupItems = _buildItemsPopupMenu();
362 _popupChannels = _buildChannelsPopupMenu();
363 ContextMenuMouseAdapter popupAdapter = new ContextMenuMouseAdapter(
365 ContextMenuMouseAdapter popupChannelsAdapter = new ContextMenuMouseAdapter(
367 listItems.addMouseListener(popupAdapter);
368 listItems.setCellRenderer(new ItemsRenderer());
369 lblChannels.setText("Channels");
372 private void postInit()
374 // clear the default hyperlink listener and replace with our own.
375 for (HyperlinkListener hll : textDescription.getHyperlinkListeners())
377 textDescription.removeHyperlinkListener(hll);
379 textDescription.addHyperlinkListener(new HyperlinkListener()
381 public void hyperlinkUpdate(HyperlinkEvent e)
383 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
385 Desktop.showUrl(e.getURL().toExternalForm());
390 this.addWindowListener(new WindowAdapter()
392 public void windowClosing(WindowEvent e)
394 ActionEvent actionEvent = new ActionEvent(this,
395 ActionEvent.ACTION_FIRST, (String) exitAction
396 .getValue(Action.NAME));
397 exitAction.actionPerformed(actionEvent);
400 public void windowOpened(WindowEvent e)
405 listItems.addListSelectionListener(new ListSelectionListener()
407 public void valueChanged(ListSelectionEvent e)
409 if (e.getValueIsAdjusting() == false)
411 _itemsValueChanged(listItems);
415 listChannels.setSelectedIndex(1);
417 _updateToolbarButtons();
419 _itemTimer = new ItemReadTimer(listChannels, listItems);
420 _itemsValueChanged(listItems);
423 public class LaunchJvBrowserOnItem extends AbstractAction implements
426 JList _listItems = null;
428 public LaunchJvBrowserOnItem(JList listItems)
430 super("Open in Browser");
431 this.putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_O));
432 this.putValue(Action.LONG_DESCRIPTION, "Open in Browser");
433 _listItems = listItems;
436 public void actionPerformed(ActionEvent e)
438 Object o = _listItems.getSelectedValue();
439 if (o instanceof Item)
441 Item item = (Item) o;
443 _listItems.repaint();
445 Desktop.showUrl(item.getLink());
449 public void update(Object o)
452 if (_listItems == null || _listItems.getModel().getSize() == 0)
456 else if (_listItems.getSelectedIndex() == -1)
464 private JPopupMenu _buildItemsPopupMenu()
466 JPopupMenu popup = new JPopupMenu();
467 popup.add(new JMenuItem(new LaunchJvBrowserOnItem(listItems)));
468 popup.addSeparator();
469 popup.add(new JMenuItem(new MarkItemAsRead(listItems)));
470 popup.add(new JMenuItem(new MarkItemAsUnread(listItems)));
474 private JPopupMenu _buildChannelsPopupMenu()
476 JPopupMenu popup = new JPopupMenu();
477 popup.add(new JMenuItem(new MarkChannelAsRead(listChannels, listItems)));
478 popup.add(new JMenuItem(
479 new MarkChannelAsUnread(listChannels, listItems)));
483 private void initItems(Channel channel)
487 channel = new Channel();
489 if (!channel.isOpen() && channel.getURL() != null)
493 SimpleRSSParser.parse(channel);
494 } catch (Exception ex)
496 ex.printStackTrace();
499 DefaultListModel itemsModel = (DefaultListModel) listItems.getModel();
501 Iterator iter = (channel.getItems() != null) ? channel.getItems()
502 .iterator() : Collections.EMPTY_LIST.iterator();
503 while (iter.hasNext())
505 itemsModel.addElement(iter.next());
507 if (itemsModel.getSize() > 0)
509 listItems.setSelectedIndex(0);
510 _itemsValueChanged(listItems);
512 setStatusBarText(channel.getURL());
516 private void _itemsValueChanged(JList itemList)
518 Item item = (Item) itemList.getSelectedValue();
521 if (itemList.getModel().getSize() > 0)
523 item = (Item) itemList.getModel().getElementAt(0);
531 itemList.setSelectedIndex(0);
535 if (_itemTimer != null)
537 // prefer a shorter delay than 5s
538 _itemTimer.setDelay(300);
540 _itemTimer.setLastItem(item);
541 final Item lastitem = item;
542 _itemTimer.addActionListener(new ActionListener()
546 public void actionPerformed(ActionEvent e)
553 setStatusBarText(item.getLink());
554 textDescription.setBlogText(item);
558 public void setStatusBarText(String text)
560 statusBar.setText(text);
563 private void _updateAllActions()
565 Iterator iter = _updatableActions.iterator();
566 while (iter.hasNext())
568 UpdatableAction action = (UpdatableAction) iter.next();
573 private void _updateToolbarButtons()
575 Map general = (Map) Main.getPreferences().get("general");
581 Component[] components = toolBar.getComponents();
582 for (int i = 0; i < components.length; i++)
584 Component component = components[i];
585 if (component instanceof JButton)
587 JButton button = (JButton) component;
588 if (Boolean.toString(false).equals(general.get("useToolBarText")))
590 // Remove the text if preferences state no toolbar text
593 if (Boolean.toString(true).equals(general.get("radioTextBelow")))
595 button.setVerticalTextPosition(AbstractButton.BOTTOM);
596 button.setHorizontalTextPosition(AbstractButton.CENTER);
598 else if (Boolean.toString(true).equals(
599 general.get("radioTextRight")))
601 button.setVerticalTextPosition(AbstractButton.CENTER);
602 button.setHorizontalTextPosition(AbstractButton.RIGHT);
608 private void listItems_mouseClicked(MouseEvent e)
610 if (e.getClickCount() == 2 && e.getModifiersEx() == MouseEvent.NOBUTTON)
612 Item item = (Item) listItems.getSelectedValue();
615 if (_itemTimer != null)
620 Action action = new LaunchJvBrowserOnItem(listItems);
621 ActionEvent event = new ActionEvent(this,
622 ActionEvent.ACTION_PERFORMED, "LaunchBrowserOnItem");
623 action.actionPerformed(event);
628 * force the news panel to refresh
630 public void refreshNews()
633 initItems((Channel)_channelModel.getElementAt(0));
635 } catch (Exception x)
639 public static void main(String args[])
641 // this tests the detection of new news based on the last read date stored
642 // in jalview properties
643 jalview.bin.Cache.loadProperties(null);
644 jalview.bin.Cache.initLogger();
645 // test will advance read date each time
646 Calendar today = Calendar.getInstance(), lastread = Calendar
648 lastread.set(1983, 01, 01);
649 while (lastread.before(today))
651 Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED",
653 BlogReader me = new BlogReader();
654 System.out.println("Set last date to "
655 + jalview.bin.Cache.date_format.format(lastread.getTime()));
658 Cache.log.info("There is news to read.");
662 Cache.log.info("There is no new news.");
664 me.setTitle("Testing : Last read is " + me.lastDate);
667 while (me.isVisible())
672 } catch (InterruptedException x)
679 Cache.log.info("Still new news after reader displayed.");
681 if (lastread.getTime().before(me.lastDate))
683 Cache.log.info("The news was read.");
684 lastread.setTime(me.lastDate);
688 lastread.add(Calendar.MONTH, 1);
700 class ChannelsRenderer extends DefaultListCellRenderer
702 private final static Icon _icon = new ImageIcon(
703 Main.class.getResource("image/ComposeMail16.gif"));
705 public Component getListCellRendererComponent(JList list, Object value,
706 int index, boolean isSelected, boolean cellHasFocus)
708 JLabel component = (JLabel) super.getListCellRendererComponent(list,
709 value, index, isSelected, cellHasFocus);
710 component.setIcon(ChannelsRenderer._icon);
711 if (value instanceof Channel)
713 Channel channel = (Channel) value;
714 component.setText(channel.getTitle() + " ("
715 + channel.getUnreadItemCount() + ")");
716 component.setToolTipText(channel.getURL());
722 class ItemsRenderer extends DefaultListCellRenderer
724 private final static Icon _icon = new ImageIcon(
725 Main.class.getResource("image/ComposeMail16.gif"));
727 public Component getListCellRendererComponent(JList list, Object value,
728 int index, boolean isSelected, boolean cellHasFocus)
730 JLabel component = (JLabel) super.getListCellRendererComponent(list,
731 value, index, isSelected, cellHasFocus);
732 component.setIcon(ItemsRenderer._icon);
733 if (value instanceof Item)
735 Item item = (Item) value;
736 if (item.getPublishDate() != null)
738 component.setText(DateFormat.getDateInstance().format(
739 item.getPublishDate())
740 + " " + item.getTitle());
742 component.setToolTipText(item.getLink());
745 component.setFont(component.getFont().deriveFont(Font.BOLD));
749 component.setFont(component.getFont().deriveFont(Font.PLAIN));