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.acacia.client.widgets; 029 030import org.opencms.acacia.client.css.I_CmsWidgetsLayoutBundle; 031import org.opencms.acacia.shared.CmsWidgetUtil; 032import org.opencms.gwt.client.CmsCoreProvider; 033import org.opencms.gwt.client.I_CmsHasResizeOnShow; 034import org.opencms.gwt.client.Messages; 035import org.opencms.gwt.client.rpc.CmsRpcAction; 036import org.opencms.gwt.client.ui.CmsPopup; 037import org.opencms.gwt.client.ui.input.CmsCategoryField; 038import org.opencms.gwt.client.ui.input.category.CmsCategoryTree; 039import org.opencms.gwt.shared.CmsCategoryTreeEntry; 040 041import java.util.HashSet; 042import java.util.Iterator; 043import java.util.List; 044import java.util.Map; 045import java.util.Set; 046 047import com.google.gwt.dom.client.Element; 048import com.google.gwt.event.dom.client.ClickEvent; 049import com.google.gwt.event.dom.client.ClickHandler; 050import com.google.gwt.event.dom.client.FocusEvent; 051import com.google.gwt.event.dom.client.FocusHandler; 052import com.google.gwt.event.logical.shared.CloseEvent; 053import com.google.gwt.event.logical.shared.CloseHandler; 054import com.google.gwt.event.logical.shared.ValueChangeEvent; 055import com.google.gwt.event.logical.shared.ValueChangeHandler; 056import com.google.gwt.event.shared.HandlerRegistration; 057import com.google.gwt.user.client.Command; 058import com.google.gwt.user.client.DOM; 059import com.google.gwt.user.client.Event; 060import com.google.gwt.user.client.Event.NativePreviewEvent; 061import com.google.gwt.user.client.Event.NativePreviewHandler; 062import com.google.gwt.user.client.Window; 063import com.google.gwt.user.client.ui.Composite; 064import com.google.gwt.user.client.ui.PopupPanel; 065 066/** 067 * Provides a standard HTML form category widget, for use on a widget dialog.<p> 068 **/ 069public class CmsCategoryWidget extends Composite implements I_CmsEditWidget, I_CmsHasResizeOnShow { 070 071 /** 072 * Drag and drop event preview handler.<p> 073 * 074 * To be used while dragging.<p> 075 */ 076 protected class CloseEventPreviewHandler implements NativePreviewHandler { 077 078 /** 079 * @see com.google.gwt.user.client.Event.NativePreviewHandler#onPreviewNativeEvent(com.google.gwt.user.client.Event.NativePreviewEvent) 080 */ 081 public void onPreviewNativeEvent(NativePreviewEvent event) { 082 083 Event nativeEvent = Event.as(event.getNativeEvent()); 084 switch (DOM.eventGetType(nativeEvent)) { 085 case Event.ONMOUSEWHEEL: 086 int x_coords = nativeEvent.getClientX(); 087 int y_coords = (nativeEvent.getClientY() + Window.getScrollTop()); 088 089 if (((x_coords > (m_xcoordspopup + 605)) || (x_coords < (m_xcoordspopup))) 090 || ((y_coords > ((m_ycoordspopup + 390))) || (y_coords < ((m_ycoordspopup))))) { 091 closePopup(); 092 } 093 break; 094 default: 095 // do nothing 096 } 097 } 098 099 } 100 101 /** Configuration parameter to set the category to display. */ 102 private static final String CONFIGURATION_CATEGORY = "category"; 103 104 /** Configuration parameter to set the collapsing state when opening the selection. */ 105 private static final String CONFIGURATION_COLLAPSED = "collapsed"; 106 107 /** Configuration parameter to set the 'selection type' parameter. */ 108 private static final String CONFIGURATION_PARENTSELECTION = "parentselection"; 109 110 /** Set the reference url relative to which category repositories are shown. */ 111 private static final String CONFIGURATION_REFPATH = "refpath"; 112 113 /** Configuration parameter to set the 'selection type' parameter. */ 114 private static final String CONFIGURATION_SELECTIONTYPE = "selectiontype"; 115 116 /** Configuration parameter to set flag, indicating if categories should be shown separated by repository. */ 117 private static final String CONFIGURATION_SHOW_WITH_REPOSITORY = "showwithrepository"; 118 119 /** Configuration parameter to set the default height. */ 120 private static final int DEFAULT_HEIGHT = 30; 121 122 /** Configuration parameter to set the maximal height. */ 123 private static final int MAX_HEIGHT = 242; 124 125 /** Category widget. */ 126 protected CmsCategoryField m_categoryField; 127 128 /** The priview handler. */ 129 protected HandlerRegistration m_previewHandlerRegistration; 130 131 /** List of all category folder. */ 132 protected List<CmsCategoryTreeEntry> m_resultList; 133 134 /** The x-coords of the popup. */ 135 protected int m_xcoordspopup; 136 137 /** The y-coords of the popup. */ 138 protected int m_ycoordspopup; 139 140 /** The category field. */ 141 CmsCategoryTree m_cmsCategoryTree; 142 143 /** The popup panel. */ 144 CmsPopup m_cmsPopup; 145 146 /** Height of the display field. */ 147 int m_height = DEFAULT_HEIGHT; 148 149 /** Flag indicating the category tree is being loaded. */ 150 boolean m_loadingCategoryTree; 151 152 /** List of all selected categories. */ 153 Set<String> m_selected; 154 155 /** Map of selected Values in relation to the select level. */ 156 String m_selectedValue; 157 158 /** Value of the activation. */ 159 private boolean m_active = true; 160 161 /** Single category folder. */ 162 private String m_category = ""; 163 164 /** Sets the value if the parent should be selected with the children. */ 165 private boolean m_children; 166 167 /** If true, the category selection opens with collapsed category trees. */ 168 private boolean m_collapsed; 169 170 /** Is true if only one value is set in xml. */ 171 private boolean m_isSingleValue; 172 173 /** List of all possible category folder. */ 174 private String m_refPath; 175 176 /** If true, the categories are shown separate for each repository. */ 177 private boolean m_showWithRepository; 178 179 /** 180 * Constructs an CmsComboWidget with the in XSD schema declared configuration.<p> 181 * @param config The configuration string given from OpenCms XSD 182 */ 183 public CmsCategoryWidget(String config) { 184 185 m_categoryField = new CmsCategoryField(); 186 m_selected = new HashSet<String>(); 187 //parse configuration string and set member variables 188 parseConfiguration(config); 189 m_categoryField.setParentSelection(m_children); 190 m_categoryField.getScrollPanel().addStyleName(I_CmsWidgetsLayoutBundle.INSTANCE.widgetCss().categoryPanel()); 191 m_categoryField.addDomHandler(new ClickHandler() { 192 193 public void onClick(ClickEvent event) { 194 195 if ((m_cmsPopup == null) || !m_cmsPopup.isShowing()) { 196 openPopup(); 197 } else { 198 closePopup(); 199 } 200 201 } 202 }, ClickEvent.getType()); 203 initWidget(m_categoryField); 204 205 } 206 207 /** 208 * @see com.google.gwt.event.dom.client.HasFocusHandlers#addFocusHandler(com.google.gwt.event.dom.client.FocusHandler) 209 */ 210 public HandlerRegistration addFocusHandler(FocusHandler handler) { 211 212 return addDomHandler(handler, FocusEvent.getType()); 213 } 214 215 /** 216 * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler) 217 */ 218 public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) { 219 220 return addHandler(handler, ValueChangeEvent.getType()); 221 } 222 223 /** 224 * Represents a value change event.<p> 225 */ 226 public void fireChangeEvent() { 227 228 ValueChangeEvent.fire(this, getValue()); 229 230 } 231 232 /** 233 * @see com.google.gwt.user.client.ui.HasValue#getValue() 234 */ 235 public String getValue() { 236 237 String result = ""; 238 int y = 0; 239 if (m_isSingleValue) { 240 if (m_selected.size() != 0) { 241 result = m_selected.iterator().next(); 242 } else { 243 result = ""; 244 } 245 } else { 246 Iterator<String> i = m_categoryField.getAllSitePath().iterator(); 247 while (i.hasNext()) { 248 if (y != 0) { 249 result += ","; 250 251 } 252 result += i.next(); 253 y++; 254 } 255 } 256 return result; 257 } 258 259 /** 260 * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#isActive() 261 */ 262 public boolean isActive() { 263 264 return m_active; 265 } 266 267 /** 268 * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#onAttachWidget() 269 */ 270 public void onAttachWidget() { 271 272 super.onAttach(); 273 } 274 275 /** 276 * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#owns(com.google.gwt.dom.client.Element) 277 */ 278 public boolean owns(Element element) { 279 280 return getElement().isOrHasChild(element); 281 } 282 283 /** 284 * @see org.opencms.gwt.client.I_CmsHasResizeOnShow#resizeOnShow() 285 */ 286 public void resizeOnShow() { 287 288 m_categoryField.resizeOnShow(); 289 } 290 291 /** 292 * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setActive(boolean) 293 */ 294 public void setActive(boolean active) { 295 296 if (m_active == active) { 297 return; 298 } 299 m_active = active; 300 // only fire change if the widget was activated 301 if (m_active) { 302 fireChangeEvent(); 303 } 304 } 305 306 /** 307 * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setName(java.lang.String) 308 */ 309 public void setName(String name) { 310 311 // no input field so nothing to do. 312 } 313 314 /** 315 * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object) 316 */ 317 public void setValue(String value) { 318 319 setValue(value, false); 320 321 } 322 323 /** 324 * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object, boolean) 325 */ 326 public void setValue(String value, boolean fireEvents) { 327 328 String[] selectedArray = value.split(","); 329 m_selected.clear(); 330 for (String selectedCat : selectedArray) { 331 m_selected.add(selectedCat); 332 } 333 334 displayValue(); 335 336 if (fireEvents) { 337 fireChangeEvent(); 338 } 339 } 340 341 /** 342 * Is called to close the popup and show the new values.<p> 343 */ 344 protected void closePopup() { 345 346 List<String> result; 347 348 if (m_previewHandlerRegistration != null) { 349 m_previewHandlerRegistration.removeHandler(); 350 m_previewHandlerRegistration = null; 351 } 352 if (m_isSingleValue) { 353 result = m_cmsCategoryTree.getSelected(); 354 } else { 355 result = m_cmsCategoryTree.getAllSelectedSitePath(); 356 } 357 m_selected.clear(); 358 m_selected.addAll(result); 359 displayValue(); 360 m_cmsPopup.hide(); 361 fireChangeEvent(); 362 363 } 364 365 /** 366 * Is called to open the popup.<p> 367 */ 368 protected void openPopup() { 369 370 if (m_cmsPopup == null) { 371 372 m_cmsPopup = new CmsPopup(Messages.get().key(Messages.GUI_DIALOG_CATEGORIES_TITLE_0), CmsPopup.WIDE_WIDTH); 373 m_cmsCategoryTree = new CmsCategoryTree(m_selected, 300, m_isSingleValue, m_resultList, m_collapsed); 374 m_cmsPopup.add(m_cmsCategoryTree); 375 m_cmsPopup.setModal(false); 376 m_cmsPopup.setAutoHideEnabled(true); 377 m_cmsPopup.addCloseHandler(new CloseHandler<PopupPanel>() { 378 379 public void onClose(CloseEvent<PopupPanel> event) { 380 381 closePopup(); 382 383 } 384 }); 385 m_cmsPopup.addDialogClose(new Command() { 386 387 public void execute() { 388 389 // do nothing all will done in onClose(); 390 } 391 }); 392 } 393 if (m_previewHandlerRegistration != null) { 394 m_previewHandlerRegistration.removeHandler(); 395 } 396 m_previewHandlerRegistration = Event.addNativePreviewHandler(new CloseEventPreviewHandler()); 397 m_cmsCategoryTree.truncate("CATEGORIES", CmsPopup.WIDE_WIDTH - 20); 398 m_cmsPopup.showRelativeTo(m_categoryField); 399 m_xcoordspopup = m_cmsPopup.getPopupLeft(); 400 m_ycoordspopup = m_cmsPopup.getPopupTop(); 401 } 402 403 /** 404 * Generates the right height for the view.<p> 405 * */ 406 protected void setHeight() { 407 408 if (m_categoryField.getValuesSet() > 0) { 409 m_height = (m_categoryField.getValuesSet() * 26) + 4; 410 411 if (m_height > MAX_HEIGHT) { 412 m_height = MAX_HEIGHT; 413 m_categoryField.getScrollPanel().setResizable(true); 414 } else { 415 m_categoryField.getScrollPanel().setResizable(false); 416 } 417 } else { 418 m_height = DEFAULT_HEIGHT; 419 420 m_categoryField.getScrollPanel().setResizable(false); 421 } 422 423 m_categoryField.setHeight(m_height); 424 425 } 426 427 /** 428 * Displays the current value.<p> 429 */ 430 private void displayValue() { 431 432 if (m_resultList == null) { 433 if (!m_loadingCategoryTree) { 434 m_loadingCategoryTree = true; 435 // generate a list of all configured categories. 436 final String category = m_category; 437 final String refPath = m_refPath; 438 final boolean showWithRepository = m_showWithRepository; 439 CmsRpcAction<List<CmsCategoryTreeEntry>> action = new CmsRpcAction<List<CmsCategoryTreeEntry>>() { 440 441 /** 442 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 443 */ 444 @Override 445 public void execute() { 446 447 CmsCoreProvider.getService().getCategories( 448 category, 449 true, 450 refPath, 451 showWithRepository, 452 m_selected, 453 this); 454 455 } 456 457 /** 458 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 459 */ 460 @Override 461 protected void onResponse(List<CmsCategoryTreeEntry> result) { 462 463 // copy the result to the global variable. 464 m_resultList = result; 465 m_loadingCategoryTree = false; 466 // start to generate the tree view. 467 m_categoryField.buildCategoryTree(m_resultList, m_selected); 468 setHeight(); 469 } 470 471 }; 472 action.execute(); 473 } 474 } else { 475 m_categoryField.buildCategoryTree(m_resultList, m_selected); 476 setHeight(); 477 } 478 } 479 480 /** 481 * Help function to parse the configuration.<p> 482 * @param configuration the value to be parsed. 483 * 484 * */ 485 private void parseConfiguration(String configuration) { 486 487 Map<String, String> configOptions = CmsWidgetUtil.parsePipeSeparatedConfigString(configuration); 488 if (!configOptions.isEmpty()) { 489 m_category = CmsWidgetUtil.getStringOption(configOptions, CONFIGURATION_CATEGORY, m_category); 490 m_isSingleValue = !("multi".equals( 491 CmsWidgetUtil.getStringOption(configOptions, CONFIGURATION_SELECTIONTYPE, "single"))); 492 m_children = CmsWidgetUtil.getBooleanOption(configOptions, CONFIGURATION_PARENTSELECTION); 493 m_collapsed = CmsWidgetUtil.getBooleanOption(configOptions, CONFIGURATION_COLLAPSED); 494 m_showWithRepository = CmsWidgetUtil.getBooleanOption(configOptions, CONFIGURATION_SHOW_WITH_REPOSITORY); 495 m_refPath = CmsWidgetUtil.getStringOption(configOptions, CONFIGURATION_REFPATH, m_refPath); 496 } 497 } 498}