Dies ist die erste Version der lokalisierten Kategorien.

Folgendes funktioniert:

- Anlegen und Löschen von Sprachversionen per Adminoberfläche
- Config-Parameter für Fallback-Modus, unterstützte Sprachen und 
  Standard-Sprache
- Lokalisierte URLs in navigation
- Dekativieren von Sprachversionen

Folgendes funktioniert noch nicht:
- Bearbeiten von Sprachversionen per Adminoberfläche
- evt. ist die Untersützung von lokalisierten URLs noch nicht vollständig
  d.h. in anderen Anwendungen als navigation

Quasimodo



git-svn-id: https://svn.libreccm.org/ccm/trunk@41 8810af33-2d31-482b-a856-94f89814c4df
master
quasi 2008-05-08 18:35:32 +00:00
parent 606b7d90d9
commit 42b45983b8
14 changed files with 1125 additions and 152 deletions

View File

@ -262,6 +262,7 @@ cms.ui.cannot_assign_groups_to_owner=cannot assign groups to owner
cms.ui.categories=Categories cms.ui.categories=Categories
cms.ui.category._back= (back)  cms.ui.category._back= (back) 
cms.ui.category.add=Add category cms.ui.category.add=Add category
cms.ui.categoryLocalization.add=Add category localization
cms.ui.category.add_index_item=Set index item cms.ui.category.add_index_item=Set index item
cms.ui.category.add_use_context=Add Use Context cms.ui.category.add_use_context=Add Use Context
cms.ui.category.assigned_purposes=Assigned Purposes: cms.ui.category.assigned_purposes=Assigned Purposes:
@ -280,6 +281,7 @@ cms.ui.category.delete_prompt=Are you sure you want to delete this category?
cms.ui.category.descriptionn=Description:\n cms.ui.category.descriptionn=Description:\n
cms.ui.category.details=Category details cms.ui.category.details=Category details
cms.ui.category.edit=Edit category cms.ui.category.edit=Edit category
cms.ui.categoryLocalization.edit=Edit category
cms.ui.category.edit_a_category=Edit a Category cms.ui.category.edit_a_category=Edit a Category
cms.ui.category.edit_purposes=Edit purposes cms.ui.category.edit_purposes=Edit purposes
cms.ui.category.index_item.select=Select an index item for this category cms.ui.category.index_item.select=Select an index item for this category
@ -291,6 +293,16 @@ cms.ui.category.is_not_abstract=Can you place objects in this category?
cms.ui.category.item.none=There are no items in this category cms.ui.category.item.none=There are no items in this category
cms.ui.category.item=Categorized item cms.ui.category.item=Categorized item
cms.ui.category.labeln=Label:\n cms.ui.category.labeln=Label:\n
cms.ui.category.localizations=Category Localizations
cms.ui.category.localization.add=Add localization
cms.ui.category.localization.name=Name
cms.ui.category.localization.description=Description
cms.ui.category.localization.url=URL
cms.ui.category.localization.locale=Language
cms.ui.category.localization.action=Action
cms.ui.category.localization.confirm_delete=Delete this localization?
cms.ui.category.localization.none=This category has no localizations
cms.ui.category.localization.error_locale=Please select a locale
cms.ui.category.linked.add=Add or remove linked categories cms.ui.category.linked.add=Add or remove linked categories
cms.ui.category.linked.none=This category has no linked categories cms.ui.category.linked.none=This category has no linked categories
cms.ui.category.linked=Linked categories cms.ui.category.linked=Linked categories

View File

@ -295,6 +295,16 @@ cms.ui.category.labeln=Label:\n
cms.ui.category.linked.add=Verkn\u00FCpfte Kategorien hinzuf\u00FCgen oder entfernen cms.ui.category.linked.add=Verkn\u00FCpfte Kategorien hinzuf\u00FCgen oder entfernen
cms.ui.category.linked.none=Diese Kategorie hat keine verkn\u00FCpften Kategorien cms.ui.category.linked.none=Diese Kategorie hat keine verkn\u00FCpften Kategorien
cms.ui.category.linked=Verkn\u00FCpfte Kategorien cms.ui.category.linked=Verkn\u00FCpfte Kategorien
cms.ui.category.localizations=Sprachversionen
cms.ui.category.localization.add=Sprachversion hinzuf\u00FCgen
cms.ui.category.localization.name=Name
cms.ui.category.localization.description=Beschreibung
cms.ui.category.localization.url=URL
cms.ui.category.localization.locale=Sprache
cms.ui.category.localization.action=Aktion
cms.ui.category.localization.confirm_delete=Soll diese Sprachversion gelöscht werden?
cms.ui.category.localization.none=Diese Kategorie hat keine Sprachversionen
cms.ui.category.localization.error_locale=Bitte wählen Sie eine Sprache aus
cms.ui.category.name_not_unique=Es gibt bereits eine Kategorie mit diesem Namen. cms.ui.category.name_not_unique=Es gibt bereits eine Kategorie mit diesem Namen.
cms.ui.category.no_categorized_objects=Es gibt keine kategorisierten Objekte cms.ui.category.no_categorized_objects=Es gibt keine kategorisierten Objekte
cms.ui.category.no_category_purposes=No Category Purposes cms.ui.category.no_category_purposes=No Category Purposes

View File

@ -58,9 +58,7 @@ class BaseCategoryForm extends BaseForm {
final TextField m_url; final TextField m_url;
final RadioGroup m_isAbstract; final RadioGroup m_isAbstract;
final RadioGroup m_isEnabled; final RadioGroup m_isEnabled;
private Label m_script = new Label("<script language=\"javascript\" src=\"/javascript/manipulate-input.js\"></script>", false); private Label m_script = new Label("<script language=\"javascript\" src=\"/javascript/manipulate-input.js\"></script>", false);
private final static String NAME = "name"; private final static String NAME = "name";
private final static String DESCRIPTION = "description"; private final static String DESCRIPTION = "description";

View File

@ -91,22 +91,28 @@ public final class CategoryAdminPane extends BaseAdminPane {
m_contextModel = new UseContextSelectionModel(new StringParameter(CONTEXT_SELECTED)); m_contextModel = new UseContextSelectionModel(new StringParameter(CONTEXT_SELECTED));
/* Left column */
/* Use context section */
List list = new List(new CategoryUseContextModelBuilder()); List list = new List(new CategoryUseContextModelBuilder());
list.setSelectionModel(m_contextModel); list.setSelectionModel(m_contextModel);
list.addChangeListener(new ContextSelectionListener()); list.addChangeListener(new ContextSelectionListener());
/* Category tree section */
m_categoryTree = new BaseTree(new CategoryTreeModelBuilder(m_contextModel)); m_categoryTree = new BaseTree(new CategoryTreeModelBuilder(m_contextModel));
m_categoryTree.addChangeListener(new SelectionListener()); m_categoryTree.addChangeListener(new SelectionListener());
m_model = m_categoryTree.getSelectionModel(); m_model = m_categoryTree.getSelectionModel();
setSelectionModel(m_model); setSelectionModel(m_model);
setSelector(m_categoryTree); setSelector(m_categoryTree);
/* setup use context form */
final Section contextSection = new Section(); final Section contextSection = new Section();
contextSection.setHeading(new Label(gz("cms.ui.category.use_contexts"))); contextSection.setHeading(new Label(gz("cms.ui.category.use_contexts")));
ActionGroup contextGroup = new ActionGroup(); ActionGroup contextGroup = new ActionGroup();
contextSection.setBody(contextGroup); contextSection.setBody(contextGroup);
contextGroup.setSubject(list); contextGroup.setSubject(list);
/* Add use context form to pane */
ActionLink addContextAction = new ActionLink(new Label(gz("cms.ui.category.add_use_context"))); ActionLink addContextAction = new ActionLink(new Label(gz("cms.ui.category.add_use_context")));
Form addContextForm = new AddUseContextForm(m_contextModel); Form addContextForm = new AddUseContextForm(m_contextModel);
getBody().add(addContextForm); getBody().add(addContextForm);
@ -129,6 +135,10 @@ public final class CategoryAdminPane extends BaseAdminPane {
m_parent = new ParentRequestLocal(); m_parent = new ParentRequestLocal();
m_category = new SelectionRequestLocal(); m_category = new SelectionRequestLocal();
/* Right column */
/* Context section aka category details */
/* Action links */
setAdd(gz("cms.ui.category.add"), setAdd(gz("cms.ui.category.add"),
new CategoryAddForm(m_category, m_model)); new CategoryAddForm(m_category, m_model));

View File

@ -73,8 +73,17 @@ public final class CategoryCollectionListModel implements ListModel {
return m_cat; return m_cat;
} }
/**
* Liest den Namen der Kategorie aus. Angepaßt, damit hier immer
* der Wert aus Category gelesen wird und nicht die lokalisierte
* Version. Ist hier sinnvoll, da es Teil der Adminoberfläche für
* Kategorien ist. Eine lokalisierte Anzeige würde hier nur zu
* Verwirrung führen.
*
* Quasimodo
*/
public Object getElement() { public Object getElement() {
return getCategory().getName(); return getCategory().getName("");
} }
public String getKey() { public String getKey() {

View File

@ -61,9 +61,9 @@ final class CategoryEditForm extends BaseCategoryForm {
final PageState state = e.getPageState(); final PageState state = e.getPageState();
final Category category = m_category.getCategory(state); final Category category = m_category.getCategory(state);
m_name.setValue(state, category.getName()); m_name.setValue(state, category.getName(""));
m_description.setValue(state, category.getDescription()); m_description.setValue(state, category.getDescription(""));
m_url.setValue(state, category.getURL()); m_url.setValue(state, category.getURL(""));
// this seems anti-intuitive but the question is "can you place // this seems anti-intuitive but the question is "can you place
// items in this category. If the user says "yes" then the // items in this category. If the user says "yes" then the
// category is not abstract // category is not abstract
@ -73,7 +73,7 @@ final class CategoryEditForm extends BaseCategoryForm {
m_isAbstract.setValue(state, "yes"); m_isAbstract.setValue(state, "yes");
} }
if (category.isEnabled()) { if (category.isEnabled("")) {
m_isEnabled.setValue(state, "yes"); m_isEnabled.setValue(state, "yes");
} else { } else {
m_isEnabled.setValue(state, "no"); m_isEnabled.setValue(state, "no");

View File

@ -32,6 +32,7 @@ import com.arsdigita.bebop.event.ActionListener;
import com.arsdigita.bebop.event.ChangeEvent; import com.arsdigita.bebop.event.ChangeEvent;
import com.arsdigita.bebop.event.ChangeListener; import com.arsdigita.bebop.event.ChangeListener;
import com.arsdigita.bebop.form.Submit; import com.arsdigita.bebop.form.Submit;
import com.arsdigita.categorization.CategorizationConfig;
import com.arsdigita.categorization.CategorizedCollection; import com.arsdigita.categorization.CategorizedCollection;
import com.arsdigita.categorization.Category; import com.arsdigita.categorization.Category;
import com.arsdigita.categorization.CategoryNotFoundException; import com.arsdigita.categorization.CategoryNotFoundException;
@ -54,6 +55,7 @@ import com.arsdigita.persistence.DataObject;
import com.arsdigita.persistence.OID; import com.arsdigita.persistence.OID;
import com.arsdigita.toolbox.ui.ActionGroup; import com.arsdigita.toolbox.ui.ActionGroup;
import com.arsdigita.toolbox.ui.PropertyList; import com.arsdigita.toolbox.ui.PropertyList;
import com.arsdigita.toolbox.ui.PropertyList.Property;
import com.arsdigita.toolbox.ui.Section; import com.arsdigita.toolbox.ui.Section;
import com.arsdigita.util.Assert; import com.arsdigita.util.Assert;
import com.arsdigita.web.Web; import com.arsdigita.web.Web;
@ -73,146 +75,172 @@ import org.apache.log4j.Logger;
*/ */
class CategoryItemPane extends BaseItemPane { class CategoryItemPane extends BaseItemPane {
public static final String versionId = public static final String versionId =
"$Id: CategoryItemPane.java 1329 2006-09-27 11:47:05Z sskracic $" + "$Id: CategoryItemPane.java 1329 2006-09-27 11:47:05Z sskracic $" +
"$Author: sskracic $" + "$Author: sskracic $" +
"$DateTime: 2004/08/17 23:15:09 $"; "$DateTime: 2004/08/17 23:15:09 $";
private static final Logger s_log = Logger.getLogger private static final Logger s_log = Logger.getLogger
(CategoryItemPane.class); (CategoryItemPane.class);
private final SingleSelectionModel m_model; private final SingleSelectionModel m_model;
private final CategoryRequestLocal m_category; private final CategoryRequestLocal m_category;
private final SimpleContainer m_detailPane; private final SimpleContainer m_detailPane;
public CategoryItemPane(final SingleSelectionModel model, public CategoryItemPane(final SingleSelectionModel model,
final CategoryRequestLocal category, final CategoryRequestLocal category,
final ActionLink addLink, final ActionLink addLink,
final ActionLink editLink, final ActionLink editLink,
final ActionLink deleteLink) { final ActionLink deleteLink) {
m_model = model; m_model = model;
m_category = category; m_category = category;
// Details // Details
m_detailPane = new SimpleContainer(); m_detailPane = new SimpleContainer();
add(m_detailPane); add(m_detailPane);
setDefault(m_detailPane); setDefault(m_detailPane);
final ActionLink orderItemsLink = final ActionLink orderItemsLink = new ActionLink(new Label(gz("cms.ui.category.categorized_objects"))) {
new ActionLink(new Label(gz("cms.ui.category.categorized_objects"))) { public boolean isVisible(PageState state) {
public boolean isVisible(PageState state) { // update for live items only
// update for live items only if (!super.isVisible(state)) {
if (!super.isVisible(state)) { return false;
return false;
}
CategorizedCollection items = m_category.getCategory
(state).getObjects(ContentItem.BASE_DATA_OBJECT_TYPE);
items.addEqualsFilter(ContentItem.VERSION,ContentItem.LIVE);
boolean canOrder = items.size() > 1;
items.close();
return canOrder;
} }
}; CategorizedCollection items = m_category.getCategory
(state).getObjects(ContentItem.BASE_DATA_OBJECT_TYPE);
items.addEqualsFilter(ContentItem.VERSION,ContentItem.LIVE);
boolean canOrder = items.size() > 1;
items.close();
return canOrder;
}
};
final Form orderItemsForm = new OrderItemsForm(m_category); final Form orderItemsForm = new OrderItemsForm(m_category);
final Form orderItemsForm2 = new OrderItemsForm(m_category); final Form orderItemsForm2 = new OrderItemsForm(m_category);
add(orderItemsForm); add(orderItemsForm);
add(orderItemsForm2); add(orderItemsForm2);
// Change index item
final ActionLink indexLink = new ActionLink(new Label(gz("cms.ui.category.change_index_item"))); final ActionLink indexLink = new ActionLink(new Label(gz("cms.ui.category.change_index_item")));
final Form indexForm = new IndexItemSelectionForm(m_category); final Form indexForm = new IndexItemSelectionForm(m_category);
add(indexForm); add(indexForm);
ViewItemLink viewIndexLink = new ViewItemLink(new Label(gz("cms.ui.category.view_index_item")),""); ViewItemLink viewIndexLink = new ViewItemLink(new Label(gz("cms.ui.category.view_index_item")),"");
EditItemLink editIndexLink = new EditItemLink(new Label(gz("cms.ui.category.edit_index_item")),""); EditItemLink editIndexLink = new EditItemLink(new Label(gz("cms.ui.category.edit_index_item")),"");
// Summary
m_detailPane.add(new SummarySection(editLink, deleteLink, indexLink, viewIndexLink, editIndexLink, orderItemsLink)); m_detailPane.add(new SummarySection(editLink, deleteLink, indexLink, viewIndexLink, editIndexLink, orderItemsLink));
// Quasimodo: BEGIN
// Localizations
ActionLink addCategoryLocalizationLink = new ActionLink(new Label(gz("cms.ui.category.localization.add"))) {
public boolean isVisible(PageState state) {
// Only show addLanguage button, if there are langauges to add
int countSupportedLanguages = (new CategorizationConfig()).getSupportedLanguages().countTokens();
long countLanguages = m_category.getCategory(state).getCategoryLocalizationCollection().size();
if(countLanguages < countSupportedLanguages) {
return true;
} else {
return false;
}
}
};
CategoryLocalizationAddForm addCategoryLocalizationForm = new CategoryLocalizationAddForm(m_category);
m_detailPane.add(new CategoryLocalizationSection(addCategoryLocalizationLink));
add(addCategoryLocalizationForm);
connect(addCategoryLocalizationLink, addCategoryLocalizationForm);
connect(addCategoryLocalizationForm);
// Quasimodo: END
// Subcategories
m_detailPane.add(new SubcategorySection(addLink)); m_detailPane.add(new SubcategorySection(addLink));
// Linked categories // Linked categories
final ActionLink linkAddLink = new ActionLink final ActionLink linkAddLink = new ActionLink
(new Label(gz("cms.ui.category.linked.add"))); (new Label(gz("cms.ui.category.linked.add")));
final Form linkForm = new LinkForm(m_category); final Form linkForm = new LinkForm(m_category);
add(linkForm); add(linkForm);
linkAddLink.addActionListener(new NavigationListener(linkForm)); linkAddLink.addActionListener(new NavigationListener(linkForm));
linkForm.addSubmissionListener(new CancelListener(linkForm)); linkForm.addSubmissionListener(new CancelListener(linkForm));
m_detailPane.add(new LinkedCategorySection(linkAddLink)); m_detailPane.add(new LinkedCategorySection(linkAddLink));
// Templates // Templates
m_detailPane.add(new AdminVisible(new CategoryTemplateSection())); m_detailPane.add(new AdminVisible(new CategoryTemplateSection()));
// Permissions // Permissions
m_detailPane.add(new PermissionsSection()); m_detailPane.add(new PermissionsSection());
connect(indexLink, indexForm); connect(indexLink, indexForm);
connect(indexForm); connect(indexForm);
connect(orderItemsLink, orderItemsForm); connect(orderItemsLink, orderItemsForm);
connect(orderItemsForm); connect(orderItemsForm);
} }
private class EditVisible extends VisibilityComponent { private class EditVisible extends VisibilityComponent {
EditVisible(final Component child) { EditVisible(final Component child) {
super(child, null); super(child, null);
} }
public boolean hasPermission(PageState ps) { public boolean hasPermission(PageState ps) {
return m_category.getCategory(ps).canEdit(); return m_category.getCategory(ps).canEdit();
} }
} }
private class AdminVisible extends VisibilityComponent { private class AdminVisible extends VisibilityComponent {
AdminVisible(final Component child) { AdminVisible(final Component child) {
super(child, null); super(child, null);
} }
public boolean hasPermission(PageState ps) { public boolean hasPermission(PageState ps) {
return m_category.getCategory(ps).canAdmin(); return m_category.getCategory(ps).canAdmin();
} }
} }
private class SummarySection extends Section { private class SummarySection extends Section {
SummarySection(final ActionLink editLink, SummarySection(final ActionLink editLink,
final ActionLink deleteLink, final ActionLink deleteLink,
final ActionLink indexLink, final ActionLink indexLink,
final ActionLink orderItemsLink) { final ActionLink orderItemsLink) {
setHeading(new Label(gz("cms.ui.category.details"))); setHeading(new Label(gz("cms.ui.category.details")));
final ActionGroup group = new ActionGroup(); final ActionGroup group = new ActionGroup();
setBody(group); setBody(group);
group.setSubject(new Properties()); group.setSubject(new Properties());
group.addAction(new EditVisible(editLink), ActionGroup.EDIT); group.addAction(new EditVisible(editLink), ActionGroup.EDIT);
group.addAction(new EditVisible(orderItemsLink)); group.addAction(new EditVisible(orderItemsLink));
group.addAction(new EditVisible(indexLink)); group.addAction(new EditVisible(indexLink));
group.addAction(new AdminVisible(deleteLink), ActionGroup.DELETE); group.addAction(new AdminVisible(deleteLink), ActionGroup.DELETE);
} }
/* /*
* This alternative constructor sets two additional links, allowing the user to view and * This alternative constructor sets two additional links, allowing the user to view and
* edit the content index item. * edit the content index item.
*/ */
SummarySection(final ActionLink editLink, SummarySection(final ActionLink editLink,
final ActionLink deleteLink, final ActionLink deleteLink,
final ActionLink indexLink, final ActionLink indexLink,
final BaseLink viewIndexItem, final BaseLink viewIndexItem,
final BaseLink editIndexItem, final BaseLink editIndexItem,
final ActionLink orderItemsLink) { final ActionLink orderItemsLink) {
setHeading(new Label(gz("cms.ui.category.details"))); setHeading(new Label(gz("cms.ui.category.details")));
final ActionGroup group = new ActionGroup(); final ActionGroup group = new ActionGroup();
setBody(group); setBody(group);
group.setSubject(new Properties()); group.setSubject(new Properties());
group.addAction(new EditVisible(editLink), ActionGroup.EDIT); group.addAction(new EditVisible(editLink), ActionGroup.EDIT);
group.addAction(new EditVisible(orderItemsLink)); group.addAction(new EditVisible(orderItemsLink));
group.addAction(new EditVisible(indexLink)); group.addAction(new EditVisible(indexLink));
@ -220,131 +248,145 @@ class CategoryItemPane extends BaseItemPane {
group.addAction(new EditVisible(editIndexItem)); group.addAction(new EditVisible(editIndexItem));
group.addAction(new AdminVisible(deleteLink), ActionGroup.DELETE); group.addAction(new AdminVisible(deleteLink), ActionGroup.DELETE);
} }
private class Properties extends PropertyList { private class Properties extends PropertyList {
protected final java.util.List properties(final PageState state) { protected final java.util.List properties(final PageState state) {
final java.util.List props = super.properties(state); final java.util.List props = super.properties(state);
final Category category = m_category.getCategory(state); final Category category = m_category.getCategory(state);
final ACSObject item = category.getDirectIndexObject(); final ACSObject item = category.getDirectIndexObject();
String itemTitle = ""; String itemTitle = "";
if (item != null) { if (item != null) {
itemTitle = item.getDisplayName(); itemTitle = item.getDisplayName();
} }
props.add(new Property(gz("cms.ui.name"), props.add(new Property(gz("cms.ui.name"),
category.getName())); category.getName("")));
props.add(new Property(gz("cms.ui.description"), props.add(new Property(gz("cms.ui.description"),
category.getDescription())); category.getDescription("")));
props.add(new Property(gz("cms.ui.category.url"), props.add(new Property(gz("cms.ui.category.url"),
category.getURL())); category.getURL("")));
props.add(new Property(gz("cms.ui.category.is_not_abstract"), props.add(new Property(gz("cms.ui.category.is_not_abstract"),
category.isAbstract() ? category.isAbstract() ?
gz("cms.ui.no") : gz("cms.ui.no") :
gz("cms.ui.yes"))); gz("cms.ui.yes")));
props.add(new Property(gz("cms.ui.category.is_enabled"), props.add(new Property(gz("cms.ui.category.is_enabled"),
category.isEnabled() ? category.isEnabled("") ?
gz("cms.ui.yes") : gz("cms.ui.yes") :
gz("cms.ui.no"))); gz("cms.ui.no")));
props.add(new Property(gz("cms.ui.category.index_item"), props.add(new Property(gz("cms.ui.category.index_item"),
itemTitle)); itemTitle));
return props; return props;
} }
} }
} }
// Quasimodo: BEGIN
// CategoryLocalizationSection
private class CategoryLocalizationSection extends Section {
CategoryLocalizationSection(ActionLink addLink) {
setHeading(new Label(gz("cms.ui.category.localizations")));
final ActionGroup group = new ActionGroup();
setBody(group);
group.setSubject(new CategoryLocalizationTable(m_category, m_model));
group.addAction(new AdminVisible(addLink), ActionGroup.ADD);
}
}
private class SubcategorySection extends Section { private class SubcategorySection extends Section {
SubcategorySection(final ActionLink addLink) { SubcategorySection(final ActionLink addLink) {
setHeading(new Label(gz("cms.ui.category.subcategories"))); setHeading(new Label(gz("cms.ui.category.subcategories")));
final ActionGroup group = new ActionGroup(); final ActionGroup group = new ActionGroup();
setBody(group); setBody(group);
group.setSubject(new SubcategoryList(m_category, m_model)); group.setSubject(new SubcategoryList(m_category, m_model));
group.addAction(new AdminVisible(addLink), ActionGroup.ADD); group.addAction(new AdminVisible(addLink), ActionGroup.ADD);
} }
} }
private class LinkedCategorySection extends Section { private class LinkedCategorySection extends Section {
LinkedCategorySection(final ActionLink linkAddLink) { LinkedCategorySection(final ActionLink linkAddLink) {
setHeading(new Label(gz("cms.ui.category.linked"))); setHeading(new Label(gz("cms.ui.category.linked")));
final ActionGroup group = new ActionGroup(); final ActionGroup group = new ActionGroup();
setBody(group); setBody(group);
group.setSubject(new CategoryLinks(m_category, m_model)); group.setSubject(new CategoryLinks(m_category, m_model));
group.addAction(new EditVisible(linkAddLink), ActionGroup.EDIT); group.addAction(new EditVisible(linkAddLink), ActionGroup.EDIT);
} }
public final boolean isVisible(final PageState state) { public final boolean isVisible(final PageState state) {
return !m_category.getCategory(state).isRoot(); return !m_category.getCategory(state).isRoot();
} }
} }
private class CategoryTemplateSection extends Section { private class CategoryTemplateSection extends Section {
CategoryTemplateSection() { CategoryTemplateSection() {
setHeading(new Label(gz("cms.ui.category.templates"))); setHeading(new Label(gz("cms.ui.category.templates")));
final ActionGroup group = new ActionGroup(); final ActionGroup group = new ActionGroup();
setBody(group); setBody(group);
group.setSubject(new CategoryTemplates(m_category)); group.setSubject(new CategoryTemplates(m_category));
// XXX secvis // XXX secvis
//group.addAction(link); //group.addAction(link);
} }
} }
private class PermissionsSection extends Section { private class PermissionsSection extends Section {
public boolean isVisible(PageState ps) { public boolean isVisible(PageState ps) {
Category cat = m_category.getCategory(ps); Category cat = m_category.getCategory(ps);
return !cat.isRoot() && cat.canAdmin(); return !cat.isRoot() && cat.canAdmin();
} }
PermissionsSection() { PermissionsSection() {
setHeading(new Label(gz("cms.ui.permissions"))); setHeading(new Label(gz("cms.ui.permissions")));
final ActionGroup group = new ActionGroup(); final ActionGroup group = new ActionGroup();
setBody(group); setBody(group);
PrivilegeDescriptor[] privs = new PrivilegeDescriptor[] { PrivilegeDescriptor[] privs = new PrivilegeDescriptor[] {
PrivilegeDescriptor.EDIT, PrivilegeDescriptor.EDIT,
Category.MAP_DESCRIPTOR, Category.MAP_DESCRIPTOR,
PrivilegeDescriptor.DELETE, PrivilegeDescriptor.DELETE,
PrivilegeDescriptor.ADMIN PrivilegeDescriptor.ADMIN
}; };
HashMap privMap = new HashMap(); HashMap privMap = new HashMap();
privMap.put("edit", "Edit"); privMap.put("edit", "Edit");
privMap.put("delete", "Delete"); privMap.put("delete", "Delete");
privMap.put(Category.MAP_DESCRIPTOR.getName(), "Categorize Items"); privMap.put(Category.MAP_DESCRIPTOR.getName(), "Categorize Items");
privMap.put("admin", "Admin"); privMap.put("admin", "Admin");
final CMSPermissionsPane permPane = new CMSPermissionsPane final CMSPermissionsPane permPane = new CMSPermissionsPane
(privs, privMap, new ACSObjectSelectionModel(m_model)) { (privs, privMap, new ACSObjectSelectionModel(m_model)) {
public void showAdmin(PageState ps) { public void showAdmin(PageState ps) {
Assert.exists(m_model.getSelectedKey(ps)); Assert.exists(m_model.getSelectedKey(ps));
super.showAdmin(ps); super.showAdmin(ps);
getAdminListingPanel().setVisible(ps, false); getAdminListingPanel().setVisible(ps, false);
} }
}; };
final ActionLink restoreDefault = new ActionLink(new Label(gz("cms.ui.restore_default_permissions"))) { final ActionLink restoreDefault = new ActionLink(new Label(gz("cms.ui.restore_default_permissions"))) {
public boolean isVisible(PageState ps) { public boolean isVisible(PageState ps) {
Category cat = m_category.getCategory(ps); Category cat = m_category.getCategory(ps);
return PermissionService.getContext(cat) == null; return PermissionService.getContext(cat) == null;
} }
}; };
final ActionLink useCustom = new ActionLink(new Label(gz("cms.ui.use_custom_permissions"))) { final ActionLink useCustom = new ActionLink(new Label(gz("cms.ui.use_custom_permissions"))) {
public boolean isVisible(PageState ps) { public boolean isVisible(PageState ps) {
Category cat = m_category.getCategory(ps); Category cat = m_category.getCategory(ps);
return PermissionService.getContext(cat) != null; return PermissionService.getContext(cat) != null;
} }
}; };
ActionListener al = new ActionListener() { ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent event) { public void actionPerformed(ActionEvent event) {
PageState state = event.getPageState(); PageState state = event.getPageState();
@ -363,18 +405,18 @@ class CategoryItemPane extends BaseItemPane {
parent = cat.getDefaultParentCategory(); parent = cat.getDefaultParentCategory();
} catch (CategoryNotFoundException ce) { } catch (CategoryNotFoundException ce) {
throw new IllegalStateException( throw new IllegalStateException(
"link shouldn't exist for root categories"); "link shouldn't exist for root categories");
} }
PermissionService.setContext(cat, parent); PermissionService.setContext(cat, parent);
// revoke all direct permissions so category will only // revoke all direct permissions so category will only
// have inherited permissions // have inherited permissions
ObjectPermissionCollection perms = ObjectPermissionCollection perms =
PermissionService.getDirectGrantedPermissions( PermissionService.getDirectGrantedPermissions(
cat.getOID()); cat.getOID());
while (perms.next()) { while (perms.next()) {
PermissionService.revokePermission( PermissionService.revokePermission(
new PermissionDescriptor( new PermissionDescriptor(
perms.getPrivilege(), cat.getOID(), perms.getPrivilege(), cat.getOID(),
perms.getGranteeOID())); perms.getGranteeOID()));
} }
@ -382,17 +424,17 @@ class CategoryItemPane extends BaseItemPane {
permPane.reset(state); permPane.reset(state);
} }
}; };
restoreDefault.addActionListener(al); restoreDefault.addActionListener(al);
useCustom.addActionListener(al); useCustom.addActionListener(al);
SimpleContainer links = new SimpleContainer(); SimpleContainer links = new SimpleContainer();
links.add(restoreDefault); links.add(restoreDefault);
links.add(useCustom); links.add(useCustom);
group.setSubject(permPane); group.setSubject(permPane);
group.addAction(links); group.addAction(links);
m_model.addChangeListener(new ChangeListener() { m_model.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) { public void stateChanged(ChangeEvent e) {
PageState ps = e.getPageState(); PageState ps = e.getPageState();
@ -400,22 +442,22 @@ class CategoryItemPane extends BaseItemPane {
}); });
} }
} }
private static class OrderItemsForm extends CMSForm { private static class OrderItemsForm extends CMSForm {
public OrderItemsForm(CategoryRequestLocal category) { public OrderItemsForm(CategoryRequestLocal category) {
super("orderItems", new SimpleContainer()); super("orderItems", new SimpleContainer());
Label header = new Label(gz("cms.ui.category.categorized_objects")); Label header = new Label(gz("cms.ui.category.categorized_objects"));
header.setFontWeight(Label.BOLD); header.setFontWeight(Label.BOLD);
add(header); add(header);
add(new CategorizedObjectsList(category)); add(new CategorizedObjectsList(category));
add(new Submit("Done")); add(new Submit("Done"));
} }
} }
/* /*
* This private class creates a link to the index item for a category. * This private class creates a link to the index item for a category.
*/ */
@ -423,11 +465,11 @@ class CategoryItemPane extends BaseItemPane {
ViewItemLink(Component c, String s) { ViewItemLink(Component c, String s) {
super(c,s); super(c,s);
} }
// Build the preview link. This uses a standard redirect link to find the content. // Build the preview link. This uses a standard redirect link to find the content.
// The prepareURL method is called by the printwriter // The prepareURL method is called by the printwriter
protected String prepareURL(final PageState state, String location) { protected String prepareURL(final PageState state, String location) {
ContentItem indexItem = ((ContentBundle)(m_category.getCategory(state).getDirectIndexObject())).getPrimaryInstance(); ContentItem indexItem = ((ContentBundle)(m_category.getCategory(state).getDirectIndexObject())).getPrimaryInstance();
if(indexItem==null) { if(indexItem==null) {
return ""; return "";
@ -435,7 +477,7 @@ class CategoryItemPane extends BaseItemPane {
return "/redirect/?oid=" + URLEncoder.encode(indexItem.getOID().toString()); return "/redirect/?oid=" + URLEncoder.encode(indexItem.getOID().toString());
} }
} }
// We only show this link when an index item exists for this category // We only show this link when an index item exists for this category
public boolean isVisible(PageState state) { public boolean isVisible(PageState state) {
if (!super.isVisible(state)) { if (!super.isVisible(state)) {
@ -449,12 +491,12 @@ class CategoryItemPane extends BaseItemPane {
} }
} }
}; };
private class EditItemLink extends Link { private class EditItemLink extends Link {
EditItemLink(Component c, String s) { EditItemLink(Component c, String s) {
super(c,s); super(c,s);
} }
// Build the preview link. This is based on code in the ContentSoonExpiredPane class. // Build the preview link. This is based on code in the ContentSoonExpiredPane class.
// The prepareURL method of the parent is overwritten. This method is called by the printwriter // The prepareURL method of the parent is overwritten. This method is called by the printwriter
protected String prepareURL(final PageState state, String location) { protected String prepareURL(final PageState state, String location) {
@ -470,7 +512,7 @@ class CategoryItemPane extends BaseItemPane {
return "item.jsp?item_id=" + draftID + "&set_tab=" + ContentItemPage.AUTHORING_TAB; return "item.jsp?item_id=" + draftID + "&set_tab=" + ContentItemPage.AUTHORING_TAB;
} }
} }
// We only show this link when an index item exists for this category and // We only show this link when an index item exists for this category and
// the user is allowed to edit this item. // the user is allowed to edit this item.
public boolean isVisible(PageState state) { public boolean isVisible(PageState state) {
@ -484,7 +526,7 @@ class CategoryItemPane extends BaseItemPane {
return isItemEditable((ContentItem)indexItem,state); return isItemEditable((ContentItem)indexItem,state);
} }
} }
// This method checks whether a usern is allowed to edit a particular item // This method checks whether a usern is allowed to edit a particular item
private boolean isItemEditable(ContentItem item, PageState state) { private boolean isItemEditable(ContentItem item, PageState state) {
BigDecimal id = item.getID(); BigDecimal id = item.getID();

View File

@ -22,10 +22,13 @@ model com.arsdigita.categorization;
import com.arsdigita.kernel.*; import com.arsdigita.kernel.*;
object type Category extends ACSObject { object type Category extends ACSObject {
// Hier werden die Default-Werte gespeichert ???
String[0..1] description = cat_categories.description VARCHAR(4000); String[0..1] description = cat_categories.description VARCHAR(4000);
String[1..1] name = cat_categories.name VARCHAR(200); String[1..1] name = cat_categories.name VARCHAR(200);
String[0..1] url = cat_categories.url VARCHAR(200); String[0..1] url = cat_categories.url VARCHAR(200);
Boolean[1..1] isEnabled = cat_categories.enabled_p CHAR(1); Boolean[1..1] isEnabled = cat_categories.enabled_p CHAR(1);
Boolean[1..1] isAbstract = cat_categories.abstract_p CHAR(1); Boolean[1..1] isAbstract = cat_categories.abstract_p CHAR(1);
String[1..1] defaultAncestors = cat_categories.default_ancestors VARCHAR(3209); String[1..1] defaultAncestors = cat_categories.default_ancestors VARCHAR(3209);
Boolean[1..1] ignoreParentIndexItem = cat_categories.ignore_parent_index_p CHAR(1); Boolean[1..1] ignoreParentIndexItem = cat_categories.ignore_parent_index_p CHAR(1);
@ -33,6 +36,28 @@ object type Category extends ACSObject {
reference key (cat_categories.category_id); reference key (cat_categories.category_id);
} }
// locale dependend entries
object type CategoryLocalization extends ACSObject {
String[1..1] locale = cat_category_localizations.locale CHAR(2);
// Moved down from Category
String[0..1] description = cat_category_localizations.description VARCHAR(4000);
String[1..1] name = cat_category_localizations.name VARCHAR(200);
String[0..1] url = cat_category_localizations.url VARCHAR(200);
Boolean[1..1] isEnabled = cat_category_localizations.enabled_p CHAR(1);
reference key (cat_category_localizations.id);
}
association {
composite Category[1..1] category = join cat_category_localizations.category_id
to cat_categories.category_id;
component CategoryLocalization[0..n] localizations = join cat_categories.category_id
to cat_category_localizations.category_id;
}
object type UseContext { object type UseContext {
BigDecimal[1..1] id = cat_root_cat_object_map.id; BigDecimal[1..1] id = cat_root_cat_object_map.id;

View File

@ -0,0 +1,91 @@
/*
* CategorizationConfig.java
*
* Created on 17. Januar 2008, 15:29
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package com.arsdigita.categorization;
/**
*
* @author quasi
*/
import com.arsdigita.runtime.AbstractConfig;
import com.arsdigita.runtime.RuntimeConfig;
import com.arsdigita.util.Assert;
import com.arsdigita.util.parameter.BooleanParameter;
import com.arsdigita.util.parameter.StringParameter;
import com.arsdigita.util.parameter.ErrorList;
import com.arsdigita.util.parameter.IntegerParameter;
import com.arsdigita.util.parameter.Parameter;
import com.arsdigita.util.parameter.ParameterError;
import java.util.StringTokenizer;
import org.apache.log4j.Logger;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
/**
* Stores the configuration record for the Categorization functionality
*/
public final class CategorizationConfig extends AbstractConfig {
private static Logger s_log = Logger.getLogger(CategorizationConfig.class);
private final Parameter m_showInternalName;
private final Parameter m_supportedLanguages;
public CategorizationConfig() {
m_showInternalName = new BooleanParameter
("waf.categorization.show_internal_name",
Parameter.REQUIRED,
new Boolean(false));
m_supportedLanguages = new StringParameter
("waf.categorization.supported_languages",
Parameter.REQUIRED,
"en,de,fr");
register(m_showInternalName);
register(m_supportedLanguages);
loadInfo();
}
/**
* Returns the showInternalName flag.
*/
public final boolean getShowInternalName() {
return ((Boolean) get(m_showInternalName)).booleanValue();
}
/**
* Returns the defaultLanguage flag.
*/
public final String getDefaultLanguage() {
return ((String) get(m_supportedLanguages)).trim().substring(0, 2);
}
/**
* Returns the supportedLanguages as StringTokenizer.
*/
public final StringTokenizer getSupportedLanguages() {
return new StringTokenizer((String) get(m_supportedLanguages), ",", false);
}
/**
* Return true, if language lang is part of supported langs
*/
public final boolean hasLanguage(String lang) {
return ((String) get(m_supportedLanguages)).contains(lang);
}
}

View File

@ -0,0 +1,8 @@
waf.categorization.show_internal_name.title=Activate output of internal keys for categorization
waf.categorization.show_internal_name.purpose=Activate this setting to output internal keys for categories without the requested locale. This is usually for debugging.
waf.categorization.show_internal_name.example=false
waf.categorization.show_internal_name.format=[boolean]
waf.categorization.supported_languages.title=Set the supported languages for categorization
waf.categorization.supported_languages.purpose=Set the supported languages for categorization. First entry is the default language
waf.categorization.supported_languages.example=en,de,fr
waf.categorization.supported_languages.format=[string]

View File

@ -83,6 +83,24 @@ import org.apache.log4j.Logger;
* *
* @author Randy Graebner * @author Randy Graebner
* @version $Revision: 1.1 $ $DateTime: $ * @version $Revision: 1.1 $ $DateTime: $
*
* <p>Localization is done with some new classes, so the category tree is
* now multilanguage. This is completly transparent to the rest of the
* system (hopefully) and uses the negotiated language from the browser
* environment. The following attributes are localizable:
*
* <ul>
* <li>Name</li>
* <li>Description</li>
* <li>URL</li>
* <li>IsEnabled</li>
* </ul>
*
* To use localized URLs I had to change NavigationFileReolver.resolveCategory()
* in ccm-ldn-navigation to filter the categories in Java. There might be other
* location in the code where this patch may also be needed. So fix it.
*
* Quasimodo
*/ */
public class Category extends ACSObject { public class Category extends ACSObject {
private static final Logger s_log = Logger.getLogger(Category.class); private static final Logger s_log = Logger.getLogger(Category.class);
@ -103,6 +121,14 @@ public class Category extends ACSObject {
public static final PrivilegeDescriptor MAP_DESCRIPTOR = public static final PrivilegeDescriptor MAP_DESCRIPTOR =
new PrivilegeDescriptor("map_to_category"); new PrivilegeDescriptor("map_to_category");
// Quasimodo: Begin
private static CategorizationConfig s_config = new CategorizationConfig();
static {
s_config.load();
}
// Quasimodo: End
public static final String ROOT_CATEGORY = "rootCategory"; public static final String ROOT_CATEGORY = "rootCategory";
public static final String USE_CONTEXT = "useContext"; public static final String USE_CONTEXT = "useContext";
public static final String CATEGORY_OWNER = "categoryOwner"; public static final String CATEGORY_OWNER = "categoryOwner";
@ -149,6 +175,8 @@ public class Category extends ACSObject {
public final static String CHILD_OBJECTS = "childObjects"; public final static String CHILD_OBJECTS = "childObjects";
public final static String RELATED_CATEGORIES = RELATED; public final static String RELATED_CATEGORIES = RELATED;
public final static String CATEGORIES = "categories"; public final static String CATEGORIES = "categories";
public static final String LOCALIZATIONS = "localizations";
// some named queries in the pdl files // some named queries in the pdl files
private static final String CHILD_CATEGORY_IDS = private static final String CHILD_CATEGORY_IDS =
@ -158,6 +186,11 @@ public class Category extends ACSObject {
private HierarchyDenormalization m_hierarchy; private HierarchyDenormalization m_hierarchy;
// Quasimodo: Begin
// Save the localized parts of category
private CategoryLocalizationCollection m_categoryLocalizationCollection;
// Quasimodo: End
protected String getBaseDataObjectType() { protected String getBaseDataObjectType() {
return BASE_DATA_OBJECT_TYPE; return BASE_DATA_OBJECT_TYPE;
} }
@ -316,6 +349,15 @@ public class Category extends ACSObject {
} }
// Quasimodo: Begin
/**
* Retrieves the current configuration
*/
public static CategorizationConfig getConfig() {
return s_config;
}
/** /**
* @see com.arsdigita.domain.DomainObject#initialize() * @see com.arsdigita.domain.DomainObject#initialize()
*/ */
@ -334,21 +376,58 @@ public class Category extends ACSObject {
setAbstract(false); setAbstract(false);
//by default do not ignore the parent index item //by default do not ignore the parent index item
setIgnoreParentIndexItem(false); setIgnoreParentIndexItem(false);
} }
m_hierarchy = new HierarchyDenormalization m_hierarchy = new HierarchyDenormalization
("com.arsdigita.categorization.updateCategoryDescendants", this, ("com.arsdigita.categorization.updateCategoryDescendants", this,
DEFAULT_ANCESTORS) {}; DEFAULT_ANCESTORS) {};
}
m_categoryLocalizationCollection = new CategoryLocalizationCollection(this);
}
// Quasimodo: End
/**
* Quasimodo:
* Returns the localized name or the name key if localized version don't exist
*
* @return the category name.
*/
public String getName(String locale) {
// Test for localized version
if(locale != "" && m_categoryLocalizationCollection != null && m_categoryLocalizationCollection.localizationExists(locale)) {
// Return value of isEnabled from localized version, so categories could be disabled depending on locale
return m_categoryLocalizationCollection.getName();
} else {
// Return name key
return (String) get(NAME);
}
}
/** /**
* @return the category name. * @return the category name.
*/ */
public String getName() { public String getName() {
return (String) get(NAME); return getName(this.getNegotiatedLocale());
} }
/**
* Returns the display name of the category. This overrides the parent
* implementation.
* @return the category name.
*/
public String getDisplayName(String locale) {
return getName(locale);
}
/** /**
* Returns the display name of the category. This overrides the parent * Returns the display name of the category. This overrides the parent
* implementation. * implementation.
@ -462,17 +541,55 @@ public class Category extends ACSObject {
* *
* @param value the new name of the category * @param value the new name of the category
*/ */
public void setName(String value) { public void setName(String name, String locale) {
set(NAME, value);
if(locale != "" && m_categoryLocalizationCollection != null && m_categoryLocalizationCollection.localizationExists(locale)) {
m_categoryLocalizationCollection.getCategoryLocalization().setName(name);
}
} }
/**
* Sets the name of the category.
*
* @param value the new name of the category
*/
public void setName(String name) {
set(NAME, name);
}
/**
* Returns the description of the category.
*
* Quasimodo:
* Returns localized version of description or description key if localized version don't exist
*
* @return the category description.
*/
public String getDescription(String locale) {
// Test for localized version
// HACK
if(locale != "" && m_categoryLocalizationCollection != null && m_categoryLocalizationCollection.localizationExists(locale)) {
// Return value of isEnabled from localized version, so categories could be disabled depending on locale
return m_categoryLocalizationCollection.getDescription();
} else {
// Return description key
return (String) get(DESCRIPTION);
}
}
/** /**
* Returns the description of the category. * Returns the description of the category.
* @return the category name. * @return the category name.
*/ */
public String getDescription() { public String getDescription() {
return (String) get(DESCRIPTION); return getDescription(this.getNegotiatedLocale());
} }
/** /**
@ -487,10 +604,47 @@ public class Category extends ACSObject {
* *
* @param value the new description of the category * @param value the new description of the category
*/ */
public void setDescription(String value) { public void setDescription(String description, String locale) {
set(DESCRIPTION, value);
if(locale != "" && m_categoryLocalizationCollection != null && m_categoryLocalizationCollection.localizationExists(locale)) {
m_categoryLocalizationCollection.getCategoryLocalization().setDescription(description);
}
} }
/**
* Sets the description of the category.
*
* @param value the new description of the category
*/
public void setDescription(String description) {
set(DESCRIPTION, description);
}
/**
* Returns the URL component of the category.
*
* Quasimodo:
* Returns the localized version of the URL or URL-key if localized version don't exist
*
* @return URL component used when browsing categories
*/
public String getURL(String locale) {
// Test for localized version
if(locale != "" && m_categoryLocalizationCollection != null && m_categoryLocalizationCollection.localizationExists(locale)) {
// Return value of isEnabled from localized version, so categories could be disabled depending on locale
return m_categoryLocalizationCollection.getURL();
} else {
// Return URL-key
return (String) get(URL);
}
}
/** /**
* Returns the URL component of the category. * Returns the URL component of the category.
@ -498,10 +652,24 @@ public class Category extends ACSObject {
* @return URL component used when browsing categories * @return URL component used when browsing categories
*/ */
public String getURL() { public String getURL() {
return (String) get(URL); return getURL(this.getNegotiatedLocale());
} }
/**
* Sets the URL component of the category.
*
* @param url URL component used when browsing categories
*/
public void setURL(String url, String locale) {
if(locale != "" && m_categoryLocalizationCollection != null && m_categoryLocalizationCollection.localizationExists(locale)) {
m_categoryLocalizationCollection.getCategoryLocalization().setURL(url);
}
}
/** /**
* Sets the URL component of the category. * Sets the URL component of the category.
* *
@ -517,11 +685,64 @@ public class Category extends ACSObject {
* *
* @return <code>true</code> if the category is enabled; <code>false</code> * @return <code>true</code> if the category is enabled; <code>false</code>
* otherwise. * otherwise.
*
* Quasimodo:
* This is getting a bit more compliated:
* 1. Check if category is globally disabled
* 2. If not, check if localized version exists
* 2.1 If so, return isEnabled from localized version
* 2.2 If not, return Category.getConfig().getShowInternalName()
*
*/ */
public boolean isEnabled() { public boolean isEnabled(String locale) {
return ((Boolean) get(IS_ENABLED)).booleanValue();
// If locale == "" return global status
// or if globally disabled, return category as disabled
if(locale == "" || ((Boolean) get(IS_ENABLED)).booleanValue() == false) {
return ((Boolean) get(IS_ENABLED)).booleanValue();
}
// Test for localized version
// HACK
if(locale != "" && m_categoryLocalizationCollection != null && m_categoryLocalizationCollection.localizationExists(locale)) {
// Return value of isEnabled from localized version, so categories could be disabled depending on locale
return m_categoryLocalizationCollection.isEnabled();
} else {
// Return value of Category.getConfig().getShowInternalName()
// This will disable all categories without selected locale, if Category.getConfig().getShowInternalName() == false
return Category.getConfig().getShowInternalName();
}
} }
/**
* Determines the current state of the category.
*
* @return <code>true</code> if the category is enabled; <code>false</code>
* otherwise.
*/
public boolean isEnabled() {
return isEnabled(this.getNegotiatedLocale());
}
/**
* Sets whether the category is enabled.
*
* @param isEnabled <code>true</code> if the category is enabled;
* <code>false</false> otherwise.
*/
public void setEnabled(boolean isEnabled, String locale) {
if(locale != "" && m_categoryLocalizationCollection != null && m_categoryLocalizationCollection.localizationExists(locale)) {
m_categoryLocalizationCollection.getCategoryLocalization().setEnabled(isEnabled);
}
}
/** /**
* Sets whether the category is enabled. * Sets whether the category is enabled.
@ -1706,6 +1927,11 @@ public class Category extends ACSObject {
* @return Array of constituent categories. The first element of the array * @return Array of constituent categories. The first element of the array
* is the current category (hence the array will always have length >= * is the current category (hence the array will always have length >=
* 1). If the path is bad, this returns <code>null</code>. * 1). If the path is bad, this returns <code>null</code>.
*
* This one may be patched to work with localized URLs. I didn't do it for now
* because I don't know where it is called and if it's really needed to patch.
* Quasimodo
*
*/ */
public Category[] getChildrenByURL(String path) { public Category[] getChildrenByURL(String path) {
final List children = new LinkedList(); final List children = new LinkedList();
@ -1971,4 +2197,103 @@ public class Category extends ACSObject {
(new PermissionDescriptor(PrivilegeDescriptor.ADMIN, this, (new PermissionDescriptor(PrivilegeDescriptor.ADMIN, this,
Kernel.getContext().getParty())); Kernel.getContext().getParty()));
} }
// Quasimodo: Begin
/**
* Getting the negotiated locale from requestContext
* @return the negotiated language string if in supported lang list or default language else
*/
private String getNegotiatedLocale() {
String locale = null;
try {
// Try to get locale from request context
locale = com.arsdigita.dispatcher.DispatcherHelper.getRequestContext().getLocale().getLanguage();
} catch(NullPointerException ex) {
// If there is no request context (ex. during ccm setup) use default language
locale = Category.getConfig().getDefaultLanguage();
} finally {
// if supported lang contains locale
if(Category.getConfig().hasLanguage(locale)) {
// then return locale
return locale;
} else {
// else return default language
return Category.getConfig().getDefaultLanguage();
}
}
}
public CategoryLocalizationCollection getCategoryLocalizationCollection() {
return m_categoryLocalizationCollection;
}
public DataAssociation getLocalizations() {
return ((DataAssociation) this.get(LOCALIZATIONS));
}
public boolean hasLocalizations() {
return !m_categoryLocalizationCollection.isEmpty();
}
/**
* Add a new language set to this category
*/
public boolean addLanguage(String locale, String name, String description, String url) {
// If locale don't exist
if(locale != "" && m_categoryLocalizationCollection != null && !m_categoryLocalizationCollection.localizationExists(locale)) {
// Get DataAssociation
DataAssociation categoryLocalizationAssociation = this.getLocalizations();
// Add association with category
(new CategoryLocalization(locale, name, description, url)).addToAssociation(categoryLocalizationAssociation);
// Reload CategoryLocalizationCollection
// this.m_categoryLocalizationCollection = new CategoryLocalizationCollection(this);
return true;
}
return false;
}
/**
* Delete a language set from this category
*/
public boolean delLanguage(String locale) {
// If locale exist
if(locale != "" && m_categoryLocalizationCollection != null && m_categoryLocalizationCollection.localizationExists(locale)) {
// Get DataAssociation
DataAssociation categoryLocalizationAssociation = this.getLocalizations();
// Remove CategoryLocalization from Association
m_categoryLocalizationCollection.getCategoryLocalization().removeFromAssociation(categoryLocalizationAssociation);
// Reload CategoryLocalizationCollection
this.m_categoryLocalizationCollection = new CategoryLocalizationCollection(this);
return true;
}
return false;
}
} }

View File

@ -0,0 +1,278 @@
/*
* CategoryLocalization.java
*
* Created on 17. Januar 2008, 14:36
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package com.arsdigita.categorization;
import com.arsdigita.kernel.ACSObject;
import com.arsdigita.persistence.DataObject;
import com.arsdigita.persistence.OID;
import com.arsdigita.persistence.metadata.ObjectType;
import java.math.BigDecimal;
/**
*
* @author quasi
*/
public class CategoryLocalization extends ACSObject {
public static final String BASE_DATA_OBJECT_TYPE = "com.arsdigita.categorization.CategoryLocalization";
private static final String BASE_DATA_OBJECT_PACKAGE = "com.arsdigita.categorization";
// Constants to use in the code
public static final String LOCALE = "locale";
public static final String NAME = "name";
public static final String DESCRIPTION = "description";
public static final String URL = "url";
public static final String IS_ENABLED = "isEnabled";
protected String getBaseDataObjectType() {
return BASE_DATA_OBJECT_TYPE;
}
public static String getBaseDataObjectPackage() {
return BASE_DATA_OBJECT_PACKAGE;
}
/**
* Initializes the categoryLocalization with the specified data object.
*
* @param categoryObjectData the data object
**/
public CategoryLocalization(DataObject categoryLocalizationObjectData) {
super(categoryLocalizationObjectData);
}
/**
* Serves as a shortcut to {@link #CategoryLocalization(String)
* CategoryLocalization(CategoryLocalization.BASE_DATA_OBJECT_TYPE)}.
*
* @see com.arsdigita.domain.DomainObject#DomainObject(String)
**/
public CategoryLocalization() {
this(BASE_DATA_OBJECT_TYPE);
}
/**
* Initializes the contained data object with a new data object whose object
* type is specified by the passed in type name.
*
* @param typeName the object type for the contained data object
*
* @see com.arsdigita.domain.DomainObject#DomainObject(String)
* @see com.arsdigita.persistence.DataObject
* @see com.arsdigita.persistence.metadata.ObjectType
**/
public CategoryLocalization(String typeName) {
super(typeName);
}
/**
* Initializes the contained data object with a new data object whose object
* type is the specified type.
*
* @param type the object type for the contained data object
*
* @see com.arsdigita.domain.DomainObject#DomainObject(ObjectType)
* @see com.arsdigita.persistence.DataObject
**/
public CategoryLocalization(ObjectType type) {
super(type);
}
/**
* Retrieves the data object with the specified OID from the persistent
* storage mechanism.
*
* @param oid the OID for the data object to retrieve
* @throws DataObjectNotFoundException if this OID is invalid or has been
* deleted.
*
* @see com.arsdigita.domain.DomainObject#DomainObject(OID)
* @see com.arsdigita.persistence.DataObject
**/
public CategoryLocalization(OID oid) {
super(oid);
}
/**
* Retrieves the data object with the specified ID from the persistence
* storage mechanism. This method is just a wrapper for the {@link
* #CategoryLocalization(OID)} constructor.
*
* @throws DataObjectNotFoundException
*/
public CategoryLocalization(BigDecimal id) {
this(new OID(BASE_DATA_OBJECT_TYPE, id));
}
/**
* Creates a new categoryLocalization with the given name and description.
*
* @param name the name for the new category
* @param description the description for the new category
*/
public CategoryLocalization(String locale, String name, String description) {
this();
setLocale(locale);
setName(name);
setDescription(description);
}
/**
* Creates a new categoryLocalization with the given name, description and URL
* component.
*
* @param name the name for the new category
* @param description the description for the new category
* @param url URL component used when browsing categories.
*/
public CategoryLocalization(String locale, String name, String description, String url) {
this();
setLocale(locale);
setName(name);
setDescription(description);
setURL (url);
}
/**
* Retrieves the categoryLocalization with the given category ID, and sets the name and
* description. For the new name and descrption to be permanent, the caller
* must call the save() method.
*
* @param categoryID the category ID
* @param name the category name
* @param description the category description
* @exception DataObjectNotFoundException if this OID is
* invalid or has been deleted.
*
* @see com.arsdigita.domain.DomainObject#DomainObject(OID)
*/
public CategoryLocalization(OID categoryID, String name, String description) {
this(categoryID);
setName(name);
setDescription(description);
}
/**
* Retrieves the categoryLocalization with the given category ID, and sets the name and
* description. For the new name and descrption to be permanent, the caller
* must call the save() method.
*
* @param categoryID the category ID
* @param name the category name
* @param description the category description
* @param url URL component used when browsing categories.
* @exception DataObjectNotFoundException if this OID is
* invalid or has been deleted.
*
* @see com.arsdigita.domain.DomainObject#DomainObject(OID)
*/
public CategoryLocalization(OID categoryID, String name, String description, String url) {
this(categoryID);
setName(name);
setDescription(description);
setURL (url);
}
/**
* @see com.arsdigita.domain.DomainObject#initialize()
*/
protected void initialize() {
super.initialize();
if(isNew()) {
setEnabled(true);
}
}
// Getter / Setter methods
/**
* Returns the locale
*/
public String getLocale() {
return (String) get(LOCALE);
}
/**
* Sets the locale
*/
private void setLocale(String locale) {
set(LOCALE, locale);
}
/**
* Returns the localized name
*/
public String getName() {
return (String) get(NAME);
}
/**
* Set localized name
*/
public void setName(String name) {
set(NAME, name);
}
/**
* Returns the localized description
*/
public String getDescription() {
return (String) get(DESCRIPTION);
}
/**
* Set localized description
*/
public void setDescription(String description) {
set(DESCRIPTION, description);
}
/**
* Returns the localized URL
*/
public String getURL() {
return (String) get(URL);
}
/**
* Set localized URL
*/
public void setURL(String url) {
set(URL, url);
}
/**
* Returns the localized status
*/
public boolean isEnabled() {
return ((Boolean) get(IS_ENABLED)).booleanValue();
}
/**
* Set localized status
*/
public void setEnabled(boolean isEnabled) {
set(IS_ENABLED, new Boolean(isEnabled));
}
}

View File

@ -0,0 +1,140 @@
/*
* CategoryLocalizationCollection.java
*
* Created on 19. Januar 2008, 13:24
*
* Author: Quasimodo
*/
package com.arsdigita.categorization;
import com.arsdigita.kernel.ACSObject;
import com.arsdigita.kernel.ACSObjectCollection;
import com.arsdigita.persistence.DataAssociation;
import com.arsdigita.persistence.DataCollection;
import com.arsdigita.persistence.DataObject;
/**
* Represents a collection of categoryLocalizations.
*
* <p>Instances of this class are produced by various methods in {@link
* Category} and other classes. See, for example, {@link Category#getChildren()}
* or {@link Category#getDescendants()}.</p>
*
* @author Randy Graebner (randyg@alum.mit.edu)
* @version $Revision: #15 $ $DateTime: 2004/08/16 18:10:38 $
**/
public class CategoryLocalizationCollection extends ACSObjectCollection {
public CategoryLocalizationCollection(Category category) {
super(category.getLocalizations().getDataCollection());
}
public CategoryLocalizationCollection(DataCollection dataCollection) {
super(dataCollection);
}
/**
* Returns the locale of the categoryLocalization.
*
* @return the category locale.
* @see Category#getLocale()
*/
public String getLocale() {
return getCategoryLocalization().getLocale();
}
/**
* Returns the name of the category.
*
* @return the category name.
* @see Category#getName()
*/
public String getName() {
return getCategoryLocalization().getName();
}
/**
* Returns the description.
*
* @return the description
* @see Category#getDescription()
*/
public String getDescription() {
return getCategoryLocalization().getDescription();
}
/**
* Returns the URL.
*
* @return the URL
* @see Category#getURL()
*/
public String getURL() {
return getCategoryLocalization().getURL();
}
/**
* Determines the current state of the category.
*
* @return <code>true</code> if the category is enabled; <code>false</code>
* otherwise.
* @see Category#isEnabled()
*/
public boolean isEnabled() {
return getCategoryLocalization().isEnabled();
}
/**
* Wrapper to <code>getDomainObject()</code> that casts the returned
* <code>DomainObject</code> as a <code>CategoryLocalization</code>.
*
* @return a <code>CategoryLocalization</code> for the current position in the
* collection.
**/
public CategoryLocalization getCategoryLocalization() {
return (CategoryLocalization) getDomainObject();
}
public ACSObject getACSObject() {
return getCategoryLocalization();
}
/**
* Search for the requested localization in the Collection
*
* @return result of the search. If true, the CollectionCursor is set to the position of the requested locale.
*/
public boolean localizationExists(String locale) {
//
if(!m_dataCollection.isEmpty() && locale != "") {
// First check, if we are already at the right position. This will speed up repeated access for the same locale
if(this.getPosition() > 0 && this.getCategoryLocalization().getLocale().equals(locale)) return true;
// Nope, so we have to start a search
this.rewind();
while(this.next()) {
if(this.getCategoryLocalization().getLocale().equals(locale)) return true;
}
}
// Not found
return false;
}
/**
* Sorts the category collection by the category sort key.
*
* @see CategorizedCollection#sort(boolean)
**/
public final void sort(boolean ascending) {
if ( ascending ) {
addOrder("link.sortKey asc");
} else {
addOrder("link.sortKey desc");
}
}
}

View File

@ -16,6 +16,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
/**
* Diese Klasse ist für die Verabeitung der URLs innerhalb der Anwendung navigation zuständig.
*/
package com.arsdigita.london.navigation; package com.arsdigita.london.navigation;
@ -315,7 +319,20 @@ public class NavigationFileResolver extends DefaultApplicationFileResolver {
return NavigationFileResolver.resolveCategory(root, path); return NavigationFileResolver.resolveCategory(root, path);
} }
/**
* In dieser Methode wird eine URL mit dem Kategorienbaum abgeglichen
* und die angeforderte Kategorie zurückgegeben, soweit sie vorhanden
* ist.
*
* Ursprünglich hat diese Methode addEqualsFilter verwendet, um die
* passenden Kategorien direkt in der SQL-Abfrage zu filtern. Das ist
* aber mit den lokalisierten URL der neuen, lokalisierten Kategorien
* nicht mehr möglich - oder zumindest habe ich keinen Weg gefunden.
* Stattdessen wird die Filterung nun in Java vorgenommen.
*
* Quasimodo
*/
public static Category[] resolveCategory(Category root, public static Category[] resolveCategory(Category root,
String path) { String path) {
String[] bits = StringUtils.split(path, '/'); String[] bits = StringUtils.split(path, '/');
@ -333,16 +350,24 @@ public class NavigationFileResolver extends DefaultApplicationFileResolver {
} }
CategoryCollection children = cat.getChildren(); CategoryCollection children = cat.getChildren();
children.addEqualsFilter(Category.URL, bits[i]); // children.addEqualsFilter(Category.URL, bits[i]);
children.addEqualsFilter(Category.IS_ENABLED, Boolean.TRUE); // children.addEqualsFilter(Category.IS_ENABLED, Boolean.TRUE);
if (children.next()) { // if (children.next()) {
boolean found = false;
while (children.next()) {
cat = children.getCategory(); cat = children.getCategory();
if (s_log.isDebugEnabled()) { if(cat.getURL().equals(bits[i]) && cat.isEnabled() == true) {
s_log.debug("Got category " + cat); if (s_log.isDebugEnabled()) {
s_log.debug("Got category " + cat);
}
cats.add(cat);
children.close();
found = true;
break;
} }
cats.add(cat); }
children.close(); // } else {
} else { if(found == false) {
if (s_log.isDebugEnabled()) { if (s_log.isDebugEnabled()) {
s_log.debug("No category found "); s_log.debug("No category found ");
} }