// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2006 by R. Pito Salas
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software Foundation;
// either version 2 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with this program;
// if not, write to the Free Software Foundation, Inc., 59 Temple Place,
// Suite 330, Boston, MA 02111-1307 USA
//
// Contact: R. Pito Salas
// mailto:pitosalas@users.sourceforge.net
// More information: about BlogBridge
// http://www.blogbridge.com
// http://sourceforge.net/projects/blogbridge
//
// $Id: HTMLFeedDisplay.java,v 1.56 2008/02/28 15:59:45 spyromus Exp $
//
package com.salas.bb.views.feeds.html;
import com.jgoodies.binding.value.ValueModel;
import com.salas.bb.domain.IArticle;
import com.salas.bb.domain.IFeed;
import com.salas.bb.utils.i18n.Strings;
import com.salas.bb.utils.uif.html.CustomHTMLEditorKit;
import com.salas.bb.views.feeds.AbstractFeedDisplay;
import com.salas.bb.views.feeds.IArticleDisplay;
import com.salas.bb.views.feeds.IFeedDisplayConstants;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.net.URL;
import java.util.Iterator;
import java.util.logging.Logger;
/**
* Traditional HTML feed view.
*/
public class HTMLFeedDisplay extends AbstractFeedDisplay
implements IFeedJumpLinkClickCallback
{
private static final Logger LOG = Logger.getLogger(HTMLFeedDisplay.class.getName());
/** Selected article property. */
public static final String PROP_SELECTED_ARTICLE = "selectedArticle";
/** Hovered link property. */
public static final String PROP_HOVERED_LINK = "hoveredLink";
private final IHTMLFeedDisplayConfig htmlConfig;
/**
* Creates feed view.
*
* @param aConfig configuration of the view.
* @param pageModel page model to update when page changes.
* @param pageCountModel page model with the number of pages (updated by the FeedDisplayModel).
*/
public HTMLFeedDisplay(IHTMLFeedDisplayConfig aConfig, ValueModel pageModel, ValueModel pageCountModel)
{
super(aConfig, pageModel, pageCountModel);
htmlConfig = aConfig;
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
for (ArticlesGroup group : groups) add(group);
add(noContentPanel);
updateMaxArticleAge();
enableEvents(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_WHEEL_EVENT_MASK);
}
/**
* Returns currently selected text in currently selected article.
*
* @return text.
*/
public String getSelectedText()
{
return selectedDisplay == null
? null
: ((HTMLArticleDisplay)selectedDisplay).getSelectedText();
}
/**
* Returns message to show when there's no articles to display.
*
* @return the message.
*/
protected String getNoContentPanelMessage()
{
String msg;
int filter = getConfig().getFilter();
switch (filter)
{
case IFeedDisplayConstants.FILTER_PINNED:
msg = Strings.message("feeddisplay.no.pinned.articles");
break;
case IFeedDisplayConstants.FILTER_UNREAD:
msg = Strings.message("feeddisplay.no.unread.articles");
break;
default:
msg = Strings.message("feeddisplay.no.articles");
}
return msg;
}
/**
* Creates new article display for addition to the display.
*
* @param aArticle article to create display for.
*
* @return display.
*/
protected IArticleDisplay createNewArticleDisplay(IArticle aArticle)
{
IFeed loadedFeed = model.getFeed();
boolean smartFeed = loadedFeed != aArticle.getFeed();
IArticleDisplayConfig articleConfig = htmlConfig.getArticleViewConfig();
return new HTMLArticleDisplay(aArticle, articleConfig, smartFeed, this,
new CustomHTMLEditorKit());
}
/**
* Returns current logger.
*
* @return logger object.
*/
protected Logger getLogger()
{
return LOG;
}
// --------------------------------------------------------------------------------------------
// Keyboard events
// --------------------------------------------------------------------------------------------
/**
* Feed jump link clicked.
*
* @param feed feed.
*/
public void onFeedJumpLinkClicked(IFeed feed)
{
fireFeedJumpLinkClicked(feed);
}
// --------------------------------------------------------------------------------------------
// Events
// --------------------------------------------------------------------------------------------
@Override
protected void processKeyEvent(KeyEvent e)
{
boolean isCollapsing = e.getKeyCode() == KeyEvent.VK_LEFT;
if (e.getID() == KeyEvent.KEY_PRESSED &&
(isCollapsing || e.getKeyCode() == KeyEvent.VK_RIGHT))
{
cycleViewMode(e.isControlDown(), !isCollapsing);
} else if (e.getID() == KeyEvent.KEY_PRESSED &&
e.getKeyCode() == KeyEvent.VK_CLOSE_BRACKET)
{
// DEBUG sequence
model.dump();
Component[] cs = getComponents();
LOG.warning("--- List Dump ---");
LOG.warning("Number of components: " + cs.length);
for (Component c : cs)
{
if (c instanceof AbstractArticleDisplay)
{
LOG.warning(" " + ((AbstractArticleDisplay)c).getArticle().getTitle());
} else
{
LOG.warning(" - Group: " + c.getName());
}
}
} else
{
super.processKeyEvent(e);
}
}
/**
* Returns the component the user clicked on.
*
* @param e event.
*
* @return component.
*/
protected Object getComponentForMouseEvent(MouseEvent e)
{
return getComponentAt(e.getPoint());
}
/**
* Returns the view popup adapter.
*
* @return view popup adapter.
*/
protected MouseListener getViewPopupAdapter()
{
return htmlConfig.getViewPopupAdapter();
}
/**
* Returns the link popup adapter.
*
* @return link popup adapter.
*/
protected MouseListener getLinkPopupAdapter()
{
return htmlConfig.getLinkPopupAdapter();
}
/**
* Repaints article text if is currently in the given mode.
*
* @param briefMode <code>TRUE</code> for brief mode, otherwise -- full mode.
*/
public void repaintIfInMode(boolean briefMode)
{
Iterator it = new ArticleDisplayIterator();
while (it.hasNext())
{
HTMLArticleDisplay display = (HTMLArticleDisplay)it.next();
display.repaintIfInMode(briefMode);
}
}
/**
* Invoked on date visibility change.
*
* TODO deprecated
*/
private void onDateStatusChange()
{
Iterator it = new ArticleDisplayIterator();
while (it.hasNext())
{
HTMLArticleDisplay display = (HTMLArticleDisplay)it.next();
display.updateDateStatus();
}
}
/**
* Invoked on view mode layout changes.
*/
private void onViewModeLayoutChange()
{
Iterator it = new ArticleDisplayIterator();
while (it.hasNext())
{
HTMLArticleDisplay display = (HTMLArticleDisplay)it.next();
display.updateComponentsState();
}
}
/**
* Sets max article age.
*/
private void updateMaxArticleAge()
{
int maxAge = htmlConfig.isSuppressingOld() ? htmlConfig.getMaxArticleAge() * 24 * 3600000 : -1;
model.setMaxArticleAge(maxAge);
}
/**
* Returns tool-tip for a give link.
*
* @param link link.
* @param textPane pane requesting the tooltip.
*
* @return tool-tip text.
*/
protected String getHoveredLinkTooltip(URL link, JComponent textPane)
{
return link == null ? null : htmlConfig.getArticleViewConfig().getLinkTooltip(link);
}
/**
* Invoked when config property changes.
*
* @param name name of the property.
*/
protected void onConfigPropertyChange(String name)
{
if (IHTMLFeedDisplayConfig.SHOW_DATE.equals(name))
{
onDateStatusChange();
} else if (IHTMLFeedDisplayConfig.SUPPRESS_OLD.equals(name) ||
IHTMLFeedDisplayConfig.MAX_ARTICLE_AGE.equals(name))
{
updateMaxArticleAge();
} else if (IHTMLFeedDisplayConfig.VIEW_MODE_LAYOUT.equals(name))
{
onViewModeLayoutChange();
} else
{
super.onConfigPropertyChange(name);
}
}
}