/* * Copyright 2002-2004 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * 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.springframework.richclient.command; import org.apache.commons.lang.SystemUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.richclient.application.PropertyNotSetException; import org.springframework.richclient.command.config.CommandConfigurer; import org.springframework.richclient.core.SecurityControllable; import org.springframework.richclient.util.Assert; import org.springframework.util.StringUtils; /** * A {@link FactoryBean} that produces a {@link CommandGroup}. * *
* Use of this bean simplifies the process of building up complex nested command groups such as the * main menu of an application window, a toolbar or popup menus. The main property of interest * when creating a bean definition for this class is the {@code members} list. This list defines the * members of the command group that will be produced by the factory. The objects contained in this * list can be instances of the actual command or they can be strings that represent the identifier * of the command. Some strings have special meaning: * *
true if the exclusive commandGroup can have no item selected.
*/
protected boolean isAllowsEmptySelection() {
return this.allowsEmptySelection;
}
/**
* Returns the command group that this factory produces.
*
* @return The factory's command group, never null.
*/
public Object getObject() throws Exception {
return getCommandGroup();
}
/**
* Returns the command group that this factory produces.
*
* @return The factory's command group, never null.
*/
public CommandGroup getCommandGroup() {
if (commandGroup == null) {
commandGroup = createCommandGroup();
}
return commandGroup;
}
/**
* Creates the command group for this factory and assigns it an identifier equal to the group
* id of the factory. The command group will also be assigned the security controller id,
* if any, that was provided via the {@link #setSecurityControllerId(String)} method and the
* values from the encoded members list will be used to retrieve the corresponding command
* objects from the command registry.
*
* @return The command group, never null.
*/
//NOTE: Find out (and add some comment about) what happens if a command registry has not been provided.
protected CommandGroup createCommandGroup() {
CommandGroup group;
if (isExclusive()) {
ExclusiveCommandGroup g = new ExclusiveCommandGroup(getBeanName(), getCommandRegistry());
g.setAllowsEmptySelection(isAllowsEmptySelection());
group = g;
}
else {
group = new CommandGroup(getBeanName(), getCommandRegistry());
}
// Apply our security controller id to the new group
group.setSecurityControllerId( getSecurityControllerId() );
initCommandGroupMembers(group);
return group;
}
private boolean registerMacOSXCommandAdapters(AbstractCommand command){
if(aboutCommandId.equals(command.getId())){
OSXAdapter.setAboutHandler(command);
return true;
}
else if(quitCommandId.equals(command.getId())){
OSXAdapter.setQuitHandler(command);
return true;
}
else if(preferencesCommandId.equals(command.getId())){
OSXAdapter.setPreferencesHandler(command);
return true;
}
return false;
}
/**
* Iterates over the collection of encoded members and adds them to the given command group.
*
* @param group The group that is to contain the commands from the encoded members list. Must
* not be null.
*
* @throws InvalidGroupMemberEncodingException if a member prefix is provided without
* a command id.
*/
protected void initCommandGroupMembers(CommandGroup group) {
for (int i = 0; i < members.length; i++) {
Object o = members[i];
if (o instanceof AbstractCommand) {
AbstractCommand command = (AbstractCommand)o;
boolean adapted = false;
if(SystemUtils.IS_OS_MAC_OSX && macosxCommandsEnabled){
adapted = registerMacOSXCommandAdapters(command);
}
if(!adapted){
group.addInternal(command);
configureIfNecessary(command);
}
}
else if (o instanceof String) {
String str = (String)o;
if (str.equalsIgnoreCase(SEPARATOR_MEMBER_CODE)) {
group.addSeparatorInternal();
}
else if (str.equalsIgnoreCase(GLUE_MEMBER_CODE)) {
group.addGlueInternal();
}
else if (str.startsWith(COMMAND_MEMBER_PREFIX)) {
String commandId = str.substring(COMMAND_MEMBER_PREFIX.length());
if (!StringUtils.hasText(commandId)) {
throw new InvalidGroupMemberEncodingException(
"The group member encoding does not specify a command id",
str);
}
addCommandMember(str.substring(COMMAND_MEMBER_PREFIX.length()), false, group);
}
else if (str.startsWith(GROUP_MEMBER_PREFIX)) {
String commandId = str.substring(GROUP_MEMBER_PREFIX.length());
if (!StringUtils.hasText(commandId)) {
throw new InvalidGroupMemberEncodingException(
"The group member encoding does not specify a command id",
str);
}
addCommandMember(commandId, true, group);
}
else {
addCommandMember(str, false, group);
}
}
}
}
/**
* Adds the command object with the given id to the given command group. If a command
* registry has not yet been provided to this factory, the command id will be passed as
* a 'lazy placeholder' to the group instead.
*
* @param commandId The id of the command to be added to the group. This is expected to be in
* decoded form, i.e. any command prefixes have been removed. Must not be null.
* @param isGroup indicates if the command is actually a command group.
* @param group The group that the commands will be added to. Must not be null.
*
*/
private void addCommandMember(String commandId, boolean isGroup, CommandGroup group) {
Assert.required(commandId, "commandId");
Assert.required(group, "group");
if (logger.isDebugEnabled()) {
logger.debug("adding command group member with id ["
+ commandId
+ "] to group ["
+ group.getId()
+ "]");
}
AbstractCommand command = null;
if (commandRegistry != null) {
if (isGroup) {
command = commandRegistry.getCommandGroup(commandId);
if (command != null) {
group.addInternal(command);
}
}
else {
command = commandRegistry.getActionCommand(commandId);
if (command != null) {
group.addInternal(command);
}
}
}
if (command == null) {
group.addLazyInternal(commandId);
}
}
/**
* Configures the given command if it has not already been configured and this instance has
* been provided with a {@link CommandConfigurer}.
*
* @param command The command to be configured.
* @throws IllegalArgumentException if {@code command} is null.
*/
protected void configureIfNecessary(AbstractCommand command) {
Assert.required(command, "command");
if (commandConfigurer != null) {
if (!command.isFaceConfigured()) {
commandConfigurer.configure(command);
}
}
}
/**
* Returns the Class object for {@link CommandGroup}.
* @return CommandGroup.class
*/
public Class getObjectType() {
return CommandGroup.class;
}
/**
* Always returns true. The command groups produced by this factory are always singletons.
* @return {@code true} always.
*/
public boolean isSingleton() {
return true;
}
/**
* {@inheritDoc}
*/
public void setSecurityControllerId(String controllerId) {
this.securityControllerId = controllerId;
}
/**
* {@inheritDoc}
*/
public String getSecurityControllerId() {
return securityControllerId;
}
/**
* {@inheritDoc}
*/
public void setAuthorized(boolean authorized) {
// nothing to do on the factory. This method is only implemented because
// it is declared on the SecurityControllable interface, which we need to
// implement in order to be assigned a securityControllerId that we can then
// pass on to the commandGroup produced by this factory
}
/**
* {@inheritDoc}
*/
public boolean isAuthorized() {
return false;
}
}