// 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: GuideListCellRenderer.java,v 1.46 2007/04/17 13:43:26 spyromus Exp $ // package com.salas.bb.views; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; import com.jgoodies.uif.util.ResourceUtils; import com.salas.bb.core.GlobalModel; import com.salas.bb.core.GuideDisplayModeManager; import com.salas.bb.domain.IGuide; import com.salas.bb.utils.ResourceID; import com.salas.bb.utils.uif.IconSource; import com.salas.bb.views.mainframe.UnreadButton; import com.salas.bb.views.settings.RenderingManager; import javax.swing.*; import javax.swing.border.Border; import java.awt.*; import java.text.MessageFormat; /** * Renderer for cells of guides list. */ public class GuideListCellRenderer extends JPanel implements ListCellRenderer { /** Guide cell top margin, in pixels. */ public static final int CELL_MARGIN_TOP = 4; /** Guide cell bottom margin, in pixels. */ public static final int CELL_MARGIN_BOTTOM = 4; /** Guide cell left margin, in pixels. */ public static final int CELL_MARGIN_LEFT = 0; /** Guide cell right margin, in pixels. */ public static final int CELL_MARGIN_RIGHT = 1; private static final float GUIDE_LABEL_FONT_SIZE = 10f; private static final Border BORDER_NO_FOCUS = BorderFactory.createEmptyBorder(1, 1, 1, 1); private GuidesPanel.UnreadController unreadController; private IGuideCellRenderer renderer; /** * Constructs new renderer. * * @param anUnreadController unread controller. */ public GuideListCellRenderer(GuidesPanel.UnreadController anUnreadController) { unreadController = anUnreadController; updateRendererAndLayout(); } /** * Invoked when the size of an icon changes. */ public void onIconSizeChange() { updateRendererAndLayout(); } /** Initialzes sub-renderer. */ public void updateRendererAndLayout() { boolean largeIcon = RenderingManager.isBigIconInGuides() && RenderingManager.isShowIconInGuides(); if (renderer == null || (largeIcon && renderer instanceof SmallIconGuideCellRenderer) || (!largeIcon && renderer instanceof LargeIconGuideCellRenderer)) { renderer = largeIcon ? new LargeIconGuideCellRenderer() : new SmallIconGuideCellRenderer(); } updateLayout(); } /** * Set up the cell layout based on current settings. */ private void updateLayout() { renderer.showUnreadButton(RenderingManager.isShowUnreadInGuides()); renderer.showIcon(RenderingManager.isShowIconInGuides()); renderer.showText(RenderingManager.isShowTextInGuides()); } /** * Return a component that has been configured to display the specified * value. That component's <code>paint</code> method is then called to * "render" the cell. If it is necessary to compute the dimensions * of a list because the list cells do not have a fixed size, this method * is called to generate a component on which <code>getPreferredSize</code> * can be invoked. * * @param list The JList we're painting. * @param value The value returned by list.getModel().getElementAt(index). * @param index The cells index. * @param isSelected True if the specified cell was selected. * @param cellHasFocus True if the specified cell has the focus. * * @return A component whose paint() method will render the specified value. * * @see javax.swing.JList * @see javax.swing.ListSelectionModel * @see javax.swing.ListModel */ public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean cellHasFocus) { IGuide cg = (IGuide)value; // Text String textName = cg.getTitle(); renderer.setText(textName); // Icon final String iconKey = cg.getIconKey() == null ? ResourceID.ICON_GUIDE_DEFAULT_KEY : cg.getIconKey(); ImageIcon icon = IconSource.getIcon(iconKey); if (icon == null) icon = IconSource.getIcon(ResourceID.ICON_GUIDE_DEFAULT_KEY); renderer.setIcon(icon); // Unread counter renderer.setUnreadCount(unreadController.deferCalcUnreadStats(cg)); // Colors Color background = isSelected ? RenderingManager.getFeedsListSelectedBackground() : RenderingManager.getFeedsListBackground(index % 2 == 0); Color foreground = GuideDisplayModeManager.getInstance().getColor(cg, isSelected); if (foreground == null || isSelected) { foreground = RenderingManager.getFeedsListForeground(isSelected); } renderer.setColors(background, foreground); // Border Border border = GlobalModel.SINGLETON.getSelectedGuide() == value && list.isFocusOwner() ? UIManager.getBorder("List.focusCellHighlightBorder") : BORDER_NO_FOCUS; renderer.setBorder(border); return renderer.getComponent(); } /** * Returns the height necessary to display a cell renderer by current renderer. * * @return the height of a cell. */ public int getRequiredHeight() { renderer.setText("ty"); renderer.setIcon(IconSource.getIcon(ResourceID.ICON_GUIDE_DEFAULT_KEY)); return renderer.getComponent().getPreferredSize().height; } /** * Number of pixels the unread button is away from the top. * * @return pixels. */ public int getUnreadButtonYOffset() { return renderer.getUnreadButtonYOffset(); } /** * The interface to be implemented */ private static interface IGuideCellRenderer { /** * Sets the text to be shown. * * @param text text. */ void setText(String text); /** * Sets the icon to be shown. * * @param icon icon. */ void setIcon(ImageIcon icon); /** * Sets under of unread elements to be shown. * * @param unread unread count. */ void setUnreadCount(int unread); /** * Sets background and foreground colors. * * @param background background. * @param foreground foreground. */ void setColors(Color background, Color foreground); /** * Sets the border around the cell. * * @param border border. */ void setBorder(Border border); /** * Shows / hides unread button. * * @param show unread button state. */ void showUnreadButton(boolean show); /** * Shows / hides icon. * * @param show icon state. */ void showIcon(boolean show); /** * Shows / hides text. * * @param show text state. */ void showText(boolean show); /** * Returns the component to display. * * @return component. */ Component getComponent(); /** * Number of pixels the unread button is away from the top. * * @return pixels. */ int getUnreadButtonYOffset(); } /** * Guide cell renderer with big icon, label and optional unread button. */ private static class LargeIconGuideCellRenderer extends JPanel implements IGuideCellRenderer { private static final String COLS = MessageFormat.format("{0}px, center:0:grow, right:p, {1}px", CELL_MARGIN_LEFT, CELL_MARGIN_RIGHT); private static final String ROWS = MessageFormat.format("{0}px, p, {1}px", CELL_MARGIN_TOP, CELL_MARGIN_BOTTOM); private JLabel iconLabel; private UnreadButton unreadButton; private boolean iconVisible; private boolean textVisible; /** * Creates the renderer. */ public LargeIconGuideCellRenderer() { iconLabel = new JLabel(ResourceUtils.getIcon(ResourceID.ICON_GUIDE_DEFAULT_KEY)); iconLabel.setFont(iconLabel.getFont().deriveFont(GUIDE_LABEL_FONT_SIZE)); iconLabel.setHorizontalTextPosition(SwingConstants.CENTER); iconLabel.setVerticalTextPosition(SwingConstants.BOTTOM); iconLabel.setAlignmentY(CENTER_ALIGNMENT); iconLabel.setIconTextGap(1); unreadButton = new UnreadButton(); init(); } /** Initializes the view. */ private void init() { // The unread button is in the upper-right corner. // The iconLabel is centered over both cells. This means that // it overlaps with the unreadButton, but because the icons tend // to be narrow the images don't collide, and this ensures that the // guide title can be laid out over the full width. setLayout(new FormLayout(COLS, ROWS)); CellConstraints cc = new CellConstraints(); add(iconLabel, cc.xyw(2, 2, 2)); add(unreadButton, cc.xy(3, 2, "center,top")); } /** * Number of pixels the unread button is away from the top. * * @return pixels. */ public int getUnreadButtonYOffset() { return 0; } /** * Returns the component to display. * * @return component. */ public Component getComponent() { return this; } /** * Sets background and foreground colors. * * @param background background. * @param foreground foreground. */ public void setColors(Color background, Color foreground) { setBackground(background); setForeground(foreground); iconLabel.setForeground(foreground); } /** * Sets the icon to be shown. * * @param icon icon. */ public void setIcon(ImageIcon icon) { iconLabel.setIcon(iconVisible ? icon : null); } /** * Sets the text to be shown. * * @param text text. */ public void setText(String text) { iconLabel.setText(textVisible ? text : null); } /** * Sets under of unread elements to be shown. * * @param unread unread count. */ public void setUnreadCount(int unread) { unreadButton.init(unread); } /** * Shows / hides unread button. * * @param show unread button state. */ public void showUnreadButton(boolean show) { unreadButton.setVisible(show); } /** * Shows / hides icon. * * @param show icon state. */ public void showIcon(boolean show) { iconVisible = show; } /** * Shows / hides text. * * @param show text state. */ public void showText(boolean show) { textVisible = show; } } /** * Small icon, label and optional button. This renderer is special in a * way it renders a big icon as small. */ private static class SmallIconGuideCellRenderer extends JPanel implements IGuideCellRenderer { private static final String COLS = MessageFormat.format("{0}px, 4px, p, 4px, left:0:grow, 4px, p, {1}px", CELL_MARGIN_LEFT, CELL_MARGIN_RIGHT); private static final String ROWS = MessageFormat.format("{0}px, p, {1}px", CELL_MARGIN_TOP, CELL_MARGIN_BOTTOM); private final ScalingIcon icon; private final JLabel text; private final UnreadButton unreadButton; private final int unreadButtonYOffset; /** Creates a new <code>JPanel</code> with a double buffer and a flow layout. */ public SmallIconGuideCellRenderer() { icon = new ScalingIcon(new Dimension(16, 16)); text = new JLabel(); text.setFont(text.getFont().deriveFont(GUIDE_LABEL_FONT_SIZE)); unreadButton = new UnreadButton(); unreadButtonYOffset = (16 - unreadButton.getSize().height) / 2; setLayout(new FormLayout(COLS, ROWS)); CellConstraints cc = new CellConstraints(); add(icon, cc.xy(3, 2)); add(text, cc.xy(5, 2)); add(unreadButton, cc.xy(7, 2)); } /** * Number of pixels the unread button is away from the top. * * @return pixels. */ public int getUnreadButtonYOffset() { return icon.isVisible() ? unreadButtonYOffset : 0; } /** * Returns the component to display. * * @return component. */ public Component getComponent() { return this; } /** * Sets background and foreground colors. * * @param background background. * @param foreground foreground. */ public void setColors(Color background, Color foreground) { setBackground(background); setForeground(foreground); text.setForeground(foreground); } /** * Sets the icon to be shown. * * @param anIcon icon. */ public void setIcon(ImageIcon anIcon) { icon.setIcon(anIcon); } /** * Sets the text to be shown. * * @param aText text. */ public void setText(String aText) { text.setText(aText); } /** * Sets under of unread elements to be shown. * * @param unread unread count. */ public void setUnreadCount(int unread) { unreadButton.init(unread); } /** * Shows / hides unread button. * * @param show unread button state. */ public void showUnreadButton(boolean show) { unreadButton.setVisible(show); } /** * Shows / hides icon. * * @param show icon state. */ public void showIcon(boolean show) { icon.setVisible(show); } /** * Shows / hides text. * * @param show text state. */ public void showText(boolean show) { text.setVisible(show); } } /** * Scales icon to given dimensions. */ private static class ScalingIcon extends JComponent { private final Dimension dimensions; private ImageIcon icon; /** * Creates icon displayer which shrinks or enlarges icon to the known dimensions. * * @param aDimensions dimensions. */ public ScalingIcon(Dimension aDimensions) { dimensions = aDimensions; icon = null; } /** * Returns the preferred size. * * @return the value of the <code>preferredSize</code> property */ public Dimension getPreferredSize() { return dimensions; } /** * Sets the icon to paint. * * @param anIcon icon. */ public void setIcon(ImageIcon anIcon) { icon = anIcon; repaint(); } /** * Invoked by Swing to draw components. * * @param g the <code>Graphics</code> context in which to paint */ public void paint(Graphics g) { if (icon != null) { Image image = icon.getImage(); image = image.getScaledInstance(dimensions.width, dimensions.height, Image.SCALE_SMOOTH); g.drawImage(image, 0, 0, null); } } } }