/*==========================================================================*\
| $Id: OptionEditPanel.java,v 1.5 2012/03/28 13:48:08 stedwar2 Exp $
|*-------------------------------------------------------------------------*|
| Copyright (C) 2006-2012 Virginia Tech
|
| This file is part of Web-CAT.
|
| Web-CAT is free software; you can redistribute it and/or modify
| it under the terms of the GNU Affero General Public License as published
| by the Free Software Foundation; either version 3 of the License, or
| (at your option) any later version.
|
| Web-CAT is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| You should have received a copy of the GNU Affero General Public License
| along with Web-CAT; if not, see <http://www.gnu.org/licenses/>.
\*==========================================================================*/
package org.webcat.core;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.Map;
import java.util.zip.ZipOutputStream;
import org.apache.log4j.Logger;
import org.webcat.archives.ArchiveManager;
import org.webcat.archives.IWritableContainer;
import org.webcat.ui.generators.JavascriptGenerator;
import org.webcat.ui.util.ComponentIDGenerator;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WOResponse;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSData;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSKeyValueCodingAdditions;
import com.webobjects.foundation.NSMutableDictionary;
import er.extensions.eof.ERXConstant;
//-------------------------------------------------------------------------
/**
* A small component that allows editing of one option in an option set.
* @see OptionSetEditor
*
* @author Stephen Edwards
* @author Last changed by $Author: stedwar2 $
* @version $Revision: 1.5 $, $Date: 2012/03/28 13:48:08 $
*/
public class OptionEditPanel
extends WCComponent
implements FileBrowser.FileSelectionListener, FilePickerDelegate
{
//~ Constructors ..........................................................
// ----------------------------------------------------------
/**
* Creates a new OptionEditPanel object.
*
* @param context The context to use
*/
public OptionEditPanel( WOContext context )
{
super( context );
}
//~ KVC Attributes (must be public) .......................................
public NSDictionary<?, ?> option;
public NSKeyValueCodingAdditions optionValues;
public Boolean terse;
public int type = 0;
public String property;
public NSDictionary<?, ?> choice;
public String browsePageName;
public java.io.File base;
public RepositoryEntryRef initialSelectionForFilePicker;
public ComponentIDGenerator idFor = new ComponentIDGenerator(this);
//~ Methods ...............................................................
// ----------------------------------------------------------
public OptionEditPanel self()
{
return this;
}
// ----------------------------------------------------------
public void appendToResponse( WOResponse response, WOContext context )
{
// if ( type == 0 )
{
String typeName = (String)option.objectForKey( "type" );
for ( int i = 0; i < types.length; i++ )
{
if ( types[i].equals( typeName ) )
{
type = i;
break;
}
}
}
theSelectedChoice = null;
if ( property == null )
{
property = (String)option.objectForKey( "property" );
}
log.debug( "option = " + property
+ ", type = " + option.objectForKey( "type" )
+ ", type = " + type );
if (optionValues != null)
{
log.debug("option values hash id = " + optionValues.hashCode());
}
super.appendToResponse( response, context );
}
// ----------------------------------------------------------
public String initialStyle()
{
String style = "margin-top: 0;";
if (terse)
{
style += " display: none";
}
return style;
}
// ----------------------------------------------------------
public boolean isBoolean()
{
return type == BOOLEAN_TYPE;
}
// ----------------------------------------------------------
public boolean isInteger()
{
return type == INTEGER_TYPE;
}
// ----------------------------------------------------------
public boolean isDouble()
{
return type == DOUBLE_TYPE;
}
// ----------------------------------------------------------
public boolean isString()
{
return type == STRING_TYPE;
}
// ----------------------------------------------------------
public boolean isListChoice()
{
return type == LIST_CHOICE_TYPE;
}
// ----------------------------------------------------------
public boolean isRadioChoice()
{
return type == RADIO_CHOICE_TYPE;
}
// ----------------------------------------------------------
public boolean isFile()
{
return type == FILE_TYPE;
}
// ----------------------------------------------------------
public boolean isFileOrDir()
{
return type == FILE_OR_DIR_TYPE;
}
// ----------------------------------------------------------
public boolean isShortText()
{
return type == SHORT_TEXT_TYPE;
}
// ----------------------------------------------------------
public boolean isLongText()
{
return type == LONG_TEXT_TYPE;
}
// ----------------------------------------------------------
public boolean isAntBoolean()
{
return type == ANT_BOOLEAN_TYPE;
}
// ----------------------------------------------------------
public boolean isPassword()
{
return type == PASSWORD_TYPE;
}
// ----------------------------------------------------------
public Object fieldSize()
{
Object result = option.objectForKey( "size" );
if ( result == null )
{
// default sizes
switch ( type )
{
case INTEGER_TYPE:
result = ERXConstant.integerForInt( 4 );
break;
case DOUBLE_TYPE:
result = ERXConstant.integerForInt( 6 );
break;
}
}
return result;
}
// ----------------------------------------------------------
public Object value()
{
Object result = optionValues.valueForKey( property );
if ( result == null )
{
result = option.objectForKey( "default" );
}
return result;
}
// ----------------------------------------------------------
public void setValue( Object value )
{
Object oldValue = value();
log.debug( "set " + property + " = " + value );
if ( isAntBoolean()
&& value != null
&& !( (Boolean)value ).booleanValue() )
{
// For ANT-style booleans, any set value = true, and false means
// unset, so convert false values into nulls
value = null;
}
if ( value != null
&& ( oldValue == null ||
!value().toString().equals( value.toString() ) ) )
{
log.debug( "storing value" );
optionValues.takeValueForKey( value, property );
}
else
{
log.debug( "removing value" );
if ( optionValues instanceof NSMutableDictionary )
{
( (NSMutableDictionary<?, ?>)optionValues )
.removeObjectForKey( property );
}
else if ( optionValues instanceof Map )
{
( (Map<?, ?>)optionValues ).remove( property );
}
else
{
log.error( "Unable to remove key from optionValues of class "
+ optionValues.getClass().getName() );
}
}
}
// ----------------------------------------------------------
public boolean hasValue()
{
Object oldValue = optionValues.valueForKey( property );
return oldValue != null;
}
// ----------------------------------------------------------
public JavascriptGenerator clearValue()
{
setValue( null );
return new JavascriptGenerator().refresh(idFor.get("valueContainer"));
}
// ----------------------------------------------------------
public Object choiceLabel()
{
Object result = choice == null ? null : choice.objectForKey( "label" );
if ( result == null )
{
result = choiceValue();
}
return result;
}
// ----------------------------------------------------------
public Object choiceValue()
{
return choice == null ? null : choice.objectForKey( "value" );
}
// ----------------------------------------------------------
public Object selectedChoice()
{
Object currentValue = value();
if ( theSelectedChoice == null && currentValue != null )
{
String valueString = currentValue.toString();
NSArray<?> choices = (NSArray<?>)option.objectForKey( "choices" );
for ( int i = 0; i < choices.count(); i++ )
{
NSDictionary<?, ?> thisChoice =
(NSDictionary<?, ?>)choices.objectAtIndex( i );
if ( valueString.equals(
thisChoice.objectForKey( "value" ).toString() ) )
{
theSelectedChoice = thisChoice;
break;
}
}
}
return theSelectedChoice;
}
// ----------------------------------------------------------
public void setSelectedChoice( NSDictionary<?, ?> theChoice )
{
setValue( theChoice.objectForKey( "value" ) );
}
// ----------------------------------------------------------
public boolean canBrowse()
{
return browsePageName != null && base != null;
}
// ----------------------------------------------------------
public WOComponent browse()
{
if ( !canBrowse() )
{
error( "File and directory configuration options are" +
"not supported on this page!" );
return null;
}
WOComponent newPage = pageWithName( browsePageName );
myPage = context().page();
newPage.takeValueForKey( myPage, "nextPage" );
newPage.takeValueForKey( Boolean.TRUE, "isEditable" );
if ( ! base.exists() )
{
base.mkdirs();
}
newPage.takeValueForKey( base, "base" );
newPage.takeValueForKey( value(), "currentSelection" );
log.debug( "browse(): current selection = " + value() );
newPage.takeValueForKey( this, "fileSelectionListener" );
newPage.takeValueForKey( Boolean.valueOf( type == FILE_OR_DIR_TYPE ),
"allowSelectDir" );
newPage.takeValueForKey( option.objectForKey( "fileTypes" ),
"allowSelectExtensions" );
return newPage;
}
// ----------------------------------------------------------
private RepositoryEntryRef repositoryEntryRefValue()
{
RepositoryEntryRef entryRef;
if (value() instanceof String)
{
entryRef = RepositoryEntryRef.fromOldStylePath((String) value());
}
else if (value() instanceof NSDictionary<?, ?>)
{
@SuppressWarnings("unchecked")
NSDictionary<String, Object> value =
(NSDictionary<String, Object>) value();
entryRef = RepositoryEntryRef.fromDictionary(value);
}
else
{
entryRef = null;
}
return entryRef;
}
// ----------------------------------------------------------
public JavascriptGenerator showFileDialog()
{
initialSelectionForFilePicker = repositoryEntryRefValue();
JavascriptGenerator js = new JavascriptGenerator();
js.dijit(idFor.get("filePickerDialog")).call("show");
return js;
}
// ----------------------------------------------------------
public boolean fileCanBeSelected(RepositoryEntryRef file, boolean isDirectory)
{
if (isDirectory && type == FILE_TYPE)
{
return false;
}
else if (isDirectory && type == FILE_OR_DIR_TYPE)
{
return true;
}
else
{
NSArray<?> extensions =
(NSArray<?>) option.objectForKey("fileTypes");
if (extensions == null)
{
return true;
}
else
{
return extensions.contains(FileUtilities.extensionOf(
file.name()).toLowerCase());
}
}
}
// ----------------------------------------------------------
public JavascriptGenerator fileWasSelected(RepositoryEntryRef file)
{
setValue(file.dictionaryRepresentation());
JavascriptGenerator js = new JavascriptGenerator();
js.refresh(idFor.get("valueContainer"));
return js;
}
// ----------------------------------------------------------
/**
* View or download the selected file.
* @return a download page for the selected file
* @throws java.io.IOException if an error occurs reading the file
*/
public WOComponent downloadFile()
throws java.io.IOException
{
DeliverFile downloadPage = pageWithName(DeliverFile.class);
RepositoryEntryRef fileRef = repositoryEntryRefValue();
fileRef.resolve(localContext());
if (fileRef.isDirectory())
{
File zipFile = new File(fileRef.name() + ".zip");
downloadPage.setFileName(zipFile);
downloadPage.setContentType(FileUtilities.mimeType(zipFile));
ByteArrayOutputStream boas = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(boas);
IWritableContainer container =
ArchiveManager.getInstance().writableContainerForZip(zos);
fileRef.repository().copyItemToContainer(
fileRef.objectId(), fileRef.name(), container);
container.finish();
zos.close();
downloadPage.setFileData(new NSData(boas.toByteArray()));
boas.close();
}
else
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
File file = new File(fileRef.name());
downloadPage.setFileName(file);
downloadPage.setContentType(FileUtilities.mimeType(file));
fileRef.repository().writeBlobToStream(fileRef.objectId(), baos);
downloadPage.setFileData(new NSData(baos.toByteArray()));
baos.close();
}
downloadPage.setStartDownload(true);
return downloadPage;
}
// ----------------------------------------------------------
public WOComponent selectFile( String filePath )
{
if ( log.isDebugEnabled() )
{
log.debug("selectFile(" + filePath + ")");
}
// Force enclosing option editor to pull new value for optionValues,
// in case the file operations caused a MutableDictionary to be
// flushed and re-read.
if (parent() != null && parent() instanceof OptionSetEditor)
{
OptionSetEditor parent = (OptionSetEditor)parent();
parent.takeValueForKey(
parent.valueForBinding("optionValues"), "optionValues");
}
// Now pull the new value from the parent, but just for this
// binding.
optionValues =
(NSKeyValueCodingAdditions)valueForBinding("optionValues");
setValue( user().authenticationDomain().subdirName()
+ "/" + filePath );
if ( log.isDebugEnabled() )
{
log.debug("selectFile(" + filePath + ")");
log.debug( "new option values: ("
+ (optionValues == null ? "null" : optionValues.hashCode())
+ ")\n" + optionValues );
}
return myPage; // context().page();
}
//~ Instance/static variables .............................................
private NSDictionary<?, ?> theSelectedChoice = null;
private WOComponent myPage;
// private static int UNKNOWN_TYPE = 0;
private static final int BOOLEAN_TYPE = 1;
private static final int INTEGER_TYPE = 2;
private static final int DOUBLE_TYPE = 3;
private static final int STRING_TYPE = 4;
private static final int LIST_CHOICE_TYPE = 5;
private static final int RADIO_CHOICE_TYPE = 6;
private static final int FILE_TYPE = 7;
private static final int FILE_OR_DIR_TYPE = 8;
private static final int SHORT_TEXT_TYPE = 9;
private static final int LONG_TEXT_TYPE = 10;
private static final int ANT_BOOLEAN_TYPE = 11;
private static final int PASSWORD_TYPE = 12;
private static final String[] types = new String[] {
"unknown",
"boolean",
"integer",
"double",
"string",
"listChoice",
"radioChoice",
"file",
"fileOrDir",
"shortText",
"longText",
"antBoolean",
"password"
};
static Logger log = Logger.getLogger( OptionEditPanel.class );
}