RCP Problem mit MenuManager

dzim

Top Contributor
Hallo zusammen,

ich habe vor kurzem begonnen eine Anwendung noch ein wenig zu "pimpen".
Dazu fiel mir auf, das vor allem viele Tabellen und Trees keine Menüs haben und viele Funktionen umständliche (also: weiter Weg mit der Maus) nur über Buttons steuerbar sind (add/edit/remove/...)

Ich habe daher angefangen mittels MenuManager das ganze aufzupeppen:
Java:
final MenuManager menuManager = new MenuManager();
menuManager.setRemoveAllWhenShown(true);
final Menu menu = menuManager.createContextMenu(tableViewer
		.getControl());
menuManager.addMenuListener(new IMenuListener() {

	@Override
	public void menuAboutToShow(final IMenuManager manager) {
		manager.setRemoveAllWhenShown(true);
		fillContextMenu(ssdModel, tableViewer, manager);
	}
});
tableViewer.getControl().setMenu(menu);

Das funktioniert für meinen ersten TreeViewer hervorragend, für einen anderen aber überhaupt nicht.
Ich wollte zur fillContextMenu-Methode debuggen, stellte aber einfach fest, dass der Listener offenbar nie ausgelöst wurde.
Der folgende Hack zeigt beim ersten Rechtsklick das Menü (mit DropDown-Menü-Item), beim zweiten Klick sind die DropDown-Items auf einmal auf der Hauptebene der Menü-Items. Beim dritten Klick verrent sich (reproduzierbar) offenbar mein fglrx Graphiktreiber (Ubuntu 11.04/Unity).
Java:
ispTableViewer.getTable().addMenuDetectListener(
		new MenuDetectListener() {

			@Override
			public void menuDetected(MenuDetectEvent e) {
				if (!menuManager.getMenu().isDisposed())
					menuManager.getMenu().setVisible(true);
				}
		});

Ich versteh aber schlicht und ergreifend nicht, warum der grundsätzlich gleiche Code in einem Composite geht, und in einem anderen nicht.
Kann es an inkompatibilitäten mit anderen Listenern liegen, die die Ausführung des IMenuListener des MenuManagers verhindern?

Vielen Dank und Grüße,
Daniel

PS: meine fillContextMenu-Methode:
Java:
	private void fillContextMenu(SSDModel ssdModel, TableViewer viewer,
			IMenuManager manager) {

		Object[] selection = ((IStructuredSelection) viewer.getSelection())
				.toArray();

		Action action = new AddEditRemoveEntryAction(ssdModel, selection,
				viewer, AddEditRemoveEntryAction.Type.ADD);
		manager.add(action);

		action = new AddEditRemoveEntryAction(ssdModel, selection, viewer,
				AddEditRemoveEntryAction.Type.EDIT);
		if (selection == null || selection.length == 0 || selection.length > 1) {
			action.setEnabled(false);
		}
		manager.add(action);

		action = new AddEditRemoveEntryAction(ssdModel, selection, viewer,
				AddEditRemoveEntryAction.Type.REMOVE);
		if (selection == null || selection.length == 0) {
			action.setEnabled(false);
		}
		manager.add(action);

		manager.add(new Separator());

		action = new AddEditRemoveEntryAction(ssdModel, selection, viewer,
				AddEditRemoveEntryAction.Type.MENU);
		if (selection == null || selection.length == 0 || selection.length > 1) {
			action.setEnabled(false);
		}
		manager.add(action);
	}

PPS: Die Action(s), die ich in den MenuManager rein werfe (gekürzt, da zu lang):
Java:
public class AddEditRemoveEntryAction extends Action {

	private static final Image ADD = IconProvider.getImageByIconName(
			"fugue_plus.png", true); //$NON-NLS-1$
	private static final Image REMOVE = IconProvider.getImageByIconName(
			"fugue_minus.png", true); //$NON-NLS-1$
	private static final Image EDIT = IconProvider.getImageByIconName(
			"fugue_pencil.png", true); //$NON-NLS-1$
	private static final Image CALENDAR = IconProvider
			.getImageByIconName("fugue_calendar--pencil.png", true); //$NON-NLS-1$

	public static enum Type {
		ADD, EDIT, REMOVE, MENU;
	}

	private SSDModel ssdModel;
	private Object[] selection;

	private Viewer parentViewer;

	private AddEditRemoveEntryAction.Type type;

	// used only if Type == MENU
	private MenuCreatorImpl menuCreator = null;

	public AddEditRemoveEntryAction(SSDModel ssdModel, Object[] selection,
			Viewer parentViewer, AddEditRemoveEntryAction.Type type) {

		super("", Type.MENU == type ? AS_DROP_DOWN_MENU : AS_PUSH_BUTTON); //$NON-NLS-1$

		this.ssdModel = ssdModel;
		this.selection = selection;
		this.parentViewer = parentViewer;
		this.type = type;

		switch (type) {
		case ADD:
			setText(Messages
					.getString("EntrySettingsComposite.addButton.text")); //$NON-NLS-1$
			setImageDescriptor(ImageDescriptor.createFromImage(ADD));
			break;
		case EDIT:
			setText(Messages
					.getString("EntrySettingsComposite.editButton.text")); //$NON-NLS-1$
			setImageDescriptor(ImageDescriptor.createFromImage(EDIT));
			break;
		case REMOVE:
			setText(Messages
					.getString("EntrySettingsComposite.deleteButton.text")); //$NON-NLS-1$
			setImageDescriptor(ImageDescriptor.createFromImage(REMOVE));
			break;
		case MENU:
			setText("Edit Retention Time");
			setImageDescriptor(ImageDescriptor.createFromImage(CALENDAR));
			// create MenuCreatorImpl (private class at the end of this one)
			menuCreator = new MenuCreatorImpl();
			setMenuCreator(menuCreator);
			break;
		}
	}

	@Override
	public void run() {

		switch (type) {
		case ADD:
			handleAdd();
			break;
		case EDIT:
			handleEdit();
			break;
		case REMOVE:
			handleRemove();
			break;
		case MENU:
			// create menu
			handleMenu();
			break;
		}
	}

	private void handleAdd() {
		[...]
	}

	private void handleEdit() {
		[...]
	}

	private void handleRemove() {
		[...]
	}

	private void handleMenu() {
		setMenuCreator(menuCreator);
		Menu menu = menuCreator.getMenu(parentViewer.getControl());
		if (menu != null && !menu.isDisposed())
			menu.setVisible(true);
	}

	private class MenuCreatorImpl implements IMenuCreator {

		private Menu menu;

		@Override
		public void dispose() {
			if (menu != null) {
				menu.dispose();
			}
		}

		@Override
		public Menu getMenu(Menu parent) {
			return getMenu(parent.getShell());
		}

		@Override
		public Menu getMenu(Control parent) {

			if (menu != null) {
				menu.dispose();
			}

			menu = new Menu(parent);

			int i = 0;
			for (LookupTimes.Day day : LookupTimes.Day.values()) {
				LookupTimeAction action = new LookupTimeAction(day,
						selection[0]);
				addActionToMenu(menu, action, i + 1);
				i++;
			}

			return menu;
		}

		private void addActionToMenu(Menu parent, Action action, int accelerator) {
			if (accelerator < 10) {
				StringBuffer label = new StringBuffer();
				// add the numerical accelerator
				label.append("&"); //$NON-NLS-1$
				label.append(accelerator);
				label.append(" "); //$NON-NLS-1$
				label.append(action.getText());
				action.setText(label.toString());
			}
			ActionContributionItem item = new ActionContributionItem(action);
			item.fill(parent, -1);
		}
	}

	private class LookupTimeAction extends Action {

		private lookupTimes.Day day;

		private Object firstSelection;

		public LookupTimeAction(LookupTimes.Day day, Object firstSelection) {
			super(day.getName(), AS_PUSH_BUTTON);
			this.day = day;
			this.firstSelection = firstSelection;
		}

		@Override
		public void run() {

			if (day == null)
				return;

			Entry e = (Entry) firstSelection;
			if (e == null)
				return;

			ModifyLookupTimeShell shell = new ModifyLookupTimeShell(
					parentViewer.getControl().getDisplay());
			shell.setData(e, day);
			Point location = parentViewer.getControl().getDisplay()
					.getCursorLocation();
			if (location != null)
				shell.openShellAtLocation(location, true);
			else
				shell.openShellOverlay(parentViewer.getControl(), true);

			ModifyLookupTimeResult result = shell.getRetentionTime();
			if (result.isCanceled()) {
				return;
			}

			if (result.getEntry() != null && result.getDay() != null) {
				Entry e = result.getEntry();
				LookupTimes lookupTimes = entry.getLookupTimes();
				if (result.getLookupTime() != null) {
					lookupTimes.setLookupTime(result.getLookupTime());
				} else {
					lookupTimes.setLookupTime(new LookupTime(result
							.getDay()));
				}
				parentViewer.refresh();
			}
		}
	}
}
 
Hallo dzim

Möglicherweise bin ich auf dem Holzweg, aber probier doch mal, ob Du bessere Ergebnisse beider Darstellung erzielst, wenn Du beim Login in Dein System von Ubuntu auf Ubuntu Classic stellst. Das geht, wenn Du auf Deinen Account klickst und unten in der Taskleiste den Anzeigemanager aus einem Drop-Down Menu wählst.

Ich habe selbst einige Probleme, bei der Darstellung der Menüs unter Ubuntu 11.04 gehabt. Dort wird in RCP Anwendungen gar kein Menü der Anwendung ins global Menu geladen. Erst als ich statt Unity auf Classic beim Login geschaltet habe, wurde das Menü wieder im eigentlichen Anwendungsfenster anständig gezeigt und war zugreifbar.

Viele Grüße,
Semo
 
Das Problem kenn' ich auch: Das globale Eclipse-Menü wird noch dargestellt, aber nicht von der eigenen RCP. Das habe ich "gelöst" indem ich alle packages mit "appmenu" im Namen (sind nur eine Hand voll) deinstalliert habe. Seitdem habe ich auch kein Problem mit dem globalen Menü meiner Anwendung mehr.
Ich gebe an dieser Stelle zu, dass mir der Weg, wie Eclipse das gelöst hat lieber gewesen wäre (dann ist es universell einsetzbar), aber da der Kunde für den das Programm ist, nur Windows und Mac verwendet, spielt das eh keine Rolle.

Kurzum: Ich denke, dass mein Problem damit nichts zu tun hat. Hier habe ich irgendwie Bockmist gebaut und weiß nur nicht wo und wie! Es wird ja nur der Listener, der das Menü der Tabelle erstellen soll (wie gesagt, es geht nicht ums globale Menü der Anwendung), nicht ausgelöst wird.

Ich kann aber dennoch mal auf KDE oder so ausprobieren, wie es sich da verhält...

Thx anyway!
Daniel
 
Hallo zusammen,

schade, dass mir bei dem Problem offenbar keiner weiterhelfen konnte.
Ich verstehe bis heute nicht, warum das Event (menuAboutToShow) nicht ausgelöst wird, ich habe - nachdem ich hier wieder ein wenig Zeit zum "experimentieren" hatte aber erst einmal einen Workaround gefunden, der mich die MenuManager weiter nutzen lässt:
Java:
		final MenuManager menuManager = new MenuManager();
		menuManager.setRemoveAllWhenShown(true);
		menuManager.addMenuListener(new IMenuListener() {
			@Override
			public void menuAboutToShow(final IMenuManager manager) {
				SelectionSettingsComposite.this.fillContextMenu(manager);
			}
		});
		final Menu menu = menuManager.createContextMenu(settingsTreeViewer
				.getControl());
		settingsTreeViewer.getControl().setMenu(menu);
		// FIXME this hack enables the menu
		// The menuAboutToShow method from the MenuManager is never triggered
		// for some unknown reason! (At least unknown to me...)
		settingsTreeViewer.getControl().addMenuDetectListener(
				new MenuDetectListener() {
					@Override
					public void menuDetected(MenuDetectEvent e) {
						SelectionSettingsComposite.this
								.fillContextMenu(menuManager);
						settingsTreeViewer.getControl().setMenu(
								menuManager.getMenu());
						settingsTreeViewer.getControl().getMenu()
								.setVisible(true);
					}
				});

Das Problem ist damit nicht wirklich behoben, aber ich betrachte das Thema damit erst einmal als erledigt.
Das nächste folgt allerdings auch schon wieder ;-)

Daniel
 

Neue Themen


Zurück
Oben