CCM NG/ccm-cms: Progress for ItemLanguages and related classes (not finished yet)

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4454 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2016-11-23 18:35:16 +00:00
parent 681ba87a68
commit 582bcab967
14 changed files with 509 additions and 232 deletions

View File

@ -53,9 +53,6 @@ public class ItemSelectionModel extends CcmObjectSelectionModel<ContentItem> {
private Long typeId; private Long typeId;
private static final Logger LOGGER = Logger.getLogger(
ItemSelectionModel.class);
/** /**
* Construct a new <code>ItemSelectionModel</code> * Construct a new <code>ItemSelectionModel</code>
* *

View File

@ -23,6 +23,7 @@ import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.FormProcessException; import com.arsdigita.bebop.FormProcessException;
import com.arsdigita.bebop.Label; import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.SingleSelectionModel;
import com.arsdigita.bebop.event.FormProcessListener; import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSectionEvent; import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.event.PrintEvent; import com.arsdigita.bebop.event.PrintEvent;
@ -30,13 +31,17 @@ import com.arsdigita.bebop.event.PrintListener;
import com.arsdigita.bebop.form.Option; import com.arsdigita.bebop.form.Option;
import com.arsdigita.bebop.form.OptionGroup; import com.arsdigita.bebop.form.OptionGroup;
import com.arsdigita.bebop.form.Submit; import com.arsdigita.bebop.form.Submit;
import org.librecms.contentsection.ContentItem; import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.ContentType; import org.librecms.contentsection.ContentType;
import com.arsdigita.cms.ItemSelectionModel; import com.arsdigita.cms.ItemSelectionModel;
import com.arsdigita.cms.ui.ContentItemPage; import com.arsdigita.cms.ui.ContentItemPage;
import com.arsdigita.cms.ui.authoring.LanguageWidget; import com.arsdigita.cms.ui.authoring.LanguageWidget;
import org.librecms.util.LanguageUtil; import org.librecms.util.LanguageUtil;
import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.toolbox.ui.ActionGroup; import com.arsdigita.toolbox.ui.ActionGroup;
import com.arsdigita.toolbox.ui.LayoutPanel; import com.arsdigita.toolbox.ui.LayoutPanel;
@ -46,12 +51,17 @@ import com.arsdigita.util.Pair;
import com.arsdigita.util.UncheckedWrapperException; import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.web.RedirectSignal; import com.arsdigita.web.RedirectSignal;
import com.arsdigita.web.URL; import com.arsdigita.web.URL;
import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.workflow.Workflow; import org.libreccm.workflow.Workflow;
import org.libreccm.workflow.WorkflowTemplate; import org.libreccm.workflow.WorkflowTemplate;
import org.librecms.contentsection.ContentItemL10NManager;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.TooManyListenersException; import java.util.TooManyListenersException;
import java.util.stream.Collectors;
/** /**
* Displays the "Language instances" pane, with all the language instances in * Displays the "Language instances" pane, with all the language instances in
@ -63,6 +73,7 @@ import java.util.TooManyListenersException;
public class ItemLanguages extends LayoutPanel { public class ItemLanguages extends LayoutPanel {
private final ItemSelectionModel selectionModel; private final ItemSelectionModel selectionModel;
private final SingleSelectionModel<String> selectedLanguage;
private final LanguageWidget languageWidget; private final LanguageWidget languageWidget;
private final Submit changeSubmit; private final Submit changeSubmit;
private final Submit createSubmit; private final Submit createSubmit;
@ -70,11 +81,15 @@ public class ItemLanguages extends LayoutPanel {
/** /**
* Constructs a new <code>ItemLanguages</code>. * Constructs a new <code>ItemLanguages</code>.
* *
* @param selectionModel the {@link ItemSelectionModel} which will supply * @param selectionModel the {@link ItemSelectionModel} which will supply
* the current item * the current item
* @param selectedLanguage {@link SingleSelectionModel} for the selected
* language.
*/ */
public ItemLanguages(final ItemSelectionModel selectionModel) { public ItemLanguages(final ItemSelectionModel selectionModel,
final SingleSelectionModel<String> selectedLanguage) {
this.selectionModel = selectionModel; this.selectionModel = selectionModel;
this.selectedLanguage = selectedLanguage;
final Section section = new Section(gz("cms.ui.item.languages")); final Section section = new Section(gz("cms.ui.item.languages"));
setBody(section); setBody(section);
@ -82,15 +97,17 @@ public class ItemLanguages extends LayoutPanel {
final ActionGroup group = new ActionGroup(); final ActionGroup group = new ActionGroup();
section.setBody(group); section.setBody(group);
group.setSubject(new ItemLanguagesTable(selectionModel)); group.setSubject(new ItemLanguagesTable(selectionModel,
selectedLanguage));
final Form form = new Form("newLanguage", new BoxPanel( final Form form = new Form("newLanguage", new BoxPanel(
BoxPanel.HORIZONTAL)); BoxPanel.HORIZONTAL));
group.addAction(form); group.addAction(form);
form.setRedirecting(true); form.setRedirecting(true);
languageWidget = new LanguageWidget(ContentItem.LANGUAGE) { languageWidget = new LanguageWidget("language_widget") {
@Override
protected void setupOptions() { protected void setupOptions() {
// Don't do anything. // Don't do anything.
} }
@ -99,8 +116,8 @@ public class ItemLanguages extends LayoutPanel {
try { try {
languageWidget.addPrintListener(new OptionPrinter()); languageWidget.addPrintListener(new OptionPrinter());
} catch (TooManyListenersException tmle) { } catch (TooManyListenersException ex) {
new UncheckedWrapperException(tmle); throw new UncheckedWrapperException(ex);
} }
form.add(languageWidget); form.add(languageWidget);
@ -116,16 +133,26 @@ public class ItemLanguages extends LayoutPanel {
*/ */
private class OptionPrinter implements PrintListener { private class OptionPrinter implements PrintListener {
public final void prepare(final PrintEvent e) { @Override
final PageState state = e.getPageState(); public final void prepare(final PrintEvent event) {
final OptionGroup optionGroup = (OptionGroup) e.getTarget(); final PageState state = event.getPageState();
final ContentPage item = (ContentPage) selectionModel. final OptionGroup optionGroup = (OptionGroup) event.getTarget();
getSelectedItem(state); final ContentItem item = selectionModel.getSelectedItem(state);
final Collection languages = LanguageUtil.convertToG11N(
LanguageUtil.getCreatableLanguages(item));
for (Iterator iter = languages.iterator(); iter.hasNext();) { final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final Pair pair = (Pair) iter.next(); final LanguageUtil languageUtil = cdiUtil.findBean(
LanguageUtil.class);
final ContentItemL10NManager l10NManager = cdiUtil.findBean(
ContentItemL10NManager.class);
final List<String> creatableLangs = l10NManager.creatableLocales(
item).stream()
.map(locale -> locale.toString())
.collect(Collectors.toList());
final List<Pair> languages = languageUtil.convertToG11N(
creatableLangs);
for(final Pair pair : languages) {
final String langCode = (String) pair.getKey(); final String langCode = (String) pair.getKey();
final GlobalizedMessage langName final GlobalizedMessage langName
= (GlobalizedMessage) pair = (GlobalizedMessage) pair
@ -141,9 +168,10 @@ public class ItemLanguages extends LayoutPanel {
*/ */
private class ProcessListener implements FormProcessListener { private class ProcessListener implements FormProcessListener {
public final void process(final FormSectionEvent e) @Override
public final void process(final FormSectionEvent event)
throws FormProcessException { throws FormProcessException {
PageState state = e.getPageState(); PageState state = event.getPageState();
String lang = (String) languageWidget.getValue(state); String lang = (String) languageWidget.getValue(state);
ContentPage item = (ContentPage) selectionModel.getSelectedItem( ContentPage item = (ContentPage) selectionModel.getSelectedItem(
state); state);

View File

@ -0,0 +1,89 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.cms.ui.item;
import com.arsdigita.bebop.table.RowData;
import org.libreccm.l10n.GlobalizationHelper;
import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentItemL10NManager;
import org.librecms.contentsection.ContentItemRepository;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class ItemLanguagesController {
@Inject
private ContentItemRepository itemRepo;
@Inject
private ContentItemL10NManager itemL10NManager;
@Inject
private GlobalizationHelper globalizationHelper;
public List<RowData<String>> retrieveLanguageVariants(final ContentItem item) {
return retrieveLanguageVariants(item.getObjectId());
}
@Transactional(Transactional.TxType.REQUIRED)
public List<RowData<String>> retrieveLanguageVariants(final long itemId) {
final Optional<ContentItem> item = itemRepo.findById(itemId);
if (!item.isPresent()) {
throw new IllegalArgumentException(String.format(
"No content item with id %d found.", itemId));
}
final List<Locale> availableLangs = new ArrayList<>(itemL10NManager
.availableLanguages(item.get()));
availableLangs.sort((locale1, locale2) -> {
return locale1.toString().compareTo(locale2.toString());
});
return availableLangs.stream()
.map(lang -> createRow(item.get(), lang))
.collect(Collectors.toList());
}
private RowData<String> createRow(final ContentItem item,
final Locale lang) {
final RowData<String> row = new RowData<>(2);
row.setRowKey(lang.toString());
row.setColData(0, lang.getDisplayName(globalizationHelper.getNegotiatedLocale()));
row.setColData(1, item.getTitle().getValue(lang));
return row;
}
}

View File

@ -18,237 +18,162 @@
*/ */
package com.arsdigita.cms.ui.item; package com.arsdigita.cms.ui.item;
import com.arsdigita.bebop.event.TableActionAdapter; import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.ControlLink;
import com.arsdigita.bebop.FormProcessException;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.Link;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.SingleSelectionModel;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.event.TableActionEvent; import com.arsdigita.bebop.event.TableActionEvent;
import com.arsdigita.bebop.event.TableActionListener;
import com.arsdigita.bebop.table.TableCellRenderer; import com.arsdigita.bebop.table.TableCellRenderer;
import com.arsdigita.bebop.table.TableColumn; import com.arsdigita.bebop.table.TableColumn;
import com.arsdigita.bebop.table.TableColumnModel;
import com.arsdigita.cms.ItemSelectionModel; import com.arsdigita.cms.ItemSelectionModel;
import com.arsdigita.cms.dispatcher.MultilingualItemResolver;
import com.arsdigita.cms.ui.ContentItemPage; import com.arsdigita.cms.ui.ContentItemPage;
import com.arsdigita.globalization.GlobalizedMessage;
import org.libreccm.cdi.utils.CdiUtil;
import org.librecms.CmsConstants;
import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentItemL10NManager;
import org.librecms.util.LanguageUtil; import org.librecms.util.LanguageUtil;
import com.arsdigita.toolbox.ui.DataTable;
import com.arsdigita.util.LockableImpl; import java.util.Locale;
import com.arsdigita.web.RedirectSignal;
import com.arsdigita.web.URL;
import java.math.BigDecimal;
import org.apache.log4j.Logger;
/** /**
* Displays a list of all language instances of an item. * Displays a list of all language instances of an item.
* *
*/ */
public class ItemLanguagesTable extends DataTable { public class ItemLanguagesTable extends Table {
private static final Logger LOGGER = Logger.getLogger(ItemLanguagesTable.class); public static final int COL_LANGUAGE = 0;
private final ItemSelectionModel m_model; public static final int COL_TITLE = 1;
private final TableColumn m_deleteColumn; public static final int COL_DELETE = 2;
private final ItemSelectionModel itemSelectionModel;
private final SingleSelectionModel<String> langSelectionModel;
// private final TableColumn deleteColumn;
/** /**
* Construct a new * Construct a new {@code ItemLanguagesTable} which shows all language
* <code>ItemHistoryTable</code> * variants of an item.
* *
* @param model the ItemSelectionModel that supplies the current item * @param itemSelectionModel the ItemSelectionModel that supplies the
* current item
* @param langSelectionModel the single selection model which stores the
* selected language.
*/ */
public ItemLanguagesTable(ItemSelectionModel model) { public ItemLanguagesTable(final ItemSelectionModel itemSelectionModel,
super(new LanguagesBuilder(model)); final SingleSelectionModel<String> langSelectionModel) {
m_model = model; super();
setIdAttr("item_languages_table");
addColumn("cms.ui.language.header", this.itemSelectionModel = itemSelectionModel;
ContentPage.LANGUAGE, this.langSelectionModel = langSelectionModel;
false, setModelBuilder(new ItemLanguagesTableModelBuilder(itemSelectionModel));
new LanguageCellRenderer(m_model));
addColumn("cms.ui.title",
ContentPage.TITLE);
m_deleteColumn = addColumn("cms.ui.action", new ActionCellRenderer(
m_model));
setResourceBundle(GlobalizationUtil.getBundleName());
addTableActionListener(new InstanceDeleter(m_model));
}
/** final TableColumnModel columnModel = getColumnModel();
* Builds the query for all the language instances in the current Bundle columnModel.add(new TableColumn(COL_LANGUAGE,
*/ new Label(new GlobalizedMessage(
private static class LanguagesBuilder extends LockableImpl "cms.ui.language.header",
implements DataQueryBuilder { CmsConstants.CMS_BUNDLE))));
columnModel.add(new TableColumn(COL_TITLE,
new Label(new GlobalizedMessage(
"cms.ui.language.title",
CmsConstants.CMS_BUNDLE))));
columnModel.add(new TableColumn(COL_DELETE,
new Label(new GlobalizedMessage(
"cms.ui.action",
CmsConstants.CMS_BUNDLE))));
ItemSelectionModel m_model; columnModel.get(COL_LANGUAGE).setCellRenderer(new TableCellRenderer() {
public LanguagesBuilder(ItemSelectionModel model) { @Override
super(); public Component getComponent(final Table table,
m_model = model; final PageState state,
} final Object value,
final boolean isSelected,
final Object key,
final int row,
final int column) {
public DataQuery makeDataQuery(DataTable t, PageState s) { final Locale locale = new Locale((String) value);
ContentPage multiLingual =
(ContentPage) m_model.getSelectedObject(s);
DataQuery q = SessionManager.getSession().retrieveQuery(
"com.arsdigita.cms.getBundledItems");
q.setParameter("bundleID", multiLingual.getContentBundle().getID());
return q;
}
public String getKeyColumn() { final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
return ContentPage.ID; final LanguageUtil langUtil = cdiUtil.findBean(
} LanguageUtil.class);
}
/** final Label label = new Label(langUtil.getLangFull(locale));
* Renders the full language name.
*/
private static class LanguageCellRenderer implements TableCellRenderer {
private ItemSelectionModel m_model; if (langSelectionModel.getSelectedKey(state).equals(key)) {
// Current variant, no link
public LanguageCellRenderer(ItemSelectionModel model) { return label;
m_model = model;
}
public Component getComponent(Table table, PageState state, Object value,
boolean isSelected, Object key,
int row, int column) {
BigDecimal id = (BigDecimal) key;
ContentPage cp;
try {
cp = new ContentPage(id);
} catch (DataObjectNotFoundException ex) {
// Content item was not found, return nothing
return new Label();
}
ContentBundle bundle = cp.getContentBundle();
if (bundle != null
&& !(cp instanceof LanguageInvariantContentItem
&& ((LanguageInvariantContentItem) cp).isLanguageInvariant())) {
StringBuilder fontWeight = new StringBuilder(2);
StringBuilder classes = new StringBuilder(20);
if (cp.isLive()) {
fontWeight.append(Label.BOLD);
classes.append("live ");
}
if (bundle.getPrimaryInstance().equals(cp)) {
fontWeight.append(Label.ITALIC);
classes.append("primaryInstance");
}
String target = ContentItemPage.getItemURL(cp, ContentItemPage.AUTHORING_TAB);
Label langLabel = new Label(LanguageUtil.getLangFull((String) value));
langLabel.setFontWeight(fontWeight.toString().trim());
langLabel.setClassAttr(classes.toString().trim());
if (m_model.getSelectedKey(state).equals(key)) {
// Current instance: no link
return langLabel;
} else { } else {
return new Link(langLabel, target); final String target = ContentItemPage.getItemURL(
itemSelectionModel.getSelectedItem(state),
ContentItemPage.AUTHORING_TAB);
return new Link(label, target);
} }
} }
return new Label();
} }
);
columnModel.get(COL_DELETE).setCellRenderer(new TableCellRenderer() {
@Override
public Component getComponent(final Table table,
final PageState state,
final Object value,
final boolean isSelected,
final Object key,
final int row,
final int column) {
final ControlLink link = new ControlLink(new Label(
new GlobalizedMessage("cms.ui.delete",
CmsConstants.CMS_BUNDLE)));
link.setConfirmation(new GlobalizedMessage(
"cms.ui.delete.confirmation", CmsConstants.CMS_BUNDLE));
return link;
}
});
addTableActionListener(new TableActionListener() {
@Override
public void cellSelected(final TableActionEvent event)
throws FormProcessException {
if (event.getColumn() != COL_DELETE) {
//Nothing to do
return;
}
final PageState state = event.getPageState();
final ContentItem item = itemSelectionModel
.getSelectedItem(state);
final String selectedLang = (String) event.getRowKey();
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final ContentItemL10NManager l10nManager = cdiUtil.findBean(
ContentItemL10NManager.class);
l10nManager.removeLangauge(item, new Locale(selectedLang));
}
@Override
public void headSelected(final TableActionEvent event) {
//Nothing
}
});
} }
/**
* Delete language instance action link.
*/
private static class ActionCellRenderer implements TableCellRenderer {
private static final Logger logger =
Logger.getLogger(ActionCellRenderer.class);
private static final Label s_noAction;
private static final Label s_primary;
private static final ControlLink s_link;
static {
logger.debug("Static initializer is starting...");
s_noAction = new Label("&nbsp;", false);
s_noAction.lock();
s_primary = new Label(GlobalizationUtil.globalize(
"cms.ui.primary_instance"), false);
s_primary.lock();
s_link = new ControlLink(new Label(GlobalizationUtil.globalize(
"cms.ui.delete")));
s_link.setConfirmation(GlobalizationUtil.globalize(
"cms.ui.delete_confirmation"));
logger.debug("Static initalizer finished.");
}
private ItemSelectionModel m_model;
public ActionCellRenderer(ItemSelectionModel model) {
m_model = model;
}
public Component getComponent(Table table, PageState state, Object value,
boolean isSelected, Object key,
int row, int column) {
// check if primary instance
BigDecimal id = new BigDecimal(key.toString());
OID oid = new OID(ContentPage.BASE_DATA_OBJECT_TYPE, id);
try {
ContentPage item = (ContentPage) DomainObjectFactory.newInstance(oid);
if (item.getLanguage().equals(
item.getContentBundle().getDefaultLanguage())) {
return s_primary;
} else if (item.isLive()) {
return s_noAction;
}
} catch (DataObjectNotFoundException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not get item with id " + id);
}
return s_noAction;
}
return s_link;
}
}
// delete one language instance
private class InstanceDeleter extends TableActionAdapter {
private ItemSelectionModel m_model;
public InstanceDeleter(ItemSelectionModel model) {
m_model = model;
}
@Override
public void cellSelected(TableActionEvent e) {
int col = e.getColumn().intValue();
if (m_deleteColumn != getColumn(col)) {
return;
}
PageState s = e.getPageState();
BigDecimal id = new BigDecimal(e.getRowKey().toString());
OID oid = new OID(ContentPage.BASE_DATA_OBJECT_TYPE, id);
try {
ContentPage item =
(ContentPage) DomainObjectFactory.newInstance(oid);
ContentBundle bundle = item.getContentBundle();
bundle.removeInstance(item);
item.delete();
if (m_model.getSelectedKey(s).equals(id)) {
throw new RedirectSignal(
URL.there((new MultilingualItemResolver()
.generateItemURL(s,
bundle.getPrimaryInstance(),
bundle.getContentSection(),
ContentItem.DRAFT)),
null),
true);
}
} catch (com.arsdigita.domain.DataObjectNotFoundException ex) {
// Object not found is ok, it has probably been deleted already
}
((Table) e.getSource()).clearSelection(s);
}
}
} }

View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.cms.ui.item;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.table.RowData;
import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.globalization.GlobalizedMessage;
import org.librecms.CmsConstants;
import java.util.Iterator;
import java.util.List;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
class ItemLanguagesTableModel implements TableModel {
private final Iterator<RowData<String>> iterator;
private RowData<String> curentRow;
protected ItemLanguagesTableModel(final List<RowData<String>> rows) {
iterator = rows.iterator();
}
@Override
public int getColumnCount() {
return 3;
}
@Override
public boolean nextRow() {
if (iterator.hasNext()) {
curentRow = iterator.next();
return true;
} else {
return false;
}
}
@Override
public Object getElementAt(final int columnIndex) {
switch (columnIndex) {
case ItemLanguagesTable.COL_LANGUAGE:
return curentRow.getColData(0);
case ItemLanguagesTable.COL_TITLE:
return curentRow.getColData(1);
case ItemLanguagesTable.COL_DELETE:
return new Label(new GlobalizedMessage("cms.ui.delete",
CmsConstants.CMS_BUNDLE));
default:
throw new IllegalArgumentException("Invalid column index.");
}
}
@Override
public Object getKeyAt(final int columnIndex) {
return curentRow.getRowKey();
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2016 LibreCCM Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.cms.ui.item;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.table.RowData;
import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.bebop.table.TableModelBuilder;
import com.arsdigita.cms.ItemSelectionModel;
import com.arsdigita.util.LockableImpl;
import org.libreccm.cdi.utils.CdiUtil;
import org.librecms.contentsection.ContentItem;
import java.util.List;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
class ItemLanguagesTableModelBuilder
extends LockableImpl
implements TableModelBuilder {
private final ItemSelectionModel itemSelectionModel;
protected ItemLanguagesTableModelBuilder(
final ItemSelectionModel itemSelectionModel) {
this.itemSelectionModel = itemSelectionModel;
}
@Override
public TableModel makeModel(final Table table, final PageState state) {
final ContentItem item = itemSelectionModel.getSelectedItem(state);
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final ItemLanguagesController controller = cdiUtil.findBean(ItemLanguagesController.class);
final List<RowData<String>> rows = controller.retrieveLanguageVariants(
item);
return new ItemLanguagesTableModel(rows);
}
}

View File

@ -24,6 +24,7 @@ import com.arsdigita.util.UncheckedWrapperException;
import org.libreccm.configuration.ConfigurationManager; import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.l10n.LocalizedString; import org.libreccm.l10n.LocalizedString;
import org.libreccm.security.AuthorizationRequired; import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.PermissionChecker;
import org.libreccm.security.RequiresPrivilege; import org.libreccm.security.RequiresPrivilege;
import org.librecms.CmsConstants; import org.librecms.CmsConstants;
import org.librecms.contentsection.privileges.ItemPrivileges; import org.librecms.contentsection.privileges.ItemPrivileges;
@ -34,9 +35,11 @@ import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -60,6 +63,9 @@ public class ContentItemL10NManager {
@Inject @Inject
private ContentItemRepository itemRepo; private ContentItemRepository itemRepo;
@Inject
private PermissionChecker permissionChecker;
private Locale defaultLocale; private Locale defaultLocale;
private List<Locale> supportedLocales; private List<Locale> supportedLocales;
@ -112,6 +118,50 @@ public class ContentItemL10NManager {
return locales; return locales;
} }
/**
* Helper method for reading methods in this class for verifying that the
* current user is permitted to read the item.
*
* If the provided {@code item} is a live item
* ({@link ContentItem#getVersion()} returns
* {@link ContentItemVersion#LIVE}) the current user needs the a permission
* which grants the {@link ItemPrivileges#VIEW_PUBLISHED} privilege for the
* provided {@code item}. If the item is a draft item
* ({@link ContentItem#getVersion()} returns
* {@link ContentItemVersion#DRAFT}, {@link ContentItemVersion#PENDING} or
* {@link ContentItemVersion#PUBLISHING} the user needs a permission which
* grants the {@link ItemPrivileges#PREVIEW} privilege for the provided
* {@code item}.
*
* @param item The item for which the read permission is verified.
*/
private void checkReadPermission(final ContentItem item) {
final String requiredPrivilege;
if (ContentItemVersion.LIVE == item.getVersion()) {
requiredPrivilege = ItemPrivileges.VIEW_PUBLISHED;
} else {
requiredPrivilege = ItemPrivileges.PREVIEW;
}
permissionChecker.checkPermission(requiredPrivilege, item);
}
/**
* Retrieves all languages in which content item is available.
*
* @param item The item.
*
* @return A (unmodifiable) {@link Set} containing all languages in which
* the item is available.
*/
@Transactional(Transactional.TxType.REQUIRED)
public Set<Locale> availableLanguages(
final ContentItem item) {
checkReadPermission(item);
return Collections.unmodifiableSet(collectLanguages(item));
}
/** /**
* Checks if an content item has data for particular language. * Checks if an content item has data for particular language.
* *
@ -121,8 +171,13 @@ public class ContentItemL10NManager {
* @return {@link true} if the item has data for the language, {@code false} * @return {@link true} if the item has data for the language, {@code false}
* if not. * if not.
*/ */
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public boolean hasLanguage(final ContentItem item, final Locale locale) { public boolean hasLanguage(
@RequiresPrivilege(ItemPrivileges.VIEW_PUBLISHED)
final ContentItem item,
final Locale locale) {
if (item == null) { if (item == null) {
throw new IllegalArgumentException("Can't check if item null has a" throw new IllegalArgumentException("Can't check if item null has a"
+ "specific locale."); + "specific locale.");
@ -132,14 +187,27 @@ public class ContentItemL10NManager {
throw new IllegalArgumentException("Can't check for locale null."); throw new IllegalArgumentException("Can't check for locale null.");
} }
checkReadPermission(item);
return collectLanguages(item).contains(locale); return collectLanguages(item).contains(locale);
} }
/**
* Returns a {@link Set} containing the locales for which the item does not
* yet have a variant.
*
* @param item The item.
*
* @return A {@link Set} with the locales for which the item does not have a
* variant.
*/
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public Set<Locale> creatableLocales(final ContentItem item) { public Set<Locale> creatableLocales(final ContentItem item) {
checkReadPermission(item);
return supportedLocales.stream() return supportedLocales.stream()
.filter(locale -> hasLanguage(item, locale)) .filter(locale -> hasLanguage(item, locale))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }
/** /**
@ -149,7 +217,11 @@ public class ContentItemL10NManager {
* configured in {@link KernelConfig}. If a field does not have an entry for * configured in {@link KernelConfig}. If a field does not have an entry for
* the default language the first value found is used. * the default language the first value found is used.
* *
* @param item The item to which the language variant is added. * @param item The item to which the language variant is added. The item
* <strong>must be</strong> the <strong>draft version</strong>
* of the item! If a <em>live version</em> or a
* <em>pending version</em> is provided the method will throw an
* {@link IllegalArgumentException}!
* @param locale The locale of the language variant to add. * @param locale The locale of the language variant to add.
*/ */
@AuthorizationRequired @AuthorizationRequired
@ -160,7 +232,14 @@ public class ContentItemL10NManager {
final Locale locale) { final Locale locale) {
if (item == null) { if (item == null) {
throw new IllegalArgumentException("Can't add language to item null."); throw new IllegalArgumentException(
"Can't add language to item null.");
}
if (ContentItemVersion.DRAFT != item.getVersion()) {
throw new IllegalArgumentException(String.format(
"The provided item %s is not the draft version of an item.",
Objects.toString(item)));
} }
if (locale == null) { if (locale == null) {
@ -220,7 +299,11 @@ public class ContentItemL10NManager {
* the entry for the provided locale if the field has an entry for that * the entry for the provided locale if the field has an entry for that
* locale. * locale.
* *
* @param item The item from which the language variant is removed. * @param item The item from which the language variant is removed. The
* item <strong>must be</strong> the <strong>draft
* version</strong> of the item! If a <em>live version</em> or
* a <em>pending version</em> is provided the method will
* throw an {@link IllegalArgumentException}!
* @param locale The locale of the language variant to remove. * @param locale The locale of the language variant to remove.
*/ */
@AuthorizationRequired @AuthorizationRequired
@ -235,6 +318,12 @@ public class ContentItemL10NManager {
"Can't remove language from item null."); "Can't remove language from item null.");
} }
if (ContentItemVersion.DRAFT != item.getVersion()) {
throw new IllegalArgumentException(String.format(
"The provided item %s is not the draft version of an item.",
Objects.toString(item)));
}
if (locale == null) { if (locale == null) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Can't remove language null from an item."); "Can't remove language null from an item.");
@ -268,7 +357,10 @@ public class ContentItemL10NManager {
* {@link LocalizedString} has an entry for every language in the set. If * {@link LocalizedString} has an entry for every language in the set. If
* not an entry for the language is added. * not an entry for the language is added.
* *
* @param item The item to normalise. * @param item The item to normalise. The item <strong>must be</strong> the
* <strong>draft version</strong> of the item! If a <em>live
* version</em> or a <em>pending version</em> is provided the
* method will throw an {@link IllegalArgumentException}!
*/ */
@AuthorizationRequired @AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
@ -280,6 +372,12 @@ public class ContentItemL10NManager {
throw new IllegalArgumentException("Can't normalise item null."); throw new IllegalArgumentException("Can't normalise item null.");
} }
if (ContentItemVersion.DRAFT != item.getVersion()) {
throw new IllegalArgumentException(String.format(
"The provided item %s is not the draft version of an item.",
Objects.toString(item)));
}
final Set<Locale> languages = collectLanguages(item); final Set<Locale> languages = collectLanguages(item);
findLocalizedStringProperties(item) findLocalizedStringProperties(item)