/*******************************************************************************
* Copyright (c) 2012 Rushan R. Gilmullin and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Rushan R. Gilmullin - initial API and implementation
*******************************************************************************/
package org.semanticsoft.vaaclipse.presentation.renderers;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import org.eclipse.e4.core.contexts.ContextInjectionFactory;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.di.annotations.CanExecute;
import org.eclipse.e4.core.services.contributions.IContributionFactory;
import org.eclipse.e4.ui.model.application.ui.MElementContainer;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.menu.ItemType;
import org.eclipse.e4.ui.model.application.ui.menu.MDirectToolItem;
import org.eclipse.e4.ui.model.application.ui.menu.MHandledItem;
import org.eclipse.e4.ui.model.application.ui.menu.MHandledToolItem;
import org.eclipse.e4.ui.model.application.ui.menu.MItem;
import org.eclipse.e4.ui.model.application.ui.menu.MOpaqueToolItem;
import org.eclipse.e4.ui.model.application.ui.menu.MToolBarElement;
import org.eclipse.e4.ui.model.application.ui.menu.MToolItem;
import org.eclipse.e4.ui.services.internal.events.EventBroker;
import org.eclipse.e4.ui.workbench.UIEvents;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import org.semanticsoft.vaaclipse.presentation.utils.Commons;
import org.semanticsoft.vaaclipse.publicapi.resources.ResourceHelper;
import org.semanticsoft.vaaclipse.widgets.ToolbarButton;
import org.semanticsoft.vaaclipse.widgets.ToolbarButtonBase;
import org.semanticsoft.vaaclipse.widgets.ToolbarButton.Type;
import org.semanticsoft.vaaclipse.widgets.TwoStateToolbarButton;
import com.vaadin.server.Resource;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Component;
@SuppressWarnings("restriction")
public class ToolItemRenderer extends ItemRenderer {
@Inject
IContributionFactory contributionFactory;
@Inject
EventBroker eventBroker;
private static final String HCI_STATIC_CONTEXT = "HCI-staticContext";
private EventHandler itemUpdater = new EventHandler() {
public void handleEvent(Event event) {
// Ensure that this event is for a MMenuItem
if (!(event.getProperty(UIEvents.EventTags.ELEMENT) instanceof MToolBarElement))
return;
MToolBarElement itemModel = (MToolBarElement) event
.getProperty(UIEvents.EventTags.ELEMENT);
Button ici = (Button) itemModel.getWidget();
if (ici == null) {
return;
}
String attName = (String) event
.getProperty(UIEvents.EventTags.ATTNAME);
String newValue = (String) event
.getProperty(UIEvents.EventTags.NEW_VALUE);
if (UIEvents.UILabel.LABEL.equals(attName)) {
ici.setCaption(newValue);
} else if (UIEvents.UILabel.ICONURI.equals(attName)) {
Resource icon = ResourceHelper.createResource(newValue);
ici.setIcon(icon);
} else if (UIEvents.UILabel.TOOLTIP.equals(attName)) {
ici.setDescription(newValue);
}
}
};
private EventHandler toBeRenderedUpdater = new EventHandler() {
public void handleEvent(Event event) {
// Ensure that this event is for a MMenuItem
if (!(event.getProperty(UIEvents.EventTags.ELEMENT) instanceof MToolBarElement))
return;
MToolBarElement itemModel = (MToolBarElement) event
.getProperty(UIEvents.EventTags.ELEMENT);
String attName = (String) event
.getProperty(UIEvents.EventTags.ATTNAME);
if (UIEvents.UIElement.VISIBLE.equals(attName)) {
Button ici = (Button) itemModel.getWidget();
if (ici == null) {
return;
}
ici.setVisible(itemModel.isVisible());
}
}
};
private EventHandler selectionUpdater = new EventHandler() {
public void handleEvent(Event event) {
// Ensure that this event is for a MToolItem
if (!(event.getProperty(UIEvents.EventTags.ELEMENT) instanceof MToolBarElement))
return;
MToolBarElement itemModel = (MToolBarElement) event
.getProperty(UIEvents.EventTags.ELEMENT);
if (itemModel.getWidget() instanceof TwoStateToolbarButton) {
TwoStateToolbarButton button = (TwoStateToolbarButton) itemModel
.getWidget();
Boolean newValue = (Boolean) event
.getProperty(UIEvents.EventTags.NEW_VALUE);
button.setCheckedState(newValue);
}
}
};
private EventHandler enabledUpdater = new EventHandler() {
public void handleEvent(Event event) {
// Ensure that this event is for a MMenuItem
if (!(event.getProperty(UIEvents.EventTags.ELEMENT) instanceof MToolBarElement))
return;
MToolBarElement itemModel = (MToolBarElement) event
.getProperty(UIEvents.EventTags.ELEMENT);
Button ici = (Button) itemModel.getWidget();
Boolean newValue = (Boolean) event
.getProperty(UIEvents.EventTags.NEW_VALUE);
ici.setEnabled(newValue);
}
};
@PostConstruct
public void init() {
eventBroker.subscribe(UIEvents.UILabel.TOPIC_ALL, itemUpdater);
eventBroker.subscribe(UIEvents.Item.TOPIC_SELECTED, selectionUpdater);
eventBroker.subscribe(UIEvents.Item.TOPIC_ENABLED, enabledUpdater);
eventBroker
.subscribe(UIEvents.UIElement.TOPIC_ALL, toBeRenderedUpdater);
}
@PreDestroy
public void contextDisposed() {
eventBroker.unsubscribe(itemUpdater);
eventBroker.unsubscribe(selectionUpdater);
eventBroker.unsubscribe(enabledUpdater);
eventBroker.unsubscribe(toBeRenderedUpdater);
}
@Override
public void createWidget(MUIElement element,
MElementContainer<MUIElement> parent) {
if (element instanceof MHandledToolItem
|| element instanceof MDirectToolItem) {
final MToolItem item = (MToolItem) element;
ToolbarButtonBase button;
if (item.getType() == ItemType.CHECK)
{
button = new TwoStateToolbarButton();
((TwoStateToolbarButton)button).setCheckedState(item.isSelected());
}
else if (item.getType() == ItemType.RADIO)
{
button = new TwoStateToolbarButton();
((TwoStateToolbarButton)button).setCheckedState(item.isSelected());
((TwoStateToolbarButton)button).setSwitchStateByUserClickEnabled(false);
}
else { //By default - ItemType.PUSH
ToolbarButton toolbarButton = new ToolbarButton();
button = toolbarButton;
if (item.getTags().contains("link"))
{
toolbarButton.setType(Type.Link);
}
}
//label and icon
button.setLabelAndIcon(Commons.trim(item.getLabel()), Commons.trim(item.getIconURI()));
//tooltip
if (item.getTooltip() != null)
button.setDescription(item.getLocalizedTooltip());
element.setWidget(button);
updateItemEnablement(item);
button.setEnabled(item.isEnabled());
registerEnablementUpdaters(item);
}
}
protected void updateItemEnablement(MItem item) {
if (!(item.getWidget() instanceof Button))
return;
Button widget = (Button) item.getWidget();
if (widget == null)
return;
item.setEnabled(canExecute(item));
}
private boolean canExecute(MItem item) {
if (item instanceof MHandledItem)
return canExecuteItem((MHandledItem) item);
else if (item instanceof MDirectToolItem)
return canExecuteItem((MDirectToolItem) item);
else
return false;
}
private boolean canExecuteItem(MDirectToolItem item) {
final IEclipseContext eclipseContext = getContext(item);
if (eclipseContext == null) // item is not in hierarchy
return false;
if (item.getObject() == null)
{
item.setObject(contributionFactory.create(
item.getContributionURI(), getContext(item)));
}
eclipseContext.set(MItem.class, item);
setupContext(eclipseContext, item);
return (Boolean) ContextInjectionFactory.invoke(item.getObject(), CanExecute.class,
eclipseContext, true);
}
@Override
public void hookControllerLogic(MUIElement me) {
if (me instanceof MDirectToolItem) {
final MDirectToolItem item = (MDirectToolItem) me;
final Button button = (Button) item.getWidget();
button.addClickListener(new ClickListener() {
@SuppressWarnings("unchecked")
@Override
public void buttonClick(ClickEvent event) {
if (item.getType() == ItemType.CHECK) {
item.setSelected(((TwoStateToolbarButton) button)
.getCheckedState());
}
else if (item.getType() == ItemType.RADIO)
{
MElementContainer<? extends MToolItem> parent = (MElementContainer<? extends MToolItem>) item.getParent();
for (MToolItem toolItem : parent.getChildren())
{
if (toolItem.getType() == ItemType.RADIO)
{
toolItem.setSelected(toolItem != item);
}
}
}
processAction(item);
}
});
} else if (me instanceof MHandledToolItem) {
final MHandledItem item = (MHandledToolItem) me;
final Button button = (Button) item.getWidget();
button.addClickListener(new ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
if (item.getType() == ItemType.CHECK) {
item.setSelected(((TwoStateToolbarButton) button)
.getCheckedState());
}
else if (item.getType() == ItemType.RADIO)
{
MElementContainer<? extends MToolItem> parent = (MElementContainer<? extends MToolItem>) item.getParent();
for (MToolItem toolItem : parent.getChildren())
{
if (toolItem.getType() == ItemType.RADIO)
{
toolItem.setSelected(toolItem != item);
}
}
}
processParametrizedAction(item);
}
});
}
}
@Override
protected void setupContext(IEclipseContext context, MItem item) {
super.setupContext(context, item);
context.set(MToolItem.class, (MToolItem) item);
if (item instanceof MDirectToolItem)
context.set(MDirectToolItem.class, (MDirectToolItem) item);
else if (item instanceof MHandledToolItem)
context.set(MHandledToolItem.class, (MHandledToolItem) item);
else if (item instanceof MOpaqueToolItem)
context.set(MOpaqueToolItem.class, (MOpaqueToolItem) item);
}
}