/* * #! * Ontopia Vizigator * #- * Copyright (C) 2001 - 2013 The Ontopia Project * #- * Licensed 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 net.ontopia.topicmaps.viz; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import javax.swing.AbstractButton; import javax.swing.ButtonGroup; import javax.swing.JCheckBoxMenuItem; import javax.swing.JMenu; import javax.swing.JRadioButtonMenuItem; import net.ontopia.topicmaps.core.TopicIF; import net.ontopia.topicmaps.core.TopicMapIF; import net.ontopia.topicmaps.core.index.ScopeIndexIF; import net.ontopia.topicmaps.nav.utils.comparators.TopicComparator; import net.ontopia.topicmaps.utils.TopicStringifiers; import net.ontopia.utils.OntopiaRuntimeException; public class AssociationScopeFilterMenu extends JMenu { private ButtonGroup radioButtons; private JRadioButtonMenuItem[] strictnessMap; private ArrayList scopes; private ArrayList checkBoxes; public AssociationScopeFilterMenu(String s) { super(s); } /** * Configure/reconfigure this menu. * @param currentTopicMap The topicmap holding the associations (and their * scopes) to be used in this menu. * @param parentListener Allows the caller to act upon actions. * @param controller manages the interaction between the gui, model and * configuration manager */ public void configure(TopicMapIF currentTopicMap, ActionListener parentListener, VizController controller) { if (currentTopicMap == null) return; ScopeIndexIF scopeix = (ScopeIndexIF) currentTopicMap.getIndex( "net.ontopia.topicmaps.core.index.ScopeIndexIF"); // Remove all menu items from this menu. removeAll(); // Add radio-button menu part for "Show All", "Loose Filter" // and "Strict Filter" int SHOW_ALL = VizTopicMapConfigurationManager.SHOW_ALL_ASSOCIATION_SCOPES; int LOOSE = VizTopicMapConfigurationManager.LOOSE_ASSOCIATION_SCOPES; int STRICT = VizTopicMapConfigurationManager.STRICT_ASSOCIATION_SCOPES; // Create radio buttons for the different ways of filtering. // Determine which radio button is selected int selectedStrictness = controller.getAssociationScopeFilterStrictness(); String showAll = Messages.getString("Viz.ShowAll"); String looseFilter = Messages.getString("Viz.LooseFilter"); String strictFilter = Messages.getString("Viz.StrictFilter"); strictnessMap = new JRadioButtonMenuItem[4]; // Create radio buttons JRadioButtonMenuItem radio1 = new JRadioButtonMenuItem(showAll, SHOW_ALL == selectedStrictness); JRadioButtonMenuItem radio2 = new JRadioButtonMenuItem(looseFilter, LOOSE == selectedStrictness); JRadioButtonMenuItem radio3 = new JRadioButtonMenuItem(strictFilter, STRICT == selectedStrictness); strictnessMap[SHOW_ALL] = radio1; strictnessMap[LOOSE] = radio2; strictnessMap[STRICT] = radio3; // Add radio buttons to this menu. add(radio1); add(radio2); add(radio3); // Add ActionListeners to the radiobuttons. radio1.addActionListener(new StrictnessActionListener(controller, SHOW_ALL, parentListener)); radio2.addActionListener(new StrictnessActionListener(controller, LOOSE, parentListener)); radio3.addActionListener(new StrictnessActionListener(controller, STRICT, parentListener)); // Make a group of radiobuttons to make them all exclusive to each other. radioButtons = new ButtonGroup(); radioButtons.add(radio1); radioButtons.add(radio2); radioButtons.add(radio3); // Add a separating line to this menu. addSeparator(); // Create checkboxes for each association scope to determine whether it // should be used for filtering. // Get all topics that are used to scope associations and sort them. scopes = new ArrayList(scopeix.getAssociationThemes()); Collections.sort(scopes, new TopicComparator()); // For each association scoping topic... checkBoxes = new ArrayList(scopes.size()); for (Iterator iter = scopes.iterator(); iter.hasNext();) { TopicIF scope = (TopicIF)iter.next(); // Add checkbox for this scope with appropriate name to the menu. String name = TopicStringifiers.getDefaultStringifier().toString(scope); boolean checked = controller.isInAssociationScopeFilter(scope); JCheckBoxMenuItem mItem = new JCheckBoxMenuItem(name, checked); add(mItem); checkBoxes.add(mItem); // Set the checkbox to always be enabled. boolean enabled = true; mItem.addActionListener(new ScopeFilterActionListener(scope, controller, parentListener)); mItem.setEnabled(enabled); } } /** * Listens for changes to a checkbox controlling whether an association * scoping topic should be part of the association scope filter. */ protected class ScopeFilterActionListener implements ActionListener { private TopicIF scope; ActionListener parentListener; VizController controller; /** * Create new. * @param scope The scoping topic controlled by this checkbox. * @param parentListener The parent listener receives (and may act upon) any * events that happen in this ActionListener. * @param controller Notified when the scope is added to/removed from the * filter (i.e. any checkbox state change). */ protected ScopeFilterActionListener(TopicIF scope, VizController controller, ActionListener parentListener) { this.parentListener = parentListener; this.scope = scope; this.controller = controller; } public void actionPerformed(ActionEvent aE) { boolean setPreviously = controller.isInAssociationScopeFilter(scope); controller.setInAssociationScopeFilter(scope, !setPreviously); if (parentListener != null) parentListener.actionPerformed(aE); } } public void setStrictnessSelection(int strictness) { radioButtons.setSelected(strictnessMap[strictness].getModel(), true); Enumeration elements = radioButtons.getElements(); while(elements.hasMoreElements()) ((AbstractButton)elements.nextElement()).repaint(); } public void setInAssociationScopeFilter(TopicIF scope, boolean useInFilter) { Iterator scopesIt = scopes.iterator(); Iterator checkBoxesIt = checkBoxes.iterator(); TopicIF currentScope = null; JCheckBoxMenuItem checkBox = null; // Assume scopes and checkBoxes have the same size, which they should! while (scopesIt.hasNext()) { currentScope = (TopicIF)scopesIt.next(); if (currentScope.equals(scope)) { checkBox = (JCheckBoxMenuItem)checkBoxesIt.next(); } else checkBoxesIt.next(); } if (checkBox == null) throw new OntopiaRuntimeException("Internal error. There should be a " + "scoping topic menu item for every scoping topic."); checkBox.setState(useInFilter); } /** * Listens for changes to the scrictness of the scope filter. */ protected class StrictnessActionListener implements ActionListener { VizController controller; int strictnessLevel; ActionListener parentListener; /** * * @param controller Notified whenever the strictness level changes. * @param strictnessLevel The strictnes level attached to this menu item. * @param parentListener The parent listener receives (and may act upon) any * events that happen in this ActionListener. */ protected StrictnessActionListener(VizController controller, int strictnessLevel, ActionListener parentListener) { this.controller = controller; this.strictnessLevel = strictnessLevel; this.parentListener = parentListener; } public void actionPerformed(ActionEvent aE) { controller.setAssociationScopeFilterStrictness(strictnessLevel); parentListener.actionPerformed(aE); } } }