All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.webui.jsf.component.FileChooser Maven / Gradle / Ivy

There is a newer version: 4.4.0.1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2007-2018 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://oss.oracle.com/licenses/CDDL+GPL-1.1
 * or LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.webui.jsf.component;

import com.sun.faces.annotation.Component;
import com.sun.faces.annotation.Property;
import com.sun.webui.jsf.model.FileChooserModel;
import com.sun.webui.jsf.model.Option;
import com.sun.webui.jsf.model.ResourceItem;
import com.sun.webui.jsf.model.ResourceModel;
import com.sun.webui.jsf.model.ResourceModelException;
import com.sun.webui.jsf.theme.ThemeStyles;
import com.sun.webui.jsf.theme.ThemeImages;
import com.sun.webui.jsf.util.ThemeUtilities;
import com.sun.webui.jsf.util.LogUtil;
import com.sun.webui.jsf.util.ClientSniffer;
import com.sun.webui.jsf.util.ComponentUtilities;
import com.sun.webui.jsf.util.ConversionUtilities;
import com.sun.webui.jsf.validator.FileChooserLookInValidator;
import com.sun.webui.jsf.validator.FileChooserFilterValidator;
import com.sun.webui.jsf.validator.FileChooserSelectValidator;
import com.sun.webui.jsf.validator.FileChooserSortValidator;
import com.sun.webui.theme.Theme;
import java.io.File;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.LinkedList;
import java.util.Vector;

import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.application.FacesMessage;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.component.UIComponentBase; /* For javadoc */
import javax.faces.component.NamingContainer;
import javax.faces.component.ValueHolder;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.event.ValueChangeEvent;
import javax.faces.render.Renderer;
import javax.faces.validator.ValidatorException;

// The file chooser poses several problems when trying to integrate
// with the JSF lifecycle. As an EditableValueHolder it must
// provide a value and allow it to be edited. This includes having a
// submittedValue, validation and model updating.
// 
// However, it also supports several actions to allow the user to
// navigate a filesystem directory tree, including an initial directory
// called the look in field, a filter field to filter the directory
// contents, a sort menu allowing the user to sort the contents of
// the directory, a moveup button (displaye parent directory contents)
// and an open folder button to navigate a filesystem tree.
//
// In addition it must conform to SWAED guidelines in the appearance
// and behavior of the basic component as well as in context
// with other components.
//
// Handling the submittedValue
//
// The submittedValue is the sole means by which the component 
// determines that it has selections. It is only at this time that
// the file chooser participates in the full JSF lifecycle.
//
// All other actions are intermediate and perform only the necessary
// validations associated with those actions.
//
// Actions
//
// OpenFolder
//
//    This serves as the action handler for the followin actions
//    - return key pressed in the look in field
//    - return key pressed in the filter field
//    - double clicking a folder in the list box
//    - return key pressed in the listbox with a folder selection
//    - the open folder button clicked
//
// MoveUp
//
//    - uses the current lookin field value. First ensures it is 
//      valid. Must also ensure the validity of the filter field as well.
//
// Sort
//
//    - uses the current lookin field value. First ensures it is 
//      valid. Must also ensure the validity of the filter field as well.
//
// LookInField
//
//    - Effectively validated on every request.
//
// Filter
//
//    - Effectively validated on every request.
//
// FIXME: The model is used as a persistant store and is being
// referenced in preference to the subcompoents which containt
// the current data. The model must be stateless and data
// must be obtained from the sub components and respect
// their validity by checking the submittedValue if the
// component is not valid and then the component's value
// if it is valid. The model should only be used to validate
// and obtain contents.
//
/**
 * The FileChooser component allows the user to select files and folders.
 */
@Component(type = "com.sun.webui.jsf.FileChooser", family = "com.sun.webui.jsf.FileChooser",
displayName = "File Chooser", tagName = "fileChooser",
helpKey = "projrave_ui_elements_palette_wdstk-jsf1.2_file_chooser",
propertiesHelpKey = "projrave_ui_elements_palette_wdstk-jsf1.2_propsheets_file_chooser_props")
public class FileChooser extends WebuiInput implements NamingContainer {

    // These should be model constants.
    //
    /**
     * Alphabetic sort field type
     */
    public static final String ALPHABETIC = "alphabetic";
    public static final String ALPHABETIC_ASC = "alphabetica";
    public static final String ALPHABETIC_DSC = "alphabeticd";
    /**
     * Sort "by size" field type
     */
    public static final String SIZE = "size";
    public static final String SIZE_ASC = "sizea";
    public static final String SIZE_DSC = "sized";
    /**
     * Sort "by last modified" field type
     */
    public static final String LASTMODIFIED = "time";
    public static final String LASTMODIFIED_ASC = "timea";
    public static final String LASTMODIFIED_DSC = "timed";
    /** default component ids  */
    // server name facet
    public static String FILECHOOSER_SERVERNAME_STATICTEXT_FACET =
            "serverNameText";
    // server label facet
    public static String FILECHOOSER_SERVERNAME_LABEL_FACET =
            "serverLabel";
    // enter keypress inline help facet
    public static String FILECHOOSER_ENTERPRESS_HELP_FACET =
            "enterPressHelp";
    // multiselct inline help facet
    public static String FILECHOOSER_MULTISELECT_HELP_FACET =
            "multiSelectHelp";
    public static String FILECHOOSER_LOOKIN_TEXTFIELD_FACET =
            "lookinField";  //NOI18N
    public static String FILECHOOSER_LOOKIN_LABEL_FACET =
            "lookinLabel";   //NOI18N
    public static String FILECHOOSER_LABEL_FACET =
            "fileChooserLabel";   //NOI18N
    public static String FILECHOOSER_FILTERON_TEXTFIELD_FACET =
            "filterField";    //NOI18N
    public static String FILECHOOSER_FILTER_LABEL_FACET =
            "filterLabel";    //NOI18N
    public static String FILECHOOSER_SELECTED_TEXTFIELD_FACET =
            "selectedField";     //NOI18N
    public static String FILECHOOSER_SELECT_LABEL_FACET =
            "selectedLabel";    //NOI18N
    public static String FILECHOOSER_UPLEVEL_BUTTON_FACET =
            "upButton";       //NOI18N
    public static String FILECHOOSER_OPENFOLDER_BUTTON_FACET =
            "openButton";     //NOI18N
    public static String FILECHOOSER_SORTMENU_FACET =
            "sortMenu";    //NOI18N
    public static String FILECHOOSER_SORT_LABEL_FACET =
            "sortLabel";    //NOI18N
    public static String FILECHOOSER_HIDDEN_BUTTON_FACET =
            "hiddenButton";    //NOI18N
    public static String FILECHOOSER_LISTBOX_FACET =
            "listEntries";     //NOI18N

    // Refereced in FileChooserRenderer
    public static String FILECHOOSER_HIDDENFIELD_ID =
            "_hiddenField";    //NOI18N

    // Error string constant for Internal Exceptions
    //
    private static final String NULLMODEL = "Null model value."; //NOI18N

    // Flag for detecting a change in the look in field.
    // Can't use value change events because they happen
    // too late. We could implement queueEvent and watch
    // events being queued  from the sub components.
    //
    private boolean openFolderChanged;
    private boolean filterChanged;
    private String lastOpenFolder;
    // handling a special case where both files and folders can be chosen
    private boolean fileAndFolderChooser = false;

    /**
     * Default constructor.
     */
    public FileChooser() {
        super();
        setRendererType("com.sun.webui.jsf.FileChooser");
    }

    /**
     * 

Return the family for this component.

*/ @Override public String getFamily() { return "com.sun.webui.jsf.FileChooser"; } public String getEscapeChar() { return getModel().getEscapeChar(); } public String getDelimiterChar() { return getModel().getDelimiterChar(); } /** * Return the current folder. * The value of getModel().getCurrentDir() is returned. */ public String getCurrentFolder() { return getModel().getCurrentDir(); } /** * Return the path element separator. * The value of getModel().getSeparatorString() is returned. */ public String getSeparatorString() { return getModel().getSeparatorString(); } /** * Return the current folder's parent folder. * The value of getModel().getParentFolder() is returned. * If model is FileChooserModel and there is no * parent folder null is returned. */ public String getParentFolder() { return getModel().getParentFolder(); } // Set flag to true if you want the fileChooser to be able to select both // files and folders. If this method is used neither the folderChooser // attribute nor the model API methods to set the chooser type should be // set. public void setFileAndFolderChooser(boolean flag) { if (flag) { _setFolderChooser(false); } this.fileAndFolderChooser = flag; } // Return true if both files and folders can be selected. public boolean isFileAndFolderChooser() { return this.fileAndFolderChooser; } public boolean isFolderChooser() { if (isFileAndFolderChooser()) { return false; } else { return _isFolderChooser(); } } public void setFolderChooser(boolean chooser) { if (isFileAndFolderChooser()) { _setFolderChooser(false); } else { _setFolderChooser(chooser); } } // - FileChooserModel must be stateless. (unless absolutely impossible // which I don't think is the case.). This will allow the FileChooser // to operate in a request scope. It means that data must be obtained // from the sub components and not the model for things like the // current directory. // // - There must be some mechanism like value change events from the // subcomponents to indicate that data has changed that might // affect a subcomponent after or before it has been validated. // This is the case if the lookin field has changed, selections // must be thrown away. (This is what the "lastOpenFolder" hack // is about, as well as the directory changing due to a file // selection.) // One way to accomplish this is to intercept the queueEvents // for the subcomponents since they bubble up the component hierachy // and either do something based on seeing that event or // if the PhaseId isn't ANYPHASE, make it ANYPHASE and use a // value change listener. This is necessary so the immediate // behavior can be realized. // // - Calls like getDirContent() should be parameterized with the // the value of the look in field, since it is // the real data store for that value. Likewise the file value // and sort value. // // - If the model is null create the model. // It will be created on every request unless it is bound a // session scope backing bean. It appears that the Model object is // actually serialized during restore/save state. // public ResourceModel getModel() { ResourceModel model = _getModel(); if (model == null) { log(NULLMODEL); model = new FileChooserModel(); Object obj = getLookin(); String currentDir = null; if (obj != null) { if (obj instanceof File) { currentDir = ((File) obj).getAbsolutePath(); } else if (obj instanceof String) { currentDir = (String) obj; } } model.setCurrentDir(currentDir); setModel(model); } return model; } public String[] getRoots() { return getModel().getRoots(); } /** *

Override the default {@link UIComponentBase#processDecodes} * processing to perform the following steps.

*
    * FileChooser obtains instances of the subcomponents and * calls their "processDecodes" methods before it calls its * own "decode" method. After, if FacesContext.getRenderResponse() * returns true an error has occured and FileChooser should take its * "failure" course. * After calling the processDecodes of the subcomponents, in the decode * method of the FileChooser obtain the submittedValues of the * subcomponents and synthesize a submitted value for the FileChooser * and set its submitted value which will cause the FileChooser to * participate in the JSF lifecycle processing. * *
  • If the rendered property of this {@link UIComponent} * is false, skip further processing.
  • *
  • Call the processDecodes() method of all facets * of this {@link FileChooser}, in the order determined * by a call to getFacets().keySet().iterator().
  • * *
  • Call the processDecodes() method of all children * of this {@link FileChooser}, in the order determined * by a call to getChildren().keySet().iterator().
  • * *
* @param context {@link FacesContext} for the current request * * @exception NullPointerException if context * is null */ @Override public void processDecodes(FacesContext context) { if (context == null) { throw new NullPointerException(); } if (!isRendered()) { return; } Iterator it = getFacets().keySet().iterator(); while (it.hasNext()) { UIComponent facet = (UIComponent) getFacets().get(it.next()); facet.processDecodes(context); } it = getChildren().iterator(); while (it.hasNext()) { UIComponent child = (UIComponent) it.next(); child.processDecodes(context); } // If the facet input components are immediate it can // be misleading if the chooser's submitted values, i.e. // the file selections, are full paths. // // If the filechooser's submittedValue is one or more // fully qualified paths, then these fields are irrelevant // and invalidating the chooser because any of them are // invalid is misleading. // // Policy decision. // This may be contrary to SWAED desires. // In an effort to not create new request protocols in // order to conditionally decode or validate facets, the // look in component, the filter component and the sort // component will always be validated as if they were immediate. // // The policy difference is that it may be that SWAED only // wants these values validated if explicitly commited by // virtue of pressing the return key in the in the look in // or filter text fields, or only when explicitly selecting a sort. // But that is very problematic when trying to integrate with the // JSF lifecycle. // // The chosen policy is also implemented in the javascript. // // If these components are immediate, they have already been validated. // All internally created facet fields are set as immediate. // // Typically JSF performs all validation even if one // validator fails. // boolean invalid = false; EditableValueHolder evh = null; // Need to do this first. // The policy is that if the look in field changes // then any selections have to be thrown away // since they may be relative to the last shown // directory. // // This is contrary to the feature of allowing the // selected file field to contain a full path to the // desired file. // evh = (EditableValueHolder) getLookInTextField(); if (evh != null && !evh.isImmediate()) { ((UIComponent) evh).processValidators(context); } invalid = invalid || !evh.isValid(); // Do this second for the a similar reason. // These policies reflect the client behavior of // clearing the selected field when the filter field // and the lookin field are changed by hitting the // return key. // evh = (EditableValueHolder) getFilterTextField(); if (evh != null && !evh.isImmediate()) { ((UIComponent) evh).processValidators(context); } invalid = invalid || !evh.isValid(); // Checks to see if the the look in field or the // filter field have changed. If they have throw // away the selections. // // Can't use value change events because they // come too late. // // Need to also update the lookin field if a // selection implies a new folder location. // evh = (EditableValueHolder) getSelectedTextField(); if (evh != null && !evh.isImmediate()) { ((UIComponent) evh).processValidators(context); } invalid = invalid || !evh.isValid(); evh = (EditableValueHolder) getSortComponent(); if (evh != null && !evh.isImmediate()) { ((UIComponent) evh).processValidators(context); } invalid = invalid || !evh.isValid(); // Update the listbox state // evh = (EditableValueHolder) getListComponent(); if (evh != null && !isImmediate()) { ((UIComponent) evh).processValidators(context); } invalid = invalid || !evh.isValid(); // As noted above, if the submitted values are // full paths, then the prior validation may be misleading. // decode(context); // If this component is immediate, then we would // validate it now. However if the other components aren't // immediate, it wouldn't make much sense. // But since we are treating the facet input components as // immediate, we're ok. // if (isImmediate()) { // If the other fields are invalid don't perform the // validation. It's probably not useful since the // values may be derived from the other fields most of the time. // i.e. relative path values requiring the look in field value. // if (!invalid) { validate(context); } else { setValid(false); } } else { // If any of the components were invalid set the // chooser invalid. // if (invalid) { setValid(false); } } if (!isValid()) { context.renderResponse(); } } /** *

Override the default {@link UIComponentBase#processValidators} * processing to perform the following steps.

*
    *
  • If the rendered property of this {@link UIComponent} * is false, skip further processing.
  • *
  • Call the processValidators() method of all facets * and children of the fileChooser component except the * listbox. Then validate the listbox followed by the * filechooser component itself. The listbox needs to be * validated after the other components because its * value depends on user input to the other components. *
  • *
* * @param context {@link FacesContext} for the current request * * @exception NullPointerException if context * is null */ @Override public void processValidators(FacesContext context) { if (context == null) { throw new NullPointerException(); } if (!isRendered()) { return; } // This has the potential of validating // developer defined facets twice. Once, above // because we treat them as immediate even if they // are not immediate. // Iterator it = getFacetsAndChildren(); Listbox lb = null; while (it.hasNext()) { UIComponent child = (UIComponent) it.next(); if (child instanceof Listbox) { lb = (Listbox) child; continue; } else { child.processValidators(context); if (child instanceof EditableValueHolder) { if (!((EditableValueHolder) child).isValid()) { setValid(false); } } } } // This only needs to happen if a developer defined // facet is specified. But this is not a supported // facet, but do it anyway. // if (lb != null) { lb.processValidators(context); if (!lb.isValid()) { setValid(false); } } try { if (!isImmediate()) { validate(context); } } catch (RuntimeException rte) { context.renderResponse(); } if (!isValid()) { context.renderResponse(); } } /** *

Retrieve the submitted value with getSubmittedValue(). If this * returns null, exit without further processing. (This indicates that * no value was submitted for fileChooser.) Convert the submitted value * into a "local value" of the appropriate data type by calling * getConvertedValue(javax.faces.context.FacesContext, java.lang.Object). * Validate the property by calling * validateValue(javax.faces.context.FacesContext, java.lang.Object). * If the valid property of this component is still true, retrieve the * previous value of the component (with getValue()), store the new * local value using setValue(), and reset the submitted value to null. * If the local value is different from the previous value of this * component, fire a ValueChangeEvent to be broadcast to all interested * listeners. * processing to perform the following steps.

*
    *
  • If the rendered property of this {@link UIComponent} * is false, skip further processing.
  • *
  • Call the processUpdates() method of all facets * of this {@link FileChooser}, in the order determined * by a call to getFacets().keySet().iterator().
  • *
* * @param context {@link FacesContext} for the current request * * @exception NullPointerException if context * is null */ @Override public void validate(javax.faces.context.FacesContext context) { if (context == null) { throw new NullPointerException(); } // If submittedValue is null, then no selections were // And this validate will never be called unless the // file chooser is immediate or we are processing a true // submit and not an intermediate action like openFolder. // Object submittedValue = getSubmittedValue(); if (submittedValue == null) { return; } // enforce isMultiple here // if (!isMultiple() && ((String[]) submittedValue).length > 1) { FacesMessage fmsg = null; if (isFolderChooser()) { fmsg = createFacesMessage( "filechooser.tooManyFileErrSum", //NOI18N "filechooser.tooManyFileErrDet", //NOI18N null, null); } else if (isFileAndFolderChooser()) { fmsg = createFacesMessage( "filechooser.tooManyFileFolderErrSum", //NOI18N "filechooser.tooManyFileFolderErrDet", //NOI18N null, null); fmsg = createFacesMessage( "filechooser.tooManyFolderErrSum", //NOI18N "filechooser.tooManyFolderErrDet", //NOI18N null, null); } context.addMessage(getClientId(context), fmsg); setValid(false); return; } // Get the current dir to see if it has changed // from the previous value. // ResourceModel model = getModel(); lastOpenFolder = model.getCurrentDir(); Object newValue = null; try { newValue = getConvertedValue(context, submittedValue); } catch (ConverterException ce) { // display error message here setValid(false); } // Here's where it gets ugly. // If the openFolder has changed, call processValidators // on the look in field after setting its submittedValue // to the new value. If it turns out to be invalid. // null the submittedValue, and set the file chooser as invalid. // It should validate since it already is the current directory. // if (!lastOpenFolder.equals(model.getCurrentDir())) { EditableValueHolder evh = (EditableValueHolder) getLookInTextField(); evh.setSubmittedValue(model.getCurrentDir()); try { ((UIComponent) evh).processValidators(context); } catch (ValidatorException ve) { setValid(false); // Get the last known good value // evh.setSubmittedValue(lastOpenFolder); model.setCurrentDir(lastOpenFolder); return; } } // We have to handle a special case where the chooser does // not record a value event though a selection was submitted. // If the chooser is a file chooser and there is only one // selection and it is a folder,then this is not set as the // value and is the same as changing the look in field. // no need to validate as validate is done in the getConvertedValue() // method. If our value is valid, store the new value, erase the // "submitted" value, and emit a ValueChangeEvent if appropriate if (isValid()) { Object previous = getValue(); setValue(newValue); setSubmittedValue(null); if (compareValues(previous, newValue)) { queueEvent(new ValueChangeEvent(this, previous, newValue)); } } } // Currently previous and newValue are ResourceItem arrays. // Return true if values are different // @Override protected boolean compareValues(Object previous, Object value) { // Let super take care of null cases // if (previous == null || value == null) { return super.compareValues(previous, value); } if (value instanceof Object[]) { // If the lengths aren't equal return true // int length = Array.getLength(value); if (Array.getLength(previous) != length) { return true; } // Each element at index "i" in previous must be equal to the // elementa at index "i" in value. // for (int i = 0; i < length; ++i) { Object newValue = Array.get(value, i); Object prevValue = Array.get(previous, i); if (newValue == null) { if (prevValue == null) { continue; } else { return true; } } if (prevValue == null) { return true; } if (!prevValue.equals(newValue)) { return true; } } return false; } return super.compareValues(previous, value); } /** * This validation method is in addition to any that might * be part of the component when specified as a facet. * Throw a ValidatorException with a FacesMessage explaining what happened. * * Called from ChooserLookInValidator. */ public void validateLookInComponent(FacesContext context, UIComponent component, Object value) throws ValidatorException { // No need to check for null, getModel throws FacesException if null. // ResourceModel model = getModel(); // Assuming object value type is String. // String lookInValue = (String) value; // For now assume this is called from // ChooserLookInValidator. It is a registered validator. // setCurrentDir throws exception, return its FacesMessage. // LookInValidator will throw ValidatorException // with that FacesMessage. // When it throws JSF will add that message // to the context, but with the component // id of the lookInField. Therefore, add it to the // context under the filechooser id since that is what // "displayAlert" and the renderer expects. // // The error strategy to be more integrated and well defined // so the renderer can do the right thing. // try { model.setCurrentDir(lookInValue); } catch (ResourceModelException cme) { // First clear the submitted value so the last known // valid value is rendered. // This is part of the policy of the FileChooser. // ((EditableValueHolder) component).setSubmittedValue(null); FacesMessage fmsg = cme.getFacesMessage(); context.addMessage(getClientId(context), fmsg); throw new ValidatorException(fmsg); } } /** * This validation method is in addition to any that might * be part of the component when specified as a facet. * Throw a ValidatorException with a FacesMessage explaining what happened. * * Called from ChooserFilterValidator. */ public void validateFilterComponent(FacesContext context, UIComponent component, Object value) throws ValidatorException { // No need to check for null, getModel throws FacesException if null. // ResourceModel model = getModel(); // For now assume this is called from // ChooserFilterValidator. It is a registered validator. // setFilterValue throws exception, return its FacesMessage. // ChooserFilterValidator will throw ValidatorException // with that FacesMessage. // When it throws JSF will add that message // to the context, but with the component // id of the filterField. Therefore, add it to the // context under the filechooser id since that is what // "displayAlert" and the renderer expects. // // The error strategy needs to be more integrated and well defined // so the renderer can do the right thing. // String filterValue = (String) value; // Get the current filter to see if it has changed // from the previous value. // String lastFilter = model.getFilterValue(); try { model.setFilterValue(filterValue); } catch (ResourceModelException cme) { ((EditableValueHolder) component).setSubmittedValue(null); FacesMessage fmsg = cme.getFacesMessage(); context.addMessage(getClientId(context), fmsg); throw new ValidatorException(fmsg); } filterChanged = !lastFilter.equals(model.getFilterValue()); } /** * This validation method is in addition to any that might * be part of the component if specified as a facet. * Throw a ValidatorException with a FacesMessage explaining what happened. * * Called from ChooserSortValidator. */ public void validateSortComponent(FacesContext context, UIComponent component, Object value) throws ValidatorException { // No need to check for null, getModel throws FacesException if null. // ResourceModel model = getModel(); // For now assume this is called from // ChooserSortValidator. It is a registered validator. // setSortValue throws exception, return its FacesMessage. // ChooserSortValidator will throw ValidatorException // with that FacesMessage. // When it throws JSF will add that message // to the context, but with the component // id of the sortField. Therefore, add it to the // context under the filechooser id since that is what // "displayAlert" and the renderer expects. // // The error strategy needs to be more integrated and well defined // so the renderer can do the right thing. // String sortValue = (String) value; // Not sure is this is the right thing to do for a drop down. // try { model.setSortValue(sortValue); } catch (ResourceModelException cme) { ((EditableValueHolder) component).setSubmittedValue(null); FacesMessage fmsg = cme.getFacesMessage(); context.addMessage(getClientId(context), fmsg); throw new ValidatorException(fmsg); } } /** * This validation method is in addition to any that might * be part of the component if specified as a facet. * Throw a ValidatorException with a FacesMessage explaining what happened. * * Called from ChooserSelectValidator. */ public void validateSelectComponent(FacesContext context, UIComponent component, Object value) throws ValidatorException { // This validator is a strange validator. // It going to parse out the selection and set the // result as the submittedValue of the filechooser. // // This is due to the fact that the selections can be // submitted in two ways. // // If this selectFieldComponent doesn't exist, then // the selections are submitted differently and decoded // by the file chooser renderer as an array of selections // as a request parameter. // // If this select field component does exist it is // submitted as well. Since it can have user entered // data and not just selections from the list it must // take precedence in the request. // // Parse the comma separated selections. // // To enforce similar policies on the client, if the // look in field has changed or the filter has changed // Throw a ValidatorException with a null message // to simulate what happens on the client. // We may want a real message at some point. // if (openFolderChanged || filterChanged) { ((EditableValueHolder) component).setSubmittedValue(null); ((EditableValueHolder) component).setValid(false); return; } if (value != null || ((String) value).length() > 0) { String[] selections = decodeSelections((String) value, getEscapeChar(), getDelimiterChar()); this.setSubmittedValue(selections); } } /** * Perform the following algorithm to update the model data * associated with this UIInput, if any, as appropriate. * * If the valid property of filechooser is false, take no * further action. * If the localValueSet property of this component is false, * take no further action. * If no ValueBinding for value exists, take no further action. * Call setValue() method of the ValueBinding to update the value * that the ValueBinding points at. * If the setValue() method returns successfully: * o Clear the local value of this UIInput. * o Set the localValueSet property of this UIInput to false. * If the setValue() method call fails: * o Enqueue an error message by calling addMessage() on * the specified FacesContext instance. * o Set the valid property of this UIInput to false. * */ @Override public void updateModel(javax.faces.context.FacesContext context) { // Update the individual component values from the model // and then update the fileChooser component. if (context == null) { throw new NullPointerException(); } if (!isValid() || !isLocalValueSet()) { return; } ValueExpression vb = getValueExpression("selected"); //NOI18N if (vb != null) { try { vb.setValue(context.getELContext(), getLocalValue()); setValue(null); setLocalValueSet(false); return; } catch (FacesException e) { FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, CONVERSION_MESSAGE_ID, e.getMessage()); context.addMessage(getClientId(context), message); setValid(false); } catch (IllegalArgumentException e) { FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, CONVERSION_MESSAGE_ID, e.getMessage()); context.addMessage(getClientId(context), message); setValid(false); } catch (Exception e) { FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, CONVERSION_MESSAGE_ID, e.getMessage()); context.addMessage(getClientId(context), message); setValid(false); } } } /** * @exception NullPointerException {@inheritDoc} */ /* public void encodeEnd(FacesContext context) throws IOException { if (context == null) { throw new NullPointerException(); } if (!isRendered()) { return; } String rendererType = getRendererType(); if (rendererType != null) { getRenderer(context).encodeEnd(context, this); } } */ // EditableValueMethods // this is the overriden method of UIInput. /** * Create a value for the fileChooser component based on the * submitted value, which are the user selections. * The selections may be absolute or relative paths. * The result is an array of objects. * * @return - an object that reflects the value of the fileChooser * component. * */ public java.lang.Object getConvertedValue(FacesContext context, UIComponent component, Object submittedValue) throws ConverterException { // First defer to the renderer. // Renderer renderer = getRenderer(context); if (renderer != null) { return renderer.getConvertedValue(context, this, submittedValue); } return getConvertedValue(context, (FileChooser) component, submittedValue); } /** * Overloaded getConvertedValue called by our renderer. * * We have this method because the we want the implementation * of getConvertedValue to exist in the component and not solely in * the renderer. * However JSF by convention defers to the renderer first * in getConvertedValue and if there isn't a renderer will * getConvetedValue(FacesContext, UIComponent, Object) calls this method. * Typically our renderer is registered as the renferer for this * component. Therefore it calls this method to obtain the * the value when the other getConvertedValue is called and tries * exectute its getConvertedValue. */ public Object getConvertedValue(FacesContext context, FileChooser chooser, Object submittedValue) throws ConverterException { // No need to check for null, getModel throws FacesException if null. // ResourceModel model = chooser.getModel(); if (submittedValue == null) { return null; } if (!(submittedValue instanceof String[])) { String msg = "FileChooser getConvertedValue requires " + //NOI18N "String[] for its submittedValue."; //NOI18N log(msg); throw new ConverterException(msg); } // FIXME: We should strive to make this Object[] or ResourceItem[] // and try to convert anonymously, as needed. // Object[] chooserValues = null; try { // Need to record any change to the current directory // from a selection. Unfortunately I haven't figured // out a way to do this in an elegant way. // lastOpenFolder = model.getCurrentDir(); // It really returns Object but for now assume File[] // if (isFolderChooser()) { chooserValues = (Object[]) model.getSelectedContent((String[]) submittedValue, true); } else if (isFileAndFolderChooser()) { Object[] fVals = (Object[]) model.getSelectedContent((String[]) submittedValue, false); Object[] dVals = (Object[]) model.getSelectedContent((String[]) submittedValue, true); int dsize = 0; if (dVals != null) { dsize = dVals.length; } int fsize = 0; if (fVals != null) { fsize = fVals.length; } if (fsize + dsize > 0) { if (fVals instanceof File[]) { chooserValues = new File[dsize + fsize]; } else { chooserValues = new Object[dsize + fsize]; } int k = 0; for (int i = 0; i < dsize; i++) { chooserValues[k++] = dVals[i]; } for (int j = 0; j < fsize; j++) { chooserValues[k++] = fVals[j]; } } } else { chooserValues = (Object[]) model.getSelectedContent((String[]) submittedValue, false); } // Set a flag if the directory has changed. // openFolderChanged = !lastOpenFolder.equals(model.getCurrentDir()); } catch (ResourceModelException cme) { FacesMessage fmsg = cme.getFacesMessage(); context.addMessage(getClientId(context), fmsg); throw new ConverterException(fmsg.getDetail() == null ? fmsg.getSummary() : fmsg.getDetail()); } // Need to coordinate this with "DB null values" strategy. // if (chooserValues == null || chooserValues.length == 0) { return null; } // For now, if the developer chooses to use a custom model then // no converter will be supplied. The backing bean has to be // aware of what the model was and read the value of the component // accordingly. if (!(chooserValues instanceof File[])) { return chooserValues; } File[] realChooserValues = (File[]) chooserValues; // In case its a value binding // boolean isMultiple = isMultiple(); // Try and get a converter // Object value = getValue(); Converter converter = ((ValueHolder) chooser).getConverter(); if (converter == null) { converter = getConverterFromValue(value); } // If there's no value binding or existing value, // convert if necessary or return File[] or File // ValueExpression valueExpr = chooser.getValueExpression("value"); //NOI18N Class vclazz = null; if (valueExpr != null) { vclazz = valueExpr.getType(context.getELContext()); } else if (value != null) { vclazz = value.getClass(); } // Default to File as native type. // if (vclazz == null) { if (isMultiple) { if (converter == null) { return realChooserValues; } else { return convertFileArrayToObjectArray(context, converter, realChooserValues); } } else { if (converter == null) { return realChooserValues[0]; } else { return convertFileToObject(context, converter, realChooserValues[0]); } } } if (isMultiple) { if (vclazz.isArray()) { // File[] and String[] special case // if (converter == null) { if (vclazz.getComponentType().isAssignableFrom( java.io.File.class)) { return realChooserValues; } else if (vclazz.getComponentType().isAssignableFrom( java.lang.String.class)) { return convertFileArrayToStringArray(realChooserValues); } } else { // Convert to object with a converter. // return convertFileArrayToObjectArray(context, converter, realChooserValues); } } else { List list = null; if (vclazz.isAssignableFrom(java.util.ArrayList.class)) { list = new ArrayList(); } else if (vclazz.isAssignableFrom(java.util.Vector.class)) { list = new Vector(); } else if (vclazz.isAssignableFrom(java.util.LinkedList.class)) { list = new LinkedList(); } else { try { list = (java.util.List) vclazz.newInstance(); } catch (Throwable t) { throw new ConverterException( "FileChooser is configured for multiple selection " + "but the value is not bound to an assignable type."); } } // Create the list of converted or File types. // return convertFileArrayToList(context, converter, realChooserValues, list); } } else { if (converter != null) { return converter.getAsObject(context, chooser, convertFileToString(realChooserValues[0])); } if (vclazz.isAssignableFrom(java.io.File.class)) { return realChooserValues[0]; } else if (vclazz.isAssignableFrom(java.lang.String.class)) { return convertFileToString(realChooserValues[0]); } else { return (Object) realChooserValues[0]; } } // We shouldn't get here but if we do return null. // return null; } // Converters // // FIXME: Some of these should be in the model. Especially if native type // of the model is more Opaque like ChooserItem // Then the ChooseItem would provide the converters. // private Converter getConverterFromValue(Object value) { if (value == null) { return null; } Converter converter = null; try { Class clazz = value.getClass(); if (isMultiple()) { if (clazz.isArray()) { clazz = clazz.getComponentType(); } else if (value instanceof List && ((List) value).size() != 0) { Object listItem = ((List) value).get(0); clazz = listItem != null ? listItem.getClass() : null; } else { // Can't figure out for multiple return null // clazz = null; log("Failed to obtain a class for the " + //NOI18N "FileChooser multiple value."); //NOI18N return null; } } if (clazz != null) { converter = ConversionUtilities.getConverterForClass(clazz); } } catch (Exception e) { // Proceed but log the error // String msg = "Failed to obtain a class for FileChooser value."; //NOI18N log(msg + "\nException: " + e.getStackTrace()); //NOI18N } return converter; } /** * If converter is not null return an Object[] where each entry * is converted by applying the converted to each entry in * fileArray. * If converter is null return fileArray. * If fileArray is null return null; */ protected Object convertFileArrayToObjectArray(FacesContext context, Converter converter, File[] fileArray) throws ConverterException { // What does it mean if fileArray.length == 0 ? // if (fileArray == null) { return null; } Object[] objArray = new Object[fileArray.length]; if (converter == null) { for (int i = 0; i < fileArray.length; ++i) { objArray[i] = fileArray[i]; } } else { for (int i = 0; i < fileArray.length; ++i) { objArray[i] = converter.getAsObject(context, this, convertFileToString(fileArray[i])); } } return objArray; } protected List convertFileArrayToList(FacesContext context, Converter converter, File[] fileArray, List list) throws ConverterException { if (list == null) { return null; } if (converter != null) { for (int i = 0; i < fileArray.length; ++i) { list.add(converter.getAsObject(context, this, convertFileToString(fileArray[i]))); } } else { for (int i = 0; i < fileArray.length; ++i) { list.add(fileArray[i]); } } return list; } /** * If converter is not null return an Object that was converted * by converter. * If converter is null, return file. */ protected Object convertFileToObject(FacesContext context, Converter converter, File file) throws ConverterException { if (converter == null) { return file; } String fileString = convertFileToString(file); if (fileString == null) { return null; } return converter.getAsObject(context, this, fileString); } protected String convertFileToString(File file) { // using getAbsolutePath path for this is a policy // issue and need to make sure this is consistent // and expected. // return file != null ? file.getAbsolutePath() : null; } protected String[] convertFileArrayToStringArray(File[] fileArray) { if (fileArray == null) { return null; } String[] strArray = new String[fileArray.length]; for (int i = 0; i < fileArray.length; ++i) { strArray[i] = convertFileToString(fileArray[i]); } return strArray; } /** * */ protected String[] convertValueToStringArray(FacesContext context, Converter converter, Object value) throws ConverterException { // If there's no value just return null. // if (value == null) { return null; } Class vclazz = value.getClass(); if (!isMultiple()) { return new String[]{ convertValueToString(context, converter, value)}; } else { if (vclazz.isArray()) { return convertObjectArrayToStringArray(context, converter, (Object[]) value); } else if (value instanceof List) { return convertObjectListToStringArray(context, converter, (List) value); } String msg = "FileChooser is configured for multiple selection " + "but the value is not an assignable type."; log(msg); throw new ConverterException(msg); } } protected String convertValueToString(FacesContext context, Converter converter, Object value) throws ConverterException { if (value == null) { return null; } if (converter != null) { return converter.getAsString(context, this, value); } else if (value instanceof File) { return convertFileToString((File) value); } else if (value instanceof String) { return (String) value; } else { // Instead of bailing just return "toString". // log("Resorting to object.toString() to convert single " + "value to String."); return value.toString(); } } protected String[] convertObjectArrayToStringArray(FacesContext context, Converter converter, Object[] value) throws ConverterException { if (value == null) { return null; } if (converter != null) { String[] strArray = new String[value.length]; for (int i = 0; i < value.length; ++i) { strArray[i] = converter.getAsString(context, this, value[i]); } return strArray; } else { if (value instanceof File[]) { return convertFileArrayToStringArray((File[]) value); } else if (value instanceof String[]) { return (String[]) value; } else { // Instead of bailing just return "toString". // log("Resorting to object.toString() to convert multiple " + "array value to String[]."); String[] strArray = new String[value.length]; for (int i = 0; i < value.length; ++i) { strArray[i] = value[i].toString(); } return strArray; } } } protected String[] convertObjectListToStringArray(FacesContext context, Converter converter, List list) throws ConverterException { if (list == null) { return null; } if (converter != null) { String[] strArray = new String[list.size()]; for (int i = 0; i < list.size(); ++i) { strArray[i] = converter.getAsString(context, this, list.get(i)); } return strArray; } else { // Try and find out what type we have by looking at the // first List value. // // To be consistent // String[] strArray = new String[list.size()]; if (list.size() == 0) { return strArray; } Object listItem = list.get(0); if (listItem instanceof File) { File[] fileArray = new File[list.size()]; fileArray = (File[]) list.toArray(fileArray); return convertFileArrayToStringArray(fileArray); } else if (listItem instanceof String) { return (String[]) list.toArray(strArray); } else { // Instead of bailing just return "toString". // log("Resorting to object.toString() to convert multiple " + "list value to String[]."); for (int i = 0; i < list.size(); ++i) { strArray[i] = list.get(i).toString(); } return strArray; } } } public static final String HYPHEN = "-"; //NOI18N /** * This method returns a Listbox containing the list of * resources selected by the user. */ private Listbox populateListComponent(Listbox fileList) { // No need to check for null, getModel throws FacesException if null. // ResourceModel model = getModel(); ResourceItem[] items = null; // If a folder chooser always disable files // items = model.getFolderContent(model.getCurrentDir(), isFolderChooser(), false); // FIXME: Need more well defined data here for the // list options. We probably want files read only // in a folder chooser, folders read only or // disabled whichever allows a javascript event // to open a folder but not to select it for // submission. // if (items != null && items.length != 0) { Option[] optList = new Option[items.length]; for (int i = 0; i < items.length; i++) { optList[i] = new Option(items[i].getItemKey(), items[i].getItemLabel()); optList[i].setDisabled(items[i].isItemDisabled()); } fileList.setItems(optList); } else { populateEmptyList(fileList); } return fileList; } private void populateEmptyList(Listbox fileList) { Theme theme = getTheme(); // FIXME: Consider having a format string in the Theme // int fileNameLen = Integer.parseInt(theme.getMessage("filechooser.fileNameLen")); int fileSizeLen = Integer.parseInt(theme.getMessage("filechooser.fileSizeLen")); int fileDateLen = Integer.parseInt(theme.getMessage("filechooser.fileDateLen")); // no files or directories exist // A line with "--------" has to be added to make the list box // have a width String label = ""; //NOI18N String value = "0"; //NOI18N // int len = fileNameLen + fileSizeLen + fileDateLen + 6; int len = fileNameLen + fileSizeLen + fileDateLen + 10; for (int i = 0; i < len; i++) { label += HYPHEN; } Option[] fileEntries = new Option[1]; fileEntries[0] = new Option(value, label); fileEntries[0].setDisabled(true); fileList.setItems(fileEntries); } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Child Methods // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Since the server text label does not use the for // attribute, neither the StaticText component or // label need to be placed in the facet map. // /** * Return a component that implements the server name field. * If a facet named serverNameText is found * that component is returned. Otherwise a StaticText component * is returned. It is assigned the id
* getId() + "_serverNameText"
*

* If the facet is not defined then the returned StaticText * component is recreated every time this method is called. *

* @return - the server name field component */ public UIComponent getServerNameText() { UIComponent facet = getFacet(FILECHOOSER_SERVERNAME_STATICTEXT_FACET); if (facet != null) { return facet; } StaticText child = new StaticText(); child.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_SERVERNAME_STATICTEXT_FACET)); child.setParent(this); Theme theme = getTheme(); child.setText(theme.getMessage("filechooser.lookinColumn")); child.setStyleClass(theme.getStyleClass(ThemeStyles.FILECHOOSER_NAME_TXT)); // No need to check for null, getModel throws FacesException if null. // ResourceModel model = getModel(); // Defaults to "localhost" // String serverName = model.getServerName(); child.setText(serverName); return child; } /** * Return a component that implements the inline help for the * filter text field. * If a facet named enterPressHelp is found * that component is returned. Otherwise a HelpInline component * is returned. It is assigned the id
* getId() + "_enterPressHelp"
*

* If the facet is not defined then the returned StaticText * component is created every time this method is called. *

* * @return the inline help component */ public UIComponent getEnterInlineHelp() { UIComponent facet = getFacet(FILECHOOSER_ENTERPRESS_HELP_FACET); if (facet != null) { return facet; } HelpInline child = new HelpInline(); child.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_ENTERPRESS_HELP_FACET)); child.setParent(this); Theme theme = getTheme(); child.setText(theme.getMessage("filechooser.enterKeyHelp")); // NOI18N child.setType("field"); return child; } /** * Return a component that implements the inline help for * selecting multiple rows from the listbox. * If the isMultiple returns false, null is returned.
* If a facet named multiSelectHelp is found * that component is returned. Otherwise a HelpInline component * is returned. It is assigned the id
* getId() + "_multiSelectHelp"
*

* If the facet is not defined then the returned HelpInline * component is created every time this method is called. *

* * @return the inline help component */ public UIComponent getMultiSelectHelp() { if (!isMultiple()) { return null; } UIComponent facet = getFacet(FILECHOOSER_MULTISELECT_HELP_FACET); if (facet != null) { return facet; } HelpInline child = new HelpInline(); child.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_MULTISELECT_HELP_FACET)); child.setParent(this); Theme theme = getTheme(); child.setText(theme.getMessage("filechooser.multiSelectHelp")); // NOI18N child.setType("field"); return child; } /** * Return a component that implements the server name field label. * If a facet named serverLabel is found * that component is returned. Otherwise a Label component * is returned. It is assigned the id
* getId() + "_serverLabel"
*

* If the facet is not defined then the returned Label * component is created every time this method is called. *

* * @return the server name field label component */ public UIComponent getServerNameLabel() { UIComponent facet = getFacet(FILECHOOSER_SERVERNAME_LABEL_FACET); if (facet != null) { return facet; } Label child = new Label(); child.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_SERVERNAME_LABEL_FACET)); child.setParent(this); // Should be in theme // child.setLabelLevel(2); Theme theme = getTheme(); child.setText(theme.getMessage("filechooser.serverPrompt")); //NOI18N child.setStyleClass(theme.getStyleClass(ThemeStyles.LABEL_LEVEL_TWO_TEXT)); return child; } /** * Return a component that implements the title text. * If a facet named fileChooserLabel is found * that component is returned. Otherwise a StaticText component * is returned. It is assigned the id
* getId() + "_fileChooserLabel"
*

* If the facet is not defined then the returned StaticText * component is created every time this method is called. *

* * @return the FileChooser title component */ public UIComponent getFileChooserTitle() { UIComponent facet = getFacet(FILECHOOSER_LABEL_FACET); if (facet != null) { return facet; } StaticText child = new StaticText(); child.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_LABEL_FACET)); child.setParent(this); Theme theme = getTheme(); child.setText(theme.getMessage("filechooser.title")); //NOI18N /*child.setStyleClass(theme .getStyleClass(ThemeStyles.FILECHOOSER_LABEL_TXT));*/ return child; } /** * Return a component that implements the look in input field. * If a facet named lookinField is found * that component is returned. Otherwise a TextField component * is returned. It is assigned the id
* getId() + "_lookinField"
*

* If the facet is not defined then the returned TextField * component is re-intialized every time this method is called. *

* * @return the look in input field component */ public UIComponent getLookInTextField() { UIComponent facet = getFacet(FILECHOOSER_LOOKIN_TEXTFIELD_FACET); if (facet != null) { return facet; } TextField child = (TextField) ComponentUtilities.getPrivateFacet(this, FILECHOOSER_LOOKIN_TEXTFIELD_FACET, true); if (child == null) { child = new TextField(); child.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_LOOKIN_TEXTFIELD_FACET)); child.addValidator(new FileChooserLookInValidator()); child.setSubmittedValue(getModel().getCurrentDir()); ComponentUtilities.putPrivateFacet(this, FILECHOOSER_LOOKIN_TEXTFIELD_FACET, child); } Theme theme = getTheme(); child.setColumns(Integer.parseInt(theme.getMessage("filechooser.lookinColumn"))); //NOI18N child.setStyleClass( theme.getStyleClass( ThemeStyles.FILECHOOSER_NAME_TXT).concat(" ").concat(theme.getStyleClass(ThemeStyles.FILECHOOSER_WIDTH_TXT))); int tindex = getTabIndex(); if (tindex > 0 && tindex < 32767) { child.setTabIndex(tindex); } return child; } /** * Return a component that implements the look in input field label. * If a facet named lookinLabel is found * that component is returned. Otherwise a Label component * is returned. It is assigned the id
* getId() + "_lookinLabel"
*

* If the facet is not defined then the returned Label * component is re-intialized every time this method is called. *

* * @return the look in input field label component */ public UIComponent getLookInLabel() { UIComponent facet = getFacet(FILECHOOSER_LOOKIN_LABEL_FACET); if (facet != null) { return facet; } Label child = (Label) ComponentUtilities.getPrivateFacet(this, FILECHOOSER_LOOKIN_LABEL_FACET, true); if (child == null) { child = new Label(); child.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_LOOKIN_LABEL_FACET)); // Should be in theme // child.setLabelLevel(2); ComponentUtilities.putPrivateFacet(this, FILECHOOSER_LOOKIN_LABEL_FACET, child); } Theme theme = getTheme(); child.setText(theme.getMessage("filechooser.lookin")); //NOI18N child.setFor(getLookInTextField().getClientId(getFacesContext())); return child; } /** * Return a component that implements the filter input field. * If a facet named filterField is found * that component is returned. Otherwise a TextField component * is returned. It is assigned the id
* getId() + "_filterField"
*

* If the facet is not defined then the returned TextField * component is re-intialized every time this method is called. *

* * @return the filter input field component */ public UIComponent getFilterTextField() { UIComponent facet = (TextField) getFacet(FILECHOOSER_FILTERON_TEXTFIELD_FACET); if (facet != null) { return facet; } TextField child = (TextField) ComponentUtilities.getPrivateFacet(this, FILECHOOSER_FILTERON_TEXTFIELD_FACET, true); if (child == null) { child = new TextField(); child.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_FILTERON_TEXTFIELD_FACET)); child.addValidator(new FileChooserFilterValidator()); child.setSubmittedValue(getModel().getFilterValue()); ComponentUtilities.putPrivateFacet(this, FILECHOOSER_FILTERON_TEXTFIELD_FACET, child); } FacesContext context = FacesContext.getCurrentInstance(); ClientSniffer sniffer = ClientSniffer.getInstance(context); // Needs to be in Theme. // int size = sniffer.isNav6up() ? 32 : 18; child.setColumns(size); int tindex = getTabIndex(); if (tindex > 0 && tindex < 32767) { child.setTabIndex(tindex); } return child; } /** * Return a component that implements the filter input field label. * If a facet named filterLabel is found * that component is returned. Otherwise a Label component * is returned. It is assigned the id
* getId() + "_filterLabel"
*

* If the facet is not defined then the returned Label * component is re-intialized every time this method is called. *

* * @return the filter input field label component */ public UIComponent getFilterLabel() { UIComponent facet = getFacet(FILECHOOSER_FILTER_LABEL_FACET); if (facet != null) { return facet; } Label child = (Label) ComponentUtilities.getPrivateFacet(this, FILECHOOSER_FILTER_LABEL_FACET, true); if (child == null) { child = new Label(); child.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_FILTER_LABEL_FACET)); // Should be in theme // child.setLabelLevel(2); ComponentUtilities.putPrivateFacet(this, FILECHOOSER_FILTER_LABEL_FACET, child); } Theme theme = getTheme(); if (isFolderChooser()) { child.setText( theme.getMessage("filechooser.folderFilter")); //NOI18N } else { child.setText( theme.getMessage("filechooser.fileFilter")); //NOI18N } child.setFor(getFilterTextField().getClientId(getFacesContext())); return child; } /** * Return a component that implements the selected file(s) or * folder(s) input field. * If a facet named selectedField is found * that component is returned. Otherwise a TextField component * is returned. It is assigned the id
* getId() + "_selectedField"
*

* If the facet is not defined then the returned TextField * component is re-intialized every time this method is called. *

* * @return the select text field component. This text * field displays the list of selected items. */ public UIComponent getSelectedTextField() { UIComponent facet = null; facet = getFacet(FILECHOOSER_SELECTED_TEXTFIELD_FACET); if (facet != null) { return facet; } TextField child = (TextField) ComponentUtilities.getPrivateFacet(this, FILECHOOSER_SELECTED_TEXTFIELD_FACET, true); if (child == null) { child = new TextField(); child.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_SELECTED_TEXTFIELD_FACET)); child.addValidator(new FileChooserSelectValidator()); ComponentUtilities.putPrivateFacet(this, FILECHOOSER_SELECTED_TEXTFIELD_FACET, child); } Theme theme = getTheme(); if (isMultiple()) { child.setColumns(Integer.parseInt(theme.getMessage("filechooser.multipleColumn"))); //NOI18N } else { child.setColumns(Integer.parseInt(theme.getMessage("filechooser.singleColumn"))); //NOI18N } if (isFolderChooser()) { child.setStyleClass(theme.getStyleClass(ThemeStyles.FILECHOOSER_FOLD_STYLE)); } else { child.setStyleClass(theme.getStyleClass(ThemeStyles.FILECHOOSER_FILE_STYLE)); } int tindex = getTabIndex(); if (tindex > 0 && tindex < 32767) { child.setTabIndex(tindex); } // FIXME: Need to add onblur handler. // This will be the only way to control the // chooser button correctly when a user enters a // value manually. // return child; } // This label does not use the for attribute. // Therefore it does not necessarily have to be placed in the // facet map. /** * Return a component that implements the selected file(s) or * folder(s) input field label. * If a facet named selectedLabel is found * that component is returned. Otherwise a Label component * is returned. It is assigned the id
* getId() + "_selectedLabel"
*

* If the facet is not defined then the returned Label * component is re-intialized every time this method is called. *

* * @return - returns the selected text field label component */ public UIComponent getSelectLabel() { UIComponent facet = getFacet(FILECHOOSER_SELECT_LABEL_FACET); if (facet != null) { return facet; } Label child = (Label) ComponentUtilities.getPrivateFacet(this, FILECHOOSER_SELECT_LABEL_FACET, true); if (child == null) { child = new Label(); child.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_SELECT_LABEL_FACET)); // Should be in theme // child.setLabelLevel(2); ComponentUtilities.putPrivateFacet(this, FILECHOOSER_SELECT_LABEL_FACET, child); } Theme theme = getTheme(); child.setFor(getSelectedTextField().getClientId(getFacesContext())); boolean ismultiple = isMultiple(); String labelKey = null; if (isFolderChooser()) { labelKey = ismultiple ? "filechooser.selectedFolders" : //NOI18N "filechooser.selectedFolder"; //NOI18N } else if (isFileAndFolderChooser()) { labelKey = ismultiple ? "filechooser.selectedFileAndFolders" : //NOI18N "filechooser.selectedFileAndFolder"; //NOI18N } else { labelKey = ismultiple ? "filechooser.selectedFiles" : //NOI18N "filechooser.selectedFile"; //NOI18N } child.setText(theme.getMessage(labelKey)); return child; } /** * Return a component that implements the sort criteria menu. * If a facet named sortMenu is found * that component is returned. Otherwise a DropDown component * is returned. It is assigned the id
* getId() + "_sortMenu"
*

* If the facet is not defined then the returned DropDown * component is re-intialized every time this method is called. *

* * @return the dropdown sort menu component */ public UIComponent getSortComponent() { UIComponent facet = getFacet(FILECHOOSER_SORTMENU_FACET); if (facet != null) { return facet; } DropDown jdd = (DropDown) ComponentUtilities.getPrivateFacet(this, FILECHOOSER_SORTMENU_FACET, true); if (jdd == null) { jdd = new DropDown(); jdd.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_SORTMENU_FACET)); jdd.setSubmitForm(true); // Should be part of theme // jdd.setLabelLevel(2); jdd.addValidator(new FileChooserSortValidator()); jdd.setImmediate(true); ComponentUtilities.putPrivateFacet(this, FILECHOOSER_SORTMENU_FACET, jdd); } // FIXME: These sort constants are a function of the // chooser model and should be obtained from // model. Sort should be some sort of sort class // from which one could get the "display" names // of the sort options. // // Possibly even have the model return // and Option array. This is a known model type // for our components. // Theme theme = getTheme(); Option[] sortFields = new Option[6]; sortFields[0] = new Option(ALPHABETIC_ASC, theme.getMessage("filechooser.sortOption1")); //NOI18N sortFields[1] = new Option(ALPHABETIC_DSC, theme.getMessage("filechooser.sortOption4")); //NOI18N sortFields[2] = new Option(LASTMODIFIED_ASC, theme.getMessage("filechooser.sortOption2")); //NOI18N sortFields[3] = new Option(LASTMODIFIED_DSC, theme.getMessage("filechooser.sortOption5")); //NOI18N sortFields[4] = new Option(SIZE_ASC, theme.getMessage("filechooser.sortOption3")); //NOI18N sortFields[5] = new Option(SIZE_DSC, theme.getMessage("filechooser.sortOption6")); //NOI18N jdd.setItems(sortFields); // jdd.setLabel(theme.getMessage("filechooser.sortBy")); //NOI18N // jdd.setLabelLevel(2); jdd.setStyleClass(theme.getStyleClass(ThemeStyles.MENU_JUMP)); int tindex = getTabIndex(); if (tindex > 0 && tindex < 32767) { jdd.setTabIndex(tindex); } // No need to check for null, getModel throws FacesException if null. // ResourceModel model = getModel(); String sortVal = model.getSortValue(); // first check if model's sortfield is set // if (sortVal == null) { String sField = getSortField(); if (isDescending()) { sField = sField.concat("d"); //NOI18N } else { sField = sField.concat("a"); //NOI18N } jdd.setSelected(sField); model.setSortValue(sField); } else { jdd.setSelected(sortVal); } return jdd; } /** * Return a component that implements the sort criteria menu. * If a facet named sortMenu is found * that component is returned. Otherwise a DropDown component * is returned. It is assigned the id
* getId() + "_sortMenu"
*

* If the facet is not defined then the returned DropDown * component is re-intialized every time this method is called. *

* * @return the dropdown sort menu component */ public UIComponent getSortComponentLabel() { UIComponent facet = getFacet(FILECHOOSER_SORT_LABEL_FACET); if (facet != null) { return facet; } Label child = (Label) ComponentUtilities.getPrivateFacet(this, FILECHOOSER_SORT_LABEL_FACET, true); if (child == null) { child = new Label(); child.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_SORT_LABEL_FACET)); // Should be in theme // child.setLabelLevel(2); ComponentUtilities.putPrivateFacet(this, FILECHOOSER_SORT_LABEL_FACET, child); } Theme theme = getTheme(); child.setText( theme.getMessage("filechooser.sortBy")); //NOI18N child.setFor(getSortComponent().getClientId(getFacesContext())); return child; } /** * Return a component that implements the list of files and folders. * It is assigned the id
* getId() + "_listEntries"
*

* The returned Listbox * component is re-intialized every time this method is called. *

* * @return the dropdown sort menu component */ public UIComponent getListComponent() { Listbox fileList = (Listbox) ComponentUtilities.getPrivateFacet(this, FILECHOOSER_LISTBOX_FACET, true); if (fileList == null) { fileList = new Listbox(); fileList.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_LISTBOX_FACET)); // FIXME: This should be in Theme // fileList.setMonospace(true); ComponentUtilities.putPrivateFacet(this, FILECHOOSER_LISTBOX_FACET, fileList); } fileList.setRows(getRows()); Theme theme = getTheme(); if (isFolderChooser()) { fileList.setToolTip(theme.getMessage("filechooser.listTitleFolder")); //NOI18N } else if (isFileAndFolderChooser()) { fileList.setToolTip(theme.getMessage("filechooser.listTitleFileAndFolder")); //NOI18N) } else { fileList.setToolTip(theme.getMessage("filechooser.listTitleFile")); //NOI18N } fileList.setMultiple(isMultiple()); fileList.setValue(null); int tindex = getTabIndex(); if (tindex > 0 && tindex < 32767) { fileList.setTabIndex(tindex); } return populateListComponent(fileList); } /** * Return a component that implements the move up button. * If a facet named upButton is found * that component is returned. Otherwise a Button component * is returned. It is assigned the id
* getId() + "_upButton"
*

* If the facet is not defined then the returned Button * component is re-intialized every time this method is called. *

* * @param disabled Flag indicating button is disabled * @return the button component for moving up the folder hierarchy */ public UIComponent getUpLevelButton(boolean disabled) { UIComponent facet = getFacet(FILECHOOSER_UPLEVEL_BUTTON_FACET); if (facet != null) { return facet; } Theme theme = getTheme(); Button child = (Button) ComponentUtilities.getPrivateFacet(this, FILECHOOSER_UPLEVEL_BUTTON_FACET, true); if (child == null) { child = new Button(); child.setStyleClass(theme.getStyleClass(ThemeStyles.FILECHOOSER_IMG_BTN)); child.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_UPLEVEL_BUTTON_FACET)); child.setIcon(ThemeImages.FC_UP_1LEVEL); child.setImmediate(true); ComponentUtilities.putPrivateFacet(this, FILECHOOSER_UPLEVEL_BUTTON_FACET, child); } child.setText(theme.getMessage("filechooser.upOneLevel")); //NOI18N child.setToolTip( theme.getMessage("filechooser.upOneLevelTitle")); //NOI18N // Disabled should not be passed in. // This should either be determined solely on the client // or from the model, if there is a parent folder of the // current folder. The problem is ensuring that the // model has been updated to have the latest data // when this method is called. // child.setDisabled(disabled); int tindex = getTabIndex(); if (tindex > 0 && tindex < 32767) { child.setTabIndex(tindex); } return child; } /** * Return a component that implements the open folder button. * If a facet named openButton is found * that component is returned. Otherwise a Button component * is returned. It is assigned the id
* getId() + "_openButton"
*

* If the facet is not defined then the returned Button * component is re-intialized every time this method is called. *

* * @return the OpenFolder button component. */ public UIComponent getOpenFolderButton() { UIComponent facet = getFacet(FILECHOOSER_OPENFOLDER_BUTTON_FACET); if (facet != null) { return facet; } Theme theme = getTheme(); Button child = (Button) ComponentUtilities.getPrivateFacet(this, FILECHOOSER_OPENFOLDER_BUTTON_FACET, true); if (child == null) { child = new Button(); child.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_OPENFOLDER_BUTTON_FACET)); child.setDisabled(false); child.setImmediate(true); child.setIcon(ThemeImages.FC_OPEN_FOLDER); ComponentUtilities.putPrivateFacet(this, FILECHOOSER_OPENFOLDER_BUTTON_FACET, child); } child.setText(theme.getMessage("filechooser.openFolder")); //NOI18N child.setToolTip( theme.getMessage("filechooser.openFolderTitle")); //NOI18N int tindex = getTabIndex(); if (tindex > 0 && tindex < 32767) { child.setTabIndex(tindex); } return child; } // I don't think this is ever used on the client any more. // This method is referenced in the renderer but I don't think // the client javascript "clicks" it anymore. /** * Get a hidden button. In order to associate all user actions * with an ActionEvent and have a single ActionListener to listen * for these events a hidden button is being created to monitor * changes in texh filed values. When a user enters data in a * text field and hits enter a click of this hidden button will * be initiated using Javascript. * * @return the hidden button component. */ public UIComponent getHiddenFCButton() { Button child = (Button) ComponentUtilities.getPrivateFacet(this, FILECHOOSER_HIDDEN_BUTTON_FACET, true); if (child == null) { child = new Button(); child.setId(ComponentUtilities.createPrivateFacetId(this, FILECHOOSER_HIDDEN_BUTTON_FACET)); child.setPrimary(true); ComponentUtilities.putPrivateFacet(this, FILECHOOSER_HIDDEN_BUTTON_FACET, child); } return child; } /** *

Restore the state of this component.

*/ @Override public void restoreState(FacesContext _context, Object _state) { if (_state == null) { return; } Object _values[] = (Object[]) _state; _restoreState(_context, _values[0]); this.fileAndFolderChooser = ((Boolean) _values[1]).booleanValue(); //this.valueChangeListenerExpression =(MethodExpression) restoreAttachedState(_context, _values[2]); //this.validatorExpression = (MethodExpression)restoreAttachedState(_context, _values[3]); } /** *

Save the state of this component.

*/ @Override public Object saveState(FacesContext _context) { Object _values[] = new Object[2]; _values[0] = _saveState(_context); _values[1] = this.fileAndFolderChooser ? Boolean.TRUE : Boolean.FALSE; //_values[2] = saveAttachedState(_context, valueChangeListenerExpression); //_values[3] = saveAttachedState(_context, validatorExpression); return _values; } /** * This method handles the display of error messages. * @param summary The error message summary * @param detail The error message detail */ public void displayAlert(String summary, String detail, String[] summaryArgs, String[] detailArgs) { FacesContext context = FacesContext.getCurrentInstance(); FacesMessage fmsg = createFacesMessage(summary, detail, summaryArgs, detailArgs); context.addMessage(getClientId(context), fmsg); } /* * Implement this method so that it returns the DOM ID of the * HTML element which should receive focus when the filechooser * receives focus, and to which a component label should apply. * Usually, this is the first element that accepts input. For * the fileChooser this happens to be the lookIn text field. * * @param context The FacesContext for the request * @return The client id, also the JavaScript element id */ // Looks like implementing the ComplexComponent interface comes in the way // of individual elements setting focus. Commenting it out for now. // There is a prolem with the textField component in that it does not // maintain focus. /* public String getPrimaryElementID(FacesContext context) { return getLookInTextField().getClientId(context); } */ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Protected Methods // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // private convenience methods. Some may be useful for // general utilities. // /** * Log an error - only used during development time. */ void log(String s) { if (LogUtil.fineEnabled(FileChooser.class)) { LogUtil.fine(FileChooser.class, s); } } /**

Convience function to get the current Theme.

*/ private String getEncodedSelections() { Object value = getValue(); Converter converter = getConverter(); if (converter == null) { converter = getConverterFromValue(value); } String[] selections = null; try { selections = convertValueToStringArray( FacesContext.getCurrentInstance(), converter, value); } catch (ConverterException ce) { log("Failed to convert and encode initial selections."); } return encodeSelections(selections, getEscapeChar(), getDelimiterChar()); } private Theme getTheme() { return ThemeUtilities.getTheme(FacesContext.getCurrentInstance()); } /** * This method creates a FacesMessage. * @param summary The error message summary * @param detail The error message detail */ private FacesMessage createFacesMessage(String summary, String detail, String[] summaryArgs, String[] detailArgs) { FacesContext context = FacesContext.getCurrentInstance(); Theme theme = ThemeUtilities.getTheme(context); String summaryMsg = theme.getMessage(summary, summaryArgs); String detailMsg = theme.getMessage(detail, detailArgs); FacesMessage fmsg = new FacesMessage( FacesMessage.SEVERITY_ERROR, summaryMsg, detailMsg); return fmsg; } /** * Encode the selectedFileField value. * This is an escaped, comma separated list of selected * entries. This method is used to format an initial * value for the selectedFileField. It is only used * on initial display (?), which is true if processDecodes * has not been called. If processDecodes has not been called format and * set the value of the selectedFileField. Do this * by setting the submittedValue not by the setValue method. * * This can get complicated since converters may be necessary * to convert the values to Strings. */ private String encodeSelections(String[] selections, String escapeChar, String delimiter) { if (selections == null || selections.length == 0) { return null; } StringBuffer sb = new StringBuffer( escapeString(selections[0], escapeChar, delimiter)); for (int i = 1; i < selections.length; ++i) { sb.append(delimiter); sb.append(escapeString(selections[i], escapeChar, delimiter)); } return sb.toString(); } private String[] decodeSelections(String selections, String escapeChar, String delimiter) { if (selections == null) { return null; } // This has to be done character by character // char del = delimiter.toCharArray()[0]; char esc = escapeChar.toCharArray()[0]; char[] charArray = selections.toCharArray(); int escseen = 0; int ind = 0; int j = 0; ArrayList strArray = new ArrayList(); for (int i = 0; i < selections.length(); ++i) { if (charArray[i] == del) { if (escseen % 2 == 0) { strArray.add(ind++, unescapeString(selections.substring(j, i), escapeChar, delimiter)); j = i + 1; } } if (charArray[i] == esc) { ++escseen; continue; } else { escseen = 0; } } // Capture the last substring // strArray.add(ind, unescapeString(selections.substring(j), escapeChar, delimiter)); return (String[]) strArray.toArray(new String[strArray.size()]); } // These should be made utility methods but I'm not sure // where they should go. // private String escapeString(String s, String escapeChar, String delimiter) { // Replace all escapeChar's with two escapeChar's // But if the escaape char is "\" need to escape it // in the regex since it is a special character. // String escaped_escapeChar = escapeChar; if (escapeChar.equals("\\")) { escaped_escapeChar = escapeChar + escapeChar; } String regEx = escaped_escapeChar; String s0 = s.replaceAll(regEx, escaped_escapeChar + escaped_escapeChar); // Replace all delimiter characters with the // escapeChar and a delimiter. // regEx = delimiter; s0 = s0.replaceAll(regEx, escaped_escapeChar + delimiter); return s0; } private String unescapeString(String s, String escapeChar, String delimiter) { // Replace every escaped delimiter with just the // delimter. // But if the escaape char is "\" need to escape it // in the regex since it is a special character. // String escaped_escapeChar = escapeChar; if (escapeChar.equals("\\")) { escaped_escapeChar = escapeChar + escapeChar; } String regEx = escaped_escapeChar + delimiter; String s0 = s.replaceAll(regEx, delimiter); // Replace every two occurrences of the escape char with one. // regEx = escaped_escapeChar + escaped_escapeChar; s0 = s0.replaceAll(regEx, escaped_escapeChar); return s0; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Tag attribute methods // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** *

Return the ValueExpression stored for the * specified name (if any), respecting any property aliases.

* * @param name Name of value binding expression to retrieve */ @Override public ValueExpression getValueExpression(String name) { if (name.equals("selected")) { return super.getValueExpression("value"); } return super.getValueExpression(name); } /** *

Set the ValueExpression stored for the * specified name (if any), respecting any property * aliases.

* * @param name Name of value binding to set * @param binding ValueExpression to set, or null to remove */ @Override public void setValueExpression(String name, ValueExpression binding) { if (name.equals("selected")) { super.setValueExpression("value", binding); return; } super.setValueExpression(name, binding); } // Hide required @Property(name = "required", isHidden = true, isAttribute = false) @Override public boolean isRequired() { return super.isRequired(); } /** *

Use the visible attribute to indicate whether the component should be * viewable by the user in the rendered HTML page. If set to false, the * HTML code for the component is present in the page, but the component * is hidden with style attributes. By default, visible is set to true, so * HTML for the component HTML is included and visible to the user. If the * component is not visible, it can still be processed on subsequent form * submissions because the HTML is present.

*/ @Property(name = "visible", displayName = "Visible", category = "Behavior") private boolean visible = true; private boolean visible_set = false; /** *

Use the visible attribute to indicate whether the component should be * viewable by the user in the rendered HTML page. If set to false, the * HTML code for the component is present in the page, but the component * is hidden with style attributes. By default, visible is set to true, so * HTML for the component HTML is included and visible to the user. If the * component is not visible, it can still be processed on subsequent form * submissions because the HTML is present.

*/ public boolean isVisible() { if (this.visible_set) { return this.visible; } ValueExpression _vb = getValueExpression("visible"); if (_vb != null) { Object _result = _vb.getValue(getFacesContext().getELContext()); if (_result == null) { return false; } else { return ((Boolean) _result).booleanValue(); } } return this.visible; } /** *

Use the visible attribute to indicate whether the component should be * viewable by the user in the rendered HTML page. If set to false, the * HTML code for the component is present in the page, but the component * is hidden with style attributes. By default, visible is set to true, so * HTML for the component HTML is included and visible to the user. If the * component is not visible, it can still be processed on subsequent form * submissions because the HTML is present.

* @see #isVisible() */ public void setVisible(boolean visible) { this.visible = visible; this.visible_set = true; } /** *

Position of this element in the tabbing order of the current document. * Tabbing order determines the sequence in which elements receive * focus when the tab key is pressed. The value must be an integer * between 0 and 32767.

*/ @Property(name = "tabIndex", displayName = "Tab Index", category = "Accessibility", editorClassName = "com.sun.rave.propertyeditors.IntegerPropertyEditor") private int tabIndex = Integer.MIN_VALUE; private boolean tabIndex_set = false; /** *

Position of this element in the tabbing order of the current document. * Tabbing order determines the sequence in which elements receive * focus when the tab key is pressed. The value must be an integer * between 0 and 32767.

*/ public int getTabIndex() { if (this.tabIndex_set) { return this.tabIndex; } ValueExpression _vb = getValueExpression("tabIndex"); if (_vb != null) { Object _result = _vb.getValue(getFacesContext().getELContext()); if (_result == null) { return Integer.MIN_VALUE; } else { return ((Integer) _result).intValue(); } } return Integer.MIN_VALUE; } /** *

Position of this element in the tabbing order of the current document. * Tabbing order determines the sequence in which elements receive * focus when the tab key is pressed. The value must be an integer * between 0 and 32767.

* @see #getTabIndex() */ public void setTabIndex(int tabIndex) { this.tabIndex = tabIndex; this.tabIndex_set = true; } // Hide value @Property(name = "value", isHidden = true, isAttribute = false) @Override public Object getValue() { return super.getValue(); } /** *

Set this attribute to true to sort from the highest value to lowest value, * such as Z-A for alphabetic, or largest file to smallest for sorting * on file size. The default is to sort in ascending order.

*/ @Property(name = "descending", displayName = "Descending", category = "Advanced") private boolean descending = false; private boolean descending_set = false; public boolean isDescending() { if (this.descending_set) { return this.descending; } ValueExpression _vb = getValueExpression("descending"); if (_vb != null) { Object _result = _vb.getValue(getFacesContext().getELContext()); if (_result != null) { return ((Boolean) _result).booleanValue(); } } // Return the default value. boolean defaultValue = descending; try { defaultValue = Boolean.parseBoolean(getTheme().getMessage( "filechooser.descending")); //NOI18N } catch (Exception e) { log("Failed to obtain the default value from the theme." + "Using the default value " + defaultValue + "."); } return defaultValue; } /** *

Set descending to true to sort from the highest value to lowest value, * such as Z-A for alphabetic, or largest file to smallest for sorting * on file size. The default is to sort in ascending order.

* @see #isDescending() */ public void setDescending(boolean descending) { this.descending = descending; this.descending_set = true; } /** *

Indicates that activation of this component by the user is not * currently permitted.

*/ @Property(name = "disabled", displayName = "Disabled", category = "Behavior") private boolean disabled = false; private boolean disabled_set = false; public boolean isDisabled() { if (this.disabled_set) { return this.disabled; } ValueExpression _vb = getValueExpression("disabled"); if (_vb != null) { Object _result = _vb.getValue(getFacesContext().getELContext()); if (_result == null) { return false; } else { return ((Boolean) _result).booleanValue(); } } return false; } /** *

Indicates that activation of this component by the user is not * currently permitted.

* @see #isDisabled() */ public void setDisabled(boolean disabled) { this.disabled = disabled; this.disabled_set = true; } /** *

Use this attribute to configure the file chooser as a folder chooser. * Set the value to true for a folder chooser or false for a file * chooser. The default value is false.

*/ @Property(name = "folderChooser", displayName = "Folder Chooser", category = "Appearance") private boolean folderChooser = false; private boolean folderChooser_set = false; private boolean _isFolderChooser() { if (this.folderChooser_set) { return this.folderChooser; } ValueExpression _vb = getValueExpression("folderChooser"); if (_vb != null) { Object _result = _vb.getValue(getFacesContext().getELContext()); if (_result == null) { return false; } else { return ((Boolean) _result).booleanValue(); } } return false; } /** *

Use this attribute to configure the file chooser as a folder chooser. * Set the value to true for a folder chooser or false for a file * chooser. The default value is false.

* @see #isFolderChooser() */ private void _setFolderChooser(boolean folderChooser) { this.folderChooser = folderChooser; this.folderChooser_set = true; } /** *

Use this attribute to specify the initial folder to display in the * Look In text field. The contents of this folder will be displayed. * Only java.io.File or java.lang.String objects * can be bound to this attribute.

*/ @Property(name = "lookin", displayName = "Lookin", category = "Data", editorClassName = "com.sun.rave.propertyeditors.StringPropertyEditor") private Object lookin = null; public Object getLookin() { if (this.lookin != null) { return this.lookin; } ValueExpression _vb = getValueExpression("lookin"); if (_vb != null) { return (Object) _vb.getValue(getFacesContext().getELContext()); } return null; } /** *

Use this attribute to specify the initial folder to display in the * Look In text field. The contents of this folder will be displayed. * Only java.io.File or java.lang.String objects * can be bound to this attribute.

* @see #getLookin() */ public void setLookin(Object lookin) { this.lookin = lookin; } // model /** *

Specifies the model associated with the FileChooser. The model * provides the file chooser with content displayed in the file * chooser's list. It provides other services as defined incom.sun.webui.jsf.model.ResourceModel. * If the model attribute is not assigned a value, a FileChooserModel is * used as the ResourceModel instance. A value binding assigned to this * attribute must return an instance of ResourceModel.

*/ @Property(name = "model", displayName = "Model", shortDescription = "The model associated with the filechooser", isHidden = true, isAttribute = false) private com.sun.webui.jsf.model.ResourceModel model = null; private com.sun.webui.jsf.model.ResourceModel _getModel() { if (this.model != null) { return this.model; } ValueExpression _vb = getValueExpression("model"); if (_vb != null) { return (com.sun.webui.jsf.model.ResourceModel) _vb.getValue(getFacesContext().getELContext()); } return null; } /** *

Specifies the model associated with the FileChooser. The model * provides the file chooser with content displayed in the file * chooser's list. It provides other services as defined incom.sun.webui.jsf.model.ResourceModel. * If the model attribute is not assigned a value, a FileChooserModel is * used as the ResourceModel instance. A value binding assigned to this * attribute must return an instance of ResourceModel.

* @see #getModel() */ public void setModel(com.sun.webui.jsf.model.ResourceModel model) { this.model = model; } /** *

Set multiple to true to allow multiple files or folders * to be selected from the list. The default is * false, which allows only one item to be selected.

*/ @Property(name = "multiple", displayName = "Multiple", category = "Appearance") private boolean multiple = false; private boolean multiple_set = false; public boolean isMultiple() { if (this.multiple_set) { return this.multiple; } ValueExpression _vb = getValueExpression("multiple"); if (_vb != null) { Object _result = _vb.getValue(getFacesContext().getELContext()); if (_result == null) { return false; } else { return ((Boolean) _result).booleanValue(); } } return false; } /** *

Set multiple to true to allow multiple files or folders * to be selected from the list. The default is * false, which allows only one item to be selected.

* @see #isMultiple() */ public void setMultiple(boolean multiple) { this.multiple = multiple; this.multiple_set = true; } /** *

If readOnly is set to true, the value of the component is * rendered as text, preceded by the label if one was defined.

*/ @Property(name = "readOnly", displayName = "Read-only", category = "Behavior") private boolean readOnly = false; private boolean readOnly_set = false; public boolean isReadOnly() { if (this.readOnly_set) { return this.readOnly; } ValueExpression _vb = getValueExpression("readOnly"); if (_vb != null) { Object _result = _vb.getValue(getFacesContext().getELContext()); if (_result == null) { return false; } else { return ((Boolean) _result).booleanValue(); } } return false; } /** *

If readOnly is set to true, the value of the component is * rendered as text, preceded by the label if one was defined.

* @see #isReadOnly() */ public void setReadOnly(boolean readOnly) { this.readOnly = readOnly; this.readOnly_set = true; } /** *

The number of items to display in the listbox. The value must be * greater than or equal to one. The default value is 12. Invalid values * are ignored and the value is set to 12.

*/ @Property(name = "rows", displayName = "Rows", category = "Appearance", editorClassName = "com.sun.rave.propertyeditors.IntegerPropertyEditor") private int rows = 12; private boolean rows_set = false; public int getRows() { if (this.rows_set) { return this.rows; } ValueExpression _vb = getValueExpression("rows"); if (_vb != null) { Object _result = _vb.getValue(getFacesContext().getELContext()); if (_result != null && ((Integer) _result).intValue() > 0) { return ((Integer) _result).intValue(); } } // Return the default. int defaultRows = rows; try { defaultRows = Integer.parseInt(getTheme().getMessage( "filechooser.rows")); //NOI18N if (defaultRows < 1) { defaultRows = rows; } } catch (Exception e) { log("Failed to obtain the default value from the theme." + "Using the default value " + defaultRows + "."); } return defaultRows; } /** *

The number of items to display in the listbox. The value must be * greater than or equal to one. The default value is 12. Invalid values * are ignored and the value is set to 12.

* @see #getRows() */ public void setRows(int rows) { if (rows < 1) { throw new IllegalArgumentException(getTheme().getMessage( "filechooser.invalidRows")); } this.rows = rows; this.rows_set = true; } /** *

This attribute represents the value of the fileChooser. Depending on * the value of the folderChooser * attribute, the value of the selected * attribute can consist of * selected files or folders from the listbox and/or paths to files * or folders entered into the Selected File field.

If the multiple attribute is true, the selected attribute must be bound to * one of the following:

  • java.io.File[]
  • java.lang.String[]
  • a java.util.List[] such as java.util.ArrayList, or java.util.LinkedList, or java.util.Vector containing instances of java.io.File or java.lang.String.

* If the multiple attribute is false, * the selected * attribute must * be bound to one of the following:

  • java.io.File
  • java.lang.String

* If a type other than these is contained in a list type or bound * directly to the selected * attribute, then you must specify a converter with the converter * attribute.

*/ @Property(name = "selected", displayName = "Selected", shortDescription = "The selected file(s) or folder(s) name.", category = "Data", editorClassName = "com.sun.rave.propertyeditors.binding.ValueBindingPropertyEditor") public Object getSelected() { return getValue(); } /** *

This attribute represents the value of the fileChooser. Depending on * the value of the folderChooser * attribute, the value of the selected * attribute can consist of * selected files or folders from the listbox and/or paths to files * or folders entered into the Selected File field.

If the multiple attribute is true, the selected attribute must be bound to * one of the following:

  • java.io.File[]
  • java.lang.String[]
  • a java.util.List[] such as java.util.ArrayList, or java.util.LinkedList, or java.util.Vector containing instances of java.io.File or java.lang.String.

* If the multiple attribute is false, * the selected * attribute must * be bound to one of the following:

  • java.io.File
  • java.lang.String

* If a type other than these is contained in a list type or bound * directly to the selected * attribute, then you must specify a converter with the converter * attribute.

* @see #getSelected() */ public void setSelected(Object selected) { setValue(selected); } /** *

Field to use to sort the list of files. Valid values are: *

  • alphabetic - sort alphabetically
  • *
  • size - sort by file size
  • *
  • time - sort by last modified date
*

Note that these values are case sensitive. By default, the list is sorted alphabetically.

*/ @Property(name = "sortField", displayName = "Sort Field", category = "Advanced", editorClassName = "com.sun.webui.jsf.component.propertyeditors.SortFieldEditor") private String sortField = "alphabetic"; private boolean sortField_set = false; public String getSortField() { if (this.sortField_set) { return this.sortField; } ValueExpression _vb = getValueExpression("sortField"); if (_vb != null) { String _result = (String) _vb.getValue(getFacesContext().getELContext()); if (_result != null || _result.trim().length() > 0) { _result = _result.trim(); if (_result.equals(ALPHABETIC) || _result.equals(SIZE) || _result.equals(LASTMODIFIED)) { return _result; } } } // Return the default value. String defaultValue = getTheme().getMessage("filechooser.sortField"); //NOI18N if (defaultValue == null || defaultValue.length() < 1) { defaultValue = sortField; log("Failed to obtain the default value from the theme." + "Using the default value " + defaultValue + "."); } return defaultValue; } /** *

Field to use to sort the list of files. Valid values are: *

  • alphabetic - sort alphabetically
  • *
  • size - sort by file size
  • *
  • time - sort by last modified date
*

Note that these values are case sensitive. By default, the list is sorted alphabetically.

* @see #getSortField() */ public void setSortField(String sortField) { if (sortField == null) { throw new IllegalArgumentException(getTheme().getMessage( "filechooser.nullSortField")); } sortField = sortField.trim(); if (sortField.length() < 1) { throw new IllegalArgumentException(getTheme().getMessage( "filechooser.whitespaceSortField")); } if (!(sortField.equals(ALPHABETIC) || sortField.equals(SIZE) || sortField.equals(LASTMODIFIED))) { throw new IllegalArgumentException(getTheme().getMessage( "filechooser.invalidSortField")); } this.sortField = sortField; this.sortField_set = true; } /** *

CSS style(s) to be applied to the outermost HTML element when this * component is rendered.

*/ @Property(name = "style", displayName = "CSS Style(s)", category = "Appearance", editorClassName = "com.sun.jsfcl.std.css.CssStylePropertyEditor") private String style = null; public String getStyle() { if (this.style != null) { return this.style; } ValueExpression _vb = getValueExpression("style"); if (_vb != null) { return (String) _vb.getValue(getFacesContext().getELContext()); } return null; } /** *

CSS style(s) to be applied to the outermost HTML element when this * component is rendered.

* @see #getStyle() */ public void setStyle(String style) { this.style = style; } /** *

CSS style class(es) to be applied to the outermost HTML element when this * component is rendered.

*/ @Property(name = "styleClass", displayName = "CSS Style Class(es)", category = "Appearance", editorClassName = "com.sun.rave.propertyeditors.StyleClassPropertyEditor") private String styleClass = null; public String getStyleClass() { if (this.styleClass != null) { return this.styleClass; } ValueExpression _vb = getValueExpression("styleClass"); if (_vb != null) { return (String) _vb.getValue(getFacesContext().getELContext()); } return null; } /** *

CSS style class(es) to be applied to the outermost HTML element when this * component is rendered.

* @see #getStyleClass() */ public void setStyleClass(String styleClass) { this.styleClass = styleClass; } /** *

Restore the state of this component.

*/ private void _restoreState(FacesContext _context, Object _state) { Object _values[] = (Object[]) _state; super.restoreState(_context, _values[0]); this.descending = ((Boolean) _values[1]).booleanValue(); this.descending_set = ((Boolean) _values[2]).booleanValue(); this.disabled = ((Boolean) _values[3]).booleanValue(); this.disabled_set = ((Boolean) _values[4]).booleanValue(); this.folderChooser = ((Boolean) _values[5]).booleanValue(); this.folderChooser_set = ((Boolean) _values[6]).booleanValue(); this.lookin = (Object) _values[7]; this.model = (com.sun.webui.jsf.model.ResourceModel) _values[8]; this.multiple = ((Boolean) _values[9]).booleanValue(); this.multiple_set = ((Boolean) _values[10]).booleanValue(); this.readOnly = ((Boolean) _values[11]).booleanValue(); this.readOnly_set = ((Boolean) _values[12]).booleanValue(); this.rows = ((Integer) _values[13]).intValue(); this.rows_set = ((Boolean) _values[14]).booleanValue(); this.sortField = (String) _values[15]; this.style = (String) _values[16]; this.styleClass = (String) _values[17]; } /** *

Save the state of this component.

*/ private Object _saveState(FacesContext _context) { Object _values[] = new Object[18]; _values[0] = super.saveState(_context); _values[1] = this.descending ? Boolean.TRUE : Boolean.FALSE; _values[2] = this.descending_set ? Boolean.TRUE : Boolean.FALSE; _values[3] = this.disabled ? Boolean.TRUE : Boolean.FALSE; _values[4] = this.disabled_set ? Boolean.TRUE : Boolean.FALSE; _values[5] = this.folderChooser ? Boolean.TRUE : Boolean.FALSE; _values[6] = this.folderChooser_set ? Boolean.TRUE : Boolean.FALSE; _values[7] = this.lookin; _values[8] = this.model; _values[9] = this.multiple ? Boolean.TRUE : Boolean.FALSE; _values[10] = this.multiple_set ? Boolean.TRUE : Boolean.FALSE; _values[11] = this.readOnly ? Boolean.TRUE : Boolean.FALSE; _values[12] = this.readOnly_set ? Boolean.TRUE : Boolean.FALSE; _values[13] = new Integer(this.rows); _values[14] = this.rows_set ? Boolean.TRUE : Boolean.FALSE; _values[15] = this.sortField; _values[16] = this.style; _values[17] = this.styleClass; return _values; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy