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.util.ArrayList;
20 import java.util.Calendar;
21 import java.util.Collections;
22 import java.util.Iterator;
23 import java.util.List;
26 import javax.swing.AbstractAction;
27 import javax.swing.AbstractButton;
28 import javax.swing.Action;
29 import javax.swing.DefaultListCellRenderer;
30 import javax.swing.DefaultListModel;
31 import javax.swing.Icon;
32 import javax.swing.ImageIcon;
33 import javax.swing.JButton;
34 import javax.swing.JLabel;
35 import javax.swing.JList;
36 import javax.swing.JMenuItem;
37 import javax.swing.JPanel;
38 import javax.swing.JPopupMenu;
39 import javax.swing.JScrollPane;
40 import javax.swing.JSplitPane;
41 import javax.swing.JToolBar;
42 import javax.swing.ListSelectionModel;
43 import javax.swing.SwingUtilities;
44 import javax.swing.event.HyperlinkEvent;
45 import javax.swing.event.HyperlinkListener;
46 import javax.swing.event.ListSelectionEvent;
47 import javax.swing.event.ListSelectionListener;
49 import org.robsite.jswingreader.action.MarkChannelAsRead;
50 import org.robsite.jswingreader.action.MarkChannelAsUnread;
51 import org.robsite.jswingreader.action.MarkItemAsRead;
52 import org.robsite.jswingreader.action.MarkItemAsUnread;
53 import org.robsite.jswingreader.action.UpdatableAction;
54 import org.robsite.jswingreader.model.Channel;
55 import org.robsite.jswingreader.model.ChannelListModel;
56 import org.robsite.jswingreader.model.Item;
57 import org.robsite.jswingreader.model.SimpleRSSParser;
58 import org.robsite.jswingreader.ui.BlogContentPane;
59 import org.robsite.jswingreader.ui.ItemReadTimer;
60 import org.robsite.jswingreader.ui.Main;
61 import org.robsite.jswingreader.ui.util.ContextMenuMouseAdapter;
64 * Blog reading window, adapted from JSwingReader's
65 * org.robsite.jswingreader.ui.MainWindow class
68 public class BlogReader extends GBlogReader
70 private JButton buttonAbout = new JButton();
72 private JButton buttonRefresh = new JButton();
74 private JToolBar toolBar = new JToolBar();
76 private JLabel statusBar = new JLabel();
78 private JPanel panelMain = new JPanel();
80 private BorderLayout layoutMain = new BorderLayout();
82 private BorderLayout borderLayout1 = new BorderLayout();
84 private JPanel topPanel = new JPanel();
86 private JPanel bottomPanel = new JPanel();
88 private BorderLayout borderLayout2 = new BorderLayout();
90 private BorderLayout borderLayout3 = new BorderLayout();
92 private JSplitPane topBottomSplitPane = new JSplitPane();
94 private JList listItems = new JList(new DefaultListModel());
96 // SWITCH IN JALVIEW HTML VIEWER PANE HERE
97 private BlogContentPane textDescription = new BlogContentPane();
99 // ADD IN JALVIEW BANNER FOR PRETTINESS
100 private BorderLayout borderLayout4 = new BorderLayout();
102 private BorderLayout borderLayout5 = new BorderLayout();
104 private ChannelListModel _channelModel = null;
106 private JList listChannels = new JList();
108 private Action exitAction = new Action()
112 public void actionPerformed(ActionEvent arg0)
117 parent.showNews(false);
123 public void setEnabled(boolean arg0)
129 public void removePropertyChangeListener(PropertyChangeListener arg0)
131 // TODO Auto-generated method stub
136 public void putValue(String arg0, Object arg1)
138 // TODO Auto-generated method stub
143 public boolean isEnabled()
145 // TODO Auto-generated method stub
150 public Object getValue(String arg0)
152 // TODO Auto-generated method stub
157 public void addPropertyChangeListener(PropertyChangeListener arg0)
159 // TODO Auto-generated method stub
164 private JLabel lblChannels = new JLabel();
166 private List _updatableActions = new ArrayList();
168 private ItemReadTimer _itemTimer = null;
170 private JPopupMenu _popupItems = null;
172 private JPopupMenu _popupChannels = null;
174 private String lastm = "";
176 private boolean newsnew = false;
178 private Desktop parent = null;
185 // should we ignore fake gui events
186 private boolean updating = false;
188 public BlogReader(Desktop desktop)
193 this.setSize(new Dimension(550, 350));
197 Rectangle bounds = parent
198 .getLastKnownDimensions("JALVIEW_RSS_WINDOW_");
201 setBounds(parent.getX(), parent.getY(), 550, 350);
205 setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
208 _channelModel = new ChannelListModel();
209 // Construct our jalview news channel
210 Channel chan = new Channel();
211 chan.setURL(jalview.bin.Cache.getDefault(
213 jalview.bin.Cache.getDefault("www.jalview.org",
214 "http://www.jalview.org") + "/feeds/desktop/rss"));
216 _channelModel.addChannel(chan);
222 } catch (Exception e)
229 boolean setvisible = checkForNew(chan, true);
232 Cache.log.info("Will show jalview news automatically");
233 SwingUtilities.invokeLater(new Runnable()
240 parent.showNews(true);
252 * update hasnew flag and mark all new messages as unread.
254 private boolean checkForNew(Channel chan, boolean updateItems)
256 if (!updating || updateItems)
260 if (chan != null && chan.getItems() != null)
262 for (Item i : (List<Item>) chan.getItems())
264 boolean isread = (lastDate != null && i.getPublishDate() != null && !lastDate
265 .before(i.getPublishDate()));
267 if (i.getPublishDate() != null && (!updating || updateItems))
280 java.util.Date lastDate = null;
282 private void loadLastM()
284 lastDate = Cache.getDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED");
287 private void saveLastM(Item item)
289 if (item != null && item.getPublishDate() != null
290 && (lastDate == null || item.getPublishDate().after(lastDate)))
292 lastDate = item.getPublishDate();
293 if (lastDate != null)
295 jalview.bin.Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED",
297 jalview.bin.Cache.log.info("Saved last read date as "
298 + jalview.bin.Cache.date_format.format(lastDate));
301 if (_channelModel.getElementAt(0) != null)
303 checkForNew((Channel) _channelModel.getElementAt(0), false);
308 private void jbInit() throws Exception
310 this.setTitle("News from www.jalview.org");
311 this.getContentPane().setLayout(layoutMain);
312 panelMain.setLayout(borderLayout1);
313 topPanel.setLayout(borderLayout5);
314 bottomPanel.setLayout(borderLayout4);
315 topBottomSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
316 topBottomSplitPane.setDividerLocation(100);
317 topBottomSplitPane.setTopComponent(topPanel);
318 topBottomSplitPane.setBottomComponent(bottomPanel);
319 JScrollPane spTextDescription = new JScrollPane(textDescription);
320 textDescription.setText("");
321 statusBar.setText(" [Status] ");
322 buttonRefresh.addActionListener(new ActionListener()
326 public void actionPerformed(ActionEvent e)
331 this.getContentPane().add(statusBar, BorderLayout.SOUTH);
332 toolBar.add(buttonRefresh);
333 toolBar.addSeparator();
334 JLabel about=new JLabel("brought to you by JSwingReader (jswingreader.sourceforge.net)");
336 toolBar.setFloatable(false);
337 this.getContentPane().add(toolBar, BorderLayout.NORTH);
338 panelMain.add(topBottomSplitPane, BorderLayout.CENTER);
339 this.getContentPane().add(panelMain, BorderLayout.CENTER);
340 JScrollPane spListItems = new JScrollPane(listItems);
342 .setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
343 topPanel.add(spListItems, BorderLayout.CENTER);
344 bottomPanel.add(spTextDescription, BorderLayout.CENTER);
345 listChannels.setModel(_channelModel);
347 listItems.addMouseListener(new java.awt.event.MouseAdapter()
349 public void mouseClicked(MouseEvent e)
351 listItems_mouseClicked(e);
354 _popupItems = _buildItemsPopupMenu();
355 _popupChannels = _buildChannelsPopupMenu();
356 ContextMenuMouseAdapter popupAdapter = new ContextMenuMouseAdapter(
358 ContextMenuMouseAdapter popupChannelsAdapter = new ContextMenuMouseAdapter(
360 listItems.addMouseListener(popupAdapter);
361 listItems.setCellRenderer(new ItemsRenderer());
362 lblChannels.setText("Channels");
365 private void postInit()
367 // clear the default hyperlink listener and replace with our own.
368 for (HyperlinkListener hll : textDescription.getHyperlinkListeners())
370 textDescription.removeHyperlinkListener(hll);
372 textDescription.addHyperlinkListener(new HyperlinkListener()
374 public void hyperlinkUpdate(HyperlinkEvent e)
376 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
378 Desktop.showUrl(e.getURL().toExternalForm());
383 this.addWindowListener(new WindowAdapter()
385 public void windowClosing(WindowEvent e)
387 ActionEvent actionEvent = new ActionEvent(this,
388 ActionEvent.ACTION_FIRST, (String) exitAction
389 .getValue(Action.NAME));
390 exitAction.actionPerformed(actionEvent);
393 public void windowOpened(WindowEvent e)
398 listItems.addListSelectionListener(new ListSelectionListener()
400 public void valueChanged(ListSelectionEvent e)
402 if (e.getValueIsAdjusting() == false)
404 _itemsValueChanged(listItems);
408 listChannels.setSelectedIndex(1);
410 _updateToolbarButtons();
412 _itemTimer = new ItemReadTimer(listChannels, listItems);
413 _itemsValueChanged(listItems);
416 public class LaunchJvBrowserOnItem extends AbstractAction implements
419 JList _listItems = null;
421 public LaunchJvBrowserOnItem(JList listItems)
423 super("Open in Browser");
424 this.putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_O));
425 this.putValue(Action.LONG_DESCRIPTION, "Open in Browser");
426 _listItems = listItems;
429 public void actionPerformed(ActionEvent e)
431 Object o = _listItems.getSelectedValue();
432 if (o instanceof Item)
434 Item item = (Item) o;
436 _listItems.repaint();
438 Desktop.showUrl(item.getLink());
442 public void update(Object o)
445 if (_listItems == null || _listItems.getModel().getSize() == 0)
449 else if (_listItems.getSelectedIndex() == -1)
457 private JPopupMenu _buildItemsPopupMenu()
459 JPopupMenu popup = new JPopupMenu();
460 popup.add(new JMenuItem(new LaunchJvBrowserOnItem(listItems)));
461 popup.addSeparator();
462 popup.add(new JMenuItem(new MarkItemAsRead(listItems)));
463 popup.add(new JMenuItem(new MarkItemAsUnread(listItems)));
467 private JPopupMenu _buildChannelsPopupMenu()
469 JPopupMenu popup = new JPopupMenu();
470 popup.add(new JMenuItem(new MarkChannelAsRead(listChannels, listItems)));
471 popup.add(new JMenuItem(
472 new MarkChannelAsUnread(listChannels, listItems)));
476 private void initItems(Channel channel)
480 channel = new Channel();
482 if (!channel.isOpen() && channel.getURL() != null)
486 SimpleRSSParser.parse(channel);
487 } catch (Exception ex)
489 ex.printStackTrace();
492 DefaultListModel itemsModel = (DefaultListModel) listItems.getModel();
494 Iterator iter = (channel.getItems() != null) ? channel.getItems()
495 .iterator() : Collections.EMPTY_LIST.iterator();
496 while (iter.hasNext())
498 itemsModel.addElement(iter.next());
500 if (itemsModel.getSize() > 0)
502 listItems.setSelectedIndex(0);
503 _itemsValueChanged(listItems);
505 setStatusBarText(channel.getURL());
509 private void _itemsValueChanged(JList itemList)
511 Item item = (Item) itemList.getSelectedValue();
514 if (itemList.getModel().getSize() > 0)
516 item = (Item) itemList.getModel().getElementAt(0);
524 itemList.setSelectedIndex(0);
528 if (_itemTimer != null)
530 // prefer a shorter delay than 5s
531 _itemTimer.setDelay(300);
533 _itemTimer.setLastItem(item);
534 final Item lastitem = item;
535 _itemTimer.addActionListener(new ActionListener()
539 public void actionPerformed(ActionEvent e)
546 setStatusBarText(item.getLink());
547 textDescription.setBlogText(item);
551 public void setStatusBarText(String text)
553 statusBar.setText(text);
556 private void _updateAllActions()
558 Iterator iter = _updatableActions.iterator();
559 while (iter.hasNext())
561 UpdatableAction action = (UpdatableAction) iter.next();
566 private void _updateToolbarButtons()
568 Map general = (Map) Main.getPreferences().get("general");
574 Component[] components = toolBar.getComponents();
575 for (int i = 0; i < components.length; i++)
577 Component component = components[i];
578 if (component instanceof JButton)
580 JButton button = (JButton) component;
581 if (Boolean.toString(false).equals(general.get("useToolBarText")))
583 // Remove the text if preferences state no toolbar text
586 if (Boolean.toString(true).equals(general.get("radioTextBelow")))
588 button.setVerticalTextPosition(AbstractButton.BOTTOM);
589 button.setHorizontalTextPosition(AbstractButton.CENTER);
591 else if (Boolean.toString(true).equals(
592 general.get("radioTextRight")))
594 button.setVerticalTextPosition(AbstractButton.CENTER);
595 button.setHorizontalTextPosition(AbstractButton.RIGHT);
601 private void listItems_mouseClicked(MouseEvent e)
603 if (e.getClickCount() == 2 && e.getModifiersEx() == MouseEvent.NOBUTTON)
605 Item item = (Item) listItems.getSelectedValue();
608 if (_itemTimer != null)
613 Action action = new LaunchJvBrowserOnItem(listItems);
614 ActionEvent event = new ActionEvent(this,
615 ActionEvent.ACTION_PERFORMED, "LaunchBrowserOnItem");
616 action.actionPerformed(event);
621 * force the news panel to refresh
623 public void refreshNews()
626 initItems((Channel)_channelModel.getElementAt(0));
628 } catch (Exception x)
632 public static void main(String args[])
634 // this tests the detection of new news based on the last read date stored
635 // in jalview properties
636 jalview.bin.Cache.loadProperties(null);
637 jalview.bin.Cache.initLogger();
638 // test will advance read date each time
639 Calendar today = Calendar.getInstance(), lastread = Calendar
641 lastread.set(1983, 01, 01);
642 while (lastread.before(today))
644 Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED",
646 BlogReader me = new BlogReader();
647 System.out.println("Set last date to "
648 + jalview.bin.Cache.date_format.format(lastread.getTime()));
651 Cache.log.info("There is news to read.");
655 Cache.log.info("There is no new news.");
657 me.setTitle("Testing : Last read is " + me.lastDate);
660 while (me.isVisible())
665 } catch (InterruptedException x)
672 Cache.log.info("Still new news after reader displayed.");
674 if (lastread.getTime().before(me.lastDate))
676 Cache.log.info("The news was read.");
677 lastread.setTime(me.lastDate);
681 lastread.add(Calendar.MONTH, 1);
693 class ChannelsRenderer extends DefaultListCellRenderer
695 private final static Icon _icon = new ImageIcon(
696 Main.class.getResource("image/ComposeMail16.gif"));
698 public Component getListCellRendererComponent(JList list, Object value,
699 int index, boolean isSelected, boolean cellHasFocus)
701 JLabel component = (JLabel) super.getListCellRendererComponent(list,
702 value, index, isSelected, cellHasFocus);
703 component.setIcon(ChannelsRenderer._icon);
704 if (value instanceof Channel)
706 Channel channel = (Channel) value;
707 component.setText(channel.getTitle() + " ("
708 + channel.getUnreadItemCount() + ")");
709 component.setToolTipText(channel.getURL());
715 class ItemsRenderer extends DefaultListCellRenderer
717 private final static Icon _icon = new ImageIcon(
718 Main.class.getResource("image/ComposeMail16.gif"));
720 public Component getListCellRendererComponent(JList list, Object value,
721 int index, boolean isSelected, boolean cellHasFocus)
723 JLabel component = (JLabel) super.getListCellRendererComponent(list,
724 value, index, isSelected, cellHasFocus);
725 component.setIcon(ItemsRenderer._icon);
726 if (value instanceof Item)
728 Item item = (Item) value;
729 if (item.getPublishDate() != null)
731 component.setText(DateFormat.getDateInstance().format(
732 item.getPublishDate())
733 + " " + item.getTitle());
735 component.setToolTipText(item.getLink());
738 component.setFont(component.getFont().deriveFont(Font.BOLD));
742 component.setFont(component.getFont().deriveFont(Font.PLAIN));