diff --git a/ccm-cms/src/com/arsdigita/cms/ui/CMSResources.properties b/ccm-cms/src/com/arsdigita/cms/ui/CMSResources.properties index 4fa55fc2f..d13ae9475 100755 --- a/ccm-cms/src/com/arsdigita/cms/ui/CMSResources.properties +++ b/ccm-cms/src/com/arsdigita/cms/ui/CMSResources.properties @@ -262,6 +262,7 @@ cms.ui.cannot_assign_groups_to_owner=cannot assign groups to owner cms.ui.categories=Categories cms.ui.category._back= (back)  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_use_context=Add Use Context 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.details=Category details 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_purposes=Edit purposes 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=Categorized item 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.none=This category has no linked categories cms.ui.category.linked=Linked categories diff --git a/ccm-cms/src/com/arsdigita/cms/ui/CMSResources_de.properties b/ccm-cms/src/com/arsdigita/cms/ui/CMSResources_de.properties index 64cb4f10e..062d66cbf 100755 --- a/ccm-cms/src/com/arsdigita/cms/ui/CMSResources_de.properties +++ b/ccm-cms/src/com/arsdigita/cms/ui/CMSResources_de.properties @@ -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.none=Diese Kategorie hat keine verkn\u00FCpften 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.no_categorized_objects=Es gibt keine kategorisierten Objekte cms.ui.category.no_category_purposes=No Category Purposes diff --git a/ccm-cms/src/com/arsdigita/cms/ui/category/BaseCategoryForm.java b/ccm-cms/src/com/arsdigita/cms/ui/category/BaseCategoryForm.java index 4687ae198..b7c926d46 100755 --- a/ccm-cms/src/com/arsdigita/cms/ui/category/BaseCategoryForm.java +++ b/ccm-cms/src/com/arsdigita/cms/ui/category/BaseCategoryForm.java @@ -58,9 +58,7 @@ class BaseCategoryForm extends BaseForm { final TextField m_url; final RadioGroup m_isAbstract; final RadioGroup m_isEnabled; - private Label m_script = new Label("", false); - - + private Label m_script = new Label("", false); private final static String NAME = "name"; private final static String DESCRIPTION = "description"; diff --git a/ccm-cms/src/com/arsdigita/cms/ui/category/CategoryAdminPane.java b/ccm-cms/src/com/arsdigita/cms/ui/category/CategoryAdminPane.java index c30118934..b266b383f 100755 --- a/ccm-cms/src/com/arsdigita/cms/ui/category/CategoryAdminPane.java +++ b/ccm-cms/src/com/arsdigita/cms/ui/category/CategoryAdminPane.java @@ -91,22 +91,28 @@ public final class CategoryAdminPane extends BaseAdminPane { m_contextModel = new UseContextSelectionModel(new StringParameter(CONTEXT_SELECTED)); - + /* Left column */ + /* Use context section */ List list = new List(new CategoryUseContextModelBuilder()); list.setSelectionModel(m_contextModel); list.addChangeListener(new ContextSelectionListener()); + + /* Category tree section */ m_categoryTree = new BaseTree(new CategoryTreeModelBuilder(m_contextModel)); m_categoryTree.addChangeListener(new SelectionListener()); m_model = m_categoryTree.getSelectionModel(); - setSelectionModel(m_model); setSelector(m_categoryTree); + + /* setup use context form */ final Section contextSection = new Section(); contextSection.setHeading(new Label(gz("cms.ui.category.use_contexts"))); ActionGroup contextGroup = new ActionGroup(); contextSection.setBody(contextGroup); contextGroup.setSubject(list); + + /* Add use context form to pane */ ActionLink addContextAction = new ActionLink(new Label(gz("cms.ui.category.add_use_context"))); Form addContextForm = new AddUseContextForm(m_contextModel); getBody().add(addContextForm); @@ -129,6 +135,10 @@ public final class CategoryAdminPane extends BaseAdminPane { m_parent = new ParentRequestLocal(); m_category = new SelectionRequestLocal(); + /* Right column */ + /* Context section aka category details */ + + /* Action links */ setAdd(gz("cms.ui.category.add"), new CategoryAddForm(m_category, m_model)); diff --git a/ccm-cms/src/com/arsdigita/cms/ui/category/CategoryCollectionListModel.java b/ccm-cms/src/com/arsdigita/cms/ui/category/CategoryCollectionListModel.java index a0336a415..f3765d775 100755 --- a/ccm-cms/src/com/arsdigita/cms/ui/category/CategoryCollectionListModel.java +++ b/ccm-cms/src/com/arsdigita/cms/ui/category/CategoryCollectionListModel.java @@ -73,8 +73,17 @@ public final class CategoryCollectionListModel implements ListModel { 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() { - return getCategory().getName(); + return getCategory().getName(""); } public String getKey() { diff --git a/ccm-cms/src/com/arsdigita/cms/ui/category/CategoryEditForm.java b/ccm-cms/src/com/arsdigita/cms/ui/category/CategoryEditForm.java index 8b601be4c..882c179ae 100755 --- a/ccm-cms/src/com/arsdigita/cms/ui/category/CategoryEditForm.java +++ b/ccm-cms/src/com/arsdigita/cms/ui/category/CategoryEditForm.java @@ -61,9 +61,9 @@ final class CategoryEditForm extends BaseCategoryForm { final PageState state = e.getPageState(); final Category category = m_category.getCategory(state); - m_name.setValue(state, category.getName()); - m_description.setValue(state, category.getDescription()); - m_url.setValue(state, category.getURL()); + m_name.setValue(state, category.getName("")); + m_description.setValue(state, category.getDescription("")); + m_url.setValue(state, category.getURL("")); // this seems anti-intuitive but the question is "can you place // items in this category. If the user says "yes" then the // category is not abstract @@ -73,7 +73,7 @@ final class CategoryEditForm extends BaseCategoryForm { m_isAbstract.setValue(state, "yes"); } - if (category.isEnabled()) { + if (category.isEnabled("")) { m_isEnabled.setValue(state, "yes"); } else { m_isEnabled.setValue(state, "no"); diff --git a/ccm-cms/src/com/arsdigita/cms/ui/category/CategoryItemPane.java b/ccm-cms/src/com/arsdigita/cms/ui/category/CategoryItemPane.java index f889609a4..a9df661fa 100755 --- a/ccm-cms/src/com/arsdigita/cms/ui/category/CategoryItemPane.java +++ b/ccm-cms/src/com/arsdigita/cms/ui/category/CategoryItemPane.java @@ -32,6 +32,7 @@ import com.arsdigita.bebop.event.ActionListener; import com.arsdigita.bebop.event.ChangeEvent; import com.arsdigita.bebop.event.ChangeListener; import com.arsdigita.bebop.form.Submit; +import com.arsdigita.categorization.CategorizationConfig; import com.arsdigita.categorization.CategorizedCollection; import com.arsdigita.categorization.Category; import com.arsdigita.categorization.CategoryNotFoundException; @@ -54,6 +55,7 @@ import com.arsdigita.persistence.DataObject; import com.arsdigita.persistence.OID; import com.arsdigita.toolbox.ui.ActionGroup; import com.arsdigita.toolbox.ui.PropertyList; +import com.arsdigita.toolbox.ui.PropertyList.Property; import com.arsdigita.toolbox.ui.Section; import com.arsdigita.util.Assert; import com.arsdigita.web.Web; @@ -73,146 +75,172 @@ import org.apache.log4j.Logger; */ class CategoryItemPane extends BaseItemPane { public static final String versionId = - "$Id: CategoryItemPane.java 1329 2006-09-27 11:47:05Z sskracic $" + - "$Author: sskracic $" + - "$DateTime: 2004/08/17 23:15:09 $"; - + "$Id: CategoryItemPane.java 1329 2006-09-27 11:47:05Z sskracic $" + + "$Author: sskracic $" + + "$DateTime: 2004/08/17 23:15:09 $"; + private static final Logger s_log = Logger.getLogger - (CategoryItemPane.class); - + (CategoryItemPane.class); + private final SingleSelectionModel m_model; private final CategoryRequestLocal m_category; - + private final SimpleContainer m_detailPane; - + public CategoryItemPane(final SingleSelectionModel model, - final CategoryRequestLocal category, - final ActionLink addLink, - final ActionLink editLink, - final ActionLink deleteLink) { + final CategoryRequestLocal category, + final ActionLink addLink, + final ActionLink editLink, + final ActionLink deleteLink) { m_model = model; m_category = category; - + // Details - + m_detailPane = new SimpleContainer(); add(m_detailPane); setDefault(m_detailPane); - - final ActionLink orderItemsLink = - new ActionLink(new Label(gz("cms.ui.category.categorized_objects"))) { - public boolean isVisible(PageState state) { - // update for live items only - if (!super.isVisible(state)) { - 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; + + final ActionLink orderItemsLink = new ActionLink(new Label(gz("cms.ui.category.categorized_objects"))) { + public boolean isVisible(PageState state) { + // update for live items only + if (!super.isVisible(state)) { + 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; + } + }; + + final Form orderItemsForm = new OrderItemsForm(m_category); final Form orderItemsForm2 = new OrderItemsForm(m_category); add(orderItemsForm); add(orderItemsForm2); - + + // Change index item final ActionLink indexLink = new ActionLink(new Label(gz("cms.ui.category.change_index_item"))); final Form indexForm = new IndexItemSelectionForm(m_category); add(indexForm); - + 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")),""); - + + // Summary 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)); - + // Linked categories 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); add(linkForm); - + linkAddLink.addActionListener(new NavigationListener(linkForm)); linkForm.addSubmissionListener(new CancelListener(linkForm)); - + m_detailPane.add(new LinkedCategorySection(linkAddLink)); - + // Templates m_detailPane.add(new AdminVisible(new CategoryTemplateSection())); - + // Permissions m_detailPane.add(new PermissionsSection()); - + connect(indexLink, indexForm); connect(indexForm); - + connect(orderItemsLink, orderItemsForm); connect(orderItemsForm); - + } - + private class EditVisible extends VisibilityComponent { EditVisible(final Component child) { super(child, null); } - + public boolean hasPermission(PageState ps) { return m_category.getCategory(ps).canEdit(); } } - + private class AdminVisible extends VisibilityComponent { AdminVisible(final Component child) { super(child, null); } - + public boolean hasPermission(PageState ps) { return m_category.getCategory(ps).canAdmin(); } } - + private class SummarySection extends Section { - + SummarySection(final ActionLink editLink, - final ActionLink deleteLink, - final ActionLink indexLink, - final ActionLink orderItemsLink) { + final ActionLink deleteLink, + final ActionLink indexLink, + final ActionLink orderItemsLink) { setHeading(new Label(gz("cms.ui.category.details"))); - + final ActionGroup group = new ActionGroup(); setBody(group); - + group.setSubject(new Properties()); - + group.addAction(new EditVisible(editLink), ActionGroup.EDIT); group.addAction(new EditVisible(orderItemsLink)); group.addAction(new EditVisible(indexLink)); group.addAction(new AdminVisible(deleteLink), ActionGroup.DELETE); } - + /* * This alternative constructor sets two additional links, allowing the user to view and * edit the content index item. */ SummarySection(final ActionLink editLink, - final ActionLink deleteLink, - final ActionLink indexLink, - final BaseLink viewIndexItem, - final BaseLink editIndexItem, - final ActionLink orderItemsLink) { + final ActionLink deleteLink, + final ActionLink indexLink, + final BaseLink viewIndexItem, + final BaseLink editIndexItem, + final ActionLink orderItemsLink) { setHeading(new Label(gz("cms.ui.category.details"))); - + final ActionGroup group = new ActionGroup(); setBody(group); - + group.setSubject(new Properties()); - + group.addAction(new EditVisible(editLink), ActionGroup.EDIT); group.addAction(new EditVisible(orderItemsLink)); group.addAction(new EditVisible(indexLink)); @@ -220,131 +248,145 @@ class CategoryItemPane extends BaseItemPane { group.addAction(new EditVisible(editIndexItem)); group.addAction(new AdminVisible(deleteLink), ActionGroup.DELETE); } - + private class Properties extends PropertyList { protected final java.util.List properties(final PageState state) { final java.util.List props = super.properties(state); final Category category = m_category.getCategory(state); final ACSObject item = category.getDirectIndexObject(); - + String itemTitle = ""; - + if (item != null) { itemTitle = item.getDisplayName(); } - + props.add(new Property(gz("cms.ui.name"), - category.getName())); + category.getName(""))); props.add(new Property(gz("cms.ui.description"), - category.getDescription())); + category.getDescription(""))); props.add(new Property(gz("cms.ui.category.url"), - category.getURL())); + category.getURL(""))); props.add(new Property(gz("cms.ui.category.is_not_abstract"), - category.isAbstract() ? - gz("cms.ui.no") : - gz("cms.ui.yes"))); + category.isAbstract() ? + gz("cms.ui.no") : + gz("cms.ui.yes"))); props.add(new Property(gz("cms.ui.category.is_enabled"), - category.isEnabled() ? - gz("cms.ui.yes") : - gz("cms.ui.no"))); + category.isEnabled("") ? + gz("cms.ui.yes") : + gz("cms.ui.no"))); props.add(new Property(gz("cms.ui.category.index_item"), - itemTitle)); - + itemTitle)); + 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 { SubcategorySection(final ActionLink addLink) { setHeading(new Label(gz("cms.ui.category.subcategories"))); - + final ActionGroup group = new ActionGroup(); setBody(group); - + group.setSubject(new SubcategoryList(m_category, m_model)); group.addAction(new AdminVisible(addLink), ActionGroup.ADD); } } - + private class LinkedCategorySection extends Section { LinkedCategorySection(final ActionLink linkAddLink) { setHeading(new Label(gz("cms.ui.category.linked"))); - + final ActionGroup group = new ActionGroup(); setBody(group); - + group.setSubject(new CategoryLinks(m_category, m_model)); group.addAction(new EditVisible(linkAddLink), ActionGroup.EDIT); } - + public final boolean isVisible(final PageState state) { return !m_category.getCategory(state).isRoot(); } } - + private class CategoryTemplateSection extends Section { CategoryTemplateSection() { setHeading(new Label(gz("cms.ui.category.templates"))); - + final ActionGroup group = new ActionGroup(); setBody(group); - + group.setSubject(new CategoryTemplates(m_category)); // XXX secvis //group.addAction(link); } } - + private class PermissionsSection extends Section { public boolean isVisible(PageState ps) { Category cat = m_category.getCategory(ps); return !cat.isRoot() && cat.canAdmin(); } - + PermissionsSection() { setHeading(new Label(gz("cms.ui.permissions"))); - + final ActionGroup group = new ActionGroup(); setBody(group); - + PrivilegeDescriptor[] privs = new PrivilegeDescriptor[] { PrivilegeDescriptor.EDIT, Category.MAP_DESCRIPTOR, PrivilegeDescriptor.DELETE, PrivilegeDescriptor.ADMIN }; - + HashMap privMap = new HashMap(); privMap.put("edit", "Edit"); privMap.put("delete", "Delete"); privMap.put(Category.MAP_DESCRIPTOR.getName(), "Categorize Items"); privMap.put("admin", "Admin"); - + final CMSPermissionsPane permPane = new CMSPermissionsPane - (privs, privMap, new ACSObjectSelectionModel(m_model)) { + (privs, privMap, new ACSObjectSelectionModel(m_model)) { public void showAdmin(PageState ps) { Assert.exists(m_model.getSelectedKey(ps)); - + super.showAdmin(ps); getAdminListingPanel().setVisible(ps, false); } }; - + final ActionLink restoreDefault = new ActionLink(new Label(gz("cms.ui.restore_default_permissions"))) { public boolean isVisible(PageState ps) { Category cat = m_category.getCategory(ps); return PermissionService.getContext(cat) == null; } }; - + final ActionLink useCustom = new ActionLink(new Label(gz("cms.ui.use_custom_permissions"))) { public boolean isVisible(PageState ps) { Category cat = m_category.getCategory(ps); return PermissionService.getContext(cat) != null; } }; - + ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent event) { PageState state = event.getPageState(); @@ -363,18 +405,18 @@ class CategoryItemPane extends BaseItemPane { parent = cat.getDefaultParentCategory(); } catch (CategoryNotFoundException ce) { throw new IllegalStateException( - "link shouldn't exist for root categories"); + "link shouldn't exist for root categories"); } PermissionService.setContext(cat, parent); - + // revoke all direct permissions so category will only // have inherited permissions ObjectPermissionCollection perms = - PermissionService.getDirectGrantedPermissions( + PermissionService.getDirectGrantedPermissions( cat.getOID()); while (perms.next()) { PermissionService.revokePermission( - new PermissionDescriptor( + new PermissionDescriptor( perms.getPrivilege(), cat.getOID(), perms.getGranteeOID())); } @@ -382,17 +424,17 @@ class CategoryItemPane extends BaseItemPane { permPane.reset(state); } }; - + restoreDefault.addActionListener(al); useCustom.addActionListener(al); - + SimpleContainer links = new SimpleContainer(); links.add(restoreDefault); links.add(useCustom); - + group.setSubject(permPane); group.addAction(links); - + m_model.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { PageState ps = e.getPageState(); @@ -400,22 +442,22 @@ class CategoryItemPane extends BaseItemPane { }); } } - + private static class OrderItemsForm extends CMSForm { - + public OrderItemsForm(CategoryRequestLocal category) { super("orderItems", new SimpleContainer()); Label header = new Label(gz("cms.ui.category.categorized_objects")); header.setFontWeight(Label.BOLD); add(header); add(new CategorizedObjectsList(category)); - + add(new Submit("Done")); - + } - + } - + /* * 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) { super(c,s); } - + // Build the preview link. This uses a standard redirect link to find the content. // The prepareURL method is called by the printwriter protected String prepareURL(final PageState state, String location) { - + ContentItem indexItem = ((ContentBundle)(m_category.getCategory(state).getDirectIndexObject())).getPrimaryInstance(); if(indexItem==null) { return ""; @@ -435,7 +477,7 @@ class CategoryItemPane extends BaseItemPane { return "/redirect/?oid=" + URLEncoder.encode(indexItem.getOID().toString()); } } - + // We only show this link when an index item exists for this category public boolean isVisible(PageState state) { if (!super.isVisible(state)) { @@ -449,12 +491,12 @@ class CategoryItemPane extends BaseItemPane { } } }; - + private class EditItemLink extends Link { EditItemLink(Component c, String s) { super(c,s); } - + // 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 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; } } - + // We only show this link when an index item exists for this category and // the user is allowed to edit this item. public boolean isVisible(PageState state) { @@ -484,7 +526,7 @@ class CategoryItemPane extends BaseItemPane { return isItemEditable((ContentItem)indexItem,state); } } - + // This method checks whether a usern is allowed to edit a particular item private boolean isItemEditable(ContentItem item, PageState state) { BigDecimal id = item.getID(); diff --git a/ccm-core/pdl/com/arsdigita/categorization/Category.pdl b/ccm-core/pdl/com/arsdigita/categorization/Category.pdl index afd6d3904..8252b5966 100755 --- a/ccm-core/pdl/com/arsdigita/categorization/Category.pdl +++ b/ccm-core/pdl/com/arsdigita/categorization/Category.pdl @@ -22,10 +22,13 @@ model com.arsdigita.categorization; import com.arsdigita.kernel.*; object type Category extends ACSObject { + + // Hier werden die Default-Werte gespeichert ??? String[0..1] description = cat_categories.description VARCHAR(4000); String[1..1] name = cat_categories.name VARCHAR(200); String[0..1] url = cat_categories.url VARCHAR(200); Boolean[1..1] isEnabled = cat_categories.enabled_p CHAR(1); + Boolean[1..1] isAbstract = cat_categories.abstract_p CHAR(1); String[1..1] defaultAncestors = cat_categories.default_ancestors VARCHAR(3209); 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); } +// 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 { BigDecimal[1..1] id = cat_root_cat_object_map.id; diff --git a/ccm-core/src/com/arsdigita/categorization/CategorizationConfig.java b/ccm-core/src/com/arsdigita/categorization/CategorizationConfig.java new file mode 100644 index 000000000..83e214d9d --- /dev/null +++ b/ccm-core/src/com/arsdigita/categorization/CategorizationConfig.java @@ -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); + } + +} diff --git a/ccm-core/src/com/arsdigita/categorization/CategorizationConfig_parameter.properties b/ccm-core/src/com/arsdigita/categorization/CategorizationConfig_parameter.properties new file mode 100644 index 000000000..af8f40e5e --- /dev/null +++ b/ccm-core/src/com/arsdigita/categorization/CategorizationConfig_parameter.properties @@ -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] diff --git a/ccm-core/src/com/arsdigita/categorization/Category.java b/ccm-core/src/com/arsdigita/categorization/Category.java index 722989ee0..9051f86aa 100755 --- a/ccm-core/src/com/arsdigita/categorization/Category.java +++ b/ccm-core/src/com/arsdigita/categorization/Category.java @@ -83,6 +83,24 @@ import org.apache.log4j.Logger; * * @author Randy Graebner * @version $Revision: 1.1 $ $DateTime: $ + * + *

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: + * + *

+ * + * 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 { 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 = 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 USE_CONTEXT = "useContext"; 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 RELATED_CATEGORIES = RELATED; public final static String CATEGORIES = "categories"; + + public static final String LOCALIZATIONS = "localizations"; // some named queries in the pdl files private static final String CHILD_CATEGORY_IDS = @@ -158,6 +186,11 @@ public class Category extends ACSObject { private HierarchyDenormalization m_hierarchy; + // Quasimodo: Begin + // Save the localized parts of category + private CategoryLocalizationCollection m_categoryLocalizationCollection; + // Quasimodo: End + protected String getBaseDataObjectType() { 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() */ @@ -334,21 +376,58 @@ public class Category extends ACSObject { setAbstract(false); //by default do not ignore the parent index item setIgnoreParentIndexItem(false); + } - + m_hierarchy = new HierarchyDenormalization ("com.arsdigita.categorization.updateCategoryDescendants", this, 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. */ 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 * implementation. @@ -462,17 +541,55 @@ public class Category extends ACSObject { * * @param value the new name of the category */ - public void setName(String value) { - set(NAME, value); + public void setName(String name, String locale) { + + 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. * @return the category name. */ 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 */ - public void setDescription(String value) { - set(DESCRIPTION, value); + public void setDescription(String description, String locale) { + + 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. @@ -498,10 +652,24 @@ public class Category extends ACSObject { * @return URL component used when browsing categories */ 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. * @@ -517,11 +685,64 @@ public class Category extends ACSObject { * * @return true if the category is enabled; false * 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() { - return ((Boolean) get(IS_ENABLED)).booleanValue(); + public boolean isEnabled(String locale) { + + // 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 true if the category is enabled; false + * otherwise. + */ + public boolean isEnabled() { + return isEnabled(this.getNegotiatedLocale()); + } + + + /** + * Sets whether the category is enabled. + * + * @param isEnabled true if the category is enabled; + * 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. @@ -1706,6 +1927,11 @@ public class Category extends ACSObject { * @return Array of constituent categories. The first element of the array * is the current category (hence the array will always have length >= * 1). If the path is bad, this returns null. + * + * 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) { final List children = new LinkedList(); @@ -1971,4 +2197,103 @@ public class Category extends ACSObject { (new PermissionDescriptor(PrivilegeDescriptor.ADMIN, this, 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; + } + } diff --git a/ccm-core/src/com/arsdigita/categorization/CategoryLocalization.java b/ccm-core/src/com/arsdigita/categorization/CategoryLocalization.java new file mode 100644 index 000000000..2713afd89 --- /dev/null +++ b/ccm-core/src/com/arsdigita/categorization/CategoryLocalization.java @@ -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)); + } + +} diff --git a/ccm-core/src/com/arsdigita/categorization/CategoryLocalizationCollection.java b/ccm-core/src/com/arsdigita/categorization/CategoryLocalizationCollection.java new file mode 100644 index 000000000..450c0b84b --- /dev/null +++ b/ccm-core/src/com/arsdigita/categorization/CategoryLocalizationCollection.java @@ -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. + * + *

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()}.

+ * + * @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 true if the category is enabled; false + * otherwise. + * @see Category#isEnabled() + */ + public boolean isEnabled() { + return getCategoryLocalization().isEnabled(); + } + + /** + * Wrapper to getDomainObject() that casts the returned + * DomainObject as a CategoryLocalization. + * + * @return a CategoryLocalization 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"); + } + } +} diff --git a/ccm-ldn-navigation/src/com/arsdigita/london/navigation/NavigationFileResolver.java b/ccm-ldn-navigation/src/com/arsdigita/london/navigation/NavigationFileResolver.java index e035a7814..abac47804 100755 --- a/ccm-ldn-navigation/src/com/arsdigita/london/navigation/NavigationFileResolver.java +++ b/ccm-ldn-navigation/src/com/arsdigita/london/navigation/NavigationFileResolver.java @@ -16,6 +16,10 @@ * 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; @@ -315,7 +319,20 @@ public class NavigationFileResolver extends DefaultApplicationFileResolver { 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, String path) { String[] bits = StringUtils.split(path, '/'); @@ -333,16 +350,24 @@ public class NavigationFileResolver extends DefaultApplicationFileResolver { } CategoryCollection children = cat.getChildren(); - children.addEqualsFilter(Category.URL, bits[i]); - children.addEqualsFilter(Category.IS_ENABLED, Boolean.TRUE); - if (children.next()) { +// children.addEqualsFilter(Category.URL, bits[i]); +// children.addEqualsFilter(Category.IS_ENABLED, Boolean.TRUE); +// if (children.next()) { + boolean found = false; + while (children.next()) { cat = children.getCategory(); - if (s_log.isDebugEnabled()) { - s_log.debug("Got category " + cat); + if(cat.getURL().equals(bits[i]) && cat.isEnabled() == true) { + 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()) { s_log.debug("No category found "); }