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.upload;
029
030import org.opencms.gwt.client.Messages;
031import org.opencms.gwt.client.ui.CmsFlowPanel;
032import org.opencms.gwt.client.ui.I_CmsButton;
033import org.opencms.gwt.client.ui.I_CmsButton.ButtonColor;
034import org.opencms.gwt.client.ui.I_CmsButton.ButtonStyle;
035import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
036import org.opencms.gwt.client.util.CmsDomUtil;
037import org.opencms.util.CmsStringUtil;
038
039import com.google.gwt.core.client.GWT;
040import com.google.gwt.dom.client.Style.Display;
041import com.google.gwt.event.dom.client.ChangeEvent;
042import com.google.gwt.event.dom.client.ChangeHandler;
043import com.google.gwt.event.dom.client.ClickEvent;
044import com.google.gwt.event.dom.client.ClickHandler;
045import com.google.gwt.event.dom.client.MouseOutEvent;
046import com.google.gwt.event.dom.client.MouseOverEvent;
047import com.google.gwt.i18n.client.NumberFormat;
048import com.google.gwt.uibinder.client.UiBinder;
049import com.google.gwt.uibinder.client.UiField;
050import com.google.gwt.uibinder.client.UiHandler;
051import com.google.gwt.user.client.ui.Composite;
052import com.google.gwt.user.client.ui.HTML;
053import com.google.gwt.user.client.ui.HasHorizontalAlignment;
054
055/**
056 * Provides a upload button.<p>
057 *
058 * @since 8.0.0
059 */
060public class CmsUploadButton extends Composite implements HasHorizontalAlignment, I_CmsUploadButton {
061
062    /** The ui-binder interface. */
063    protected interface I_CmsUploadButtonUiBinder extends UiBinder<CmsFlowPanel, CmsUploadButton> {
064        // GWT interface, nothing to do
065    }
066
067    /** The size for kilobytes in bytes. */
068    private static final float KILOBYTE = 1024L;
069
070    /** The ui-binder for this widget. */
071    private static I_CmsUploadButtonUiBinder m_uiBinder = GWT.create(I_CmsUploadButtonUiBinder.class);
072
073    /** The button face. */
074    @UiField
075    protected HTML m_buttonFace;
076
077    /** The main panel. */
078    @UiField
079    protected CmsFlowPanel m_main;
080
081    /** The handler for the upload button. */
082    I_CmsUploadButtonHandler m_buttonHandler;
083
084    /** The file input field. */
085    CmsFileInput m_fileInput;
086
087    /** The horizontal alignment. */
088    private HorizontalAlignmentConstant m_align;
089
090    /** Stores the button style. */
091    private ButtonStyle m_buttonStyle;
092
093    /** Stores the button color. */
094    private I_CmsButton.ButtonColor m_color;
095
096    /** Flag if button is enabled. */
097    private boolean m_enabled;
098
099    /** The icon image css class. */
100    private String m_imageClass;
101
102    /** The button size. */
103    private I_CmsButton.Size m_size;
104
105    /** The current style dependent name. */
106    private String m_styleDependent;
107
108    /** The button text. */
109    private String m_text;
110
111    /** The button title. */
112    private String m_title;
113
114    /** Flag if a button minimum width should be used. */
115    private boolean m_useMinWidth;
116
117    /**
118     * The default constructor.<p>
119     *
120     * Creates a new upload button. This upload button opens a new OS file selector on click.<p>
121     *
122     * On change the button handler passed into the constructor is notified.<p>
123     *
124     * @param buttonHandler the buttonHandler
125     */
126    public CmsUploadButton(I_CmsUploadButtonHandler buttonHandler) {
127
128        org.opencms.gwt.client.ui.css.I_CmsLayoutBundle.INSTANCE.uploadButton().ensureInjected();
129        initWidget(m_uiBinder.createAndBindUi(this));
130        m_buttonHandler = buttonHandler;
131        m_buttonHandler.setButton(this);
132        m_align = HasHorizontalAlignment.ALIGN_RIGHT;
133        updateState("up");
134        m_enabled = true;
135        // set the button properties
136        setSize(I_CmsButton.Size.medium);
137        setText(Messages.get().key(Messages.GUI_UPLOAD_BUTTON_TITLE_0));
138        setTitle(Messages.get().key(Messages.GUI_UPLOAD_BUTTON_TITLE_0));
139        setButtonStyle(ButtonStyle.TEXT, ButtonColor.BLUE);
140        createFileInput();
141        // prevent click event from bubbling up to the surrounding widget
142        addDomHandler(new ClickHandler() {
143
144            public void onClick(ClickEvent event) {
145
146                event.stopPropagation();
147            }
148        }, ClickEvent.getType());
149    }
150
151    /**
152     * Formats a given bytes value (file size).<p>
153     *
154     * @param filesize the file size to format
155     *
156     * @return the formated file size in KB
157     */
158    public static String formatBytes(long filesize) {
159
160        double kByte = Math.ceil(filesize / KILOBYTE);
161        String formated = NumberFormat.getDecimalFormat().format(new Double(kByte));
162        return formated + " KB";
163    }
164
165    /**
166     * Creates and adds a file input.<p>
167     *
168     * @return returns the previous file input widget
169     */
170    public CmsFileInput createFileInput() {
171
172        // remove the current file input field and add a new one
173        CmsFileInput previous = m_fileInput;
174        if (m_fileInput != null) {
175            m_fileInput.getElement().getStyle().setDisplay(Display.NONE);
176        }
177        m_fileInput = new CmsFileInput();
178        m_fileInput.addChangeHandler(new ChangeHandler() {
179
180            public void onChange(ChangeEvent event) {
181
182                CmsDomUtil.ensureMouseOut(m_main.getElement());
183                m_buttonHandler.onChange(m_fileInput);
184            }
185        });
186        m_buttonHandler.initializeFileInput(m_fileInput);
187        m_main.add(m_fileInput);
188        return previous;
189    }
190
191    /**
192     * Disables the button and changes the button title attribute to the disabled reason.<p>
193     *
194     * @param disabledReason the disabled reason
195     */
196    public void disable(String disabledReason) {
197
198        m_enabled = false;
199        // hide the current file input field
200        if (m_fileInput != null) {
201            m_fileInput.getElement().getStyle().setDisplay(Display.NONE);
202        }
203
204        updateState("up-disabled");
205        super.setTitle(disabledReason);
206    }
207
208    /**
209     * Enables the button, switching the button title attribute from the disabled reason to the original title.<p>
210     */
211    public void enable() {
212
213        updateState("up");
214        m_enabled = true;
215        // show the current file input field
216        if (m_fileInput != null) {
217            m_fileInput.getElement().getStyle().clearDisplay();
218        }
219        super.setTitle(m_title);
220    }
221
222    /**
223     * Gets the upload button handler instance for this button.<p>
224     *
225     * @return the upload button handler
226     */
227    public I_CmsUploadButtonHandler getButtonHandler() {
228
229        return m_buttonHandler;
230    }
231
232    /**
233     * This is the alignment of the text in reference to the image, possible values are left or right.<p>
234     *
235     * @see com.google.gwt.user.client.ui.HasHorizontalAlignment#getHorizontalAlignment()
236     */
237    public HorizontalAlignmentConstant getHorizontalAlignment() {
238
239        return m_align;
240    }
241
242    /**
243     * Returns the master image class.<p>
244     *
245     * @return the master image class
246     */
247    public String getImageClass() {
248
249        return m_imageClass;
250    }
251
252    /**
253     * Returns the size.<p>
254     *
255     * @return the size
256     */
257    public I_CmsButton.Size getSize() {
258
259        return m_size;
260    }
261
262    /**
263     * Returns the text.<p>
264     *
265     * @return the text
266     */
267    public String getText() {
268
269        return m_text;
270    }
271
272    /**
273     * Returns the title.<p>
274     *
275     * @return the title
276     */
277    @Override
278    public String getTitle() {
279
280        return m_title;
281    }
282
283    /**
284     * Returns if the upload button is enabled.<p>
285     *
286     * @return <code>true</code> if the upload button is enabled
287     */
288    public boolean isEnabled() {
289
290        return m_enabled;
291    }
292
293    /**
294     * Checks if the button is constraint to a minimal width.<p>
295     *
296     * @return <code>true</code> if the button is constraint to a minimal width
297     */
298    public boolean isUseMinWidth() {
299
300        return m_useMinWidth;
301    }
302
303    /**
304     * Reinitializes the button with a new button handler.<p>
305     *
306     * @param buttonHandler the button handler
307     */
308    public void reinitButton(I_CmsUploadButtonHandler buttonHandler) {
309
310        m_buttonHandler = buttonHandler;
311        m_buttonHandler.setButton(this);
312        updateState("up");
313        m_enabled = true;
314        createFileInput();
315    }
316
317    /**
318     * Sets the button style.<p>
319     *
320     * @param style the style to set
321     * @param color the color to set
322     */
323    public void setButtonStyle(I_CmsButton.ButtonStyle style, I_CmsButton.ButtonColor color) {
324
325        if (m_buttonStyle != null) {
326            for (String styleName : m_buttonStyle.getAdditionalClasses()) {
327                removeStyleName(styleName);
328            }
329        }
330        if (style == ButtonStyle.TRANSPARENT) {
331            setSize(null);
332        }
333        addStyleName(style.getCssClassName());
334        m_buttonStyle = style;
335
336        if (m_color != null) {
337            removeStyleName(m_color.getClassName());
338        }
339        if (color != null) {
340            addStyleName(color.getClassName());
341        }
342        m_color = color;
343    }
344
345    public void setEnabled(boolean enabled, String disabledMessage) {
346
347        if (enabled) {
348            enable();
349        } else {
350            disable(disabledMessage);
351        }
352
353        // TODO Auto-generated method stub
354
355    }
356
357    /**
358     * This is the alignment of the text in reference to the image, possible values are left or right.<p>
359     *
360     * @see com.google.gwt.user.client.ui.HasHorizontalAlignment#setHorizontalAlignment(com.google.gwt.user.client.ui.HasHorizontalAlignment.HorizontalAlignmentConstant)
361     */
362    public void setHorizontalAlignment(HorizontalAlignmentConstant align) {
363
364        if (align.equals(HasHorizontalAlignment.ALIGN_CENTER)) {
365            // ignore center alignment
366            return;
367        }
368        m_align = align;
369    }
370
371    /**
372     * Sets the master image class.<p>
373     *
374     * @param imageClass the master image class to set
375     */
376    public void setImageClass(String imageClass) {
377
378        setUpFace(m_text, imageClass);
379    }
380
381    /**
382     * Sets the size.<p>
383     *
384     * @param size the size to set
385     */
386    public void setSize(I_CmsButton.Size size) {
387
388        if (m_size != null) {
389            removeStyleName(m_size.getCssClassName());
390        }
391        if (size != null) {
392            addStyleName(size.getCssClassName());
393        }
394        m_size = size;
395    }
396
397    /**
398     * Sets the text.<p>
399     *
400     * @param text the text to set
401     */
402    public void setText(String text) {
403
404        setUpFace(text, m_imageClass);
405        setTitle(text);
406    }
407
408    /**
409     * @see com.google.gwt.user.client.ui.UIObject#setTitle(java.lang.String)
410     */
411    @Override
412    public void setTitle(String title) {
413
414        m_main.setTitle(title);
415        m_title = title;
416    }
417
418    /**
419     * Sets the up face text and image.<p>
420     *
421     * @param text the up face text to set, set to <code>null</code> to not show any
422     * @param imageClass the up face image class to use, set to <code>null</code> to not show any
423     */
424    public void setUpFace(String text, String imageClass) {
425
426        m_text = text;
427        m_imageClass = imageClass;
428        m_buttonFace.setHTML(getFaceHtml(text, imageClass));
429    }
430
431    /**
432     * Tells the button to use a minimal width.<p>
433     *
434     * @param useMinWidth <code>true</code> to use a minimal width
435     */
436    public void setUseMinWidth(boolean useMinWidth) {
437
438        if (useMinWidth != m_useMinWidth) {
439            if (useMinWidth) {
440                addStyleName(I_CmsLayoutBundle.INSTANCE.buttonCss().cmsMinWidth());
441            } else {
442                removeStyleName(I_CmsLayoutBundle.INSTANCE.buttonCss().cmsMinWidth());
443            }
444            m_useMinWidth = useMinWidth;
445        }
446    }
447
448    public void updateFileInput() {
449
450        m_buttonHandler.initializeFileInput(m_fileInput);
451    }
452
453    /**
454     * Convenience method to assemble the HTML to use for a button face.<p>
455     *
456     * @param text text the up face text to set, set to <code>null</code> to not show any
457     * @param imageClass the up face image class to use, set to <code>null</code> to not show any
458     *
459     * @return the HTML
460     */
461    protected String getFaceHtml(String text, String imageClass) {
462
463        return CmsDomUtil.createFaceHtml(text, imageClass, m_align);
464    }
465
466    /**
467     * Handles the mouse over event on the main panel.<p>
468     *
469     * @param event the event
470     *
471     * @see com.google.gwt.event.dom.client.MouseOutHandler#onMouseOut(com.google.gwt.event.dom.client.MouseOutEvent)
472     */
473    @UiHandler("m_main")
474    protected void handleMouseOut(MouseOutEvent event) {
475
476        if (isEnabled()) {
477            updateState("up");
478        }
479    }
480
481    /**
482     * Handles the mouse over event on the main panel.<p>
483     *
484     * @param event the event
485     *
486     * @see com.google.gwt.event.dom.client.MouseOverHandler#onMouseOver(com.google.gwt.event.dom.client.MouseOverEvent)
487     */
488    @UiHandler("m_main")
489    protected void handleMouseOver(MouseOverEvent event) {
490
491        if (isEnabled()) {
492            updateState("up-hovering");
493        }
494    }
495
496    /**
497     * Updates the CSS classes according to the button state.<p>
498     *
499     * @param styleDependent the dependent style name
500     */
501    private void updateState(String styleDependent) {
502
503        if (CmsStringUtil.isEmptyOrWhitespaceOnly(styleDependent)) {
504            // reseting to cmsState-up
505            styleDependent = "up";
506        }
507        if (!styleDependent.equals(m_styleDependent)) {
508            m_main.removeStyleDependentName(m_styleDependent);
509            m_main.setStyleDependentName(styleDependent, true);
510            m_styleDependent = styleDependent;
511        }
512    }
513}