001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.workplace.search; 029 030import org.opencms.db.CmsUserSettings.CmsSearchResultStyle; 031import org.opencms.jsp.CmsJspActionElement; 032import org.opencms.main.CmsIllegalStateException; 033import org.opencms.main.OpenCms; 034import org.opencms.search.CmsSearchParameters; 035import org.opencms.search.I_CmsSearchIndex; 036import org.opencms.search.fields.CmsLuceneField; 037import org.opencms.search.fields.CmsSearchField; 038import org.opencms.util.CmsStringUtil; 039import org.opencms.widgets.A_CmsWidget; 040import org.opencms.widgets.CmsCalendarWidget; 041import org.opencms.widgets.CmsCheckboxWidget; 042import org.opencms.widgets.CmsInputWidget; 043import org.opencms.widgets.CmsMultiSelectWidget; 044import org.opencms.widgets.CmsSelectOnChangeReloadWidget; 045import org.opencms.widgets.CmsSelectWidget; 046import org.opencms.widgets.CmsSelectWidgetOption; 047import org.opencms.workplace.CmsDialog; 048import org.opencms.workplace.CmsWidgetDialog; 049import org.opencms.workplace.CmsWidgetDialogParameter; 050import org.opencms.workplace.CmsWorkplaceSettings; 051import org.opencms.workplace.list.A_CmsListDialog; 052import org.opencms.workplace.list.A_CmsListExplorerDialog; 053import org.opencms.workplace.list.CmsListMetadata; 054import org.opencms.workplace.tools.CmsToolDialog; 055 056import java.util.ArrayList; 057import java.util.HashMap; 058import java.util.Iterator; 059import java.util.List; 060import java.util.Map; 061 062import javax.servlet.http.HttpServletRequest; 063import javax.servlet.http.HttpServletResponse; 064import javax.servlet.jsp.PageContext; 065 066/** 067 * Provides a GUI for the workplace search feature.<p> 068 * 069 * @since 6.2.0 070 */ 071public class CmsSearchDialog extends CmsWidgetDialog { 072 073 /** Localization key label infix for fields. */ 074 public static final String LABEL_FIELD_INFIX = "field."; 075 076 /** the dialog type. */ 077 private static final String DIALOG_TYPE = "search"; 078 079 /** Defines which pages are valid for this dialog. */ 080 private static final String[] PAGES = {"page1"}; 081 082 /** the search data. */ 083 private CmsSearchWorkplaceBean m_search; 084 085 /** 086 * Default constructor.<p> 087 * 088 * @param jsp an initialized JSP action element 089 */ 090 public CmsSearchDialog(CmsJspActionElement jsp) { 091 092 super(jsp); 093 } 094 095 /** 096 * Public constructor with JSP variables.<p> 097 * 098 * @param context the JSP page context 099 * @param req the JSP request 100 * @param res the JSP response 101 */ 102 public CmsSearchDialog(PageContext context, HttpServletRequest req, HttpServletResponse res) { 103 104 this(new CmsJspActionElement(context, req, res)); 105 } 106 107 /** 108 * @see org.opencms.workplace.CmsWidgetDialog#actionCommit() 109 */ 110 @Override 111 public void actionCommit() { 112 113 List<Throwable> errors = new ArrayList<Throwable>(); 114 try { 115 Map<String, String[]> params = new HashMap<String, String[]>(); 116 params.put(CmsDialog.PARAM_ACTION, new String[] {A_CmsListDialog.LIST_SELECT_PAGE}); 117 params.put(A_CmsListDialog.PARAM_PAGE, new String[] {"1"}); 118 params.put(CmsToolDialog.PARAM_ROOT, new String[] {"explorer"}); 119 if (getSettings().getUserSettings().getWorkplaceSearchViewStyle() == CmsSearchResultStyle.STYLE_EXPLORER) { 120 getSettings().setExplorerPage(1); 121 params.put(A_CmsListExplorerDialog.PARAM_SHOW_EXPLORER, new String[] {Boolean.TRUE.toString()}); 122 } else { 123 CmsSearchResultsList resultsList = new CmsSearchResultsList(getJsp()); 124 CmsListMetadata metadata = resultsList.getMetadata( 125 CmsSearchResultsList.class.getName(), 126 resultsList.getListId()); 127 boolean withExcerpts = (getSettings().getUserSettings().getWorkplaceSearchViewStyle() == CmsSearchResultStyle.STYLE_LIST_WITH_EXCERPTS); 128 if (metadata == null) { 129 if (!withExcerpts) { 130 // prevent the excerpts to be displayed by default 131 params.put(CmsDialog.PARAM_ACTION, new String[] {A_CmsListDialog.LIST_INDEPENDENT_ACTION}); 132 params.put( 133 A_CmsListDialog.PARAM_LIST_ACTION, 134 new String[] {CmsSearchResultsList.LIST_DETAIL_EXCERPT}); 135 } 136 } else { 137 // toggle excerpts 138 metadata.getItemDetailDefinition(CmsSearchResultsList.LIST_DETAIL_EXCERPT).setVisible(withExcerpts); 139 } 140 params.put(A_CmsListExplorerDialog.PARAM_SHOW_EXPLORER, new String[] {Boolean.FALSE.toString()}); 141 } 142 getToolManager().jspForwardTool(this, "/search/results", params); 143 } catch (Exception e) { 144 errors.add(e); 145 } 146 setCommitErrors(errors); 147 } 148 149 /** 150 * Returns the list of searchable fields used in the workplace search index.<p> 151 * 152 * @return the list of searchable fields used in the workplace search index 153 */ 154 public List<CmsLuceneField> getFields() { 155 156 I_CmsSearchIndex index = getIndex(); 157 List<CmsLuceneField> result = new ArrayList<CmsLuceneField>(); 158 Iterator<CmsSearchField> i = index.getFieldConfiguration().getFields().iterator(); 159 while (i.hasNext()) { 160 CmsLuceneField field = (CmsLuceneField)i.next(); 161 if (field.isIndexed() && field.isDisplayed()) { 162 // only include indexed (ie. searchable) fields 163 result.add(field); 164 } 165 } 166 return result; 167 } 168 169 /** 170 * Creates the dialog HTML for all defined widgets of the named dialog (page).<p> 171 * 172 * This overwrites the method from the super class to create a layout variation for the widgets.<p> 173 * 174 * @param dialog the dialog (page) to get the HTML for 175 * @return the dialog HTML for all defined widgets of the named dialog (page) 176 */ 177 @Override 178 protected String createDialogHtml(String dialog) { 179 180 // check if the configured search index exists 181 I_CmsSearchIndex index = getIndex(); 182 if (index == null) { 183 throw new CmsIllegalStateException( 184 Messages.get().container( 185 Messages.ERR_INDEX_INVALID_1, 186 getSettings().getUserSettings().getWorkplaceSearchIndexName())); 187 } 188 189 StringBuffer result = new StringBuffer(1024); 190 191 // create widget table 192 result.append(createWidgetTableStart()); 193 194 // show error header once if there were validation errors 195 result.append(createWidgetErrorHeader()); 196 197 if (dialog.equals(PAGES[0])) { 198 // content 199 result.append(createWidgetBlockStart(key(Messages.GUI_SEARCH_QUERY_TITLE_0))); 200 result.append(createDialogRowsHtml(0, 3)); 201 result.append(createWidgetBlockEnd()); 202 // fields for limiting time ranges 203 // result.append(createWidgetBlockStart(key(Messages.GUI_SEARCH_TIME_RANGES_0))); 204 // result.append(createDialogRowsHtml(4, 7)); 205 // result.append(createWidgetBlockEnd()); 206 result.append(createWidgetBlockStart(key(Messages.GUI_SEARCH_FIELDS_TITLE_0))); 207 result.append(createDialogRowsHtml(8, 8)); 208 result.append(createWidgetBlockEnd()); 209 } 210 // close widget table 211 result.append(createWidgetTableEnd()); 212 213 return result.toString(); 214 } 215 216 /** 217 * @see org.opencms.workplace.CmsWidgetDialog#defineWidgets() 218 */ 219 @Override 220 protected void defineWidgets() { 221 222 initParams(); 223 addWidget( 224 new CmsWidgetDialogParameter( 225 m_search, 226 "indexName", 227 PAGES[0], 228 new CmsSelectOnChangeReloadWidget(getSortNamesIndex()))); 229 addWidget(new CmsWidgetDialogParameter(m_search, "query", PAGES[0], new CmsInputWidget())); 230 addWidget( 231 new CmsWidgetDialogParameter(m_search, "sortOrder", PAGES[0], new CmsSelectWidget(getSortNamesConf()))); 232 addWidget(new CmsWidgetDialogParameter(m_search, "restrictSearch", PAGES[0], new CmsCheckboxWidget())); 233 addWidget(new CmsWidgetDialogParameter(m_search, "minDateCreated", PAGES[0], new CmsCalendarWidget())); 234 addWidget(new CmsWidgetDialogParameter(m_search, "maxDateCreated", PAGES[0], new CmsCalendarWidget())); 235 addWidget(new CmsWidgetDialogParameter(m_search, "minDateLastModified", PAGES[0], new CmsCalendarWidget())); 236 addWidget(new CmsWidgetDialogParameter(m_search, "maxDateLastModified", PAGES[0], new CmsCalendarWidget())); 237 addWidget( 238 new CmsWidgetDialogParameter(m_search, "fields", PAGES[0], new CmsMultiSelectWidget(getFieldList(), true))); 239 } 240 241 /** 242 * @see org.opencms.workplace.CmsWidgetDialog#getPageArray() 243 */ 244 @Override 245 protected String[] getPageArray() { 246 247 return PAGES; 248 } 249 250 /** 251 * @see org.opencms.workplace.CmsWorkplace#initMessages() 252 */ 253 @Override 254 protected void initMessages() { 255 256 // add specific dialog resource bundle 257 addMessages(Messages.get().getBundleName()); 258 // add default resource bundles 259 super.initMessages(); 260 } 261 262 /** 263 * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, javax.servlet.http.HttpServletRequest) 264 */ 265 @Override 266 protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) { 267 268 // set the dialog type 269 setParamDialogtype(DIALOG_TYPE); 270 super.initWorkplaceRequestValues(settings, request); 271 // save the current state of the parameters (may be changed because of the widget values) 272 setDialogObject(m_search); 273 } 274 275 /** 276 * Returns a list of <code>{@link CmsSelectWidgetOption}</code> objects for field list selection.<p> 277 * 278 * @return a list of <code>{@link CmsSelectWidgetOption}</code> objects 279 */ 280 private List<CmsSelectWidgetOption> getFieldList() { 281 282 List<CmsSelectWidgetOption> retVal = new ArrayList<CmsSelectWidgetOption>(); 283 try { 284 Iterator<CmsLuceneField> i = getFields().iterator(); 285 while (i.hasNext()) { 286 CmsLuceneField field = i.next(); 287 if (isInitialCall()) { 288 // search form is in the initial state 289 retVal.add( 290 new CmsSelectWidgetOption( 291 field.getName(), 292 true, 293 getMacroResolver().resolveMacros(field.getDisplayName()))); 294 } else { 295 // search form is not in the initial state 296 retVal.add( 297 new CmsSelectWidgetOption( 298 field.getName(), 299 false, 300 getMacroResolver().resolveMacros(field.getDisplayName()))); 301 } 302 } 303 } catch (Exception e) { 304 // noop 305 } 306 return retVal; 307 } 308 309 /** Gets the index to use in the search. 310 * 311 * @return the index to use in the search 312 */ 313 private I_CmsSearchIndex getIndex() { 314 315 I_CmsSearchIndex index = null; 316 // get the configured index or the selected index 317 if (isInitialCall()) { 318 // the search form is in the initial state 319 // get the configured index 320 index = OpenCms.getSearchManager().getIndex(getSettings().getUserSettings().getWorkplaceSearchIndexName()); 321 } else { 322 // the search form is not in the inital state, the submit button was used already or the 323 // search index was changed already 324 // get the selected index in the search dialog 325 index = OpenCms.getSearchManager().getIndex(getJsp().getRequest().getParameter("indexName.0")); 326 } 327 return index; 328 } 329 330 /** 331 * Creates the select widget configuration for the sort names.<p> 332 * 333 * @return the select widget configuration for the sort names 334 */ 335 private List<CmsSelectWidgetOption> getSortNamesConf() { 336 337 List<CmsSelectWidgetOption> retVal = new ArrayList<CmsSelectWidgetOption>(); 338 try { 339 String[] names = CmsSearchParameters.SORT_NAMES; 340 for (int i = 0; i < names.length; i++) { 341 retVal.add( 342 new CmsSelectWidgetOption( 343 names[i], 344 (i == 0), 345 key(A_CmsWidget.LABEL_PREFIX + names[i].toLowerCase()))); 346 } 347 } catch (Exception e) { 348 // noop 349 } 350 return retVal; 351 } 352 353 /** 354 * Creates the select widget configuration for the index names.<p> 355 * 356 * @return the select widget configuration for the index names 357 */ 358 private List<CmsSelectWidgetOption> getSortNamesIndex() { 359 360 List<CmsSelectWidgetOption> retVal = new ArrayList<CmsSelectWidgetOption>(); 361 try { 362 List<String> names = OpenCms.getSearchManager().getIndexNames(); 363 for (int i = 0; i < names.size(); i++) { 364 String indexName = names.get(i); 365 String wpIndexName = getSettings().getUserSettings().getWorkplaceSearchIndexName(); 366 boolean isDefault = indexName.toLowerCase().equals(wpIndexName.toLowerCase()); 367 retVal.add(new CmsSelectWidgetOption(names.get(i), isDefault, names.get(i))); 368 } 369 } catch (Exception e) { 370 // noop 371 } 372 return retVal; 373 } 374 375 /** 376 * Initializes the parameters.<p> 377 */ 378 private void initParams() { 379 380 Object o; 381 382 if (CmsStringUtil.isEmpty(getParamAction()) || CmsDialog.DIALOG_INITIAL.equals(getParamAction())) { 383 // read params from config 384 o = null; 385 } else { 386 // this is not the initial call, get params from session 387 o = getDialogObject(); 388 } 389 if (!(o instanceof CmsSearchWorkplaceBean)) { 390 String oldExplorerMode = getSettings().getExplorerMode(); 391 getSettings().setExplorerMode(null); 392 String explorerResource = getSettings().getExplorerResource(); 393 getSettings().setExplorerMode(oldExplorerMode); 394 m_search = new CmsSearchWorkplaceBean(explorerResource); 395 } else { 396 // reuse params stored in session 397 m_search = (CmsSearchWorkplaceBean)o; 398 } 399 } 400 401 /** 402 * Gets the information if the search form is in the inital state.<p> 403 * 404 * @return true, the search form is in the inital state. otherwise false 405 */ 406 private boolean isInitialCall() { 407 408 // return false in case the form was submitted already or the submit button was pressed or the index was changed 409 return !(((getJsp().getRequest().getParameter(CmsDialog.PARAM_ACTION) != null) 410 && (getJsp().getRequest().getParameter(CmsDialog.PARAM_ACTION).equals( 411 CmsDialog.PARAM_ACTION_VALUE_FOR_CHANGED_INDEX))) 412 || ((getJsp().getRequest().getParameter("indexName.0")) != null)); 413 } 414}