/*==========================================================================*\
| $Id: WCStyledTable.java,v 1.2 2012/03/28 13:48:07 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.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.log4j.Logger;
import org.json.JSONArray;
import org.webcat.ui.util.ComponentIDGenerator;
import org.webcat.ui.util.DojoUtils;
import org.webcat.core.WCStyledTable;
import com.webobjects.appserver.*;
import com.webobjects.foundation.NSMutableSet;
import er.extensions.components.ERXComponentUtilities;
import er.extensions.foundation.ERXStringUtilities;
// -------------------------------------------------------------------------
/**
* <p>
* A WOGenericContainer that represents a table, formatted and styled
* the standard Web-CAT way. This component also supports drag-and-drop of
* rows.
* </p>
*
* <h2>Bindings</h2>
*
* <p>
* Any bindings not specified below are passed directly to the underlying
* <table> tag so that you can style it and specify any other attributes.
* </p>
*
* <dl>
*
* <dt>id</dt>
* <dd>A unique identifier for the table. When using drag-and-drop, this is
* used to identify the source and target tables for a drag operation.</dd>
*
* <dt>onDropMethod</dt>
* <dd>The name of a method that will be called when one or more rows are
* dropped on this table. If omitted, the table will not support drag and drop.
* This method should be implemented by the component
* that conatins the WCStyledTable, and should have the following signature:
* <code>void yourMethodName(String sourceId, int[] draggedRowIndices,
* String targetId, int[] droppedRowIndices, boolean isCopy).</code>
*
* <dt>multiple</dt>
* <dd>True to allow multiple selection and dragging of rows in the table,
* otherwise false. Defaults to true.</dd>
*
* <dt>withHandles</dt>
* <dd>True if rows can only be dragged by a drag handle; false if they can
* be dragged by clicking anywhere in the row. To place a drag handle on a
* row, put the WCDragHandle element somewhere in the row with an appropriate
* id (the same id can be used for all drag handles in the table, unless you
* do something more complicated like nest tables inside rows), and then
* on the table row, use the <code>dragHandle="theId"</code> attribute. Unlike
* the default Dojo behavior, this value defaults to true.</dd>
*
* <dt>isSource</dt>
* <dd>True if the table can be used as a drag source; false if it can only
* act as a target. Defaults to true.</dd>
*
* <dt>copyOnly</dt>
* <dd>Set to true if items may only be copied; false if moves are also
* permitted. Defaults to false.</dd>
*
* <dt>moveOnly</dt>
* <dd>Set to true if items may only be rearranged in this container; false if
* they may also be copied. Defaults to false.</dd>
*
* <dt>accept</dt>
* <dd>A comma-delimited list of DnD types that can be accepted by this table
* when it acts as a target. The type of a row can be specified by using the
* dndType attribute on the table row's <code><tr></code> tag. By
* default this value will be equivalent to "text", which is also the default
* type of any row that does not have a dndType explicitly provided.</dd>
*
* </dl>
*
* @author Stephen Edwards, Tony Allevato
* @author Last changed by $Author: stedwar2 $
* @version $Revision: 1.2 $, $Date: 2012/03/28 13:48:07 $
*/
public class WCStyledTable
extends WOComponent
{
//~ Constructors ..........................................................
// ----------------------------------------------------------
/**
* Creates a new WCStyledTable object.
*
* @param context The page's context
*/
public WCStyledTable( WOContext context )
{
super( context );
}
//~ KVC attributes (must be public) .......................................
/* public String onDropMethod;
public boolean multiple = true;
public boolean withHandles = true;
public boolean isSource = true;
public boolean copyOnly = false;
public boolean moveOnly = false;
public String accept = null;*/
public ComponentIDGenerator idFor;
//~ Methods ...............................................................
// ----------------------------------------------------------
@Override
public void appendToResponse(WOResponse response, WOContext context)
{
idFor = new ComponentIDGenerator(this);
if (id == null)
{
id = ERXStringUtilities.safeIdentifierName(context.elementID());
}
super.appendToResponse(response, context);
}
// ----------------------------------------------------------
public boolean synchronizesVariablesWithBindings()
{
return false;
}
// ----------------------------------------------------------
public String id()
{
return (String) valueForBinding("id");
}
// ----------------------------------------------------------
public String onDropMethod()
{
return (String) valueForBinding("onDropMethod");
}
// ----------------------------------------------------------
public boolean multiple()
{
return ERXComponentUtilities.booleanValueForBinding(this,
"multiple", true);
}
// ----------------------------------------------------------
public boolean withHandles()
{
return ERXComponentUtilities.booleanValueForBinding(this,
"withHandles", true);
}
// ----------------------------------------------------------
public boolean isSource()
{
return ERXComponentUtilities.booleanValueForBinding(this,
"isSource", true);
}
// ----------------------------------------------------------
public boolean copyOnly()
{
return ERXComponentUtilities.booleanValueForBinding(this,
"copyOnly", false);
}
// ----------------------------------------------------------
public boolean moveOnly()
{
return ERXComponentUtilities.booleanValueForBinding(this,
"moveOnly", false);
}
// ----------------------------------------------------------
public String accept()
{
return (String) valueForBinding("accept");
}
// ----------------------------------------------------------
/**
* Gets the dojoType of the table depending on whether items can be copied
* or not, or whether the table is a pure target.
*
* @return the dojoType of the table
*/
public String sourceDojoType()
{
return "webcat.TableSource";
}
// ----------------------------------------------------------
/**
* Returns the accepted dndTypes of this target as a JSON array that can be
* passed into Dojo. For example, the type list "text,image" would be
* converted to the JSON string '["text", "image"]'.
*
* @return the accepted dndTypes of this target as a JSON array string
*/
public String acceptedTypesAsJSONArray()
{
String accept = accept();
if (accept == null)
{
return null;
}
JSONArray array = new JSONArray();
String[] types = accept.split("\\s*,\\s*");
for (String type : types)
{
array.put(type);
}
return DojoUtils.doubleToSingleQuotes(array.toString());
}
// ----------------------------------------------------------
/**
* The internal JavaScript identifier of the JSON bridge that will be used
* to communicate with the server to handle user interaction events and
* model data requests.
*
* @return the internal JavaScript identifier of the JSON bridge
*/
public String JSONBridgeName()
{
return "__JSONBridge_" + id;
}
// ----------------------------------------------------------
/**
* The internal JavaScript identifier that will refer to the actual
* component inside an AjaxProxy.
*
* @return the internal JavaScript identifier of the component inside the
* AjaxProxy
*/
public String componentProxyName()
{
return "styledTable";
}
// ----------------------------------------------------------
/**
* The full JavaScript reference to the proxy object.
*
* @return the full JavaScript reference to the component proxy object
*/
public String fullProxyReference()
{
return JSONBridgeName() + "." + componentProxyName();
}
// ----------------------------------------------------------
public String attributeStringForOtherBindings()
{
StringBuffer buffer = new StringBuffer(32);
boolean first = true;
for (String binding : bindingKeys())
{
if (explicitBindings.containsObject(binding))
{
continue;
}
Object value = valueForBinding(binding);
if (!first)
{
buffer.append(' ');
}
buffer.append(binding);
buffer.append("=\"");
buffer.append(ERXStringUtilities.escapeNonXMLChars(
value.toString()));
buffer.append('"');
first = false;
}
return buffer.toString();
}
// ----------------------------------------------------------
/**
* Called when items were dropped onto the table. Delegates to the method
* on the parent component that was specified by the "onDropMethod"
* binding.
*
* @param sourceId the identifier of the source of the items that were
* dropped
* @param _dragIndices the array of indices of the items that were dropped
* @param targetId the identifier of this target
* @param _dropIndices the array of indices that represent the locations at
* which the corresponding items in _dragIndices were dropped
* @param isCopy true if the items were copied; false if they were moved
*/
public void _itemsWereDropped(
String sourceId,
JSONArray _dragIndices,
String targetId,
JSONArray _dropIndices,
boolean isCopy)
{
try
{
Method method = parent().getClass().getMethod(
onDropMethod(),
String.class, // sourceId
int[].class, // draggedRowIndices
String.class, // targetId
int[].class, // droppedRowIndices
boolean.class // copy
);
int[] draggedRowIndices = new int[_dragIndices.length()];
for (int i = 0; i < _dragIndices.length(); i++)
{
draggedRowIndices[i] = _dragIndices.getInt(i);
}
int[] droppedRowIndices = new int[_dropIndices.length()];
for (int i = 0; i < _dropIndices.length(); i++)
{
droppedRowIndices[i] = _dropIndices.getInt(i);
}
method.invoke(parent(),
sourceId, draggedRowIndices,
targetId, droppedRowIndices,
isCopy);
}
catch (InvocationTargetException e)
{
log.warn(e.getCause());
}
catch (Exception e)
{
log.warn(e);
}
}
//~ Static/instance variables .............................................
private String id;
static NSMutableSet<String> explicitBindings;
static
{
explicitBindings = new NSMutableSet<String>();
explicitBindings.addObject("id");
explicitBindings.addObject("onDropMethod");
explicitBindings.addObject("multiple");
explicitBindings.addObject("withHandles");
explicitBindings.addObject("isSource");
explicitBindings.addObject("copyOnly");
explicitBindings.addObject("moveOnly");
explicitBindings.addObject("accept");
}
static Logger log = Logger.getLogger(WCStyledTable.class);
}