CCM NG: Current progress of porting the ItemSearch forms to NG
git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4495 8810af33-2d31-482b-a856-94f89814c4dfpull/2/head
parent
6b1f80cfaa
commit
25161c8f04
|
|
@ -56,6 +56,12 @@
|
|||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-search-orm</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
|
|
|
|||
|
|
@ -56,6 +56,12 @@
|
|||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-search-orm</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
|
|
|
|||
|
|
@ -56,6 +56,12 @@
|
|||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-search-orm</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
|
|
|
|||
|
|
@ -56,6 +56,12 @@
|
|||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-search-orm</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
|
|
|
|||
|
|
@ -56,6 +56,12 @@
|
|||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-search-orm</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
|
|
|
|||
|
|
@ -56,6 +56,12 @@
|
|||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-search-orm</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
|
|
|
|||
|
|
@ -56,6 +56,12 @@
|
|||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-search-orm</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
|
|
|
|||
|
|
@ -22,30 +22,29 @@ import com.arsdigita.bebop.Form;
|
|||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Resettable;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
|
||||
import com.arsdigita.search.QuerySpecification;
|
||||
import com.arsdigita.search.ui.QueryGenerator;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* A wrapper around the {@link ItemSearchSection} which embedds
|
||||
* the form section in a form.
|
||||
* A wrapper around the {@link ItemSearchSection} which embeds the form section
|
||||
* in a form.
|
||||
*
|
||||
* @author Stanislav Freidin (sfreidin@arsdigita.com)
|
||||
* @version $Id: ItemSearch.java 1940 2009-05-29 07:15:05Z terry $
|
||||
* @author <a href="jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public class ItemSearch extends Form implements Resettable, QueryGenerator {
|
||||
public class ItemSearch extends Form implements Resettable {
|
||||
|
||||
private static final org.apache.log4j.Logger s_log =
|
||||
org.apache.log4j.Logger.getLogger(ItemSearch.class);
|
||||
private static final Logger LOGGER = LogManager.getLogger(ItemSearch.class);
|
||||
public static final String SINGLE_TYPE_PARAM = ItemSearchSection.SINGLE_TYPE_PARAM;
|
||||
private ItemSearchSection m_section;
|
||||
|
||||
private ItemSearchSection itemSearchSection;
|
||||
|
||||
/**
|
||||
* Construct a new <code>ItemSearch</code> component
|
||||
* Default to limit the search to current content section
|
||||
* Construct a new <code>ItemSearch</code> component Default to limit the
|
||||
* search to current content section
|
||||
*
|
||||
* @param context the context for the retrieved items. Should be
|
||||
* {@link ContentItem#DRAFT} or {@link ContentItem#LIVE}
|
||||
* {@link ContentItem#DRAFT} or {@link ContentItem#LIVE}
|
||||
*/
|
||||
public ItemSearch(String context) {
|
||||
this(context, true);
|
||||
|
|
@ -55,32 +54,34 @@ public class ItemSearch extends Form implements Resettable, QueryGenerator {
|
|||
* Construct a new <code>ItemSearch</code> component
|
||||
*
|
||||
* @param context the context for the retrieved items. Should be
|
||||
* {@link ContentItem#DRAFT} or {@link ContentItem#LIVE}
|
||||
* @param limitToContentSection limit the search to the current content section
|
||||
* {@link ContentItem#DRAFT} or {@link ContentItem#LIVE}
|
||||
* @param limitToContentSection limit the search to the current content
|
||||
* section
|
||||
*/
|
||||
public ItemSearch(String context, boolean limitToContentSection) {
|
||||
super("itemSearch", new SimpleContainer());
|
||||
//setMethod("GET");
|
||||
m_section = createSearchSection(context, limitToContentSection);
|
||||
add(m_section);
|
||||
itemSearchSection = createSearchSection(context, limitToContentSection);
|
||||
add(itemSearchSection);
|
||||
}
|
||||
|
||||
protected ItemSearchSection createSearchSection(String context, boolean limitToContentSection) {
|
||||
protected ItemSearchSection createSearchSection(String context,
|
||||
boolean limitToContentSection) {
|
||||
return new ItemSearchSection(context, limitToContentSection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasQuery(PageState state) {
|
||||
return m_section.hasQuery(state);
|
||||
return itemSearchSection.hasQuery(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QuerySpecification getQuerySpecification(PageState state) {
|
||||
return m_section.getQuerySpecification(state);
|
||||
return itemSearchSection.getQuerySpecification(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(PageState state) {
|
||||
m_section.reset(state);
|
||||
itemSearchSection.reset(state);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.BoxPanel;
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.ParameterSingleSelectionModel;
|
||||
import com.arsdigita.bebop.Resettable;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.bebop.SingleSelectionModel;
|
||||
import com.arsdigita.bebop.Tree;
|
||||
import com.arsdigita.bebop.event.ActionEvent;
|
||||
import com.arsdigita.bebop.event.ActionListener;
|
||||
import com.arsdigita.bebop.event.ChangeEvent;
|
||||
import com.arsdigita.bebop.event.ChangeListener;
|
||||
import com.arsdigita.bebop.event.FormInitListener;
|
||||
import com.arsdigita.bebop.event.FormProcessListener;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.event.FormSubmissionListener;
|
||||
import com.arsdigita.bebop.event.TreeExpansionEvent;
|
||||
import com.arsdigita.bebop.event.TreeExpansionListener;
|
||||
import com.arsdigita.bebop.form.Option;
|
||||
import com.arsdigita.bebop.form.SingleSelect;
|
||||
import com.arsdigita.bebop.form.Submit;
|
||||
import com.arsdigita.bebop.parameters.BigDecimalParameter;
|
||||
import com.arsdigita.cms.dispatcher.Utilities;
|
||||
|
||||
import com.arsdigita.cms.CMS;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.contentsection.Folder;
|
||||
import com.arsdigita.cms.ui.authoring.NewItemForm;
|
||||
import com.arsdigita.cms.ui.folder.FolderRequestLocal;
|
||||
import com.arsdigita.cms.ui.folder.FolderSelectionModel;
|
||||
import com.arsdigita.cms.ui.folder.FolderTreeModelBuilder;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.toolbox.ui.LayoutPanel;
|
||||
import com.arsdigita.util.Assert;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.arsdigita.cms.CMSConfig;
|
||||
import org.librecms.CmsConstants;
|
||||
import org.librecms.contentsection.ContentSectionConfig;
|
||||
|
||||
/**
|
||||
* A pane that contains a folder tree on the left and a folder manipulator on
|
||||
* the right.
|
||||
*
|
||||
* @author David LutterKort <dlutter@redhat.com>
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public class ItemSearchBrowsePane extends SimpleContainer implements Resettable,
|
||||
TreeExpansionListener,
|
||||
ChangeListener,
|
||||
FormProcessListener,
|
||||
FormSubmissionListener {
|
||||
|
||||
private static final String CONTENT_TYPE_ID = "ct";
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
ItemSearchBrowsePane.class);
|
||||
private final FolderSelectionModel folderSelectionModel;
|
||||
private final FolderRequestLocal folderRequestLocal;
|
||||
private final Tree tree;
|
||||
private ItemSearchFolderBrowser folderBrowser;
|
||||
private SingleSelect sectionSelect;
|
||||
private SingleSelectionModel typeSelectionModel;
|
||||
|
||||
public ItemSearchBrowsePane() {
|
||||
|
||||
final LayoutPanel mainPanel = new LayoutPanel();
|
||||
|
||||
setClassAttr("sidebarNavPanel");
|
||||
setAttribute("navbar-title",
|
||||
new GlobalizedMessage("cms.ui.folder_browser",
|
||||
CmsConstants.CMS_BUNDLE)
|
||||
.localize().toString());
|
||||
|
||||
final BoxPanel left = new BoxPanel(BoxPanel.VERTICAL);
|
||||
|
||||
final Label label = new Label(new GlobalizedMessage(
|
||||
"cms.ui.folder_browser", CmsConstants.CMS_BUNDLE));
|
||||
label.setClassAttr("heading");
|
||||
left.add(label);
|
||||
|
||||
// As described in ticket 20540, some clients do not want the option to pick items from other
|
||||
// subsites through the ItemSearchBrowsePane. A new parameter has been added to allow the
|
||||
// administrator to pick between the old and new versions.
|
||||
boolean linksOnlyInSameSubsite = CMSConfig.getConfig()
|
||||
.isLinksOnlyInSameSubsite();
|
||||
LOGGER.debug("linksOnlyInSameSubsite value is {}",
|
||||
linksOnlyInSameSubsite);
|
||||
|
||||
tree = new Tree(new FolderTreeModelBuilder() {
|
||||
@Override
|
||||
protected Folder getRoot(PageState ps) {
|
||||
Folder root = getRootFolder(ps);
|
||||
|
||||
if (null == root) {
|
||||
return super.getRoot(ps);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
});
|
||||
folderSelectionModel = createFolderSelectionModel();
|
||||
folderSelectionModel.addChangeListener(this);
|
||||
folderRequestLocal = new FolderRequestLocal(folderSelectionModel);
|
||||
|
||||
if (!linksOnlyInSameSubsite) {
|
||||
// The client should be able to pick between the subsites
|
||||
Form sectionForm = getSectionForm();
|
||||
add(sectionForm);
|
||||
}
|
||||
|
||||
tree.setSelectionModel(folderSelectionModel);
|
||||
|
||||
tree.setClassAttr("navbar");
|
||||
tree.addTreeExpansionListener(this);
|
||||
left.add(tree);
|
||||
|
||||
// CMSContainer container = new CMSContainer();
|
||||
left.setClassAttr("main");
|
||||
|
||||
final BoxPanel body = new BoxPanel(BoxPanel.VERTICAL);
|
||||
folderBrowser = new ItemSearchFolderBrowser(folderSelectionModel);
|
||||
body.add(folderBrowser);
|
||||
body.add(folderBrowser.getPaginator());
|
||||
|
||||
// m_newItem = new SectionNewItemForm("newItem");
|
||||
// m_typeSel = new ParameterSingleSelectionModel(new BigDecimalParameter(CONTENT_TYPE_ID));
|
||||
// m_newItem.addProcessListener(this);
|
||||
//
|
||||
// container.add(m_newItem);
|
||||
//add(container);
|
||||
mainPanel.setLeft(left);
|
||||
mainPanel.setBody(body);
|
||||
add(mainPanel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible(PageState s) {
|
||||
// Always expand root node
|
||||
if (tree.isCollapsed(getRootFolder(s).getID().toString(), s)) {
|
||||
tree.expand(getRootFolder(s).getID().toString(), s);
|
||||
}
|
||||
|
||||
return super.isVisible(s);
|
||||
}
|
||||
|
||||
private Form getSectionForm() {
|
||||
Form sectionForm = new Form("isfbSectionForm",
|
||||
new BoxPanel(BoxPanel.HORIZONTAL));
|
||||
sectionForm.setClassAttr("navbar");
|
||||
|
||||
sectionSelect = new SingleSelect(new OIDParameter("isfbSection"));
|
||||
ContentSectionCollection sections = ContentSection.getAllSections();
|
||||
while (sections.next()) {
|
||||
ContentSection section = sections.getContentSection();
|
||||
sectionSelect.addOption(new Option(section.getOID().toString(),
|
||||
section.getDisplayName()));
|
||||
}
|
||||
|
||||
sectionForm.addInitListener(new FormInitListener() {
|
||||
@Override
|
||||
public void init(FormSectionEvent ev) {
|
||||
PageState ps = ev.getPageState();
|
||||
|
||||
if (null == sectionSelect.getValue(ps)) {
|
||||
ContentSection section = CMS.getContext().
|
||||
getContentSection();
|
||||
sectionSelect.setValue(ps, section.getOID());
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
sectionForm.add(sectionSelect);
|
||||
sectionForm.add(new Submit("Change Section"));
|
||||
|
||||
return sectionForm;
|
||||
}
|
||||
|
||||
private Folder getRootFolder(PageState ps) {
|
||||
LOGGER.debug("Getting the root folder.");
|
||||
if (sectionSelect != null) {
|
||||
// We have more than one subsite to choose between
|
||||
OID sectionOID = (OID) sectionSelect.getValue(ps);
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
if (null != sectionOID) {
|
||||
LOGGER.debug("Using section " + sectionOID.toString());
|
||||
} else {
|
||||
LOGGER.debug("Using default section");
|
||||
}
|
||||
}
|
||||
|
||||
if (null == sectionOID) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ContentSection section = (ContentSection) DomainObjectFactory.
|
||||
newInstance(sectionOID);
|
||||
|
||||
return section.getRootFolder();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Page p) {
|
||||
super.register(p);
|
||||
p.addComponentStateParam(this, folderSelectionModel.getStateParameter());
|
||||
|
||||
// Only add the SingleSelect item if it exists
|
||||
if (sectionSelect != null) {
|
||||
p.addComponentStateParam(this, sectionSelect.getParameterModel());
|
||||
}
|
||||
|
||||
// Save the state of the new item component
|
||||
// p.addComponentStateParam(this, m_typeSel.getStateParameter());
|
||||
p.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
final PageState state = e.getPageState();
|
||||
|
||||
if (state.isVisibleOnPage(ItemSearchBrowsePane.this)) {
|
||||
showHideSegments(state);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show/hide segments based on access checks.
|
||||
*
|
||||
* @param state The page state
|
||||
* @pre ( state != null )
|
||||
*/
|
||||
private void showHideSegments(PageState state) {
|
||||
SecurityManager sm = Utilities.getSecurityManager(state);
|
||||
Folder folder = folderRequestLocal.getFolder(state);
|
||||
Assert.exists(folder);
|
||||
|
||||
// MP: This should be checked on the current folder instead of just
|
||||
// the content section.
|
||||
// boolean newItem =
|
||||
// sm.canAccess(state.getRequest(), SecurityManager.NEW_ITEM, folder);
|
||||
//
|
||||
// if (!newItem) {
|
||||
// browseMode(state);
|
||||
// }
|
||||
// m_newItem.setVisible(state, newItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(PageState s) {
|
||||
//m_browser.reset(s);
|
||||
}
|
||||
|
||||
public ItemSearchFolderBrowser getFolderBrowser() {
|
||||
return folderBrowser;
|
||||
}
|
||||
|
||||
public final FolderSelectionModel getFolderSelectionModel() {
|
||||
return folderSelectionModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the current level of expansion of the folder tree and in the folder
|
||||
* browser table
|
||||
*/
|
||||
protected void setSelectedFolder(PageState s, String key) {
|
||||
|
||||
//set the selected folder of the folder browser
|
||||
folderBrowser.getFolderSelectionModel().setSelectedKey(s, key);
|
||||
|
||||
//set the selected folder of the folder tree
|
||||
folderSelectionModel.setSelectedKey(s, key);
|
||||
Folder current = (Folder) folderSelectionModel.getSelectedObject(s);
|
||||
Folder parent = (Folder) current.getParent();
|
||||
if (parent != null) {
|
||||
BigDecimal id = parent.getID();
|
||||
tree.expand(id.toString(), s);
|
||||
}
|
||||
}
|
||||
|
||||
// Implement TreeExpansionListener
|
||||
@Override
|
||||
public void treeCollapsed(TreeExpansionEvent e) {
|
||||
PageState s = e.getPageState();
|
||||
folderSelectionModel.setSelectedKey(s, e.getNodeKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void treeExpanded(TreeExpansionEvent e) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
PageState s = e.getPageState();
|
||||
Folder current = (Folder) folderSelectionModel.getSelectedObject(s);
|
||||
Folder parent = (Folder) current.getParent();
|
||||
folderBrowser.getPaginator().reset(s);
|
||||
if (parent != null) {
|
||||
BigDecimal id = parent.getID();
|
||||
tree.expand(id.toString(), s);
|
||||
}
|
||||
//m_browser.getPermissionsPane().reset(s);
|
||||
//m_browser.setPermissionLinkVis(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(FormSectionEvent e) {
|
||||
PageState s = e.getPageState();
|
||||
final Object source = e.getSource();
|
||||
// if (source == m_newItem) {
|
||||
// BigDecimal typeID = m_newItem.getTypeID(s);
|
||||
// m_typeSel.setSelectedKey(s, typeID);
|
||||
// newItemMode(s);
|
||||
// } else {
|
||||
browseMode(s);
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submitted(FormSectionEvent e) {
|
||||
PageState s = e.getPageState();
|
||||
final Object source = e.getSource();
|
||||
// if (source == m_newItem) {
|
||||
// BigDecimal typeID = m_newItem.getTypeID(s);
|
||||
// m_typeSel.setSelectedKey(s, typeID);
|
||||
// //newItemMode(s);
|
||||
// }
|
||||
}
|
||||
|
||||
private void browseMode(PageState s) {
|
||||
// m_browseSeg.setVisible(s, true);
|
||||
typeSelectionModel.clearSelection(s);
|
||||
}
|
||||
|
||||
private void newItemMode(PageState s) {
|
||||
// m_newItemSeg.setVisible(s, true);
|
||||
}
|
||||
|
||||
private FolderSelectionModel createFolderSelectionModel() {
|
||||
return new FolderSelectionModel("folder") {
|
||||
@Override
|
||||
protected BigDecimal getRootFolderID(PageState ps) {
|
||||
Folder root = getRootFolder(ps);
|
||||
|
||||
if (null == root) {
|
||||
return super.getRootFolderID(ps);
|
||||
}
|
||||
return root.getID();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private static class SectionNewItemForm extends NewItemForm {
|
||||
|
||||
public SectionNewItemForm(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentSection getContentSection(PageState s) {
|
||||
return CMS.getContext().getContentSection();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,494 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.Bebop;
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.Link;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.RequestLocal;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.PaginationModelBuilder;
|
||||
import com.arsdigita.bebop.Paginator;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.bebop.Table;
|
||||
import com.arsdigita.bebop.event.ActionEvent;
|
||||
import com.arsdigita.bebop.event.ActionListener;
|
||||
import com.arsdigita.bebop.event.TableActionAdapter;
|
||||
import com.arsdigita.bebop.event.TableActionEvent;
|
||||
import com.arsdigita.bebop.event.TableActionListener;
|
||||
import com.arsdigita.bebop.parameters.BigDecimalParameter;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.bebop.table.AbstractTableModelBuilder;
|
||||
import com.arsdigita.bebop.table.DefaultTableCellRenderer;
|
||||
import com.arsdigita.bebop.table.TableColumn;
|
||||
import com.arsdigita.bebop.table.TableModel;
|
||||
import com.arsdigita.bebop.util.BebopConstants;
|
||||
import com.arsdigita.cms.CMS;
|
||||
import com.arsdigita.cms.ContentItem;
|
||||
import com.arsdigita.cms.ContentPage;
|
||||
import com.arsdigita.cms.ContentSection;
|
||||
import com.arsdigita.cms.ContentType;
|
||||
import com.arsdigita.cms.Folder;
|
||||
import com.arsdigita.cms.SecurityManager;
|
||||
import com.arsdigita.cms.dispatcher.Utilities;
|
||||
import com.arsdigita.cms.ui.folder.FolderSelectionModel;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.persistence.CompoundFilter;
|
||||
import com.arsdigita.persistence.FilterFactory;
|
||||
import com.arsdigita.toolbox.GlobalisationUtil;
|
||||
import com.arsdigita.util.Assert;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* Browse folders and items. If the user clicks on a folder, the folder selection model is updated.
|
||||
* If the user clicks on any other item, an separate item selection model is updated.
|
||||
*
|
||||
* @author <a href="mailto:lutter@arsdigita.com">David Lutterkort</a>
|
||||
* @version $Revision: #9 $ $DateTime: 2004/08/17 23:15:09 $
|
||||
*/
|
||||
public class ItemSearchFolderBrowser extends Table {
|
||||
|
||||
private static final org.apache.log4j.Logger s_log = org.apache.log4j.Logger.getLogger(
|
||||
ItemSearchFolderBrowser.class);
|
||||
private static GlobalizedMessage[] s_headers = {
|
||||
globalize("cms.ui.folder.name"),
|
||||
globalize("cms.ui.folder.title"),
|
||||
globalize("cms.ui.folder.type")};
|
||||
private FolderSelectionModel m_currentFolder;
|
||||
private TableActionListener m_folderChanger;
|
||||
private TableActionListener m_deleter;
|
||||
private TableActionListener m_indexChanger;
|
||||
private TableColumn m_nameColumn;
|
||||
private Paginator m_paginator;
|
||||
|
||||
public ItemSearchFolderBrowser(FolderSelectionModel currentFolder) {
|
||||
super((FolderTableModelBuilder) null, s_headers);
|
||||
|
||||
FolderTableModelBuilder builder = new FolderTableModelBuilder();
|
||||
setModelBuilder(builder);
|
||||
|
||||
m_paginator = new Paginator(builder, ContentSection.getConfig().
|
||||
getFolderBrowseListSize());
|
||||
|
||||
m_currentFolder = currentFolder;
|
||||
|
||||
setClassAttr("dataTable");
|
||||
|
||||
getHeader().setDefaultRenderer(
|
||||
new com.arsdigita.cms.ui.util.DefaultTableCellRenderer());
|
||||
m_nameColumn = getColumn(0);
|
||||
m_nameColumn.setCellRenderer(new NameCellRenderer());
|
||||
|
||||
m_folderChanger = new FolderChanger();
|
||||
addTableActionListener(m_folderChanger);
|
||||
|
||||
setEmptyView(new Label(globalize("cms.ui.folder.no_items")));
|
||||
|
||||
Assert.exists(m_currentFolder.getStateParameter());
|
||||
}
|
||||
|
||||
public Paginator getPaginator() {
|
||||
return m_paginator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Page p) {
|
||||
super.register(p);
|
||||
p.addComponentStateParam(this, m_currentFolder.getStateParameter());
|
||||
|
||||
p.addActionListener(new ActionListener() {
|
||||
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
// MP: This action listener should only be called when the
|
||||
// folder browser is visible.
|
||||
showHideFolderActions(event.getPageState());
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private Folder getCurrentFolder(PageState state) {
|
||||
return (Folder) m_currentFolder.getSelectedObject(state);
|
||||
}
|
||||
|
||||
private void showHideFolderActions(PageState state) {
|
||||
SecurityManager sm = Utilities.getSecurityManager(state);
|
||||
Folder folder = getCurrentFolder(state);
|
||||
Assert.exists(folder);
|
||||
}
|
||||
|
||||
public FolderSelectionModel getFolderSelectionModel() {
|
||||
return m_currentFolder;
|
||||
}
|
||||
|
||||
private class FolderTableModelBuilder
|
||||
extends AbstractTableModelBuilder implements PaginationModelBuilder {
|
||||
|
||||
private RequestLocal m_size = new RequestLocal() {
|
||||
|
||||
@Override
|
||||
protected Object initialValue(PageState state) {
|
||||
Folder.ItemCollection itemColl = getItemCollection(state);
|
||||
|
||||
if (null == itemColl) {
|
||||
return new Integer(0);
|
||||
}
|
||||
return new Integer((int) itemColl.size());
|
||||
}
|
||||
|
||||
};
|
||||
private RequestLocal m_itemColl = new RequestLocal() {
|
||||
|
||||
@Override
|
||||
protected Object initialValue(PageState state) {
|
||||
Folder.ItemCollection itemColl = getItemCollection(state);
|
||||
|
||||
itemColl.addOrder("item.name");
|
||||
itemColl.setRange(new Integer(m_paginator.getFirst(state)),
|
||||
new Integer(m_paginator.getLast(state) + 1));
|
||||
|
||||
return itemColl;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public TableModel makeModel(Table t, PageState s) {
|
||||
FolderSelectionModel sel = ((ItemSearchFolderBrowser) t).
|
||||
getFolderSelectionModel();
|
||||
Folder f = getCurrentFolder(s);
|
||||
|
||||
if (s_log.isDebugEnabled()) {
|
||||
if (null == f) {
|
||||
s_log.debug("Selected folder is null");
|
||||
} else {
|
||||
s_log.debug("Selected folder: " + f.getLabel() + " " + f.
|
||||
getOID().toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (f == null) {
|
||||
return Table.EMPTY_MODEL;
|
||||
} else {
|
||||
t.getRowSelectionModel().clearSelection(s);
|
||||
return new FolderTableModel((Folder.ItemCollection) m_itemColl.
|
||||
get(s));
|
||||
}
|
||||
}
|
||||
|
||||
private Folder.ItemCollection getItemCollection(PageState state) {
|
||||
Folder f = getCurrentFolder(state);
|
||||
Folder.ItemCollection itemColl = f.getPrimaryInstances();
|
||||
|
||||
if (null == itemColl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BigDecimal singleTypeID = (BigDecimal) state.getValue(new BigDecimalParameter(
|
||||
ItemSearch.SINGLE_TYPE_PARAM));
|
||||
|
||||
if (singleTypeID != null) {
|
||||
|
||||
// The Filter Factory
|
||||
FilterFactory ff = itemColl.getFilterFactory();
|
||||
|
||||
// Create an or-filter
|
||||
CompoundFilter or = ff.or();
|
||||
|
||||
// The content type must be either of the requested type
|
||||
or.addFilter(ff.equals(ContentItem.CONTENT_TYPE + "."
|
||||
+ ContentType.ID, singleTypeID));
|
||||
|
||||
// Or must be a sibling of the requested type
|
||||
/*
|
||||
* jensp 2011-11-14: The orginal code here was only traversing
|
||||
* one level, but ContentType hierarchies may have several
|
||||
* levels. Therefore, this code was replaced by method which is
|
||||
* called recursivly until the type with no descendents is
|
||||
* reached.
|
||||
*/
|
||||
createSiblingFilter(or, ff, singleTypeID);
|
||||
/*try {
|
||||
ContentType ct = new ContentType(singleTypeID);
|
||||
|
||||
StringTokenizer strTok = new StringTokenizer(ct.
|
||||
getDescendants(), "/");
|
||||
while (strTok.hasMoreElements()) {
|
||||
or.addFilter(ff.equals(ContentItem.CONTENT_TYPE + "."
|
||||
+ ContentType.ID,
|
||||
(String) strTok.nextElement()));
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// WTF? The selected content type does not exist in the table???
|
||||
s_log.error(String.format(
|
||||
"Something is very wrong here, the ContentType '%s' "
|
||||
+ "seems not to exist. Ignoring for now, but please "
|
||||
+ "make your checks.",
|
||||
singleTypeID.toString()),
|
||||
ex);
|
||||
}*/
|
||||
|
||||
itemColl.addFilter(or);
|
||||
|
||||
}
|
||||
|
||||
itemColl.addOrder("isFolder desc");
|
||||
itemColl.addOrder("lower(item." + ContentItem.NAME + ") ");
|
||||
return itemColl;
|
||||
}
|
||||
|
||||
private void createSiblingFilter(final CompoundFilter filter,
|
||||
final FilterFactory filterFactory,
|
||||
final BigDecimal typeId) {
|
||||
final ContentType type = new ContentType(typeId);
|
||||
if ((type.getDescendants() == null)
|
||||
|| type.getDescendants().trim().isEmpty()) {
|
||||
return;
|
||||
} else {
|
||||
final String[] descendantsIds = type.getDescendants().split("/");
|
||||
|
||||
for (String descendantId : descendantsIds) {
|
||||
filter.addFilter(filterFactory.equals(String.format(
|
||||
ContentItem.CONTENT_TYPE + "." + ContentType.ID),
|
||||
descendantId));
|
||||
createSiblingFilter(filter, filterFactory, descendantId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createSiblingFilter(final CompoundFilter filter,
|
||||
final FilterFactory filterFactory,
|
||||
final String typeId) {
|
||||
try {
|
||||
final BigDecimal _typeId = new BigDecimal(typeId);
|
||||
createSiblingFilter(filter, filterFactory, _typeId);
|
||||
} catch (NumberFormatException ex) {
|
||||
s_log.error(String.format("Failed to parse typeId '%s'.",
|
||||
typeId),
|
||||
ex);
|
||||
}
|
||||
}
|
||||
|
||||
public int getTotalSize(Paginator paginator, PageState state) {
|
||||
|
||||
Integer size = (Integer) m_size.get(state);
|
||||
return size.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the paginator should be visible, based on the visibility of the folder
|
||||
* browser itself and how many items are displayed
|
||||
*
|
||||
* @return true if folder browser is visible and there is more than 1 page of items, false
|
||||
* otherwise
|
||||
*/
|
||||
public boolean isVisible(PageState state) {
|
||||
int size = ((Integer) m_size.get(state)).intValue();
|
||||
|
||||
return ItemSearchFolderBrowser.this.isVisible(state)
|
||||
&& (size
|
||||
> ContentSection.getConfig().getFolderBrowseListSize());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce links to view an item or control links for folders to change into the folder.
|
||||
*/
|
||||
private class NameCellRenderer extends DefaultTableCellRenderer {
|
||||
|
||||
public NameCellRenderer() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getComponent(Table table, PageState state,
|
||||
Object value, boolean isSelected,
|
||||
Object key, int row, int column) {
|
||||
Folder.ItemCollection coll = (Folder.ItemCollection) value;
|
||||
String name = coll.getName();
|
||||
if (coll.isFolder()) {
|
||||
return super.getComponent(table, state, name, isSelected, key,
|
||||
row, column);
|
||||
} else {
|
||||
ContentSection section = CMS.getContext().getContentSection();
|
||||
BigDecimal id = (BigDecimal) key;
|
||||
|
||||
if (section == null) {
|
||||
return new Label(name);
|
||||
} else {
|
||||
//ItemResolver resolver = section.getItemResolver();
|
||||
|
||||
//String url =
|
||||
//resolver.generateItemURL
|
||||
//(state, id, name, section, coll.getVersion()));
|
||||
SimpleContainer container = new SimpleContainer();
|
||||
|
||||
String widget = (String) state.getValue(new StringParameter(
|
||||
ItemSearchPopup.WIDGET_PARAM));
|
||||
String searchWidget = (String) state.getValue(
|
||||
new StringParameter("searchWidget"));
|
||||
boolean useURL = "true".equals(state.getValue(new StringParameter(
|
||||
ItemSearchPopup.URL_PARAM)));
|
||||
|
||||
String fillString;
|
||||
if (useURL) {
|
||||
fillString = ItemSearchPopup.getItemURL(state.getRequest(),
|
||||
coll.getDomainObject().getOID());
|
||||
} else {
|
||||
fillString = id.toString();// + " (" + name + ")";
|
||||
}
|
||||
|
||||
String title = ((ContentPage) coll.getDomainObject()).getTitle();
|
||||
|
||||
Label js = new Label(
|
||||
generateJSLabel(id, widget, searchWidget, fillString, title),
|
||||
false);
|
||||
container.add(js);
|
||||
|
||||
String url = "#";
|
||||
|
||||
Link link = new Link(name, url);
|
||||
link.setClassAttr("title");
|
||||
link.setOnClick("return fillItem" + id + "()");
|
||||
|
||||
container.add(link);
|
||||
|
||||
return container;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String generateJSLabel(BigDecimal id, String widget, String searchWidget,
|
||||
String fill, String title) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append(" <script language=javascript> ");
|
||||
buffer.append(" <!-- \n");
|
||||
buffer.append(" function fillItem").append(id).append("() { \n");
|
||||
buffer.append(" window.opener.document.").append(widget).append(".value=\"").
|
||||
append(fill).append("\";\n");
|
||||
if (searchWidget != null) {
|
||||
buffer.append(" window.opener.document.").append(searchWidget).append(".value=\"").
|
||||
append(title.
|
||||
replace("\"", "\\\"")).append("\";\n");
|
||||
}
|
||||
// set protocol to 'other' in FCKEditor, else relative url prepended by http://
|
||||
if (Bebop.getConfig().getDHTMLEditor().equals(
|
||||
BebopConstants.BEBOP_FCKEDITOR)) {
|
||||
buffer.append(
|
||||
" if(window.opener.document.getElementById('cmbLinkProtocol')) {\n");
|
||||
buffer.append(
|
||||
" window.opener.document.getElementById('cmbLinkProtocol').value=\"\";\n");
|
||||
buffer.append(" }\n");
|
||||
}
|
||||
|
||||
buffer.append(" self.close(); \n"
|
||||
+ " return false; \n"
|
||||
+ " } \n"
|
||||
+ " --> \n"
|
||||
+ " </script> ");
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Table model around ItemCollection
|
||||
*/
|
||||
private static class FolderTableModel implements TableModel {
|
||||
|
||||
private static final int NAME = 0;
|
||||
private static final int TITLE = 1;
|
||||
private static final int TYPE = 2;
|
||||
private Folder.ItemCollection m_itemColl;
|
||||
|
||||
public FolderTableModel(Folder.ItemCollection itemColl) {
|
||||
m_itemColl = itemColl;
|
||||
}
|
||||
|
||||
public int getColumnCount() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
public boolean nextRow() {
|
||||
return m_itemColl != null ? m_itemColl.next() : false;
|
||||
}
|
||||
|
||||
public Object getElementAt(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case NAME:
|
||||
return m_itemColl;
|
||||
case TITLE:
|
||||
return m_itemColl.getDisplayName();
|
||||
case TYPE:
|
||||
return m_itemColl.getTypeLabel();
|
||||
default:
|
||||
throw new IndexOutOfBoundsException("Column index "
|
||||
+ columnIndex
|
||||
+ " not in table model.");
|
||||
}
|
||||
}
|
||||
|
||||
public Object getKeyAt(int columnIndex) {
|
||||
// Mark folders by using their negative ID (dirty, dirty)
|
||||
return (m_itemColl.isFolder()) ? m_itemColl.getID().negate()
|
||||
: m_itemColl.getID();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class FolderChanger extends TableActionAdapter {
|
||||
|
||||
@Override
|
||||
public void cellSelected(TableActionEvent e) {
|
||||
PageState s = e.getPageState();
|
||||
int col = e.getColumn().intValue();
|
||||
|
||||
if (m_nameColumn != getColumn(col)) {
|
||||
return;
|
||||
}
|
||||
String key = (String) e.getRowKey();
|
||||
if (key.startsWith("-")) {
|
||||
clearSelection(s);
|
||||
getFolderSelectionModel().setSelectedKey(s, key.substring(1));
|
||||
m_paginator.reset(s);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Getting the GlobalizedMessage using a CMS Class targetBundle.
|
||||
*
|
||||
* @param key The resource key
|
||||
*
|
||||
* @pre ( key != null )
|
||||
*/
|
||||
private static GlobalizedMessage globalize(String key) {
|
||||
//return FolderManipulator.globalize(key);
|
||||
final GlobalisationUtil util = new GlobalisationUtil(
|
||||
"com.arsdigita.cms."
|
||||
+ "ui.folder.CMSFolderResources");
|
||||
return util.globalize(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -28,15 +28,12 @@ import com.arsdigita.bebop.parameters.BigDecimalParameter;
|
|||
import com.arsdigita.bebop.parameters.BooleanParameter;
|
||||
import com.arsdigita.bebop.parameters.IntegerParameter;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.cms.*;
|
||||
import com.arsdigita.cms.dispatcher.CMSPage;
|
||||
import com.arsdigita.cms.util.GlobalizationUtil;
|
||||
import com.arsdigita.dispatcher.RequestContext;
|
||||
import com.arsdigita.domain.DataObjectNotFoundException;
|
||||
import com.arsdigita.templating.PresentationManager;
|
||||
import com.arsdigita.templating.Templating;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
import com.arsdigita.web.Application;
|
||||
import org.libreccm.web.CcmApplication;
|
||||
import com.arsdigita.web.Web;
|
||||
import com.arsdigita.xml.Document;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.bebop.Container;
|
||||
import com.arsdigita.bebop.Resettable;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.FormSection;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.event.FormProcessListener;
|
||||
import com.arsdigita.bebop.event.FormSectionEvent;
|
||||
import com.arsdigita.bebop.parameters.BigDecimalParameter;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentType;
|
||||
import com.arsdigita.cms.ui.search.ItemQueryComponent;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
|
||||
import com.arsdigita.search.ui.ResultsPane;
|
||||
import com.arsdigita.search.ui.QueryGenerator;
|
||||
import com.arsdigita.toolbox.ui.LayoutPanel;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.librecms.CmsConstants;
|
||||
|
||||
/**
|
||||
* Contains a form for specifying search parameters, as well as a
|
||||
* {@link com.arsdigita.search.ui.ResultsPane} which will perform the search and
|
||||
* display the results
|
||||
*
|
||||
* @author Stanislav Freidin (sfreidin@arsdigita.com)
|
||||
* @version $Id: ItemSearchSection.java 1940 2009-05-29 07:15:05Z terry $
|
||||
*/
|
||||
public class ItemSearchSection extends FormSection implements Resettable,
|
||||
QueryGenerator {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
ItemSearchSection.class);
|
||||
public static final String SINGLE_TYPE_PARAM = "single_type";
|
||||
|
||||
private ItemQueryComponent itemQueryComponent;
|
||||
private Component resultsComponent;
|
||||
|
||||
/**
|
||||
* Construct a new <code>ItemSearchSection</code> component
|
||||
*
|
||||
* @param context the context for the retrieved items. Should be
|
||||
* {@link ContentItem#DRAFT} or {@link ContentItem#LIVE}
|
||||
* @param limitToContentSection limit the search to the current content
|
||||
* section
|
||||
*/
|
||||
public ItemSearchSection(final String context,
|
||||
final boolean limitToContentSection) {
|
||||
this(null, context, limitToContentSection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new <code>ItemSearchSection</code> component
|
||||
*
|
||||
* @param context the context for the retrieved items. Should be
|
||||
* {@link ContentItem#DRAFT} or {@link ContentItem#LIVE}
|
||||
* @param name The name of the search parameter for the particular
|
||||
* FormSection
|
||||
* @param limitToContentSection limit the search to the current content
|
||||
* section
|
||||
*/
|
||||
public ItemSearchSection(final String name,
|
||||
final String context,
|
||||
final boolean limitToContentSection) {
|
||||
this(name, context, limitToContentSection, null);
|
||||
}
|
||||
|
||||
public ItemSearchSection(final String name,
|
||||
final String context,
|
||||
final boolean limitToContentSection,
|
||||
final ContentType type) {
|
||||
super(new SimpleContainer());
|
||||
final String thisName;
|
||||
if (name == null) {
|
||||
thisName = "itemSearch";
|
||||
} else {
|
||||
thisName = name;
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
itemQueryComponent = createQueryGenerator(context,
|
||||
limitToContentSection);
|
||||
} else {
|
||||
itemQueryComponent = createQueryGenerator(context,
|
||||
limitToContentSection,
|
||||
type);
|
||||
}
|
||||
resultsComponent = createResultsPane(itemQueryComponent);
|
||||
|
||||
LayoutPanel searchPanel = new LayoutPanel();
|
||||
searchPanel.setLeft(itemQueryComponent);
|
||||
searchPanel.setBody(resultsComponent);
|
||||
this.add(searchPanel);
|
||||
|
||||
// addQueryGenerator(this);
|
||||
// addResultsPane(this);
|
||||
addFormListener();
|
||||
|
||||
setClassAttr("itemSearch");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasQuery(final PageState state) {
|
||||
return itemQueryComponent.hasQuery(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query getQuerySpecification(final PageState state) {
|
||||
return itemQueryComponent.getQuerySpecification(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(final PageState state) {
|
||||
resultsComponent.setVisible(state, false);
|
||||
}
|
||||
|
||||
protected ItemQueryComponent createQueryGenerator(
|
||||
final String context, final boolean limitToContentSection) {
|
||||
return new ItemQueryComponent(context, limitToContentSection);
|
||||
}
|
||||
|
||||
protected ItemQueryComponent createQueryGenerator(
|
||||
final String context,
|
||||
final boolean limitToContentSection,
|
||||
final ContentType type) {
|
||||
|
||||
return new ItemQueryComponent(context, limitToContentSection, type);
|
||||
}
|
||||
|
||||
protected Component createResultsPane(QueryGenerator generator) {
|
||||
ResultsPane pane = new ResultsPane(generator);
|
||||
pane.setRelativeURLs(true);
|
||||
pane.setSearchHelpMsg(new GlobalizedMessage("cms.ui.search.help",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
pane.setNoResultsMsg(new GlobalizedMessage("cms.ui.search.no_results",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
return pane;
|
||||
}
|
||||
|
||||
protected void addResultsPane(final Container container) {
|
||||
container.add(resultsComponent);
|
||||
}
|
||||
|
||||
protected void addQueryGenerator(final Container container) {
|
||||
container.add(itemQueryComponent);
|
||||
}
|
||||
|
||||
protected void processQuery(final PageState state) {
|
||||
resultsComponent.setVisible(state, itemQueryComponent.hasQuery(state));
|
||||
}
|
||||
|
||||
protected void addFormListener() {
|
||||
addProcessListener(new SearchFormProcessListener());
|
||||
}
|
||||
|
||||
// Hide results by default
|
||||
@Override
|
||||
public void register(final Page page) {
|
||||
super.register(page);
|
||||
page.setVisibleDefault(resultsComponent, false);
|
||||
page.addGlobalStateParam(new BigDecimalParameter(SINGLE_TYPE_PARAM));
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the "keywords" and "content types" widgets
|
||||
*/
|
||||
private class SearchFormProcessListener implements FormProcessListener {
|
||||
|
||||
@Override
|
||||
public void process(final FormSectionEvent event)
|
||||
throws FormProcessException {
|
||||
|
||||
PageState s = event.getPageState();
|
||||
processQuery(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui.search;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.form.Submit;
|
||||
import org.libreccm.categorization.Category;
|
||||
import com.arsdigita.cms.CMS;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.contentsection.ContentType;
|
||||
import com.arsdigita.cms.ui.ContentSectionPage;
|
||||
import com.arsdigita.search.ui.BaseQueryComponent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class provides a basic query form for CMS admin pages that automatically
|
||||
* adds components for the maximal set of filters supported by the current
|
||||
* search query engine.
|
||||
*
|
||||
* @author unknown
|
||||
* @author Sören Bernstein <quasi@quasiweb.de>
|
||||
* @author Jens Pelzetter (jens@jp-digital.de)
|
||||
*/
|
||||
public class ItemQueryComponent extends BaseQueryComponent {
|
||||
|
||||
private String context;
|
||||
|
||||
public ItemQueryComponent(final String context,
|
||||
final boolean limitToContentSection) {
|
||||
this(context, limitToContentSection, null);
|
||||
}
|
||||
|
||||
public ItemQueryComponent(final String context,
|
||||
final boolean limitToContentSection,
|
||||
final ContentType type) {
|
||||
this.context = context;
|
||||
|
||||
// add(new PermissionFilterComponent(
|
||||
// SecurityManager.CMS_PREVIEW_ITEM));
|
||||
//
|
||||
// add(new SimpleCategoryFilterWidget() {
|
||||
//
|
||||
// @Override
|
||||
// protected Category[] getRoots(PageState state) {
|
||||
// Category[] roots;
|
||||
// if (limitToContentSection == true && CMS.getContext().
|
||||
// hasContentSection()) {
|
||||
// ContentSection section = CMS.getContext().
|
||||
// getContentSection();
|
||||
// roots = new Category[]{section.getRootCategory()};
|
||||
// } else {
|
||||
// ContentSectionCollection sections =
|
||||
// ContentSection.getAllSections();
|
||||
// List cats = new ArrayList();
|
||||
// while (sections.next()) {
|
||||
// ContentSection section =
|
||||
// sections.getContentSection();
|
||||
// cats.add(section.getRootCategory());
|
||||
// }
|
||||
// roots =
|
||||
// (Category[]) cats.toArray(new Category[cats.size()]);
|
||||
// }
|
||||
// return roots;
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// if (type == null) {
|
||||
// add(new ContentTypeFilterWidget() {
|
||||
//
|
||||
// @Override
|
||||
// protected ContentSection getContentSection() {
|
||||
// if (limitToContentSection == true && CMS.getContext().
|
||||
// hasContentSection()) {
|
||||
// return CMS.getContext().getContentSection();
|
||||
// } else {
|
||||
// return super.getContentSection();
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// add(new ContentTypeFilterWidget(type) {
|
||||
//
|
||||
// @Override
|
||||
// protected ContentSection getContentSection() {
|
||||
// if (limitToContentSection == true && CMS.getContext().
|
||||
// hasContentSection()) {
|
||||
// return CMS.getContext().getContentSection();
|
||||
// } else {
|
||||
// return super.getContentSection();
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// add(new VersionFilterComponent(context));
|
||||
// if (limitToContentSection == true) {
|
||||
// add(new ContentSectionFilterComponent());
|
||||
// }
|
||||
// add(new DateRangeFilterWidget(new LastModifiedDateFilterType(),
|
||||
// LastModifiedDateFilterType.KEY));
|
||||
// add(new DateRangeFilterWidget(new CreationDateFilterType(),
|
||||
// CreationDateFilterType.KEY));
|
||||
// add(new PartyFilterWidget(new CreationUserFilterType(),
|
||||
// CreationUserFilterType.KEY));
|
||||
// add(new PartyFilterWidget(new LastModifiedUserFilterType(),
|
||||
// LastModifiedUserFilterType.KEY));
|
||||
|
||||
|
||||
Submit submit =
|
||||
new Submit(context + "_search",
|
||||
ContentSectionPage.globalize("cms.ui.search"));
|
||||
add(submit);
|
||||
}
|
||||
|
||||
// private class LaunchDateFilterWidget extends DateRangeFilterWidget {
|
||||
//
|
||||
// public LaunchDateFilterWidget(FilterType type, String name) {
|
||||
// super(type, name);
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean isVisible(PageState state) {
|
||||
// return !ContentSection.getConfig().getHideLaunchDate()
|
||||
// && super.isVisible(state);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (C) 2016 LibreCCM Foundation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
package com.arsdigita.search;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public final class SearchConstants {
|
||||
|
||||
private SearchConstants() {
|
||||
//Nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Constant for search XML namespace prefix
|
||||
*/
|
||||
public static final String XML_PREFIX = "search:";
|
||||
/**
|
||||
* Constant for search XML namespace URL
|
||||
*/
|
||||
public static final String XML_NS = "http://rhea.redhat.com/search/1.0";
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.search.ui;
|
||||
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.FormModel;
|
||||
import com.arsdigita.bebop.FormData;
|
||||
import com.arsdigita.bebop.parameters.ParameterData;
|
||||
import com.arsdigita.globalization.Globalization;
|
||||
import com.arsdigita.xml.Element;
|
||||
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.search.SearchConstants;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* This is a simple extension of the QueryComponent that provides management of
|
||||
* the 'terms' parameter and uses FilterGenerators to populate a query
|
||||
* specification
|
||||
* <p>
|
||||
* Typical use would be as follows:
|
||||
* <pre>
|
||||
* Form f = new Form("search");
|
||||
* BaseQueryComponent q = new BaseQueryComponent();
|
||||
* q.add(new ObjectTypeFilterComponent("com.arsdigita.kernel.User");
|
||||
* q.add(new PermissionGenerator(PrivilegeDescriptor.READ));
|
||||
* q.add(new Submit("Go"));
|
||||
* f.add(q);
|
||||
* </pre>
|
||||
*/
|
||||
public class BaseQueryComponent extends QueryComponent {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
BaseQueryComponent.class);
|
||||
|
||||
private Set filters;
|
||||
private Form form;
|
||||
private StringParameter termsParameter = new StringParameter("terms");
|
||||
|
||||
/**
|
||||
* Creates a new query component
|
||||
*/
|
||||
public BaseQueryComponent() {
|
||||
super("query");
|
||||
filters = new HashSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(final Page page) {
|
||||
super.register(page);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(final Form form, final FormModel formModel) {
|
||||
LOGGER.debug("Adding {} to form model...", termsParameter.getName());
|
||||
|
||||
termsParameter.setPassIn(true);
|
||||
formModel.addFormParam(termsParameter);
|
||||
this.form = form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current search terms
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected String getTerms(final PageState state) {
|
||||
final FormData formData = form.getFormData(state);
|
||||
|
||||
if (formData != null) {
|
||||
final ParameterData data = formData.getParameter(termsParameter.
|
||||
getName());
|
||||
LOGGER.debug("Search terms were: {}", (String) data.getValue());
|
||||
|
||||
return (String) data.getValue();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param state
|
||||
* @param parent
|
||||
*/
|
||||
@Override
|
||||
public void generateXML(final PageState state, final Element parent) {
|
||||
final Element content = generateParent(parent);
|
||||
|
||||
final Element terms = new Element(SearchConstants.XML_PREFIX + "terms",
|
||||
SearchConstants.XML_NS);
|
||||
terms.addAttribute("param", termsParameter.getName());
|
||||
terms.addAttribute("value",
|
||||
Globalization.decodeParameter(
|
||||
state.getRequest(),
|
||||
termsParameter.getName()));
|
||||
generateErrorXML(state, terms);
|
||||
content.addContent(terms);
|
||||
|
||||
generateChildrenXML(state, content);
|
||||
}
|
||||
|
||||
protected void generateErrorXML(final PageState state,
|
||||
final Element parent) {
|
||||
final FormData formData = form.getFormData(state);
|
||||
if (formData == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Iterator iterator = formData.getErrors(termsParameter.getName());
|
||||
while (iterator.hasNext()) {
|
||||
final Element error = new Element(
|
||||
SearchConstants.XML_PREFIX + "error",
|
||||
SearchConstants.XML_NS);
|
||||
error.setText((String) ((GlobalizedMessage) iterator.next()).
|
||||
localize(state.getRequest())
|
||||
);
|
||||
parent.addContent(error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.search.ui;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.search.SearchConstants;
|
||||
|
||||
import com.arsdigita.util.Assert;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.hibernate.search.query.dsl.QueryBuilder;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.CcmObject;
|
||||
import org.libreccm.search.SearchManager;
|
||||
|
||||
/**
|
||||
* A base class for generating a query specification from the state. Subclasses
|
||||
* must implement two methods, one for getting the query terms, the other for
|
||||
* getting a set of filter specs.
|
||||
*/
|
||||
public abstract class QueryComponent extends SimpleContainer
|
||||
implements QueryGenerator {
|
||||
|
||||
public QueryComponent(final String name) {
|
||||
setTag(SearchConstants.XML_PREFIX + name);
|
||||
setNamespace(SearchConstants.XML_NS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a query specification is available
|
||||
*
|
||||
* @return true if the user has entered some search terms
|
||||
*/
|
||||
@Override
|
||||
public boolean hasQuery(final PageState state) {
|
||||
String terms = getTerms(state);
|
||||
|
||||
return (terms != null && !"".equals(terms));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current query specification
|
||||
*/
|
||||
@Override
|
||||
public Query getQuerySpecification(final PageState state) {
|
||||
final String terms = getTerms(state);
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final SearchManager searchManager = cdiUtil.
|
||||
findBean(SearchManager.class);
|
||||
|
||||
final QueryBuilder queryBuilder = searchManager.createQueryBuilder(CcmObject.class);
|
||||
|
||||
return queryBuilder
|
||||
.keyword().onFields("displayName", "summary", "description", "title")
|
||||
.matching(terms)
|
||||
.createQuery();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current query terms
|
||||
*
|
||||
* @param state
|
||||
* @return the query terms, or null
|
||||
*/
|
||||
protected abstract String getTerms(PageState state);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.search.ui;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import org.apache.lucene.search.Query;
|
||||
|
||||
/**
|
||||
* This interface provides the API for retrieving a query specification based on
|
||||
* the current state. The ResultsPane component uses an instance of this class
|
||||
* to retrieve the query spec and display a list of results
|
||||
*
|
||||
* @see com.arsdigita.search.ui.QueryComponent
|
||||
* @see com.arsdigita.search.ui.ResultsPane
|
||||
*/
|
||||
public interface QueryGenerator {
|
||||
|
||||
/**
|
||||
* Determines whether a query spec currently exists.
|
||||
*
|
||||
* @param state The current page state.
|
||||
* @return true if a query spec is available.
|
||||
*/
|
||||
boolean hasQuery(PageState state);
|
||||
|
||||
/**
|
||||
* Retrieves the current query spec. This method can only be called if
|
||||
* hasQuery(state) returns true.
|
||||
*
|
||||
* @param state The current page.
|
||||
* @return The query
|
||||
*/
|
||||
Query getQuerySpecification(PageState state);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,381 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.search.ui;
|
||||
|
||||
import com.arsdigita.bebop.SimpleComponent;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.parameters.IntegerParameter;
|
||||
import com.arsdigita.globalization.Globalization;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.search.SearchConstants;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import org.libreccm.security.Party;
|
||||
import com.arsdigita.xml.Element;
|
||||
import com.arsdigita.xml.XML;
|
||||
|
||||
import com.arsdigita.web.URL;
|
||||
import com.arsdigita.web.ParameterMap;
|
||||
import com.arsdigita.web.Web;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.logging.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.CcmObject;
|
||||
import org.libreccm.search.SearchManager;
|
||||
|
||||
public class ResultsPane extends SimpleComponent {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(ResultsPane.class);
|
||||
public static final int PAGE_SIZE = 10;
|
||||
|
||||
private final int pageSize = PAGE_SIZE;
|
||||
|
||||
private final QueryGenerator queryGenerator;
|
||||
private IntegerParameter pageNumber;
|
||||
private boolean relative;
|
||||
//jensp 2014-03-04 Allow using classes to set a suitable info messages.
|
||||
private GlobalizedMessage searchHelpMsg;
|
||||
private GlobalizedMessage noResultsMsg;
|
||||
|
||||
public ResultsPane(final QueryGenerator query) {
|
||||
pageNumber = new IntegerParameter("page");
|
||||
relative = false;
|
||||
this.queryGenerator = query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the links to the search results will be relative or
|
||||
* absolute. The default is absolute.
|
||||
*
|
||||
* @param relative
|
||||
*/
|
||||
public void setRelativeURLs(final boolean relative) {
|
||||
this.relative = relative;
|
||||
}
|
||||
|
||||
public void setSearchHelpMsg(final GlobalizedMessage msg) {
|
||||
searchHelpMsg = msg;
|
||||
}
|
||||
|
||||
public void setNoResultsMsg(final GlobalizedMessage msg) {
|
||||
noResultsMsg = msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateXML(final PageState state, final Element parent) {
|
||||
if (!queryGenerator.hasQuery(state)) {
|
||||
|
||||
LOGGER.debug("No query available, skipping XML generation");
|
||||
|
||||
final Element content = new Element(
|
||||
SearchConstants.XML_PREFIX + "results",
|
||||
SearchConstants.XML_NS);
|
||||
final Element info = content.newChildElement("info");
|
||||
if (searchHelpMsg == null) {
|
||||
info.setText(
|
||||
"To search for content items, please enter at least 3 letters into the search field. You can narrow the result by using additional parameters.");
|
||||
} else {
|
||||
//info.setText(GlobalizationUtil.globalize("cms.ui.search_help").localize().toString());
|
||||
info.setText(searchHelpMsg.localize().toString());
|
||||
}
|
||||
|
||||
parent.addContent(content);
|
||||
return;
|
||||
}
|
||||
|
||||
final Query spec = queryGenerator.getQuerySpecification(state);
|
||||
final SearchManager searchManager = CdiUtil.createCdiUtil().findBean(
|
||||
SearchManager.class);
|
||||
final List<CcmObject> results = (List<CcmObject>) searchManager.
|
||||
executeQuery(spec);
|
||||
LOGGER.debug("Got result list with {} items.", results.size());
|
||||
if (results.isEmpty()) {
|
||||
final long objectCount = results.size();
|
||||
final int pageCount = (int) Math.ceil((double) objectCount
|
||||
/ (double) pageSize);
|
||||
|
||||
final Integer page = (Integer) pageNumber.transformValue(state.
|
||||
getRequest());
|
||||
int pageNum;
|
||||
if (page == null) {
|
||||
pageNum = 1;
|
||||
} else if (page < 1) {
|
||||
pageNum = 1;
|
||||
} else if (page > pageCount) {
|
||||
if (pageCount == 0) {
|
||||
pageNum = 1;
|
||||
} else {
|
||||
pageNum = page;
|
||||
}
|
||||
} else {
|
||||
pageNum = page;
|
||||
}
|
||||
|
||||
final long begin = ((pageNum - 1) * pageSize);
|
||||
final long count = Math.min(pageSize, (objectCount - begin));
|
||||
final long end = begin + count;
|
||||
|
||||
final Iterator iterator = results
|
||||
.subList((int) begin, (int) begin + (int) count)
|
||||
.iterator();
|
||||
|
||||
final Element content = new Element(
|
||||
SearchConstants.XML_PREFIX + "results",
|
||||
SearchConstants.XML_NS);
|
||||
exportAttributes(content);
|
||||
|
||||
LOGGER.debug("Paginator stats\n"
|
||||
+ " page number: {}\n"
|
||||
+ " page count.: {}\n"
|
||||
+ " page size..: {}\n"
|
||||
+ " begin......: {}\n"
|
||||
+ " end........: {}\n"
|
||||
+ " count : {}",
|
||||
pageNum,
|
||||
pageCount,
|
||||
pageSize,
|
||||
begin,
|
||||
end,
|
||||
objectCount);
|
||||
|
||||
content.addContent(generatePaginatorXML(state,
|
||||
pageNumber.getName(),
|
||||
pageNum,
|
||||
pageCount,
|
||||
pageSize,
|
||||
begin,
|
||||
end,
|
||||
objectCount));
|
||||
content.addContent(generateDocumentsXML(state, iterator));
|
||||
|
||||
parent.addContent(content);
|
||||
} else {
|
||||
// No search result, so we don't need a paginator, but we want
|
||||
// to inform the user, that there are no results for this search
|
||||
final Element content = new Element(
|
||||
SearchConstants.XML_PREFIX + "results",
|
||||
SearchConstants.XML_NS);
|
||||
final Element info = content.newChildElement("info");
|
||||
// info.setText(GlobalizationUtil.globalize("cms.ui.search_no_results").localize().toString());
|
||||
if (noResultsMsg == null) {
|
||||
info.setText("Sorry. Your search returned 0 results.");
|
||||
} else {
|
||||
info.setText(noResultsMsg.localize().toString());
|
||||
}
|
||||
parent.addContent(content);
|
||||
}
|
||||
}
|
||||
|
||||
protected Element generatePaginatorXML(final PageState state,
|
||||
final String pageParam,
|
||||
final int pageNumber,
|
||||
final int pageCount,
|
||||
final int pageSize,
|
||||
final long begin,
|
||||
final long end,
|
||||
final long objectCount) {
|
||||
final Element paginator = new Element(
|
||||
SearchConstants.XML_PREFIX + "paginator",
|
||||
SearchConstants.XML_NS);
|
||||
final URL url = Web.getWebContext().getRequestURL();
|
||||
|
||||
final ParameterMap parameterMap = new ParameterMap();
|
||||
final Iterator current = url.getParameterMap().keySet().iterator();
|
||||
while (current.hasNext()) {
|
||||
final String key = (String) current.next();
|
||||
if (key.equals(pageParam)) {
|
||||
continue;
|
||||
}
|
||||
parameterMap.setParameterValues(
|
||||
key, decodeParameters(url.getParameterValues(key), state));
|
||||
}
|
||||
|
||||
paginator.addAttribute("pageParam", this.pageNumber.getName());
|
||||
paginator.addAttribute("baseURL", URL.there(url.getPathInfo(),
|
||||
parameterMap).toString());
|
||||
paginator.addAttribute("pageNumber", XML.format(pageNumber));
|
||||
paginator.addAttribute("pageCount", XML.format(pageCount));
|
||||
paginator.addAttribute("pageSize", XML.format(pageSize));
|
||||
paginator.addAttribute("objectBegin", XML.format(begin + 1));
|
||||
paginator.addAttribute("objectEnd", XML.format(end));
|
||||
paginator.addAttribute("objectCount", XML.format(objectCount));
|
||||
|
||||
return paginator;
|
||||
}
|
||||
|
||||
private String[] decodeParameters(final String[] parameters,
|
||||
final PageState state) {
|
||||
|
||||
final String[] decoded = new String[parameters.length];
|
||||
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
decoded[i] = decodeParameter(parameters[i], state);
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
private String decodeParameter(final String parameter,
|
||||
final PageState state) {
|
||||
String re = state.getRequest().getParameter(
|
||||
Globalization.ENCODING_PARAM_NAME);
|
||||
|
||||
if ((re == null) || (re.isEmpty())) {
|
||||
re = Globalization.getDefaultCharset();
|
||||
}
|
||||
|
||||
if ((parameter == null) || (parameter.isEmpty())) {
|
||||
return parameter;
|
||||
} else if (Globalization.getDefaultCharset(state.getRequest()).
|
||||
equals(re)) {
|
||||
return parameter;
|
||||
} else {
|
||||
try {
|
||||
return new String(parameter.getBytes(Globalization.
|
||||
getDefaultCharset(
|
||||
state.getRequest())), re);
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
LOGGER.warn("Unsupported encoding.", ex);
|
||||
return parameter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Element generateDocumentsXML(final PageState state,
|
||||
final Iterator<CcmObject> results) {
|
||||
|
||||
final Element documents = new Element(
|
||||
SearchConstants.XML_PREFIX + "documents",
|
||||
SearchConstants.XML_NS);
|
||||
|
||||
LOGGER.debug("Outputting documents");
|
||||
|
||||
while (results.hasNext()) {
|
||||
final CcmObject doc = results.next();
|
||||
LOGGER.debug("Current document {} {}",
|
||||
doc.getObjectId(),
|
||||
doc.getDisplayName());
|
||||
|
||||
documents.addContent(generateDocumentXML(state, doc));
|
||||
}
|
||||
|
||||
return documents;
|
||||
}
|
||||
|
||||
private Optional<String> getSummary(final CcmObject doc) {
|
||||
final BeanInfo beanInfo;
|
||||
try {
|
||||
beanInfo = Introspector.getBeanInfo(doc.getClass());
|
||||
} catch (IntrospectionException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
|
||||
final Optional<PropertyDescriptor> propertyDesc
|
||||
= Arrays.stream(beanInfo.
|
||||
getPropertyDescriptors())
|
||||
.filter(descriptor -> {
|
||||
return "description".equals(descriptor.getName())
|
||||
|| "summary".equals(descriptor.
|
||||
getName());
|
||||
})
|
||||
.findFirst();
|
||||
|
||||
if (propertyDesc.isPresent()) {
|
||||
final Method readMethod = propertyDesc.get().getReadMethod();
|
||||
final String summary;
|
||||
try {
|
||||
summary = (String) readMethod.invoke(doc);
|
||||
} catch (IllegalAccessException
|
||||
| IllegalArgumentException
|
||||
| InvocationTargetException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
return Optional.of(summary);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
protected Element generateDocumentXML(final PageState state,
|
||||
final CcmObject doc) {
|
||||
final Element entry = new Element(SearchConstants.XML_PREFIX + "object",
|
||||
SearchConstants.XML_NS);
|
||||
|
||||
final Optional<String> summary = getSummary(doc);
|
||||
|
||||
entry.addAttribute("id", XML.format(doc.getObjectId()));
|
||||
entry.addAttribute("uuid", XML.format(doc.getUuid()));
|
||||
// entry.addAttribute("url", XML.format(relative ? url.getPath() + "?"
|
||||
// + url.getQuery()
|
||||
// : url.toString()));
|
||||
entry.addAttribute("title", XML.format(doc.getDisplayName()));
|
||||
if (summary.isPresent()) {
|
||||
entry.addAttribute("summary", XML.format(summary));
|
||||
}
|
||||
|
||||
// entry.addAttribute("locale", XML.format(doc.getLocale()));
|
||||
|
||||
// Date creationDate = doc.getCreationDate();
|
||||
// if (creationDate != null) {
|
||||
// entry.addAttribute("creationDate", XML.format(
|
||||
// creationDate.toString()));
|
||||
// }
|
||||
// Party creationParty = doc.getCreationParty();
|
||||
// if (creationParty != null) {
|
||||
// entry.addAttribute("creationParty",
|
||||
// XML.format(creationParty.getDisplayName()));
|
||||
// }
|
||||
//
|
||||
// Date lastModifiedDate = doc.getLastModifiedDate();
|
||||
// if (lastModifiedDate != null) {
|
||||
// entry.addAttribute("lastModifiedDate",
|
||||
// XML.format(lastModifiedDate));
|
||||
// }
|
||||
// Party lastModifiedParty = doc.getLastModifiedParty();
|
||||
// if (lastModifiedParty != null) {
|
||||
// entry.addAttribute("lastModifiedParty",
|
||||
// XML.format(lastModifiedParty.getDisplayName()));
|
||||
// }
|
||||
|
||||
// LOGGER.debug(
|
||||
// "about to add the contentSectionName from search index Doc to search result xml");
|
||||
// entry.addAttribute("contentSectionName", XML.format(doc.
|
||||
// getContentSection()));
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue