Bug 462445 - MenuTypes not correctly updated in TablePages

Change-Id: I3b969f5c1e813527a31ce26ed707cb3c82a702ff
Signed-off-by: Judith Gull <jgu@bsiag.com>

Change-Id: I525acb88332d8e014f4775d9d40be9cb57b9d69f
Reviewed-on: https://git.eclipse.org/r/45109
Tested-by: Hudson CI
Reviewed-by: Judith Gull <jgu@bsiag.com>
diff --git a/org.eclipse.scout.rt.client.test/src/org/eclipse/scout/rt/client/ui/action/menu/TableMenuTest.java b/org.eclipse.scout.rt.client.test/src/org/eclipse/scout/rt/client/ui/action/menu/TableMenuTest.java
index 03d6834..b51e134 100644
--- a/org.eclipse.scout.rt.client.test/src/org/eclipse/scout/rt/client/ui/action/menu/TableMenuTest.java
+++ b/org.eclipse.scout.rt.client.test/src/org/eclipse/scout/rt/client/ui/action/menu/TableMenuTest.java
@@ -10,6 +10,10 @@
  ******************************************************************************/
 package org.eclipse.scout.rt.client.ui.action.menu;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 
@@ -19,81 +23,180 @@
 import org.eclipse.scout.commons.exception.ProcessingException;
 import org.eclipse.scout.rt.client.ui.action.ActionUtility;
 import org.eclipse.scout.rt.client.ui.action.IActionFilter;
+import org.eclipse.scout.rt.client.ui.action.menu.fixture.OwnerValueCapturingMenu;
 import org.eclipse.scout.rt.client.ui.action.menu.root.ITableContextMenu;
 import org.eclipse.scout.rt.client.ui.basic.table.AbstractTable;
+import org.eclipse.scout.rt.client.ui.basic.table.ITable;
 import org.eclipse.scout.rt.client.ui.basic.table.ITableRow;
 import org.eclipse.scout.rt.client.ui.basic.table.columns.AbstractStringColumn;
 import org.eclipse.scout.testing.client.runner.ScoutClientTestRunner;
-import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 /**
- *
+ * Tests for {@link AbstractTableMenu}
  */
 @RunWith(ScoutClientTestRunner.class)
 public class TableMenuTest {
 
+  private OwnerValueCapturingMenu m_multi;
+  private OwnerValueCapturingMenu m_single;
+  private OwnerValueCapturingMenu m_emptySpace;
+  private OwnerValueCapturingMenu m_combindedSingle;
+  private OwnerValueCapturingMenu m_all;
+
+  @Before
+  public void before() {
+    m_multi = new OwnerValueCapturingMenu(TableMenuType.MultiSelection);
+    m_single = new OwnerValueCapturingMenu(TableMenuType.SingleSelection);
+    m_emptySpace = new OwnerValueCapturingMenu(TableMenuType.EmptySpace);
+    m_combindedSingle = new OwnerValueCapturingMenu(TableMenuType.EmptySpace, TableMenuType.SingleSelection);
+    m_all = new OwnerValueCapturingMenu(TableMenuType.values());
+  }
+
+  private static final Object[][] TEST_ROWS = new Object[][]{
+      {"Boss", "Hugo"},
+      {"Meier", "Hans"}
+  };
+
+  /**
+   * Tests the visibility for a single selection menu
+   */
   @Test
-  public void testSingleSelection() throws Exception {
+  public void testSingleSelection() throws ProcessingException {
     Table t = new Table();
-    t.addRowsByMatrix(new Object[][]{
-        {"Boss", "Hugo"},
-        {"Meier", "Hans"}
-    });
+    t.addRowsByMatrix(TEST_ROWS);
     ITableContextMenu contextMenu = t.getContextMenu();
 
     // single hugo boss
     t.selectRows(CollectionUtility.arrayList(t.getRow(0)), false);
     IActionFilter filter = ActionUtility.createMenuFilterMenuTypes(contextMenu.getCurrentMenuTypes(), true);
     List<IMenu> visibleMenus = ActionUtility.normalizedActions(contextMenu.getChildActions(), filter);
-    Assert.assertEquals(2, visibleMenus.size());
-    Assert.assertEquals("SingleSelectionMenu", visibleMenus.get(0).getClass().getSimpleName());
-    Assert.assertEquals("HugoBossMenu", visibleMenus.get(1).getClass().getSimpleName());
+    assertEquals(2, visibleMenus.size());
+    assertEquals("SingleSelectionMenu", visibleMenus.get(0).getClass().getSimpleName());
+    assertEquals("HugoBossMenu", visibleMenus.get(1).getClass().getSimpleName());
 
     // single only meier
     t.selectRows(CollectionUtility.arrayList(t.getRow(1)), false);
     filter = ActionUtility.createMenuFilterMenuTypes(contextMenu.getCurrentMenuTypes(), true);
     visibleMenus = ActionUtility.normalizedActions(contextMenu.getChildActions(), filter);
-    Assert.assertEquals(1, visibleMenus.size());
-    Assert.assertEquals("SingleSelectionMenu", visibleMenus.get(0).getClass().getSimpleName());
-
+    assertEquals(1, visibleMenus.size());
+    assertEquals("SingleSelectionMenu", visibleMenus.get(0).getClass().getSimpleName());
   }
 
+  /**
+   * Tests the visibility for a multi selection menu
+   */
   @Test
   public void setMultiSeleciton() throws ProcessingException {
     Table t = new Table();
-    t.addRowsByMatrix(new Object[][]{
-        {"Boss", "Hugo"},
-        {"Meier", "Hans"}
-    });
+    t.addRowsByMatrix(TEST_ROWS);
     ITableContextMenu contextMenu = t.getContextMenu();
     // multi selection
     t.selectRows(CollectionUtility.arrayList(t.getRow(0), t.getRow(1)), false);
     IActionFilter filter = ActionUtility.createMenuFilterMenuTypes(contextMenu.getCurrentMenuTypes(), true);
     List<IMenu> visibleMenus = ActionUtility.normalizedActions(contextMenu.getChildActions(), filter);
-    Assert.assertEquals(1, visibleMenus.size());
-    Assert.assertEquals("MultiSelectionMenu", visibleMenus.get(0).getClass().getSimpleName());
+    assertEquals(1, visibleMenus.size());
+    assertEquals("MultiSelectionMenu", visibleMenus.get(0).getClass().getSimpleName());
 
   }
 
+  /**
+   * Tests the visibility for a empty space menu
+   */
   @Test
   public void testEmptySeleciton() throws ProcessingException {
     Table t = new Table();
-    t.addRowsByMatrix(new Object[][]{
-        {"Boss", "Hugo"},
-        {"Meier", "Hans"}
-    });
+    t.addRowsByMatrix(TEST_ROWS);
     ITableContextMenu contextMenu = t.getContextMenu();
     // empty selection
     t.selectRows(CollectionUtility.<ITableRow> emptyArrayList(), false);
     IActionFilter filter = ActionUtility.createMenuFilterMenuTypes(contextMenu.getCurrentMenuTypes(), true);
     List<IMenu> visibleMenus = ActionUtility.normalizedActions(contextMenu.getChildActions(), filter);
-    Assert.assertEquals(1, visibleMenus.size());
-    Assert.assertEquals("EmptySpaceMenu", visibleMenus.get(0).getClass().getSimpleName());
-
+    assertEquals(1, visibleMenus.size());
+    assertEquals("EmptySpaceMenu", visibleMenus.get(0).getClass().getSimpleName());
   }
 
+  /**
+   * Tests that {@link AbstractMenu#execOwnerValueChanged} is only called only multi-selection menus, if multiple rows
+   * are selected.
+   */
+  @Test
+  public void testOwnerValueOnMultiSelection() throws ProcessingException {
+    final ContextMenuTable table = createContextMenuTable();
+    addTestMenus(table);
+
+    table.selectAllRows();
+
+    assertOwnerValueChange(m_multi, 2);
+    assertOwnerValueChange(m_all, 2);
+    assertNoOwnerValueChange(m_single);
+    assertNoOwnerValueChange(m_emptySpace);
+    assertNoOwnerValueChange(m_combindedSingle);
+  }
+
+  /**
+   * Tests that {@link AbstractMenu#execOwnerValueChanged} is only called only single-selection menus, if the a single
+   * row is selected.
+   */
+  @Test
+  public void testOwnerValueOnSingleSelection() throws ProcessingException {
+    final ContextMenuTable table = createContextMenuTable();
+    addTestMenus(table);
+    table.selectFirstRow();
+
+    assertOwnerValueChange(m_single, 1);
+    assertOwnerValueChange(m_all, 1);
+    assertNoOwnerValueChange(m_multi);
+    assertNoOwnerValueChange(m_emptySpace);
+  }
+
+  /**
+   * Tests that {@link AbstractMenu#execOwnerValueChanged} is only called only empty space menus, if empty space is
+   * selected.
+   */
+  @Test
+  public void testOwnerValueOnEmptySpace() throws ProcessingException {
+    final ContextMenuTable table = createContextMenuTable();
+    table.selectAllRows();
+    addTestMenus(table);
+    table.deselectAllRows();
+
+    assertOwnerValueChange(m_emptySpace, 0);
+    assertOwnerValueChange(m_all, 0);
+    assertNoOwnerValueChange(m_multi);
+    assertNoOwnerValueChange(m_single);
+  }
+
+  /// HELPERS
+
+  private void addTestMenus(ITable table) {
+    table.addMenu(m_emptySpace);
+    table.addMenu(m_single);
+    table.addMenu(m_multi);
+    table.addMenu(m_all);
+    table.addMenu(m_combindedSingle);
+  }
+
+  private ContextMenuTable createContextMenuTable() throws ProcessingException {
+    final ContextMenuTable table = new ContextMenuTable();
+    table.addRowsByMatrix(TEST_ROWS);
+    return table;
+  }
+
+  private void assertOwnerValueChange(OwnerValueCapturingMenu menu, int rows) {
+    assertEquals(1, menu.getCount());
+    assertTrue("Owner should be a collection of 2 rows " + menu.getLastOwnerValue().getClass(), menu.getLastOwnerValue() instanceof Collection);
+    assertEquals(rows, ((Collection) menu.getLastOwnerValue()).size());
+  }
+
+  private void assertNoOwnerValueChange(OwnerValueCapturingMenu menu) {
+    assertEquals(0, menu.getCount());
+  }
+
+  /// FIXTURES
+
   public class Table extends AbstractTable {
     public NameColumn getNameColumn() {
       return getColumnSet().getColumnByClass(NameColumn.class);
@@ -156,4 +259,12 @@
       }
     }
   }
+
+  private static class ContextMenuTable extends AbstractTable {
+    @Override
+    public void setContextMenu(ITableContextMenu contextMenu) {
+      super.setContextMenu(contextMenu);
+    }
+  }
+
 }
diff --git a/org.eclipse.scout.rt.client.test/src/org/eclipse/scout/rt/client/ui/action/menu/TreeMenuTest.java b/org.eclipse.scout.rt.client.test/src/org/eclipse/scout/rt/client/ui/action/menu/TreeMenuTest.java
new file mode 100644
index 0000000..1101316
--- /dev/null
+++ b/org.eclipse.scout.rt.client.test/src/org/eclipse/scout/rt/client/ui/action/menu/TreeMenuTest.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Copyright (c) 2015 BSI Business Systems Integration AG.
+ * 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:
+ *     BSI Business Systems Integration AG - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.scout.rt.client.ui.action.menu;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.scout.commons.exception.ProcessingException;
+import org.eclipse.scout.rt.client.ui.action.menu.fixture.OwnerValueCapturingMenu;
+import org.eclipse.scout.rt.client.ui.action.menu.root.ITreeContextMenu;
+import org.eclipse.scout.rt.client.ui.action.menu.root.internal.TreeContextMenu;
+import org.eclipse.scout.rt.client.ui.basic.tree.AbstractTree;
+import org.eclipse.scout.rt.client.ui.basic.tree.AbstractTreeNode;
+import org.eclipse.scout.testing.client.runner.ScoutClientTestRunner;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link TreeContextMenu}
+ */
+@RunWith(ScoutClientTestRunner.class)
+public class TreeMenuTest {
+
+  private OwnerValueCapturingMenu m_multi;
+  private OwnerValueCapturingMenu m_single;
+  private OwnerValueCapturingMenu m_emptySpace;
+  private OwnerValueCapturingMenu m_singleEmpty;
+  private OwnerValueCapturingMenu m_all;
+
+  @Before
+  public void before() {
+    m_multi = new OwnerValueCapturingMenu(TreeMenuType.MultiSelection);
+    m_single = new OwnerValueCapturingMenu(TreeMenuType.SingleSelection);
+    m_emptySpace = new OwnerValueCapturingMenu(TreeMenuType.EmptySpace);
+    m_singleEmpty = new OwnerValueCapturingMenu(TreeMenuType.EmptySpace, TreeMenuType.SingleSelection);
+    m_all = new OwnerValueCapturingMenu(TreeMenuType.values());
+  }
+
+  /**
+   * Tests that {@link AbstractMenu#execOwnerValueChanged} is only called only single-selection menus, if a single node
+   * is selected.
+   */
+  @Test
+  public void testOwnerValueOnSingleSelection() throws ProcessingException {
+    final ContextMenuTree tree = createContextMenuTree();
+    addTestMenus(tree);
+    tree.selectFirstNode();
+
+    assertOwnerValueChange(m_single, 1);
+    assertOwnerValueChange(m_all, 1);
+    assertOwnerValueChange(m_singleEmpty, 1);
+    assertNoOwnerValueChange(m_multi);
+    assertNoOwnerValueChange(m_emptySpace);
+  }
+
+  /**
+   * Tests that {@link AbstractMenu#execOwnerValueChanged} is only called only multi-selection menus, if multiple nodes
+   * are selected.
+   */
+  @Test
+  public void testOwnerValueOnMultiSelection() throws ProcessingException {
+    final ContextMenuTree tree = createContextMenuTree();
+    addTestMenus(tree);
+    tree.setMultiSelect(true);
+    tree.selectNodes(tree.getRootNode().getChildNodes(), true);
+
+    assertOwnerValueChange(m_multi, 2);
+    assertOwnerValueChange(m_all, 2);
+    assertNoOwnerValueChange(m_singleEmpty);
+    assertNoOwnerValueChange(m_single);
+    assertNoOwnerValueChange(m_emptySpace);
+  }
+
+  /**
+   * Tests that {@link AbstractMenu#execOwnerValueChanged} is only called only empty space menus, if no nodes are
+   * selected.
+   */
+  @Test
+  public void testEmptySpaceSelection() throws ProcessingException {
+    final ContextMenuTree tree = createContextMenuTree();
+    tree.selectNode(tree.getRootNode());
+    addTestMenus(tree);
+    tree.deselectNode(tree.getRootNode());
+
+    assertOwnerValueChange(m_emptySpace, 0);
+    assertOwnerValueChange(m_all, 0);
+    assertOwnerValueChange(m_singleEmpty, 0);
+    assertNoOwnerValueChange(m_single);
+    assertNoOwnerValueChange(m_multi);
+  }
+
+  private void assertOwnerValueChange(OwnerValueCapturingMenu menu, int rows) {
+    assertEquals(1, menu.getCount());
+    assertTrue("Owner should be a collection of 2 rows " + menu.getLastOwnerValue().getClass(), menu.getLastOwnerValue() instanceof Collection);
+    assertEquals(rows, ((Collection) menu.getLastOwnerValue()).size());
+  }
+
+  private void assertNoOwnerValueChange(OwnerValueCapturingMenu menu) {
+    assertEquals(0, menu.getCount());
+  }
+
+  private void addTestMenus(ContextMenuTree tree) {
+    List<IMenu> menus = new ArrayList<IMenu>();
+    menus.add(m_emptySpace);
+    menus.add(m_single);
+    menus.add(m_multi);
+    menus.add(m_all);
+    menus.add(m_singleEmpty);
+    tree.setContextMenuInternal(new TreeContextMenu(tree, menus));
+  }
+
+  private ContextMenuTree createContextMenuTree() throws ProcessingException {
+    final ContextMenuTree tree = new ContextMenuTree();
+    tree.addChildNode(tree.getRootNode(), new AbstractTreeNode() {
+    });
+    tree.addChildNode(tree.getRootNode(), new AbstractTreeNode() {
+    });
+    tree.getRootNode().setExpanded(true);
+    return tree;
+  }
+
+  private static class ContextMenuTree extends AbstractTree {
+
+    @Override
+    public void setContextMenuInternal(ITreeContextMenu contextMenu) {
+      super.setContextMenuInternal(contextMenu);
+    }
+  }
+
+}
diff --git a/org.eclipse.scout.rt.client.test/src/org/eclipse/scout/rt/client/ui/action/menu/fixture/OwnerValueCapturingMenu.java b/org.eclipse.scout.rt.client.test/src/org/eclipse/scout/rt/client/ui/action/menu/fixture/OwnerValueCapturingMenu.java
new file mode 100644
index 0000000..08e3c0f
--- /dev/null
+++ b/org.eclipse.scout.rt.client.test/src/org/eclipse/scout/rt/client/ui/action/menu/fixture/OwnerValueCapturingMenu.java
@@ -0,0 +1,35 @@
+package org.eclipse.scout.rt.client.ui.action.menu.fixture;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.scout.commons.exception.ProcessingException;
+import org.eclipse.scout.rt.client.ui.action.menu.AbstractMenu;
+import org.eclipse.scout.rt.client.ui.action.menu.IMenuType;
+
+public class OwnerValueCapturingMenu extends AbstractMenu {
+  private int m_count = 0;
+  private Object m_lastOwnerValue;
+
+  public OwnerValueCapturingMenu(IMenuType... types) {
+    final Set<IMenuType> s = new HashSet<IMenuType>();
+    for (IMenuType t : types) {
+      s.add(t);
+    }
+    setMenuTypes(s);
+  }
+
+  @Override
+  protected void execOwnerValueChanged(Object ownerValue) throws ProcessingException {
+    m_count++;
+    m_lastOwnerValue = ownerValue;
+  }
+
+  public int getCount() {
+    return m_count;
+  }
+
+  public Object getLastOwnerValue() {
+    return m_lastOwnerValue;
+  }
+}
diff --git a/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/AbstractMenu.java b/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/AbstractMenu.java
index 3ca0164..9ffd0fb 100644
--- a/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/AbstractMenu.java
+++ b/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/AbstractMenu.java
@@ -92,6 +92,13 @@
    * This method is only called for menus without submenus (leafs) on a {@link ITable}, {@link ITree},
    * {@link IValueField}! For all other fields
    * this method will NEVER be called.</b> <br>
+   * The method is only called, if the the current owner value matches the menu type.
+   * If the menu is not visible due to it's type, execOwnerValueChanged is not called: E.g.
+   * <ul>
+   * <li>Menu with type SingleSelection: only called, if the selection is a single selection
+   * <li>Menu with type MultiSelection: only called, if the selection is a multi selection
+   * <li>Menu with type EmptySpace: only called, if the selection is a on empty space
+   * </ul>
    *
    * @param newOwnerValue
    *          depending on the owner the newOwnerValue differs.
diff --git a/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/ActivityMapContextMenu.java b/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/ActivityMapContextMenu.java
index 02b7757..701e3f1 100644
--- a/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/ActivityMapContextMenu.java
+++ b/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/ActivityMapContextMenu.java
@@ -14,28 +14,17 @@
 import java.util.List;
 
 import org.eclipse.scout.commons.CompositeObject;
-import org.eclipse.scout.commons.exception.ProcessingException;
-import org.eclipse.scout.commons.logger.IScoutLogger;
-import org.eclipse.scout.commons.logger.ScoutLogManager;
-import org.eclipse.scout.rt.client.ui.action.IAction;
-import org.eclipse.scout.rt.client.ui.action.IActionVisitor;
 import org.eclipse.scout.rt.client.ui.action.menu.IMenu;
 import org.eclipse.scout.rt.client.ui.action.menu.MenuUtility;
 import org.eclipse.scout.rt.client.ui.action.menu.root.AbstractPropertyObserverContextMenu;
 import org.eclipse.scout.rt.client.ui.action.menu.root.IActivityMapContextMenu;
 import org.eclipse.scout.rt.client.ui.basic.activitymap.IActivityMap;
-import org.eclipse.scout.rt.shared.services.common.exceptionhandler.IExceptionHandlerService;
-import org.eclipse.scout.service.SERVICES;
 
 /**
  * The invisible root menu node of any activity map. (internal usage only)
  */
 public class ActivityMapContextMenu extends AbstractPropertyObserverContextMenu<IActivityMap<?, ?>> implements IActivityMapContextMenu {
-  private static final IScoutLogger LOG = ScoutLogManager.getLogger(ActivityMapContextMenu.class);
 
-  /**
-   * @param owner
-   */
   public ActivityMapContextMenu(IActivityMap<?, ?> owner, List<? extends IMenu> initialChildMenus) {
     super(owner, initialChildMenus);
   }
@@ -56,24 +45,8 @@
   protected void handleOwnerValueChanged() {
     if (getOwner() != null) {
       final CompositeObject ownerValue = new CompositeObject(getOwner().getSelectedActivityCell(), getOwner().getSelectedResourceIds(), getOwner().getSelectedBeginTime(), getOwner().getSelectedEndTime());
-      acceptVisitor(new IActionVisitor() {
-        @Override
-        public int visit(IAction action) {
-          if (action instanceof IMenu) {
-            IMenu menu = (IMenu) action;
-            try {
-              menu.handleOwnerValueChanged(ownerValue);
-            }
-            catch (ProcessingException ex) {
-              SERVICES.getService(IExceptionHandlerService.class).handleException(ex);
-            }
-          }
-          return CONTINUE;
-        }
-      });
-      // set active filter
       setCurrentMenuTypes(MenuUtility.getMenuTypesForActivityMapSelection(getOwner().getSelectedActivityCell()));
-
+      acceptVisitor(new MenuOwnerChangedVisitor(ownerValue, getCurrentMenuTypes()));
       calculateLocalVisibility();
     }
   }
diff --git a/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/CalendarContextMenu.java b/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/CalendarContextMenu.java
index eacae9b..753de08 100644
--- a/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/CalendarContextMenu.java
+++ b/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/CalendarContextMenu.java
@@ -13,26 +13,17 @@
 import java.beans.PropertyChangeEvent;
 import java.util.List;
 
-import org.eclipse.scout.commons.exception.ProcessingException;
-import org.eclipse.scout.commons.logger.IScoutLogger;
-import org.eclipse.scout.commons.logger.ScoutLogManager;
-import org.eclipse.scout.rt.client.ui.action.IAction;
-import org.eclipse.scout.rt.client.ui.action.IActionVisitor;
 import org.eclipse.scout.rt.client.ui.action.menu.IMenu;
 import org.eclipse.scout.rt.client.ui.action.menu.MenuUtility;
 import org.eclipse.scout.rt.client.ui.action.menu.root.AbstractPropertyObserverContextMenu;
 import org.eclipse.scout.rt.client.ui.action.menu.root.ICalendarContextMenu;
 import org.eclipse.scout.rt.client.ui.basic.calendar.CalendarComponent;
 import org.eclipse.scout.rt.client.ui.basic.calendar.ICalendar;
-import org.eclipse.scout.rt.shared.services.common.exceptionhandler.IExceptionHandlerService;
-import org.eclipse.scout.service.SERVICES;
 
 /**
  * The invisible root menu node of any calendar. (internal usage only)
  */
 public class CalendarContextMenu extends AbstractPropertyObserverContextMenu<ICalendar> implements ICalendarContextMenu {
-  private static final IScoutLogger LOG = ScoutLogManager.getLogger(CalendarContextMenu.class);
-
   /**
    * @param owner
    */
@@ -54,28 +45,13 @@
   }
 
   /**
-  *
-  */
+   *
+   */
   protected void handleOwnerValueChanged() {
     if (getOwner() != null) {
       final CalendarComponent ownerValue = getOwner().getSelectedComponent();
-      acceptVisitor(new IActionVisitor() {
-        @Override
-        public int visit(IAction action) {
-          if (action instanceof IMenu) {
-            IMenu menu = (IMenu) action;
-            try {
-              menu.handleOwnerValueChanged(ownerValue);
-            }
-            catch (ProcessingException ex) {
-              SERVICES.getService(IExceptionHandlerService.class).handleException(ex);
-            }
-          }
-          return CONTINUE;
-        }
-      });
-      // set active filter
       setCurrentMenuTypes(MenuUtility.getMenuTypesForCalendarSelection(ownerValue));
+      acceptVisitor(new MenuOwnerChangedVisitor(ownerValue, getCurrentMenuTypes()));
       calculateLocalVisibility();
     }
   }
diff --git a/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/MenuOwnerChangedVisitor.java b/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/MenuOwnerChangedVisitor.java
new file mode 100644
index 0000000..5456f21
--- /dev/null
+++ b/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/MenuOwnerChangedVisitor.java
@@ -0,0 +1,46 @@
+package org.eclipse.scout.rt.client.ui.action.menu.root.internal;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.eclipse.scout.commons.exception.ProcessingException;
+import org.eclipse.scout.commons.logger.IScoutLogger;
+import org.eclipse.scout.commons.logger.ScoutLogManager;
+import org.eclipse.scout.rt.client.ui.action.IAction;
+import org.eclipse.scout.rt.client.ui.action.IActionVisitor;
+import org.eclipse.scout.rt.client.ui.action.menu.IMenu;
+import org.eclipse.scout.rt.client.ui.action.menu.IMenuType;
+import org.eclipse.scout.rt.shared.services.common.exceptionhandler.IExceptionHandlerService;
+import org.eclipse.scout.service.SERVICES;
+
+/**
+ * Visitor calling {@link IMenu#handleOwnerValueChanged(Object)} on menus, if the menu type allows it.
+ */
+public class MenuOwnerChangedVisitor implements IActionVisitor {
+  private static final IScoutLogger LOG = ScoutLogManager.getLogger(MenuOwnerChangedVisitor.class);
+  private final Object m_ownerValue;
+  private final Set<? extends IMenuType> m_menuTypes;
+
+  public MenuOwnerChangedVisitor(Object ownerValue, Set<? extends IMenuType> menuTypes) {
+    m_ownerValue = ownerValue;
+    m_menuTypes = menuTypes;
+  }
+
+  @Override
+  public int visit(IAction action) {
+    if (action instanceof IMenu && !Collections.disjoint(((IMenu) action).getMenuTypes(), m_menuTypes)) {
+      IMenu menu = (IMenu) action;
+      try {
+        menu.handleOwnerValueChanged(m_ownerValue);
+      }
+      catch (ProcessingException ex) {
+        SERVICES.getService(IExceptionHandlerService.class).handleException(ex);
+      }
+      catch (Exception ex) {
+        LOG.error("Error handling handleOwnerValueChanged in " + menu.getClass().getName(), ex);
+      }
+    }
+    return CONTINUE;
+  }
+
+}
diff --git a/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/TableContextMenu.java b/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/TableContextMenu.java
index 080fa42..80ec584 100644
--- a/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/TableContextMenu.java
+++ b/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/TableContextMenu.java
@@ -15,9 +15,6 @@
 import java.util.List;
 
 import org.eclipse.scout.commons.CollectionUtility;
-import org.eclipse.scout.commons.exception.ProcessingException;
-import org.eclipse.scout.commons.logger.IScoutLogger;
-import org.eclipse.scout.commons.logger.ScoutLogManager;
 import org.eclipse.scout.rt.client.ui.action.IAction;
 import org.eclipse.scout.rt.client.ui.action.IActionVisitor;
 import org.eclipse.scout.rt.client.ui.action.menu.IMenu;
@@ -28,15 +25,11 @@
 import org.eclipse.scout.rt.client.ui.basic.table.ITableRow;
 import org.eclipse.scout.rt.client.ui.basic.table.TableAdapter;
 import org.eclipse.scout.rt.client.ui.basic.table.TableEvent;
-import org.eclipse.scout.rt.shared.services.common.exceptionhandler.IExceptionHandlerService;
-import org.eclipse.scout.service.SERVICES;
 
 /**
  * The invisible root menu node of any table. (internal usage only)
  */
 public class TableContextMenu extends AbstractPropertyObserverContextMenu<ITable> implements ITableContextMenu {
-  private static final IScoutLogger LOG = ScoutLogManager.getLogger(TableContextMenu.class);
-
   private List<? extends ITableRow> m_currentSelection;
 
   /**
@@ -98,23 +91,8 @@
     if (getOwner() != null) {
       final List<ITableRow> ownerValue = getOwner().getSelectedRows();
       m_currentSelection = CollectionUtility.arrayList(ownerValue);
-      acceptVisitor(new IActionVisitor() {
-        @Override
-        public int visit(IAction action) {
-          if (action instanceof IMenu) {
-            IMenu menu = (IMenu) action;
-            try {
-              menu.handleOwnerValueChanged(ownerValue);
-            }
-            catch (ProcessingException ex) {
-              SERVICES.getService(IExceptionHandlerService.class).handleException(ex);
-            }
-          }
-          return CONTINUE;
-        }
-      });
-      // set current menu types
       setCurrentMenuTypes(MenuUtility.getMenuTypesForTableSelection(ownerValue));
+      acceptVisitor(new MenuOwnerChangedVisitor(ownerValue, getCurrentMenuTypes()));
       calculateLocalVisibility();
       calculateEnableState(ownerValue);
     }
diff --git a/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/TreeContextMenu.java b/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/TreeContextMenu.java
index 0cf676e..c30980c 100644
--- a/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/TreeContextMenu.java
+++ b/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/TreeContextMenu.java
@@ -16,9 +16,6 @@
 import java.util.Set;
 
 import org.eclipse.scout.commons.CollectionUtility;
-import org.eclipse.scout.commons.exception.ProcessingException;
-import org.eclipse.scout.commons.logger.IScoutLogger;
-import org.eclipse.scout.commons.logger.ScoutLogManager;
 import org.eclipse.scout.rt.client.ui.action.IAction;
 import org.eclipse.scout.rt.client.ui.action.IActionVisitor;
 import org.eclipse.scout.rt.client.ui.action.menu.IMenu;
@@ -30,15 +27,11 @@
 import org.eclipse.scout.rt.client.ui.basic.tree.ITreeNode;
 import org.eclipse.scout.rt.client.ui.basic.tree.TreeAdapter;
 import org.eclipse.scout.rt.client.ui.basic.tree.TreeEvent;
-import org.eclipse.scout.rt.shared.services.common.exceptionhandler.IExceptionHandlerService;
-import org.eclipse.scout.service.SERVICES;
 
 /**
  *
  */
 public class TreeContextMenu extends AbstractPropertyObserverContextMenu<ITree> implements ITreeContextMenu {
-  private static final IScoutLogger LOG = ScoutLogManager.getLogger(TreeContextMenu.class);
-
   private Set<? extends ITreeNode> m_currentSelection;
 
   /**
@@ -99,23 +92,9 @@
     if (getOwner() != null) {
       final Set<ITreeNode> ownerSelection = getOwner().getSelectedNodes();
       m_currentSelection = CollectionUtility.hashSet(ownerSelection);
-      acceptVisitor(new IActionVisitor() {
-        @Override
-        public int visit(IAction action) {
-          if (action instanceof IMenu) {
-            IMenu menu = (IMenu) action;
-            try {
-              menu.handleOwnerValueChanged(ownerSelection);
-            }
-            catch (ProcessingException ex) {
-              SERVICES.getService(IExceptionHandlerService.class).handleException(ex);
-            }
-          }
-          return CONTINUE;
-        }
-      });
-      // update menu types
       setCurrentMenuTypes(MenuUtility.getMenuTypesForTreeSelection(ownerSelection));
+      acceptVisitor(new MenuOwnerChangedVisitor(ownerSelection, getCurrentMenuTypes()));
+      // update menu types
       calculateLocalVisibility();
       calculateEnableState(ownerSelection);
     }
diff --git a/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/ValueFieldContextMenu.java b/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/ValueFieldContextMenu.java
index 689dd35..8146e3e 100644
--- a/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/ValueFieldContextMenu.java
+++ b/org.eclipse.scout.rt.client/src/org/eclipse/scout/rt/client/ui/action/menu/root/internal/ValueFieldContextMenu.java
@@ -14,15 +14,10 @@
 import java.util.Collection;
 import java.util.List;
 
-import org.eclipse.scout.commons.exception.ProcessingException;
-import org.eclipse.scout.rt.client.ui.action.IAction;
-import org.eclipse.scout.rt.client.ui.action.IActionVisitor;
 import org.eclipse.scout.rt.client.ui.action.menu.IMenu;
 import org.eclipse.scout.rt.client.ui.action.menu.MenuUtility;
 import org.eclipse.scout.rt.client.ui.action.menu.root.IValueFieldContextMenu;
 import org.eclipse.scout.rt.client.ui.form.fields.IValueField;
-import org.eclipse.scout.rt.shared.services.common.exceptionhandler.IExceptionHandlerService;
-import org.eclipse.scout.service.SERVICES;
 
 /**
  *
@@ -64,23 +59,8 @@
   protected void handleOwnerValueChanged() {
     if (getOwner() != null) {
       final Object ownerValue = getOwner().getValue();
-      acceptVisitor(new IActionVisitor() {
-        @Override
-        public int visit(IAction action) {
-          if (action instanceof IMenu) {
-            IMenu menu = (IMenu) action;
-            try {
-              menu.handleOwnerValueChanged(ownerValue);
-            }
-            catch (ProcessingException ex) {
-              SERVICES.getService(IExceptionHandlerService.class).handleException(ex);
-            }
-          }
-          return CONTINUE;
-        }
-      });
-      // set active filter
       setCurrentMenuTypes(MenuUtility.getMenuTypesForValueFieldValue(ownerValue));
+      acceptVisitor(new MenuOwnerChangedVisitor(ownerValue, getCurrentMenuTypes()));
     }
     calculateLocalVisibility();
   }