- Localisation for Search (ResultsPane), Ticket #1762

- Some formating


git-svn-id: https://svn.libreccm.org/ccm/trunk@2553 8810af33-2d31-482b-a856-94f89814c4df
master
jensp 2014-03-04 18:35:21 +00:00
parent ef8618fad2
commit c21769dfc8
15 changed files with 490 additions and 353 deletions

View File

@ -1068,3 +1068,5 @@ cms.ui.move.category=Move category "{0}" to
cms.ui.category.move=Move category
cms.ui.category.cantmoved=This category can't be moved
cms.ui.authoring.error_conflicts_with_this_url=There are conflicts with this URL. Specifically, there is at least one item in the same category as this item with the name (url) of
cms.ui.search.help=To search for content items, please enter at least 3 letters into the search field. You can narrow the result by using additional parameters.
cms.ui.search.no_results=Sorry. Not content items found which match your search.

View File

@ -1062,3 +1062,5 @@ cms.ui.move.category=Verschiebe Kategorie "{0}" nach
cms.ui.category.move=Kategorie verschieben
cms.ui.category.cantmoved=Diese Kategorie kann nicht verschoben werden
cms.ui.authoring.error_conflicts_with_this_url=Es gibt Konflikte mit dieser URL. Insbesondere gibt es mindestens ein Dokument in der gleichen Kategorie wie dieser mit dem Namen (URL)
cms.ui.search.help=Geben sie mindestens drei Buchstaben ein, um nach Content Items zu suchen. Sie k\u00f6nnen das Ergebnis mit weiteren Parametern einschr\u00e4nken.
cms.ui.search.no_results=Es wurden keine Content Items gefunden, die Ihren Suchparametern entsprechen

View File

@ -116,3 +116,5 @@ cms.ui.move.category=Move category "{0}" to
cms.ui.category.move=Move category
cms.ui.category.cantmoved=This category can't be moved
cms.ui.authoring.error_conflicts_with_this_url=There are conflicts with this URL. Specifically, there is at least one item in the same category as this item with the name (url) of
cms.ui.search.help=
cms.ui.search.no_results=

View File

@ -590,3 +590,5 @@ cms.ui.move.category=Move category "{0}" to
cms.ui.category.move=Move category
cms.ui.category.cantmoved=This category can't be moved
cms.ui.authoring.error_conflicts_with_this_url=There are conflicts with this URL. Specifically, there is atleast one item in the same category as this item with the name (url) of
cms.ui.search.help=
cms.ui.search.no_results=

View File

@ -22,6 +22,7 @@ import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.cms.util.GlobalizationUtil;
import com.arsdigita.persistence.OID;
import com.arsdigita.xml.Element;
@ -105,6 +106,8 @@ public class ItemSearchPopup extends ItemSearch {
public PopupResultsPane(QueryGenerator generator) {
super(generator);
setRelativeURLs(true);
setSearchHelpMsg(GlobalizationUtil.globalize("cms.ui.search.help"));
setNoResultsMsg(GlobalizationUtil.globalize("cms.ui.search.no_results"));
}
@Override

View File

@ -29,8 +29,10 @@ import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.parameters.BigDecimalParameter;
import com.arsdigita.cms.ContentItem;
import com.arsdigita.cms.ContentType;
import com.arsdigita.cms.ui.search.ItemQueryComponent;
import com.arsdigita.cms.util.GlobalizationUtil;
import com.arsdigita.search.ui.ResultsPane;
import com.arsdigita.search.ui.QueryGenerator;
@ -139,6 +141,8 @@ public class ItemSearchSection extends FormSection
protected Component createResultsPane(QueryGenerator generator) {
ResultsPane pane = new ResultsPane(generator);
pane.setRelativeURLs(true);
pane.setSearchHelpMsg(GlobalizationUtil.globalize("cms.ui.search.help"));
pane.setNoResultsMsg(GlobalizationUtil.globalize("cms.ui.search.no_results"));
return pane;
}

View File

@ -27,6 +27,7 @@ import com.arsdigita.toolbox.ui.OIDParameter;
import com.arsdigita.persistence.OID;
import com.arsdigita.cms.ContentItem;
import com.arsdigita.cms.ContentType;
import com.arsdigita.cms.util.GlobalizationUtil;
import com.arsdigita.domain.DomainObjectFactory;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.xml.Element;
@ -154,6 +155,8 @@ public class ItemSearchSectionInline extends ItemSearchSection {
public InlineResultsPane(QueryGenerator query) {
super(query);
setRelativeURLs(true);
setSearchHelpMsg(GlobalizationUtil.globalize("cms.ui.search.help"));
setNoResultsMsg(GlobalizationUtil.globalize("cms.ui.search.no_results"));
}
@Override

View File

@ -51,16 +51,16 @@ import java.util.ArrayList;
import java.util.Collection;
/**
* A form for editing subclasses of ContentItem. This is just a convenience
* class.
* A form for editing subclasses of ContentItem. This is just a convenience class.
*
* @author Stanislav Freidin (stas@arsdigita.com)
* @version $Revision: #13 $ $DateTime: 2004/08/17 23:15:09 $
**/
*
*/
public abstract class BasicItemForm extends FormSection
implements FormInitListener,
FormProcessListener,
FormValidationListener {
implements FormInitListener,
FormProcessListener,
FormValidationListener {
private static final Logger s_log = Logger.getLogger(BasicItemForm.class);
private final ItemSelectionModel m_itemModel;
@ -78,9 +78,9 @@ public abstract class BasicItemForm extends FormSection
*
*
*
* @param formName the name of this form
* @param itemModel The {@link ItemSelectionModel} which will
* be responsible for loading the current item
* @param formName the name of this form
* @param itemModel The {@link ItemSelectionModel} which will be responsible for loading the
* current item
*/
public BasicItemForm(String formName, ItemSelectionModel itemModel) {
super(new ColumnPanel(2));
@ -110,13 +110,12 @@ public abstract class BasicItemForm extends FormSection
}
/**
* Construct a new BasicItemForm with a specified number of ColumnPanels
* and without any content
* Construct a new BasicItemForm with a specified number of ColumnPanels and without any content
*
* @param formName the name of this form
* @param formName the name of this form
* @param columnPanel the columnpanel of the form
* @param itemModel The {@link ItemSelectionModel} which will
* be responsible for loading the current item
* @param itemModel The {@link ItemSelectionModel} which will be responsible for loading the
* current item
*/
public BasicItemForm(String formName,
ColumnPanel columnPanel,
@ -124,7 +123,7 @@ public abstract class BasicItemForm extends FormSection
super(columnPanel);
m_widgetSection = new FormSection(new ColumnPanel(columnPanel.getNumCols(),
true));
true));
super.add(m_widgetSection, ColumnPanel.INSERT);
m_itemModel = itemModel;
}
@ -137,7 +136,6 @@ public abstract class BasicItemForm extends FormSection
super.add(m_saveCancelSection, ColumnPanel.FULL_WIDTH | ColumnPanel.LEFT);
}
/**
* Currently, to insert javascript code the Label Widget is "abused".
*/
@ -148,17 +146,16 @@ public abstract class BasicItemForm extends FormSection
/**
* Add basic widgets to the form.
*
* Widgets added are 'title' and 'name (url)' which are part of any content
* item.
* Child classes will override this method to perform all their widget-adding
* needs but may use super() to add the basic widgets.
* Widgets added are 'title' and 'name (url)' which are part of any content item. Child classes
* will override this method to perform all their widget-adding needs but may use super() to add
* the basic widgets.
*/
protected void addWidgets() {
//add(new FormErrorDisplay(this), ColumnPanel.FULL_WIDTH | ColumnPanel.LEFT);
//add(new Label("id"));
final Hidden id = new Hidden(CONTENT_ITEM_ID);
//final TextField id = new TextField(CONTENT_ITEM_ID);
//final TextField id = new TextField(CONTENT_ITEM_ID);
add(id);
// JavaScript auto-name generation is off by default.
@ -172,7 +169,6 @@ public abstract class BasicItemForm extends FormSection
// created you don't want to subsequently change it since
// it breaks URLs & potentially overwrites the user's
// customizations.
// For some content types it is maybe useful to change the label of the
// title field to something different than 'title'.
// This can nowbe done by overwriting the getTitleLabel() method.
@ -184,8 +180,8 @@ public abstract class BasicItemForm extends FormSection
+ " defaulting = true; this.form." + NAME
+ ".value = urlize(this.value); }");
titleWidget.setOnKeyUp(
"if (defaulting) { this.form." + NAME
+ ".value = urlize(this.value) }");
"if (defaulting) { this.form." + NAME
+ ".value = urlize(this.value) }");
titleWidget.setLabel(getTitleLabel());
titleWidget.setHint(getTitleHint());
add(titleWidget);
@ -200,9 +196,9 @@ public abstract class BasicItemForm extends FormSection
nameWidget.setMaxLength(190);
nameWidget.setOnFocus("defaulting = false");
nameWidget.setOnBlur(
"if (this.value == '') "
+ "{ defaulting = true; this.value = urlize(this.form." + TITLE
+ ".value) } " + " else { this.value = urlize(this.value); }");
"if (this.value == '') "
+ "{ defaulting = true; this.value = urlize(this.form." + TITLE
+ ".value) } " + " else { this.value = urlize(this.value); }");
nameWidget.addValidationListener(new NotNullValidationListener());
nameWidget.setHint(getNameHint());
add(nameWidget);
@ -230,25 +226,28 @@ public abstract class BasicItemForm extends FormSection
}
/**
* Perform form initialization. Children should override this
* this method to pre-fill the widgets with data, instantiate
* the content item, etc.
* Perform form initialization. Children should override this this method to pre-fill the
* widgets with data, instantiate the content item, etc.
*
* @param e
*
* @throws FormProcessException
*/
public abstract void init(FormSectionEvent e) throws FormProcessException;
/**
* Process the form. Children should override this method to save
* the user's changes to the database.
* Process the form. Children should override this method to save the user's changes to the
* database.
*
* @param e
*
* @throws FormProcessException
*/
public abstract void process(FormSectionEvent e) throws FormProcessException;
/**
* Validate the form. Children should override this method to provide
* custom form validation.
* Validate the form. Children should override this method to provide custom form validation.
*
* @param e
*/
public void validate(FormSectionEvent e) throws FormProcessException {
@ -256,17 +255,17 @@ public abstract class BasicItemForm extends FormSection
}
/**
* Ensure that the name of an item is unique within a folder. A "New
* item" form should call this method in the validation listener.
* Ensure that the name of an item is unique within a folder. A "New item" form should call this
* method in the validation listener.
*
* @param parent the folder in which to check
* @param event the {@link FormSectionEvent} which was passed to the
* validation listener
* @throws FormProcessException if the folder already contains an item
* with the name the user provided on the input form.
* @param event the {@link FormSectionEvent} which was passed to the validation listener
*
* @throws FormProcessException if the folder already contains an item with the name the user
* provided on the input form.
*/
public void validateNameUniqueness(Folder parent, FormSectionEvent event)
throws FormProcessException {
throws FormProcessException {
FormData data = event.getFormData();
String newName = (String) data.get(NAME);
@ -279,11 +278,12 @@ public abstract class BasicItemForm extends FormSection
* @param parent
* @param event
* @param newName
*
* @throws FormProcessException
*/
public void validateNameUniqueness(Folder parent, FormSectionEvent event,
String newName)
throws FormProcessException {
throws FormProcessException {
if (newName != null) {
final String query = "com.arsdigita.cms.validateUniqueItemName";
DataQuery dq = SessionManager.getSession().retrieveQuery(query);
@ -300,20 +300,24 @@ public abstract class BasicItemForm extends FormSection
ContentItem item = null;
if (getItemSelectionModel() != null) {
item = (ContentItem) getItemSelectionModel().
getSelectedObject(event.getPageState());
getSelectedObject(event.getPageState());
}
if (item == null) {
// this means it is a creation form
// throw new FormProcessException(
// "An item with this name already exists");
throw new FormProcessException(
"An item with this name already exists");
"cms.ui.authoring.an_item_with_this_name_already_exists");
}
Collection list = getAllVersionIDs(item);
while (dq.next()) {
itemID = (BigDecimal) dq.get("itemID");
if (!list.contains(itemID)) {
dq.close();
// throw new FormProcessException(
// "An item with this name already exists");
throw new FormProcessException(
"An item with this name already exists");
"cms.ui.authoring.an_item_with_this_name_already_exists");
}
}
}
@ -321,19 +325,18 @@ public abstract class BasicItemForm extends FormSection
}
/**
* Ensure that the name of an item is unique within a category. This
* should only be called from the validation listener of an "edit" form.
* Ensure that the name of an item is unique within a category. This should only be called from
* the validation listener of an "edit" form.
*
* @param event the {@link FormSectionEvent} which was passed to the
* validation listener
* @param id The id of the item that is being checked. This must no
* be null.
* @throws FormProcessException if the folder already contains an item
* with the name the user provided on the input form.
* @param event the {@link FormSectionEvent} which was passed to the validation listener
* @param id The id of the item that is being checked. This must no be null.
*
* @throws FormProcessException if the folder already contains an item with the name the user
* provided on the input form.
*/
public void validateNameUniquenessWithinCategory(FormSectionEvent event,
BigDecimal id)
throws FormProcessException {
throws FormProcessException {
if (id == null) {
s_log.warn("Trying to validation the name uniqueness without "
+ " a valid item is invalid. This method should only "
@ -349,9 +352,8 @@ public abstract class BasicItemForm extends FormSection
if (url == null) {
return;
}
DataQuery query =
SessionManager.getSession().retrieveQuery(
"com.arsdigita.categorization.getAllItemURLsForCategoryFromItem");
DataQuery query = SessionManager.getSession().retrieveQuery(
"com.arsdigita.categorization.getAllItemURLsForCategoryFromItem");
query.setParameter("itemID", id);
query.addEqualsFilter("lower(url)", url.toLowerCase());
if (query.size() > 0) {
@ -359,9 +361,8 @@ public abstract class BasicItemForm extends FormSection
// pending or live version of the same item
BigDecimal itemID = null;
ContentItem item =
(ContentItem) getItemSelectionModel().getSelectedObject(event.
getPageState());
ContentItem item = (ContentItem) getItemSelectionModel().getSelectedObject(event.
getPageState());
Collection list = getAllVersionIDs(item);
try {
while (query.next()) {
@ -369,7 +370,7 @@ public abstract class BasicItemForm extends FormSection
if (!list.contains(itemID)) {
StringBuffer buffer = new StringBuffer((String) GlobalizationUtil
.globalize("cms.ui.authoring.error_conflicts_with_this_url")
.localize() );
.localize());
buffer.append(url);
throw new FormProcessException(buffer.toString());
}
@ -402,34 +403,33 @@ public abstract class BasicItemForm extends FormSection
* Adds a component to this container.
*
* @param pc the component to add to this BasicPageForm
* */
*
*/
@Override
public void add(Component pc) {
m_widgetSection.add(pc);
}
/**
* Adds a component with the specified layout constraints to this
* container. Layout constraints are defined in each layout container as
* static ints. Use a bitwise OR to specify multiple constraints.
* Adds a component with the specified layout constraints to this container. Layout constraints
* are defined in each layout container as static ints. Use a bitwise OR to specify multiple
* constraints.
*
* @param pc the component to add to this container
* @param pc the component to add to this container
*
* @param constraints layout constraints (a
* bitwise OR of static ints in the particular layout)
* */
* @param constraints layout constraints (a bitwise OR of static ints in the particular layout)
*
*/
@Override
public void add(Component pc, int constraints) {
m_widgetSection.add(pc, constraints);
}
/**
* jensp, 2011-01-28
* This method can be overridden to change the label of the title field.
* To change to label of the title field can be useful for some
* content types. For example, for an organization the label "Title" for
* the field is may confusing for the normal user. For such a content type,
* the label would be changed to something like "Name of the organization".
* jensp, 2011-01-28 This method can be overridden to change the label of the title field. To
* change to label of the title field can be useful for some content types. For example, for an
* organization the label "Title" for the field is may confusing for the normal user. For such a
* content type, the label would be changed to something like "Name of the organization".
*
* @return (Content for the) Label for the title field as string
*/
@ -438,8 +438,8 @@ public abstract class BasicItemForm extends FormSection
}
/**
* Provides the text for the user hint providing some detailed information
* how to use this widget.
* Provides the text for the user hint providing some detailed information how to use this
* widget.
*
* This method can be overwritten to adjust the text for some content types.
* {@link #getTitleLabel()}
@ -451,9 +451,8 @@ public abstract class BasicItemForm extends FormSection
}
/**
* jensp, 2011-01-28
* This method does the same as {@link #getTitleLabel() } for the label of
* the name (URL) field.
* jensp, 2011-01-28 This method does the same as {@link #getTitleLabel() } for the label of the
* name (URL) field.
*
* @return (Content for the) Label for the name field as string
*/
@ -462,8 +461,8 @@ public abstract class BasicItemForm extends FormSection
}
/**
* Provides the text for the unser hint providing some detailed information
* how to use this widget.
* Provides the text for the unser hint providing some detailed information how to use this
* widget.
*
* This method can be overwritten to adjust the text for some content types.
* {@link #getNameLabel()}
@ -473,4 +472,5 @@ public abstract class BasicItemForm extends FormSection
protected GlobalizedMessage getNameHint() {
return GlobalizationUtil.globalize("cms.contenttypes.ui.name_hint");
}
}

View File

@ -28,13 +28,13 @@ import com.arsdigita.globalization.GlobalizedMessage;
import java.util.Iterator;
/**
* Displays validation errors for the page. These might have occured due to validation
* listeners on some state parameters within the page.
* Displays validation errors for the page. These might have occured due to validation listeners on
* some state parameters within the page.
*
* @author Stanislav Freidin
* @version $Id: PageErrorDisplay.java 287 2005-02-22 00:29:02Z sskracic $
*/
public class PageErrorDisplay extends List {
public class PageErrorDisplay extends List {
private static final String COLOR = "color";
@ -46,8 +46,8 @@ public class PageErrorDisplay extends List {
}
/**
* Constructs a new <code>PageErrorDisplay</code> from the errors
* supplied by a list model builder.
* Constructs a new <code>PageErrorDisplay</code> from the errors supplied by a list model
* builder.
*
* @param builder the {@link ListModelBuilder} that will supply the errors
*
@ -70,6 +70,7 @@ public class PageErrorDisplay extends List {
/**
* Gets the HTML color of the error messages.
*
* @return the HTML color of the error messages.
*/
public String getTextColor() {
@ -80,23 +81,24 @@ public class PageErrorDisplay extends List {
* Determines if there are errors to display.
*
* @param state the current page state
* @return <code>true</code> if there are any errors to display;
* <code>false</code> otherwise.
*
* @return <code>true</code> if there are any errors to display; <code>false</code> otherwise.
*/
protected boolean hasErrors(PageState state) {
return(state.getErrors().hasNext());
return (state.getErrors().hasNext());
}
/**
* Generates the XML for this component. If the state has no errors
* in it, does not generate any XML.
* Generates the XML for this component. If the state has no errors in it, does not generate any
* XML.
*
* @param state the current page state
* @param state the current page state
* @param parent the parent XML element
*/
public void generateXML(PageState state, Element parent) {
if(hasErrors(state))
if (hasErrors(state)) {
super.generateXML(state, parent);
}
}
// A private class which builds a ListModel based on form errors
@ -110,6 +112,7 @@ public class PageErrorDisplay extends List {
public ListModel makeModel(List l, PageState state) {
return new StringIteratorModel(state.getErrors());
}
}
// A ListModel which generates items based on an Iterator
@ -126,22 +129,22 @@ public class PageErrorDisplay extends List {
}
public boolean next() {
if(!m_iter.hasNext()) {
if (!m_iter.hasNext()) {
m_i = 0;
return false;
}
m_error = (GlobalizedMessage)m_iter.next();
m_error = (GlobalizedMessage) m_iter.next();
++m_i;
return true;
}
private void checkState() {
if(m_i == 0) {
throw new IllegalStateException (
"next() has not been called succesfully"
);
if (m_i == 0) {
throw new IllegalStateException(
"next() has not been called succesfully"
);
}
}
@ -154,14 +157,17 @@ public class PageErrorDisplay extends List {
checkState();
return Integer.toString(m_i);
}
}
// A ListCellRenderer that renders labels
private static class LabelCellRenderer implements ListCellRenderer {
public Component getComponent(List list, PageState state, Object value,
String key, int index, boolean isSelected) {
return new Label((GlobalizedMessage)value);
return new Label((GlobalizedMessage) value);
}
}
}

View File

@ -21,7 +21,9 @@ package com.arsdigita.search.ui;
import com.arsdigita.bebop.SimpleComponent;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.parameters.IntegerParameter;
import com.arsdigita.bebop.util.GlobalizationUtil;
import com.arsdigita.globalization.Globalization;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.kernel.Party;
import com.arsdigita.xml.Element;
@ -44,265 +46,287 @@ import org.apache.log4j.Logger;
public class ResultsPane extends SimpleComponent {
private static final Logger s_log = Logger.getLogger(ResultsPane.class);
public static final int PAGE_SIZE = 10;
private int m_pageSize = PAGE_SIZE;
private String m_engine;
private QueryGenerator m_query;
private IntegerParameter m_pageNumber;
private boolean m_relative;
private static final Logger s_log = Logger.getLogger(ResultsPane.class);
public static final int PAGE_SIZE = 10;
private int m_pageSize = PAGE_SIZE;
private String m_engine;
private QueryGenerator m_query;
private IntegerParameter m_pageNumber;
private boolean m_relative;
//jensp 2014-03-04 Allow using classes to set a suitable info messages.
private GlobalizedMessage searchHelpMsg;
private GlobalizedMessage noResultsMsg;
public ResultsPane(QueryGenerator query) {
this(query, null);
}
public ResultsPane(QueryGenerator query) {
this(query, null);
}
/**
* Determines whether the links to the search results will be relative or
* absolute. The default is absolute.
*/
public void setRelativeURLs(boolean relative) {
m_relative = relative;
}
/**
* Determines whether the links to the search results will be relative or absolute. The default
* is absolute.
*/
public void setRelativeURLs(boolean relative) {
m_relative = relative;
}
public ResultsPane(QueryGenerator query,
String engine) {
m_query = query;
m_engine = engine;
m_pageNumber = new IntegerParameter("page");
m_relative = false;
}
public ResultsPane(QueryGenerator query,
String engine) {
m_query = query;
m_engine = engine;
m_pageNumber = new IntegerParameter("page");
m_relative = false;
}
@Override
public void generateXML(PageState state, Element parent) {
if (!m_query.hasQuery(state)) {
if (s_log.isDebugEnabled()) {
s_log.debug("No query available, skipping XMl generation");
}
Element content = Search.newElement("results");
Element info = content.newChildElement("info");
// info.setText(GlobalizationUtil.globalize("cms.ui.search_help").localize().toString());
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.");
parent.addContent(content);
return;
}
public void setSearchHelpMsg(final GlobalizedMessage msg) {
searchHelpMsg = msg;
}
QuerySpecification spec = m_query.getQuerySpecification(state);
ResultSet resultSet = null;
try {
resultSet = m_engine == null
? Search.process(spec)
: Search.process(spec, Search.DEFAULT_RESULT_CACHE,
m_engine);
public void setNoResultsMsg(final GlobalizedMessage msg) {
noResultsMsg = msg;
}
if (s_log.isDebugEnabled()) {
s_log.debug("Got result set " + resultSet.getClass()
+ " count: " + resultSet.getCount());
}
@Override
public void generateXML(PageState state, Element parent) {
if (!m_query.hasQuery(state)) {
if (s_log.isDebugEnabled()) {
s_log.debug("No query available, skipping XMl generation");
}
Element content = Search.newElement("results");
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());
}
if (resultSet.getCount() > 0) {
parent.addContent(content);
return;
}
Integer page = (Integer) m_pageNumber.transformValue(state.
getRequest());
int pageNumber = (page == null ? 1 : page.intValue());
long objectCount = resultSet.getCount();
int pageCount = (int) Math.ceil((double) objectCount
/ (double) m_pageSize);
QuerySpecification spec = m_query.getQuerySpecification(state);
ResultSet resultSet = null;
try {
resultSet = m_engine == null
? Search.process(spec)
: Search.process(spec, Search.DEFAULT_RESULT_CACHE,
m_engine);
if (pageNumber < 1) {
pageNumber = 1;
}
if (s_log.isDebugEnabled()) {
s_log.debug("Got result set " + resultSet.getClass()
+ " count: " + resultSet.getCount());
}
if (pageNumber > pageCount) {
pageNumber = (pageCount == 0 ? 1 : pageCount);
}
if (resultSet.getCount() > 0) {
long begin = ((pageNumber - 1) * m_pageSize);
int count = (int) Math.min(m_pageSize, (objectCount - begin));
long end = begin + count;
Integer page = (Integer) m_pageNumber.transformValue(state.
getRequest());
int pageNumber = (page == null ? 1 : page.intValue());
long objectCount = resultSet.getCount();
int pageCount = (int) Math.ceil((double) objectCount
/ (double) m_pageSize);
Iterator results = resultSet.getDocuments(begin, count);
if (pageNumber < 1) {
pageNumber = 1;
}
Element content = Search.newElement("results");
exportAttributes(content);
if (pageNumber > pageCount) {
pageNumber = (pageCount == 0 ? 1 : pageCount);
}
if (s_log.isDebugEnabled()) {
s_log.debug("Paginator stats\n page number:" + pageNumber
+ "\n page count: " + pageCount
+ "\n page size: "
+ m_pageSize + "\n start " + begin + "\n end: "
+ end + "\n count: " + objectCount);
}
long begin = ((pageNumber - 1) * m_pageSize);
int count = (int) Math.min(m_pageSize, (objectCount - begin));
long end = begin + count;
content.addContent(generatePaginatorXML(state,
m_pageNumber.getName(),
pageNumber, pageCount,
m_pageSize, begin, end,
objectCount));
content.addContent(generateDocumentsXML(state, results));
Iterator results = resultSet.getDocuments(begin, count);
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
Element content = Search.newElement("results");
Element info = content.newChildElement("info");
Element content = Search.newElement("results");
exportAttributes(content);
if (s_log.isDebugEnabled()) {
s_log.debug("Paginator stats\n page number:" + pageNumber
+ "\n page count: " + pageCount
+ "\n page size: "
+ m_pageSize + "\n start " + begin + "\n end: "
+ end + "\n count: " + objectCount);
}
content.addContent(generatePaginatorXML(state,
m_pageNumber.getName(),
pageNumber, pageCount,
m_pageSize, begin, end,
objectCount));
content.addContent(generateDocumentsXML(state, results));
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
Element content = Search.newElement("results");
Element info = content.newChildElement("info");
// info.setText(GlobalizationUtil.globalize("cms.ui.search_no_results").localize().toString());
info.setText("Sorry. Your search returned 0 results.");
parent.addContent(content);
}
if (noResultsMsg == null) {
info.setText("Sorry. Your search returned 0 results.");
} else {
info.setText(noResultsMsg.localize().toString());
}
parent.addContent(content);
}
} finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (Exception e) {
/*
* If there is a problem closing the result set this probably means
* it has been closed elsewhere and is probably not fatal. We write
* a line to the error log but otherwise ignore the exception allowing
* the code to continue normally. Any issues willemerge in the log.
*/
s_log.error("Error closing resultset: " + e.getMessage());
}
}
}
}
} finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (Exception e) {
/*
* If there is a problem closing the result set this probably means
* it has been closed elsewhere and is probably not fatal. We write
* a line to the error log but otherwise ignore the exception allowing
* the code to continue normally. Any issues willemerge in the log.
*/
s_log.error("Error closing resultset: " + e.getMessage());
}
}
}
}
protected Element generatePaginatorXML(PageState state,
String pageParam,
int pageNumber,
int pageCount,
int pageSize,
long begin,
long end,
long objectCount) {
Element paginator = Search.newElement("paginator");
URL url = Web.getContext().getRequestURL();
protected Element generatePaginatorXML(PageState state,
String pageParam,
int pageNumber,
int pageCount,
int pageSize,
long begin,
long end,
long objectCount) {
Element paginator = Search.newElement("paginator");
URL url = Web.getContext().getRequestURL();
ParameterMap map = new ParameterMap();
Iterator current = url.getParameterMap().keySet().iterator();
while (current.hasNext()) {
String key = (String) current.next();
if (key.equals(pageParam)) {
continue;
}
//map.setParameterValues(key, url.getParameterValues(key));
map.setParameterValues(key,
decodeParameters(url.getParameterValues(key),
state));
}
ParameterMap map = new ParameterMap();
Iterator current = url.getParameterMap().keySet().iterator();
while (current.hasNext()) {
String key = (String) current.next();
if (key.equals(pageParam)) {
continue;
}
//map.setParameterValues(key, url.getParameterValues(key));
map.setParameterValues(key,
decodeParameters(url.getParameterValues(key),
state));
}
paginator.addAttribute("pageParam", m_pageNumber.getName());
paginator.addAttribute("baseURL", URL.there(url.getPathInfo(), map).
toString());
paginator.addAttribute("pageNumber", XML.format(new Integer(pageNumber)));
paginator.addAttribute("pageCount", XML.format(new Integer(pageCount)));
paginator.addAttribute("pageSize", XML.format(new Integer(pageSize)));
paginator.addAttribute("objectBegin", XML.format(new Long(begin + 1)));
paginator.addAttribute("objectEnd", XML.format(new Long(end)));
paginator.addAttribute("objectCount", XML.format(new Long(objectCount)));
return paginator;
}
paginator.addAttribute("pageParam", m_pageNumber.getName());
paginator.addAttribute("baseURL", URL.there(url.getPathInfo(), map).
toString());
paginator.addAttribute("pageNumber", XML.format(new Integer(pageNumber)));
paginator.addAttribute("pageCount", XML.format(new Integer(pageCount)));
paginator.addAttribute("pageSize", XML.format(new Integer(pageSize)));
paginator.addAttribute("objectBegin", XML.format(new Long(begin + 1)));
paginator.addAttribute("objectEnd", XML.format(new Long(end)));
paginator.addAttribute("objectCount", XML.format(new Long(objectCount)));
return paginator;
}
private String[] decodeParameters(final String[] parameters,
final PageState state) {
final String[] decoded = new String[parameters.length];
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);
}
for (int i = 0; i < parameters.length; i++) {
decoded[i] = decodeParameter(parameters[i], state);
}
return decoded;
}
return decoded;
}
private String decodeParameter(final String parameter,
final PageState state) {
String re = state.getRequest().getParameter(Globalization.ENCODING_PARAM_NAME);
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 ((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) {
s_log.warn("Unsupported encoding.", ex);
return parameter;
}
}
}
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) {
s_log.warn("Unsupported encoding.", ex);
return parameter;
}
}
}
protected Element generateDocumentsXML(PageState state,
Iterator results) {
Element documents = Search.newElement("documents");
protected Element generateDocumentsXML(PageState state,
Iterator results) {
Element documents = Search.newElement("documents");
if (s_log.isDebugEnabled()) {
s_log.debug("Outputting documents");
}
while (results.hasNext()) {
Document doc = (Document) results.next();
if (s_log.isDebugEnabled()) {
s_log.debug("One doc " + doc.getOID() + " " + doc.getTitle());
}
documents.addContent(generateDocumentXML(state, doc));
}
if (s_log.isDebugEnabled()) {
s_log.debug("Outputting documents");
}
while (results.hasNext()) {
Document doc = (Document) results.next();
if (s_log.isDebugEnabled()) {
s_log.debug("One doc " + doc.getOID() + " " + doc.getTitle());
}
documents.addContent(generateDocumentXML(state, doc));
}
return documents;
}
return documents;
}
protected Element generateDocumentXML(PageState state,
Document doc) {
Element entry = Search.newElement("object");
protected Element generateDocumentXML(PageState state,
Document doc) {
Element entry = Search.newElement("object");
String summary = doc.getSummary();
String summary = doc.getSummary();
java.net.URL url = doc.getURL();
java.net.URL url = doc.getURL();
entry.addAttribute("oid", XML.format(doc.getOID()));
entry.addAttribute("url", XML.format(m_relative ? url.getPath() + "?"
+ url.getQuery()
: url.toString()));
entry.addAttribute("score", XML.format(doc.getScore()));
entry.addAttribute("title", XML.format(doc.getTitle()));
if (summary != null) {
entry.addAttribute("summary", XML.format(summary));
}
entry.addAttribute("oid", XML.format(doc.getOID()));
entry.addAttribute("url", XML.format(m_relative ? url.getPath() + "?"
+ url.getQuery()
: url.toString()));
entry.addAttribute("score", XML.format(doc.getScore()));
entry.addAttribute("title", XML.format(doc.getTitle()));
if (summary != null) {
entry.addAttribute("summary", XML.format(summary));
}
entry.addAttribute("locale", XML.format(doc.getLocale()));
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 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()));
}
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()));
}
s_log.debug(
"about to add the contentSectionName from search index Doc to search result xml");
entry.addAttribute("contentSectionName", XML.format(doc.
getContentSection()));
s_log.debug(
"about to add the contentSectionName from search index Doc to search result xml");
entry.addAttribute("contentSectionName", XML.format(doc.
getContentSection()));
return entry;
}
return entry;
}
}

View File

@ -130,7 +130,9 @@ public class DispatcherServlet extends BaseServlet {
s_log.debug("Successfully dispatched to an application");
} else {
s_log.debug("Could not dispatch this request to an " +
"application; using the fallback servlet");
"application; sending 404");
sresp.sendError(HttpServletResponse.SC_NOT_FOUND);
/*
sreq.setAttribute(FALLING_BACK_ATTRIBUTE, Boolean.TRUE);
@ -143,6 +145,8 @@ public class DispatcherServlet extends BaseServlet {
m_dispatcher.forward(fallbackDispatcher, sreq, sresp);
DeveloperSupport.endStage("BaseDispatcher.forward");
*/
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2002-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.london.search;
import com.arsdigita.globalization.Globalized;
import com.arsdigita.globalization.GlobalizedMessage;
/**
* Compilation of methods to simplify the handling of globalizing keys.
* Basically it adds the name of package's resource bundle files to the
* globalize methods and forwards to GlobalizedMessage, shortening the
* method invocation in the various application classes.
*
* @author <a href="mailto:yon@arsdigita.com">yon@arsdigita.com</a>
* @version $Revision$ $Date$
*/
public class SearchGlobalizationUtil implements Globalized {
/** Name of Java resource files to handle CMS's globalisation. */
private static final String BUNDLE_NAME = "com.arsdigita.london.search.SearchResources";
/**
* Returns a globalized message using the package specific bundle,
* provided by BUNDLE_NAME.
*/
public static GlobalizedMessage globalize(String key) {
return new GlobalizedMessage(key, BUNDLE_NAME);
}
/**
* Returns a globalized message object, using the package specific bundle,
* as specified by BUNDLE_NAME. Also takes in an Object[] of arguments to
* interpolate into the retrieved message using the MessageFormat class.
*/
public static GlobalizedMessage globalize(String key, Object[] args) {
return new GlobalizedMessage(key, BUNDLE_NAME, args);
}
/**
* Returns the name of the package specific resource bundle.
*
* Used e.g. by com.arsdigita.cms.ui.item.ItemLanguageTable to get the
* bundle tp pass to DataTable.
*
* @return Name of resource bundle as String
*/
public static String getBundleName() {
return BUNDLE_NAME;
}
}

View File

@ -0,0 +1,7 @@
# To change this license header, choose License Headers in Project Properties.
# To change this template file, choose Tools | Templates
# and open the template in the editor.
search.ui.submit_button=Find
search.ui.help=Please enter at least three letters for a search. You may narrow the result by adding further parameters.
search.ui.no_results=No results found.

View File

@ -0,0 +1,7 @@
# To change this license header, choose License Headers in Project Properties.
# To change this template file, choose Tools | Templates
# and open the template in the editor.
search.ui.submit_button=Finden
search.ui.help=Bitte geben Sie miindestens drei Buchstaben f\u00fcr die Suche ein. Sie k\u00f6nnen das Ergebnis mit weiteren Suchparametern weiter einschr\u00e4nken.
search.ui.no_results=Keine Ergebnisse gefunden.

View File

@ -26,6 +26,7 @@ import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.form.Submit;
import com.arsdigita.bebop.parameters.BigDecimalParameter;
import com.arsdigita.cms.ui.ItemSearch;
import com.arsdigita.london.search.SearchGlobalizationUtil;
import com.arsdigita.search.ui.QueryComponent;
import com.arsdigita.search.ui.ResultsPane;
@ -49,9 +50,11 @@ public class SearchComponent extends SimpleContainer {
m_form = new Form("search", new SimpleContainer());
m_form.setMethod(Form.GET);
m_form.add(m_query);
m_form.add(new Submit("search", "Search"));
m_form.add(new Submit("search", SearchGlobalizationUtil.globalize("search.ui.submit_button")));
m_results = new ResultsPane(query, engine);
m_results.setSearchHelpMsg(SearchGlobalizationUtil.globalize("search.ui.help"));
m_results.setNoResultsMsg(SearchGlobalizationUtil.globalize("search.ui.no_results"));
add(m_form);