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.gwt.client.ui.input;
029
030import org.opencms.gwt.client.I_CmsHasInit;
031import org.opencms.gwt.client.ui.I_CmsAutoHider;
032import org.opencms.gwt.client.ui.css.I_CmsInputCss;
033import org.opencms.gwt.client.ui.css.I_CmsInputLayoutBundle;
034import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
035import org.opencms.gwt.client.ui.input.form.CmsWidgetFactoryRegistry;
036import org.opencms.gwt.client.ui.input.form.I_CmsFormWidgetFactory;
037import org.opencms.gwt.client.util.CmsDomUtil;
038import org.opencms.gwt.client.util.CmsExtendedValueChangeEvent;
039import org.opencms.util.CmsStringUtil;
040
041import java.util.ArrayList;
042import java.util.List;
043import java.util.Map;
044
045import com.google.common.base.Objects;
046import com.google.common.base.Optional;
047import com.google.gwt.dom.client.Style.Unit;
048import com.google.gwt.event.dom.client.BlurEvent;
049import com.google.gwt.event.dom.client.BlurHandler;
050import com.google.gwt.event.dom.client.ClickEvent;
051import com.google.gwt.event.dom.client.ClickHandler;
052import com.google.gwt.event.dom.client.FocusEvent;
053import com.google.gwt.event.dom.client.FocusHandler;
054import com.google.gwt.event.dom.client.HasBlurHandlers;
055import com.google.gwt.event.dom.client.HasClickHandlers;
056import com.google.gwt.event.dom.client.HasFocusHandlers;
057import com.google.gwt.event.dom.client.HasKeyPressHandlers;
058import com.google.gwt.event.dom.client.KeyCodes;
059import com.google.gwt.event.dom.client.KeyPressEvent;
060import com.google.gwt.event.dom.client.KeyPressHandler;
061import com.google.gwt.event.dom.client.KeyUpEvent;
062import com.google.gwt.event.dom.client.KeyUpHandler;
063import com.google.gwt.event.dom.client.MouseOutEvent;
064import com.google.gwt.event.dom.client.MouseOutHandler;
065import com.google.gwt.event.dom.client.MouseOverEvent;
066import com.google.gwt.event.dom.client.MouseOverHandler;
067import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
068import com.google.gwt.event.logical.shared.ValueChangeEvent;
069import com.google.gwt.event.logical.shared.ValueChangeHandler;
070import com.google.gwt.event.shared.HandlerRegistration;
071import com.google.gwt.user.client.Event;
072import com.google.gwt.user.client.ui.Composite;
073import com.google.gwt.user.client.ui.FlowPanel;
074import com.google.gwt.user.client.ui.TextBox;
075
076/**
077 * Basic text box class for forms.
078 *
079 * @since 8.0.0
080 *
081 */
082public class CmsTextBox extends Composite
083implements I_CmsFormWidget, I_CmsHasInit, HasFocusHandlers, HasBlurHandlers, HasValueChangeHandlers<String>,
084HasKeyPressHandlers, HasClickHandlers, I_CmsHasBlur, I_CmsHasGhostValue {
085
086    /**
087     * Event handler for this text box.<p>
088     */
089    private class TextBoxHandler
090    implements MouseOverHandler, MouseOutHandler, FocusHandler, BlurHandler, ValueChangeHandler<String>, KeyUpHandler {
091
092        /** The current text box value. */
093        private String m_currentValue;
094
095        /** True if the text box is focused. */
096        private boolean m_focus;
097
098        /**
099         * Constructor.<p>
100         *
101         * @param currentValue the current text box value
102         */
103        protected TextBoxHandler(String currentValue) {
104
105            m_currentValue = currentValue;
106            if (m_currentValue == null) {
107                m_currentValue = "";
108            }
109        }
110
111        /**
112         * Gets the value.<p>
113         *
114         * @return the value
115         */
116        public String getValue() {
117
118            return m_currentValue;
119        }
120
121        /**
122         * @see com.google.gwt.event.dom.client.BlurHandler#onBlur(com.google.gwt.event.dom.client.BlurEvent)
123         */
124        public void onBlur(BlurEvent event) {
125
126            m_focus = false;
127            ValueChangeEvent.fire(CmsTextBox.this, m_currentValue); // need this to trigger validation
128            updateGhostStyle();
129        }
130
131        /**
132         * @see com.google.gwt.event.dom.client.FocusHandler#onFocus(com.google.gwt.event.dom.client.FocusEvent)
133         */
134        @SuppressWarnings("synthetic-access")
135        public void onFocus(FocusEvent event) {
136
137            if (CmsStringUtil.isEmpty(m_currentValue) && m_clearOnChangeMode) {
138                m_textbox.setValue("");
139            }
140            m_focus = true;
141            CmsDomUtil.fireFocusEvent(CmsTextBox.this);
142            updateGhostStyle();
143        }
144
145        /**
146         * @see com.google.gwt.event.dom.client.KeyUpHandler#onKeyUp(com.google.gwt.event.dom.client.KeyUpEvent)
147         */
148        public void onKeyUp(KeyUpEvent event) {
149
150            actionChangeTextFieldValue(m_textbox.getValue(), true);
151
152        }
153
154        /**
155         * @see com.google.gwt.event.dom.client.MouseOutHandler#onMouseOut(com.google.gwt.event.dom.client.MouseOutEvent)
156         */
157        public void onMouseOut(MouseOutEvent event) {
158
159            hideError();
160        }
161
162        /**
163         * @see com.google.gwt.event.dom.client.MouseOverHandler#onMouseOver(com.google.gwt.event.dom.client.MouseOverEvent)
164         */
165        public void onMouseOver(MouseOverEvent event) {
166
167            if (!isPreventShowError()) {
168                showError();
169            }
170        }
171
172        /**
173         * @see com.google.gwt.event.logical.shared.ValueChangeHandler#onValueChange(ValueChangeEvent event)
174         */
175        public void onValueChange(ValueChangeEvent<String> event) {
176
177            actionChangeTextFieldValue(event.getValue(), false);
178
179        }
180
181        /**
182         * Sets the current value.<p>
183         *
184         * @param value the current value
185         * @param inhibitValidation true if validation should be inhibited
186         */
187        public void setValue(String value, boolean inhibitValidation) {
188
189            if (value == null) {
190                value = "";
191            }
192            if (!Objects.equal(value, m_currentValue)) {
193                m_currentValue = value;
194                CmsExtendedValueChangeEvent<String> event = new CmsExtendedValueChangeEvent<String>(value);
195                event.setInhibitValidation(inhibitValidation);
196                fireEvent(event);
197            }
198        }
199
200        /**
201         * Updates the ghost style and text box content depending on the real and ghost value.<p>
202         */
203        protected void updateGhostStyle() {
204
205            if (CmsStringUtil.isEmpty(m_currentValue)) {
206                if (CmsStringUtil.isEmpty(m_ghostValue)) {
207                    updateTextBox("");
208                    return;
209                }
210                if (!m_focus) {
211                    setGhostStyleEnabled(true);
212                    updateTextBox(m_ghostValue);
213                } else {
214                    // don't show ghost mode while focused
215                    setGhostStyleEnabled(false);
216                }
217            } else {
218                setGhostStyleEnabled(false);
219                updateTextBox(m_currentValue);
220            }
221
222        }
223
224        /**
225         * This method is called when the value in the text box is changed.<p>
226         *
227         * @param value the new value
228         * @param inhibitValidation true if validation should be inhibited
229         */
230        private void actionChangeTextFieldValue(String value, boolean inhibitValidation) {
231
232            if (m_focus) {
233                setValue(value, inhibitValidation);
234                updateGhostStyle();
235            }
236        }
237
238        /**
239         * Updates the value in the text box.<p>
240         *
241         * @param value the new value
242         */
243        private void updateTextBox(String value) {
244
245            if (!Objects.equal(m_textbox.getValue(), value)) {
246                m_textbox.setValue(value);
247            }
248        }
249    }
250
251    /** The CSS bundle used for this widget. */
252    public static final I_CmsInputCss CSS = I_CmsInputLayoutBundle.INSTANCE.inputCss();
253
254    /** The widget type identifier for this widget. */
255    public static final String WIDGET_TYPE = "string";
256
257    /** Key codes for functional keys. */
258    protected static final int[] NAVIGATION_CODES = {
259        KeyCodes.KEY_ALT,
260        KeyCodes.KEY_CTRL,
261        KeyCodes.KEY_DOWN,
262        KeyCodes.KEY_END,
263        KeyCodes.KEY_ENTER,
264        KeyCodes.KEY_ESCAPE,
265        KeyCodes.KEY_HOME,
266        KeyCodes.KEY_LEFT,
267        KeyCodes.KEY_RIGHT,
268        KeyCodes.KEY_SHIFT,
269        KeyCodes.KEY_TAB,
270        KeyCodes.KEY_UP};
271
272    /** Default pseudo-padding for text boxes. */
273    private static final int DEFAULT_PADDING = 4;
274
275    /** A counter used for giving text box widgets ids. */
276    private static int idCounter;
277
278    /** The ghost value. */
279    protected String m_ghostValue;
280
281    /** The text box used internally by this widget. */
282    protected TextBox m_textbox = new TextBox();
283
284    /** Flag which controls whether validation should be inhibited when value change events are fired as a consequence of key presses. */
285    boolean m_inhibitValidationForKeypresses;
286
287    /** Flag indicating if the text box should be cleared when leaving the ghost mode. */
288    private boolean m_clearOnChangeMode;
289
290    /** A list of the click handler registrations for this text box. */
291    private List<HandlerRegistration> m_clickHandlerRegistrations = new ArrayList<HandlerRegistration>();
292
293    /** A list of the click handlers for this text box. */
294    private List<ClickHandler> m_clickHandlers = new ArrayList<ClickHandler>();
295
296    /** Stores the enable/disable state of the textbox. */
297    private boolean m_enabled;
298
299    /** The error display for this widget. */
300    private CmsErrorWidget m_error = new CmsErrorWidget();
301
302    /** The width of the error message. */
303    private String m_errorMessageWidth;
304
305    /** The text box handler instance. */
306    private TextBoxHandler m_handler;
307
308    /** The container for the textbox container and error widget. */
309    private FlowPanel m_panel = new FlowPanel();
310
311    /** Signals whether the error message will be shown on mouse over. */
312    private boolean m_preventShowError;
313
314    /** The container for the text box. */
315    private FlowPanel m_textboxContainer = new FlowPanel();
316
317    /** Flag indicating if the value change event should also be fired after key press events. */
318    private boolean m_triggerChangeOnKeyPress;
319
320    /**
321     * Constructs a new instance of this widget.
322     */
323    public CmsTextBox() {
324
325        this(new TextBox());
326    }
327
328    /**
329     * Creates a new text box based on an underlying GWT text box instance.<p>
330     *
331     * @param textbox the GWT text box instance to wrap
332     */
333    public CmsTextBox(TextBox textbox) {
334
335        m_textbox = textbox;
336        setEnabled(true);
337        m_textbox.setStyleName(CSS.textBox());
338        m_textbox.getElement().setId("CmsTextBox_" + (idCounter++));
339
340        TextBoxHandler handler = new TextBoxHandler("");
341        m_textbox.addMouseOverHandler(handler);
342        m_textbox.addMouseOutHandler(handler);
343        m_textbox.addFocusHandler(handler);
344        m_textbox.addBlurHandler(handler);
345        m_textbox.addValueChangeHandler(handler);
346        //m_textbox.addKeyPressHandler(handler);
347        m_textbox.addKeyUpHandler(handler);
348
349        m_handler = handler;
350
351        m_textboxContainer.setStyleName(CSS.textBoxPanel());
352        m_textboxContainer.addStyleName(I_CmsLayoutBundle.INSTANCE.generalCss().cornerAll());
353        m_textboxContainer.addStyleName(I_CmsLayoutBundle.INSTANCE.generalCss().textMedium());
354        m_panel.add(m_textboxContainer);
355        m_panel.add(m_error);
356        m_textboxContainer.add(m_textbox);
357        sinkEvents(Event.ONPASTE);
358        initWidget(m_panel);
359
360    }
361
362    /**
363     * Initializes this class.<p>
364     */
365    public static void initClass() {
366
367        // registers a factory for creating new instances of this widget
368        CmsWidgetFactoryRegistry.instance().registerFactory(WIDGET_TYPE, new I_CmsFormWidgetFactory() {
369
370            /**
371             * @see org.opencms.gwt.client.ui.input.form.I_CmsFormWidgetFactory#createWidget(java.util.Map, com.google.common.base.Optional)
372             */
373            public I_CmsFormWidget createWidget(Map<String, String> widgetParams, Optional<String> defaultValue) {
374
375                return new CmsTextBox().colorWhite();
376            }
377        });
378    }
379
380    /**
381     * @see com.google.gwt.event.dom.client.HasBlurHandlers#addBlurHandler(com.google.gwt.event.dom.client.BlurHandler)
382     */
383    public HandlerRegistration addBlurHandler(BlurHandler handler) {
384
385        return m_textbox.addBlurHandler(handler);
386    }
387
388    /**
389     * @see com.google.gwt.event.dom.client.HasClickHandlers#addClickHandler(com.google.gwt.event.dom.client.ClickHandler)
390     */
391    public HandlerRegistration addClickHandler(ClickHandler handler) {
392
393        HandlerRegistration registration = addDomHandler(handler, ClickEvent.getType());
394        m_clickHandlerRegistrations.add(registration);
395        m_clickHandlers.add(handler);
396        return registration;
397    }
398
399    /**
400     * @see com.google.gwt.event.dom.client.HasFocusHandlers#addFocusHandler(com.google.gwt.event.dom.client.FocusHandler)
401     */
402    public HandlerRegistration addFocusHandler(FocusHandler handler) {
403
404        return m_textbox.addFocusHandler(handler);
405    }
406
407    /**
408     * @see com.google.gwt.event.dom.client.HasKeyPressHandlers#addKeyPressHandler(com.google.gwt.event.dom.client.KeyPressHandler)
409     */
410    public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) {
411
412        return addDomHandler(handler, KeyPressEvent.getType());
413    }
414
415    /**
416     * Adds a handler for the keyup event.<p>
417     *
418     * @param handler the handler
419     * @return the handler registration
420     */
421    public HandlerRegistration addKeyUpHandler(KeyUpHandler handler) {
422
423        return addDomHandler(handler, KeyUpEvent.getType());
424    }
425
426    /**
427     * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler)
428     */
429    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
430
431        return addHandler(handler, ValueChangeEvent.getType());
432
433    }
434
435    /**
436     * @see org.opencms.gwt.client.ui.input.I_CmsHasBlur#blur()
437     */
438    public void blur() {
439
440        m_textbox.getElement().blur();
441    }
442
443    /**
444     * Sets the background color to white.<p>
445     *
446     * @return this widget
447     */
448    public CmsTextBox colorWhite() {
449
450        getTextBoxContainer().addStyleName(I_CmsInputLayoutBundle.INSTANCE.inputCss().textBoxPanelWhite());
451        return this;
452    }
453
454    /**
455     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#getApparentValue()
456     */
457    public String getApparentValue() {
458
459        String result = m_textbox.getValue();
460        if (CmsStringUtil.isEmpty(result)) {
461            result = null;
462        }
463        return result;
464    }
465
466    /**
467     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#getFieldType()
468     */
469    public FieldType getFieldType() {
470
471        return I_CmsFormWidget.FieldType.STRING;
472    }
473
474    /**
475     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#getFormValue()
476     */
477    public Object getFormValue() {
478
479        return m_handler.getValue();
480    }
481
482    /**
483     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#getFormValueAsString()
484     */
485    public String getFormValueAsString() {
486
487        return (String)getFormValue();
488    }
489
490    /**
491     * Returns the HTML id of the internal textbox used by this widget.<p>
492     *
493     * @return the HTML id of the internal textbox used by this widget
494     */
495    public String getId() {
496
497        return m_textbox.getElement().getId();
498    }
499
500    /**
501     * Returns the text in the text box.<p>
502     *
503     * @return the text
504     */
505    public String getText() {
506
507        return m_textbox.getText();
508    }
509
510    /**
511     * Returns the Textbox of this widget.<p>
512     *
513     * @return the CmsTextBox
514     */
515    public TextBox getTextBox() {
516
517        return m_textbox;
518    }
519
520    /**
521     * Returns the Panel of this widget.<p>
522     *
523     * @return the Panel
524     */
525    public FlowPanel getTextBoxContainer() {
526
527        return m_textboxContainer;
528    }
529
530    /**
531     * Returns <code>true</code> if this textbox has an error set.<p>
532     *
533     * @return <code>true</code> if this textbox has an error set
534     */
535    public boolean hasError() {
536
537        return m_error.hasError();
538    }
539
540    /**
541     * Gets whether this widget is enabled.
542     *
543     * @return <code>true</code> if the widget is enabled
544     */
545    public boolean isEnabled() {
546
547        return m_enabled;
548    }
549
550    /**
551     * Returns the preventShowError.<p>
552     *
553     * @return the preventShowError
554     */
555    public boolean isPreventShowError() {
556
557        return m_preventShowError;
558    }
559
560    /**
561     * Returns the read only flag.<p>
562     *
563     * @return <code>true</code> if this text box is only readable
564     */
565    public boolean isReadOnly() {
566
567        return m_textbox.isReadOnly();
568    }
569
570    /**
571     * Returns if the text box is set to trigger the value changed event on key press and not on blur only.<p>
572     *
573     * @return <code>true</code> if the text box is set to trigger the value changed event on key press
574     */
575    public boolean isTriggerChangeOnKeyPress() {
576
577        return m_triggerChangeOnKeyPress;
578    }
579
580    /**
581     * @see com.google.gwt.user.client.ui.Composite#onBrowserEvent(com.google.gwt.user.client.Event)
582     */
583    @Override
584    public void onBrowserEvent(Event event) {
585
586        super.onBrowserEvent(event);
587        /*
588         * In IE8, the change event is not fired if we switch to another application window after having
589         * pasted some text into the text box, so we need to turn off ghost mode manually
590         */
591        if (event.getTypeInt() == Event.ONPASTE) {
592            setGhostMode(false);
593        }
594    }
595
596    /**
597     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#reset()
598     */
599    public void reset() {
600
601        m_textbox.setText("");
602    }
603
604    /**
605     * Selects text in the text box.<p>
606     */
607    public void selectAll() {
608
609        m_textbox.selectAll();
610    }
611
612    /**
613     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#setAutoHideParent(org.opencms.gwt.client.ui.I_CmsAutoHider)
614     */
615    public void setAutoHideParent(I_CmsAutoHider autoHideParent) {
616
617        // nothing to do
618    }
619
620    /**
621     * Sets the changed style on the text box.<p>
622     */
623    public void setChangedStyle() {
624
625        m_textbox.addStyleName(CSS.changed());
626    }
627
628    /**
629     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#setEnabled(boolean)
630     */
631    public void setEnabled(boolean enabled) {
632
633        if (!m_enabled && enabled) {
634            // if the state changed to enable then add the stored handlers
635            // copy the stored handlers into a new list to avoid concurred access to the list
636            List<ClickHandler> handlers = new ArrayList<ClickHandler>(m_clickHandlers);
637            m_clickHandlers.clear();
638            for (ClickHandler handler : handlers) {
639                addClickHandler(handler);
640            }
641            m_textboxContainer.removeStyleName(CSS.textBoxPanelDisabled());
642            m_enabled = true;
643        } else if (m_enabled && !enabled) {
644            // if state changed to disable then remove all click handlers
645            for (HandlerRegistration registration : m_clickHandlerRegistrations) {
646                registration.removeHandler();
647            }
648            m_clickHandlerRegistrations.clear();
649            m_textboxContainer.addStyleName(CSS.textBoxPanelDisabled());
650            setErrorMessage(null);
651            m_enabled = false;
652        }
653        m_textbox.setEnabled(m_enabled);
654    }
655
656    /**
657     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#setErrorMessage(java.lang.String)
658     */
659    public void setErrorMessage(String errorMessage) {
660
661        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(errorMessage)) {
662            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_errorMessageWidth)) {
663                m_error.setWidth(m_errorMessageWidth);
664            } else {
665                int width = getOffsetWidth() - 8;
666                width = width > 0 ? width : 100;
667                m_error.setWidth(width + Unit.PX.toString());
668            }
669            m_textboxContainer.removeStyleName(CSS.textBoxPanel());
670            m_textboxContainer.addStyleName(CSS.textBoxPanelError());
671        } else {
672            m_textboxContainer.removeStyleName(CSS.textBoxPanelError());
673            m_textboxContainer.addStyleName(CSS.textBoxPanel());
674        }
675        m_error.setText(errorMessage);
676    }
677
678    /**
679     * Sets the width of the error message for this textbox.<p>
680     *
681     * @param width the object's new width, in CSS units (e.g. "10px", "1em")
682     */
683    public void setErrorMessageWidth(String width) {
684
685        m_errorMessageWidth = width;
686    }
687
688    /**
689     * Sets the focus on the text box.<p>
690     *
691     * @param focused signals if the focus should be set
692     */
693    public void setFocus(boolean focused) {
694
695        m_textbox.setFocus(focused);
696    }
697
698    /**
699     * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#setFormValueAsString(java.lang.String)
700     */
701    public void setFormValueAsString(String newValue) {
702
703        m_handler.setValue(newValue, false);
704        m_handler.updateGhostStyle();
705    }
706
707    /**
708     * Enables or disables ghost mode.<p>
709     *
710     * @param ghostMode if true, enables ghost mode, else disables it
711     */
712    public void setGhostMode(boolean ghostMode) {
713
714        // do nothing
715    }
716
717    /**
718     * Sets if the input field should be cleared when leaving the ghost mode.<p>
719     *
720     * @param clearOnChangeMode <code>true</code> to clear on leaving the ghost mode
721     */
722    public void setGhostModeClear(boolean clearOnChangeMode) {
723
724        m_clearOnChangeMode = clearOnChangeMode;
725    }
726
727    /**
728     * Enables or disables the "ghost mode" style.<p>
729     *
730     * This *only* changes the style, not the actual mode.
731     *
732     * @param enabled <code>true</code> if the ghost mode style should be enabled, false if it should be disabled
733     */
734    public void setGhostStyleEnabled(boolean enabled) {
735
736        if (enabled) {
737            m_textbox.addStyleName(CSS.textboxGhostMode());
738        } else {
739            m_textbox.removeStyleName(CSS.textboxGhostMode());
740        }
741    }
742
743    /**
744     * @see org.opencms.gwt.client.ui.input.I_CmsHasGhostValue#setGhostValue(java.lang.String, boolean)
745     */
746    public void setGhostValue(String value, boolean ghostMode) {
747
748        m_ghostValue = value;
749        m_handler.updateGhostStyle();
750    }
751
752    /**
753     * Sets the 'inhibitValidationForKeypresses' flag.<p>
754     *
755     * @param inhibitValidationForKeypresses the new flag value
756     */
757    public void setInhibitValidationForKeypresses(boolean inhibitValidationForKeypresses) {
758
759        m_inhibitValidationForKeypresses = inhibitValidationForKeypresses;
760    }
761
762    /**
763     * Sets the name of the input box.
764     *
765     * @param name of the input box
766     * */
767    public void setName(String name) {
768
769        m_textbox.setName(name);
770    }
771
772    /**
773     * Sets the preventShowError.<p>
774     *
775     * @param preventShowError the preventShowError to set
776     */
777    public void setPreventShowError(boolean preventShowError) {
778
779        m_preventShowError = preventShowError;
780        if (preventShowError) {
781            m_error.setErrorVisible(false);
782        }
783    }
784
785    /**
786     * Enables or disables read-only mode.<p>
787     *
788     * @param readOnly if true, enables read-only mode, else disables it
789     */
790    public void setReadOnly(boolean readOnly) {
791
792        m_textbox.setReadOnly(readOnly);
793        if (readOnly) {
794            addStyleName(CSS.textBoxReadOnly());
795        } else {
796            removeStyleName(CSS.textBoxReadOnly());
797        }
798    }
799
800    /**
801     * Sets if the value changed event should be triggered on key press and not on blur only.<p>
802     *
803     * @param triggerOnKeyPress <code>true</code> if the value changed event should be triggered on key press
804     */
805    public void setTriggerChangeOnKeyPress(boolean triggerOnKeyPress) {
806
807        m_triggerChangeOnKeyPress = triggerOnKeyPress;
808    }
809
810    /**
811     * Fires a value change event.<p>
812     */
813    protected void fireValueChangedEvent() {
814
815        fireValueChangedEvent(false);
816    }
817
818    /**
819     * Helper method for firing a 'value changed' event.<p>
820     *
821     * @param inhibitValidation if true, some additional information will be added to the event to ask event handlers to not perform any validation directly
822     */
823    protected void fireValueChangedEvent(boolean inhibitValidation) {
824
825        if (!inhibitValidation) {
826            ValueChangeEvent.fire(this, getFormValueAsString());
827        } else {
828            CmsExtendedValueChangeEvent<String> e = new CmsExtendedValueChangeEvent<String>(getFormValueAsString());
829            e.setInhibitValidation(true);
830            fireEvent(e);
831        }
832    }
833
834    /**
835     * Hides the error for this textbox.<p>
836     */
837    protected void hideError() {
838
839        m_error.hideError();
840    }
841
842    /**
843     * Checks if the given key code represents a functional key.<p>
844     *
845     * @param keyCode the key code to check
846     *
847     * @return <code>true</code> if the given key code represents a functional key
848     */
849    protected boolean isNavigationKey(int keyCode) {
850
851        for (int i = 0; i < NAVIGATION_CODES.length; i++) {
852            if (NAVIGATION_CODES[i] == keyCode) {
853                return true;
854            }
855        }
856        return false;
857    }
858
859    /**
860     * Shows the error for this textbox.<p>
861     */
862    protected void showError() {
863
864        m_error.showError();
865    }
866
867}