/*
* Copyright 2014 cruxframework.org.
*
* 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.cruxframework.crux.smartfaces.client.menu;
import org.cruxframework.crux.core.client.collection.FastList;
import org.cruxframework.crux.core.client.event.HasSelectHandlers;
import org.cruxframework.crux.core.client.event.SelectEvent;
import org.cruxframework.crux.core.client.event.SelectHandler;
import org.cruxframework.crux.core.client.utils.StringUtils;
import org.cruxframework.crux.smartfaces.client.button.Button;
import org.cruxframework.crux.smartfaces.client.label.HTML;
import org.cruxframework.crux.smartfaces.client.label.Label;
import org.cruxframework.crux.smartfaces.client.panel.SelectablePanel;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.HasEnabled;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;
/**
* A cross device menu item
*
* @author Samuel Almeida Cardoso (samuel@cruxframework.org)
* @author Thiago da Rosa de Bustamante
*/
public class MenuItem extends UIObject implements HasSelectHandlers, HasEnabled
{
private SelectablePanel itemPanel;
private MenuItem parentItem;
private FastList<MenuItem> children = new FastList<MenuItem>();
private boolean root;
private Element childrenContainer;
private HandlerManager handlerManager;
private Menu menu;
private Button openCloseTriggerHelper = null;
private boolean opened = false;
private boolean enabled = true;
private String value = null;
MenuItem(Widget itemWidget)
{
if (itemWidget == null)
{
root = true;
childrenContainer = DOM.createElement("ul");
setElement(childrenContainer);
setStyleName(Menu.STYLE_FACES_UL);
}
else
{
this.itemPanel = new SelectablePanel();
this.itemPanel.add(itemWidget);
setElement(Document.get().createElement("li"));
setStyleName(Menu.STYLE_FACES_LI);
getElement().appendChild(itemPanel.getElement());
}
}
protected void setMenu(Menu menu)
{
if (this.menu != menu)
{
if (menu == null)
{
this.menu.orphan(this);
}
else
{
if (this.menu != null)
{
this.menu.orphan(this);
}
menu.adopt(this);
}
this.menu = menu;
for (int i = 0; i < children.size(); i++)
{
children.get(i).setMenu(menu);
}
}
}
public boolean isRoot()
{
return root;
}
public void open()
{
if (this.parentItem != null && menu.isSlider())
{
final Button closeButton = new Button();
closeButton.setStyleName(Menu.STYLE_AUX_CLOSE_TRIGGER_SLIDER_HELPER);
closeButton.addSelectHandler(new SelectHandler()
{
@Override
public void onSelect(SelectEvent event)
{
if (MenuItem.this.childrenContainer != null)
{
MenuItem.this.childrenContainer.removeChild(closeButton.getElement());
}
close();
}
});
menu.adopt(this, closeButton);
if (this.childrenContainer != null)
{
this.childrenContainer.insertFirst(closeButton.getElement());
}
}
opened = true;
if (!getOpenCloseTriggerHelper().getStyleName().contains(Menu.STYLE_FACES_OPEN))
{
getOpenCloseTriggerHelper().addStyleName(Menu.STYLE_FACES_OPEN);
}
MenuUtils.addOrRemoveClass(Menu.STYLE_FACES_OPEN, true, this);
}
public void close()
{
opened = false;
getOpenCloseTriggerHelper().removeStyleName(Menu.STYLE_FACES_OPEN);
MenuUtils.addOrRemoveClass(Menu.STYLE_FACES_OPEN, false, this);
}
public void clear()
{
for (int i = 0; i < children.size(); i++)
{
children.get(i).setMenu(null);
}
if (childrenContainer != null)
{
childrenContainer.removeFromParent();
}
children.clear();
}
@Override
public HandlerRegistration addSelectHandler(SelectHandler handler)
{
return addHandler(handler, SelectEvent.getType());
}
protected void addItem(final MenuItem menuItem)
{
if (childrenContainer == null)
{
childrenContainer = Document.get().createElement("ul");
getElement().appendChild(childrenContainer);
setStyleName(childrenContainer, Menu.STYLE_FACES_UL);
}
childrenContainer.appendChild(menuItem.getElement());
menuItem.parentItem = this;
children.add(menuItem);
menuItem.setMenu(menu);
menuItem.getItemPanel().addSelectHandler(new SelectHandler()
{
@Override
public void onSelect(SelectEvent event)
{
if (!menuItem.enabled)
{
event.setCanceled(true);
event.stopPropagation();
return;
}
if (!menu.isTree())
{
if (menuItem.opened)
{
menuItem.close();
}
else
{
menuItem.open();
}
}
SelectEvent.fire(menuItem);
SelectionEvent.fire(menu, menuItem);
}
});
if (!root)
{
if (!getElement().getClassName().contains(Menu.STYLE_FACES_HAS_CHILDREN))
{
getElement().appendChild(getOpenCloseTriggerHelper().getElement());
menu.adopt(this, getOpenCloseTriggerHelper());
getElement().addClassName(Menu.STYLE_FACES_HAS_CHILDREN);
}
}
else
{
getElement().removeClassName(Menu.STYLE_FACES_EMPTY);
}
}
// Adding CSS helper div/button important to render icons
// like open/close in accordion and tree menu types
protected Button getOpenCloseTriggerHelper()
{
if (openCloseTriggerHelper != null)
{
return openCloseTriggerHelper;
}
openCloseTriggerHelper = new Button();
openCloseTriggerHelper.setStyleName(Menu.STYLE_AUX_OPEN_CLOSE_TRIGGER_HELPER);
openCloseTriggerHelper.addSelectHandler(new SelectHandler()
{
@Override
public void onSelect(SelectEvent event)
{
if (!enabled)
{
event.setCanceled(true);
event.stopPropagation();
return;
}
if (opened)
{
close();
}
else
{
open();
}
}
});
return openCloseTriggerHelper;
}
public String getValue()
{
return value;
}
public void setValue(String value)
{
this.value = value;
}
public MenuItem addItem(Widget widget)
{
MenuItem menuItem = new MenuItem(widget);
addItem(menuItem);
return menuItem;
}
public MenuItem addItem(String labelText)
{
return addItem(new Label(labelText));
}
public MenuItem addItem(SafeHtml html)
{
return addItem(new HTML(html));
}
public boolean removeItem(MenuItem item)
{
return removeItem(indexOf(item));
}
public boolean removeItem(int index)
{
if (index >= 0 && index < children.size())
{
MenuItem item = getItem(index);
item.getElement().removeFromParent();
children.remove(index);
item.setMenu(null);
if (children.size() <= 0)
{
if (!root)
{
item.removeClassName(Menu.STYLE_FACES_HAS_CHILDREN);
}
else
{
item.addClassName(Menu.STYLE_FACES_EMPTY);
}
}
return true;
}
return false;
}
public int getItemCount()
{
return children.size();
}
public MenuItem getItem(int index)
{
return children.get(index);
}
public int indexOf(MenuItem item)
{
return children.indexOf(item);
}
public MenuItem getItem(String path)
{
if (StringUtils.isEmpty(path))
{
return null;
}
String[] items = path.split("-");
MenuItem result = null;
MenuItem current = this;
for (String index : items)
{
result = current.getItem(Integer.parseInt(index));
current = result;
}
return result;
}
public void removeFromMenu()
{
if (parentItem != null)
{
parentItem.removeItem(this);
}
}
public Widget getItemWidget()
{
return itemPanel.getChildWidget();
}
public void addClassName(String className)
{
getElement().addClassName(className);
}
public void removeClassName(String className)
{
getElement().removeClassName(className);
}
public MenuItem getParentItem()
{
return parentItem;
}
@Override
public void fireEvent(GwtEvent<?> event)
{
if (handlerManager != null)
{
handlerManager.fireEvent(event);
}
}
FastList<MenuItem> getChildren()
{
return children;
}
/**
* Ensures the existence of the handler manager.
*
* @return the handler manager
* */
HandlerManager ensureHandlers()
{
return handlerManager == null ? handlerManager = new HandlerManager(this) : handlerManager;
}
<H extends EventHandler> HandlerRegistration addHandler(final H handler, GwtEvent.Type<H> type)
{
return ensureHandlers().addHandler(type, handler);
}
SelectablePanel getItemPanel()
{
return itemPanel;
}
@Override
public boolean isEnabled()
{
return enabled;
}
@Override
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
if (!enabled)
{
if (!getElement().getClassName().contains(Menu.STYLE_FACES_DISABLED))
{
getElement().addClassName(Menu.STYLE_FACES_DISABLED);
}
}
else
{
getElement().removeClassName(Menu.STYLE_FACES_DISABLED);
}
}
public boolean hasChildren()
{
return children.size() > 0 ? true : false;
}
public void setId(String id)
{
this.getElement().setId(id);
}
}