JAL-1354 replacement of bare strings in GUI dialogs with i18n bundle lookup via jalvi...
[jalview.git] / src / jalview / gui / BlogReader.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.gui;
19
20 import jalview.bin.Cache;
21 import jalview.util.MessageManager;
22
23 import java.awt.BorderLayout;
24 import java.awt.Component;
25 import java.awt.Dimension;
26 import java.awt.Font;
27 import java.awt.Rectangle;
28 import java.awt.Dialog.ModalExclusionType;
29 import java.awt.event.ActionEvent;
30 import java.awt.event.ActionListener;
31 import java.awt.event.KeyEvent;
32 import java.awt.event.MouseEvent;
33 import java.awt.event.WindowAdapter;
34 import java.awt.event.WindowEvent;
35 import java.beans.PropertyChangeListener;
36 import java.text.DateFormat;
37 import java.text.SimpleDateFormat;
38 import java.util.ArrayList;
39 import java.util.Calendar;
40 import java.util.Collections;
41 import java.util.Iterator;
42 import java.util.List;
43 import java.util.Map;
44
45 import javax.swing.AbstractAction;
46 import javax.swing.AbstractButton;
47 import javax.swing.Action;
48 import javax.swing.DefaultListCellRenderer;
49 import javax.swing.DefaultListModel;
50 import javax.swing.Icon;
51 import javax.swing.ImageIcon;
52 import javax.swing.JButton;
53 import javax.swing.JFrame;
54 import javax.swing.JLabel;
55 import javax.swing.JList;
56 import javax.swing.JMenuItem;
57 import javax.swing.JPanel;
58 import javax.swing.JPopupMenu;
59 import javax.swing.JScrollPane;
60 import javax.swing.JSplitPane;
61 import javax.swing.JToolBar;
62 import javax.swing.ListSelectionModel;
63 import javax.swing.SwingUtilities;
64 import javax.swing.event.HyperlinkEvent;
65 import javax.swing.event.HyperlinkListener;
66 import javax.swing.event.ListSelectionEvent;
67 import javax.swing.event.ListSelectionListener;
68
69 import org.robsite.jswingreader.action.MarkChannelAsRead;
70 import org.robsite.jswingreader.action.MarkChannelAsUnread;
71 import org.robsite.jswingreader.action.MarkItemAsRead;
72 import org.robsite.jswingreader.action.MarkItemAsUnread;
73 import org.robsite.jswingreader.action.UpdatableAction;
74 import org.robsite.jswingreader.model.Channel;
75 import org.robsite.jswingreader.model.ChannelListModel;
76 import org.robsite.jswingreader.model.Item;
77 import org.robsite.jswingreader.model.SimpleRSSParser;
78 import org.robsite.jswingreader.ui.BlogContentPane;
79 import org.robsite.jswingreader.ui.ItemReadTimer;
80 import org.robsite.jswingreader.ui.Main;
81 import org.robsite.jswingreader.ui.util.ContextMenuMouseAdapter;
82
83 /**
84  * Blog reading window, adapted from JSwingReader's
85  * org.robsite.jswingreader.ui.MainWindow class
86  */
87
88 public class BlogReader extends JPanel
89 {
90   private JButton buttonRefresh = new JButton();
91
92   private JToolBar toolBar = new JToolBar();
93
94   private JLabel statusBar = new JLabel();
95
96   private JPanel panelMain = new JPanel();
97
98   private BorderLayout layoutMain = new BorderLayout();
99
100   private BorderLayout borderLayout1 = new BorderLayout();
101
102   private JPanel topPanel = new JPanel();
103
104   private JPanel bottomPanel = new JPanel();
105
106   private JSplitPane topBottomSplitPane = new JSplitPane();
107
108   private JList listItems = new JList(new DefaultListModel());
109
110   // SWITCH IN JALVIEW HTML VIEWER PANE HERE
111   private BlogContentPane textDescription = new BlogContentPane();
112
113   // ADD IN JALVIEW BANNER FOR PRETTINESS
114   private BorderLayout borderLayout4 = new BorderLayout();
115
116   private BorderLayout borderLayout5 = new BorderLayout();
117
118   private ChannelListModel _channelModel = null;
119
120   private JList listChannels = new JList();
121
122   private Action exitAction = new Action()
123   {
124
125     @Override
126     public void actionPerformed(ActionEvent arg0)
127     {
128       if (xf != null)
129       {
130         xf.dispose();
131       }
132       xf = null;
133       jd = null;
134       if (parent != null)
135       {
136         parent.showNews(false);
137       }
138
139     }
140
141     @Override
142     public void setEnabled(boolean arg0)
143     {
144
145     }
146
147     @Override
148     public void removePropertyChangeListener(PropertyChangeListener arg0)
149     {
150       // TODO Auto-generated method stub
151
152     }
153
154     @Override
155     public void putValue(String arg0, Object arg1)
156     {
157       // TODO Auto-generated method stub
158
159     }
160
161     @Override
162     public boolean isEnabled()
163     {
164       // TODO Auto-generated method stub
165       return true;
166     }
167
168     @Override
169     public Object getValue(String arg0)
170     {
171       // TODO Auto-generated method stub
172       return null;
173     }
174
175     @Override
176     public void addPropertyChangeListener(PropertyChangeListener arg0)
177     {
178       // TODO Auto-generated method stub
179
180     }
181   };
182
183   private JFrame xf = null;
184
185   private JalviewDialog jd = null;
186
187   private JalviewDialog createDialog()
188   {
189
190     return jd = new JalviewDialog()
191     {
192
193       @Override
194       protected void raiseClosed()
195       {
196         if (parent != null)
197         {
198           Cache.log.info("News window closed.");
199           jd = null;
200           parent.showNews(false);
201         }
202       }
203
204       @Override
205       protected void okPressed()
206       {
207         // TODO Auto-generated method stub
208
209       }
210
211       @Override
212       protected void cancelPressed()
213       {
214         // TODO Auto-generated method stub
215
216       }
217     };
218   };
219
220   private JLabel lblChannels = new JLabel();
221
222   private List _updatableActions = new ArrayList();
223
224   private ItemReadTimer _itemTimer = null;
225
226   private JPopupMenu _popupItems = null;
227
228   private JPopupMenu _popupChannels = null;
229
230   private String lastm = "";
231
232   private boolean newsnew = false;
233
234   private Desktop parent = null;
235
236   BlogReader()
237   {
238     this(null);
239   }
240
241   // should we ignore fake gui events
242   private boolean updating = false;
243
244   public BlogReader(Desktop desktop)
245   {
246     Cache.log.info("Constructing news reader.");
247
248     parent = desktop;
249     _channelModel = new ChannelListModel();
250     // Construct our jalview news channel
251     Channel chan = new Channel();
252     chan.setURL(jalview.bin.Cache.getDefault(
253             "JALVIEW_NEWS_RSS",
254             jalview.bin.Cache.getDefault("www.jalview.org",
255                     "http://www.jalview.org") + "/feeds/desktop/rss"));
256     loadLastM();
257     _channelModel.addChannel(chan);
258     updating = true;
259     try
260     {
261       jbInit();
262       postInit();
263     } catch (Exception e)
264     {
265       e.printStackTrace();
266     }
267
268     initItems(chan);
269     updating = false;
270     boolean setvisible = checkForNew(chan, true);
271
272     if (setvisible)
273     {
274
275       Cache.log.info("Will show jalview news automatically");
276       showNews();
277     }
278     Cache.log.info("Completed construction of reader.");
279
280   }
281
282   /**
283    * check if the news panel's container is visible
284    */
285   public boolean isVisible()
286   {
287     if (parent == null)
288     {
289       return xf != null && xf.isVisible();
290     }
291     return jd != null && jd.isVisible();
292   }
293
294   /**
295    * display the container for the news panel
296    */
297   public void showNews()
298   {
299     final BlogReader me = this;
300     SwingUtilities.invokeLater(new Runnable()
301     {
302       @Override
303       public void run()
304       {
305         Rectangle bounds = new Rectangle(5, 5, 550, 350);
306         if (parent == null)
307         {
308           xf = new JFrame();
309           xf.setContentPane(me);
310           xf.addWindowListener(new WindowAdapter()
311           {
312             public void windowClosing(WindowEvent e)
313             {
314               ActionEvent actionEvent = new ActionEvent(this,
315                       ActionEvent.ACTION_FIRST, (String) exitAction
316                               .getValue(Action.NAME));
317               exitAction.actionPerformed(actionEvent);
318             }
319
320             public void windowOpened(WindowEvent e)
321             {
322             }
323           });
324           me.setSize(new Dimension(550, 350));
325           xf.setVisible(true);
326         }
327         else
328         {
329           createDialog();
330           bounds = new Rectangle(5, 5, 550, 350);
331           jd.initDialogFrame(me, false, false, "News from www.jalview.org",
332                   bounds.width, bounds.height);
333           jd.frame.setModalExclusionType(ModalExclusionType.NO_EXCLUDE);
334           Cache.log.info("Displaying news.");
335           jd.waitForInput();
336         }
337       }
338     });
339   }
340
341   /**
342    * update hasnew flag and mark all new messages as unread.
343    */
344   private boolean checkForNew(Channel chan, boolean updateItems)
345   {
346
347     if (!updating || updateItems)
348     {
349       newsnew = false;
350     }
351     java.util.Date earliest = null;
352     try
353     {
354       earliest = new SimpleDateFormat("YYYY-MM-DD").parse(chan
355               .getHTTPLastModified());
356     } catch (Exception x)
357     {
358     }
359     ;
360     if (chan != null && chan.getItems() != null)
361     {
362       Cache.log.debug("Scanning news items: newsnew=" + newsnew
363               + " and lastDate is " + lastDate);
364       for (Item i : (List<Item>) chan.getItems())
365       {
366         boolean isread = lastDate == null ? false
367                 : (i.getPublishDate() != null && !lastDate.before(i
368                         .getPublishDate()));
369
370         if (!updating || updateItems)
371         {
372           newsnew |= !isread;
373         }
374         if (updateItems)
375         {
376           i.setRead(isread);
377         }
378         if (i.getPublishDate() != null && !i.isRead())
379         {
380           if (earliest == null || earliest.after(i.getPublishDate()))
381           {
382             earliest = i.getPublishDate();
383           }
384         }
385       }
386     }
387     if (!updateItems && !updating && lastDate == null)
388     {
389       lastDate = earliest;
390     }
391     return newsnew;
392   }
393
394   java.util.Date lastDate = null;
395
396   private void loadLastM()
397   {
398     lastDate = Cache.getDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED");
399   }
400
401   private void saveLastM(Item item)
402   {
403     if (item != null)
404     {
405       if (item.getPublishDate() != null)
406       {
407         if (lastDate == null || item.getPublishDate().after(lastDate))
408         {
409           lastDate = item.getPublishDate();
410         }
411       }
412
413       if (_channelModel.getElementAt(0) != null)
414       {
415         checkForNew((Channel) _channelModel.getElementAt(0), false);
416       }
417       if (lastDate != null)
418       {
419         jalview.bin.Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED",
420                 lastDate);
421         jalview.bin.Cache.log.info("Saved last read date as "
422                 + jalview.bin.Cache.date_format.format(lastDate));
423
424       }
425     }
426   }
427
428   private void jbInit() throws Exception
429   {
430     setLayout(layoutMain);
431     panelMain.setLayout(borderLayout1);
432     topPanel.setLayout(borderLayout5);
433     bottomPanel.setLayout(borderLayout4);
434     topBottomSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
435     topBottomSplitPane.setDividerLocation(100);
436     topBottomSplitPane.setTopComponent(topPanel);
437     topBottomSplitPane.setBottomComponent(bottomPanel);
438     JScrollPane spTextDescription = new JScrollPane(textDescription);
439     textDescription.setText("");
440     statusBar.setText(MessageManager.getString("label.status"));
441     buttonRefresh.addActionListener(new ActionListener()
442     {
443
444       @Override
445       public void actionPerformed(ActionEvent e)
446       {
447         refreshNews();
448       }
449     });
450     add(statusBar, BorderLayout.SOUTH);
451     toolBar.add(buttonRefresh);
452     toolBar.addSeparator();
453     JLabel about = new JLabel(
454             "brought to you by JSwingReader (jswingreader.sourceforge.net)");
455     toolBar.add(about);
456     toolBar.setFloatable(false);
457     add(toolBar, BorderLayout.NORTH);
458     panelMain.add(topBottomSplitPane, BorderLayout.CENTER);
459     add(panelMain, BorderLayout.CENTER);
460     JScrollPane spListItems = new JScrollPane(listItems);
461     listItems
462             .setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
463     topPanel.add(spListItems, BorderLayout.CENTER);
464     bottomPanel.add(spTextDescription, BorderLayout.CENTER);
465     listChannels.setModel(_channelModel);
466
467     listItems.addMouseListener(new java.awt.event.MouseAdapter()
468     {
469       public void mouseClicked(MouseEvent e)
470       {
471         listItems_mouseClicked(e);
472       }
473     });
474     _popupItems = _buildItemsPopupMenu();
475     _popupChannels = _buildChannelsPopupMenu();
476     ContextMenuMouseAdapter popupAdapter = new ContextMenuMouseAdapter(
477             _popupItems);
478     ContextMenuMouseAdapter popupChannelsAdapter = new ContextMenuMouseAdapter(
479             _popupChannels);
480     listItems.addMouseListener(popupAdapter);
481     listItems.setCellRenderer(new ItemsRenderer());
482     lblChannels.setText(MessageManager.getString("label.channels"));
483   }
484
485   private void postInit()
486   {
487     // clear the default hyperlink listener and replace with our own.
488     for (HyperlinkListener hll : textDescription.getHyperlinkListeners())
489     {
490       textDescription.removeHyperlinkListener(hll);
491     }
492     textDescription.addHyperlinkListener(new HyperlinkListener()
493     {
494       public void hyperlinkUpdate(HyperlinkEvent e)
495       {
496         if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
497         {
498           Desktop.showUrl(e.getURL().toExternalForm());
499         }
500       }
501     });
502
503     listItems.addListSelectionListener(new ListSelectionListener()
504     {
505       public void valueChanged(ListSelectionEvent e)
506       {
507         if (e.getValueIsAdjusting() == false)
508         {
509           _itemsValueChanged(listItems);
510         }
511       }
512     });
513     listChannels.setSelectedIndex(1);
514     _updateAllActions();
515     _updateToolbarButtons();
516
517     _itemTimer = new ItemReadTimer(listChannels, listItems);
518     _itemsValueChanged(listItems);
519   }
520
521   public class LaunchJvBrowserOnItem extends AbstractAction implements
522           UpdatableAction
523   {
524     JList _listItems = null;
525
526     public LaunchJvBrowserOnItem(JList listItems)
527     {
528       super("Open in Browser");
529       this.putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_O));
530       this.putValue(Action.LONG_DESCRIPTION, "Open in Browser");
531       _listItems = listItems;
532     }
533
534     public void actionPerformed(ActionEvent e)
535     {
536       Object o = _listItems.getSelectedValue();
537       if (o instanceof Item)
538       {
539         Item item = (Item) o;
540         item.setRead(true);
541         _listItems.repaint();
542
543         Desktop.showUrl(item.getLink());
544       }
545     }
546
547     public void update(Object o)
548     {
549       setEnabled(true);
550       if (_listItems == null || _listItems.getModel().getSize() == 0)
551       {
552         setEnabled(false);
553       }
554       else if (_listItems.getSelectedIndex() == -1)
555       {
556         setEnabled(false);
557       }
558     }
559
560   }
561
562   private JPopupMenu _buildItemsPopupMenu()
563   {
564     JPopupMenu popup = new JPopupMenu();
565     popup.add(new JMenuItem(new LaunchJvBrowserOnItem(listItems)));
566     popup.addSeparator();
567     popup.add(new JMenuItem(new MarkItemAsRead(listItems)));
568     popup.add(new JMenuItem(new MarkItemAsUnread(listItems)));
569     return popup;
570   }
571
572   private JPopupMenu _buildChannelsPopupMenu()
573   {
574     JPopupMenu popup = new JPopupMenu();
575     popup.add(new JMenuItem(new MarkChannelAsRead(listChannels, listItems)));
576     popup.add(new JMenuItem(
577             new MarkChannelAsUnread(listChannels, listItems)));
578     return popup;
579   }
580
581   private void initItems(Channel channel)
582   {
583     if (channel == null)
584     {
585       channel = new Channel();
586     }
587     if (!channel.isOpen() && channel.getURL() != null)
588     {
589       try
590       {
591         SimpleRSSParser.parse(channel);
592       } catch (Exception ex)
593       {
594         ex.printStackTrace();
595       }
596     }
597     DefaultListModel itemsModel = (DefaultListModel) listItems.getModel();
598     itemsModel.clear();
599     Iterator iter = (channel.getItems() != null) ? channel.getItems()
600             .iterator() : Collections.EMPTY_LIST.iterator();
601     while (iter.hasNext())
602     {
603       itemsModel.addElement(iter.next());
604     }
605     if (itemsModel.getSize() > 0)
606     {
607       listItems.setSelectedIndex(0);
608       _itemsValueChanged(listItems);
609     }
610     setStatusBarText(channel.getURL());
611     _updateAllActions();
612   }
613
614   private void _itemsValueChanged(JList itemList)
615   {
616     Item item = (Item) itemList.getSelectedValue();
617     if (item == null)
618     {
619       if (itemList.getModel().getSize() > 0)
620       {
621         item = (Item) itemList.getModel().getElementAt(0);
622       }
623       if (item == null)
624       {
625         item = new Item();
626       }
627       else
628       {
629         itemList.setSelectedIndex(0);
630       }
631     }
632
633     if (_itemTimer != null)
634     {
635       // prefer a shorter delay than 5s
636       _itemTimer.setDelay(300);
637       _itemTimer.start();
638       _itemTimer.setLastItem(item);
639       final Item lastitem = item;
640       _itemTimer.addActionListener(new ActionListener()
641       {
642
643         @Override
644         public void actionPerformed(ActionEvent e)
645         {
646           saveLastM(lastitem);
647         }
648       });
649     }
650
651     setStatusBarText(item.getLink());
652     textDescription.setBlogText(item);
653     _updateAllActions();
654   }
655
656   public void setStatusBarText(String text)
657   {
658     statusBar.setText(text);
659   }
660
661   private void _updateAllActions()
662   {
663     Iterator iter = _updatableActions.iterator();
664     while (iter.hasNext())
665     {
666       UpdatableAction action = (UpdatableAction) iter.next();
667       action.update(this);
668     }
669   }
670
671   private void _updateToolbarButtons()
672   {
673     Map general = (Map) Main.getPreferences().get("general");
674     if (general == null)
675     {
676       return;
677     }
678
679     Component[] components = toolBar.getComponents();
680     for (int i = 0; i < components.length; i++)
681     {
682       Component component = components[i];
683       if (component instanceof JButton)
684       {
685         JButton button = (JButton) component;
686         if (Boolean.toString(false).equals(general.get("useToolBarText")))
687         {
688           // Remove the text if preferences state no toolbar text
689           button.setText("");
690         }
691         if (Boolean.toString(true).equals(general.get("radioTextBelow")))
692         {
693           button.setVerticalTextPosition(AbstractButton.BOTTOM);
694           button.setHorizontalTextPosition(AbstractButton.CENTER);
695         }
696         else if (Boolean.toString(true).equals(
697                 general.get("radioTextRight")))
698         {
699           button.setVerticalTextPosition(AbstractButton.CENTER);
700           button.setHorizontalTextPosition(AbstractButton.RIGHT);
701         }
702       }
703     }
704   }
705
706   private void listItems_mouseClicked(MouseEvent e)
707   {
708     if (e.getClickCount() == 2 && e.getModifiersEx() == MouseEvent.NOBUTTON)
709     {
710       Item item = (Item) listItems.getSelectedValue();
711       item.setRead(true);
712       saveLastM(item);
713       if (_itemTimer != null)
714       {
715         _itemTimer.stop();
716       }
717
718       Action action = new LaunchJvBrowserOnItem(listItems);
719       ActionEvent event = new ActionEvent(this,
720               ActionEvent.ACTION_PERFORMED, "LaunchBrowserOnItem");
721       action.actionPerformed(event);
722     }
723   }
724
725   /**
726    * force the news panel to refresh
727    */
728   public void refreshNews()
729   {
730     try
731     {
732       initItems((Channel) _channelModel.getElementAt(0));
733
734     } catch (Exception x)
735     {
736     }
737   }
738
739   public static void main(String args[])
740   {
741     // this tests the detection of new news based on the last read date stored
742     // in jalview properties
743     jalview.bin.Cache.loadProperties(null);
744     jalview.bin.Cache.initLogger();
745     // test will advance read date each time
746     Calendar today = Calendar.getInstance(), lastread = Calendar
747             .getInstance();
748     lastread.set(1983, 01, 01);
749     while (lastread.before(today))
750     {
751       Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED",
752               lastread.getTime());
753       BlogReader me = new BlogReader();
754       System.out.println("Set last date to "
755               + jalview.bin.Cache.date_format.format(lastread.getTime()));
756       if (me.isNewsNew())
757       {
758         Cache.log.info("There is news to read.");
759       }
760       else
761       {
762         Cache.log.info("There is no new news.");
763         me.xf.setTitle("Testing : Last read is " + me.lastDate);
764         me.showNews();
765         me.xf.toFront();
766       }
767       Cache.log.info("Waiting for closure.");
768       do
769       {
770         try
771         {
772           Thread.sleep(300);
773         } catch (InterruptedException x)
774         {
775         }
776         ;
777       } while (me.isVisible());
778
779       if (me.isNewsNew())
780       {
781         Cache.log.info("Still new news after reader displayed.");
782       }
783       if (lastread.getTime().before(me.lastDate))
784       {
785         Cache.log.info("The news was read.");
786         lastread.setTime(me.lastDate);
787       }
788       else
789       {
790         lastread.add(Calendar.MONTH, 1);
791       }
792
793     }
794   }
795
796   boolean isNewsNew()
797   {
798     return newsnew;
799   }
800 }
801
802 class ChannelsRenderer extends DefaultListCellRenderer
803 {
804   private final static Icon _icon = new ImageIcon(
805           Main.class.getResource("image/ComposeMail16.gif"));
806
807   public Component getListCellRendererComponent(JList list, Object value,
808           int index, boolean isSelected, boolean cellHasFocus)
809   {
810     JLabel component = (JLabel) super.getListCellRendererComponent(list,
811             value, index, isSelected, cellHasFocus);
812     component.setIcon(ChannelsRenderer._icon);
813     if (value instanceof Channel)
814     {
815       Channel channel = (Channel) value;
816       component.setText(MessageManager.formatMessage("label.channel_title_item_count", new String[]{channel.getTitle(),Integer.valueOf(channel.getUnreadItemCount()).toString()}));
817       component.setToolTipText(channel.getURL());
818     }
819     return component;
820   }
821 }
822
823 class ItemsRenderer extends DefaultListCellRenderer
824 {
825   private final static Icon _icon = new ImageIcon(
826           Main.class.getResource("image/ComposeMail16.gif"));
827
828   public Component getListCellRendererComponent(JList list, Object value,
829           int index, boolean isSelected, boolean cellHasFocus)
830   {
831     JLabel component = (JLabel) super.getListCellRendererComponent(list,
832             value, index, isSelected, cellHasFocus);
833     component.setIcon(ItemsRenderer._icon);
834     if (value instanceof Item)
835     {
836       Item item = (Item) value;
837       if (item.getPublishDate() != null)
838       {
839         component.setText(MessageManager.formatMessage("label.blog_item_published_on_date", new String[]{DateFormat.getDateInstance().format(item.getPublishDate()).toString(),item.getTitle()}));
840       }
841       component.setToolTipText(item.getLink());
842       if (!item.isRead())
843       {
844         component.setFont(component.getFont().deriveFont(Font.BOLD));
845       }
846       else
847       {
848         component.setFont(component.getFont().deriveFont(Font.PLAIN));
849       }
850     }
851     return component;
852   }
853 }