487 lines
16 KiB
Java
Executable File
487 lines
16 KiB
Java
Executable File
/*
|
|
* 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:
|
|
*
|
|
* <blockquote><pre><code>
|
|
* +-----------+-------+-------+------+----------+
|
|
* | Thumbnail | Name | Size | Type | |
|
|
* +-----------+-------+-------+------+----------+
|
|
* | . . | | | | |
|
|
* | { V } | smile | 20x42 | Jpeg | (select) |
|
|
* | ---- | | | | |
|
|
* +-----------+-------+-------+------+----------+
|
|
* | | | | | |
|
|
* </code></pre></blockquote>
|
|
*
|
|
* @author Stanislav Freidin
|
|
* @author Sören Bernstein <quasi@quasiweb.de>
|
|
* @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;
|
|
}
|
|
}
|
|
}
|