You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2017/12/20 08:50:00 UTC
svn commit: r1818750 - in /jmeter/trunk/src/core/org/apache/jmeter:
control/gui/ gui/ gui/util/ testbeans/gui/ threads/ threads/gui/
Author: pmouawad
Date: Wed Dec 20 08:50:00 2017
New Revision: 1818750
URL: http://svn.apache.org/viewvc?rev=1818750&view=rev
Log:
Bug 61919 - UX : Reorder Menus
Contributed by Graham Russell
Reordered menus (1/3)
This comment #360
Bugzilla Id: 61919
Added:
jmeter/trunk/src/core/org/apache/jmeter/gui/GUIMenuSortOrder.java (with props)
jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuSeparatorInfo.java (with props)
Modified:
jmeter/trunk/src/core/org/apache/jmeter/control/gui/TestPlanGui.java
jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuFactory.java
jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuInfo.java
jmeter/trunk/src/core/org/apache/jmeter/testbeans/gui/TestBeanGUI.java
jmeter/trunk/src/core/org/apache/jmeter/threads/ThreadGroup.java
jmeter/trunk/src/core/org/apache/jmeter/threads/gui/AbstractThreadGroupGui.java
Modified: jmeter/trunk/src/core/org/apache/jmeter/control/gui/TestPlanGui.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/control/gui/TestPlanGui.java?rev=1818750&r1=1818749&r2=1818750&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/control/gui/TestPlanGui.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/control/gui/TestPlanGui.java Wed Dec 20 08:50:00 2017
@@ -41,7 +41,6 @@ import org.apache.jmeter.util.JMeterUtil
/**
* JMeter GUI component representing the test plan which will be executed when
* the test is run.
- *
*/
public class TestPlanGui extends AbstractJMeterGuiComponent {
@@ -91,14 +90,18 @@ public class TestPlanGui extends Abstrac
JPopupMenu pop = new JPopupMenu();
JMenu addMenu = new JMenu(JMeterUtils.getResString("add")); // $NON-NLS-1$
addMenu.add(MenuFactory.makeMenu(MenuFactory.THREADS, ActionNames.ADD));
- addMenu.add(MenuFactory.makeMenu(MenuFactory.FRAGMENTS, ActionNames.ADD));
- addMenu.add(MenuFactory.makeMenu(MenuFactory.NON_TEST_ELEMENTS, ActionNames.ADD));
+ addMenu.addSeparator();
addMenu.add(MenuFactory.makeMenu(MenuFactory.CONFIG_ELEMENTS, ActionNames.ADD));
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.LISTENERS, ActionNames.ADD));
+ addMenu.addSeparator();
addMenu.add(MenuFactory.makeMenu(MenuFactory.TIMERS, ActionNames.ADD));
+ addMenu.addSeparator();
addMenu.add(MenuFactory.makeMenu(MenuFactory.PRE_PROCESSORS, ActionNames.ADD));
addMenu.add(MenuFactory.makeMenu(MenuFactory.POST_PROCESSORS, ActionNames.ADD));
addMenu.add(MenuFactory.makeMenu(MenuFactory.ASSERTIONS, ActionNames.ADD));
- addMenu.add(MenuFactory.makeMenu(MenuFactory.LISTENERS, ActionNames.ADD));
+ addMenu.addSeparator();
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.FRAGMENTS, ActionNames.ADD));
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.NON_TEST_ELEMENTS, ActionNames.ADD));
pop.add(addMenu);
MenuFactory.addPasteResetMenu(pop);
MenuFactory.addFileMenu(pop, false);
Added: jmeter/trunk/src/core/org/apache/jmeter/gui/GUIMenuSortOrder.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/GUIMenuSortOrder.java?rev=1818750&view=auto
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/GUIMenuSortOrder.java (added)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/GUIMenuSortOrder.java Wed Dec 20 08:50:00 2017
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jmeter.gui;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to allow specific ordering of this item in the GUI Menu
+ * @since 4.0
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface GUIMenuSortOrder {
+ int value() default Integer.MAX_VALUE;
+}
Propchange: jmeter/trunk/src/core/org/apache/jmeter/gui/GUIMenuSortOrder.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/src/core/org/apache/jmeter/gui/GUIMenuSortOrder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuFactory.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuFactory.java?rev=1818750&r1=1818749&r2=1818750&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuFactory.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuFactory.java Wed Dec 20 08:50:00 2017
@@ -21,17 +21,15 @@ package org.apache.jmeter.gui.util;
import java.awt.Component;
import java.awt.HeadlessException;
import java.io.IOException;
-import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
-import java.util.Map.Entry;
+import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@@ -40,6 +38,7 @@ import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;
import javax.swing.MenuElement;
+import javax.swing.tree.DefaultMutableTreeNode;
import org.apache.jmeter.control.Controller;
import org.apache.jmeter.control.TestFragmentController;
@@ -61,7 +60,6 @@ import org.apache.jmeter.util.JMeterUtil
import org.apache.jmeter.visualizers.Printable;
import org.apache.jorphan.gui.GuiUtils;
import org.apache.jorphan.reflect.ClassFinder;
-import org.apache.jorphan.util.JOrphanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -70,112 +68,144 @@ public final class MenuFactory {
/*
* Predefined strings for makeMenu().
- * These are used as menu categories in the menuMap Hashmap,
+ * These are used as menu categories in the menuMap HashMap,
* and also for resource lookup in messages.properties
+ * TODO: why isn't this an enum?
*/
public static final String THREADS = "menu_threads"; //$NON-NLS-1$
-
public static final String FRAGMENTS = "menu_fragments"; //$NON-NLS-1$
-
public static final String TIMERS = "menu_timer"; //$NON-NLS-1$
-
public static final String CONTROLLERS = "menu_logic_controller"; //$NON-NLS-1$
-
public static final String SAMPLERS = "menu_generative_controller"; //$NON-NLS-1$
-
public static final String CONFIG_ELEMENTS = "menu_config_element"; //$NON-NLS-1$
-
public static final String POST_PROCESSORS = "menu_post_processors"; //$NON-NLS-1$
-
public static final String PRE_PROCESSORS = "menu_pre_processors"; //$NON-NLS-1$
-
public static final String ASSERTIONS = "menu_assertions"; //$NON-NLS-1$
-
public static final String NON_TEST_ELEMENTS = "menu_non_test_elements"; //$NON-NLS-1$
-
public static final String LISTENERS = "menu_listener"; //$NON-NLS-1$
+ public static final String SEPARATOR = "menu_separator"; //$NON-NLS-1$
- private static final Map<String, List<MenuInfo>> menuMap = new HashMap<>();
+ private static final Map<String, List<MenuInfo>> menuMap;
- private static final Set<String> elementsToSkip = new HashSet<>();
+ static {
+ menuMap = new HashMap<>();
+ menuMap.put(THREADS, new LinkedList<>());
+ menuMap.put(TIMERS, new LinkedList<>());
+ menuMap.put(ASSERTIONS, new LinkedList<>());
+ menuMap.put(CONFIG_ELEMENTS, new LinkedList<>());
+ menuMap.put(CONTROLLERS, new LinkedList<>());
+ menuMap.put(LISTENERS, new LinkedList<>());
+ menuMap.put(NON_TEST_ELEMENTS, new LinkedList<>());
+ menuMap.put(SAMPLERS, new LinkedList<>());
+ menuMap.put(POST_PROCESSORS, new LinkedList<>());
+ menuMap.put(PRE_PROCESSORS, new LinkedList<>());
+ menuMap.put(FRAGMENTS, new LinkedList<>());
+ menuMap.put(SEPARATOR, Collections.singletonList(new MenuSeparatorInfo()));
- // MENU_ADD_xxx - controls which items are in the ADD menu
- // MENU_PARENT_xxx - controls which items are in the Insert Parent menu
- private static final String[] MENU_ADD_CONTROLLER = new String[] {
- MenuFactory.CONTROLLERS,
- MenuFactory.CONFIG_ELEMENTS,
- MenuFactory.TIMERS,
- MenuFactory.PRE_PROCESSORS,
- MenuFactory.SAMPLERS,
- MenuFactory.POST_PROCESSORS,
- MenuFactory.ASSERTIONS,
- MenuFactory.LISTENERS,
- };
-
- private static final String[] MENU_PARENT_CONTROLLER = new String[] {
- MenuFactory.CONTROLLERS };
-
- private static final String[] MENU_ADD_SAMPLER = new String[] {
- MenuFactory.CONFIG_ELEMENTS,
- MenuFactory.TIMERS,
- MenuFactory.PRE_PROCESSORS,
- MenuFactory.POST_PROCESSORS,
- MenuFactory.ASSERTIONS,
- MenuFactory.LISTENERS,
- };
-
- private static final String[] MENU_PARENT_SAMPLER = new String[] {
- MenuFactory.CONTROLLERS };
-
- private static final List<MenuInfo> timers;
- private static final List<MenuInfo> controllers;
- private static final List<MenuInfo> samplers;
- private static final List<MenuInfo> threads;
- private static final List<MenuInfo> fragments;
- private static final List<MenuInfo> configElements;
- private static final List<MenuInfo> assertions;
- private static final List<MenuInfo> listeners;
- private static final List<MenuInfo> nonTestElements;
- private static final List<MenuInfo> postProcessors;
- private static final List<MenuInfo> preProcessors;
+ try {
+ initializeMenus(menuMap, classesToSkip());
+ sortMenus(menuMap.values());
+ separateItemsWithExplicitOrder(menuMap.values());
+ } catch (Error | RuntimeException ex) { // NOSONAR We want to log Errors in jmeter.log
+ log.error("Error initializing menus, check configuration if using 3rd party libraries", ex);
+ throw ex;
+ } catch (Exception ex) {
+ log.error("Error initializing menus, check configuration if using 3rd party libraries", ex);
+ }
+ }
- static {
- threads = new LinkedList<>();
- fragments = new LinkedList<>();
- timers = new LinkedList<>();
- controllers = new LinkedList<>();
- samplers = new LinkedList<>();
- configElements = new LinkedList<>();
- assertions = new LinkedList<>();
- listeners = new LinkedList<>();
- postProcessors = new LinkedList<>();
- preProcessors = new LinkedList<>();
- nonTestElements = new LinkedList<>();
- menuMap.put(THREADS, threads);
- menuMap.put(FRAGMENTS, fragments);
- menuMap.put(TIMERS, timers);
- menuMap.put(ASSERTIONS, assertions);
- menuMap.put(CONFIG_ELEMENTS, configElements);
- menuMap.put(CONTROLLERS, controllers);
- menuMap.put(LISTENERS, listeners);
- menuMap.put(NON_TEST_ELEMENTS, nonTestElements);
- menuMap.put(SAMPLERS, samplers);
- menuMap.put(POST_PROCESSORS, postProcessors);
- menuMap.put(PRE_PROCESSORS, preProcessors);
+ private static Set<String> classesToSkip() {
+ return Arrays.stream(JMeterUtils.getPropDefault("not_in_menu", "").split(","))
+ .map(String::trim)
+ .collect(Collectors.toSet());
+ }
+
+ private static void initializeMenus(
+ Map<String, List<MenuInfo>> menus, Set<String> elementsToSkip) {
try {
- String[] classesToSkip =
- JOrphanUtils.split(JMeterUtils.getPropDefault("not_in_menu", ""), ","); //$NON-NLS-1$
- for (String aClassesToSkip : classesToSkip) {
- elementsToSkip.add(aClassesToSkip.trim());
+ List<String> guiClasses = ClassFinder
+ .findClassesThatExtend(
+ JMeterUtils.getSearchPaths(),
+ new Class[] {JMeterGUIComponent.class, TestBean.class})
+ .stream()
+ // JMeterTreeNode and TestBeanGUI are special GUI classes,
+ // and aren't intended to be added to menus
+ .filter(name -> !name.endsWith("JMeterTreeNode"))
+ .filter(name -> !name.endsWith("TestBeanGUI"))
+ .filter(name -> !elementsToSkip.contains(name))
+ .distinct()
+ .map(String::trim)
+ .collect(Collectors.toList());
+
+ for (String className : guiClasses) {
+ JMeterGUIComponent item = getGUIComponent(className, elementsToSkip);
+ if (item == null) {
+ continue;
+ }
+
+ Collection<String> categories = item.getMenuCategories();
+ if (categories == null) {
+ log.debug("{} participates in no menus.", className);
+ continue;
+ }
+ for (String key: menus.keySet()) {
+ if (categories.contains(key)) {
+ menus.get(key).add(new MenuInfo(item, className));
+ }
+ }
}
+ } catch (IOException e) {
+ log.error("IO Exception while initializing menus.", e);
+ }
+ }
- initializeMenus();
- sortPluginMenus();
- } catch (Error | RuntimeException ex) { // NOSONAR We want to log Errors in jmeter.log
- log.error("Error initializing menus in static bloc, check configuration if using 3rd party libraries", ex);
- throw ex;
- } catch (Exception ex) {
- log.error("Error initializing menus in static bloc, check configuration if using 3rd party libraries", ex);
+ private static JMeterGUIComponent getGUIComponent(
+ String name, Set<String> elementsToSkip) {
+ JMeterGUIComponent item = null;
+ boolean hideBean = false; // Should the TestBean be hidden?
+ try {
+ Class<?> c = Class.forName(name);
+ if (TestBean.class.isAssignableFrom(c)) {
+ TestBeanGUI testBeanGUI = new TestBeanGUI(c);
+ hideBean = testBeanGUI.isHidden()
+ || (testBeanGUI.isExpert() && !JMeterUtils.isExpertMode());
+ item = testBeanGUI;
+ } else {
+ item = (JMeterGUIComponent) c.newInstance();
+ }
+ } catch (NoClassDefFoundError e) {
+ log.warn("Configuration error, probably corrupt or missing third party library(jar)? Could not create class: {}.",
+ name, e);
+ } catch (HeadlessException e) {
+ log.warn("Could not instantiate class: {}", name, e);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ log.warn("Could not instantiate class: {}", name, e);
+ }
+ if (hideBean || (item != null && elementsToSkip.contains(item.getStaticLabel()))) {
+ log.info("Skipping {}", name);
+ item = null;
+ }
+ return item;
+ }
+
+ private static void sortMenus(Collection<List<MenuInfo>> menus) {
+ for (List<MenuInfo> menu : menus) {
+ menu.sort(Comparator.comparing(MenuInfo::getLabel));
+ menu.sort(Comparator.comparingInt(MenuInfo::getSortOrder));
+ }
+ }
+
+ private static void separateItemsWithExplicitOrder(Collection<List<MenuInfo>> menus) {
+ for (List<MenuInfo> menu : menus) {
+ Optional<MenuInfo> firstDefaultSortItem = menu.stream()
+ .filter(info -> info.getSortOrder() == MenuInfo.SORT_ORDER_DEFAULT)
+ .findFirst();
+ int index = menu.indexOf(firstDefaultSortItem.orElseThrow(IllegalStateException::new));
+ if (index > 0) {
+ menu.add(index, new MenuSeparatorInfo());
+ }
}
}
@@ -222,7 +252,8 @@ public final class MenuFactory {
menu.add(makeMenuItemRes("menu_merge", ActionNames.MERGE));// $NON-NLS-1$
menu.add(makeMenuItemRes("save_as", ActionNames.SAVE_AS));// $NON-NLS-1$
if(addSaveTestFragmentMenu) {
- menu.add(makeMenuItemRes("save_as_test_fragment", ActionNames.SAVE_AS_TEST_FRAGMENT));// $NON-NLS-1$
+ menu.add(makeMenuItemRes("save_as_test_fragment", // $NON-NLS-1$
+ ActionNames.SAVE_AS_TEST_FRAGMENT));
}
addSeparator(menu);
JMenuItem savePicture = makeMenuItemRes("save_as_image",// $NON-NLS-1$
@@ -254,7 +285,8 @@ public final class MenuFactory {
}
/**
- * Add undo / redo
+ * Add undo / redo to the provided menu
+ *
* @param menu JPopupMenu
*/
private static void addUndoItems(JPopupMenu menu) {
@@ -265,7 +297,8 @@ public final class MenuFactory {
menu.add(undo);
JMenuItem redo = makeMenuItemRes("redo", ActionNames.REDO); //$NON-NLS-1$
- // TODO: we could even show some hints on action being undone here if this will be required (by passing those hints into history records)
+ // TODO: we could even show some hints on action being undone here
+ // if required (by passing those hints into history records)
redo.setEnabled(GuiPackage.getInstance().canRedo());
menu.add(redo);
}
@@ -273,29 +306,27 @@ public final class MenuFactory {
public static JMenu makeMenus(String[] categories, String label, String actionCommand) {
JMenu addMenu = new JMenu(label);
- for (String category : categories) {
- addMenu.add(makeMenu(category, actionCommand));
- }
+ Arrays.stream(categories)
+ .map(category -> makeMenu(category, actionCommand))
+ .forEach(addMenu::add);
GuiUtils.makeScrollableMenu(addMenu);
return addMenu;
}
public static JPopupMenu getDefaultControllerMenu() {
JPopupMenu pop = new JPopupMenu();
- pop.add(MenuFactory.makeMenus(MENU_ADD_CONTROLLER,
- JMeterUtils.getResString("add"),// $NON-NLS-1$
- ActionNames.ADD));
+ pop.add(createDefaultAddMenu());
pop.add(MenuFactory.makeMenuItemRes("add_think_times",// $NON-NLS-1$
ActionNames.ADD_THINK_TIME_BETWEEN_EACH_STEP));
pop.add(MenuFactory.makeMenuItemRes("apply_naming",// $NON-NLS-1$
ActionNames.APPLY_NAMING_CONVENTION));
- pop.add(makeMenus(MENU_PARENT_CONTROLLER,
+ pop.add(makeMenus(new String[]{CONTROLLERS},
JMeterUtils.getResString("change_parent"),// $NON-NLS-1$
ActionNames.CHANGE_PARENT));
- pop.add(makeMenus(MENU_PARENT_CONTROLLER,
+ pop.add(makeMenus(new String[]{CONTROLLERS},
JMeterUtils.getResString("insert_parent"),// $NON-NLS-1$
ActionNames.ADD_PARENT));
MenuFactory.addEditMenu(pop, true);
@@ -303,12 +334,25 @@ public final class MenuFactory {
return pop;
}
+ private static JMenu createDefaultAddMenu() {
+ String addAction = ActionNames.ADD;
+ JMenu addMenu = new JMenu(JMeterUtils.getResString("add")); // $NON-NLS-1$
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.ASSERTIONS, addAction));
+ addMenu.addSeparator();
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.TIMERS, addAction));
+ addMenu.addSeparator();
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.PRE_PROCESSORS, addAction));
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.POST_PROCESSORS, addAction));
+ addMenu.addSeparator();
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.CONFIG_ELEMENTS, addAction));
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.LISTENERS, addAction));
+ return addMenu;
+ }
+
public static JPopupMenu getDefaultSamplerMenu() {
JPopupMenu pop = new JPopupMenu();
- pop.add(MenuFactory.makeMenus(MENU_ADD_SAMPLER,
- JMeterUtils.getResString("add"),// $NON-NLS-1$
- ActionNames.ADD));
- pop.add(makeMenus(MENU_PARENT_SAMPLER,
+ pop.add(createDefaultAddMenu());
+ pop.add(makeMenus(new String[]{CONTROLLERS},
JMeterUtils.getResString("insert_parent"),// $NON-NLS-1$
ActionNames.ADD_PARENT));
MenuFactory.addEditMenu(pop, true);
@@ -325,8 +369,8 @@ public final class MenuFactory {
public static JPopupMenu getDefaultVisualizerMenu() {
JPopupMenu pop = new JPopupMenu();
- pop.add(
- MenuFactory.makeMenuItemRes("clear", ActionNames.CLEAR)); //$NON-NLS-1$
+ pop.add(MenuFactory.makeMenuItemRes(
+ "clear", ActionNames.CLEAR)); //$NON-NLS-1$
MenuFactory.addEditMenu(pop, true);
MenuFactory.addFileMenu(pop);
return pop;
@@ -363,29 +407,35 @@ public final class MenuFactory {
/**
* Create a menu from a menu category.
*
- * @param category - predefined string (used as key for menuMap HashMap and messages.properties lookup)
- * @param actionCommand - predefined string, e.g. ActionNames.ADD
- * @see org.apache.jmeter.gui.action.ActionNames
+ * @param category predefined string (used as key for menuMap HashMap
+ * and messages.properties lookup)
+ * @param actionCommand predefined string, e.g. {@code }ActionNames.ADD}
+ * {@link ActionNames}
* @return the menu
*/
public static JMenu makeMenu(String category, String actionCommand) {
- return makeMenu(menuMap.get(category), actionCommand, JMeterUtils.getResString(category));
+ return makeMenu(
+ menuMap.get(category),
+ actionCommand,
+ JMeterUtils.getResString(category));
}
/**
* Create a menu from a collection of items.
*
- * @param menuInfo - collection of MenuInfo items
- * @param actionCommand - predefined string, e.g. ActionNames.ADD
- * @see org.apache.jmeter.gui.action.ActionNames
+ * @param menuInfo collection of MenuInfo items
+ * @param actionCommand predefined string, e.g. ActionNames.ADD
+ * {@link ActionNames}
* @param menuName The name of the newly created menu
* @return the menu
*/
- public static JMenu makeMenu(Collection<MenuInfo> menuInfo, String actionCommand, String menuName) {
+ private static JMenu makeMenu(
+ Collection<MenuInfo> menuInfo, String actionCommand, String menuName) {
+
JMenu menu = new JMenu(menuName);
- for (MenuInfo info : menuInfo) {
- menu.add(makeMenuItem(info, actionCommand));
- }
+ menuInfo.stream()
+ .map(info -> makeMenuItem(info, actionCommand))
+ .forEach(menu::add);
GuiUtils.makeScrollableMenu(menu);
return menu;
}
@@ -401,8 +451,8 @@ public final class MenuFactory {
*
* @param label for the MenuItem
* @param name for the MenuItem
- * @param actionCommand - predefined string, e.g. ActionNames.ADD
- * @see org.apache.jmeter.gui.action.ActionNames
+ * @param actionCommand predefined string, e.g. ActionNames.ADD
+ * {@link ActionNames}
* @return the menu item
*/
public static JMenuItem makeMenuItem(String label, String name, String actionCommand) {
@@ -420,8 +470,8 @@ public final class MenuFactory {
* Create a single menu item from the resource name.
*
* @param resource for the MenuItem
- * @param actionCommand - predefined string, e.g. ActionNames.ADD
- * @see org.apache.jmeter.gui.action.ActionNames
+ * @param actionCommand predefined string, e.g. ActionNames.ADD
+ * {@link ActionNames}
* @return the menu item
*/
public static JMenuItem makeMenuItemRes(String resource, String actionCommand) {
@@ -439,11 +489,15 @@ public final class MenuFactory {
* Create a single menu item from a MenuInfo object
*
* @param info the MenuInfo object
- * @param actionCommand - predefined string, e.g. ActionNames.ADD
- * @see org.apache.jmeter.gui.action.ActionNames
+ * @param actionCommand predefined string, e.g. ActionNames.ADD
+ * {@link ActionNames}
* @return the menu item
*/
- public static Component makeMenuItem(MenuInfo info, String actionCommand) {
+ private static Component makeMenuItem(MenuInfo info, String actionCommand) {
+ if (info instanceof MenuSeparatorInfo) {
+ return new JPopupMenu.Separator();
+ }
+
JMenuItem newMenuChoice = new JMenuItem(info.getLabel());
newMenuChoice.setName(info.getClassName());
newMenuChoice.addActionListener(ActionRouter.getInstance());
@@ -454,115 +508,18 @@ public final class MenuFactory {
return newMenuChoice;
}
- public static JMenuItem makeMenuItemRes(String resource, String actionCommand, KeyStroke accel) {
+ private static JMenuItem makeMenuItemRes(String resource, String actionCommand, KeyStroke accel) {
JMenuItem item = makeMenuItemRes(resource, actionCommand);
item.setAccelerator(accel);
return item;
}
- public static JMenuItem makeMenuItem(String label, String name, String actionCommand, KeyStroke accel) {
+ private static JMenuItem makeMenuItem(String label, String name, String actionCommand, KeyStroke accel) {
JMenuItem item = makeMenuItem(label, name, actionCommand);
item.setAccelerator(accel);
return item;
}
- private static void initializeMenus() {
- try {
- List<String> guiClasses = ClassFinder
- .findClassesThatExtend(
- JMeterUtils.getSearchPaths(),
- new Class[] {JMeterGUIComponent.class, TestBean.class})
- .stream()
- // JMeterTreeNode and TestBeanGUI are special GUI classes,
- // and aren't intended to be added to menus
- .filter(name -> !name.endsWith("JMeterTreeNode"))
- .filter(name -> !name.endsWith("TestBeanGUI"))
- .filter(name -> !elementsToSkip.contains(name))
- .distinct()
- .sorted(Comparator.comparing(String::trim))
- .collect(Collectors.toList());
-
- for (String name : guiClasses) {
- JMeterGUIComponent item = getItem(name);
- if (item == null) {
- continue;
- }
-
- Collection<String> categories = item.getMenuCategories();
- if (categories == null) {
- log.debug("{} participates in no menus.", name);
- continue;
- }
- if (categories.contains(THREADS)) {
- threads.add(new MenuInfo(item, name));
- }
- if (categories.contains(FRAGMENTS)) {
- fragments.add(new MenuInfo(item, name));
- }
- if (categories.contains(TIMERS)) {
- timers.add(new MenuInfo(item, name));
- }
- if (categories.contains(POST_PROCESSORS)) {
- postProcessors.add(new MenuInfo(item, name));
- }
- if (categories.contains(PRE_PROCESSORS)) {
- preProcessors.add(new MenuInfo(item, name));
- }
- if (categories.contains(CONTROLLERS)) {
- controllers.add(new MenuInfo(item, name));
- }
- if (categories.contains(SAMPLERS)) {
- samplers.add(new MenuInfo(item, name));
- }
- if (categories.contains(NON_TEST_ELEMENTS)) {
- nonTestElements.add(new MenuInfo(item, name));
- }
- if (categories.contains(LISTENERS)) {
- listeners.add(new MenuInfo(item, name));
- }
- if (categories.contains(CONFIG_ELEMENTS)) {
- configElements.add(new MenuInfo(item, name));
- }
- if (categories.contains(ASSERTIONS)) {
- assertions.add(new MenuInfo(item, name));
- }
- }
- } catch (IOException e) {
- log.error("IO Exception while initializing menus.", e);
- }
- }
-
- private static JMeterGUIComponent getItem(String name) {
- JMeterGUIComponent item = null;
- boolean hideBean = false; // Should the TestBean be hidden?
- try {
- Class<?> c = Class.forName(name);
- if (TestBean.class.isAssignableFrom(c)) {
- TestBeanGUI tbgui = new TestBeanGUI(c);
- hideBean = tbgui.isHidden() || (tbgui.isExpert() && !JMeterUtils.isExpertMode());
- item = tbgui;
- } else {
- item = (JMeterGUIComponent) c.newInstance();
- }
- } catch (NoClassDefFoundError e) {
- log.warn("Configuration error, probably corrupt or missing third party library(jar) ? Could not create class: {}.",
- name, e);
- } catch (HeadlessException e) {
- log.warn("Could not instantiate class: {}", name, e);
- } catch (RuntimeException e) {
- throw e;
- } catch (Exception e) {
- log.warn("Could not instantiate class: {}", name, e);
- }
- if (hideBean || (item != null && elementsToSkip.contains(item.getStaticLabel()))) {
- log.info("Skipping {}", name);
- item = null;
- } else {
- elementsToSkip.add(name);
- }
- return item;
- }
-
private static void addSeparator(JPopupMenu menu) {
MenuElement[] elements = menu.getSubElements();
if ((elements.length > 0)
@@ -573,14 +530,12 @@ public final class MenuFactory {
/**
* Determine whether or not nodes can be added to this parent.
- *
+ * <p>
* Used by Merge
*
- * @param parentNode
- * The {@link JMeterTreeNode} to test, if a new element can be
- * added to it
- * @param element
- * - top-level test element to be added
+ * @param parentNode The {@link JMeterTreeNode} to test, if a new element
+ * can be added to it
+ * @param element top-level test element to be added
* @return whether it is OK to add the element to this parent
*/
public static boolean canAddTo(JMeterTreeNode parentNode, TestElement element) {
@@ -590,14 +545,12 @@ public final class MenuFactory {
/**
* Determine whether or not nodes can be added to this parent.
- *
+ * <p>
* Used by DragNDrop and Paste.
*
- * @param parentNode
- * The {@link JMeterTreeNode} to test, if <code>nodes[]</code>
+ * @param parentNode The {@link JMeterTreeNode} to test, if <code>nodes[]</code>
* can be added to it
- * @param nodes
- * - array of nodes that are to be added
+ * @param nodes array of nodes that are to be added
* @return whether it is OK to add the dragged nodes to this parent
*/
public static boolean canAddTo(JMeterTreeNode parentNode, JMeterTreeNode[] nodes) {
@@ -619,19 +572,22 @@ public final class MenuFactory {
}
if (parent instanceof TestPlan) {
- return !foundClass(
- nodes,
- new Class[]{Sampler.class, Controller.class}, // Samplers and Controllers need not apply ...
- new Class[]{AbstractThreadGroup.class, NonTestElement.class});
+ List<Class> samplerAndController = Arrays.asList(Sampler.class, Controller.class);
+ List<Class> exceptions = Arrays.asList(AbstractThreadGroup.class, NonTestElement.class);
+ return !foundClass(nodes, samplerAndController, exceptions);
}
// AbstractThreadGroup is only allowed under a TestPlan
if (foundClass(nodes, new Class[]{AbstractThreadGroup.class})) {
return false;
}
- if (parent instanceof Controller) {// Includes thread group; anything goes
+
+ // Includes thread group; anything goes
+ if (parent instanceof Controller) {
return true;
}
- if (parent instanceof Sampler) {// Samplers and Controllers need not apply ...
+
+ // No Samplers and Controllers
+ if (parent instanceof Sampler) {
return !foundClass(nodes, new Class[]{Sampler.class, Controller.class});
}
@@ -641,11 +597,12 @@ public final class MenuFactory {
/**
* Is any of nodes an instance of one of the classes?
+ *
* @param nodes Array of {@link JMeterTreeNode}
* @param classes Array of {@link Class}
* @return true if nodes is one of classes
*/
- private static boolean foundClass(JMeterTreeNode[] nodes, Class<?>[] classes) {
+ private static boolean foundClass(JMeterTreeNode[] nodes, Class[] classes) {
for (JMeterTreeNode node : nodes) {
for (Class<?> aClass : classes) {
if (aClass.isInstance(node.getUserObject())) {
@@ -670,94 +627,17 @@ public final class MenuFactory {
/**
* Is any node an instance of one of the classes, but not an exceptions?
+ *
* @param nodes array of {@link JMeterTreeNode}
* @param classes Array of {@link Class}
* @param exceptions Array of {@link Class}
* @return boolean
*/
- private static boolean foundClass(JMeterTreeNode[] nodes, Class<?>[] classes, Class<?>[] exceptions) {
- for (JMeterTreeNode node : nodes) {
- Object userObject = node.getUserObject();
- boolean isException = false;
- for (Class<?> except : exceptions) {
- if (except.isInstance(userObject)) {
- isException = true;
- break;
- }
- }
- if (!isException) {
- for (Class<?> aClass : classes) {
- if (aClass.isInstance(userObject)) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- // Methods used for Test cases
- static int menuMap_size() {
- return menuMap.size();
- }
- static int assertions_size() {
- return assertions.size();
- }
- static int configElements_size() {
- return configElements.size();
- }
- static int controllers_size() {
- return controllers.size();
- }
- static int listeners_size() {
- return listeners.size();
- }
- static int nonTestElements_size() {
- return nonTestElements.size();
- }
- static int postProcessors_size() {
- return postProcessors.size();
- }
- static int preProcessors_size() {
- return preProcessors.size();
- }
- static int samplers_size() {
- return samplers.size();
- }
- static int timers_size() {
- return timers.size();
- }
- static int elementsToSkip_size() {
- return elementsToSkip.size();
- }
-
- /**
- * Menu sort helper class
- */
- private static class MenuInfoComparator implements Comparator<MenuInfo>, Serializable {
- private static final long serialVersionUID = 1L;
- private final boolean caseBlind;
- MenuInfoComparator(boolean caseBlind){
- this.caseBlind = caseBlind;
- }
- @Override
- public int compare(MenuInfo o1, MenuInfo o2) {
- String lab1 = o1.getLabel();
- String lab2 = o2.getLabel();
- if (caseBlind) {
- return lab1.toLowerCase(Locale.ENGLISH).compareTo(lab2.toLowerCase(Locale.ENGLISH));
- }
- return lab1.compareTo(lab2);
- }
- }
-
- /**
- * Sort loaded menus; all but THREADS are sorted case-blind.
- * [This is so Thread Group appears before setUp and tearDown]
- */
- private static void sortPluginMenus() {
- for (Entry<String, List<MenuInfo>> me : menuMap.entrySet()) {
- me.getValue().sort(new MenuInfoComparator(!me.getKey().equals(THREADS)));
- }
+ private static boolean foundClass(
+ JMeterTreeNode[] nodes, List<Class> classes, List<Class> exceptions) {
+ return Arrays.stream(nodes)
+ .map(DefaultMutableTreeNode::getUserObject)
+ .filter(userObj -> exceptions.stream().noneMatch(c -> c.isInstance(userObj)))
+ .anyMatch(userObj -> classes.stream().anyMatch(c -> c.isInstance(userObj)));
}
}
Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuInfo.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuInfo.java?rev=1818750&r1=1818749&r2=1818750&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuInfo.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuInfo.java Wed Dec 20 08:50:00 2017
@@ -18,6 +18,7 @@
package org.apache.jmeter.gui.util;
+import org.apache.jmeter.gui.GUIMenuSortOrder;
import org.apache.jmeter.gui.JMeterGUIComponent;
/**
@@ -25,25 +26,39 @@ import org.apache.jmeter.gui.JMeterGUICo
*/
public class MenuInfo {
+ public static final int SORT_ORDER_DEFAULT = Integer.MAX_VALUE;
private final String label;
-
private final String className;
-
private final JMeterGUIComponent guiComp;
+ private final int sortOrder;
public MenuInfo(String displayLabel, String classFullName) {
label = displayLabel;
className = classFullName;
guiComp = null;
+ sortOrder = getSortOrderFromName(classFullName);
}
public MenuInfo(JMeterGUIComponent item, String classFullName) {
label = item.getStaticLabel();
className = classFullName;
guiComp = item;
+ sortOrder = getSortOrderFromName(classFullName);
}
- public String getLabel(){
+ private int getSortOrderFromName(String classFullName) {
+ try {
+ GUIMenuSortOrder menuSortOrder = Class.forName(classFullName)
+ .getDeclaredAnnotation(GUIMenuSortOrder.class);
+ if (menuSortOrder != null) {
+ return menuSortOrder.value();
+ }
+ } catch (ClassNotFoundException ignored) {
+ }
+ return SORT_ORDER_DEFAULT;
+ }
+
+ public String getLabel() {
if (guiComp != null) {
return guiComp.getStaticLabel();
}
@@ -53,4 +68,8 @@ public class MenuInfo {
public String getClassName(){
return className;
}
+
+ public int getSortOrder() {
+ return sortOrder;
+ }
}
Added: jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuSeparatorInfo.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuSeparatorInfo.java?rev=1818750&view=auto
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuSeparatorInfo.java (added)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuSeparatorInfo.java Wed Dec 20 08:50:00 2017
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jmeter.gui.util;
+
+/**
+ * Indicates a menu separator when building {@link MenuInfo} lists in {@link MenuFactory}
+ * @since 4.0
+ */
+public class MenuSeparatorInfo extends MenuInfo {
+ public MenuSeparatorInfo() {
+ super("separator", "javax.swing.JPopupMenu.Separator");
+ }
+}
Propchange: jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuSeparatorInfo.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/src/core/org/apache/jmeter/gui/util/MenuSeparatorInfo.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: jmeter/trunk/src/core/org/apache/jmeter/testbeans/gui/TestBeanGUI.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/testbeans/gui/TestBeanGUI.java?rev=1818750&r1=1818749&r2=1818750&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/testbeans/gui/TestBeanGUI.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/testbeans/gui/TestBeanGUI.java Wed Dec 20 08:50:00 2017
@@ -94,9 +94,7 @@ public class TestBeanGUI extends Abstrac
private static final Logger log = LoggerFactory.getLogger(TestBeanGUI.class);
private final Class<?> testBeanClass;
-
private transient BeanInfo beanInfo;
-
private final Class<?> customizerClass;
/**
@@ -114,19 +112,13 @@ public class TestBeanGUI extends Abstrac
@SuppressWarnings("unchecked")
private final Map<TestElement, Customizer> customizers = new LRUMap(20);
- /**
- * Index of the customizer in the JPanel's child component list:
- */
+ /** Index of the customizer in the JPanel's child component list: */
private int customizerIndexInPanel;
- /**
- * The property name to value map that the active customizer edits:
- */
+ /** The property name to value map that the active customizer edits: */
private final Map<String, Object> propertyMap = new HashMap<>();
- /**
- * Whether the GUI components have been created.
- */
+ /** Whether the GUI components have been created. */
private boolean initialized = false;
static {
@@ -168,18 +160,14 @@ public class TestBeanGUI extends Abstrac
beanInfo = Introspector.getBeanInfo(testBeanClass);
} catch (IntrospectionException e) {
log.error("Can't get beanInfo for {}", testBeanClass, e);
- throw new Error(e.toString()); // Programming error. Don't
- // continue.
+ throw new Error(e); // Programming error. Don't continue.
}
customizerClass = beanInfo.getBeanDescriptor().getCustomizerClass();
- // Creation of the customizer and GUI initialization is delayed until
- // the
- // first
- // configure call. We don't need all that just to find out the static
- // label, menu
- // categories, etc!
+ // Creation of customizer and GUI initialization
+ // is delayed until the first configure call.
+ // It's not needed to find the static label, menu categories, etc.
initialized = false;
JMeterUtils.addLocaleChangeListener(this);
}
@@ -208,23 +196,22 @@ public class TestBeanGUI extends Abstrac
* {@inheritDoc}
*/
@Override
-public TestElement createTestElement() {
+ public TestElement createTestElement() {
try {
TestElement element = (TestElement) testBeanClass.newInstance();
// In other GUI component, clearGUI resets the value to defaults one as there is one GUI per Element
// With TestBeanGUI as it's shared, its default values are only known here, we must call setValues with
// element (as it holds default values)
// otherwise we will get values as computed by customizer reset and not default ones
- if(initialized) {
+ if (initialized) {
setValues(element);
}
- modifyTestElement(element); // put the default values back into the
- // new element
+ // put the default values back into the new element
+ modifyTestElement(element);
return element;
} catch (InstantiationException | IllegalAccessException e) {
log.error("Can't create test element", e);
- throw new Error(e.toString()); // Programming error. Don't
- // continue.
+ throw new Error(e); // Programming error. Don't continue.
}
}
@@ -282,36 +269,22 @@ public TestElement createTestElement() {
*/
@Override
public JPopupMenu createPopupMenu() {
- if (Timer.class.isAssignableFrom(testBeanClass))
- {
+ if (Timer.class.isAssignableFrom(testBeanClass)) {
return MenuFactory.getDefaultTimerMenu();
- }
- else if(Sampler.class.isAssignableFrom(testBeanClass))
- {
+ } else if (Sampler.class.isAssignableFrom(testBeanClass)) {
return MenuFactory.getDefaultSamplerMenu();
- }
- else if(ConfigElement.class.isAssignableFrom(testBeanClass))
- {
+ } else if (ConfigElement.class.isAssignableFrom(testBeanClass)) {
return MenuFactory.getDefaultConfigElementMenu();
- }
- else if(Assertion.class.isAssignableFrom(testBeanClass))
- {
+ } else if (Assertion.class.isAssignableFrom(testBeanClass)) {
return MenuFactory.getDefaultAssertionMenu();
- }
- else if(PostProcessor.class.isAssignableFrom(testBeanClass) ||
- PreProcessor.class.isAssignableFrom(testBeanClass))
- {
+ } else if (PostProcessor.class.isAssignableFrom(testBeanClass)
+ || PreProcessor.class.isAssignableFrom(testBeanClass)) {
return MenuFactory.getDefaultExtractorMenu();
- }
- else if(Visualizer.class.isAssignableFrom(testBeanClass))
- {
+ } else if (Visualizer.class.isAssignableFrom(testBeanClass)) {
return MenuFactory.getDefaultVisualizerMenu();
- }
- else if(Controller.class.isAssignableFrom(testBeanClass))
- {
+ } else if (Controller.class.isAssignableFrom(testBeanClass)) {
return MenuFactory.getDefaultControllerMenu();
- }
- else {
+ } else {
log.warn("Cannot determine PopupMenu for {}", testBeanClass);
return MenuFactory.getDefaultMenu();
}
@@ -326,11 +299,8 @@ public TestElement createTestElement() {
init();
}
clearGui();
-
super.configure(element);
-
setValues(element);
-
initialized = true;
}
@@ -364,20 +334,17 @@ public TestElement createTestElement() {
/** {@inheritDoc} */
@Override
public Collection<String> getMenuCategories() {
- List<String> menuCategories = new LinkedList<>();
BeanDescriptor bd = beanInfo.getBeanDescriptor();
- // We don't want to show expert beans in the menus unless we're
- // in expert mode:
+ // Don't show expert beans in the menus unless we're in expert mode
if (bd.isExpert() && !JMeterUtils.isExpertMode()) {
return null;
}
- int matches = setupGuiClasses(menuCategories);
- if (matches == 0) {
+ List<String> menuCategories = setupGuiClassesList();
+ if (menuCategories.isEmpty()) {
log.error("Could not assign GUI class to {}", testBeanClass);
- } else if (matches > 1) {// may be impossible, but no harm in
- // checking ...
+ } else if (menuCategories.size() > 1) {
log.error("More than 1 GUI class found for {}", testBeanClass);
}
return menuCategories;
@@ -385,62 +352,55 @@ public TestElement createTestElement() {
/**
* Setup GUI class
+ *
* @return number of matches
*/
public int setupGuiClasses() {
- return setupGuiClasses(new ArrayList<String>());
+ return setupGuiClassesList().size();
}
/**
* Setup GUI class
- * @param menuCategories List<String> menu categories
- * @return number of matches
+ *
+ * @return matches
*/
- private int setupGuiClasses(List<String> menuCategories ) {
- int matches = 0;// How many classes can we assign from?
+ private List<String> setupGuiClassesList() {
+ List<String> menuCategories = new ArrayList<>();
// TODO: there must be a nicer way...
BeanDescriptor bd = beanInfo.getBeanDescriptor();
if (Assertion.class.isAssignableFrom(testBeanClass)) {
menuCategories.add(MenuFactory.ASSERTIONS);
bd.setValue(TestElement.GUI_CLASS, AbstractAssertionGui.class.getName());
- matches++;
}
if (ConfigElement.class.isAssignableFrom(testBeanClass)) {
menuCategories.add(MenuFactory.CONFIG_ELEMENTS);
bd.setValue(TestElement.GUI_CLASS, AbstractConfigGui.class.getName());
- matches++;
}
if (Controller.class.isAssignableFrom(testBeanClass)) {
menuCategories.add(MenuFactory.CONTROLLERS);
bd.setValue(TestElement.GUI_CLASS, AbstractControllerGui.class.getName());
- matches++;
}
if (Visualizer.class.isAssignableFrom(testBeanClass)) {
menuCategories.add(MenuFactory.LISTENERS);
bd.setValue(TestElement.GUI_CLASS, AbstractVisualizer.class.getName());
- matches++;
}
if (PostProcessor.class.isAssignableFrom(testBeanClass)) {
menuCategories.add(MenuFactory.POST_PROCESSORS);
bd.setValue(TestElement.GUI_CLASS, AbstractPostProcessorGui.class.getName());
- matches++;
}
if (PreProcessor.class.isAssignableFrom(testBeanClass)) {
menuCategories.add(MenuFactory.PRE_PROCESSORS);
bd.setValue(TestElement.GUI_CLASS, AbstractPreProcessorGui.class.getName());
- matches++;
}
if (Sampler.class.isAssignableFrom(testBeanClass)) {
menuCategories.add(MenuFactory.SAMPLERS);
bd.setValue(TestElement.GUI_CLASS, AbstractSamplerGui.class.getName());
- matches++;
}
if (Timer.class.isAssignableFrom(testBeanClass)) {
menuCategories.add(MenuFactory.TIMERS);
bd.setValue(TestElement.GUI_CLASS, AbstractTimerGui.class.getName());
- matches++;
}
- return matches;
+ return menuCategories;
}
private void init() {
Modified: jmeter/trunk/src/core/org/apache/jmeter/threads/ThreadGroup.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/threads/ThreadGroup.java?rev=1818750&r1=1818749&r2=1818750&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/threads/ThreadGroup.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/threads/ThreadGroup.java Wed Dec 20 08:50:00 2017
@@ -27,6 +27,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jmeter.engine.TreeCloner;
+import org.apache.jmeter.gui.GUIMenuSortOrder;
import org.apache.jmeter.testelement.property.BooleanProperty;
import org.apache.jmeter.testelement.property.IntegerProperty;
import org.apache.jmeter.testelement.property.LongProperty;
@@ -41,6 +42,7 @@ import org.slf4j.LoggerFactory;
*
* This class is intended to be ThreadSafe.
*/
+@GUIMenuSortOrder(1)
public class ThreadGroup extends AbstractThreadGroup {
private static final long serialVersionUID = 282L;
Modified: jmeter/trunk/src/core/org/apache/jmeter/threads/gui/AbstractThreadGroupGui.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/threads/gui/AbstractThreadGroupGui.java?rev=1818750&r1=1818749&r2=1818750&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/threads/gui/AbstractThreadGroupGui.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/threads/gui/AbstractThreadGroupGui.java Wed Dec 20 08:50:00 2017
@@ -26,6 +26,7 @@ import java.util.Collection;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ButtonGroup;
+import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
@@ -45,13 +46,9 @@ public abstract class AbstractThreadGrou
// Sampler error action buttons
private JRadioButton continueBox;
-
private JRadioButton startNextLoop;
-
- private JRadioButton stopThrdBox;
-
+ private JRadioButton stopThreadBox;
private JRadioButton stopTestBox;
-
private JRadioButton stopTestNowBox;
public AbstractThreadGroupGui(){
@@ -68,48 +65,15 @@ public abstract class AbstractThreadGrou
@Override
public JPopupMenu createPopupMenu() {
JPopupMenu pop = new JPopupMenu();
- pop.add(MenuFactory.makeMenus(new String[] {
- MenuFactory.CONTROLLERS,
- MenuFactory.CONFIG_ELEMENTS,
- MenuFactory.TIMERS,
- MenuFactory.PRE_PROCESSORS,
- MenuFactory.SAMPLERS,
- MenuFactory.POST_PROCESSORS,
- MenuFactory.ASSERTIONS,
- MenuFactory.LISTENERS,
- },
- JMeterUtils.getResString("add"), // $NON-NLS-1$
- ActionNames.ADD));
-
- if(this.isEnabled() &&
- // Check test is not started already
- !JMeterUtils.isTestRunning()) {
- pop.addSeparator();
+ pop.add(createAddMenu());
- JMenuItem addThinkTimesToChildren = new JMenuItem(JMeterUtils.getResString("add_think_times"));
- addThinkTimesToChildren.setName("add_think_times");
- addThinkTimesToChildren.addActionListener(ActionRouter.getInstance());
- addThinkTimesToChildren.setActionCommand(ActionNames.ADD_THINK_TIME_BETWEEN_EACH_STEP);
- pop.add(addThinkTimesToChildren);
-
- JMenuItem runTg = new JMenuItem(JMeterUtils.getResString("run_threadgroup"));
- runTg.setName("run_threadgroup");
- runTg.addActionListener(ActionRouter.getInstance());
- runTg.setActionCommand(ActionNames.RUN_TG);
- pop.add(runTg);
-
- JMenuItem runTgNotimers = new JMenuItem(JMeterUtils.getResString("run_threadgroup_no_timers"));
- runTgNotimers.setName("run_threadgroup_no_timers");
- runTgNotimers.addActionListener(ActionRouter.getInstance());
- runTgNotimers.setActionCommand(ActionNames.RUN_TG_NO_TIMERS);
- pop.add(runTgNotimers);
-
- JMenuItem validateTg = new JMenuItem(JMeterUtils.getResString("validate_threadgroup"));
- validateTg.setName("validate_threadgroup");
- validateTg.addActionListener(ActionRouter.getInstance());
- validateTg.setActionCommand(ActionNames.VALIDATE_TG);
- pop.add(validateTg);
+ if (this.isEnabled() && !JMeterUtils.isTestRunning()) {
+ pop.addSeparator();
+ pop.add(createMenuItem("add_think_times", ActionNames.ADD_THINK_TIME_BETWEEN_EACH_STEP));
+ pop.add(createMenuItem("run_threadgroup", ActionNames.RUN_TG));
+ pop.add(createMenuItem("run_threadgroup_no_timers", ActionNames.RUN_TG_NO_TIMERS));
+ pop.add(createMenuItem("validate_threadgroup", ActionNames.VALIDATE_TG));
}
MenuFactory.addEditMenu(pop, true);
@@ -117,6 +81,32 @@ public abstract class AbstractThreadGrou
return pop;
}
+ private JMenuItem createMenuItem(String name, String actionCommand) {
+ JMenuItem addThinkTimesToChildren = new JMenuItem(JMeterUtils.getResString(name));
+ addThinkTimesToChildren.setName(name);
+ addThinkTimesToChildren.addActionListener(ActionRouter.getInstance());
+ addThinkTimesToChildren.setActionCommand(actionCommand);
+ return addThinkTimesToChildren;
+ }
+
+ private JMenu createAddMenu() {
+ String addAction = ActionNames.ADD;
+ JMenu addMenu = new JMenu(JMeterUtils.getResString("add")); // $NON-NLS-1$
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.SAMPLERS, addAction));
+ addMenu.addSeparator();
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.PRE_PROCESSORS, addAction));
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.POST_PROCESSORS, addAction));
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.ASSERTIONS, addAction));
+ addMenu.addSeparator();
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.TIMERS, addAction));
+ addMenu.addSeparator();
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.FRAGMENTS, addAction));
+ addMenu.addSeparator();
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.CONFIG_ELEMENTS, addAction));
+ addMenu.add(MenuFactory.makeMenu(MenuFactory.LISTENERS, addAction));
+ return addMenu;
+ }
+
@Override
public Dimension getPreferredSize() {
return getMinimumSize();
@@ -128,7 +118,8 @@ public abstract class AbstractThreadGrou
initGui();
}
- private void init() { // WARNING: called from ctor so must not be overridden (i.e. must be private or final)
+ // WARNING: called from ctor so must not be overridden (i.e. must be private or final)
+ private void init() {
setLayout(new BorderLayout(0, 5));
setBorder(makeBorder());
@@ -144,27 +135,33 @@ public abstract class AbstractThreadGrou
private JPanel createOnErrorPanel() {
JPanel panel = new JPanel();
- panel.setBorder(BorderFactory.createTitledBorder(JMeterUtils.getResString("sampler_on_error_action"))); // $NON-NLS-1$
+ panel.setBorder(BorderFactory.createTitledBorder(
+ JMeterUtils.getResString("sampler_on_error_action"))); // $NON-NLS-1$
ButtonGroup group = new ButtonGroup();
- continueBox = new JRadioButton(JMeterUtils.getResString("sampler_on_error_continue")); // $NON-NLS-1$
+ continueBox = new JRadioButton(
+ JMeterUtils.getResString("sampler_on_error_continue")); // $NON-NLS-1$
group.add(continueBox);
panel.add(continueBox);
- startNextLoop = new JRadioButton(JMeterUtils.getResString("sampler_on_error_start_next_loop")); // $NON-NLS-1$
+ startNextLoop = new JRadioButton(
+ JMeterUtils.getResString("sampler_on_error_start_next_loop")); // $NON-NLS-1$
group.add(startNextLoop);
panel.add(startNextLoop);
- stopThrdBox = new JRadioButton(JMeterUtils.getResString("sampler_on_error_stop_thread")); // $NON-NLS-1$
- group.add(stopThrdBox);
- panel.add(stopThrdBox);
+ stopThreadBox = new JRadioButton(
+ JMeterUtils.getResString("sampler_on_error_stop_thread")); // $NON-NLS-1$
+ group.add(stopThreadBox);
+ panel.add(stopThreadBox);
- stopTestBox = new JRadioButton(JMeterUtils.getResString("sampler_on_error_stop_test")); // $NON-NLS-1$
+ stopTestBox = new JRadioButton(
+ JMeterUtils.getResString("sampler_on_error_stop_test")); // $NON-NLS-1$
group.add(stopTestBox);
panel.add(stopTestBox);
- stopTestNowBox = new JRadioButton(JMeterUtils.getResString("sampler_on_error_stop_test_now")); // $NON-NLS-1$
+ stopTestNowBox = new JRadioButton(
+ JMeterUtils.getResString("sampler_on_error_stop_test_now")); // $NON-NLS-1$
group.add(stopTestNowBox);
panel.add(stopTestNowBox);
@@ -177,7 +174,7 @@ public abstract class AbstractThreadGrou
} else if (te.getOnErrorStopTestNow()) {
stopTestNowBox.setSelected(true);
} else if (te.getOnErrorStopThread()) {
- stopThrdBox.setSelected(true);
+ stopThreadBox.setSelected(true);
} else if (te.getOnErrorStartNextLoop()) {
startNextLoop.setSelected(true);
} else {
@@ -192,7 +189,7 @@ public abstract class AbstractThreadGrou
if (stopTestNowBox.isSelected()) {
return AbstractThreadGroup.ON_SAMPLE_ERROR_STOPTEST_NOW;
}
- if (stopThrdBox.isSelected()) {
+ if (stopThreadBox.isSelected()) {
return AbstractThreadGroup.ON_SAMPLE_ERROR_STOPTHREAD;
}
if (startNextLoop.isSelected()) {