/* * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package com.arsdigita.cms.ui; import com.arsdigita.bebop.Component; import com.arsdigita.bebop.Image; import com.arsdigita.bebop.Label; import com.arsdigita.bebop.Link; import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.Table; import com.arsdigita.bebop.event.TableActionAdapter; import com.arsdigita.bebop.event.TableActionEvent; import com.arsdigita.bebop.table.DefaultTableCellRenderer; import com.arsdigita.bebop.table.TableCellRenderer; import com.arsdigita.bebop.table.TableColumn; import com.arsdigita.bebop.table.TableColumnModel; import com.arsdigita.bebop.table.TableModel; import com.arsdigita.bebop.table.TableModelBuilder; import com.arsdigita.cms.CMS; import com.arsdigita.cms.ImageAsset; import com.arsdigita.cms.SecurityManager; import com.arsdigita.cms.Service; import com.arsdigita.cms.util.GlobalizationUtil; import com.arsdigita.domain.DataObjectNotFoundException; import com.arsdigita.domain.DomainObjectFactory; import com.arsdigita.mimetypes.MimeType; import com.arsdigita.persistence.OID; import com.arsdigita.util.LockableImpl; import com.arsdigita.web.URL; import java.awt.Dimension; import java.math.BigDecimal; import org.apache.log4j.Logger; /** * Displays a list of images in a Table. The table will look something like * this: * *

 * +-----------+-------+-------+------+----------+
 * | Thumbnail | Name  | Size  | Type |          |
 * +-----------+-------+-------+------+----------+
 * |   .  .    |       |       |      |          |
 * | {   V  }  | smile | 20x42 | Jpeg | (select) |
 * |   ----    |       |       |      |          |
 * +-----------+-------+-------+------+----------+
 * |           |       |       |      |          |
 * 
* * @author Stanislav Freidin * @author Sören Bernstein * @version $Id: ImageBrowser.java 1940 2009-05-29 07:15:05Z terry $ */ public class ImageBrowser extends Table { private static final Logger s_log = Logger.getLogger(ImageBrowser.class); private ImageBrowserModelBuilder m_builder; // match columns by (symbolic) index, makes for easier reordering /** Index into TableColumn for Thumb column */ private static final int THUMB = 0; /** Index into TableColumn for Name column */ private static final int NAME = 1; /** Index into TableColumn for Size column */ private static final int SIZE = 2; /** Index into TableColumn for Type column */ private static final int TYPE = 3; /** Index into TableColumn for Select link column */ private static final int SELECT = 4; /** Index into TableColumn for Delete link column */ private static final int DELETE = 5; private int m_numColumns = -1; private int m_mode; private Dimension m_thumbSize; /** * Construct a new ImageBrowser with default mode. * * @param builder the {@link ImageBrowserModelBuilder} that will supply this * component with its {@link ImageBrowserModel} during each * request */ public ImageBrowser(ImageBrowserModelBuilder b) { this(b, ImageComponent.ATTACH_IMAGE); } /** * Construct a new ImageBrowser table with requested mode. * * @param builder the {@link ImageBrowserModelBuilder} that will supply this * component with its {@link ImageBrowserModel} during each * request * @param mode the component mode (see {@link ImageComponent}) */ public ImageBrowser(ImageBrowserModelBuilder b, int mode) { super(); // Create an empty table m_builder = b; m_mode = mode; setThumbnailSize(CMS.getConfig().getImageBrowserThumbnailMaxWidth(), CMS.getConfig().getImageBrowserThumbnailMaxHeight()); /* Add columns and column header to the yet empty table */ TableColumnModel model = getColumnModel(); model.add(new TableColumn( THUMB, new Label(GlobalizationUtil.globalize( "cms.contentasset.image.ui.table.header_thumb") ) )); model.add(new TableColumn( NAME, new Label(GlobalizationUtil.globalize( "cms.contentasset.image.ui.table.header_name") ) )); model.add(new TableColumn( SIZE, new Label(GlobalizationUtil.globalize( "cms.contentasset.image.ui.table.header_size") ) )); model.add(new TableColumn( TYPE, new Label(GlobalizationUtil.globalize( "cms.contentasset.image.ui.table.header_type") ) )); model.add(new TableColumn( SELECT, new Label(GlobalizationUtil.globalize( "cms.contentasset.image.ui.table.header_action_select") ) )); model.add(new TableColumn( // Temporary not used due to consistency DELETE, null // probs with images probably in use // new Label(GlobalizationUtil.globalize( // "cms.contentasset.image.ui.table.header_action_delete")) )); model.get(THUMB).setCellRenderer(new ThumbnailCellRenderer()); model.get(NAME).setCellRenderer(new DefaultTableCellRenderer(false)); model.get(SIZE).setCellRenderer(new DefaultTableCellRenderer(false)); model.get(TYPE).setCellRenderer(new DefaultTableCellRenderer(false)); model.get(SELECT).setCellRenderer(new SelectCellRenderer()); model.get(DELETE).setCellRenderer(new DeleteCellRenderer()); setModelBuilder(new BuilderAdapter(b)); setCellPadding("4"); setBorder("1"); setClassAttr("imageBrowser"); } /** * * @return */ public int getNumColumns() { return m_numColumns; } /** * @return the size, in pixels, of the thumbnail images */ public Dimension getThumbnailSize() { return m_thumbSize; } /** * Set the thumbnail size * * @param size the size, in pixels, of the thumbnail images */ public final void setThumbnailSize(int width, int height) { m_thumbSize = new Dimension(width, height); } /** * @return the {@link ImageBrowserModelBuilder} */ public ImageBrowserModelBuilder getImageBrowserModelBuilder() { return m_builder; } /** * @param state The current page state * * @return the {@link ImageBrowserModel} used in the current request */ public ImageBrowserModel getImageBrowserModel(PageState state) { return ((ImageModelAdapter) getTableModel(state)).getModel(); } /** * Inner class action listener that only gets fired when the "select" link * is clicked. Child classes should override the linkClicked method. */ public static abstract class LinkActionListener extends TableActionAdapter { /** * * @param e */ @Override public void cellSelected(TableActionEvent e) { int c = e.getColumn().intValue(); if (c == SELECT) { linkClicked(e.getPageState(), new BigDecimal((String) e.getRowKey())); } else if (c == DELETE) { deleteClicked(e.getPageState(), new BigDecimal((String) e.getRowKey())); } } public abstract void linkClicked(PageState state, BigDecimal imageId); public abstract void deleteClicked(PageState state, BigDecimal imageId); } /** * Inner private class renders a static image for the current asset. */ private class ThumbnailCellRenderer implements TableCellRenderer { @Override public Component getComponent(Table table, PageState state, Object value, boolean isSelected, Object key, int row, int column) { ImageAsset a = (ImageAsset) value; String url = Service.getImageURL(a); // Sets url paramter to resize the images server-side String resizeParam = "&maxWidth=" + new Double(m_thumbSize.getWidth()).intValue() + "&maxHeight=" + new Double(m_thumbSize.getHeight()).intValue(); Image img = new Image(URL.getDispatcherPath() + url + resizeParam, a.getName()); img.setBorder("0"); return new Link(img, url); } } /** * Inner private class renders the select link if the mode needs one */ private class SelectCellRenderer extends DefaultTableCellRenderer { public SelectCellRenderer() { super(true); } /** * * @param table * @param state * @param value * @param isSelected * @param key * @param row * @param column * @return */ @Override public Component getComponent(Table table, PageState state, Object value, boolean isSelected, Object key, int row, int column) { if (m_mode == ImageComponent.SELECT_IMAGE || m_mode == ImageComponent.ATTACH_IMAGE) { return super.getComponent(table, state, value, isSelected, key, row, column); } // return new Label(""); // this variant is deprecated! return new Label(); } } /** * Inner private class renders the delete link if the user has permission * to deletethe asset and it's not used in an article. */ private class DeleteCellRenderer extends DefaultTableCellRenderer { public DeleteCellRenderer() { super(true); } /** * * @param table * @param state * @param value * @param isSelected * @param key * @param row * @param column * @return */ @Override public Component getComponent(Table table, PageState state, Object value, boolean isSelected, Object key, int row, int column) { // Only show delete link in admin mode if (m_mode == ImageComponent.ADMIN_IMAGES) { boolean canDelete = false; // SecurityManager sm = Utilities.getSecurityManager(state); SecurityManager sm = CMS.getSecurityManager(state); if (sm.canAccess(state.getRequest(), SecurityManager.DELETE_IMAGES)) { try { ImageAsset asset = (ImageAsset) DomainObjectFactory .newInstance(new OID(ImageAsset.BASE_DATA_OBJECT_TYPE, (BigDecimal) key)); //XXX Find a new way to figure out, if this image is used by any CI so we can // decide if it can be deleted // if (!GenericArticleImageAssociation.imageHasAssociation(asset)) { // canDelete = true; // } } catch (DataObjectNotFoundException e) { // can't find asset, can't delete it } } // can delete image because it's not in use if (canDelete) { return super.getComponent(table, state, value, isSelected, key, row, column); } } // return (Component) null; // used to work for other tables but // doesn't here for some reason. return new Label(); } } /** * Inner private class converts an ImageBrowserModelBuilder to a * TableModelBuilder */ private static class BuilderAdapter extends LockableImpl implements TableModelBuilder { private ImageBrowserModelBuilder m_builder; public BuilderAdapter(ImageBrowserModelBuilder b) { m_builder = b; } @Override public TableModel makeModel(Table t, PageState s) { return new ImageModelAdapter( m_builder.makeModel((ImageBrowser) t, s)); } @Override public void lock() { m_builder.lock(); super.lock(); } } /** * Inner private class converts an ImageBrowserModel to a TableModel. */ private static class ImageModelAdapter implements TableModel { private ImageBrowserModel m_model; public ImageModelAdapter(ImageBrowserModel m) { m_model = m; } @Override public int getColumnCount() { return ((ImageBrowser) m_model).getNumColumns(); // return ImageBrowser.s_numColumns; } @Override public boolean nextRow() { return m_model.nextRow(); } @Override public Object getElementAt(int columnIndex) { ImageAsset a = m_model.getImageAsset(); switch (columnIndex) { case ImageBrowser.THUMB: return a; case ImageBrowser.NAME: return a.getName(); case ImageBrowser.SIZE: StringBuilder buf = new StringBuilder(); BigDecimal v; v = a.getWidth(); if (v == null) { buf.append("???"); } else { buf.append(v.toString()); } buf.append(" x "); v = a.getHeight(); if (v == null) { buf.append("???"); } else { buf.append(v.toString()); } return buf.toString(); case ImageBrowser.TYPE: MimeType m = a.getMimeType(); if (m == null) { return "???"; } return m.getMimeType(); case ImageBrowser.SELECT: // Due to current design has to be a string! Localisation // works here nevertheless. return (String) GlobalizationUtil.globalize( "cms.contentasset.image.ui.table.link_select") .localize(); case ImageBrowser.DELETE: // Due to current design has to be a string! Localisation // works here nevertheless. return (String) GlobalizationUtil.globalize( "cms.contentasset.image.ui.table.link_delete") .localize(); default: return null; } } @Override public Object getKeyAt(int columnIndex) { return m_model.getImageAsset().getID(); } public ImageBrowserModel getModel() { return m_model; } } }