/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.foundation.ie.menu;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.lang.StringUtils;
import org.openflexo.foundation.DataModification;
import org.openflexo.foundation.DeletableObject;
import org.openflexo.foundation.FlexoObservable;
import org.openflexo.foundation.FlexoObserver;
import org.openflexo.foundation.ObjectDeleted;
import org.openflexo.foundation.bindings.ComponentBindingDefinition;
import org.openflexo.foundation.ie.ComponentInstance;
import org.openflexo.foundation.ie.ComponentInstanceOwner;
import org.openflexo.foundation.ie.IEObject;
import org.openflexo.foundation.ie.IObject;
import org.openflexo.foundation.ie.TabComponentInstance;
import org.openflexo.foundation.ie.cl.ComponentDefinition;
import org.openflexo.foundation.ie.cl.FlexoComponentFolder;
import org.openflexo.foundation.ie.cl.TabComponentDefinition;
import org.openflexo.foundation.ie.dm.IEDataModification;
import org.openflexo.foundation.ie.menu.dm.MenuItemAdded;
import org.openflexo.foundation.ie.menu.dm.MenuItemRemoved;
import org.openflexo.foundation.ie.menu.dm.ReOrderedMenuItem;
import org.openflexo.foundation.ie.util.FolderType;
import org.openflexo.foundation.rm.DuplicateResourceException;
import org.openflexo.foundation.rm.FlexoProject;
import org.openflexo.foundation.rm.XMLStorageResourceData;
import org.openflexo.foundation.validation.Validable;
import org.openflexo.foundation.validation.ValidationError;
import org.openflexo.foundation.validation.ValidationIssue;
import org.openflexo.foundation.validation.ValidationModel;
import org.openflexo.foundation.validation.ValidationReport;
import org.openflexo.foundation.validation.ValidationRule;
import org.openflexo.foundation.wkf.FlexoProcess;
import org.openflexo.foundation.wkf.InvalidParentProcessException;
import org.openflexo.foundation.wkf.WKFObject;
import org.openflexo.foundation.wkf.dm.DisplayOperationSet;
import org.openflexo.foundation.wkf.dm.DisplayProcessSet;
import org.openflexo.foundation.wkf.node.OperationNode;
import org.openflexo.foundation.wkf.utils.OperationAssociatedWithComponentSuccessfully;
import org.openflexo.foundation.xml.FlexoNavigationMenuBuilder;
import org.openflexo.inspector.InspectableObject;
import org.openflexo.localization.FlexoLocalization;
import org.openflexo.toolbox.EmptyVector;
public class FlexoItemMenu extends IEObject implements DeletableObject, Validable, InspectableObject, ComponentInstanceOwner, FlexoObserver {
private static final Logger logger = Logger.getLogger(FlexoItemMenu.class.getPackage().getName());
private FlexoNavigationMenu _navigationMenu;
private Vector<FlexoItemMenu> _subItems;
private FlexoItemMenu _father;
private String _menuLabel;
private String _popupWidth;
private String _popupHeight;
private boolean _isPageTarget = true;
private String _popupWindowName;
private FlexoProcess process;
private OperationNode operation;
private long processFlexoID = -1;
private long operationFlexoID = -1;
private String url;
private boolean useUrl;
private TabComponentInstance _tabComponentInstance;
public FlexoItemMenu(FlexoProject project) {
super(project);
_subItems = new Vector<FlexoItemMenu>();
}
/**
* Creates a new FlexoComponentFolder with default values (public API outside XML serialization)
*
* @param workflow
* @throws InvalidParentProcessException
*/
public FlexoItemMenu(FlexoNavigationMenu menu, String menuLabel, FlexoItemMenu father, FlexoProject prj) {
this(prj);
_navigationMenu = menu;
_menuLabel = menuLabel;
setFather(father);
}
public FlexoItemMenu(FlexoNavigationMenuBuilder builder) {
this(builder.getProject());
_navigationMenu = builder.navigationMenu;
initializeDeserialization(builder);
}
public static FlexoItemMenu createNewRootMenu(FlexoNavigationMenu menu) {
return createNewMenu(menu, null, FlexoLocalization.localizedForKey("default_page"));
}
public static FlexoItemMenu createNewMenu(FlexoNavigationMenu menu, FlexoItemMenu parentMenu, String menuName) {
FlexoItemMenu newMenu = new FlexoItemMenu(menu, menuName, parentMenu, menu.getProject());
if (parentMenu != null) {
parentMenu.addToSubItems(newMenu);
} else {
if (logger.isLoggable(Level.INFO)) {
logger.info("NEW ROOT MENU");
}
menu.setRootMenu(newMenu);
}
return newMenu;
}
/**
* Overrides delete
*
* @see org.openflexo.foundation.FlexoModelObject#delete()
*/
@Override
public final void delete() {
if (isRootMenu()) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Root menu cannot be deleted");
}
return;
}
removeTabComponentInstance();
if (logger.isLoggable(Level.FINE)) {
logger.fine("Deletion of menu item " + _menuLabel);
}
Enumeration<FlexoItemMenu> en = getSubItems().elements();
while (en.hasMoreElements()) {
FlexoItemMenu element = en.nextElement();
element.delete();
}
if (getFather() != null) {
getFather().removeFromSubItems(this);
}
super.delete();
deleteObservers();
}
@Override
public void finalizeDeserialization(Object builder) {
getOperation(); // Forces to resolve process and operation
super.finalizeDeserialization(builder);
}
/**
* Returns reference to the main object in which this XML-serializable object is contained relating to storing scheme: here it's the
* navigation menu
*
* @return
*/
@Override
public XMLStorageResourceData getXMLResourceData() {
return getNavigationMenu();
}
@Override
public IEObject getParent() {
return getFather();
}
public FlexoItemMenu getFather() {
return _father;
}
public void setFather(FlexoItemMenu f) {
_father = f;
}
public boolean isRootMenu() {
return getFather() == null;
}
public void setMenuLabel(String label) {
String old = _menuLabel;
_menuLabel = label;
setChanged();
notifyObservers(new IEDataModification("menuLabel", old, label));
}
public String getMenuLabel() {
return _menuLabel;
}
public int getIndex() {
return getFather().getSubItems().indexOf(this) + 1;
}
public void setSubItems(Vector<FlexoItemMenu> v) {
_subItems = v;
setChanged();
}
public Vector<FlexoItemMenu> getSubItems() {
return _subItems;
}
public String getWOAUrl() {
String woaUrl = "";
if (getUseUrl()) {
woaUrl = '"' + getUrl() + '"';
} else {
/* if (getIsPageTarget()) { */
if (getOperation() != null && getOperation().hasWOComponent()) {
StringBuilder args = new StringBuilder();
for (ComponentBindingDefinition cbd : getOperation().getComponentDefinition().getBindingDefinitions()) {
if (cbd.getIsMandatory()) {
/*
* if(getOperation().getComponentInstance().getBinding(cbd).getBindingValue()!=null){
* args.append(", "+getOperation()
* .getComponentInstance().getBinding(cbd).getBindingValue().getCodeStringRepresentation()); }else
*/
args.append(", ").append(cbd.getType().getDefaultValue());
}
}
if (getOperation().getComponentInstance().getWOComponent().getFirstTabContainerTitle() != null) {
args.append(", null");
}
woaUrl = getOperation().getComponentDefinition().getName() + ".getUrlForOperation(context()" + args.toString() + ","
+ getOperation().getComponentInstance().getFlexoID() + ")";
} else {
woaUrl = "\"#\"";
/*
* } else if (getOperation() != null && getOperation().hasWOComponent()) { String w = getPopupWidth(); String h =
* getPopupHeight(); String selectedTab = "";
* if(getOperation().getComponentInstance().getComponentDefinition().getFirstTabContainerTitle()!=null) selectedTab =
* ", null"; woaUrl = "\"window.open(\\\\'\"+" + getOperation().getComponentDefinition().getName() +
* ".getUrlForOperation(context()"+selectedTab+","+getOperation().getComponentInstance().getFlexoID()+")+\"\\\\'" + ",\\\\'"
* + (getPopupWindowName() != null ? getPopupWindowName() : getOperation().getComponentDefinition().getName()) +
* "\\\\',\\\\'width=" + w + ",height=" + h +
* ",directories=no,fullscreen=no,location=no,menubar=no,resizable=yes,scrollbars=yes,status=yes,titlebar=no,toolbar=no\\\\',\\\\'\\\\')\""
* ; }
*/
}
}
return woaUrl;
}
public void addToSubItems(FlexoItemMenu item) {
_subItems.add(item);
item.setFather(this);
setChanged();
notifyObservers(new MenuItemAdded(item));
}
public void removeFromSubItems(FlexoItemMenu item) {
_subItems.remove(item);
setChanged();
notifyObservers(new MenuItemRemoved(item));
}
public boolean getIsPageTarget() {
return _isPageTarget;
}
public void setIsPageTarget(boolean v) {
_isPageTarget = v;
setChanged();
notifyObservers(new IEDataModification("isPageTarget", null, new Boolean(v)));
}
public void switchItems(FlexoItemMenu item1, FlexoItemMenu item2) {
if (item1 != null && item2 != null && _subItems.indexOf(item1) > -1 && _subItems.indexOf(item2) > -1
&& _subItems.indexOf(item1) != _subItems.indexOf(item2)) {
if (_subItems.indexOf(item1) > _subItems.indexOf(item2)) {
switchItems(item2, item1);
} else {
int i1 = _subItems.indexOf(item1);
int i2 = _subItems.indexOf(item2);
_subItems.remove(item1);
_subItems.remove(item2);
_subItems.insertElementAt(item2, i1);
_subItems.insertElementAt(item1, i2);
}
}
setChanged();
notifyObservers(new ReOrderedMenuItem());
}
public String getPopupHeight() {
return _popupHeight;
}
public void setPopupHeight(String height) {
String old = _popupHeight;
_popupHeight = height;
setChanged();
notifyObservers(new IEDataModification("popupHeight", old, height));
}
public String getPopupWidth() {
return _popupWidth;
}
public void setPopupWidth(String width) {
String old = _popupWidth;
_popupWidth = width;
setChanged();
notifyObservers(new IEDataModification("popupWidth", old, _popupWidth));
}
public String getPopupWindowName() {
return _popupWindowName;
}
public void setPopupWindowName(String windowName) {
String old = _popupWindowName;
_popupWindowName = windowName;
setChanged();
notifyObservers(new IEDataModification("popupWindowName", old, _popupWindowName));
}
/**
* Return a Vector of embedded IEObjects at this level. NOTE that this is NOT a recursive method
*
* @return a Vector of IEObject instances
*/
@Override
public Vector<IObject> getEmbeddedIEObjects() {
Vector answer = new Vector();
answer.addAll(_subItems);
return answer;
}
public FlexoNavigationMenu getNavigationMenu() {
return _navigationMenu;
}
@Override
public String getFullyQualifiedName() {
return "FLEXO_ITEM_MENU.NOT_IMPLEMENTED." + getMenuLabel();
}
public boolean isChildOf(FlexoItemMenu anItemMenu) {
FlexoItemMenu it = this;
while (it != null) {
if (it.equals(anItemMenu)) {
return true;
}
it = it.getFather();
}
return false;
}
/**
* Overrides getAllEmbeddedDeleted
*
* @see org.openflexo.foundation.DeletableObject#getAllEmbeddedDeleted()
*/
@Override
public Vector<WKFObject> getAllEmbeddedDeleted() {
return EmptyVector.EMPTY_VECTOR(WKFObject.class);
}
public Vector<FlexoItemMenu> getAllItemMenus(Vector<FlexoItemMenu> menus) {
menus.add(this);
Enumeration<FlexoItemMenu> en = getSubItems().elements();
while (en.hasMoreElements()) {
en.nextElement().getAllItemMenus(menus);
}
return menus;
}
/**
* Overrides getClassNameKey
*
* @see org.openflexo.foundation.FlexoModelObject#getClassNameKey()
*/
@Override
public String getClassNameKey() {
return "flexo_item_menu";
}
public OperationNode getOperation() {
if (operation == null && operationFlexoID > -1) {
if (getProcess() != null) {
operation = getProcess().getOperationNodeWithFlexoID(operationFlexoID);
if (operation == null) {
operationFlexoID = -1;
setChanged();
} else {
operation.addObserver(this);
}
} else if (logger.isLoggable(Level.WARNING)) {
logger.warning("This is weird, an operation has been set but not its process.");
}
}
return operation;
}
public void setOperation(OperationNode displayOperation) {
if (operation == displayOperation) {
return;
}
OperationNode old = this.operation;
if (old != null) {
old.deleteObserver(this);
}
this.operation = displayOperation;
if (displayOperation != null) {
displayOperation.addObserver(this);
operationFlexoID = displayOperation.getFlexoID();
} else {
operationFlexoID = -1;
}
setTabComponent(null);
if (isRootMenu()) {
getProject().setFirstOperation(displayOperation);
}
setChanged();
notifyObservers(new DisplayOperationSet(old, displayOperation));
}
public FlexoProcess getProcess() {
if (process == null && processFlexoID > -1) {
process = getProject().getFlexoWorkflow().getLocalFlexoProcessWithFlexoID(processFlexoID);
if (process == null) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Could not find process with flexoID " + processFlexoID);
}
processFlexoID = -1;
setOperation(null);
setChanged();
} else {
process.addObserver(this);
}
}
return process;
}
public void setProcess(FlexoProcess displayProcess) {
if (this.process == displayProcess) {
return;
}
FlexoProcess old = this.process;
if (old != null) {
old.deleteObserver(this);
}
this.process = displayProcess;
if (displayProcess != null) {
process.addObserver(this);
processFlexoID = displayProcess.getFlexoID();
} else {
processFlexoID = -1;
}
setOperation(null);
getNavigationMenu().getFlexoResource().clearDependencies();
getNavigationMenu().getFlexoResource().rebuildDependancies();
setChanged();
notifyObservers(new DisplayProcessSet(old, displayProcess));
}
public boolean isAcceptableAsDisplayProcess(FlexoProcess process) {
return process != null && !process.isImported();
}
public long getOperationFlexoID() {
if (getOperation() != null) {
return getOperation().getFlexoID();
} else {
return -1;
}
}
public void setOperationFlexoID(long displayOperationFlexoID) {
if (getOperation() != null) {
operation = null;
}
this.operationFlexoID = displayOperationFlexoID;
}
public long getProcessFlexoID() {
if (getProcess() != null) {
return getProcess().getFlexoID();
} else {
return -1;
}
}
public void setProcessFlexoID(long displayProcessFlexoID) {
if (getProcess() != null) {
process = null;
}
this.processFlexoID = displayProcessFlexoID;
}
@Override
public void update(FlexoObservable observable, DataModification obj) {
if (observable == getOperation()) {
if (obj instanceof ObjectDeleted) {
setOperation(null);
} else if (obj.propertyName() != null && obj.propertyName().equals("flexoID")) {
setChanged();
}
} else if (observable == getProcess()) {
if (obj instanceof ObjectDeleted) {
setProcess(null);
} else if (obj.propertyName() != null && obj.propertyName().equals("flexoID")) {
setChanged();
}
}
super.update(observable, obj);
}
public static class RootItemMustBeBound extends ValidationRule<RootItemMustBeBound, FlexoItemMenu> {
public RootItemMustBeBound() {
super(FlexoItemMenu.class, "root_menu_item_must_be_bound_to_an_operation");
}
@Override
public ValidationIssue<RootItemMustBeBound, FlexoItemMenu> applyValidation(FlexoItemMenu menu) {
ValidationIssue<RootItemMustBeBound, FlexoItemMenu> err = null;
if (menu.isRootMenu()) {
if (menu.getProcess() == null || menu.getOperation() == null) {
err = new ValidationError<RootItemMustBeBound, FlexoItemMenu>(this, menu,
"root_menu_item_must_be_bound_to_an_operation");
}
}
return err;
}
}
public static class MenuMustDefineAnOperation extends ValidationRule<MenuMustDefineAnOperation, FlexoItemMenu> {
public MenuMustDefineAnOperation() {
super(FlexoItemMenu.class, "menu_item_must_be_bound_to_an_operation");
}
@Override
public ValidationIssue<MenuMustDefineAnOperation, FlexoItemMenu> applyValidation(FlexoItemMenu menu) {
ValidationIssue<MenuMustDefineAnOperation, FlexoItemMenu> err = null;
if (!menu.getUseUrl() && (menu.getProcess() == null || menu.getOperation() == null)) {
err = new ValidationError<MenuMustDefineAnOperation, FlexoItemMenu>(this, menu, "menu_item_must_be_bound_to_an_operation");
}
return err;
}
}
@Override
public ValidationModel getDefaultValidationModel() {
if (getProject() != null) {
return getProject().getIEValidationModel();
} else {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Could not access to project !");
}
}
return null;
}
/**
* Returns a flag indicating if this object is valid according to default validation model
*
* @return boolean
*/
@Override
public boolean isValid() {
return isValid(getDefaultValidationModel());
}
/**
* Returns a flag indicating if this object is valid according to specified validation model
*
* @return boolean
*/
@Override
public boolean isValid(ValidationModel validationModel) {
return validationModel.isValid(this);
}
/**
* Validates this object by building new ValidationReport object Default validation model is used to perform this validation.
*/
@Override
public ValidationReport validate() {
return validate(getDefaultValidationModel());
}
/**
* Validates this object by building new ValidationReport object Supplied validation model is used to perform this validation.
*/
@Override
public ValidationReport validate(ValidationModel validationModel) {
return validationModel.validate(this);
}
/**
* Validates this object by appending eventual issues to supplied ValidationReport. Default validation model is used to perform this
* validation.
*
* @param report
* , a ValidationReport object on which found issues are appened
*/
@Override
public void validate(ValidationReport report) {
validate(report, getDefaultValidationModel());
}
/**
* Validates this object by appending eventual issues to supplied ValidationReport. Supplied validation model is used to perform this
* validation.
*
* @param report
* , a ValidationReport object on which found issues are appened
*/
@Override
public void validate(ValidationReport report, ValidationModel validationModel) {
validationModel.validate(this, report);
}
/**
* @param menuLabel
* @return
*/
public FlexoItemMenu getMenuLabeled(String menuLabel) {
if (this.getMenuLabel() != null && this.getMenuLabel().equals(menuLabel)) {
return this;
}
Vector<FlexoItemMenu> v = getSubItems();
Enumeration<FlexoItemMenu> en = v.elements();
while (en.hasMoreElements()) {
FlexoItemMenu menu = en.nextElement();
FlexoItemMenu ret = menu.getMenuLabeled(menuLabel);
if (ret != null) {
return ret;
}
}
return null;
}
@Override
public String getInspectorName() {
return "FlexoItemMenu.inspector";
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
setChanged();
notifyObservers(new IEDataModification("url", null, url));
}
public boolean getUseUrl() {
return useUrl;
}
public void setUseUrl(boolean useUrl) {
this.useUrl = useUrl;
setChanged();
notifyObservers(new IEDataModification("useUrl", null, useUrl));
}
// TABS
public String getTabComponentName() {
if (getTabComponent() != null) {
return getTabComponent().getComponentName();
}
return null;
}
public void setTabComponentName(String aComponentName) throws DuplicateResourceException, OperationAssociatedWithComponentSuccessfully {
if (getTabComponentName() != null && getTabComponentName().equals(aComponentName)) {
return;
}
if (_tabComponentInstance == null && (aComponentName == null || aComponentName.trim().equals(""))) {
return;
}
ComponentDefinition foundComponent = getProject().getFlexoComponentLibrary().getComponentNamed(aComponentName);
TabComponentDefinition newComponent = null;
if (foundComponent instanceof TabComponentDefinition) {
newComponent = (TabComponentDefinition) foundComponent;
} else if (foundComponent != null) {
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Found a component named " + aComponentName + " but this is not a TabComponent. Aborting.");
}
throw new DuplicateResourceException(aComponentName);
}
if (newComponent == null) {
if (logger.isLoggable(Level.INFO)) {
logger.info("Creating a new Component named:" + aComponentName);
}
FlexoComponentFolder selectedFolder = getProject().getFlexoComponentLibrary().getRootFolder()
.getFolderTyped(FolderType.TAB_FOLDER);
newComponent = new TabComponentDefinition(aComponentName, getProject().getFlexoComponentLibrary(), selectedFolder, getProject());
}
setTabComponent(newComponent);
}
public TabComponentDefinition getTabComponent() {
if (_tabComponentInstance != null) {
return _tabComponentInstance.getComponentDefinition();
}
return null;
}
public void setTabComponent(TabComponentDefinition aComponentDefinition) {
if (_tabComponentInstance != null && _tabComponentInstance.getComponentDefinition() == aComponentDefinition) {
return;
}
if (_tabComponentInstance != null && aComponentDefinition == null) {
removeTabComponentInstance();
}
if (aComponentDefinition != null) {
setTabMenuComponentInstance(new TabComponentInstance(aComponentDefinition, this));
}
}
public TabComponentInstance getTabMenuComponentInstance() {
return _tabComponentInstance;
}
public void setTabMenuComponentInstance(TabComponentInstance tabComponentInstance) {
if (_tabComponentInstance != null) {
removeTabComponentInstance();
}
if (tabComponentInstance.getComponentDefinition() != null) {
_tabComponentInstance = tabComponentInstance;
_tabComponentInstance.setItemMenu(this);
setChanged();
notifyObservers(new DataModification("tabMenuComponentInstance", null, _tabComponentInstance));
} else if (logger.isLoggable(Level.SEVERE)) {
logger.severe("TabComponentInstance does not have a component definition for component named "
+ tabComponentInstance.getComponentName());
}
}
public void removeTabComponentInstance() {
if (_tabComponentInstance != null) {
_tabComponentInstance.delete();
ComponentInstance oldComponentInstance = _tabComponentInstance;
_tabComponentInstance = null;
setChanged();
notifyObservers(new DataModification("tabMenuComponentInstance", oldComponentInstance, null));
}
}
public Hashtable<String, String> getLocalizableProperties() {
if (StringUtils.isNotEmpty(getMenuLabel())) {
Hashtable<String, String> reply = new Hashtable<String, String>();
reply.put("menuLabel", getMenuLabel());
return reply;
}
return null;
}
}