Merge from HEAD to WCM-DEV2.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3659 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Britt Park
2006-09-02 18:19:00 +00:00
parent 3b1d6b89f5
commit cc6af1a45c
100 changed files with 4941 additions and 1298 deletions

View File

@@ -29,8 +29,10 @@ import org.alfresco.config.ConfigService;
import org.alfresco.web.app.servlet.ExternalAccessServlet;
import org.alfresco.web.bean.NavigationBean;
import org.alfresco.web.bean.dialog.DialogManager;
import org.alfresco.web.bean.dialog.DialogState;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.wizard.WizardManager;
import org.alfresco.web.bean.wizard.WizardState;
import org.alfresco.web.config.DialogsConfigElement;
import org.alfresco.web.config.NavigationConfigElement;
import org.alfresco.web.config.NavigationElementReader;
@@ -47,9 +49,9 @@ import org.apache.commons.logging.LogFactory;
public class AlfrescoNavigationHandler extends NavigationHandler
{
public final static String OUTCOME_SEPARATOR = ":";
public final static String DIALOG_PREXIX = "dialog" + OUTCOME_SEPARATOR;
public final static String DIALOG_PREFIX = "dialog" + OUTCOME_SEPARATOR;
public final static String WIZARD_PREFIX = "wizard" + OUTCOME_SEPARATOR;
public final static String CLOSE_DIALOG_OUTCOME = DIALOG_PREXIX + "close";
public final static String CLOSE_DIALOG_OUTCOME = DIALOG_PREFIX + "close";
public final static String CLOSE_WIZARD_OUTCOME = WIZARD_PREFIX + "close";
protected final static String CONFIG_NAV_BEAN = "NavigationBean";
@@ -135,7 +137,7 @@ public class AlfrescoNavigationHandler extends NavigationHandler
{
boolean dialog = false;
if (outcome != null && outcome.startsWith(DIALOG_PREXIX))
if (outcome != null && outcome.startsWith(DIALOG_PREFIX))
{
dialog = true;
}
@@ -589,16 +591,51 @@ public class AlfrescoNavigationHandler extends NavigationHandler
// or any overridden outcome that may be present
if (getViewStack(context).empty() == false)
{
String newViewId = (String)getViewStack(context).pop();
// is there an overidden outcome?
String overriddenOutcome = getOutcomeOverride(outcome);
if (overriddenOutcome == null)
{
// there isn't an overidden outcome so go back to the previous view
if (logger.isDebugEnabled())
logger.debug("Closing " + closingItem + ", going back to view id: " + newViewId);
logger.debug("Closing " + closingItem + ", going back to previous page");
// if the top of the stack is not a dialog or wizard just get the
// view id and navigate back to it.
// if the top of the stack is a dialog or wizard retrieve the state
// and setup the appropriate manager with that state, then get the
// appropriate container page and navigate to it.
Object topOfStack = getViewStack(context).pop();
if (logger.isDebugEnabled())
logger.debug("Popped item from the top of the view stack: " + topOfStack);
String newViewId = null;
if (topOfStack instanceof String)
{
newViewId = (String)topOfStack;
}
else if (topOfStack instanceof DialogState)
{
// restore the dialog state and get the dialog container viewId
Application.getDialogManager().restoreState((DialogState)topOfStack);
newViewId = getDialogContainer(context);
}
else if (topOfStack instanceof WizardState)
{
// restore the wizard state and get the wizard container viewId
Application.getWizardManager().restoreState((WizardState)topOfStack);
newViewId = getWizardContainer(context);
}
else
{
if (logger.isWarnEnabled())
logger.warn("Invalid object found on view stack: " + topOfStack);
}
// go to the appropraite page
goToView(context, newViewId);
}
else
@@ -656,33 +693,66 @@ public class AlfrescoNavigationHandler extends NavigationHandler
*
* @param context FacesContext
*/
@SuppressWarnings("unchecked")
protected void addCurrentViewToStack(FacesContext context)
{
// if we are opening a wizard or dialog push the current view
// id on to the stack, but only if it is different than the
// current view at the top (you can't launch a dialog from
// the same page 2 times in a row!)
// if the current viewId is either the dialog or wizard container page
// we need to save the state of the current dialog or wizard to the stack
// TODO: This wouldn't happen if we could be sure a dialog is
// ALWAYS exited properly, look into a way of ensuring
// dialogs get closed if a user navigates away from the page,
// would a PhaseListener help in any way??
// If the current view is a normal page and it is not the same as the
// view currently at the top of the stack (you can't launch a dialog from
// the same page 2 times in a row so it must mean the user navigated away
// from the first dialog) just add the viewId to the stack
// work out what to add to the stack
String viewId = context.getViewRoot().getViewId();
if (getViewStack(context).empty() ||
viewId.equals(getViewStack(context).peek()) == false)
String dialogContainer = getDialogContainer(context);
String wizardContainer = getWizardContainer(context);
Object objectForStack = null;
if (viewId.equals(dialogContainer))
{
getViewStack(context).push(viewId);
if (logger.isDebugEnabled())
logger.debug("Pushed current view to stack: " + viewId);
DialogManager dlgMgr = Application.getDialogManager();
objectForStack = dlgMgr.getState();
}
else if (viewId.equals(wizardContainer))
{
WizardManager wizMgr = Application.getWizardManager();
objectForStack = wizMgr.getState();
}
else
{
if (getViewStack(context).empty() == false && logger.isDebugEnabled())
objectForStack = viewId;
}
// if the stack is currently empty add the item
Stack stack = getViewStack(context);
if (stack.empty())
{
stack.push(objectForStack);
if (logger.isDebugEnabled())
logger.debug("Pushed item to view stack: " + objectForStack);
}
else
{
// if the item to go on to the stack and the top of
// stack are both Strings and equals to each other
// don't add anything to the stack to stop it
// growing unecessarily
Object topOfStack = stack.peek();
if (objectForStack instanceof String &&
topOfStack instanceof String &&
topOfStack.equals(objectForStack))
{
logger.debug("current view is already top the view stack!");
if (logger.isDebugEnabled())
logger.debug("current view is already top of the view stack!");
}
else
{
stack.push(objectForStack);
if (logger.isDebugEnabled())
logger.debug("Pushed item to view stack: " + objectForStack);
}
}
}
@@ -725,13 +795,13 @@ public class AlfrescoNavigationHandler extends NavigationHandler
* the users session, will never be null
*/
@SuppressWarnings("unchecked")
private Stack<String> getViewStack(FacesContext context)
private Stack getViewStack(FacesContext context)
{
Stack<String> viewStack = (Stack)context.getExternalContext().getSessionMap().get(VIEW_STACK);
Stack viewStack = (Stack)context.getExternalContext().getSessionMap().get(VIEW_STACK);
if (viewStack == null)
{
viewStack = new Stack<String>();
viewStack = new Stack();
context.getExternalContext().getSessionMap().put(VIEW_STACK, viewStack);
}

View File

@@ -0,0 +1,143 @@
package org.alfresco.web.app;
import javax.faces.context.FacesContext;
import javax.faces.el.EvaluationException;
import javax.faces.el.VariableResolver;
import org.alfresco.config.Config;
import org.alfresco.config.ConfigService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.jsf.DelegatingVariableResolver;
/**
* JSF VariableResolver that first delegates to the Spring JSF variable
* resolver. The sole purpose of this variable resolver is to look out
* for the <code>Container</code> variable. If this variable is encountered
* the current viewId is examined. If the current viewId matches the
* configured dialog or wizard container the appropriate manager object is
* returned i.e. DialogManager or WizardManager.
*
* <p>Configure this resolver in your <code>faces-config.xml</code> file as follows:
*
* <pre>
* &lt;application&gt;
* ...
* &lt;variable-resolver&gt;org.alfresco.web.app.AlfrescoVariableResolver&lt;/variable-resolver&gt;
* &lt;/application&gt;</pre>
*
* @see org.alfresco.web.bean.dialog.DialogManager
* @see org.alfresco.web.bean.wizard.WizardManager
* @author gavinc
*/
public class AlfrescoVariableResolver extends DelegatingVariableResolver
{
protected String dialogContainer = null;
protected String wizardContainer = null;
private static final String CONTAINER = "Container";
private static final Log logger = LogFactory.getLog(AlfrescoVariableResolver.class);
/**
* Creates a new VariableResolver.
*
* @param originalVariableResolver The original variable resolver
*/
public AlfrescoVariableResolver(VariableResolver originalVariableResolver)
{
super(originalVariableResolver);
}
/**
* Resolves the variable with the given name.
* <p>
* This implementation will first delegate to the Spring variable resolver.
* If the variable is not found by the Spring resolver and the variable name
* is <code>Container</code> the current viewId is examined.
* If the current viewId matches the configured dialog or wizard container
* the appropriate manager object is returned i.e. DialogManager or WizardManager.
*
* @param context FacesContext
* @param name The name of the variable to resolve
*/
public Object resolveVariable(FacesContext context, String name)
throws EvaluationException
{
Object variable = super.resolveVariable(context, name);
if (variable == null)
{
// if the variable was not resolved see if the name is "Container"
if (name.equals(CONTAINER))
{
// get the current view id and the configured dialog and wizard
// container pages
String viewId = context.getViewRoot().getViewId();
String dialogContainer = getDialogContainer(context);
String wizardContainer = getWizardContainer(context);
// see if we are currently in a wizard or a dialog
if (viewId.equals(dialogContainer))
{
variable = Application.getDialogManager();
}
else if (viewId.equals(wizardContainer))
{
variable = Application.getWizardManager();
}
if (variable != null && logger.isDebugEnabled())
{
logger.debug("Resolved 'Container' variable to: " + variable);
}
}
}
return variable;
}
/**
* Retrieves the configured dialog container page
*
* @param context FacesContext
* @return The container page
*/
protected String getDialogContainer(FacesContext context)
{
if (this.dialogContainer == null)
{
ConfigService configSvc = Application.getConfigService(context);
Config globalConfig = configSvc.getGlobalConfig();
if (globalConfig != null)
{
this.dialogContainer = globalConfig.getConfigElement("dialog-container").getValue();
}
}
return this.dialogContainer;
}
/**
* Retrieves the configured wizard container page
*
* @param context FacesContext
* @return The container page
*/
protected String getWizardContainer(FacesContext context)
{
if (this.wizardContainer == null)
{
ConfigService configSvc = Application.getConfigService(context);
Config globalConfig = configSvc.getGlobalConfig();
if (globalConfig != null)
{
this.wizardContainer = globalConfig.getConfigElement("wizard-container").getValue();
}
}
return this.wizardContainer;
}
}

View File

@@ -33,6 +33,7 @@ import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.UnavailableException;
import org.alfresco.config.ConfigService;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.service.cmr.security.AuthenticationService;
@@ -43,7 +44,9 @@ import org.alfresco.web.app.servlet.AuthenticationStatus;
import org.alfresco.web.bean.ErrorBean;
import org.alfresco.web.bean.FileUploadBean;
import org.alfresco.web.bean.LoginBean;
import org.alfresco.web.bean.NavigationBean;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.config.ClientConfigElement;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.portlet.PortletFileUpload;
@@ -259,7 +262,18 @@ public class AlfrescoFacesPortlet extends MyFacesGenericPortlet
// perform the forward to the page processed by the Faces servlet
response.setContentType("text/html");
request.getPortletSession().setAttribute(PortletUtil.PORTLET_REQUEST_FLAG, "true");
nonFacesRequest(request, response, "/jsp/browse/browse.jsp");
// get the start location as configured by the web-client config
ConfigService configService = (ConfigService)ctx.getBean("webClientConfigService");
ClientConfigElement configElement = (ClientConfigElement)configService.getGlobalConfig().getConfigElement("client");
if (NavigationBean.LOCATION_MYALFRESCO.equals(configElement.getInitialLocation()))
{
nonFacesRequest(request, response, "/jsp/dashboards/container.jsp");
}
else
{
nonFacesRequest(request, response, "/jsp/browse/browse.jsp");
}
}
else
{

View File

@@ -77,7 +77,6 @@ public abstract class BaseServlet extends HttpServlet
validRedirectJSPs.add("/jsp/forums/forums.jsp");
validRedirectJSPs.add("/jsp/users/users.jsp");
validRedirectJSPs.add("/jsp/trashcan/trash-list.jsp");
validRedirectJSPs.add("/jsp/dashboards/container.jsp");
}
private static Log logger = LogFactory.getLog(BaseServlet.class);
@@ -156,10 +155,15 @@ public abstract class BaseServlet extends HttpServlet
throws IOException
{
// authentication failed - so end servlet execution and redirect to login page
// also save the full requested URL so the login page knows where to redirect too later
res.sendRedirect(req.getContextPath() + FACES_SERVLET + Application.getLoginPage(sc));
// save the full requested URL so the login page knows where to redirect too later
String uri = req.getRequestURI();
String url = uri + (req.getQueryString() != null ? ("?" + req.getQueryString()) : "");
String url = uri;
if (req.getQueryString() != null && req.getQueryString().length() != 0)
{
url += "?" + req.getQueryString();
}
if (uri.indexOf(req.getContextPath() + FACES_SERVLET) != -1)
{
// if we find a JSF servlet reference in the URI then we need to check if the rest of the

View File

@@ -40,13 +40,12 @@ import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.version.Version;
import org.alfresco.service.cmr.version.VersionType;
import org.alfresco.web.app.AlfrescoNavigationHandler;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.context.UIContextService;
import org.alfresco.web.app.servlet.DownloadContentServlet;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.templating.OutputUtil;
import org.alfresco.web.templating.TemplatingService;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.apache.commons.logging.Log;
@@ -376,8 +375,8 @@ public class CheckinCheckoutBean
*/
private Node setupContentDocument(String id)
{
if (LOGGER.isDebugEnabled())
LOGGER.debug("Setup for action, setting current document to: " + id);
if (logger.isDebugEnabled())
logger.debug("Setup for action, setting current document to: " + id);
Node node = null;
@@ -427,14 +426,14 @@ public class CheckinCheckoutBean
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
tx.begin();
if (LOGGER.isDebugEnabled())
LOGGER.debug("Trying to checkout content node Id: " + node.getId());
if (logger.isDebugEnabled())
logger.debug("Trying to checkout content node Id: " + node.getId());
// checkout the node content to create a working copy
if (LOGGER.isDebugEnabled())
if (logger.isDebugEnabled())
{
LOGGER.debug("Checkout copy location: " + getCopyLocation());
LOGGER.debug("Selected Space Id: " + this.selectedSpaceId);
logger.debug("Checkout copy location: " + getCopyLocation());
logger.debug("Selected Space Id: " + this.selectedSpaceId);
}
NodeRef workingCopyRef;
if (getCopyLocation().equals(COPYLOCATION_OTHER) && this.selectedSpaceId != null)
@@ -478,7 +477,7 @@ public class CheckinCheckoutBean
}
else
{
LOGGER.warn("WARNING: checkoutFile called without a current Document!");
logger.warn("WARNING: checkoutFile called without a current Document!");
}
return outcome;
@@ -494,16 +493,22 @@ public class CheckinCheckoutBean
Node node = getWorkingDocument();
if (node != null)
{
// reset the underlying node
if (this.browseBean.getDocument() != null)
{
this.browseBean.getDocument().reset();
}
// clean up and clear action context
clearUpload();
setDocument(null);
setWorkingDocument(null);
outcome = "browse";
outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME;
}
else
{
LOGGER.warn("WARNING: checkoutFileOK called without a current WorkingDocument!");
logger.warn("WARNING: checkoutFileOK called without a current WorkingDocument!");
}
return outcome;
@@ -524,11 +529,11 @@ public class CheckinCheckoutBean
setDocument(null);
setWorkingDocument(null);
outcome = "browse";
outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME;
}
else
{
LOGGER.warn("WARNING: editFileOK called without a current Document!");
logger.warn("WARNING: editFileOK called without a current Document!");
}
return outcome;
@@ -567,17 +572,12 @@ public class CheckinCheckoutBean
MimetypeMap.MIMETYPE_JAVASCRIPT.equals(mimetype))
{
// make content available to the editing screen
String contentString = reader.getContentString();
setDocumentContent(contentString);
setEditorOutput(contentString);
// navigate to appropriate screen
FacesContext fc = FacesContext.getCurrentInstance();
this.navigator.setupDispatchContext(node);
String s = (MimetypeMap.MIMETYPE_XML.equals(mimetype)
? "editXmlInline"
: "editTextInline");
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, s);
setEditorOutput(reader.getContentString());
// navigate to appropriate screen
FacesContext fc = FacesContext.getCurrentInstance();
this.navigator.setupDispatchContext(node);
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "dialog:editTextInline");
}
else
{
@@ -588,7 +588,7 @@ public class CheckinCheckoutBean
// navigate to appropriate screen
FacesContext fc = FacesContext.getCurrentInstance();
this.navigator.setupDispatchContext(node);
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "editHtmlInline");
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "dialog:editHtmlInline");
}
}
}
@@ -598,7 +598,7 @@ public class CheckinCheckoutBean
// normal downloadable document
FacesContext fc = FacesContext.getCurrentInstance();
this.navigator.setupDispatchContext(node);
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "editFile");
fc.getApplication().getNavigationHandler().handleNavigation(fc, null, "dialog:editFile");
}
}
}
@@ -620,31 +620,23 @@ public class CheckinCheckoutBean
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
tx.begin();
if (LOGGER.isDebugEnabled())
LOGGER.debug("Trying to update content node Id: " + node.getId());
if (logger.isDebugEnabled())
logger.debug("Trying to update content node Id: " + node.getId());
// get an updating writer that we can use to modify the content on the current node
ContentWriter writer = this.contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, true);
writer.putContent(this.editorOutput);
// commit the transaction
tx.commit();
if (nodeService.getProperty(node.getNodeRef(),
TemplatingService.TT_QNAME) != null)
{
OutputUtil.regenerate(node.getNodeRef(),
this.contentService,
this.nodeService);
}
// clean up and clear action context
clearUpload();
setDocument(null);
setDocumentContent(null);
setEditorOutput(null);
outcome = "browse";
outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME;
}
catch (Throwable err)
{
@@ -656,7 +648,7 @@ public class CheckinCheckoutBean
}
else
{
LOGGER.warn("WARNING: editInlineOK called without a current Document!");
logger.warn("WARNING: editInlineOK called without a current Document!");
}
return outcome;
@@ -679,7 +671,7 @@ public class CheckinCheckoutBean
clearUpload();
outcome = "browse";
outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME;
}
catch (Throwable err)
{
@@ -689,7 +681,7 @@ public class CheckinCheckoutBean
}
else
{
LOGGER.warn("WARNING: undoCheckout called without a current WorkingDocument!");
logger.warn("WARNING: undoCheckout called without a current WorkingDocument!");
}
return outcome;
@@ -726,10 +718,10 @@ public class CheckinCheckoutBean
{
throw new IllegalStateException("Node supplied for undo checkout has neither Working Copy or Locked aspect!");
}
clearUpload();
outcome = "browse";
outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME + AlfrescoNavigationHandler.OUTCOME_SEPARATOR + "browse";
}
catch (Throwable err)
{
@@ -738,7 +730,7 @@ public class CheckinCheckoutBean
}
else
{
LOGGER.warn("WARNING: undoCheckout called without a current WorkingDocument!");
logger.warn("WARNING: undoCheckout called without a current WorkingDocument!");
}
return outcome;
@@ -763,8 +755,8 @@ public class CheckinCheckoutBean
tx = Repository.getUserTransaction(context);
tx.begin();
if (LOGGER.isDebugEnabled())
LOGGER.debug("Trying to checkin content node Id: " + node.getId());
if (logger.isDebugEnabled())
logger.debug("Trying to checkin content node Id: " + node.getId());
// we can either checkin the content from the current working copy node
// which would have been previously updated by the user
@@ -816,7 +808,8 @@ public class CheckinCheckoutBean
setDocument(null);
clearUpload();
outcome = "browse";
outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME +
AlfrescoNavigationHandler.OUTCOME_SEPARATOR + "browse";
}
catch (Throwable err)
{
@@ -828,7 +821,7 @@ public class CheckinCheckoutBean
}
else
{
LOGGER.warn("WARNING: checkinFileOK called without a current Document!");
logger.warn("WARNING: checkinFileOK called without a current Document!");
}
return outcome;
@@ -853,8 +846,8 @@ public class CheckinCheckoutBean
tx = Repository.getUserTransaction(context);
tx.begin();
if (LOGGER.isDebugEnabled())
LOGGER.debug("Trying to update content node Id: " + node.getId());
if (logger.isDebugEnabled())
logger.debug("Trying to update content node Id: " + node.getId());
// get an updating writer that we can use to modify the content on the current node
ContentWriter writer = this.contentService.getWriter(node.getNodeRef(), ContentModel.PROP_CONTENT, true);
@@ -872,7 +865,7 @@ public class CheckinCheckoutBean
setDocument(null);
clearUpload();
outcome = "browse";
outcome = AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME;
}
catch (Throwable err)
{
@@ -884,7 +877,7 @@ public class CheckinCheckoutBean
}
else
{
LOGGER.warn("WARNING: updateFileOK called without a current Document!");
logger.warn("WARNING: updateFileOK called without a current Document!");
}
return outcome;
@@ -898,7 +891,7 @@ public class CheckinCheckoutBean
// reset the state
clearUpload();
return "browse";
return AlfrescoNavigationHandler.CLOSE_DIALOG_OUTCOME;
}
/**
@@ -929,7 +922,7 @@ public class CheckinCheckoutBean
// ------------------------------------------------------------------------------
// Private data
private static final Log LOGGER = LogFactory.getLog(CheckinCheckoutBean.class);
private static Log logger = LogFactory.getLog(CheckinCheckoutBean.class);
/** I18N messages */
private static final String MSG_ERROR_CHECKIN = "error_checkin";

View File

@@ -91,13 +91,21 @@ public class LoginBean
}
/**
* @param navigator The NavigationBean to set.
* @param navigator The NavigationBean to set.
*/
public void setNavigator(NavigationBean navigator)
{
this.navigator = navigator;
}
/**
* @param preferences The UserPreferencesBean to set
*/
public void setUserPreferencesBean(UserPreferencesBean preferences)
{
this.preferences = preferences;
}
/**
* @return true if the default Alfresco authentication process is being used, else false
* if an external authorisation mechanism is present.
@@ -329,7 +337,7 @@ public class LoginBean
else
{
// special case to handle jump to My Alfresco page initially
String location = Application.getClientConfig(FacesContext.getCurrentInstance()).getInitialLocation();
String location = this.preferences.getStartLocation();
if (NavigationBean.LOCATION_MYALFRESCO.equals(location))
{
return "myalfresco";
@@ -451,4 +459,7 @@ public class LoginBean
/** The NavigationBean bean reference */
protected NavigationBean navigator;
/** The user preferences bean reference */
protected UserPreferencesBean preferences;
}

View File

@@ -126,6 +126,14 @@ public class NavigationBean
this.contentDiskDriver = contentDiskDriver;
}
/**
* @param preferences The UserPreferencesBean to set
*/
public void setUserPreferencesBean(UserPreferencesBean preferences)
{
this.preferences = preferences;
}
/**
* @return the User object representing the current instance for this user
*/
@@ -252,6 +260,15 @@ public class NavigationBean
}
else if (LOCATION_MYALFRESCO.equals(location))
{
// make sure we set a current node ID as some screens expect this
if (getCurrentNodeId() == null)
{
String homeSpaceId = Application.getCurrentUser(context).getHomeSpaceId();
NodeRef homeSpaceRef = new NodeRef(Repository.getStoreRef(), homeSpaceId);
setCurrentNodeId(homeSpaceRef.getId());
}
// create a breadcrumb handler for this special case location (not a node)
List<IBreadcrumbHandler> elements = new ArrayList<IBreadcrumbHandler>(1);
elements.add(new IBreadcrumbHandler()
{
@@ -507,13 +524,8 @@ public class NavigationBean
{
if (this.location == null)
{
// get the initial location from the client config
String initialLocation = clientConfig.getInitialLocation();
if (initialLocation == null || initialLocation.length() == 0)
{
initialLocation = LOCATION_HOME;
}
processToolbarLocation(initialLocation, false);
// get the initial location from the user preferences
processToolbarLocation(this.preferences.getStartLocation(), false);
}
return this.location;
@@ -798,10 +810,10 @@ public class NavigationBean
private static Logger s_logger = Logger.getLogger(NavigationBean.class);
/** constant values used by the toolbar location modelist control */
static final String LOCATION_COMPANY = "companyhome";
static final String LOCATION_HOME = "userhome";
static final String LOCATION_GUEST = "guesthome";
static final String LOCATION_MYALFRESCO = "myalfresco";
public static final String LOCATION_COMPANY = "companyhome";
public static final String LOCATION_HOME = "userhome";
public static final String LOCATION_GUEST = "guesthome";
public static final String LOCATION_MYALFRESCO = "myalfresco";
private static final String MSG_MYALFRESCO = "my_alfresco";
@@ -828,6 +840,9 @@ public class NavigationBean
/** Client configuration object */
protected ClientConfigElement clientConfig = null;
/** The user preferences bean reference */
protected UserPreferencesBean preferences;
/** Cached path to our CIFS server and top level node DIR */
private String cifsServerPath;

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.bean;
import java.util.ResourceBundle;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.PreferencesService;
/**
* Simple bean backing the user preferences settings.
*
* @author Kevin Roast
*/
public class UserPreferencesBean
{
private static final String PREF_STARTLOCATION = "start-location";
private static final String MSG_MYALFRESCO = "my_alfresco";
private static final String MSG_MYHOME = "my_home";
private static final String MSG_COMPANYHOME = "company_home";
private static final String MSG_GUESTHOME = "guest_home";
public String getStartLocation()
{
String location = (String)PreferencesService.getPreferences().getValue(PREF_STARTLOCATION);
if (location == null)
{
// default to value from client config
location = Application.getClientConfig(FacesContext.getCurrentInstance()).getInitialLocation();
}
return location;
}
public void setStartLocation(String location)
{
PreferencesService.getPreferences().setValue(PREF_STARTLOCATION, location);
}
public SelectItem[] getStartLocations()
{
ResourceBundle msg = Application.getBundle(FacesContext.getCurrentInstance());
return new SelectItem[] {
new SelectItem(NavigationBean.LOCATION_MYALFRESCO, msg.getString(MSG_MYALFRESCO)),
new SelectItem(NavigationBean.LOCATION_HOME, msg.getString(MSG_MYHOME)),
new SelectItem(NavigationBean.LOCATION_COMPANY, msg.getString(MSG_COMPANYHOME)),
new SelectItem(NavigationBean.LOCATION_GUEST, msg.getString(MSG_GUESTHOME))};
}
}

View File

@@ -6,7 +6,7 @@ import java.util.Map;
import javax.faces.context.FacesContext;
import org.alfresco.repo.action.executer.ScriptActionExecutor;
import org.alfresco.repo.action.executer.ScriptActionExecuter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.FacesHelper;
@@ -25,7 +25,7 @@ public class ScriptHandler extends BaseActionHandler
public String getJSPPath()
{
return getJSPPath(ScriptActionExecutor.NAME);
return getJSPPath(ScriptActionExecuter.NAME);
}
public void prepareForSave(Map<String, Serializable> actionProps,
@@ -34,13 +34,13 @@ public class ScriptHandler extends BaseActionHandler
// add the selected script noderef to the action properties
String id = (String)actionProps.get(PROP_SCRIPT);
NodeRef scriptRef = new NodeRef(Repository.getStoreRef(), id);
repoProps.put(ScriptActionExecutor.PARAM_SCRIPTREF, scriptRef);
repoProps.put(ScriptActionExecuter.PARAM_SCRIPTREF, scriptRef);
}
public void prepareForEdit(Map<String, Serializable> actionProps,
Map<String, Serializable> repoProps)
{
NodeRef scriptRef = (NodeRef)repoProps.get(ScriptActionExecutor.PARAM_SCRIPTREF);
NodeRef scriptRef = (NodeRef)repoProps.get(ScriptActionExecuter.PARAM_SCRIPTREF);
actionProps.put(PROP_SCRIPT, scriptRef.getId());
}

View File

@@ -34,8 +34,6 @@ import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.model.FileExistsException;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.CopyService;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
@@ -182,12 +180,8 @@ public class ClipboardBean
*/
private void performPasteItems(int index, int action)
{
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
tx.begin();
if (index == -1)
{
// paste all
@@ -219,16 +213,11 @@ public class ClipboardBean
}
}
// commit the transaction
tx.commit();
// refresh UI on success
UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans();
}
catch (Throwable err)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
Utils.addErrorMessage(Application.getMessage(
FacesContext.getCurrentInstance(), MSG_ERROR_PASTE) + err.getMessage(), err);
}
@@ -241,7 +230,7 @@ public class ClipboardBean
* @param action the clipboard action to perform (see UIClipboardShelfItem)
*/
private void performClipboardOperation(ClipboardItem item, int action)
throws FileExistsException, FileNotFoundException
throws Throwable
{
NodeRef destRef = new NodeRef(Repository.getStoreRef(), this.navigator.getCurrentNodeId());
@@ -267,8 +256,12 @@ public class ClipboardBean
boolean operationComplete = false;
while (operationComplete == false)
{
UserTransaction tx = null;
try
{
// attempt each copy/paste in its own transaction
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance());
tx.begin();
if (item.Mode == ClipboardStatus.COPY)
{
if (action == UIClipboardShelfItem.ACTION_PASTE_LINK)
@@ -399,10 +392,25 @@ public class ClipboardBean
throw fileExistsErr;
}
}
if (operationComplete == false)
catch (Throwable e)
{
String copyOf = Application.getMessage(FacesContext.getCurrentInstance(), MSG_COPY_OF);
name = copyOf + ' ' + name;
// some other type of exception occured - rollback and exit
throw e;
}
finally
{
// rollback if the operation didn't complete
if (operationComplete == false)
{
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
String copyOf = Application.getMessage(FacesContext.getCurrentInstance(), MSG_COPY_OF);
name = copyOf + ' ' + name;
}
else
{
// commit the transaction
tx.commit();
}
}
}
}

View File

@@ -1,23 +1,6 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.bean.content;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
@@ -35,17 +18,9 @@ import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.data.IDataContainer;
import org.alfresco.web.data.QuickSort;
import org.alfresco.web.templating.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.ContentWriter;
import java.io.OutputStreamWriter;
import org.alfresco.web.app.servlet.FacesHelper;
/**
* Bean implementation for the "Create Content Wizard" dialog
*
@@ -53,14 +28,12 @@ import org.alfresco.web.app.servlet.FacesHelper;
*/
public class CreateContentWizard extends BaseContentWizard
{
protected String content = null;
protected String templateTypeName;
protected List<SelectItem> createMimeTypes;
private static final Log LOGGER =
LogFactory.getLog(CreateContentWizard.class);
protected String content = null;
protected List<SelectItem> createMimeTypes;
private static Log logger = LogFactory.getLog(CreateContentWizard.class);
// ------------------------------------------------------------------------------
// Wizard implementation
@@ -68,28 +41,10 @@ public class CreateContentWizard extends BaseContentWizard
protected String finishImpl(FacesContext context, String outcome)
throws Exception
{
LOGGER.debug("saving file content to " + this.fileName);
saveContent(null, this.content);
if (this.templateTypeName != null)
{
LOGGER.debug("generating template output for " + this.templateTypeName);
this.nodeService.setProperty(this.createdNode,
TemplatingService.TT_QNAME,
this.templateTypeName);
TemplatingService ts = TemplatingService.getInstance();
TemplateType tt = this.getTemplateType();
OutputUtil.generate(this.createdNode,
ts.parseXML(this.content),
tt,
this.fileName,
this.getContainerNodeRef(),
this.fileFolderService,
this.contentService,
this.nodeService);
}
// return the default outcome
return outcome;
saveContent(null, this.content);
// return the default outcome
return outcome;
}
@Override
@@ -99,7 +54,6 @@ public class CreateContentWizard extends BaseContentWizard
this.content = null;
this.inlineEdit = true;
this.templateTypeName = null;
this.mimeType = MimetypeMap.MIMETYPE_HTML;
}
@@ -162,20 +116,6 @@ public class CreateContentWizard extends BaseContentWizard
{
this.content = content;
}
public List<SelectItem> getCreateTemplateTypes()
{
Collection<TemplateType> ttl = TemplatingService.getInstance().getTemplateTypes();
List<SelectItem> sil = new ArrayList<SelectItem>(ttl.size());
for (TemplateType tt : ttl)
{
sil.add(new SelectItem(tt.getName(), tt.getName()));
}
QuickSort sorter = new QuickSort(sil, "label", true, IDataContainer.SORT_CASEINSENSITIVE);
sorter.sort();
return sil;
}
/**
* @return Returns a list of mime types to allow the user to select from
@@ -213,37 +153,18 @@ public class CreateContentWizard extends BaseContentWizard
}
else
{
LOGGER.warn("Could not find 'create-mime-types' configuration element");
logger.warn("Could not find 'create-mime-types' configuration element");
}
}
else
{
LOGGER.warn("Could not find 'Content Wizards' configuration section");
logger.warn("Could not find 'Content Wizards' configuration section");
}
}
return this.createMimeTypes;
}
public String getTemplateTypeName()
{
return this.templateTypeName;
}
public TemplateType getTemplateType()
{
final TemplatingService ts = TemplatingService.getInstance();
return ts.getTemplateType(this.getTemplateTypeName());
}
/**
* @param templateType Sets the currently selected template type
*/
public void setTemplateTypeName(final String templateTypeName)
{
this.templateTypeName = templateTypeName;
}
/**
* @return Returns the summary data for the wizard.

View File

@@ -0,0 +1,75 @@
package org.alfresco.web.bean.content;
import java.util.Map;
import javax.faces.context.FacesContext;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.dialog.BaseDialogBean;
import org.alfresco.web.bean.repository.Node;
/**
* Bean implementation of the "View Content Properties" dialog.
*
* @author gavinc
*/
public class ViewContentPropertiesDialog extends BaseDialogBean
{
protected static final String TEMP_PROP_MIMETYPE = "mimetype";
protected Node viewingNode;
// ------------------------------------------------------------------------------
// Dialog implementation
@Override
public void init(Map<String, String> parameters)
{
super.init(parameters);
// setup the editable node
this.viewingNode = new Node(this.browseBean.getDocument().getNodeRef());
// special case for Mimetype - since this is a sub-property of the ContentData object
// we must extract it so it can be edited in the client, then we check for it later
// and create a new ContentData object to wrap it and it's associated URL
ContentData content = (ContentData)this.viewingNode.getProperties().get(ContentModel.PROP_CONTENT);
if (content != null)
{
this.viewingNode.getProperties().put(TEMP_PROP_MIMETYPE, content.getMimetype());
}
// add the specially handled 'size' property
this.viewingNode.addPropertyResolver("size", this.browseBean.resolverSize);
}
@Override
protected String finishImpl(FacesContext context, String outcome)
throws Exception
{
// nothing to do as the finish button is not shown and the dialog is read only
return outcome;
}
@Override
public String getCancelButtonLabel()
{
return Application.getMessage(FacesContext.getCurrentInstance(), "close");
}
// ------------------------------------------------------------------------------
// Bean getters and setters
/**
* Returns the node being viewed
*
* @return The node being viewed
*/
public Node getViewingNode()
{
return this.viewingNode;
}
}

View File

@@ -125,6 +125,14 @@ public class DashboardWizard extends BaseWizardBean
// ------------------------------------------------------------------------------
// Dashboard Wizard bean getters
/**
* @return true to allow the Guest user to configure the dashboard, false otherwise
*/
public boolean getAllowGuestConfig()
{
return DashboardManager.getDashboardConfig().getAllowGuestConfig();
}
/**
* @return The currently selected layout ID - used by the Dynamic Description component
*/

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.bean.dashboard;
import javax.faces.context.FacesContext;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.NavigationBean;
/**
* Backing bean for the Getting Started Dashlet page.
*
* @author Kevin Roast
*/
public class GettingStartedBean
{
private NavigationBean navigationBean;
/**
* @param navigationBean The navigationBean to set.
*/
public void setNavigationBean(NavigationBean navigationBean)
{
this.navigationBean = navigationBean;
}
public String browseHomeSpace()
{
this.navigationBean.setCurrentNodeId(getHomeSpaceId());
return "browse";
}
public String createSpace()
{
this.navigationBean.setCurrentNodeId(getHomeSpaceId());
return "dialog:createSpace";
}
public String createContent()
{
this.navigationBean.setCurrentNodeId(getHomeSpaceId());
return "wizard:createContent";
}
public String addContent()
{
this.navigationBean.setCurrentNodeId(getHomeSpaceId());
return "addContent";
}
private String getHomeSpaceId()
{
return Application.getCurrentUser(FacesContext.getCurrentInstance()).getHomeSpaceId();
}
}

View File

@@ -59,6 +59,11 @@ public abstract class BaseDialogBean implements IDialogBean
this.isFinished = false;
}
public void restored()
{
// do nothing by default, subclasses can override if necessary
}
public String cancel()
{
return getDefaultCancelOutcome();
@@ -126,6 +131,16 @@ public abstract class BaseDialogBean implements IDialogBean
return true;
}
public String getTitle()
{
return null;
}
public String getDescription()
{
return null;
}
/**
* @param browseBean The BrowseBean to set.
*/

View File

@@ -20,11 +20,10 @@ import org.alfresco.web.ui.common.component.UIActionLink;
*
* @author gavinc
*/
public class DialogManager
public final class DialogManager
{
protected IDialogBean currentDialog;
protected DialogConfig currentDialogConfig;
protected Map<String, String> currentDialogParams;
private DialogState currentDialogState;
private Map<String, String> paramsToApply;
/**
* Action handler used to setup parameters for the dialog being launched
@@ -38,7 +37,7 @@ public class DialogManager
if (component instanceof UIActionLink)
{
// store the parameters
this.currentDialogParams = ((UIActionLink)component).getParameterMap();
this.paramsToApply = ((UIActionLink)component).getParameterMap();
}
}
@@ -49,22 +48,48 @@ public class DialogManager
*/
public void setCurrentDialog(DialogConfig config)
{
this.currentDialogConfig = config;
String beanName = this.currentDialogConfig.getManagedBean();
this.currentDialog = (IDialogBean)FacesHelper.getManagedBean(
String beanName = config.getManagedBean();
IDialogBean dialog = (IDialogBean)FacesHelper.getManagedBean(
FacesContext.getCurrentInstance(), beanName);
if (this.currentDialog == null)
if (dialog == null)
{
throw new AlfrescoRuntimeException("Failed to find managed bean '" + beanName + "'");
}
// initialise the managed bean
this.currentDialog.init(this.currentDialogParams);
dialog.init(this.paramsToApply);
// reset the current parameters so subsequent dialogs don't get them
this.currentDialogParams = null;
this.paramsToApply = null;
// create the DialogState object
this.currentDialogState = new DialogState(config, dialog);
}
/**
* Returns the state of the currently active dialog
*
* @return Current dialog's state
*/
public DialogState getState()
{
return this.currentDialogState;
}
/**
* Restores the dialog represented by the given DialogState object.
* NOTE: The dialog's restored() method is also called during this
* method.
*
* @param state The DialogState for the dialog to restore
*/
public void restoreState(DialogState state)
{
this.currentDialogState = state;
// retrieve the dialog and call it's restored() method
this.currentDialogState.getDialog().restored();
}
/**
@@ -74,7 +99,7 @@ public class DialogManager
*/
public DialogConfig getCurrentDialog()
{
return this.currentDialogConfig;
return this.currentDialogState.getConfig();
}
/**
@@ -84,7 +109,7 @@ public class DialogManager
*/
public IDialogBean getBean()
{
return this.currentDialog;
return this.currentDialogState.getDialog();
}
/**
@@ -94,7 +119,7 @@ public class DialogManager
*/
public String getIcon()
{
return this.currentDialogConfig.getIcon();
return this.currentDialogState.getConfig().getIcon();
}
/**
@@ -105,7 +130,7 @@ public class DialogManager
public String getErrorMessage()
{
return Application.getMessage(FacesContext.getCurrentInstance(),
this.currentDialogConfig.getErrorMessageId());
this.currentDialogState.getConfig().getErrorMessageId());
}
/**
@@ -115,15 +140,23 @@ public class DialogManager
*/
public String getTitle()
{
String title = this.currentDialogConfig.getTitleId();
// try and get the title directly from the dialog
String title = this.currentDialogState.getDialog().getTitle();
if (title != null)
if (title == null)
{
title = Application.getMessage(FacesContext.getCurrentInstance(), title);
}
else
{
title = this.currentDialogConfig.getTitle();
// try and get the title via a message bundle key
title = this.currentDialogState.getConfig().getTitleId();
if (title != null)
{
title = Application.getMessage(FacesContext.getCurrentInstance(), title);
}
else
{
// try and get the title from the configuration
title = this.currentDialogState.getConfig().getTitle();
}
}
return title;
@@ -136,15 +169,23 @@ public class DialogManager
*/
public String getDescription()
{
String desc = this.currentDialogConfig.getDescriptionId();
// try and get the description directly from the dialog
String desc = this.currentDialogState.getDialog().getDescription();
if (desc != null)
if (desc == null)
{
desc = Application.getMessage(FacesContext.getCurrentInstance(), desc);
}
else
{
desc = this.currentDialogConfig.getDescription();
// try and get the description via a message bundle key
desc = this.currentDialogState.getConfig().getDescriptionId();
if (desc != null)
{
desc = Application.getMessage(FacesContext.getCurrentInstance(), desc);
}
else
{
// try and get the description from the configuration
desc = this.currentDialogState.getConfig().getDescription();
}
}
return desc;
@@ -158,7 +199,7 @@ public class DialogManager
*/
public String getActions()
{
return this.currentDialogConfig.getActionsConfigId();
return this.currentDialogState.getConfig().getActionsConfigId();
}
/**
@@ -168,7 +209,7 @@ public class DialogManager
*/
public String getPage()
{
return this.currentDialogConfig.getPage();
return this.currentDialogState.getConfig().getPage();
}
/**
@@ -178,7 +219,7 @@ public class DialogManager
*/
public boolean isOKButtonVisible()
{
return this.currentDialogConfig.isOKButtonVisible();
return this.currentDialogState.getConfig().isOKButtonVisible();
}
/**
@@ -191,10 +232,10 @@ public class DialogManager
List<DialogButtonConfig> buttons = null;
// get a list of buttons to display from the configuration
List<DialogButtonConfig> cfgButtons = this.currentDialogConfig.getButtons();
List<DialogButtonConfig> cfgButtons = this.currentDialogState.getConfig().getButtons();
// get a list of buttons added dynamically by the dialog
List<DialogButtonConfig> dynButtons = this.currentDialog.getAdditionalButtons();
List<DialogButtonConfig> dynButtons = this.currentDialogState.getDialog().getAdditionalButtons();
if (cfgButtons != null && dynButtons != null)
{
@@ -223,7 +264,7 @@ public class DialogManager
*/
public String getCancelButtonLabel()
{
return this.currentDialog.getCancelButtonLabel();
return this.currentDialogState.getDialog().getCancelButtonLabel();
}
/**
@@ -233,7 +274,7 @@ public class DialogManager
*/
public String getFinishButtonLabel()
{
return this.currentDialog.getFinishButtonLabel();
return this.currentDialogState.getDialog().getFinishButtonLabel();
}
/**
@@ -243,7 +284,7 @@ public class DialogManager
*/
public boolean getFinishButtonDisabled()
{
return this.currentDialog.getFinishButtonDisabled();
return this.currentDialogState.getDialog().getFinishButtonDisabled();
}
/**
@@ -253,7 +294,7 @@ public class DialogManager
*/
public String finish()
{
return this.currentDialog.finish();
return this.currentDialogState.getDialog().finish();
}
/**
@@ -263,6 +304,6 @@ public class DialogManager
*/
public String cancel()
{
return this.currentDialog.cancel();
return this.currentDialogState.getDialog().cancel();
}
}

View File

@@ -0,0 +1,53 @@
package org.alfresco.web.bean.dialog;
import org.alfresco.web.app.AlfrescoNavigationHandler;
import org.alfresco.web.config.DialogsConfigElement.DialogConfig;
/**
* Object responsible for holding the current state of an active dialog.
*
* @author gavinc
*/
public final class DialogState
{
private DialogConfig config;
private IDialogBean dialog;
/**
* Default constructor
*
* @param config The configuration for the dialog
* @param dialog The dialog bean instance
*/
public DialogState(DialogConfig config, IDialogBean dialog)
{
this.config = config;
this.dialog = dialog;
}
/**
* Returns the configuration for the dialog
*
* @return The dialog configuration
*/
public DialogConfig getConfig()
{
return config;
}
/**
* Returns the bean representing the dialog instance
*
* @return The dialog bean instance
*/
public IDialogBean getDialog()
{
return dialog;
}
@Override
public String toString()
{
return AlfrescoNavigationHandler.DIALOG_PREFIX + this.config.getName();
}
}

View File

@@ -19,6 +19,11 @@ public interface IDialogBean
*/
public void init(Map<String, String> parameters);
/**
* Called when the dialog is restored after a nested dialog is closed
*/
public void restored();
/**
* Method handler called when the cancel button of the dialog is pressed
*
@@ -60,4 +65,22 @@ public interface IDialogBean
* @return true if the button should be disabled
*/
public boolean getFinishButtonDisabled();
/**
* Returns the title to be used for the dialog
* <p>If this returns null the DialogManager will
* lookup the title via the dialog configuration</p>
*
* @return The title or null if the title is to be acquired via configuration
*/
public String getTitle();
/**
* Returns the description to be used for the dialog
* <p>If this returns null the DialogManager will
* lookup the description via the dialog configuration</p>
*
* @return The title or null if the title is to be acquired via configuration
*/
public String getDescription();
}

View File

@@ -12,7 +12,6 @@ import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
*/
public class HeaderSeparatorGenerator extends SeparatorGenerator
{
@Override
protected String getHtml(UIComponent component, PropertySheetItem item)
{
String html = "<div class='wizardSectionHeading mainSubTitle' style='margin-top: 6px; margin-bottom: 6px;'>&nbsp;" +

View File

@@ -0,0 +1,79 @@
package org.alfresco.web.bean.generator;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
/**
* Generates a component to represent a separator.
* <p>The HTML to be used for the separator is configured via the
* <code>setHtml</code> method.
*
* @author gavinc
*/
public class HtmlSeparatorGenerator extends BaseComponentGenerator
{
protected String html = "<b>default</b>";
/**
* Returns the HTML configured to be used for this separator
*
* @return The HTML to display
*/
public String getHtml()
{
return html;
}
/**
* Sets the HTML to display for the separator
*
* @param html The HTML
*/
public void setHtml(String html)
{
this.html = html;
}
@SuppressWarnings("unchecked")
public UIComponent generate(FacesContext context, String id)
{
UIComponent component = this.createOutputTextComponent(context, id);
component.getAttributes().put("escape", Boolean.FALSE);
return component;
}
@Override
@SuppressWarnings("unchecked")
protected UIComponent createComponent(FacesContext context, UIPropertySheet propertySheet,
PropertySheetItem item)
{
UIComponent component = this.generate(context, item.getName());
// set the HTML to use
component.getAttributes().put("value", getResolvedHtml(component, item));
return component;
}
/**
* Returns the resolved HTML to use for the separator.
* <p>In the default case we just return the HTML set
* via setHtml however subclasses may choose to generate
* the resulting HTML using a combination of the HTML set
* via setHtml and the given PropertySheetItem.
*
* @param component The JSF component representing the separator
* @param item The separator item
* @return The resolved HTML
*/
protected String getResolvedHtml(UIComponent component, PropertySheetItem item)
{
// In the default case we just return the HTML set via setHtml
return this.html;
}
}

View File

@@ -0,0 +1,85 @@
package org.alfresco.web.bean.generator;
import javax.faces.component.UIComponent;
import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
/**
* Generates a component to represent a separator that uses the
* property sheet display label configuration. The CSS class used
* for the HTML representing the label can also be configured via
* the <code>setStyleClass</code> method.
*
* @author gavinc
*/
public class LabelSeparatorGenerator extends HtmlSeparatorGenerator
{
protected String style = "margin-top: 6px; margin-bottom: 6px;";
protected String styleClass;
/**
* Returns the CSS class configured to be used for this separator
*
* @return The CSS class
*/
public String getStyleClass()
{
return styleClass;
}
/**
* Sets the CSS class to use for the separator
*
* @param styleClass The CSS class
*/
public void setStyleClass(String styleClass)
{
this.styleClass = styleClass;
}
/**
* Returns the CSS style configured to be used for this separator
*
* @return The CSS style
*/
public String getStyle()
{
return style;
}
/**
* Sets the CSS style to use for the separator
*
* @param style The CSS style
*/
public void setStyle(String style)
{
this.style = style;
}
@Override
protected String getResolvedHtml(UIComponent component, PropertySheetItem item)
{
StringBuilder htmlBuilder = new StringBuilder("<div");
if (this.styleClass != null && this.styleClass.length() > 0)
{
htmlBuilder.append(" class=\"");
htmlBuilder.append(this.styleClass);
htmlBuilder.append("\"");
}
if (this.style != null && this.style.length() > 0)
{
htmlBuilder.append(" style=\"");
htmlBuilder.append(this.style);
htmlBuilder.append("\"");
}
// add the display label and close the div
htmlBuilder.append(">&nbsp;");
htmlBuilder.append(item.getDisplayLabel());
htmlBuilder.append("</div>");
return htmlBuilder.toString();
}
}

View File

@@ -1,49 +1,16 @@
package org.alfresco.web.bean.generator;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
/**
* Generates a component to represent a separator.
* Generates a component to represent a separator using the HTML <code>&lt;hr/&gt;</code> element.
*
* @author gavinc
*/
public class SeparatorGenerator extends BaseComponentGenerator
public class SeparatorGenerator extends HtmlSeparatorGenerator
{
@SuppressWarnings("unchecked")
public UIComponent generate(FacesContext context, String id)
public SeparatorGenerator()
{
UIComponent component = this.createOutputTextComponent(context, id);
component.getAttributes().put("escape", Boolean.FALSE);
// For the standard separator just show a <hr/> element
return component;
}
@Override
@SuppressWarnings("unchecked")
protected UIComponent createComponent(FacesContext context, UIPropertySheet propertySheet,
PropertySheetItem item)
{
UIComponent component = this.generate(context, item.getName());
// set the HTML to use
component.getAttributes().put("value", getHtml(component, item));
return component;
}
/**
* Returns the HTML to display for the separator
*
* @param component The JSF component representing the separator
* @param item The separator item
* @return The HTML
*/
protected String getHtml(UIComponent component, PropertySheetItem item)
{
return "<div style='margin-top: 6px; margin-bottom: 6px;'><hr/></div>";
this.html = "<div style='margin-top: 6px; margin-bottom: 6px;'><hr/></div>";
}
}

View File

@@ -1,7 +1,9 @@
package org.alfresco.web.bean.repository;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
@@ -10,6 +12,8 @@ import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.GUID;
@@ -54,9 +58,6 @@ public class TransientNode extends Node
// initialise the node
initNode(data);
if (logger.isDebugEnabled())
logger.debug("Constructed transient node: " + this);
}
/**
@@ -93,11 +94,64 @@ public class TransientNode extends Node
{
if (assocDef.isChild())
{
this.childAssociations.put(item, data.get(item));
// TODO: handle lists of NodeRef's
NodeRef child = null;
Object obj = data.get(item);
if (obj instanceof String)
{
child = new NodeRef((String)obj);
}
else if (obj instanceof NodeRef)
{
child = (NodeRef)obj;
}
else if (obj instanceof List)
{
if (logger.isWarnEnabled())
logger.warn("0..* child associations are not supported yet");
}
if (child != null)
{
// create a child association reference, add it to a list and add the list
// to the list of child associations for this node
List<ChildAssociationRef> assocs = new ArrayList<ChildAssociationRef>(1);
ChildAssociationRef childRef = new ChildAssociationRef(assocDef.getName(), this.nodeRef,
null, child);
assocs.add(childRef);
this.childAssociations.put(item, assocs);
}
}
else
{
this.associations.put(item, data.get(item));
// TODO: handle lists of NodeRef's
NodeRef target = null;
Object obj = data.get(item);
if (obj instanceof String)
{
target = new NodeRef((String)obj);
}
else if (obj instanceof NodeRef)
{
target = (NodeRef)obj;
}
else if (obj instanceof List)
{
if (logger.isWarnEnabled())
logger.warn("0..* associations are not supported yet");
}
if (target != null)
{
// create a association reference, add it to a list and add the list
// to the list of associations for this node
List<AssociationRef> assocs = new ArrayList<AssociationRef>(1);
AssociationRef assocRef = new AssociationRef(this.nodeRef, assocDef.getName(), target);
assocs.add(assocRef);
this.associations.put(item, assocs);
}
}
}
}
@@ -140,7 +194,7 @@ public class TransientNode extends Node
// don't reset anything otherwise we'll lose our data
// with no way of getting it back!!
}
@Override
public String toString()
{

View File

@@ -130,7 +130,7 @@ public class EmailSpaceUsersDialog extends BaseDialogBean implements IContextLis
Set<String> mailedAuthorities = new HashSet<String>(usersGroups.size());
// walk the list of users/groups to notify
// walk the list of users/groups to notify - handle duplicates along the way
for (Map node : usersGroups)
{
String authority = (String)node.get(PROP_USERNAME);
@@ -254,31 +254,47 @@ public class EmailSpaceUsersDialog extends BaseDialogBean implements IContextLis
tx = Repository.getUserTransaction(context, true);
tx.begin();
// Return all the permissions set against the current node
// for any authentication instance (user/group).
// Then combine them into a single list for each authentication found.
// Return all the permissions set against the current node for any authentication
// instance (user/group), walking the parent space inheritance chain.
// Then combine them into a single list for each authentication found.
String currentAuthority = Application.getCurrentUser(context).getUserName();
Map<String, List<String>> permissionMap = new HashMap<String, List<String>>(8, 1.0f);
Set<AccessPermission> permissions = permissionService.getAllSetPermissions(getSpace().getNodeRef());
for (AccessPermission permission : permissions)
NodeRef spaceRef = getSpace().getNodeRef();
while (spaceRef != null)
{
// we are only interested in Allow and not groups/owner etc.
if (permission.getAccessStatus() == AccessStatus.ALLOWED &&
(permission.getAuthorityType() == AuthorityType.USER ||
permission.getAuthorityType() == AuthorityType.GROUP ||
permission.getAuthorityType() == AuthorityType.GUEST ||
permission.getAuthorityType() == AuthorityType.EVERYONE))
Set<AccessPermission> permissions = permissionService.getAllSetPermissions(spaceRef);
for (AccessPermission permission : permissions)
{
String authority = permission.getAuthority();
List<String> userPermissions = permissionMap.get(authority);
if (userPermissions == null)
// we are only interested in Allow and not Guest/Everyone/owner
if (permission.getAccessStatus() == AccessStatus.ALLOWED &&
(permission.getAuthorityType() == AuthorityType.USER ||
permission.getAuthorityType() == AuthorityType.GROUP))
{
// create for first time
userPermissions = new ArrayList<String>(4);
permissionMap.put(authority, userPermissions);
String authority = permission.getAuthority();
if (currentAuthority.equals(authority) == false)
{
List<String> userPermissions = permissionMap.get(authority);
if (userPermissions == null)
{
// create for first time
userPermissions = new ArrayList<String>(4);
permissionMap.put(authority, userPermissions);
}
// add the permission name for this authority
userPermissions.add(permission.getPermission());
}
}
// add the permission name for this authority
userPermissions.add(permission.getPermission());
}
// walk parent inheritance chain until root or no longer inherits
if (permissionService.getInheritParentPermissions(spaceRef))
{
spaceRef = nodeService.getPrimaryParent(spaceRef).getParentRef();
}
else
{
spaceRef = null;
}
}
@@ -316,79 +332,6 @@ public class EmailSpaceUsersDialog extends BaseDialogBean implements IContextLis
}
return this.usersGroups;
}
/**
* Build a Map representing a user/group with a set of useful property values required
* by the UIUserGroupPicker UI component.
*
* @param authority User/Group authority
* @param roles Role text for the authority
*
* @return Map
*/
private Map buildAuthorityMap(String authority, String roles)
{
Map node = null;
if (AuthorityType.getAuthorityType(authority) == AuthorityType.GUEST ||
this.personService.personExists(authority))
{
NodeRef nodeRef = this.personService.getPerson(authority);
if (nodeRef != null)
{
// create our Node representation
node = new MapNode(nodeRef);
// set data binding properties
// this will also force initialisation of the props now during the UserTransaction
// it is much better for performance to do this now rather than during page bind
Map<String, Object> props = ((MapNode)node).getProperties();
props.put(PROP_FULLNAME, ((String)props.get("firstName")) + ' ' + ((String)props.get("lastName")));
props.put(PROP_ICON, WebResources.IMAGE_PERSON);
props.put(PROP_ISGROUP, false);
}
}
else if (AuthorityType.getAuthorityType(authority) == AuthorityType.GROUP)
{
// need a map (dummy node) to represent props for this Group Authority
node = new HashMap<String, Object>(8, 1.0f);
if (authority.startsWith(PermissionService.GROUP_PREFIX) == true)
{
node.put(PROP_FULLNAME, authority.substring(PermissionService.GROUP_PREFIX.length()));
}
else
{
node.put(PROP_FULLNAME, authority);
}
node.put(PROP_USERNAME, authority);
node.put(PROP_ID, authority);
node.put(PROP_ICON, WebResources.IMAGE_GROUP);
node.put(PROP_ISGROUP, true);
node.put(PROP_EXPANDED, false);
}
if (node != null)
{
// add the common properties
node.put(PROP_ROLES, roles);
node.put(PROP_PARENT, null);
if (this.userGroupLookup.get(authority) != null)
{
// this authority already exists in the list somewhere else - mark as duplicate
node.put(PROP_DUPLICATE, true);
node.put(PROP_SELECTED, false);
}
else
{
// add to table for the first time, not a duplicate
this.userGroupLookup.put(authority, node);
node.put(PROP_DUPLICATE, false);
node.put(PROP_SELECTED, true);
}
}
return node;
}
/**
* @return TemplateMailHelperBean instance for this wizard
@@ -398,6 +341,29 @@ public class EmailSpaceUsersDialog extends BaseDialogBean implements IContextLis
return this.mailHelper;
}
/**
* @return true if any authorities are selected, false otherwise
*/
public boolean getFinishButtonDisabled()
{
boolean disabled = true;
if (this.usersGroups != null)
{
for (Map userGroup : this.usersGroups)
{
if (((Boolean)userGroup.get(PROP_EXPANDED)) == false &&
((Boolean)userGroup.get(PROP_SELECTED)) == true)
{
disabled = false;
break;
}
}
}
return disabled;
}
// ------------------------------------------------------------------------------
// Action Event Listeners
@@ -435,16 +401,25 @@ public class EmailSpaceUsersDialog extends BaseDialogBean implements IContextLis
{
// expand the list for this group by adding the immediate child authorities
boolean selected = (Boolean)userGroup.get(PROP_SELECTED);
String currentAuthority =
Application.getCurrentUser(FacesContext.getCurrentInstance()).getUserName();
Set<String> authorities = authorityService.getContainedAuthorities(
null, pickerEvent.Authority, true);
for (String authority : authorities)
{
Map node = buildAuthorityMap(authority, (String)userGroup.get(PROP_ROLES));
if (node != null)
if (currentAuthority.equals(authority) == false)
{
node.put(PROP_PARENT, userGroup);
node.put(PROP_SELECTED, selected);
this.usersGroups.add(++index, node);
if (AuthorityType.getAuthorityType(authority) == AuthorityType.USER ||
AuthorityType.getAuthorityType(authority) == AuthorityType.GROUP)
{
Map node = buildAuthorityMap(authority, (String)userGroup.get(PROP_ROLES));
if (node != null)
{
node.put(PROP_PARENT, userGroup);
node.put(PROP_SELECTED, selected);
this.usersGroups.add(++index, node);
}
}
}
}
}
@@ -494,4 +469,81 @@ public class EmailSpaceUsersDialog extends BaseDialogBean implements IContextLis
}
}
}
// ------------------------------------------------------------------------------
// Private helpers
/**
* Build a Map representing a user/group with a set of useful property values required
* by the UIUserGroupPicker UI component.
*
* @param authority User/Group authority
* @param roles Role text for the authority
*
* @return Map
*/
private Map buildAuthorityMap(String authority, String roles)
{
Map node = null;
if (AuthorityType.getAuthorityType(authority) == AuthorityType.GUEST ||
this.personService.personExists(authority))
{
NodeRef nodeRef = this.personService.getPerson(authority);
if (nodeRef != null)
{
// create our Node representation
node = new MapNode(nodeRef);
// set data binding properties
// this will also force initialisation of the props now during the UserTransaction
// it is much better for performance to do this now rather than during page bind
Map<String, Object> props = ((MapNode)node).getProperties();
props.put(PROP_FULLNAME, ((String)props.get("firstName")) + ' ' + ((String)props.get("lastName")));
props.put(PROP_ICON, WebResources.IMAGE_PERSON);
props.put(PROP_ISGROUP, false);
}
}
else if (AuthorityType.getAuthorityType(authority) == AuthorityType.GROUP)
{
// need a map (dummy node) to represent props for this Group Authority
node = new HashMap<String, Object>(8, 1.0f);
if (authority.startsWith(PermissionService.GROUP_PREFIX) == true)
{
node.put(PROP_FULLNAME, authority.substring(PermissionService.GROUP_PREFIX.length()));
}
else
{
node.put(PROP_FULLNAME, authority);
}
node.put(PROP_USERNAME, authority);
node.put(PROP_ID, authority);
node.put(PROP_ICON, WebResources.IMAGE_GROUP);
node.put(PROP_ISGROUP, true);
}
if (node != null)
{
// add the common properties
node.put(PROP_ROLES, roles);
node.put(PROP_PARENT, null);
node.put(PROP_EXPANDED, false);
if (this.userGroupLookup.get(authority) != null)
{
// this authority already exists in the list somewhere else - mark as duplicate
node.put(PROP_DUPLICATE, true);
node.put(PROP_SELECTED, false);
}
else
{
// add to table for the first time, not a duplicate
this.userGroupLookup.put(authority, node);
node.put(PROP_DUPLICATE, false);
node.put(PROP_SELECTED, true);
}
}
return node;
}
}

View File

@@ -26,16 +26,12 @@ import org.apache.commons.logging.LogFactory;
*
* @author gavinc
*/
public class WizardManager
public final class WizardManager
{
private static Log logger = LogFactory.getLog(WizardManager.class);
protected int currentStep = 1;
protected PageConfig currentPageCfg;
protected WizardConfig currentWizardConfig;
protected IWizardBean currentWizard;
protected List<StepConfig> steps;
protected Map<String, String> currentWizardParams;
private WizardState currentWizardState;
private Map<String, String> paramsToApply;
/**
* Action handler used to setup parameters for the wizard being launched
@@ -49,7 +45,7 @@ public class WizardManager
if (component instanceof UIActionLink)
{
// store the parameters
this.currentWizardParams = ((UIActionLink)component).getParameterMap();
this.paramsToApply = ((UIActionLink)component).getParameterMap();
}
}
@@ -60,31 +56,53 @@ public class WizardManager
*/
public void setCurrentWizard(WizardConfig config)
{
this.currentStep = 1;
this.currentWizardConfig = config;
String beanName = this.currentWizardConfig.getManagedBean();
this.currentWizard = (IWizardBean)FacesHelper.getManagedBean(
String beanName = config.getManagedBean();
IWizardBean wizard = (IWizardBean)FacesHelper.getManagedBean(
FacesContext.getCurrentInstance(), beanName);
if (this.currentWizard == null)
if (wizard == null)
{
throw new AlfrescoRuntimeException("Failed to find managed bean '" + beanName + "'");
}
// initialise the managed bean
this.currentWizard.init(this.currentWizardParams);
wizard.init(this.paramsToApply);
// reset the current parameters so subsequent wizards don't get them
this.currentWizardParams = null;
this.paramsToApply = null;
// get the steps for the wizard
this.steps = this.currentWizardConfig.getStepsAsList();
// create the WizardState object
this.currentWizardState = new WizardState(config, wizard);
// setup the first step
determineCurrentPage();
}
/**
* Returns the state of the currently active wizard
*
* @return Current wizard's state
*/
public WizardState getState()
{
return this.currentWizardState;
}
/**
* Restores the wizard represented by the given WizardState object.
* NOTE: The wizard's restored() method is also called during this
* method.
*
* @param state The WizardState for the wizard to restore
*/
public void restoreState(WizardState state)
{
this.currentWizardState = state;
// retrieve the wizard and call it's restored() method
this.currentWizardState.getWizard().restored();
}
/**
* Returns the config for the current wizard
*
@@ -92,7 +110,7 @@ public class WizardManager
*/
public WizardConfig getCurrentWizard()
{
return this.currentWizardConfig;
return this.currentWizardState.getConfig();
}
/**
@@ -102,7 +120,7 @@ public class WizardManager
*/
public IWizardBean getBean()
{
return this.currentWizard;
return this.currentWizardState.getWizard();
}
/**
@@ -112,7 +130,7 @@ public class WizardManager
*/
public String getIcon()
{
return this.currentWizardConfig.getIcon();
return this.currentWizardState.getConfig().getIcon();
}
/**
@@ -123,7 +141,7 @@ public class WizardManager
public String getErrorMessage()
{
return Application.getMessage(FacesContext.getCurrentInstance(),
this.currentWizardConfig.getErrorMessageId());
this.currentWizardState.getConfig().getErrorMessageId());
}
/**
@@ -133,15 +151,23 @@ public class WizardManager
*/
public String getTitle()
{
String title = this.currentWizardConfig.getTitleId();
// try and get the title directly from the wizard
String title = this.currentWizardState.getWizard().getTitle();
if (title != null)
if (title == null)
{
title = Application.getMessage(FacesContext.getCurrentInstance(), title);
}
else
{
title = this.currentWizardConfig.getTitle();
// try and get the title via a message bundle key
title = this.currentWizardState.getConfig().getTitleId();
if (title != null)
{
title = Application.getMessage(FacesContext.getCurrentInstance(), title);
}
else
{
// try and get the title from the configuration
title = this.currentWizardState.getConfig().getTitle();
}
}
return title;
@@ -154,15 +180,23 @@ public class WizardManager
*/
public String getDescription()
{
String desc = this.currentWizardConfig.getDescriptionId();
// try and get the description directly from the dialog
String desc = this.currentWizardState.getWizard().getDescription();
if (desc != null)
if (desc == null)
{
desc = Application.getMessage(FacesContext.getCurrentInstance(), desc);
}
else
{
desc = this.currentWizardConfig.getDescription();
// try and get the description via a message bundle key
desc = this.currentWizardState.getConfig().getDescriptionId();
if (desc != null)
{
desc = Application.getMessage(FacesContext.getCurrentInstance(), desc);
}
else
{
// try and get the description from the configuration
desc = this.currentWizardState.getConfig().getDescription();
}
}
return desc;
@@ -175,7 +209,7 @@ public class WizardManager
*/
public int getCurrentStep()
{
return this.currentStep;
return this.currentWizardState.getCurrentStep();
}
/**
@@ -185,7 +219,7 @@ public class WizardManager
*/
public String getCurrentStepAsString()
{
return Integer.toString(this.currentStep);
return Integer.toString(this.currentWizardState.getCurrentStep());
}
/**
@@ -197,7 +231,8 @@ public class WizardManager
*/
public String getCurrentStepName()
{
return ((StepConfig)this.steps.get(this.currentStep-1)).getName();
return ((StepConfig)this.currentWizardState.getSteps().get(
this.currentWizardState.getCurrentStep()-1)).getName();
}
/**
@@ -207,12 +242,12 @@ public class WizardManager
*/
public List<UIListItem> getStepItems()
{
List<UIListItem> items = new ArrayList<UIListItem>(this.steps.size());
List<UIListItem> items = new ArrayList<UIListItem>(this.currentWizardState.getSteps().size());
for (int x = 0; x < this.steps.size(); x++)
for (int x = 0; x < this.currentWizardState.getSteps().size(); x++)
{
String uiStepNumber = Integer.toString(x + 1);
StepConfig stepCfg = this.steps.get(x);
StepConfig stepCfg = this.currentWizardState.getSteps().get(x);
UIListItem item = new UIListItem();
item.setValue(uiStepNumber);
@@ -255,7 +290,7 @@ public class WizardManager
*/
public String getPage()
{
return this.currentPageCfg.getPath();
return this.currentWizardState.getCurrentPageCfg().getPath();
}
/**
@@ -265,7 +300,7 @@ public class WizardManager
*/
public String getStepTitle()
{
String title = this.currentPageCfg.getTitleId();
String title = this.currentWizardState.getCurrentPageCfg().getTitleId();
if (title != null)
{
@@ -273,7 +308,7 @@ public class WizardManager
}
else
{
title = this.currentPageCfg.getTitle();
title = this.currentWizardState.getCurrentPageCfg().getTitle();
}
return title;
@@ -286,7 +321,7 @@ public class WizardManager
*/
public String getStepDescription()
{
String desc = this.currentPageCfg.getDescriptionId();
String desc = this.currentWizardState.getCurrentPageCfg().getDescriptionId();
if (desc != null)
{
@@ -294,7 +329,7 @@ public class WizardManager
}
else
{
desc = this.currentPageCfg.getDescription();
desc = this.currentWizardState.getCurrentPageCfg().getDescription();
}
return desc;
@@ -307,7 +342,7 @@ public class WizardManager
*/
public String getStepInstructions()
{
String instruction = this.currentPageCfg.getInstructionId();
String instruction = this.currentWizardState.getCurrentPageCfg().getInstructionId();
if (instruction != null)
{
@@ -315,7 +350,7 @@ public class WizardManager
}
else
{
instruction = this.currentPageCfg.getInstruction();
instruction = this.currentWizardState.getCurrentPageCfg().getInstruction();
}
return instruction;
@@ -328,7 +363,7 @@ public class WizardManager
*/
public String getNextButtonLabel()
{
return this.currentWizard.getNextButtonLabel();
return this.currentWizardState.getWizard().getNextButtonLabel();
}
/**
@@ -338,13 +373,13 @@ public class WizardManager
*/
public boolean getNextButtonDisabled()
{
if (this.currentStep == this.steps.size())
if (this.currentWizardState.getCurrentStep() == this.currentWizardState.getSteps().size())
{
return true;
}
else
{
return this.currentWizard.getNextButtonDisabled();
return this.currentWizardState.getWizard().getNextButtonDisabled();
}
}
@@ -355,7 +390,7 @@ public class WizardManager
*/
public String getBackButtonLabel()
{
return this.currentWizard.getBackButtonLabel();
return this.currentWizardState.getWizard().getBackButtonLabel();
}
/**
@@ -365,7 +400,7 @@ public class WizardManager
*/
public boolean getBackButtonDisabled()
{
if (this.currentStep == 1)
if (this.currentWizardState.getCurrentStep() == 1)
{
return true;
}
@@ -382,7 +417,7 @@ public class WizardManager
*/
public String getCancelButtonLabel()
{
return this.currentWizard.getCancelButtonLabel();
return this.currentWizardState.getWizard().getCancelButtonLabel();
}
/**
@@ -392,7 +427,7 @@ public class WizardManager
*/
public String getFinishButtonLabel()
{
return this.currentWizard.getFinishButtonLabel();
return this.currentWizardState.getWizard().getFinishButtonLabel();
}
/**
@@ -402,13 +437,13 @@ public class WizardManager
*/
public boolean getFinishButtonDisabled()
{
if (this.currentStep == this.steps.size())
if (this.currentWizardState.getCurrentStep() == this.currentWizardState.getSteps().size())
{
return false;
}
else
{
return this.currentWizard.getFinishButtonDisabled();
return this.currentWizardState.getWizard().getFinishButtonDisabled();
}
}
@@ -419,13 +454,16 @@ public class WizardManager
*/
public void next()
{
this.currentStep++;
// calculate next step number and update wizard state
int currentStep = this.currentWizardState.getCurrentStep();
currentStep++;
this.currentWizardState.setCurrentStep(currentStep);
if (logger.isDebugEnabled())
logger.debug("next called, current step is now: " + this.currentStep);
logger.debug("next called, current step is now: " + this.currentWizardState.getCurrentStep());
// tell the wizard the next button has been pressed
this.currentWizard.next();
this.currentWizardState.getWizard().next();
determineCurrentPage();
}
@@ -437,13 +475,16 @@ public class WizardManager
*/
public void back()
{
this.currentStep--;
// calculate next step number and update wizard state
int currentStep = this.currentWizardState.getCurrentStep();
currentStep--;
this.currentWizardState.setCurrentStep(currentStep);
if (logger.isDebugEnabled())
logger.debug("back called, current step is now: " + this.currentStep);
logger.debug("back called, current step is now: " + this.currentWizardState.getCurrentStep());
// tell the wizard the back button has been pressed
this.currentWizard.back();
this.currentWizardState.getWizard().back();
determineCurrentPage();
}
@@ -455,7 +496,7 @@ public class WizardManager
*/
public String finish()
{
return this.currentWizard.finish();
return this.currentWizardState.getWizard().finish();
}
/**
@@ -465,7 +506,7 @@ public class WizardManager
*/
public String cancel()
{
return this.currentWizard.cancel();
return this.currentWizardState.getWizard().cancel();
}
/**
@@ -473,10 +514,14 @@ public class WizardManager
*/
protected void determineCurrentPage()
{
this.currentPageCfg = null;
// reset the current page config in the state object
this.currentWizardState.setCurrentPageCfg(null);
PageConfig currentPageCfg = null;
// get the config for the current step position
StepConfig stepCfg = this.steps.get(this.currentStep-1);
StepConfig stepCfg = this.currentWizardState.getSteps().get(
this.currentWizardState.getCurrentStep()-1);
// is the step conditional?
if (stepCfg.hasConditionalPages())
@@ -497,25 +542,28 @@ public class WizardManager
Object obj = vb.getValue(context);
if (obj instanceof Boolean && ((Boolean)obj).booleanValue())
{
this.currentPageCfg = pageCfg;
currentPageCfg = pageCfg;
break;
}
}
}
// if none of the conditions passed use the default page
if (this.currentPageCfg == null)
if (currentPageCfg == null)
{
this.currentPageCfg = stepCfg.getDefaultPage();
currentPageCfg = stepCfg.getDefaultPage();
}
if (this.currentPageCfg == null)
if (currentPageCfg == null)
{
throw new AlfrescoRuntimeException("Failed to determine page for step '" + stepCfg.getName() +
"'. Make sure a default page is configured.");
}
// save the current page config in the state object
this.currentWizardState.setCurrentPageCfg(currentPageCfg);
if (logger.isDebugEnabled())
logger.debug("Config for current page: " + this.currentPageCfg);
logger.debug("Config for current page: " + this.currentWizardState.getCurrentPageCfg());
}
}

View File

@@ -0,0 +1,113 @@
package org.alfresco.web.bean.wizard;
import java.util.List;
import org.alfresco.web.app.AlfrescoNavigationHandler;
import org.alfresco.web.config.WizardsConfigElement.PageConfig;
import org.alfresco.web.config.WizardsConfigElement.StepConfig;
import org.alfresco.web.config.WizardsConfigElement.WizardConfig;
/**
* Object responsible for holding the current state of an active wizard.
*
* @author gavinc
*/
public final class WizardState
{
private int currentStep = 1;
private PageConfig currentPageCfg;
private WizardConfig config;
private IWizardBean wizard;
private List<StepConfig> steps;
/**
* Default constructor
*
* @param config The configuration for the wizard
* @param wizard The wizard bean instance
*/
public WizardState(WizardConfig config, IWizardBean wizard)
{
this.config = config;
this.wizard = wizard;
this.steps = this.config.getStepsAsList();
}
/**
* Sets the configuration for the current page of the wizard
*
* @param currentPageCfg The configuration
*/
public void setCurrentPageCfg(PageConfig currentPageCfg)
{
this.currentPageCfg = currentPageCfg;
}
/**
* Sets the current step the wizard is on
*
* @param currentStep The current step number
*/
public void setCurrentStep(int currentStep)
{
this.currentStep = currentStep;
}
/**
* Returns the wizard bean instance
*
* @return The wizard bean instance
*/
public IWizardBean getWizard()
{
return this.wizard;
}
/**
* Returns the configuration for the current wizard
*
* @return The wizard configuration
*/
public WizardConfig getConfig()
{
return this.config;
}
/**
* Returns the configuration for the current page of the wizard
*
* @return The current page configuration
*/
public PageConfig getCurrentPageCfg()
{
return currentPageCfg;
}
/**
* The current step the wizard is on
*
* @return The current wizard step
*/
public int getCurrentStep()
{
return currentStep;
}
/**
* Returns the list of steps the wizard has
*
* @return List of wizard steps
*/
public List<StepConfig> getSteps()
{
return steps;
}
@Override
public String toString()
{
return AlfrescoNavigationHandler.WIZARD_PREFIX + this.config.getName() +
"[" + this.currentStep + "]";
}
}

View File

@@ -0,0 +1,667 @@
package org.alfresco.web.bean.workflow;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.workflow.WorkflowInstance;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition;
import org.alfresco.service.cmr.workflow.WorkflowTransition;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.web.app.AlfrescoNavigationHandler;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.dialog.BaseDialogBean;
import org.alfresco.web.bean.repository.MapNode;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.NodePropertyResolver;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.TransientNode;
import org.alfresco.web.config.DialogsConfigElement.DialogButtonConfig;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.alfresco.web.ui.common.component.data.UIRichList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Bean implementation for the "Manage Task" dialog.
*
* @author gavinc
*/
public class ManageTaskDialog extends BaseDialogBean
{
protected WorkflowService workflowService;
protected Node taskNode;
protected WorkflowTask task;
protected WorkflowInstance workflowInstance;
protected WorkflowTransition[] transitions;
protected NodeRef workflowPackage;
protected List<Node> resources;
protected TaskCompleteResolver completeResolver = new TaskCompleteResolver();
protected UIRichList packageItemsRichList;
protected List<String> packageItemsToAdd;
protected List<String> packageItemsToRemove;
protected String[] itemsToAdd;
protected boolean isItemBeingAdded = false;
protected final Log logger = LogFactory.getLog(getClass());
protected static final String ID_PREFIX = "transition_";
protected static final String CLIENT_ID_PREFIX = AlfrescoNavigationHandler.DIALOG_PREFIX + ID_PREFIX;
// ------------------------------------------------------------------------------
// Dialog implementation
@Override
public void init(Map<String, String> parameters)
{
super.init(parameters);
// reset variables
this.task = null;
this.taskNode = null;
this.workflowInstance = null;
this.transitions = null;
this.workflowPackage = null;
this.resources = null;
this.itemsToAdd = null;
this.packageItemsToAdd = null;
this.packageItemsToRemove = null;
this.isItemBeingAdded = false;
if (this.packageItemsRichList != null)
{
this.packageItemsRichList.setValue(null);
this.packageItemsRichList = null;
}
// get the task details
String taskId = this.parameters.get("id");
this.task = this.workflowService.getTaskById(taskId);
if (this.task != null)
{
// setup a transient node to represent the task we're managing
WorkflowTaskDefinition taskDef = this.task.definition;
this.taskNode = new TransientNode(taskDef.metadata.getName(),
"task_" + System.currentTimeMillis(), this.task.properties);
// get access to the workflow instance for the task
this.workflowInstance = this.task.path.instance;
// setup the workflow package for the task
Serializable obj = this.task.properties.get(WorkflowModel.ASSOC_PACKAGE);
// TODO: remove this workaroud where JBPM may return a String and not the NodeRef
if (obj instanceof NodeRef)
{
this.workflowPackage = (NodeRef)obj;
}
else if (obj instanceof String)
{
this.workflowPackage = new NodeRef((String)obj);
}
if (logger.isDebugEnabled())
{
logger.debug("Task: " + this.task);
logger.debug("Trasient node: " + this.taskNode);
logger.debug("Workflow package: " + this.workflowPackage );
}
}
}
@Override
public void restored()
{
// reset the workflow package rich list so everything gets re-evaluated
if (this.packageItemsRichList != null)
{
this.packageItemsRichList.setValue(null);
this.packageItemsRichList = null;
}
}
@Override
protected String finishImpl(FacesContext context, String outcome)
throws Exception
{
if (logger.isDebugEnabled())
logger.debug("Saving task: " + this.task.id);
// prepare the edited parameters for saving
Map<QName, Serializable> params = WorkflowBean.prepareTaskParams(this.taskNode);
if (logger.isDebugEnabled())
logger.debug("Saving task with parameters: " + params);
// remove any items the user selected to remove
if (this.workflowPackage != null && this.packageItemsToRemove != null &&
this.packageItemsToRemove.size() > 0)
{
for (String removedItem : this.packageItemsToRemove)
{
this.nodeService.removeChild(this.workflowPackage, new NodeRef(removedItem));
}
}
// add any items the user selected to add
if (this.workflowPackage != null && this.packageItemsToAdd != null &&
this.packageItemsToAdd.size() > 0)
{
for (String addedItem : this.packageItemsToAdd)
{
NodeRef addedNodeRef = new NodeRef(addedItem);
this.nodeService.addChild(this.workflowPackage, addedNodeRef,
ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
QName.createValidLocalName((String)this.nodeService.getProperty(
addedNodeRef, ContentModel.PROP_NAME))));
}
}
// update the task with the updated parameters
this.workflowService.updateTask(this.task.id, params, null, null);
return outcome;
}
@Override
public List<DialogButtonConfig> getAdditionalButtons()
{
List<DialogButtonConfig> buttons = null;
if (this.task != null)
{
// get the transitions available from this task and
// show them in the dialog as additional buttons
this.transitions = this.task.path.node.transitions;
if (this.transitions != null)
{
buttons = new ArrayList<DialogButtonConfig>(this.transitions.length);
for (WorkflowTransition trans : this.transitions)
{
buttons.add(new DialogButtonConfig(ID_PREFIX + trans.title, trans.title, null,
"#{DialogManager.bean.transition}", "false", null));
}
}
}
return buttons;
}
@Override
public String getFinishButtonLabel()
{
return Application.getMessage(FacesContext.getCurrentInstance(), "save");
}
@Override
public boolean getFinishButtonDisabled()
{
return false;
}
@Override
public String getTitle()
{
String titleStart = Application.getMessage(FacesContext.getCurrentInstance(), "manage_task_title");
return titleStart + ": " + this.task.title;
}
@Override
public String getDescription()
{
return this.task.description;
}
// ------------------------------------------------------------------------------
// Event handlers
@SuppressWarnings("unused")
public String transition()
{
String outcome = getDefaultFinishOutcome();
if (logger.isDebugEnabled())
logger.debug("Transitioning task: " + this.task.id);
// to find out which transition button was pressed we need
// to look for the button's id in the request parameters,
// the first non-null result is the button that was pressed.
FacesContext context = FacesContext.getCurrentInstance();
Map reqParams = context.getExternalContext().getRequestParameterMap();
String selectedTransition = null;
for (WorkflowTransition trans : this.transitions)
{
Object result = reqParams.get(CLIENT_ID_PREFIX + trans.title);
if (result != null)
{
// this was the button that was pressed
selectedTransition = trans.id;
break;
}
}
if (selectedTransition != null)
{
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(context);
tx.begin();
// prepare the edited parameters for saving
Map<QName, Serializable> params = WorkflowBean.prepareTaskParams(this.taskNode);
if (logger.isDebugEnabled())
logger.debug("Transitioning task with parameters: " + params);
// update the task with the updated parameters
this.workflowService.updateTask(this.task.id, params, null, null);
// signal the selected transition to the workflow task
this.workflowService.endTask(this.task.id, selectedTransition);
// commit the changes
tx.commit();
if (logger.isDebugEnabled())
logger.debug("Ended task with transition: " + selectedTransition);
}
catch (Throwable e)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage(formatErrorMessage(e), e);
outcome = this.getErrorOutcome(e);
}
}
return outcome;
}
/**
* Prepares the dialog to allow the user to add an item to the workflow package
*
* @param event The event
*/
public void prepareForAdd(ActionEvent event)
{
this.isItemBeingAdded = true;
}
/**
* Cancels the adding of an item to the workflow package
*
* @param event The event
*/
public void cancelAddPackageItems(ActionEvent event)
{
this.isItemBeingAdded = false;
}
/**
* Adds an item to the workflow package
*
* @param event The event
*/
public void addPackageItems(ActionEvent event)
{
if (this.itemsToAdd != null)
{
if (this.packageItemsToAdd == null)
{
// create the list of items to add if necessary
this.packageItemsToAdd = new ArrayList<String>(this.itemsToAdd.length);
}
for (String item : this.itemsToAdd)
{
// if this item is in the remove list it means it was there originally
// and has now been re-added, as a result we don't need to do anything
// to the original workflow package, therefore remove from the remove list
if (this.packageItemsToRemove != null && this.packageItemsToRemove.contains(item))
{
this.packageItemsToRemove.remove(item);
if (logger.isDebugEnabled())
logger.debug("Removed item from the removed list: " + item);
}
else
{
this.packageItemsToAdd.add(item);
if (logger.isDebugEnabled())
logger.debug("Added item to the added list: " + item);
}
}
// reset the rich list so it re-renders
this.packageItemsRichList.setValue(null);
}
this.isItemBeingAdded = false;
this.itemsToAdd = null;
}
/**
* Removes an item from the workflow package
*
* @param event The event containing a reference to the item to remove
*/
public void removePackageItem(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String nodeRef = new NodeRef(Repository.getStoreRef(), params.get("id")).toString();
if (this.packageItemsToAdd != null && this.packageItemsToAdd.contains(nodeRef))
{
// remove the item from the added list if it was added in this dialog session
this.packageItemsToAdd.remove(nodeRef);
if (logger.isDebugEnabled())
logger.debug("Removed item from the added list: " + nodeRef);
}
else
{
// add the node to the list of items to remove
if (this.packageItemsToRemove == null)
{
this.packageItemsToRemove = new ArrayList<String>(1);
}
this.packageItemsToRemove.add(nodeRef);
if (logger.isDebugEnabled())
logger.debug("Added item to the removed list: " + nodeRef);
}
// reset the rich list so it re-renders
this.packageItemsRichList.setValue(null);
}
/**
* Toggles the complete flag for a workflow package item
*
* @param event The event containing a reference to the item to toggle the status for
*/
public void togglePackageItemComplete(ActionEvent event)
{
// TODO: implement this!
}
// ------------------------------------------------------------------------------
// Bean Getters and Setters
/**
* Returns a String array of NodeRef's that are being added to the workflow package
*
* @return String array of NodeRef's
*/
public String[] getItemsToAdd()
{
return this.itemsToAdd;
}
/**
* Sets the NodeRef's to add as items to the workflow package
*
* @param itemsToAdd NodeRef's to add to the workflow package
*/
public void setItemsToAdd(String[] itemsToAdd)
{
this.itemsToAdd = itemsToAdd;
}
/**
* Determines whether an item is currently being added to the workflow package
*
* @return true if an item is being added
*/
public boolean isItemBeingAdded()
{
return this.isItemBeingAdded;
}
/**
* Sets the rich list being used for the workflow package items
*
* @param richList The rich list instance
*/
public void setPackageItemsRichList(UIRichList richList)
{
this.packageItemsRichList = richList;
}
/**
* Returns the rich list being used for the workflow package items
*
* @return The rich list instance
*/
public UIRichList getPackageItemsRichList()
{
return this.packageItemsRichList;
}
/**
* Returns the Node representing the task
*
* @return The node
*/
public Node getTaskNode()
{
return this.taskNode;
}
/**
* Returns the WorkflowInstance that the current task belongs to
*
* @return The workflow instance
*/
public WorkflowInstance getWorkflowInstance()
{
return this.workflowInstance;
}
/**
* Returns the action group the current task uses for the workflow package
*
* @return action group id
*/
public String getPackageActionGroup()
{
return (String)this.task.properties.get(
WorkflowModel.PROP_PACKAGE_ACTION_GROUP);
}
/**
* Returns the action group the current task uses for each workflow package item
*
* @return action group id
*/
public String getPackageItemActionGroup()
{
return (String)this.task.properties.get(
WorkflowModel.PROP_PACKAGE_ITEM_ACTION_GROUP);
}
/**
* Returns a list of resources associated with this task
* i.e. the children of the workflow package
*
* @return The list of nodes
*/
public List<Node> getResources()
{
this.resources = new ArrayList<Node>(4);
if (this.workflowPackage != null)
{
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context, true);
tx.begin();
// get existing workflow package items
List<ChildAssociationRef> childRefs = this.nodeService.getChildAssocs(
this.workflowPackage, ContentModel.ASSOC_CONTAINS,
RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref: childRefs)
{
// create our Node representation from the NodeRef
NodeRef nodeRef = ref.getChildRef();
if (this.nodeService.exists(nodeRef))
{
// find it's type so we can see if it's a node we are interested in
QName type = this.nodeService.getType(nodeRef);
// make sure the type is defined in the data dictionary
TypeDefinition typeDef = this.dictionaryService.getType(type);
if (typeDef != null)
{
// look for content nodes or links to content
// NOTE: folders within workflow packages are ignored for now
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT) ||
ContentModel.TYPE_FILELINK.equals(type))
{
// if the node is not in the removed list then add create the
// client side representation and add to the list
if (this.packageItemsToRemove == null ||
this.packageItemsToRemove.contains(nodeRef.toString()) == false)
{
createAndAddNode(nodeRef);
}
}
}
else
{
if (logger.isWarnEnabled())
logger.warn("Found invalid object in database: id = " + nodeRef + ", type = " + type);
}
}
else
{
if (logger.isDebugEnabled())
logger.debug("Ignoring " + nodeRef + " as it has been removed from the repository");
}
}
// now iterate through the items to add list and add them to the list of resources
if (this.packageItemsToAdd != null)
{
for (String newItem : this.packageItemsToAdd)
{
NodeRef nodeRef = new NodeRef(newItem);
if (this.nodeService.exists(nodeRef))
{
// we know the type is correct as this was added as a result of a query
// for all content items so just add the item to the resources list
createAndAddNode(nodeRef);
}
else
{
if (logger.isDebugEnabled())
logger.debug("Ignoring " + nodeRef + " as it has been removed from the repository");
}
}
}
// commit the transaction
tx.commit();
}
catch (Throwable err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
this.resources = Collections.<Node>emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
}
else if (logger.isDebugEnabled())
{
logger.debug("Failed to find workflow package for task: " + this.task.id);
}
return this.resources;
}
/**
* Sets the workflow service to use
*
* @param workflowService
* WorkflowService instance
*/
public void setWorkflowService(WorkflowService workflowService)
{
this.workflowService = workflowService;
}
// ------------------------------------------------------------------------------
// Helper methods
protected void createAndAddNode(NodeRef nodeRef)
{
// create our Node representation
MapNode node = new MapNode(nodeRef, this.nodeService, true);
this.browseBean.setupCommonBindingProperties(node);
// add property resolvers to show path information
node.addPropertyResolver("path", this.browseBean.resolverPath);
node.addPropertyResolver("displayPath", this.browseBean.resolverDisplayPath);
// add a property resolver to indicate whether the item has been completed or not
// node.addPropertyResolver("completed", this.completeResolver);
this.resources.add(node);
}
// ------------------------------------------------------------------------------
// Inner classes
/**
* Property resolver to determine if the given node has been flagged as complete
*/
protected class TaskCompleteResolver implements NodePropertyResolver
{
public Object get(Node node)
{
String result = Application.getMessage(FacesContext.getCurrentInstance(), "no");
List<NodeRef> completedItems = (List<NodeRef>)task.properties.get(
WorkflowModel.PROP_COMPLETED_ITEMS);
if (completedItems != null && completedItems.size() > 0 &&
completedItems.contains(node.getNodeRef()))
{
result = Application.getMessage(FacesContext.getCurrentInstance(), "yes");
}
return result;
}
}
}

View File

@@ -1,476 +0,0 @@
package org.alfresco.web.bean.workflow;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.cmr.workflow.WorkflowTaskDefinition;
import org.alfresco.service.cmr.workflow.WorkflowTransition;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.dialog.BaseDialogBean;
import org.alfresco.web.bean.repository.MapNode;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.NodePropertyResolver;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.TransientNode;
import org.alfresco.web.config.DialogsConfigElement.DialogButtonConfig;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.alfresco.web.ui.common.component.data.UIRichList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Bean implementation for the "Manage WorkItem" dialog.
*
* @author gavinc
*/
public class ManageWorkItemDialog extends BaseDialogBean
{
protected WorkflowService workflowService;
protected Node workItemNode;
protected WorkflowTask workItem;
protected WorkflowTransition[] transitions;
protected List<Node> resources;
protected WorkItemCompleteResolver completeResolver = new WorkItemCompleteResolver();
protected UIRichList packageItemsRichList;
protected static final String ID_PREFIX = "transition_";
protected static final String CLIENT_ID_PREFIX = "dialog:" + ID_PREFIX;
private static final Log logger = LogFactory.getLog(ManageWorkItemDialog.class);
// ------------------------------------------------------------------------------
// Dialog implementation
@Override
public void init(Map<String, String> parameters)
{
super.init(parameters);
String taskId = this.parameters.get("id");
this.workItem = this.workflowService.getTaskById(taskId);
if (this.workItem != null)
{
// setup a transient node to represent the work item we're managing
WorkflowTaskDefinition taskDef = this.workItem.definition;
this.workItemNode = new TransientNode(taskDef.metadata.getName(),
"task_" + System.currentTimeMillis(), this.workItem.properties);
}
}
@Override
protected String finishImpl(FacesContext context, String outcome)
throws Exception
{
if (logger.isDebugEnabled())
logger.debug("Saving work item: " + this.workItemNode.getId());
// prepare the edited parameters for saving
Map<QName, Serializable> params = WorkflowBean.prepareWorkItemParams(this.workItemNode);
// update the task with the updated parameters
this.workflowService.updateTask(this.workItem.id, params, null, null);
return outcome;
}
@Override
public List<DialogButtonConfig> getAdditionalButtons()
{
List<DialogButtonConfig> buttons = null;
if (this.workItem != null)
{
// get the transitions available from this work item and
// show them in the dialog as additional buttons
this.transitions = this.workItem.path.node.transitions;
if (this.transitions != null)
{
buttons = new ArrayList<DialogButtonConfig>(this.transitions.length);
for (WorkflowTransition trans : this.transitions)
{
buttons.add(new DialogButtonConfig(ID_PREFIX + trans.title, trans.title, null,
"#{DialogManager.bean.transition}", "false", null));
}
}
}
return buttons;
}
@Override
public String getFinishButtonLabel()
{
return Application.getMessage(FacesContext.getCurrentInstance(), "save");
}
@Override
public boolean getFinishButtonDisabled()
{
return false;
}
// ------------------------------------------------------------------------------
// Event handlers
@SuppressWarnings("unused")
public String transition()
{
String outcome = getDefaultFinishOutcome();
if (logger.isDebugEnabled())
logger.debug("Transitioning work item: " + this.workItemNode.getId());
// to find out which transition button was pressed we need
// to look for the button's id in the request parameters,
// the first non-null result is the button that was pressed.
FacesContext context = FacesContext.getCurrentInstance();
Map reqParams = context.getExternalContext().getRequestParameterMap();
String selectedTransition = null;
for (WorkflowTransition trans : this.transitions)
{
Object result = reqParams.get(CLIENT_ID_PREFIX + trans.title);
if (result != null)
{
// this was the button that was pressed
selectedTransition = trans.id;
break;
}
}
if (selectedTransition != null)
{
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(context);
tx.begin();
// prepare the edited parameters for saving
Map<QName, Serializable> params = WorkflowBean.prepareWorkItemParams(this.workItemNode);
// update the task with the updated parameters
this.workflowService.updateTask(this.workItem.id, params, null, null);
// signal the selected transition to the workflow task
this.workflowService.endTask(this.workItem.id, selectedTransition);
// commit the changes
tx.commit();
if (logger.isDebugEnabled())
logger.debug("Ended work item with transition: " + selectedTransition);
}
catch (Throwable e)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage(formatErrorMessage(e), e);
outcome = this.getErrorOutcome(e);
}
}
return outcome;
}
/**
* Removes an item from the workflow package
*
* @param event The event containing a reference to the item to remove
*/
public void removePackageItem(ActionEvent event)
{
logger.info("remove package item: " + event);
}
/**
* Toggles the complete flag for a workflow package item
*
* @param event The event containing a reference to the item to toggle the status for
*/
public void togglePackageItemComplete(ActionEvent event)
{
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
// create the node ref for the item we are toggling
NodeRef nodeRef = new NodeRef(Repository.getStoreRef(),
(String)params.get("id"));
// get the existing list of completed items
List<NodeRef> completedItems = (List<NodeRef>)this.workItem.properties.get(
WorkflowModel.PROP_COMPLETED_ITEMS);
if (completedItems == null)
{
// if it doesn't exist yet create the list and add the noderef
completedItems = new ArrayList<NodeRef>(1);
completedItems.add(nodeRef);
this.workItem.properties.put(WorkflowModel.PROP_COMPLETED_ITEMS,
(Serializable)completedItems);
}
else
{
if (completedItems.contains(nodeRef))
{
// the item is already in the list remove it
completedItems.remove(nodeRef);
// NOTE: There is a bug somwehere which causes the list to be
// returned as a byte array instead of a list if an empty
// list is persisted, therefore if the list is now empty
// set the completed items back to null
if (completedItems.size() == 0)
{
this.workItem.properties.put(WorkflowModel.PROP_COMPLETED_ITEMS, null);
}
}
else
{
// the noderef is not in the list yet so just add it
completedItems.add(nodeRef);
}
}
// update the task with the updated parameters
this.workflowService.updateTask(this.workItem.id, this.workItem.properties,
null, null);
// commit the transaction
tx.commit();
// reset the rich list if the change was successful
this.packageItemsRichList.setValue(null);
}
catch (Throwable err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
this.resources = Collections.<Node>emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
}
// ------------------------------------------------------------------------------
// Bean Getters and Setters
/**
* Sets the rich list being used for the workflow package items
*
* @param richList The rich list instance
*/
public void setPackageItemsRichList(UIRichList richList)
{
this.packageItemsRichList = richList;
}
/**
* Returns the rich list being used for the workflow package items
*
* @return The rich list instance
*/
public UIRichList getPackageItemsRichList()
{
return this.packageItemsRichList;
}
/**
* Returns the Node representing the work item
*
* @return The node
*/
public Node getWorkItemNode()
{
return this.workItemNode;
}
/**
* Returns the action group the current task uses for the workflow package
*
* @return action group id
*/
public String getPackageActionGroup()
{
return (String)this.workItem.properties.get(
WorkflowModel.PROP_PACKAGE_ACTION_GROUP);
}
/**
* Returns the action group the current task uses for each workflow package item
*
* @return action group id
*/
public String getPackageItemActionGroup()
{
return (String)this.workItem.properties.get(
WorkflowModel.PROP_PACKAGE_ITEM_ACTION_GROUP);
}
/**
* Returns a list of resources associated with this work item
* i.e. the children of the workflow package
*
* @return The list of nodes
*/
public List<Node> getResources()
{
NodeRef workflowPackage = null;
Serializable obj = this.workItem.properties.get(WorkflowModel.ASSOC_PACKAGE);
// TODO: remove this workaroud where JBPM may return a String and not the NodeRef
if (obj instanceof NodeRef)
{
workflowPackage = (NodeRef)obj;
}
else if (obj instanceof String)
{
workflowPackage = new NodeRef((String)obj);
}
this.resources = new ArrayList<Node>(4);
if (workflowPackage != null)
{
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context, true);
tx.begin();
if (logger.isDebugEnabled())
logger.debug("Found workflow package for work item '" +
this.workItem.id + "': " + workflowPackage );
List<ChildAssociationRef> childRefs = this.nodeService.getChildAssocs(workflowPackage,
ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref: childRefs)
{
// create our Node representation from the NodeRef
NodeRef nodeRef = ref.getChildRef();
if (this.nodeService.exists(nodeRef))
{
// find it's type so we can see if it's a node we are interested in
QName type = this.nodeService.getType(nodeRef);
// make sure the type is defined in the data dictionary
TypeDefinition typeDef = this.dictionaryService.getType(type);
if (typeDef != null)
{
// look for content nodes or links to content
// NOTE: folders within workflow packages are ignored for now
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT) ||
ContentModel.TYPE_FILELINK.equals(type))
{
// create our Node representation
MapNode node = new MapNode(nodeRef, this.nodeService, true);
this.browseBean.setupCommonBindingProperties(node);
// add property resolvers to show path information
node.addPropertyResolver("path", this.browseBean.resolverPath);
node.addPropertyResolver("displayPath", this.browseBean.resolverDisplayPath);
// add a property resolver to indicate whether the item has been completed or not
node.addPropertyResolver("completed", this.completeResolver);
this.resources.add(node);
}
}
else
{
if (logger.isWarnEnabled())
logger.warn("Found invalid object in database: id = " + nodeRef + ", type = " + type);
}
}
}
// commit the transaction
tx.commit();
}
catch (Throwable err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
this.resources = Collections.<Node>emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
}
else if (logger.isDebugEnabled())
{
logger.debug("Failed to find workflow package for work item: " + this.workItem.id);
}
return this.resources;
}
/**
* Sets the workflow service to use
*
* @param workflowService
* WorkflowService instance
*/
public void setWorkflowService(WorkflowService workflowService)
{
this.workflowService = workflowService;
}
// ------------------------------------------------------------------------------
// Helper methods
// ------------------------------------------------------------------------------
// Inner classes
/**
* Property resolver to determine if the given node has been flagged as complete
*/
protected class WorkItemCompleteResolver implements NodePropertyResolver
{
public Object get(Node node)
{
String result = Application.getMessage(FacesContext.getCurrentInstance(), "no");
List<NodeRef> completedItems = (List<NodeRef>)workItem.properties.get(
WorkflowModel.PROP_COMPLETED_ITEMS);
if (completedItems != null && completedItems.size() > 0 &&
completedItems.contains(node.getNodeRef()))
{
result = Application.getMessage(FacesContext.getCurrentInstance(), "yes");
}
return result;
}
}
}

View File

@@ -0,0 +1,199 @@
package org.alfresco.web.bean.workflow;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.dialog.BaseDialogBean;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.ui.common.SortableSelectItem;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIGenericPicker;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Bean implementation for the "Reassign Task" dialog
*
* @author gavinc
*/
public class ReassignTaskDialog extends BaseDialogBean
{
protected String taskId;
protected WorkflowService workflowService;
protected PersonService personService;
private static final Log logger = LogFactory.getLog(ReassignTaskDialog.class);
// ------------------------------------------------------------------------------
// Dialog implementation
@Override
public void init(Map<String, String> parameters)
{
super.init(parameters);
this.taskId = this.parameters.get("task-id");
if (this.taskId == null || this.taskId.length() == 0)
{
throw new IllegalArgumentException("Reassign task dialog called without task id");
}
}
@Override
protected String finishImpl(FacesContext context, String outcome)
throws Exception
{
if (logger.isDebugEnabled())
logger.debug("Reassigning task with id: " + this.taskId);
UIComponent picker = context.getViewRoot().findComponent("dialog:dialog-body:user-picker");
if (picker != null && picker instanceof UIGenericPicker)
{
UIGenericPicker userPicker = (UIGenericPicker)picker;
String[] user = userPicker.getSelectedResults();
if (user != null && user.length > 0)
{
// create a map to hold the new owner property then update the task
String userName = user[0];
Map<QName, Serializable> params = new HashMap<QName, Serializable>(1);
params.put(ContentModel.PROP_OWNER, userName);
this.workflowService.updateTask(this.taskId, params, null, null);
}
else
{
if (logger.isWarnEnabled())
logger.warn("Failed to find selected user, reassign was unsuccessful");
}
}
else
{
if (logger.isWarnEnabled())
logger.warn("Failed to find user-picker component, reassign was unsuccessful");
}
if (logger.isDebugEnabled())
logger.debug("Reassigning task with id: " + this.taskId);
return outcome;
}
@Override
protected String getErrorMessageId()
{
return "error_reassign_task";
}
// ------------------------------------------------------------------------------
// Bean Getters and Setters
/**
* Property accessed by the Generic Picker component.
*
* @return the array of filter options to show in the users/groups picker
*/
public SelectItem[] getFilters()
{
ResourceBundle bundle = Application.getBundle(FacesContext.getCurrentInstance());
return new SelectItem[] {new SelectItem("0", bundle.getString("users"))};
}
/**
* Query callback method executed by the Generic Picker component.
* This method is part of the contract to the Generic Picker, it is up to the backing bean
* to execute whatever query is appropriate and return the results.
*
* @param filterIndex Index of the filter drop-down selection
* @param contains Text from the contains textbox
*
* @return An array of SelectItem objects containing the results to display in the picker.
*/
public SelectItem[] pickerCallback(int filterIndex, String contains)
{
FacesContext context = FacesContext.getCurrentInstance();
SelectItem[] items;
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(context, true);
tx.begin();
// build xpath to match available User/Person objects
NodeRef peopleRef = personService.getPeopleContainer();
// NOTE: see SearcherComponentTest
String xpath = "*[like(@" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + "firstName, '%" + contains + "%', false)" +
" or " + "like(@" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + "lastName, '%" + contains + "%', false)]";
List<NodeRef> nodes = searchService.selectNodes(
peopleRef,
xpath,
null,
this.namespaceService,
false);
items = new SelectItem[nodes.size()];
for (int index=0; index<nodes.size(); index++)
{
NodeRef personRef = nodes.get(index);
String firstName = (String)this.nodeService.getProperty(personRef, ContentModel.PROP_FIRSTNAME);
String lastName = (String)this.nodeService.getProperty(personRef, ContentModel.PROP_LASTNAME);
String username = (String)this.nodeService.getProperty(personRef, ContentModel.PROP_USERNAME);
SelectItem item = new SortableSelectItem(username, firstName + " " + lastName, lastName);
items[index] = item;
}
Arrays.sort(items);
// commit the transaction
tx.commit();
}
catch (Throwable err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
items = new SelectItem[0];
}
return items;
}
/**
* Sets the workflow service to use
*
* @param workflowService The WorkflowService instance
*/
public void setWorkflowService(WorkflowService workflowService)
{
this.workflowService = workflowService;
}
/**
* @param permissionService The PermissionService to set.
*/
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
}

View File

@@ -1,14 +1,18 @@
package org.alfresco.web.bean.workflow;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.SelectItem;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.workflow.WorkflowModel;
@@ -23,10 +27,14 @@ import org.alfresco.service.cmr.workflow.WorkflowTaskState;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.MapNode;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.TransientNode;
import org.alfresco.web.bean.wizard.BaseWizardBean;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.alfresco.web.ui.common.component.data.UIRichList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -42,6 +50,11 @@ public class StartWorkflowWizard extends BaseWizardBean
protected Map<String, WorkflowDefinition> workflows;
protected WorkflowService workflowService;
protected Node startTaskNode;
protected List<Node> resources;
protected List<String> packageItemsToAdd;
protected UIRichList packageItemsRichList;
protected String[] itemsToAdd;
protected boolean isItemBeingAdded = false;
protected boolean nextButtonDisabled = false;
private static final Log logger = LogFactory.getLog(StartWorkflowWizard.class);
@@ -65,6 +78,43 @@ public class StartWorkflowWizard extends BaseWizardBean
}
this.startTaskNode = null;
this.resources = null;
this.itemsToAdd = null;
this.packageItemsToAdd = new ArrayList<String>();
this.isItemBeingAdded = false;
if (this.packageItemsRichList != null)
{
this.packageItemsRichList.setValue(null);
this.packageItemsRichList = null;
}
// TODO: Does this need to be in a read-only transaction??
// add the item the workflow wizard was started on to the list of resources
String itemToWorkflowId = this.parameters.get("item-to-workflow");
if (itemToWorkflowId != null && itemToWorkflowId.length() > 0)
{
// create the node ref for the item and determine its type
NodeRef itemToWorkflow = new NodeRef(Repository.getStoreRef(), itemToWorkflowId);
QName type = this.nodeService.getType(itemToWorkflow);
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT) ||
this.dictionaryService.isSubClass(type, ContentModel.TYPE_FILELINK))
{
this.packageItemsToAdd.add(itemToWorkflow.toString());
}
}
}
@Override
public void restored()
{
// reset the workflow package rich list so everything gets re-evaluated
if (this.packageItemsRichList != null)
{
this.packageItemsRichList.setValue(null);
this.packageItemsRichList = null;
}
}
@Override
@@ -77,26 +127,23 @@ public class StartWorkflowWizard extends BaseWizardBean
logger.debug("Starting workflow: " + this.selectedWorkflow);
// prepare the parameters from the current state of the property sheet
Map<QName, Serializable> params = WorkflowBean.prepareWorkItemParams(this.startTaskNode);
Map<QName, Serializable> params = WorkflowBean.prepareTaskParams(this.startTaskNode);
if (logger.isDebugEnabled())
logger.debug("Starting workflow with parameters: " + params);
// create a workflow package for the attached items and add them
String itemToWorkflowId = this.parameters.get("item-to-workflow");
if (itemToWorkflowId != null && itemToWorkflowId.length() > 0)
if (this.packageItemsToAdd.size() > 0)
{
// create the node ref for the item and determine its type
NodeRef itemToWorkflow = new NodeRef(Repository.getStoreRef(), itemToWorkflowId);
QName type = this.nodeService.getType(itemToWorkflow);
NodeRef workflowPackage = this.workflowService.createPackage(null);
NodeRef workflowPackage = null;
if (this.dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT) ||
this.dictionaryService.isSubClass(type, ContentModel.TYPE_FILELINK))
for (String addedItem : this.packageItemsToAdd)
{
// create a workflow package and add the given item to workflow as a child
workflowPackage = this.workflowService.createPackage(null);
this.nodeService.addChild(workflowPackage, itemToWorkflow,
NodeRef addedNodeRef = new NodeRef(addedItem);
this.nodeService.addChild(workflowPackage, addedNodeRef,
ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
QName.createValidLocalName((String)this.nodeService.getProperty(
itemToWorkflow, ContentModel.PROP_NAME))));
addedNodeRef, ContentModel.PROP_NAME))));
}
// add the workflow package to the parameter map
@@ -175,9 +222,131 @@ public class StartWorkflowWizard extends BaseWizardBean
return this.nextButtonDisabled;
}
// ------------------------------------------------------------------------------
// Event Handlers
/**
* Prepares the dialog to allow the user to add an item to the workflow package
*
* @param event The event
*/
public void prepareForAdd(ActionEvent event)
{
this.isItemBeingAdded = true;
}
/**
* Cancels the adding of an item to the workflow package
*
* @param event The event
*/
public void cancelAddPackageItems(ActionEvent event)
{
this.isItemBeingAdded = false;
}
/**
* Adds items to the workflow package
*
* @param event The event
*/
public void addPackageItems(ActionEvent event)
{
if (this.itemsToAdd != null)
{
for (String item : this.itemsToAdd)
{
this.packageItemsToAdd.add(item);
if (logger.isDebugEnabled())
logger.debug("Added item to the added list: " + item);
}
// reset the rich list so it re-renders
this.packageItemsRichList.setValue(null);
}
this.isItemBeingAdded = false;
this.itemsToAdd = null;
}
/**
* Removes an item from the workflow package
*
* @param event The event containing a reference to the item to remove
*/
public void removePackageItem(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String nodeRef = new NodeRef(Repository.getStoreRef(), params.get("id")).toString();
if (this.packageItemsToAdd.contains(nodeRef))
{
// remove the item from the added list if it was added in this dialog session
this.packageItemsToAdd.remove(nodeRef);
if (logger.isDebugEnabled())
logger.debug("Removed item from the added list: " + nodeRef);
}
// reset the rich list so it re-renders
this.packageItemsRichList.setValue(null);
}
// ------------------------------------------------------------------------------
// Bean Getters and Setters
/**
* Returns a String array of NodeRef's that are being added to the workflow package
*
* @return String array of NodeRef's
*/
public String[] getItemsToAdd()
{
return this.itemsToAdd;
}
/**
* Sets the NodeRef's to add as items to the workflow package
*
* @param itemsToAdd NodeRef's to add to the workflow package
*/
public void setItemsToAdd(String[] itemsToAdd)
{
this.itemsToAdd = itemsToAdd;
}
/**
* Determines whether an item is currently being added to the workflow package
*
* @return true if an item is being added
*/
public boolean isItemBeingAdded()
{
return this.isItemBeingAdded;
}
/**
* Sets the rich list being used for the workflow package items
*
* @param richList The rich list instance
*/
public void setPackageItemsRichList(UIRichList richList)
{
this.packageItemsRichList = richList;
}
/**
* Returns the rich list being used for the workflow package items
*
* @return The rich list instance
*/
public UIRichList getPackageItemsRichList()
{
return this.packageItemsRichList;
}
/**
* Returns the workflow selected by the user
*
@@ -317,6 +486,59 @@ public class StartWorkflowWizard extends BaseWizardBean
return availableWorkflows;
}
/**
* Returns a list of resources associated with this task
* i.e. the children of the workflow package
*
* @return The list of nodes
*/
public List<Node> getResources()
{
this.resources = new ArrayList<Node>(4);
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context, true);
tx.begin();
for (String newItem : this.packageItemsToAdd)
{
NodeRef nodeRef = new NodeRef(newItem);
if (this.nodeService.exists(nodeRef))
{
// create our Node representation
MapNode node = new MapNode(nodeRef, this.nodeService, true);
this.browseBean.setupCommonBindingProperties(node);
// add property resolvers to show path information
node.addPropertyResolver("path", this.browseBean.resolverPath);
node.addPropertyResolver("displayPath", this.browseBean.resolverDisplayPath);
this.resources.add(node);
}
else
{
if (logger.isDebugEnabled())
logger.debug("Ignoring " + nodeRef + " as it has been removed from the repository");
}
}
// commit the transaction
tx.commit();
}
catch (Throwable err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
this.resources = Collections.<Node>emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
return this.resources;
}
/**
* Sets the workflow service to use
*

View File

@@ -0,0 +1,48 @@
package org.alfresco.web.bean.workflow;
import java.util.List;
import javax.faces.context.FacesContext;
import org.alfresco.web.app.Application;
import org.alfresco.web.config.DialogsConfigElement.DialogButtonConfig;
/**
* Bean implementation for the "View Completed Task" dialog.
*
* @author gavinc
*/
public class ViewCompletedTaskDialog extends ManageTaskDialog
{
// ------------------------------------------------------------------------------
// Dialog implementation
@Override
protected String finishImpl(FacesContext context, String outcome)
throws Exception
{
// nothing to do as the finish button is not shown and the dialog is read only
return outcome;
}
@Override
public String getCancelButtonLabel()
{
return Application.getMessage(FacesContext.getCurrentInstance(), "close");
}
@Override
public List<DialogButtonConfig> getAdditionalButtons()
{
return null;
}
@Override
public String getTitle()
{
String titleStart = Application.getMessage(FacesContext.getCurrentInstance(), "view_completed_task_title");
return titleStart + ": " + this.task.title;
}
}

View File

@@ -39,8 +39,8 @@ public class WorkflowBean
{
protected NodeService nodeService;
protected WorkflowService workflowService;
protected List<Node> workItems;
protected List<Node> completedWorkItems;
protected List<Node> tasks;
protected List<Node> completedTasks;
private static final Log logger = LogFactory.getLog(WorkflowBean.class);
@@ -48,12 +48,12 @@ public class WorkflowBean
// Bean Getters and Setters
/**
* Returns a list of nodes representing the to do work items the
* Returns a list of nodes representing the to do tasks the
* current user has.
*
* @return List of to do work items
* @return List of to do tasks
*/
public List<Node> getWorkItemsToDo()
public List<Node> getTasksToDo()
{
// get the current username
FacesContext context = FacesContext.getCurrentInstance();
@@ -71,14 +71,14 @@ public class WorkflowBean
userName, WorkflowTaskState.IN_PROGRESS);
// create a list of transient nodes to represent
this.workItems = new ArrayList<Node>(tasks.size());
this.tasks = new ArrayList<Node>(tasks.size());
for (WorkflowTask task : tasks)
{
Node node = createWorkItem(task);
this.workItems.add(node);
Node node = createTask(task);
this.tasks.add(node);
if (logger.isDebugEnabled())
logger.debug("Added to do work item: " + node);
logger.debug("Added to do task: " + node);
}
// commit the changes
@@ -88,19 +88,19 @@ public class WorkflowBean
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage("Failed to get to do work items: " + e.toString(), e);
Utils.addErrorMessage("Failed to get to do tasks: " + e.toString(), e);
}
return this.workItems;
return this.tasks;
}
/**
* Returns a list of nodes representing the completed work items the
* Returns a list of nodes representing the completed tasks the
* current user has.
*
* @return List of completed work items
* @return List of completed tasks
*/
public List<Node> getWorkItemsCompleted()
public List<Node> getTasksCompleted()
{
// get the current username
FacesContext context = FacesContext.getCurrentInstance();
@@ -118,14 +118,14 @@ public class WorkflowBean
userName, WorkflowTaskState.COMPLETED);
// create a list of transient nodes to represent
this.completedWorkItems = new ArrayList<Node>(tasks.size());
this.completedTasks = new ArrayList<Node>(tasks.size());
for (WorkflowTask task : tasks)
{
Node node = createWorkItem(task);
this.completedWorkItems.add(node);
Node node = createTask(task);
this.completedTasks.add(node);
if (logger.isDebugEnabled())
logger.debug("Added completed work item: " + node);
logger.debug("Added completed task: " + node);
}
// commit the changes
@@ -135,10 +135,10 @@ public class WorkflowBean
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
Utils.addErrorMessage("Failed to get completed work items: " + e.toString(), e);
Utils.addErrorMessage("Failed to get completed tasks: " + e.toString(), e);
}
return this.completedWorkItems;
return this.completedTasks;
}
/**
@@ -164,7 +164,7 @@ public class WorkflowBean
// ------------------------------------------------------------------------------
// Helper methods
public static Map<QName, Serializable> prepareWorkItemParams(Node node)
public static Map<QName, Serializable> prepareTaskParams(Node node)
{
Map<QName, Serializable> params = new HashMap<QName, Serializable>();
@@ -199,9 +199,6 @@ public class WorkflowBean
params.put(assocQName, (Serializable)targets);
}
if (logger.isDebugEnabled())
logger.debug("Prepared parameters: " + params);
return params;
}
@@ -211,7 +208,7 @@ public class WorkflowBean
*
* @param task The task to create a representation of
*/
protected TransientMapNode createWorkItem(WorkflowTask task)
protected TransientMapNode createTask(WorkflowTask task)
{
// get the type of the task
WorkflowTaskDefinition taskDef = task.definition;

View File

@@ -40,7 +40,7 @@ public class ClientConfigElement extends ConfigElementAdapter
private String editLinkType = "http";
private String homeSpacePermission = null;
private boolean ajaxEnabled = false;
private String initialLocation = null;
private String initialLocation = "myalfresco";
/**
* Default Constructor

View File

@@ -37,6 +37,7 @@ public class DashboardsConfigElement extends ConfigElementAdapter
private Map<String, LayoutDefinition> layoutDefs = new LinkedHashMap<String, LayoutDefinition>(4, 1.0f);
private Map<String, DashletDefinition> dashletDefs = new LinkedHashMap<String, DashletDefinition>(8, 1.0f);
private boolean allowGuestConfig = false;
/**
* Default constructor
@@ -77,9 +78,24 @@ public class DashboardsConfigElement extends ConfigElementAdapter
combinedElement.layoutDefs.putAll(this.layoutDefs);
combinedElement.layoutDefs.putAll(newElement.layoutDefs);
if (newElement.allowGuestConfig != combinedElement.allowGuestConfig)
{
combinedElement.allowGuestConfig = newElement.allowGuestConfig;
}
return combinedElement;
}
/*package*/ void setAllowGuestConfig(boolean allow)
{
this.allowGuestConfig = allow;
}
public boolean getAllowGuestConfig()
{
return this.allowGuestConfig;
}
/*package*/ void addLayoutDefinition(LayoutDefinition def)
{
this.layoutDefs.put(def.Id, def);

View File

@@ -37,6 +37,7 @@ public class DashboardsElementReader implements ConfigElementReader
public static final String ELEMENT_LAYOUT = "layout";
public static final String ELEMENT_DASHLETS = "dashlets";
public static final String ELEMENT_DASHLET = "dashlet";
public static final String ELEMENT_GUESTCONFIG = "allow-guest-config";
public static final String ATTR_ID = "id";
public static final String ATTR_COLUMNS = "columns";
public static final String ATTR_COLUMNLENGTH = "column-length";
@@ -85,6 +86,13 @@ public class DashboardsElementReader implements ConfigElementReader
configElement.addDashletDefinition(dashletDef);
}
}
Element guestConfigElement = element.element(ELEMENT_GUESTCONFIG);
if (guestConfigElement != null)
{
boolean allow = Boolean.parseBoolean(guestConfigElement.getTextTrim());
configElement.setAllowGuestConfig(allow);
}
}
return configElement;

View File

@@ -0,0 +1,401 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the GNU Lesser General Public License as
* published by the Free Software Foundation; either version
* 2.1 of the License, or (at your option) any later version.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/lgpl.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.ui.repo.component;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.el.ValueBinding;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.ui.common.Utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Component for selecting content from the repository
*
* @author gavinc
*/
public class UIContentSelector extends UIInput
{
private final static Log logger = LogFactory.getLog(UIContentSelector.class);
private final static String ACTION_SEPARATOR = ";";
private final static String ACTION_SEARCH = "0";
private final static String FIELD_CONTAINS = "_contains";
private final static String FIELD_AVAILABLE = "_available";
private final static String MSG_SEARCH = "search";
protected String availableOptionsSize;
protected Boolean disabled;
private Boolean multiSelect;
/** List containing the currently available options */
protected List<NodeRef> availableOptions;
// ------------------------------------------------------------------------------
// Component implementation
/**
* @see javax.faces.component.UIComponent#getFamily()
*/
public String getFamily()
{
return "org.alfresco.faces.ContentSelector";
}
/**
* Default constructor
*/
public UIContentSelector()
{
setRendererType(null);
}
/**
* @see javax.faces.component.StateHolder#restoreState(javax.faces.context.FacesContext, java.lang.Object)
*/
@SuppressWarnings("unchecked")
public void restoreState(FacesContext context, Object state)
{
Object values[] = (Object[])state;
// standard component attributes are restored by the super class
super.restoreState(context, values[0]);
this.availableOptions = (List<NodeRef>)values[1];
this.availableOptionsSize = (String)values[2];
this.disabled = (Boolean)values[3];
this.multiSelect = (Boolean)values[4];
}
/**
* @see javax.faces.component.StateHolder#saveState(javax.faces.context.FacesContext)
*/
public Object saveState(FacesContext context)
{
Object values[] = new Object[10];
// standard component attributes are saved by the super class
values[0] = super.saveState(context);
values[1] = this.availableOptions;
values[2] = this.availableOptionsSize;
values[3] = this.disabled;
values[4] = this.multiSelect;
return (values);
}
/**
* @see javax.faces.component.UIComponent#decode(javax.faces.context.FacesContext)
*/
public void decode(FacesContext context)
{
Map requestMap = context.getExternalContext().getRequestParameterMap();
Map valuesMap = context.getExternalContext().getRequestParameterValuesMap();
String fieldId = getHiddenFieldName();
String value = (String)requestMap.get(fieldId);
if (value != null && value.equals(ACTION_SEARCH))
{
// user has issued a search action, fill the list with options
String contains = (String)requestMap.get(fieldId + FIELD_CONTAINS);
this.availableOptions = new ArrayList<NodeRef>();
getAvailableOptions(FacesContext.getCurrentInstance(), contains);
}
else
{
// set the submitted value (if there is one)
String[] addedItems = (String[])valuesMap.get(fieldId + FIELD_AVAILABLE);
this.setSubmittedValue(addedItems);
}
}
/**
* @see javax.faces.component.UIComponent#encodeBegin(javax.faces.context.FacesContext)
*/
public void encodeBegin(FacesContext context) throws IOException
{
if (isRendered() == false)
{
return;
}
ResponseWriter out = context.getResponseWriter();
// get the child associations currently on the node and any that have been added
NodeService nodeService = Repository.getServiceRegistry(context).getNodeService();
if (isDisabled())
{
// TODO: if the component is disabled just show the current value as text
}
else
{
// start outer table
out.write("<table border='0' cellspacing='4' cellpadding='0' class='");
if (this.getAttributes().get("styleClass") != null)
{
out.write((String)this.getAttributes().get("styleClass"));
}
else
{
out.write("selector");
}
out.write("'");
if (this.getAttributes().get("style") != null)
{
out.write(" style='");
out.write((String)this.getAttributes().get("style"));
out.write("'");
}
out.write(">");
// show the search field
out.write("<tr><td colspan='2'><input type='text' maxlength='1024' size='32' name='");
out.write(getClientId(context) + FIELD_CONTAINS);
out.write("'/>&nbsp;&nbsp;<input type='submit' value='");
out.write(Application.getMessage(context, MSG_SEARCH));
out.write("' onclick=\"");
out.write(generateFormSubmit(context, ACTION_SEARCH));
out.write("\"/></td></tr>");
// show available options i.e. all content in repository
renderAvailableOptions(context, out, nodeService);
// close table
out.write("</table>");
}
}
/**
* Determines whether the component should be rendered in a disabled state
*
* @return Returns whether the component is disabled
*/
public boolean isDisabled()
{
if (this.disabled == null)
{
ValueBinding vb = getValueBinding("disabled");
if (vb != null)
{
this.disabled = (Boolean)vb.getValue(getFacesContext());
}
}
if (this.disabled == null)
{
this.disabled = Boolean.FALSE;
}
return this.disabled;
}
/**
* Determines whether the component should be rendered in a disabled state
*
* @param disabled true to disable the component
*/
public void setDisabled(boolean disabled)
{
this.disabled = disabled;
}
/**
* Returns the size of the select control when multiple items
* can be selected
*
* @return The size of the select control
*/
public String getAvailableOptionsSize()
{
if (this.availableOptionsSize == null)
{
this.availableOptionsSize = "6";
}
return this.availableOptionsSize;
}
/**
* Sets the size of the select control used when multiple items can
* be selected
*
* @param availableOptionsSize The size
*/
public void setAvailableOptionsSize(String availableOptionsSize)
{
this.availableOptionsSize = availableOptionsSize;
}
/**
* @return true if multi select should be enabled.
*/
public boolean getMultiSelect()
{
ValueBinding vb = getValueBinding("multiSelect");
if (vb != null)
{
this.multiSelect = (Boolean)vb.getValue(getFacesContext());
}
return multiSelect != null ? multiSelect.booleanValue() : true;
}
/**
* @param multiSelect Flag to determine whether multi select is enabled
*/
public void setMultiSelect(boolean multiSelect)
{
this.multiSelect = Boolean.valueOf(multiSelect);
}
/**
* Renders the list of available options
*
* @param context FacesContext
* @param out Writer to write output to
* @param nodeService The NodeService
* @throws IOException
*/
protected void renderAvailableOptions(FacesContext context, ResponseWriter out, NodeService nodeService)
throws IOException
{
boolean itemsPresent = (this.availableOptions != null && this.availableOptions.size() > 0);
out.write("<tr><td colspan='2'><select ");
if (itemsPresent == false)
{
// rather than having a very slim select box set the width if there are no results
out.write("style='width:240px;' ");
}
out.write("name='");
out.write(getClientId(context) + FIELD_AVAILABLE);
out.write("' size='");
if (getMultiSelect())
{
out.write(getAvailableOptionsSize());
out.write("' multiple");
}
else
{
out.write("1'");
}
out.write(">");
if (itemsPresent)
{
for (NodeRef item : this.availableOptions)
{
out.write("<option value='");
out.write(item.toString());
out.write("'>");
out.write(Repository.getDisplayPath(nodeService.getPath(item)));
out.write("/");
out.write(Repository.getNameForNode(nodeService, item));
out.write("</option>");
}
}
out.write("</select></td></tr>");
}
/**
* Retrieves the available options for the current association
*
* @param context Faces Context
* @param contains The contains part of the query
*/
protected void getAvailableOptions(FacesContext context, String contains)
{
// query for all content in the current repository
StringBuilder query = new StringBuilder("+TYPE:\"");
query.append(ContentModel.TYPE_CONTENT);
query.append("\"");
if (contains != null && contains.length() > 0)
{
String safeContains = Utils.remove(contains.trim(), "\"");
query.append(" AND +@");
String nameAttr = Repository.escapeQName(QName.createQName(
NamespaceService.CONTENT_MODEL_1_0_URI, "name"));
query.append(nameAttr);
query.append(":*" + safeContains + "*");
}
if (logger.isDebugEnabled())
logger.debug("Query: " + query.toString());
ResultSet results = null;
try
{
results = Repository.getServiceRegistry(context).getSearchService().query(
Repository.getStoreRef(), SearchService.LANGUAGE_LUCENE, query.toString());
this.availableOptions = results.getNodeRefs();
}
finally
{
if (results != null)
{
results.close();
}
}
if (logger.isDebugEnabled())
logger.debug("Found " + this.availableOptions.size() + " available options");
}
/**
* We use a hidden field per picker instance on the page.
*
* @return hidden field name
*/
private String getHiddenFieldName()
{
return getClientId(getFacesContext());
}
/**
* Generate FORM submit JavaScript for the specified action
*
* @param context FacesContext
* @param action Action string
*
* @return FORM submit JavaScript
*/
private String generateFormSubmit(FacesContext context, String action)
{
return Utils.generateFormSubmit(context, this, getHiddenFieldName(), action);
}
}

View File

@@ -0,0 +1,163 @@
package org.alfresco.web.ui.repo.component;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ResourceBundle;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.el.ValueBinding;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.workflow.WorkflowInstance;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.ui.common.component.SelfRenderingComponent;
/**
* JSF component that displays summary information about a workflow.
*
* @author gavinc
*/
public class UIWorkflowSummary extends SelfRenderingComponent
{
protected WorkflowInstance value = null;
// ------------------------------------------------------------------------------
// Component Impl
@Override
public String getFamily()
{
return "org.alfresco.faces.WorkflowSummary";
}
@Override
public void restoreState(FacesContext context, Object state)
{
Object values[] = (Object[])state;
// standard component attributes are restored by the super class
super.restoreState(context, values[0]);
this.value = (WorkflowInstance)values[1];
}
@Override
public Object saveState(FacesContext context)
{
Object values[] = new Object[8];
// standard component attributes are saved by the super class
values[0] = super.saveState(context);
values[1] = this.value;
return values;
}
@Override
@SuppressWarnings("unchecked")
public void encodeBegin(FacesContext context) throws IOException
{
if (!isRendered()) return;
WorkflowInstance wi = getValue();
if (wi != null)
{
ResponseWriter out = context.getResponseWriter();
ResourceBundle bundle = Application.getBundle(context);
SimpleDateFormat format = new SimpleDateFormat(bundle.getString("date_pattern"));
// output surrounding table and style if necessary
out.write("<table");
if (this.getAttributes().get("style") != null)
{
out.write(" style=\"");
out.write((String)this.getAttributes().get("style"));
out.write("\"");
}
if (this.getAttributes().get("styleClass") != null)
{
out.write(" class=\"");
out.write((String)this.getAttributes().get("styleClass"));
out.write("\"");
}
out.write(">");
// output the title and description
out.write("<tr><td>");
out.write(bundle.getString("title"));
out.write(":</td><td>");
out.write(wi.definition.title);
out.write("</td></tr><tr><td>");
out.write(bundle.getString("description"));
out.write(":</td><td>");
out.write(wi.definition.description);
out.write("</td></tr><tr><td>");
out.write(bundle.getString("initiated_by"));
out.write(":</td><td>");
if (wi.initiator != null)
{
NodeService nodeService = Repository.getServiceRegistry(
context).getNodeService();
String userName = (String)nodeService.getProperty(
wi.initiator, ContentModel.PROP_USERNAME);
out.write(userName);
}
out.write("</td></tr><tr><td>");
out.write(bundle.getString("start_date"));
out.write(":</td><td>");
if (wi.startDate != null)
{
out.write(format.format(wi.startDate));
}
out.write("</td></tr><tr><td>");
out.write(bundle.getString("due_date"));
out.write(":</td><td>");
if (wi.endDate != null)
{
out.write(format.format(wi.endDate));
}
out.write("</td></tr></table>");
}
}
@Override
public void encodeEnd(FacesContext context) throws IOException
{
if (!isRendered()) return;
}
@Override
public boolean getRendersChildren()
{
return false;
}
// ------------------------------------------------------------------------------
// Strongly typed component property accessors
/**
* Returns the workflow instance this component is showing information on
*
* @return The workflow instance
*/
public WorkflowInstance getValue()
{
ValueBinding vb = getValueBinding("value");
if (vb != null)
{
this.value = (WorkflowInstance)vb.getValue(getFacesContext());
}
return this.value;
}
/**
* Sets the workflow instance to show the summary for
*
* @param value The workflow instance
*/
public void setValue(WorkflowInstance value)
{
this.value = value;
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.ui.repo.tag;
import javax.faces.component.UIComponent;
import org.alfresco.web.ui.common.tag.HtmlComponentTag;
/**
* Tag class to allow the content selector component to be added to a JSP page
*
* @author gavinc
*/
public class ContentSelectorTag extends HtmlComponentTag
{
private String availableOptionsSize;
private String disabled;
private String value;
private String multiSelect;
/**
* @see javax.faces.webapp.UIComponentTag#getComponentType()
*/
public String getComponentType()
{
return "org.alfresco.faces.ContentSelector";
}
/**
* @see javax.faces.webapp.UIComponentTag#getRendererType()
*/
public String getRendererType()
{
return null;
}
/**
* @see javax.faces.webapp.UIComponentTag#setProperties(javax.faces.component.UIComponent)
*/
protected void setProperties(UIComponent component)
{
super.setProperties(component);
setStringStaticProperty(component, "availableOptionsSize", this.availableOptionsSize);
setStringProperty(component, "value", this.value);
setBooleanProperty(component, "disabled", this.disabled);
setBooleanProperty(component, "multiSelect", this.multiSelect);
}
/**
* @param value The value to set.
*/
public void setValue(String value)
{
this.value = value;
}
/**
* @param availableOptionsSize Sets the size of the available options size when
* multiple items can be selected
*/
public void setAvailableOptionsSize(String availableOptionsSize)
{
this.availableOptionsSize = availableOptionsSize;
}
/**
* Set the multiSelect
*
* @param mutliSelect the multiSelect
*/
public void setMultiSelect(String multiSelect)
{
this.multiSelect = multiSelect;
}
/**
* Sets whether the component should be rendered in a disabled state
*
* @param disabled true to render the component in a disabled state
*/
public void setDisabled(String disabled)
{
this.disabled = disabled;
}
/**
* @see javax.faces.webapp.UIComponentTag#release()
*/
public void release()
{
this.availableOptionsSize = null;
this.disabled = null;
this.value = null;
this.multiSelect = null;
super.release();
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.web.ui.repo.tag;
import javax.faces.component.UIComponent;
import org.alfresco.web.ui.common.tag.HtmlComponentTag;
/**
* Tag that allows the workflow summary component to be placed on a JSP page
*
* @author gavinc
*/
public class WorkflowSummaryTag extends HtmlComponentTag
{
/**
* @see javax.faces.webapp.UIComponentTag#getComponentType()
*/
public String getComponentType()
{
return "org.alfresco.faces.WorkflowSummary";
}
/**
* @see javax.faces.webapp.UIComponentTag#getRendererType()
*/
public String getRendererType()
{
return null;
}
/**
* @see javax.faces.webapp.UIComponentTag#setProperties(javax.faces.component.UIComponent)
*/
protected void setProperties(UIComponent component)
{
super.setProperties(component);
setStringProperty(component, "value", this.value);
}
/**
* @see org.alfresco.web.ui.common.tag.HtmlComponentTag#release()
*/
public void release()
{
super.release();
this.value = null;
}
/**
* Set the value (binding to the list of user/group data)
*
* @param value the value
*/
public void setValue(String value)
{
this.value = value;
}
/** the value (binding to the workflow instance) */
private String value;
}

View File

@@ -34,6 +34,7 @@ public abstract class BaseAssociationEditorTag extends BaseComponentTag
private String selectedItemsMsg;
private String noSelectedItemsMsg;
private String disabled;
private String value;
/**
* @see javax.faces.webapp.UIComponentTag#getRendererType()
@@ -56,9 +57,18 @@ public abstract class BaseAssociationEditorTag extends BaseComponentTag
setStringProperty(component, "selectItemsMsg", this.selectItemsMsg);
setStringProperty(component, "selectedItemsMsg", this.selectedItemsMsg);
setStringProperty(component, "noSelectedItemsMsg", this.noSelectedItemsMsg);
setStringProperty(component, "value", this.value);
setBooleanProperty(component, "disabled", this.disabled);
}
/**
* @param value The value to set.
*/
public void setValue(String value)
{
this.value = value;
}
/**
* Sets the association name
*
@@ -140,6 +150,7 @@ public abstract class BaseAssociationEditorTag extends BaseComponentTag
this.selectedItemsMsg = null;
this.noSelectedItemsMsg = null;
this.disabled = null;
this.value = null;
super.release();
}