diff --git a/ccm-cms/src/com/arsdigita/cms/ContentBundle.java b/ccm-cms/src/com/arsdigita/cms/ContentBundle.java index e0a2fe86b..01403f752 100755 --- a/ccm-cms/src/com/arsdigita/cms/ContentBundle.java +++ b/ccm-cms/src/com/arsdigita/cms/ContentBundle.java @@ -408,7 +408,7 @@ public class ContentBundle extends ContentItem { * @return A Collection of language 2-letter codes in * which this item is available */ - public final Collection getLanguages() { + public final Collection getLanguages() { // XXX For LIVE bundles, there might be several PENDING // instances with the same language. Maybe we should filter // these out and return only one? diff --git a/ccm-cms/src/com/arsdigita/cms/ui/folder/CMSFolderResources.properties b/ccm-cms/src/com/arsdigita/cms/ui/folder/CMSFolderResources.properties index 9899f6ca4..226bb32a4 100755 --- a/ccm-cms/src/com/arsdigita/cms/ui/folder/CMSFolderResources.properties +++ b/ccm-cms/src/com/arsdigita/cms/ui/folder/CMSFolderResources.properties @@ -70,3 +70,4 @@ cms.ui.folder.no_such_item=Item ID supplied does not match an existing Content I cms.ui.folder.filter.all=All cms.ui.folder.filter=Filter for work cms.ui.folder.filter_do=Filter +cms.ui.folder.languages= diff --git a/ccm-cms/src/com/arsdigita/cms/ui/folder/CMSFolderResources_de.properties b/ccm-cms/src/com/arsdigita/cms/ui/folder/CMSFolderResources_de.properties index f52ea3a8f..c8f409279 100755 --- a/ccm-cms/src/com/arsdigita/cms/ui/folder/CMSFolderResources_de.properties +++ b/ccm-cms/src/com/arsdigita/cms/ui/folder/CMSFolderResources_de.properties @@ -66,3 +66,4 @@ cms.ui.folder.remove_asset_link=Entfernen cms.ui.folder.filter.all=Alle cms.ui.folder.filter=Nach Begriff filtern cms.ui.folder.filter_do=Filtern +cms.ui.folder.languages= diff --git a/ccm-cms/src/com/arsdigita/cms/ui/folder/CMSFolderResources_fr.properties b/ccm-cms/src/com/arsdigita/cms/ui/folder/CMSFolderResources_fr.properties index 32027ad8d..6ebfd1b34 100755 --- a/ccm-cms/src/com/arsdigita/cms/ui/folder/CMSFolderResources_fr.properties +++ b/ccm-cms/src/com/arsdigita/cms/ui/folder/CMSFolderResources_fr.properties @@ -65,3 +65,4 @@ cms.ui.folder.item_is_live=est en ligne ; Vous devez le d\u00e9-publier avant de cms.ui.folder.no_permission_for_item=Vous n'avez pas l'autorisation de supprimer ou de d\u00e9placer cms.ui.folder.no_such_item=L'identifiant fourni pour l'\u00e9l\u00e9ment ne correspond pas \u00e0 un contenu existant. cms.ui.folder.filter.all= +cms.ui.folder.languages= diff --git a/ccm-cms/src/com/arsdigita/cms/ui/folder/FolderBrowser.java b/ccm-cms/src/com/arsdigita/cms/ui/folder/FolderBrowser.java index 6a4dceb71..1339b0be0 100755 --- a/ccm-cms/src/com/arsdigita/cms/ui/folder/FolderBrowser.java +++ b/ccm-cms/src/com/arsdigita/cms/ui/folder/FolderBrowser.java @@ -32,8 +32,6 @@ import com.arsdigita.bebop.SimpleContainer; import com.arsdigita.bebop.Table; import com.arsdigita.bebop.event.ActionEvent; import com.arsdigita.bebop.event.ActionListener; -import com.arsdigita.bebop.event.ChangeEvent; -import com.arsdigita.bebop.event.ChangeListener; import com.arsdigita.bebop.event.TableActionAdapter; import com.arsdigita.bebop.event.TableActionEvent; import com.arsdigita.bebop.event.TableActionListener; @@ -45,12 +43,7 @@ import com.arsdigita.bebop.table.TableCellRenderer; import com.arsdigita.bebop.table.TableColumn; import com.arsdigita.bebop.table.TableHeader; import com.arsdigita.bebop.table.TableModel; -import com.arsdigita.cms.CMS; -import com.arsdigita.cms.ContentBundle; -import com.arsdigita.cms.ContentItem; -import com.arsdigita.cms.ContentSection; -import com.arsdigita.cms.Folder; -import com.arsdigita.cms.ItemCollection; +import com.arsdigita.cms.*; import com.arsdigita.cms.SecurityManager; import com.arsdigita.cms.dispatcher.ItemResolver; import com.arsdigita.cms.dispatcher.Utilities; @@ -68,12 +61,13 @@ import com.arsdigita.util.Assert; import org.apache.log4j.Logger; import java.math.BigDecimal; +import java.util.Iterator; import javax.servlet.ServletException; /** * Browse folders and items. If the user clicks on a folder, the folder - * selection model is updated. If the user clicks on any other item, an - * separate item selection model is updated. + * selection model is updated. If the user clicks on any other item, an separate + * item selection model is updated. * * @author David Lutterkort * @version $Id: FolderBrowser.java 2017 2009-10-04 09:03:45Z pboy $ @@ -82,18 +76,22 @@ public class FolderBrowser extends Table { private static final Logger s_log = Logger.getLogger(FolderBrowser.class); private static GlobalizedMessage[] s_headers = { - globalize("cms.ui.folder.name"), globalize("cms.ui.folder.title"), + globalize("cms.ui.folder.name"), + globalize("cms.ui.folder.languages"), + globalize("cms.ui.folder.title"), globalize("cms.ui.folder.type"), globalize("cms.ui.folder.creation_date"), - globalize("cms.ui.folder.last_modified"), globalize( - "cms.ui.folder.action"), + globalize("cms.ui.folder.last_modified"), + globalize("cms.ui.folder.action"), globalize("cms.ui.folder.index")}; private static GlobalizedMessage[] s_noIndexHeaders = { - globalize("cms.ui.folder.name"), globalize("cms.ui.folder.title"), + globalize("cms.ui.folder.name"), + globalize("cms.ui.folder.languages"), + globalize("cms.ui.folder.title"), globalize("cms.ui.folder.type"), globalize("cms.ui.folder.creation_date"), - globalize("cms.ui.folder.last_modified"), globalize( - "cms.ui.folder.action")}; + globalize("cms.ui.folder.last_modified"), + globalize("cms.ui.folder.action")}; private static final String SORT_ACTION_UP = "sortActionUp"; private static final String SORT_ACTION_DOWN = "sortActionDown"; private FolderSelectionModel m_currentFolder; @@ -122,8 +120,8 @@ public class FolderBrowser extends Table { setModelBuilder(new FolderTableModelBuilder(currentFolder)); setColumnModel(new DefaultTableColumnModel(hideIndexColumn() - ? s_noIndexHeaders - : s_headers)); + ? s_noIndexHeaders + : s_headers)); setHeader(new TableHeader(getColumnModel())); // DEE 1/18/02: the folder table model builder needs to know about // 'this' in order to set visibility, but 'this' isn't available @@ -139,22 +137,22 @@ public class FolderBrowser extends Table { m_currentFolder = currentFolder; /* - - This code should be uncommented if the desired behaviour is for a change - of folder to cause reversion to default ordering of contained items - (by name ascending). Our feeling is that the user selected ordering - should be retained for the duration of the folder browsing session. If - anyone wants this alternative behaviour it should be brought in under - the control of a config parameter. - - m_currentFolder.addChangeListener(new ChangeListener() { - - public void stateChanged(ChangeEvent e) { - PageState state = e.getPageState(); - state.setValue(m_sortType, m_sortType.getDefaultValue()); - state.setValue(m_sortDirection, m_sortDirection.getDefaultValue()); - - }}); + * + * This code should be uncommented if the desired behaviour is for a + * change of folder to cause reversion to default ordering of contained + * items (by name ascending). Our feeling is that the user selected + * ordering should be retained for the duration of the folder browsing + * session. If anyone wants this alternative behaviour it should be + * brought in under the control of a config parameter. + * + * m_currentFolder.addChangeListener(new ChangeListener() { + * + * public void stateChanged(ChangeEvent e) { PageState state = + * e.getPageState(); state.setValue(m_sortType, + * m_sortType.getDefaultValue()); state.setValue(m_sortDirection, + * m_sortDirection.getDefaultValue()); + * + * }}); */ setClassAttr("dataTable"); @@ -164,16 +162,17 @@ public class FolderBrowser extends Table { m_nameColumn = getColumn(0); m_nameColumn.setCellRenderer(new NameCellRenderer()); m_nameColumn.setHeaderRenderer(new HeaderCellRenderer(SORT_KEY_NAME)); - getColumn(1).setHeaderRenderer(new HeaderCellRenderer(SORT_KEY_TITLE)); - getColumn(3).setHeaderRenderer(new HeaderCellRenderer( - SORT_KEY_CREATION_DATE)); + getColumn(1).setCellRenderer(new LanguagesCellRenderer()); + getColumn(2).setHeaderRenderer(new HeaderCellRenderer(SORT_KEY_TITLE)); getColumn(4).setHeaderRenderer(new HeaderCellRenderer( + SORT_KEY_CREATION_DATE)); + getColumn(5).setHeaderRenderer(new HeaderCellRenderer( SORT_KEY_LAST_MODIFIED_DATE)); - m_deleteColumn = getColumn(5); + m_deleteColumn = getColumn(6); m_deleteColumn.setCellRenderer(new ActionCellRenderer()); m_deleteColumn.setAlign("center"); if (!hideIndexColumn()) { - m_indexColumn = getColumn(6); + m_indexColumn = getColumn(7); m_indexColumn.setCellRenderer(new IndexToggleRenderer()); m_indexColumn.setAlign("center"); @@ -217,7 +216,7 @@ public class FolderBrowser extends Table { boolean canDelete = sm.canAccess(state.getRequest(), SecurityManager.DELETE_ITEM, - folder); + folder); m_deleteColumn.setVisible(state, canDelete); } @@ -261,7 +260,7 @@ public class FolderBrowser extends Table { private class FolderTableModelBuilder extends AbstractTableModelBuilder implements PaginationModelBuilder, - FolderManipulator.FilterFormModelBuilder { + FolderManipulator.FilterFormModelBuilder { private FolderSelectionModel m_folder; private RequestLocal m_size; @@ -273,7 +272,7 @@ public class FolderBrowser extends Table { } public FolderTableModelBuilder(FolderSelectionModel sel, - FolderBrowser fb) { + FolderBrowser fb) { super(); m_folder = sel; m_size = new RequestLocal(); @@ -282,8 +281,7 @@ public class FolderBrowser extends Table { } public TableModel makeModel(Table t, PageState s) { - FolderSelectionModel sel = ((FolderBrowser) t). - getFolderSelectionModel(); + FolderSelectionModel sel = ((FolderBrowser) t).getFolderSelectionModel(); Folder f = (Folder) sel.getSelectedObject(s); if (f == null) { return Table.EMPTY_MODEL; @@ -291,7 +289,7 @@ public class FolderBrowser extends Table { t.getRowSelectionModel().clearSelection(s); s_log.debug(String.format("filter = '%s'", s.getValue(m_filter))); Folder.ItemCollection itemColl = - (Folder.ItemCollection) m_itemColl.get(s); + (Folder.ItemCollection) m_itemColl.get(s); s_log.debug(String.format("itemColl.size = %d", itemColl.size())); m_folderSize = itemColl.size(); @@ -363,7 +361,7 @@ public class FolderBrowser extends Table { size = new Integer((int) itemColl.size()); itemColl.setRange(new Integer(paginator.getFirst(state)), - new Integer(paginator.getLast(state) + 1)); + new Integer(paginator.getLast(state) + 1)); String sortKey = (String) state.getValue(m_sortType); String direction = "asc"; @@ -374,13 +372,13 @@ public class FolderBrowser extends Table { if (sortKey.equals(SORT_KEY_TITLE)) { itemColl.setOrder("lower(item." + ContentItem.DISPLAY_NAME - + ") " + direction); + + ") " + direction); } else if (sortKey.equals(SORT_KEY_NAME)) { itemColl.setOrder("lower(item." + ContentItem.NAME + ") " - + direction); + + direction); } else if (sortKey.equals(SORT_KEY_LAST_MODIFIED_DATE)) { itemColl.setOrder("item.auditing.lastModifiedDate " - + direction); + + direction); } else if (sortKey.equals(SORT_KEY_CREATION_DATE)) { itemColl.setOrder("item.auditing.creationDate " + direction); } @@ -397,11 +395,11 @@ public class FolderBrowser extends Table { } /** - * Indicates whether the paginator should be visible, - * based on the visibility of the folder browser itself. + * Indicates whether the paginator should be visible, based on the + * visibility of the folder browser itself. * - * @return true if folder browser is visible, or if the - * associated folder browser is unknown. + * @return true if folder browser is visible, or if the associated + * folder browser is unknown. */ public boolean isVisible(PageState state) { return (m_fb != null) ? m_fb.isVisible(state) : true; @@ -419,9 +417,9 @@ public class FolderBrowser extends Table { } public Component getComponent(final Table table, final PageState state, - Object value, - boolean isSelected, Object key, - int row, int column) { + Object value, + boolean isSelected, Object key, + int row, int column) { String headerName = (String) ((GlobalizedMessage) value).localize(); String sortKey = (String) state.getValue(m_sortType); final boolean isCurrentKey = sortKey.equals(m_key); @@ -442,14 +440,14 @@ public class FolderBrowser extends Table { // by default, everything sorts "up" unless it // is the current key and it is already pointing up if (SORT_ACTION_UP.equals(currentSortDirection) - && isCurrentKey) { + && isCurrentKey) { sortDirectionAction = SORT_ACTION_DOWN; } else { sortDirectionAction = SORT_ACTION_UP; } ps.setControlEvent(table, - sortDirectionAction, - m_key); + sortDirectionAction, + m_key); } }; Label l = new Label(); @@ -470,8 +468,8 @@ public class FolderBrowser extends Table { } /** - * Produce links to view an item or control links for folders - * to change into the folder. + * Produce links to view an item or control links for folders to change into + * the folder. */ private class NameCellRenderer extends DefaultTableCellRenderer { @@ -481,14 +479,14 @@ public class FolderBrowser 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) { Folder.ItemCollection coll = (Folder.ItemCollection) value; String name = coll.getName(); if (coll.isFolder()) { return super.getComponent(table, state, name, - isSelected, key, row, column); + isSelected, key, row, column); } else { ContentSection section = CMS.getContext().getContentSection(); BigDecimal id = coll.getID(); @@ -498,9 +496,101 @@ public class FolderBrowser extends Table { } else { ItemResolver resolver = section.getItemResolver(); return new Link(name, resolver.generateItemURL(state, id, - name, section, - coll. - getVersion())); + name, section, coll.getVersion())); + } + } + } + } + + /** + * Added by: Sören Bernstein + * + * Produce links to view an item in a specific language and show all + * existing language version and the live status in the folder browser. + */ + private class LanguagesCellRenderer extends DefaultTableCellRenderer { + + public LanguagesCellRenderer() { + super(true); + } + + @Override + public Component getComponent(Table table, PageState state, Object value, + boolean isSelected, Object key, + int row, int column) { + + Folder.ItemCollection coll = (Folder.ItemCollection) value; + String name = coll.getName(); + if (coll.isFolder()) { + // Nothing to show on folders + return new Label(); + } else { + + ContentPage cp; + + try { + cp = new ContentPage(coll.getID()); + } catch (DataObjectNotFoundException ex) { + // Content item was not found, return nothing + return new Label(); + } + + ContentBundle bundle = cp.getContentBundle(); + ContentSection section = CMS.getContext().getContentSection(); + + + if (bundle != null + && !(cp instanceof LanguageInvariantContentItem + && ((LanguageInvariantContentItem) cp).isLanguageInvariant())) { + + Iterator languages = bundle.getLanguages().iterator(); + + + + StringBuilder temp = new StringBuilder(20); + SimpleContainer container = new SimpleContainer(); + + while (languages.hasNext()) { + String lang = languages.next(); + ContentItem ci = bundle.getInstance(lang, false); + StringBuilder fontWeight = new StringBuilder(2); + StringBuilder classes = new StringBuilder(20); + + if (ci.isLive()) { + fontWeight.append(Label.BOLD); + classes.append("live "); + } + if (bundle.getPrimaryInstance().equals(ci)) { + fontWeight.append(Label.ITALIC); + classes.append("primaryInstance"); + } + + Label langLabel = new Label(lang); + langLabel.setFontWeight(fontWeight.toString().trim()); + langLabel.setClassAttr(classes.toString().trim()); + + if (section == null) { + container.add(langLabel); + + } else { + ItemResolver resolver = section.getItemResolver(); + container.add( + new Link(langLabel, + resolver.generateItemURL(state, + ci.getID(), + name, + section, + coll.getVersion()))); + } + if (languages.hasNext()) { + container.add(new Label(" ", false)); + } + + } + + return container; + } else { + return new Label(); } } } @@ -527,8 +617,8 @@ public class FolderBrowser extends Table { } 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 (((Boolean) value).booleanValue()) { return s_link; } else { @@ -540,8 +630,8 @@ public class FolderBrowser extends Table { private final class IndexToggleRenderer implements TableCellRenderer { 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 (value == null) { return new Label(GlobalizationUtil.globalize("cms.ui.folder.na")); @@ -558,7 +648,7 @@ public class FolderBrowser extends Table { } } - // Deletes an item +// Deletes an item private class ItemDeleter extends TableActionAdapter { public void cellSelected(TableActionEvent e) { @@ -596,12 +686,13 @@ public class FolderBrowser extends Table { private static class FolderTableModel implements TableModel { private static final int NAME = 0; - private static final int TITLE = 1; - private static final int TYPE = 2; - private static final int CREATION_DATE = 3; - private static final int LAST_MODIFIED = 4; - private static final int DELETABLE = 5; - private static final int IS_INDEX = 6; + private static final int LANGUAGES = 1; + private static final int TITLE = 2; + private static final int TYPE = 3; + private static final int CREATION_DATE = 4; + private static final int LAST_MODIFIED = 5; + private static final int DELETABLE = 6; + private static final int IS_INDEX = 7; private PageState m_state; private FolderBrowser m_table; private Folder.ItemCollection m_itemColl; @@ -613,7 +704,7 @@ public class FolderBrowser extends Table { //m_itemColl = folder.getItems(); //} public FolderTableModel(FolderBrowser table, PageState state, - Folder.ItemCollection itemColl) { + Folder.ItemCollection itemColl) { m_state = state; m_table = table; m_itemColl = itemColl; @@ -631,7 +722,7 @@ public class FolderBrowser extends Table { } public int getColumnCount() { - return hideIndexColumn() ? 6 : 7; + return hideIndexColumn() ? 7 : 8; } public boolean nextRow() { @@ -642,6 +733,8 @@ public class FolderBrowser extends Table { switch (columnIndex) { case NAME: return m_itemColl; + case LANGUAGES: + return m_itemColl; case TITLE: return m_itemColl.getDisplayName(); case TYPE: @@ -655,7 +748,7 @@ public class FolderBrowser extends Table { } case LAST_MODIFIED: { java.util.Date lastModified = - m_itemColl.getLastModifiedDate(); + m_itemColl.getLastModifiedDate(); if (lastModified == null) { return "--"; } @@ -675,13 +768,12 @@ public class FolderBrowser extends Table { if (m_folIndexID == null) { return new Boolean(false); } - return new Boolean(m_folIndexID.compareTo(m_itemColl. - getBundleID()) == 0); + return new Boolean(m_folIndexID.compareTo(m_itemColl.getBundleID()) == 0); } default: throw new IndexOutOfBoundsException("Column index " - + columnIndex - + " not in table model."); + + columnIndex + + " not in table model."); } } @@ -702,13 +794,13 @@ public class FolderBrowser extends Table { if (!m_itemColl.hasChildren()) { if (s_log.isDebugEnabled()) { s_log.debug("The item is an empty folder; it may be " - + "deleted"); + + "deleted"); } return true; } else { if (s_log.isDebugEnabled()) { s_log.debug("The folder is not empty; it cannot be " - + "deleted"); + + "deleted"); } return false; } @@ -724,7 +816,7 @@ public class FolderBrowser extends Table { public Object getKeyAt(int columnIndex) { // Mark folders by using their negative ID (dirty, dirty) return (m_itemColl.isFolder()) ? m_itemColl.getID().negate() - : m_itemColl.getBundleID(); + : m_itemColl.getBundleID(); } } @@ -767,11 +859,10 @@ public class FolderBrowser extends Table { Folder folder = (Folder) m_fol.getSelectedObject(state); - ContentBundle currentIndexItem = (ContentBundle) folder. - getIndexItem(); + ContentBundle currentIndexItem = (ContentBundle) folder.getIndexItem(); if (currentIndexItem == null || (currentIndexItem.getID(). - compareTo(contentItem.getID()) - != 0)) { + compareTo(contentItem.getID()) + != 0)) { folder.setIndexItem(contentItem); } else { folder.removeIndexItem(); @@ -786,8 +877,7 @@ public class FolderBrowser extends Table { /** * Getting the GlobalizedMessage using a CMS Class targetBundle. * - * @param key The resource key - * @pre ( key != null ) + * @param key The resource key @pre ( key != null ) */ private static GlobalizedMessage globalize(String key) { return FolderManipulator.globalize(key);