diff --git a/ccm-cms-assets-imagestep/pdl/com/arsdigita/cms/contentassets/ItemImageAttachment.pdl b/ccm-cms-assets-imagestep/pdl/com/arsdigita/cms/contentassets/ItemImageAttachment.pdl index ba233111e..ea0fc91b9 100755 --- a/ccm-cms-assets-imagestep/pdl/com/arsdigita/cms/contentassets/ItemImageAttachment.pdl +++ b/ccm-cms-assets-imagestep/pdl/com/arsdigita/cms/contentassets/ItemImageAttachment.pdl @@ -28,3 +28,16 @@ association { composite ContentItem[0..1] item = join cms_item_image_attachment.item_id to cms_items.item_id; } + +//get All items that are using +query getAllImageUser { + Integer itemID; + do{ + select item_id from cms_item_image_attachment + where image_id = :image_id + } + map{ + itemID = cms_item_image_attachment.item_id; + } +} + diff --git a/ccm-cms-assets-imagestep/src/com/arsdigita/cms/ImageInUseCheck.java b/ccm-cms-assets-imagestep/src/com/arsdigita/cms/ImageInUseCheck.java new file mode 100644 index 000000000..dfab8e6a6 --- /dev/null +++ b/ccm-cms-assets-imagestep/src/com/arsdigita/cms/ImageInUseCheck.java @@ -0,0 +1,53 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.arsdigita.cms; + +import com.arsdigita.persistence.DataQuery; +import com.arsdigita.persistence.Filter; +import com.arsdigita.persistence.SessionManager; +import static com.redhat.persistence.Expression.value; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author Koalamann + */ +public class ImageInUseCheck implements ImageInUseChecker { + + @Override + public boolean isImageInUse(ReusableImageAsset image) { + + DataQuery q = SessionManager.getSession().retrieveQuery( + "com.arsdigita.cms.contentassets.getAllImageUser"); + q.setParameter("image_id", image.getID()); + + if (q.isEmpty()) { + return false; + } + + return true; + } + + /* + * get all users(content-items) that are using the image. + * + */ + @Override + public List getImageUsers(ReusableImageAsset image) { + ArrayList list = new ArrayList(); + DataQuery query = SessionManager.getSession().retrieveQuery( + "com.arsdigita.cms.contentassets.getAllImageUser"); + query.setParameter("image_id", image.getID()); + + while (query.next()) { + Object itemID = query.get("itemID"); + list.add(itemID); + } + + return list; + } +} diff --git a/ccm-cms-assets-imagestep/src/com/arsdigita/cms/contentassets/ItemImageAttachmentInitializer.java b/ccm-cms-assets-imagestep/src/com/arsdigita/cms/contentassets/ItemImageAttachmentInitializer.java index 03d018ebf..6d7ab5ee3 100755 --- a/ccm-cms-assets-imagestep/src/com/arsdigita/cms/contentassets/ItemImageAttachmentInitializer.java +++ b/ccm-cms-assets-imagestep/src/com/arsdigita/cms/contentassets/ItemImageAttachmentInitializer.java @@ -18,6 +18,8 @@ package com.arsdigita.cms.contentassets; import com.arsdigita.cms.ContentPage; +import com.arsdigita.cms.ImageInUseCheck; +import com.arsdigita.cms.ReusableImageAsset; import com.arsdigita.cms.contenttypes.ContentAssetInitializer; import com.arsdigita.cms.contentassets.ui.ImageStep; import com.arsdigita.domain.DomainObject; @@ -64,6 +66,9 @@ public class ItemImageAttachmentInitializer extends ContentAssetInitializer { } }); + + //register checker in ReusableImage + ReusableImageAsset.registerImageInUseChecker(new ImageInUseCheck()); } diff --git a/ccm-cms/src/com/arsdigita/cms/ImageInUseChecker.java b/ccm-cms/src/com/arsdigita/cms/ImageInUseChecker.java new file mode 100644 index 000000000..6bf6dfa68 --- /dev/null +++ b/ccm-cms/src/com/arsdigita/cms/ImageInUseChecker.java @@ -0,0 +1,44 @@ +/* + * 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; + +import java.util.List; + +/** + * This interface should be used to check if an image is still in use. + * Useful to determine if you can delete an image. + * + * @author Koalamann + */ +public interface ImageInUseChecker { + + /* + * checks if the Image is currently in use + * + * @return false if the image is not used by anyone + */ + boolean isImageInUse(ReusableImageAsset image); + + /* + * get all users(content-items) that are using the image. + * + */ + List getImageUsers(ReusableImageAsset image); + +} diff --git a/ccm-cms/src/com/arsdigita/cms/ReusableImageAsset.java b/ccm-cms/src/com/arsdigita/cms/ReusableImageAsset.java index 400fcc939..454e84a49 100755 --- a/ccm-cms/src/com/arsdigita/cms/ReusableImageAsset.java +++ b/ccm-cms/src/com/arsdigita/cms/ReusableImageAsset.java @@ -27,13 +27,14 @@ import com.arsdigita.persistence.OID; import com.arsdigita.persistence.SessionManager; import com.arsdigita.versioning.VersionedACSObject; import java.math.BigDecimal; - +import java.util.ArrayList; +import java.util.List; import org.apache.log4j.Logger; /** - *

An {@link com.arsdigita.cms.Asset asset} representing a reusable - * image.

+ *

+ * An {@link com.arsdigita.cms.Asset asset} representing a reusable image.

* * @see com.arsdigita.cms.ImageAsset * @@ -44,10 +45,12 @@ import org.apache.log4j.Logger; */ public class ReusableImageAsset extends ImageAsset { - private static final Logger s_log = - Logger.getLogger(ReusableImageAsset.class); - public static final String BASE_DATA_OBJECT_TYPE = - "com.arsdigita.cms.ReusableImageAsset"; + private static final Logger s_log + = Logger.getLogger(ReusableImageAsset.class); + public static final String BASE_DATA_OBJECT_TYPE + = "com.arsdigita.cms.ReusableImageAsset"; + + private static ArrayList imageInUseCheckerList = new ArrayList(); /** * Default constructor. This creates a new image asset. @@ -57,9 +60,9 @@ public class ReusableImageAsset extends ImageAsset { } /** - * Constructor. The contained DataObject is retrieved - * from the persistent storage mechanism with an OID - * specified by oid. + * Constructor. The contained DataObject is retrieved from the + * persistent storage mechanism with an OID specified by + * oid. * * @param oid The OID for the retrieved * DataObject. @@ -69,14 +72,13 @@ public class ReusableImageAsset extends ImageAsset { } /** - * Constructor. The contained DataObject is retrieved - * from the persistent storage mechanism with an OID - * specified by id and - * ReusableImageAsset.BASE_DATA_OBJECT_TYPE. + * Constructor. The contained DataObject is retrieved from the + * persistent storage mechanism with an OID specified by + * id and ReusableImageAsset.BASE_DATA_OBJECT_TYPE. * - * @param id The id for the retrieved - * DataObject. - **/ + * @param id The id for the retrieved DataObject. + * + */ public ReusableImageAsset(BigDecimal id) throws DataObjectNotFoundException { this(new OID(BASE_DATA_OBJECT_TYPE, id)); } @@ -91,9 +93,9 @@ public class ReusableImageAsset extends ImageAsset { /** * @return the base PDL object type for this item. Child classes should - * override this method to return the correct value + * override this method to return the correct value */ - @Override + @Override public String getBaseDataObjectType() { return BASE_DATA_OBJECT_TYPE; } @@ -109,11 +111,11 @@ public class ReusableImageAsset extends ImageAsset { //da.addEqualsFilter(VersionedACSObject.IS_DELETED, new Integer(0)); //da.addEqualsFilter(ACSObject.OBJECT_TYPE, BASE_DATA_OBJECT_TYPE); da.addFilter(String.format("%s = '%s'", - VersionedACSObject.IS_DELETED, - "0")); + VersionedACSObject.IS_DELETED, + "0")); da.addFilter(String.format("%s = '%s'", - ACSObject.OBJECT_TYPE, - BASE_DATA_OBJECT_TYPE)); + ACSObject.OBJECT_TYPE, + BASE_DATA_OBJECT_TYPE)); return new ImageAssetCollection(da); } @@ -122,7 +124,7 @@ public class ReusableImageAsset extends ImageAsset { * * @param keyword a String keyword * @param context the context for the retrieved items. Should be - * {@link ContentItem#DRAFT} or {@link ContentItem#LIVE} + * {@link ContentItem#DRAFT} or {@link ContentItem#LIVE} * @return a collection of images whose name matches the keyword */ public static ImageAssetCollection getReusableImagesByKeyword( @@ -132,7 +134,7 @@ public class ReusableImageAsset extends ImageAsset { Filter f; if (!(keyword == null || keyword.length() < 1)) { f = c.addFilter("lower(name) like lower(\'%\' || :keyword || \'%\')"); - f.set("keyword", keyword); + f.set("keyword", keyword); } f = c.addFilter("version = :version"); f.set("version", context); @@ -148,4 +150,53 @@ public class ReusableImageAsset extends ImageAsset { public static ImageAssetCollection getReusableImagesByKeyword(String keyword) { return getReusableImagesByKeyword(keyword, ContentItem.DRAFT); } + + public static void registerImageInUseChecker(ImageInUseChecker checker) { + //check if the checker is already registered + if (imageInUseCheckerList.contains(checker)) { + //do nothing + return; + } + //register checker + imageInUseCheckerList.add(checker); + } + +// +// public ImageInUseChecker getChecker(ImageInUseChecker checker) { +// for (Iterator it = imageInUseCheckerList.iterator(); it.hasNext();) { +// Object check = it.next(); +// if (check.equals(checker)) { +// return (ImageInUseChecker)check; +// } +// } +// return checker; +// } + /* + *checks if the ReusableImageAsset is in use + */ + public boolean isInUse() { + boolean isInUse = false; + //get Checker: + //TODO: getting the right checker + for (ImageInUseChecker checker : imageInUseCheckerList) { + if (checker != null) { + if (checker.isImageInUse(this)) { + isInUse = true; + } + } + } + return isInUse; + } + + public List getImageUsers() { + List list = new ArrayList(); + for (ImageInUseChecker checker : imageInUseCheckerList) { + + if (checker != null) { + list = checker.getImageUsers(this); + } + } + return list; + } + } diff --git a/ccm-cms/src/com/arsdigita/cms/ui/ImageBrowser.java b/ccm-cms/src/com/arsdigita/cms/ui/ImageBrowser.java index 40d039d7d..6f3ff6a2b 100755 --- a/ccm-cms/src/com/arsdigita/cms/ui/ImageBrowser.java +++ b/ccm-cms/src/com/arsdigita/cms/ui/ImageBrowser.java @@ -18,6 +18,7 @@ */ package com.arsdigita.cms.ui; +import com.arsdigita.bebop.BoxPanel; import com.arsdigita.bebop.Component; import com.arsdigita.bebop.Image; import com.arsdigita.bebop.Label; @@ -33,9 +34,13 @@ 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.ContentItem; +import com.arsdigita.cms.ContentSection; import com.arsdigita.cms.ImageAsset; +import com.arsdigita.cms.ReusableImageAsset; import com.arsdigita.cms.SecurityManager; import com.arsdigita.cms.Service; +import com.arsdigita.cms.dispatcher.ItemResolver; import com.arsdigita.cms.util.GlobalizationUtil; import com.arsdigita.domain.DataObjectNotFoundException; import com.arsdigita.domain.DomainObjectFactory; @@ -45,6 +50,7 @@ import com.arsdigita.util.LockableImpl; import com.arsdigita.web.URL; import com.arsdigita.util.Dimension; import java.math.BigDecimal; +import java.util.List; import org.apache.log4j.Logger; /** @@ -107,8 +113,7 @@ public class ImageBrowser extends Table { * Construct a new ImageBrowser with default mode. * * @param builder the {@link ImageBrowserModelBuilder} that will supply this - * component with its {@link ImageBrowserModel} during each - * request + * component with its {@link ImageBrowserModel} during each request */ public ImageBrowser(ImageBrowserModelBuilder b) { @@ -119,9 +124,8 @@ public class ImageBrowser extends Table { * 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}) + * component with its {@link ImageBrowserModel} during each request + * @param mode the component mode (see {@link ImageComponent}) */ public ImageBrowser(ImageBrowserModelBuilder b, int mode) { @@ -131,37 +135,37 @@ public class ImageBrowser extends Table { m_mode = mode; setThumbnailSize(CMS.getConfig().getImageBrowserThumbnailMaxWidth(), - CMS.getConfig().getImageBrowserThumbnailMaxHeight()); + 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") - ))); + 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") - ))); + 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") - ))); + 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") - ))); + 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") - ))); + 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 + DELETE, null // probs with images probably in use // new Label(GlobalizationUtil.globalize( // "cms.contentasset.image.ui.table.header_action_delete")) )); @@ -225,7 +229,7 @@ public class ImageBrowser extends Table { * is clicked. Child classes should override the linkClicked method. */ public static abstract class LinkActionListener - extends TableActionAdapter { + extends TableActionAdapter { /** * @@ -236,10 +240,10 @@ public class ImageBrowser extends Table { int c = e.getColumn().intValue(); if (c == SELECT) { linkClicked(e.getPageState(), - new BigDecimal((String) e.getRowKey())); + new BigDecimal((String) e.getRowKey())); } else if (c == DELETE) { deleteClicked(e.getPageState(), - new BigDecimal((String) e.getRowKey())); + new BigDecimal((String) e.getRowKey())); } } @@ -256,12 +260,12 @@ public class ImageBrowser extends Table { @Override public Component getComponent(Table table, PageState state, Object value, - boolean isSelected, Object key, - int row, int column) { + boolean isSelected, Object key, + int row, int column) { ImageAsset a = (ImageAsset) value; Double aspectRatio = a.getWidth().doubleValue() / a.getHeight() - .doubleValue(); + .doubleValue(); Double width; Double height; @@ -273,18 +277,18 @@ public class ImageBrowser extends Table { height = m_thumbSize.getHeight(); width = height * aspectRatio; } - + 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(); + .getWidth()).intValue() + + "&maxHeight=" + + new Double(m_thumbSize + .getHeight()) + .intValue(); Image img = new Image(URL.getDispatcherPath() + url + resizeParam, - a.getName()); + a.getName()); img.setBorder("0"); // final Double width = m_thumbSize.getWidth(); @@ -320,13 +324,13 @@ public class ImageBrowser extends Table { */ @Override public Component getComponent(Table table, PageState state, Object value, - boolean isSelected, Object key, - int row, int column) { + 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); + isSelected, key, row, column); } // return new Label(""); // this variant is deprecated! @@ -337,7 +341,7 @@ public class ImageBrowser extends Table { /** * Inner private class renders the delete link if the user has permission to - * deletethe asset and it's not used in an article. + * delete the asset and it's not used in an article. */ private class DeleteCellRenderer extends DefaultTableCellRenderer { @@ -359,8 +363,8 @@ public class ImageBrowser extends Table { */ @Override public Component getComponent(Table table, PageState state, Object value, - boolean isSelected, Object key, - int row, int column) { + boolean isSelected, Object key, + int row, int column) { // Only show delete link in admin mode if (m_mode == ImageComponent.ADMIN_IMAGES) { @@ -369,12 +373,16 @@ public class ImageBrowser extends Table { // SecurityManager sm = Utilities.getSecurityManager(state); SecurityManager sm = CMS.getSecurityManager(state); if (sm.canAccess(state.getRequest(), - SecurityManager.DELETE_IMAGES)) { + SecurityManager.DELETE_IMAGES)) { try { - ImageAsset asset = (ImageAsset) DomainObjectFactory - .newInstance(new OID( - ImageAsset.BASE_DATA_OBJECT_TYPE, - (BigDecimal) key)); + //vorher war ImageAsset + ReusableImageAsset asset = (ReusableImageAsset) DomainObjectFactory + .newInstance(new OID( + ImageAsset.BASE_DATA_OBJECT_TYPE, + (BigDecimal) key)); + + canDelete = !asset.isInUse(); + //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)) { @@ -389,27 +397,105 @@ public class ImageBrowser extends Table { // can delete image because it's not in use if (canDelete) { return super.getComponent(table, - state, - value, - isSelected, - key, - row, - column); + 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(); + //get all items that uses the image: + try { + ReusableImageAsset asset = (ReusableImageAsset) DomainObjectFactory + .newInstance(new OID( + ImageAsset.BASE_DATA_OBJECT_TYPE, + (BigDecimal) key)); + List list = asset.getImageUsers(); + + return createLabel(list, state); + + } catch (DataObjectNotFoundException e) { + // can't find asset, can't delete it + } + + return new Label("image is in use"); } } + /** + * creates a BoxPanel with links to the items that are using the image + * + * @param list list with the itemIDs + * @param state PageState + * @return + */ + private BoxPanel createLabel(List list, PageState state) { + + int size = list.size(); + BoxPanel links = new BoxPanel(); + + if (size == 0) { + links.add(new Label("currently not in use")); + return links; + } + if (size >= 1) { + links.add(createLink(state, list, 0)); + } + if (size >= 2) { + links.add(createLink(state, list, 1)); + } + if (size >= 3) { + links.add(createLink(state, list, 2)); + } + if (size > 3) { + int size2 = size - 3; + links.add(new Label("and " + size2 + " more")); + } + return links; + + } + + /** + * creates the link to an item of the list. + * + * @param state PageState + * @param list list with itemIDs + * @param index + * @return + */ + private Link createLink(PageState state, List list, int index) { + + ContentItem item = (ContentItem) DomainObjectFactory + .newInstance(new OID( + ContentItem.BASE_DATA_OBJECT_TYPE, + new BigDecimal((Integer) list.get(index)))); + + ContentSection section = item.getContentSection(); + ItemResolver resolver = section.getItemResolver(); + + String displayName = item.getDisplayName(); + if (displayName.length() > 20) { + displayName = displayName.substring(0, 15); + } + + Link link = new Link( + "used by " + displayName, + resolver.generateItemURL( + state, + (item.getDraftVersion()), + section, + (item.getDraftVersion()).getVersion())); + return link; + } + /** * Inner private class converts an ImageBrowserModelBuilder to a * TableModelBuilder */ private static class BuilderAdapter extends LockableImpl - implements TableModelBuilder { + implements TableModelBuilder { private ImageBrowserModelBuilder m_builder; @@ -420,7 +506,7 @@ public class ImageBrowser extends Table { @Override public TableModel makeModel(Table t, PageState s) { return new ImageModelAdapter( - m_builder.makeModel((ImageBrowser) t, s)); + m_builder.makeModel((ImageBrowser) t, s)); } @Override @@ -462,7 +548,13 @@ public class ImageBrowser extends Table { return a; case ImageBrowser.NAME: - return a.getName(); + String name = a.getName(); + if (name.length() > 32) { + return name.substring(0, 31); + + }else{ + return name; + } case ImageBrowser.SIZE: StringBuilder buf = new StringBuilder(); @@ -497,15 +589,15 @@ public class ImageBrowser extends Table { // 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(); + "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(); + "cms.contentasset.image.ui.table.link_delete") + .localize(); default: return null;