// 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: ImageArticleDisplay.java,v 1.19 2008/02/28 12:36:17 spyromus Exp $ // package com.salas.bb.views.feeds.image; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.ColumnSpec; import com.jgoodies.forms.layout.FormLayout; import com.jgoodies.uif.util.ResourceUtils; import com.salas.bb.domain.IArticle; import com.salas.bb.domain.IArticleListener; import com.salas.bb.utils.StringUtils; import com.salas.bb.utils.uif.DelegatingMouseListener; import com.salas.bb.utils.uif.ShadowBorder; import com.salas.bb.utils.uif.UifUtilities; import com.salas.bb.utils.uif.html.CustomHTMLEditorKit; import com.salas.bb.views.feeds.IArticleDisplay; import com.salas.bb.views.feeds.html.IArticleDisplayConfig; import javax.swing.*; import javax.swing.event.HyperlinkListener; import javax.swing.text.Style; import javax.swing.text.html.HTMLDocument; import java.awt.*; import java.net.URL; /** * The view showing the article as an image. */ class ImageArticleDisplay extends JPanel implements IArticleListener, IArticleDisplay { private static final int EXCERPT_MIN_CHARS = 100; private static final int EXCERPT_MAX_CHARS = 200; private static final int EXCERPT_SENTENCES = 1; private static final String TEXT_STYLE_NAME = "normal"; private static final Color COLOR_SHADOW_BORDER = Color.decode("#b0b0b0"); private static final CellConstraints CELL_CONSTRAINTS = new CellConstraints(); private final IImageFeedDisplayConfig config; private final IArticle article; private AsyncImagePanel lbImage; private JLabel lbTitle; private JEditorPane tfText; private boolean selected; private int mode; private FormLayout layout; /** * Creates view for an article. * * @param aArticle the article. * @param aConfig configuration. */ public ImageArticleDisplay(IArticle aArticle, IImageFeedDisplayConfig aConfig) { article = aArticle; config = aConfig; URL imageURL = ImageArticleInterpreter.getImageURL(article); selected = false; initGUI(imageURL, article.getTitle(), article.getBriefText()); } /** * Initializes GUI. * * @param aImageURL URL of the image to load. * @param aTitle article title. * @param aText article text. */ private void initGUI(URL aImageURL, String aTitle, String aText) { IArticleDisplayConfig articleConfig = config.getArticleViewConfig(); lbTitle = new JLabel(aTitle); lbTitle.setToolTipText(aTitle); tfText = new JEditorPane(); tfText.setEditorKit(new CustomHTMLEditorKit()); tfText.setText(StringUtils.excerpt(aText, EXCERPT_SENTENCES, EXCERPT_MIN_CHARS, EXCERPT_MAX_CHARS)); tfText.setEditable(false); tfText.setToolTipText("<html>" + aText); HTMLDocument doc = (HTMLDocument)tfText.getDocument(); doc.setBase(article.getLink()); Style def = doc.getStyle("default"); doc.addStyle(TEXT_STYLE_NAME, def); UifUtilities.setFontAttributes(doc, TEXT_STYLE_NAME, articleConfig.getTextFont()); setViewMode(config.getViewMode()); layout = new FormLayout("5px, center:pref, 5px", "5px, pref, 5px, pref, 5px, pref, 5px"); setLayout(layout); aImageURL = aImageURL == null ? config.getNoImageURL() : aImageURL; Dimension dim = modeToDimension(config.getViewMode()); lbImage = new AsyncImagePanel(aImageURL, dim.width, dim.height, new ShadowBorder(COLOR_SHADOW_BORDER), article.isRead()); setTextComponentsWidth(); add(lbImage, CELL_CONSTRAINTS.xy(2, 2)); add(lbTitle, CELL_CONSTRAINTS.xy(2, 4)); add(tfText, CELL_CONSTRAINTS.xy(2, 6)); setToolTipText(aTitle == null ? null : "<html>" + aTitle + "</html>"); // Register delegating mouse listener DelegatingMouseListener ml = new DelegatingMouseListener(this, true); this.addMouseListener(ml); lbImage.addMouseListener(ml); lbTitle.addMouseListener(ml); tfText.addMouseListener(ml); onThemeChange(); updatePinnedState(); } private void setTextComponentsWidth() { Dimension imgSize = lbImage.getPreferredSize(); layout.setColumnSpec(2, new ColumnSpec("center:" + imgSize.width + "px")); } /** * Invoked on view mode change. */ public void onViewModeChange() { setViewMode(config.getViewMode()); doLayout(); } /** * Returns current article display view mode. * * @return mode. */ public int getViewMode() { return mode; } /** * Sets the mode of this display. * * @param aMode mode of display. */ public void setViewMode(int aMode) { mode = aMode; if (lbImage != null) { lbImage.setImageSize(modeToDimension(aMode)); setTextComponentsWidth(); } lbTitle.setVisible(aMode > 0); tfText.setVisible(aMode > EXCERPT_SENTENCES); } /** * Returns dimension of image panel for the mode. * * @param aMode mode. * * @return dimension. */ private static Dimension modeToDimension(int aMode) { Dimension imageDim; switch(aMode) { case 0: imageDim = new Dimension(50, 50); break; case EXCERPT_SENTENCES: imageDim = new Dimension(100, 100); break; default: imageDim = new Dimension(200, 200); break; } return imageDim; } /** * Returns wrapped article. * * @return article. */ public IArticle getArticle() { return article; } /** * Updates the view according to read state. */ private void updateReadState() { lbImage.setSecondMode(article.isRead()); updateFonts(); } /** * Updates the view according to pinned state. */ private void updatePinnedState() { lbImage.setBadge(article.isPinned() ? ResourceUtils.getIcon("pin.sel.icon").getImage() : null); } /** * Sets tooltip text to for the whole item cell. * * @param text the string to display; if the text is <code>null</code>, the tool tip is turned * off for this component */ public void setToolTipText(String text) { super.setToolTipText(text); lbImage.setToolTipText(text); } /** * Sets / resets the selection. * * @param sel <code>TRUE</code> to select item. */ public void setSelected(boolean sel) { selected = sel; updateBackgrounds(); } /** * Registers hyperlink listener. * * @param aListener listener. */ public void addHyperlinkListener(HyperlinkListener aListener) { } /** * Returns listener. * * @return listener. */ public IArticleListener getArticleListener() { return this; } /** * Returns visual component. * * @return visual component. */ public Component getComponent() { return this; } /** Invoked when font bias changes. */ public void onFontBiasChange() { updateFonts(); } /** Invoked on theme change. */ public void onThemeChange() { updateFonts(); updateBackgrounds(); updateForegrounds(); } /** * Updates foreground colors. */ private void updateForegrounds() { IArticleDisplayConfig cnf = config.getArticleViewConfig(); lbTitle.setForeground(cnf.getTitleFGColor(selected)); } /** * Updates background colors. */ private void updateBackgrounds() { // Image / Item colors Color color = config.getItemBGColor(selected); setBackground(color); lbImage.setBackground(color); // Font colors IArticleDisplayConfig cnf = config.getArticleViewConfig(); lbTitle.setBackground(cnf.getTitleBGColor(selected)); tfText.setBackground(cnf.getTextBGColor(selected)); } /** * Updates fonts. */ private void updateFonts() { IArticleDisplayConfig cnf = config.getArticleViewConfig(); // Title font Font font = cnf.getTitleFont(article.isRead()); lbTitle.setFont(font); // Text area font = cnf.getTextFont(); HTMLDocument doc = (HTMLDocument)tfText.getDocument(); UifUtilities.setFontAttributes(doc, TEXT_STYLE_NAME, font); UifUtilities.installTextStyle(tfText, TEXT_STYLE_NAME); doLayout(); } /** * Sets <code>TRUE</code> if the display should become collapsed. * * @param col <code>TRUE</code> if the display is currently selected. */ public void setCollapsed(boolean col) { } /** * Requests focus and returns the state. * * @return <code>FALSE</code> if focus isn't likely to be changed. */ public boolean focus() { return this.requestFocusInWindow(); } /** Invoked when article should update highlights. */ public void updateHighlights() { } /** Updates a color code. */ public void updateColorCode() { } // --------------------------------------------------------------------------------------------- // Article listener // --------------------------------------------------------------------------------------------- /** * Invoked when the property of the article has been changed. * * @param article article. * @param property property of the article. * @param oldValue old property value. * @param newValue new property value. */ public void propertyChanged(IArticle article, String property, Object oldValue, Object newValue) { if (IArticle.PROP_READ.equals(property)) { SwingUtilities.invokeLater(new Runnable() { public void run() { updateReadState(); } }); } else if (IArticle.PROP_PINNED.equals(property)) { SwingUtilities.invokeLater(new Runnable() { public void run() { updatePinnedState(); } }); } } }