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