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.ui.editors.messagebundle; 029 030import org.opencms.i18n.CmsLocaleManager; 031import org.opencms.i18n.CmsMessages; 032import org.opencms.ui.FontOpenCms; 033import org.opencms.ui.editors.messagebundle.CmsMessageBundleEditorTypes.EditMode; 034import org.opencms.ui.editors.messagebundle.CmsMessageBundleEditorTypes.I_OptionListener; 035 036import java.util.Collection; 037import java.util.Locale; 038 039import com.vaadin.event.FieldEvents.BlurEvent; 040import com.vaadin.event.FieldEvents.BlurListener; 041import com.vaadin.event.FieldEvents.FocusEvent; 042import com.vaadin.event.FieldEvents.FocusListener; 043import com.vaadin.event.ShortcutAction.KeyCode; 044import com.vaadin.event.ShortcutListener; 045import com.vaadin.ui.Alignment; 046import com.vaadin.ui.Button; 047import com.vaadin.ui.Button.ClickEvent; 048import com.vaadin.ui.Button.ClickListener; 049import com.vaadin.ui.Component; 050import com.vaadin.ui.FormLayout; 051import com.vaadin.ui.GridLayout; 052import com.vaadin.ui.Notification; 053import com.vaadin.ui.UI; 054import com.vaadin.v7.data.Property.ValueChangeEvent; 055import com.vaadin.v7.data.Property.ValueChangeListener; 056import com.vaadin.v7.ui.ComboBox; 057import com.vaadin.v7.ui.HorizontalLayout; 058import com.vaadin.v7.ui.Label; 059import com.vaadin.v7.ui.TextField; 060 061/** View of the message bundle editor options, i.e., language/mode switcher, file name display and "Add key" option. */ 062public class CmsMessageBundleEditorOptions { 063 064 /** Messages used by the GUI. */ 065 CmsMessages m_messages; 066 067 /** Grid with all options (2x2). */ 068 private GridLayout m_optionsComponent; 069 /** The upper left component in the options grid (containing the language/mode switches and the label for the file path). */ 070 private HorizontalLayout m_upperLeftComponent; 071 /** The lower left component in the options grid (containing the "Add key" label). */ 072 private Component m_lowerLeftComponent; 073 /** The lower right component in the options grid (containing the "Add key" input field and the "Add key" button). */ 074 private Component m_lowerRightComponent; 075 /** The select box for choosing the currently edited language. */ 076 private ComboBox m_languageSelect; 077 /** The component that contains the language switch. */ 078 private Component m_languageSwitch; 079 /** The component that contains the mode switch. */ 080 private Component m_modeSwitch; 081 /** The select box for the current edit mode. */ 082 private ComboBox m_modeSelect; 083 /** The component with the label of the "File"-Display. */ 084 private Component m_filePathLabel; 085 /** The input field that displays the path of the currently edited file. */ 086 private TextField m_filePathField; 087 /** The "Add key" input field. */ 088 TextField m_addKeyInput; 089 /** A flag, indicating if the mode switch should be shown. */ 090 private boolean m_showModeSwitch; 091 /** A flag, indicating if the "Add key" row should be shown. */ 092 private boolean m_showAddKeyOption; 093 /** The listener for option changes. */ 094 I_OptionListener m_listener; 095 096 /** 097 * Default constructor. 098 * @param locales the locales shown in the language switch. 099 * @param currentLocale the currently edited locale. 100 * @param currentMode the current edit mode. 101 * @param optionListener the option listener. 102 */ 103 public CmsMessageBundleEditorOptions( 104 final Collection<Locale> locales, 105 final Locale currentLocale, 106 final EditMode currentMode, 107 final I_OptionListener optionListener) { 108 109 m_messages = Messages.get().getBundle(UI.getCurrent().getLocale()); 110 m_listener = optionListener; 111 initLanguageSwitch(locales, currentLocale); 112 initModeSwitch(currentMode); 113 initFilePathLabel(); 114 initUpperLeftComponent(); 115 initLowerLeftComponent(); 116 initLowerRightComponent(); 117 118 initOptionsComponent(); 119 } 120 121 /** 122 * Puts focus on the "Add key" input field, iff it is shown. 123 * @return <code>true</code> if the focus has been set, <code>false</code> otherwise. 124 */ 125 public boolean focusAddKey() { 126 127 if (m_showAddKeyOption) { 128 m_addKeyInput.focus(); 129 } 130 return m_showAddKeyOption; 131 } 132 133 /** 134 * Returns the options component. 135 * @return the options component. 136 */ 137 public Component getOptionsComponent() { 138 139 return m_optionsComponent; 140 } 141 142 /** 143 * Sets the path of the edited file in the corresponding display. 144 * @param editedFilePath path of the edited file to set. 145 */ 146 public void setEditedFilePath(final String editedFilePath) { 147 148 m_filePathField.setReadOnly(false); 149 m_filePathField.setValue(editedFilePath); 150 m_filePathField.setReadOnly(true); 151 152 } 153 154 /** 155 * Set the edit mode. 156 * @param mode the edit mode to set. 157 */ 158 public void setEditMode(final EditMode mode) { 159 160 if (!m_modeSelect.getValue().equals(mode)) { 161 m_modeSelect.setValue(mode); 162 } 163 } 164 165 /** 166 * Update which options are shown. 167 * @param showModeSwitch flag, indicating if the mode switch should be shown. 168 * @param showAddKeyOption flag, indicating if the "Add key" row should be shown. 169 */ 170 public void updateShownOptions(boolean showModeSwitch, boolean showAddKeyOption) { 171 172 if (showModeSwitch != m_showModeSwitch) { 173 m_upperLeftComponent.removeAllComponents(); 174 m_upperLeftComponent.addComponent(m_languageSwitch); 175 if (showModeSwitch) { 176 m_upperLeftComponent.addComponent(m_modeSwitch); 177 } 178 m_upperLeftComponent.addComponent(m_filePathLabel); 179 m_showModeSwitch = showModeSwitch; 180 } 181 if (showAddKeyOption != m_showAddKeyOption) { 182 if (showAddKeyOption) { 183 m_optionsComponent.addComponent(m_lowerLeftComponent, 0, 1); 184 m_optionsComponent.addComponent(m_lowerRightComponent, 1, 1); 185 } else { 186 m_optionsComponent.removeComponent(0, 1); 187 m_optionsComponent.removeComponent(1, 1); 188 } 189 m_showAddKeyOption = showAddKeyOption; 190 } 191 } 192 193 /** 194 * Handles adding a key. Calls the registered listener and wraps it's method in some GUI adjustments. 195 */ 196 void handleAddKey() { 197 198 String key = m_addKeyInput.getValue(); 199 if (m_listener.handleAddKey(key)) { 200 Notification.show( 201 key.isEmpty() 202 ? m_messages.key(Messages.GUI_NOTIFICATION_MESSAGEBUNDLEEDITOR_EMPTY_KEY_SUCCESSFULLY_ADDED_0) 203 : m_messages.key(Messages.GUI_NOTIFICATION_MESSAGEBUNDLEEDITOR_KEY_SUCCESSFULLY_ADDED_1, key)); 204 } else { 205 CmsMessageBundleEditorTypes.showWarning( 206 m_messages.key(Messages.GUI_NOTIFICATION_MESSAGEBUNDLEEDITOR_KEY_ALREADEY_EXISTS_CAPTION_0), 207 m_messages.key(Messages.GUI_NOTIFICATION_MESSAGEBUNDLEEDITOR_KEY_ALREADEY_EXISTS_DESCRIPTION_1, key)); 208 209 } 210 m_addKeyInput.focus(); 211 m_addKeyInput.selectAll(); 212 } 213 214 /** 215 * Sets the currently edited locale. 216 * @param locale the locale to set. 217 */ 218 void setLanguage(final Locale locale) { 219 220 if (!m_languageSelect.getValue().equals(locale)) { 221 m_languageSelect.setValue(locale); 222 } 223 } 224 225 /** 226 * Creates the "Add key" button. 227 * @return the "Add key" button. 228 */ 229 private Component createAddKeyButton() { 230 231 // the "+" button 232 Button addKeyButton = new Button(); 233 addKeyButton.addStyleName("icon-only"); 234 addKeyButton.addStyleName("borderless-colored"); 235 addKeyButton.setDescription(m_messages.key(Messages.GUI_ADD_KEY_0)); 236 addKeyButton.setIcon(FontOpenCms.CIRCLE_PLUS, m_messages.key(Messages.GUI_ADD_KEY_0)); 237 addKeyButton.addClickListener(new ClickListener() { 238 239 private static final long serialVersionUID = 1L; 240 241 public void buttonClick(ClickEvent event) { 242 243 handleAddKey(); 244 245 } 246 }); 247 return addKeyButton; 248 } 249 250 /** 251 * Creates the upper right component of the options grid. 252 * Creation includes the initialization of {@link #m_filePathField}. 253 * 254 * @return the upper right component in the options grid. 255 */ 256 private Component createUpperRightComponent() { 257 258 HorizontalLayout upperRight = new HorizontalLayout(); 259 upperRight.setSizeFull(); 260 261 FormLayout fileNameDisplay = new FormLayout(); 262 fileNameDisplay.setDefaultComponentAlignment(Alignment.MIDDLE_LEFT); 263 fileNameDisplay.setSizeFull(); 264 265 m_filePathField = new TextField(); 266 m_filePathField.setWidth("100%"); 267 m_filePathField.setEnabled(true); 268 m_filePathField.setReadOnly(true); 269 270 fileNameDisplay.addComponent(m_filePathField); 271 fileNameDisplay.setSpacing(true); 272 273 FormLayout filePathDisplay = new FormLayout(); 274 filePathDisplay.setDefaultComponentAlignment(Alignment.MIDDLE_LEFT); 275 filePathDisplay.setSizeFull(); 276 filePathDisplay.addComponent(m_filePathField); 277 filePathDisplay.setSpacing(true); 278 279 upperRight.addComponent(filePathDisplay); 280 upperRight.setExpandRatio(filePathDisplay, 2f); 281 282 HorizontalLayout placeHolder = new HorizontalLayout(); 283 placeHolder.setWidth(CmsMessageBundleEditorTypes.OPTION_COLUMN_WIDTH_PX); 284 upperRight.addComponent(placeHolder); 285 286 return upperRight; 287 } 288 289 /** 290 * Initializes the input field for new keys {@link #m_addKeyInput}. 291 */ 292 private void initAddKeyInput() { 293 294 //the input field for the key 295 m_addKeyInput = new TextField(); 296 m_addKeyInput.setWidth("100%"); 297 m_addKeyInput.setInputPrompt(m_messages.key(Messages.GUI_INPUT_PROMPT_ADD_KEY_0)); 298 final ShortcutListener shortCutListener = new ShortcutListener("Add key via ENTER", KeyCode.ENTER, null) { 299 300 private static final long serialVersionUID = 1L; 301 302 @Override 303 public void handleAction(Object sender, Object target) { 304 305 handleAddKey(); 306 307 } 308 309 }; 310 m_addKeyInput.addFocusListener(new FocusListener() { 311 312 private static final long serialVersionUID = 1L; 313 314 public void focus(FocusEvent event) { 315 316 m_addKeyInput.addShortcutListener(shortCutListener); 317 318 } 319 }); 320 m_addKeyInput.addBlurListener(new BlurListener() { 321 322 private static final long serialVersionUID = 1L; 323 324 public void blur(BlurEvent event) { 325 326 m_addKeyInput.removeShortcutListener(shortCutListener); 327 328 } 329 }); 330 331 } 332 333 /** 334 * Initializes the label for the file path display {@link #m_filePathLabel}. 335 */ 336 private void initFilePathLabel() { 337 338 m_filePathLabel = new TextField(); 339 m_filePathLabel.setWidth("100%"); 340 m_filePathLabel.setEnabled(true); 341 ((TextField)m_filePathLabel).setReadOnly(true); 342 m_filePathLabel = new Label(m_messages.key(Messages.GUI_FILENAME_LABEL_0)); 343 344 } 345 346 /** 347 * Initializes the language switcher UI Component {@link #m_languageSwitch}, including {@link #m_languageSelect}. 348 * @param locales the locales that can be selected. 349 * @param current the currently selected locale. 350 */ 351 private void initLanguageSwitch(Collection<Locale> locales, Locale current) { 352 353 FormLayout languages = new FormLayout(); 354 languages.setHeight("100%"); 355 languages.setDefaultComponentAlignment(Alignment.MIDDLE_LEFT); 356 ComboBox languageSelect = new ComboBox(); 357 languageSelect.setCaption(m_messages.key(Messages.GUI_LANGUAGE_SWITCHER_LABEL_0)); 358 languageSelect.setNullSelectionAllowed(false); 359 360 // set Locales 361 for (Locale locale : locales) { 362 languageSelect.addItem(locale); 363 String caption = locale.getDisplayName(UI.getCurrent().getLocale()); 364 if (CmsLocaleManager.getDefaultLocale().equals(locale)) { 365 caption += " (" 366 + Messages.get().getBundle(UI.getCurrent().getLocale()).key(Messages.GUI_DEFAULT_LOCALE_0) 367 + ")"; 368 } 369 languageSelect.setItemCaption(locale, caption); 370 } 371 languageSelect.setValue(current); 372 languageSelect.setNewItemsAllowed(false); 373 languageSelect.setTextInputAllowed(false); 374 languageSelect.addValueChangeListener(new ValueChangeListener() { 375 376 private static final long serialVersionUID = 1L; 377 378 public void valueChange(ValueChangeEvent event) { 379 380 m_listener.handleLanguageChange((Locale)event.getProperty().getValue()); 381 382 } 383 }); 384 385 if (locales.size() == 1) { 386 languageSelect.setEnabled(false); 387 } 388 languages.addComponent(languageSelect); 389 m_languageSwitch = languages; 390 } 391 392 /** 393 * Initializes the lower left component {@link #m_lowerLeftComponent} with the correctly placed "Add key"-label. 394 */ 395 private void initLowerLeftComponent() { 396 397 HorizontalLayout placeHolderLowerLeft = new HorizontalLayout(); 398 placeHolderLowerLeft.setWidth("100%"); 399 Label newKeyLabel = new Label(m_messages.key(Messages.GUI_CAPTION_ADD_KEY_0)); 400 newKeyLabel.setWidthUndefined(); 401 HorizontalLayout lowerLeft = new HorizontalLayout(placeHolderLowerLeft, newKeyLabel); 402 lowerLeft.setWidth("100%"); 403 lowerLeft.setExpandRatio(placeHolderLowerLeft, 1f); 404 m_lowerLeftComponent = lowerLeft; 405 406 } 407 408 /** 409 * Initializes the lower right component {@link #m_lowerRightComponent}, with all its components, i.e., 410 * the "Add key" input field {@link #m_addKeyInput} and the "Add key" button. 411 */ 412 private void initLowerRightComponent() { 413 414 initAddKeyInput(); 415 416 Component addKeyButton = createAddKeyButton(); 417 HorizontalLayout addKeyWrapper = new HorizontalLayout(addKeyButton); 418 addKeyWrapper.setComponentAlignment(addKeyButton, Alignment.MIDDLE_CENTER); 419 addKeyWrapper.setHeight("100%"); 420 addKeyWrapper.setWidth(CmsMessageBundleEditorTypes.OPTION_COLUMN_WIDTH_PX); 421 422 FormLayout inputForm = new FormLayout(m_addKeyInput); 423 inputForm.setWidth("100%"); 424 HorizontalLayout lowerRight = new HorizontalLayout(); 425 lowerRight.setWidth("100%"); 426 lowerRight.addComponent(inputForm); 427 lowerRight.addComponent(addKeyWrapper); 428 lowerRight.setExpandRatio(inputForm, 1f); 429 m_lowerRightComponent = lowerRight; 430 431 } 432 433 /** 434 * Initializes the mode switcher. 435 * @param current the current edit mode 436 */ 437 private void initModeSwitch(final EditMode current) { 438 439 FormLayout modes = new FormLayout(); 440 modes.setHeight("100%"); 441 modes.setDefaultComponentAlignment(Alignment.MIDDLE_LEFT); 442 443 m_modeSelect = new ComboBox(); 444 m_modeSelect.setCaption(m_messages.key(Messages.GUI_VIEW_SWITCHER_LABEL_0)); 445 446 // add Modes 447 m_modeSelect.addItem(CmsMessageBundleEditorTypes.EditMode.DEFAULT); 448 m_modeSelect.setItemCaption( 449 CmsMessageBundleEditorTypes.EditMode.DEFAULT, 450 m_messages.key(Messages.GUI_VIEW_SWITCHER_EDITMODE_DEFAULT_0)); 451 m_modeSelect.addItem(CmsMessageBundleEditorTypes.EditMode.MASTER); 452 m_modeSelect.setItemCaption( 453 CmsMessageBundleEditorTypes.EditMode.MASTER, 454 m_messages.key(Messages.GUI_VIEW_SWITCHER_EDITMODE_MASTER_0)); 455 456 // set current mode as selected 457 m_modeSelect.setValue(current); 458 459 m_modeSelect.setNewItemsAllowed(false); 460 m_modeSelect.setTextInputAllowed(false); 461 m_modeSelect.setNullSelectionAllowed(false); 462 463 m_modeSelect.addValueChangeListener(new ValueChangeListener() { 464 465 private static final long serialVersionUID = 1L; 466 467 public void valueChange(ValueChangeEvent event) { 468 469 m_listener.handleModeChange((EditMode)event.getProperty().getValue()); 470 471 } 472 }); 473 474 modes.addComponent(m_modeSelect); 475 m_modeSwitch = modes; 476 } 477 478 /** 479 * Creates the complete options component. 480 * It's a grid with two rows and two columns, styled like: 481 * 482 * || 483 * [language switch] [mode switch] File-Label || [file path display] 484 * -------------------------------------------||---------------------------------- 485 * New-Key-Label || [new key input] [add key button] 486 * || 487 * 488 * NOTE: The second row is not filled with components on initialization, what means keys can not be added 489 * Filling is done via {@link #updateShownOptions(boolean, boolean)} 490 */ 491 private void initOptionsComponent() { 492 493 // create and layout the component 494 m_optionsComponent = new GridLayout(2, 2); 495 m_optionsComponent.setHideEmptyRowsAndColumns(true); 496 m_optionsComponent.setDefaultComponentAlignment(Alignment.MIDDLE_RIGHT); 497 m_optionsComponent.setWidth("100%"); 498 m_optionsComponent.setColumnExpandRatio(1, 1f); 499 m_optionsComponent.setStyleName("v-options"); 500 501 // add the components 502 m_optionsComponent.addComponent(m_upperLeftComponent, 0, 0); 503 504 Component upperRight = createUpperRightComponent(); 505 m_optionsComponent.addComponent(upperRight, 1, 0); 506 } 507 508 /** 509 * Initializes the upper left component. Does not show the mode switch. 510 */ 511 private void initUpperLeftComponent() { 512 513 m_upperLeftComponent = new HorizontalLayout(); 514 m_upperLeftComponent.setHeight("100%"); 515 m_upperLeftComponent.setSpacing(true); 516 m_upperLeftComponent.setDefaultComponentAlignment(Alignment.MIDDLE_RIGHT); 517 m_upperLeftComponent.addComponent(m_languageSwitch); 518 m_upperLeftComponent.addComponent(m_filePathLabel); 519 520 } 521 522}