[RCP] Command Menu Label bei Selektion ändern

zeja

Erfahrenes Mitglied
Hier ein kleines Beispiel wie man bei Menü-Einträgen die über Commands erstellt werden, basierend auf einer Selektion in der Oberfläche das Label ändern kann.

Im Menü habe ich einen Eintrag mit dem ein Kunde bearbeitet oder erstellt werden soll. Ist in einer View der Kunde selektiert, soll der Kunde über das Menü bearbeitet werden. Ist kein Kunde selektiert wird ein neuer erstellt. Das Label soll sich entsprechend in "Kunde erstellen" und "Kunde 'xyz' bearbeiten" ändern.

Ich habe das ganze über den State umgesetzt, den ich als Singleton definiert habe, um ihn als PartListener an der Workbench registrieren zu können.

Java:
public interface ICommandInfo {

	public String getCommandId();

	public Map getRefreshFilter();

	public Collection<String> getAvailableStateIds();

}

Java:
import java.util.Collection;
import java.util.Collections;
import java.util.Map;

import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.State;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.commands.IElementUpdater;

public abstract class UpdateableRightCommandHandler extends AbstractHandlerWithState implements IElementUpdater, ICommandInfo {

	public UpdateableRightCommandHandler() {
		this.setBaseEnabled(true);
		updateStates();
	}

	public Map getRefreshFilter() {
		return null;
	}

	public Collection<String> getAvailableStateIds() {
		return Collections.emptyList();
	}

	/**
	 * State wird nicht automatisch gesetzt wenn der deklarative Weg verwendet wird
	 * @param stateIds
	 */
	private void updateStates() {
		final Collection<String> availableStateIds = getAvailableStateIds();
		if (availableStateIds != null && !availableStateIds.isEmpty()) {
			final String commandId = getCommandId();
			if (commandId != null) {
				ICommandService service = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class);
				Command command = service.getCommand(commandId);
				for (String id : availableStateIds) {
					final State state = command.getState(id);
					addState(state.getId(), state);
				}
			}
		}
	}
}

Java:
import java.util.Collection;
import java.util.Collections;
import java.util.Map;

import org.apache.log4j.Logger;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.State;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.menus.UIElement;

public final class OpenCustomerDetailHandler extends UpdateableRightCommandHandler {

	public static final String COMMAND_ID = "customer.commands.OpenCustomerDetail";

	public static final String STATE_ID = "customerState";

	private static final Logger LOGGER = Logger.getLogger(OpenCustomerDetailHandler.class);

	private String customerId;

	public OpenCustomerDetailHandler() {
		super()
	}

	public String getCommandId() {
		return COMMAND_ID;
	}

	@Override
	public Collection<String> getAvailableStateIds() {
		return Collections.singleton(STATE_ID);
	}

	public Object execute(ExecutionEvent event) throws ExecutionException {
		try {
			if (customerId != null) {
				Activator.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(CustomerDetailView.ID, this.customerId, IWorkbenchPage.VIEW_ACTIVATE);
			}
			else {
				Activator.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(CustomerDetailView.ID);
			}
		} catch (PartInitException e) {
			LOGGER.error("", e);
		} catch (Exception e) {
			LOGGER.error("", e);
		}
		return null;
	}

	public void updateElement(UIElement element, Map parameters) {
		if (customerId != null) {
			element.setText("Kunden \"" + customerId + "\" öffnen");
			element.setIcon(Activator.getImageDescriptor("resource/icons/customer/customer_edit.png"));
		}
		else {
			element.setText("Kunden erstellen");
			element.setIcon(Activator.getImageDescriptor("resource/icons/customer/customer_new.png"));
		}

	}

	public void handleStateChange(State state, Object oldValue) {
		this.customerId = state.getValue() != null ? state.getValue().toString() : null;
	}

}

Der State soll an mehreren Stellen genutzt werden und er soll als PartListener registriert werden können. Daher wird ein Wrapper benötigt, der alle Aufrufe an ein Singleton weiterleitet.
Java:
import org.eclipse.core.commands.IStateListener;
import org.eclipse.core.commands.State;

public abstract class SingletonStateWrapper extends State {

	public abstract State createSingleton();

	private final State singleton;

	public SingletonStateWrapper() {
		this.singleton = createSingleton();
	}

	public void addListener(IStateListener listener) {
		singleton.addListener(listener);
	}

	public void dispose() {
		singleton.dispose();
	}

	public boolean equals(Object o) {
		return singleton.equals(o);
	}

	public Object getValue() {
		return singleton.getValue();
	}

	public int hashCode() {
		return singleton.hashCode();
	}

	public void removeListener(IStateListener listener) {
		singleton.removeListener(listener);
	}

	public void setId(String id) {
		singleton.setId(id);
	}

	public void setValue(Object value) {
		singleton.setValue(value);
	}

	public String toString() {
		return singleton.toString();
	}

}

Wenn der Wert im State aktualisiert wird, muss für alle Handler ein Update der Oberfläche getriggert werden.
Java:
import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.commands.State;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;

public class UIState extends State {

	@Override
	public void setValue(Object value) {
		super.setValue(value);

		// Weitergabe der Aktualisierung an die UI
		Map<String, Map> commandIds = new HashMap<String, Map>();
		for (Object listener : getListeners()) {
			if (listener instanceof RightCommandHandler) {
				ICommandInfo handler = (ICommandInfo) listener;
				commandIds.put(handler.getCommandId(), handler.getRefreshFilter());
			}
		}
		if (!commandIds.isEmpty()) {
			ICommandService service = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class);
			for (Map.Entry<String, Map> entry : commandIds.entrySet()) {
				service.refreshElements(entry.getKey(), entry.getValue());
			}
		}
	}

}

"Factory" die bei Instantiierung ein Singleton erstellt. Es wird immer über das Singleton-Objekt gearbeitet.
Java:
import org.eclipse.core.commands.State;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.IWorkbenchPart;

public class CustomerStateFactory extends SingletonStateWrapper {

	@Override
	public State createSingleton() {
		return getCustomerState();
	}

	public static CustomerState getCustomerState() {
		return CustomerState.INSTANCE;
	}

	public static final class CustomerState extends UIState implements IPartListener {

		static final CustomerState INSTANCE = new CustomerState();

		private CustomerState() {

		}

		public void partActivated(IWorkbenchPart part) {
			if (part instanceof ICustomerRelatedView) {
				ICustomerRelatedView view = (ICustomerRelatedView) part;
				this.setCustomerId(view.getCustomerId());
			}
			else {
				this.setCustomerId(null);
			}
		}

		public void partBroughtToTop(IWorkbenchPart part) {
			partActivated(part);
		}

		public void partClosed(IWorkbenchPart part) {
		}

		public void partDeactivated(IWorkbenchPart part) {
		}

		public void partOpened(IWorkbenchPart part) {
		}

		public void setCustomerId(String customerId) {
			setValue(customerId);
		}

	}

}

Registriert einen PartListener auf dem CustomerState.
Java:
public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {

	@Override
	public void postWindowOpen() {
		final IWorkbenchWindow activeWorkbenchWindow = Activator.getDefault().getWorkbench().getActiveWorkbenchWindow();
		final IPartService partService = activeWorkbenchWindow.getPartService();
		
		partService.addPartListener(CustomerStateFactory.getCustomerState());

		final IWorkbenchPart activePart = partService.getActivePart();
		if (activePart != null) {
			CustomerStateFactory.getCustomerState().partActivated(activePart);
		}
	}

}

Die Definition des Command:
XML:
<command
      categoryId="category.customer"
      defaultHandler="customer.commands.OpenCustomerDetailHandler"
      id="customer.commands.OpenCustomerDetail"
      name="OpenCustomerDetail">
   <state
         class="customer.commands.CustomerStateFactory"
         id="customerState">
   </state>
</command>
 
Zuletzt bearbeitet von einem Moderator:
Zurück