- /*
- * suppress action handler while updating the list
- */
- ItemListener listener = filteredFeatureChoice.getItemListeners()[0];
- filteredFeatureChoice.removeItemListener(listener);
-
- filteredFeatureChoice.removeAllItems();
- ReverseListIterator<String> types = new ReverseListIterator<>(
- fr.getRenderOrder());
-
- boolean found = false;
- while (types.hasNext())
- {
- String type = types.next();
- if (FeatureAttributes.getInstance().hasAttributes(type))
- {
- filteredFeatureChoice.addItem(type);
- found = true;
- }
- }
- if (!found)
- {
- filteredFeatureChoice
- .addItem("No filterable feature attributes known");
- }
-
- filteredFeatureChoice.addItemListener(listener);
-
- }
-
- /**
- * Refreshes the display to show any filters currently configured for the
- * selected feature type (editable, with 'remove' option), plus one extra row
- * for adding a condition. This should be called on change of selected feature
- * type, or after a filter has been removed, added or amended.
- */
- protected void refreshFiltersDisplay()
- {
- /*
- * clear the panel and list of filter conditions
- */
- chooseFiltersPanel.removeAll();
-
- String selectedType = (String) filteredFeatureChoice.getSelectedItem();
-
- filters.clear();
-
- /*
- * look up attributes known for feature type
- */
- List<String> attNames = FeatureAttributes.getInstance().getAttributes(
- selectedType);
-
- /*
- * if this feature type has filters set, load them first
- */
- KeyedMatcherSetI featureFilters = fr.getFeatureFilter(selectedType);
- filtersAsText.setText("");
- if (featureFilters != null)
- {
- filtersAsText.setText(featureFilters.toString());
- if (!featureFilters.isAnded())
- {
- orFilters.setSelected(true);
- }
- Iterator<KeyedMatcherI> matchers = featureFilters.getMatchers();
- while (matchers.hasNext())
- {
- filters.add(matchers.next());
- }
- }
-
- /*
- * and an empty filter for the user to populate (add)
- */
- KeyedMatcherI noFilter = new KeyedMatcher("", Condition.values()[0], "");
- filters.add(noFilter);
-
- /*
- * render the conditions in rows, each in its own JPanel
- */
- int i = 0;
- for (KeyedMatcherI filter : filters)
- {
- String key = filter.getKey();
- Condition condition = filter.getMatcher()
- .getCondition();
- String pattern = filter.getMatcher().getPattern();
- JPanel row = addFilter(key, attNames, condition, pattern, i);
- chooseFiltersPanel.add(row);
- i++;
- }
-
- filtersPane.validate();
- filtersPane.repaint();
- }
-
- /**
- * A helper method that constructs a panel with one filter condition:
- * <ul>
- * <li>a drop-down list of attribute names to choose from</li>
- * <li>a drop-down list of conditions to choose from</li>
- * <li>a text field for input of a match pattern</li>
- * <li>optionally, a 'remove' button</li>
- * </ul>
- * If attribute, condition or pattern are not null, they are set as defaults
- * for the input fields. The 'remove' button is added unless the pattern is
- * null or empty (incomplete filter condition).
- *
- * @param attribute
- * @param attNames
- * @param cond
- * @param pattern
- * @param filterIndex
- * @return
- */
- protected JPanel addFilter(String attribute, List<String> attNames,
- Condition cond, String pattern, int filterIndex)
- {
- JPanel filterRow = new JPanel(new FlowLayout(FlowLayout.LEFT));
- filterRow.setBackground(Color.white);
-
- /*
- * inputs for attribute, condition, pattern
- */
- final JComboBox<String> attCombo = new JComboBox<>();
- JComboBox<Condition> condCombo = new JComboBox<>();
- JTextField patternField = new JTextField(8);
-
- /*
- * action handlers that validate and (if valid) apply changes
- */
- ActionListener actionListener = new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- if (attCombo.getSelectedItem() != null)
- {
- if (validateFilter(patternField, condCombo))
- {
- updateFilter(attCombo, condCombo, patternField, filterIndex);
- filtersChanged();
- }
- }
- }
- };
- ItemListener itemListener = new ItemListener()
- {
- @Override
- public void itemStateChanged(ItemEvent e)
- {
- actionListener.actionPerformed(null);
- }
- };
-
- /*
- * drop-down choice of attribute, with description as a tooltip
- * if we can obtain it
- */
- String featureType = (String) filteredFeatureChoice.getSelectedItem();
- populateAttributesDropdown(attCombo, featureType, attNames);
- if ("".equals(attribute))
- {
- attCombo.setSelectedItem(null);
- }
- else
- {
- attCombo.setSelectedItem(attribute);
- }
- attCombo.addItemListener(itemListener);
-
- filterRow.add(attCombo);
-
- /*
- * drop-down choice of test condition
- */
- for (Condition c : Condition.values())
- {
- condCombo.addItem(c);
- }
- if (cond != null)
- {
- condCombo.setSelectedItem(cond);
- }
- condCombo.addItemListener(itemListener);
- filterRow.add(condCombo);
-
- /*
- * pattern to match against
- */
- patternField.setText(pattern);
- patternField.addActionListener(actionListener);
- patternField.addFocusListener(new FocusAdapter()
- {
- @Override
- public void focusLost(FocusEvent e)
- {
- actionListener.actionPerformed(null);
- }
- });
- filterRow.add(patternField);
-
- /*
- * add remove button if filter is populated (non-empty pattern)
- */
- if (pattern != null && pattern.trim().length() > 0)
- {
- // todo: gif for - button
- JButton removeCondition = new BasicArrowButton(SwingConstants.WEST);
- removeCondition.setToolTipText(MessageManager
- .getString("label.delete_row"));
- removeCondition.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- filters.remove(filterIndex);
- filtersChanged();
- }
- });
- filterRow.add(removeCondition);
- }
-
- return filterRow;
- }
-
- /**
- * A helper method to build the drop-down choice of attributes for a feature.
- * Where metadata is available with a description for an attribute, that is
- * added as a tooltip.
- *
- * @param attCombo
- * @param featureType
- * @param attNames
- */
- protected void populateAttributesDropdown(
- final JComboBox<String> attCombo, String featureType,
- List<String> attNames)
- {
- final ComboBoxTooltipRenderer renderer = new ComboBoxTooltipRenderer();
- attCombo.setRenderer(renderer);
- List<String> tips = new ArrayList<String>();
- if (attNames.isEmpty())
- {
- attCombo.addItem("---");
- attCombo.setToolTipText(MessageManager
- .getString("label.no_attributes_known"));
- }
- else
- {
- attCombo.setToolTipText("");
- FeatureAttributes fs = FeatureAttributes.getInstance();
- for (String attName : attNames)
- {
- attCombo.addItem(attName);
- String desc = fs.getDescription(featureType, attName);
- tips.add(desc == null ? "" : desc);
- }
- }
- renderer.setTooltips(tips);
- final MouseAdapter mouseListener = new MouseAdapter()
- {
- @Override
- public void mouseEntered(MouseEvent e)
- {
- int j = attCombo.getSelectedIndex();
- if (j > -1)
- {
- attCombo.setToolTipText(tips.get(j));
- }
- }
-
- @Override
- public void mouseExited(MouseEvent e)
- {
- attCombo.setToolTipText(null);
- }
- };
- for (Component c : attCombo.getComponents())
- {
- c.addMouseListener(mouseListener);
- }
- }
-
- /**
- * Action on any change to feature filtering, namely
- * <ul>
- * <li>change of selected attribute</li>
- * <li>change of selected condition</li>
- * <li>change of match pattern</li>
- * <li>removal of a condition</li>
- * </ul>
- * The action should be to
- * <ul>
- * <li>parse and validate the filters</li>
- * <li>if valid, update the filter text box</li>
- * <li>and apply the filters to the viewport</li>
- * </ul>
- */
- protected void filtersChanged()
- {
- /*
- * update the filter conditions for the feature type
- */
- String featureType = (String) filteredFeatureChoice.getSelectedItem();
- boolean anded = andFilters.isSelected();
- KeyedMatcherSetI combined = new KeyedMatcherSet();
-
- for (KeyedMatcherI filter : filters)
- {
- String pattern = filter.getMatcher().getPattern();
- if (pattern.trim().length() > 0)
- {
- if (anded)
- {
- combined.and(filter);
- }
- else
- {
- combined.or(filter);
- }
- }
- }
-
- /*
- * save the filter conditions in the FeatureRenderer
- * (note this might now be an empty filter with no conditions)
- */
- fr.setFeatureFilter(featureType, combined);
-
- filtersAsText.setText(combined.toString());
-
- refreshFiltersDisplay();
-