3535import java .util .stream .Collectors ;
3636
3737import org .scijava .Context ;
38+ import org .scijava .MenuEntry ;
39+ import org .scijava .MenuPath ;
3840import org .scijava .Priority ;
3941import org .scijava .app .AppService ;
4042import org .scijava .module .ModuleInfo ;
@@ -76,23 +78,21 @@ public List<SearchResult> search(final String text, final boolean fuzzy) {
7678
7779 final LinkedHashSet <ModuleInfo > matches = new LinkedHashSet <>();
7880
79- // Get the list of all enabled, visible, valid modules .
81+ // Get the list of all modules for consideration .
8082 final List <ModuleInfo > modules = moduleService .getModules ().stream () //
81- .filter (ModuleInfo ::isEnabled ) //
82- .filter (ModuleInfo ::isVisible ) //
83- .filter (ModuleInfo ::isValid ) //
83+ .filter (this ::isGoodModule ) //
8484 .collect (Collectors .toList ());
8585
8686 final String textLower = text .toLowerCase ();
8787
8888 // First, add modules where title starts with the text.
8989 modules .stream () //
90- .filter (info -> info . getTitle ( ).startsWith (textLower )) //
90+ .filter (info -> ModuleSearcher . title ( info ).startsWith (textLower )) //
9191 .forEach (matches ::add );
9292
9393 // Next, add modules where title has text inside somewhere.
9494 modules .stream () //
95- .filter (info -> matches (info . getTitle ( ), textLower )) //
95+ .filter (info -> matches (ModuleSearcher . title ( info ), textLower )) //
9696 .forEach (matches ::add );
9797
9898 // Finally, add modules where menu path has text inside somewhere.
@@ -106,8 +106,39 @@ public List<SearchResult> search(final String text, final boolean fuzzy) {
106106 .collect (Collectors .toList ());
107107 }
108108
109+ // -- Utility methods --
110+
111+ /**
112+ * Gets a human-readable title for the module, or null if none.
113+ * <p>
114+ * We do not use {@link ModuleInfo#getTitle()} because that method tries very
115+ * hard to return something in every case, whereas we only want to give really
116+ * nice titles, or null if the module is inappropriate.
117+ * </p>
118+ */
119+ public static String title (final ModuleInfo info ) {
120+ // use object label, if available
121+ final String label = info .getLabel ();
122+ if (label != null && !label .isEmpty ()) return label ;
123+
124+ // use name of leaf menu item, if available
125+ final MenuPath menuPath = info .getMenuPath ();
126+ if (menuPath != null && menuPath .size () > 0 ) {
127+ final MenuEntry menuLeaf = menuPath .getLeaf ();
128+ final String menuName = menuLeaf .getName ();
129+ if (menuName != null && !menuName .isEmpty ()) return menuName ;
130+ }
131+
132+ return null ;
133+ }
134+
109135 // -- Helper methods --
110136
137+ private boolean isGoodModule (final ModuleInfo info ) {
138+ return info .isValid () && info .isVisible () && info .isEnabled () &&
139+ title (info ) != null ;
140+ }
141+
111142 private boolean matches (final String actual , final String desired ) {
112143 // TODO: Implement fuzzy matching option, and maybe case sensitive option.
113144 // Probably put it in the SearchService itself, and make an API toggle.
0 commit comments