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.CmsEntity; 032import org.opencms.ade.contenteditor.client.CmsContentEditor; 033import org.opencms.ade.contenteditor.client.I_CmsEntityChangeListener; 034import org.opencms.ade.contenteditor.client.css.I_CmsLayoutBundle; 035import org.opencms.gwt.client.ui.input.CmsFilterSelectBox; 036import org.opencms.util.CmsPair; 037 038import java.util.LinkedHashMap; 039import java.util.List; 040import java.util.Map; 041import java.util.Map.Entry; 042 043import com.google.gwt.dom.client.Element; 044import com.google.gwt.event.dom.client.FocusEvent; 045import com.google.gwt.event.dom.client.FocusHandler; 046import com.google.gwt.event.logical.shared.ValueChangeEvent; 047import com.google.gwt.event.logical.shared.ValueChangeHandler; 048import com.google.gwt.event.shared.HandlerRegistration; 049import com.google.gwt.json.client.JSONArray; 050import com.google.gwt.json.client.JSONBoolean; 051import com.google.gwt.json.client.JSONObject; 052import com.google.gwt.json.client.JSONParser; 053import com.google.gwt.json.client.JSONString; 054import com.google.gwt.user.client.ui.Composite; 055import com.google.gwt.user.client.ui.RootPanel; 056 057/** 058 * Select widget for display types. 059 * In case the widget is configured to match display types, only formatters of a specific type may be selected at the same time.<p> 060 */ 061public class CmsDisplayTypeSelectWidget extends Composite implements I_CmsEditWidget, I_CmsHasDisplayDirection { 062 063 /** The no filter string. */ 064 private static final String NO_FILTER = "###no-filter###"; 065 066 /** The global select box. */ 067 protected CmsFilterSelectBox m_selectBox = new CmsFilterSelectBox(); 068 069 /** Flag indicating the widget is configured to match types. */ 070 boolean m_matchTypes; 071 072 /** The available select options, un-filtered. */ 073 Map<String, CmsPair<String, String>> m_options; 074 075 /** Value of the activation. */ 076 private boolean m_active = true; 077 078 /** The current filter type. */ 079 private String m_filterType; 080 081 /** Path components of the path used to select the option value. */ 082 private String[] m_valuePath; 083 084 /** The empty option label. */ 085 private String m_emptyLabel; 086 087 /** 088 * Creates a new widget instance.<p> 089 * 090 * @param configuration the widget configuration 091 */ 092 public CmsDisplayTypeSelectWidget(String configuration) { 093 094 JSONObject config = (JSONObject)JSONParser.parseStrict(configuration); 095 String path = ((JSONString)config.get("valuePath")).stringValue(); 096 m_valuePath = splitPath(path); 097 m_matchTypes = ((JSONBoolean)config.get("matchTypes")).booleanValue(); 098 m_emptyLabel = ((JSONString)config.get("emptyLabel")).stringValue(); 099 JSONArray opts = (JSONArray)config.get("options"); 100 m_options = new LinkedHashMap<String, CmsPair<String, String>>(); 101 for (int i = 0; i < opts.size(); i++) { 102 JSONObject opt = (JSONObject)opts.get(i); 103 String value = ((JSONString)opt.get("value")).stringValue(); 104 String label = ((JSONString)opt.get("label")).stringValue(); 105 String displayType = ((JSONString)opt.get("displayType")).stringValue(); 106 m_options.put(value, new CmsPair<String, String>(label, displayType)); 107 } 108 109 // Place the check above the box using a vertical panel. 110 m_selectBox.addStyleName(I_CmsWidgetsLayoutBundle.INSTANCE.widgetCss().selectBoxPanel()); 111 m_selectBox.setPopupResize(false); 112 // add some styles to parts of the selectbox. 113 m_selectBox.getOpener().addStyleName(I_CmsWidgetsLayoutBundle.INSTANCE.widgetCss().selectBoxSelected()); 114 m_selectBox.getSelectorPopup().addStyleName(I_CmsLayoutBundle.INSTANCE.globalWidgetCss().selectBoxPopup()); 115 m_selectBox.addValueChangeHandler(new ValueChangeHandler<String>() { 116 117 public void onValueChange(ValueChangeEvent<String> event) { 118 119 fireChangeEvent(); 120 121 } 122 123 }); 124 125 update(CmsContentEditor.getEntity()); 126 initWidget(m_selectBox); 127 } 128 129 /** 130 * @see com.google.gwt.event.dom.client.HasFocusHandlers#addFocusHandler(com.google.gwt.event.dom.client.FocusHandler) 131 */ 132 public HandlerRegistration addFocusHandler(FocusHandler handler) { 133 134 return addDomHandler(handler, FocusEvent.getType()); 135 } 136 137 /** 138 * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler) 139 */ 140 public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) { 141 142 return addHandler(handler, ValueChangeEvent.getType()); 143 } 144 145 /** 146 * Represents a value change event.<p> 147 * Please edit the blog entry text. 148 */ 149 public void fireChangeEvent() { 150 151 ValueChangeEvent.fire(this, m_selectBox.getFormValueAsString()); 152 153 } 154 155 /** 156 * @see org.opencms.acacia.client.widgets.I_CmsHasDisplayDirection#getDisplayingDirection() 157 */ 158 public Direction getDisplayingDirection() { 159 160 return m_selectBox.displayingAbove() ? Direction.above : Direction.below; 161 } 162 163 /** 164 * @see com.google.gwt.user.client.ui.HasValue#getValue() 165 */ 166 public String getValue() { 167 168 return m_selectBox.getFormValueAsString(); 169 } 170 171 /** 172 * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#isActive() 173 */ 174 public boolean isActive() { 175 176 return m_active; 177 } 178 179 /** 180 * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#onAttachWidget() 181 */ 182 public void onAttachWidget() { 183 184 super.onAttach(); 185 } 186 187 /** 188 * @see com.google.gwt.user.client.ui.Widget#onLoad() 189 */ 190 @Override 191 public void onLoad() { 192 193 if (m_matchTypes) { 194 update(CmsContentEditor.getEntity()); 195 196 CmsContentEditor.addEntityChangeListener(new I_CmsEntityChangeListener() { 197 198 public void onEntityChange(CmsEntity entity) { 199 200 boolean attached = RootPanel.getBodyElement().isOrHasChild(getElement()); 201 if (attached) { 202 update(CmsContentEditor.getEntity()); 203 } 204 } 205 }, null); 206 } 207 } 208 209 /** 210 * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#owns(com.google.gwt.dom.client.Element) 211 */ 212 public boolean owns(Element element) { 213 214 return getElement().isOrHasChild(element); 215 216 } 217 218 /** 219 * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setActive(boolean) 220 */ 221 public void setActive(boolean active) { 222 223 // check if value change. If not do nothing. 224 if (m_active == active) { 225 return; 226 } 227 // set new value. 228 m_active = active; 229 // set the new value to the selectbox. 230 m_selectBox.setEnabled(active); 231 // fire change event if necessary. 232 if (active) { 233 fireChangeEvent(); 234 } 235 236 } 237 238 /** 239 * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setName(java.lang.String) 240 */ 241 public void setName(String name) { 242 243 // no input field so nothing to do 244 245 } 246 247 /** 248 * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object) 249 */ 250 public void setValue(String value) { 251 252 setValue(value, false); 253 254 } 255 256 /** 257 * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object, boolean) 258 */ 259 public void setValue(String value, boolean fireEvents) { 260 261 m_selectBox.setFormValueAsString(value); 262 if (fireEvents) { 263 fireChangeEvent(); 264 } 265 266 } 267 268 /** 269 * Updates the select options from the given entity.<p> 270 * 271 * @param entity a top-level content entity 272 */ 273 public void update(CmsEntity entity) { 274 275 String filterType = NO_FILTER; 276 if (m_matchTypes) { 277 List<Object> values = CmsEntity.getValuesForPath(entity, m_valuePath); 278 if (values.size() > 1) { 279 String firstValue = (String)values.get(0); 280 CmsPair<String, String> val = m_options.get(firstValue); 281 if (val != null) { 282 filterType = val.getSecond(); 283 } 284 } 285 } 286 287 if (!filterType.equals(m_filterType)) { 288 boolean noFilter = NO_FILTER.equals(filterType); 289 Map<String, String> items = new LinkedHashMap<String, String>(); 290 // add empty option 291 items.put("", m_emptyLabel); 292 for (Entry<String, CmsPair<String, String>> optEntry : m_options.entrySet()) { 293 if (noFilter || filterType.equals(optEntry.getValue().getSecond())) { 294 items.put(optEntry.getKey(), optEntry.getValue().getFirst()); 295 } 296 } 297 replaceItems(items); 298 } 299 m_filterType = filterType; 300 } 301 302 /** 303 * Replaces the select items with the given items.<p> 304 * 305 * @param items the select items 306 */ 307 private void replaceItems(Map<String, String> items) { 308 309 String oldValue = m_selectBox.getFormValueAsString(); 310 //set value and option to the combo box. 311 m_selectBox.setItems(items); 312 if (items.containsKey(oldValue)) { 313 m_selectBox.setFormValueAsString(oldValue); 314 } 315 } 316 317 /** 318 * Splits a path into components.<p> 319 * 320 * @param path the path to split 321 * @return the path components 322 */ 323 private String[] splitPath(String path) { 324 325 path = path.replaceAll("^/", "").replaceAll("/$", ""); 326 return path.split("/"); 327 } 328 329}