/* * Freeplane - mind map editor * Copyright (C) 2009 Dimitry * * This file author is Dimitry * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.freeplane.features.filter; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.lang.ref.WeakReference; import java.util.Iterator; import javax.swing.Box; import javax.swing.ComboBoxEditor; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.ListCellRenderer; import javax.swing.RootPaneContainer; import javax.swing.text.JTextComponent; import org.freeplane.core.resources.NamedObject; import org.freeplane.core.resources.ResourceController; import org.freeplane.core.ui.FixedBasicComboBoxEditor; import org.freeplane.core.ui.MenuBuilder; import org.freeplane.core.util.TextUtils; import org.freeplane.core.util.collection.ExtendedComboBoxModel; import org.freeplane.features.filter.condition.ASelectableCondition; import org.freeplane.features.filter.condition.IElementaryConditionController; import org.freeplane.features.map.MapModel; import org.freeplane.features.mode.Controller; /** * @author Dimitry Polivaev * 23.05.2009 */ public class FilterConditionEditor extends JComponent { private class ElementaryConditionChangeListener implements ItemListener { public void itemStateChanged(final ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { setValuesEditor(); } } } private class FilteredPropertyChangeListener implements ItemListener { public void itemStateChanged(final ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { final Object selectedProperty = filteredPropertiesComponent.getSelectedItem(); final IElementaryConditionController conditionController = filterController.getConditionFactory() .getConditionController(selectedProperty); final ComboBoxModel simpleConditionComboBoxModel = conditionController .getConditionsForProperty(selectedProperty); elementaryConditions.setModel(simpleConditionComboBoxModel); elementaryConditions.setEnabled(simpleConditionComboBoxModel.getSize() > 0); setValuesEditor(); return; } } } /** * Start "Find next" action when pressing enter key in "value" combo box */ private void setValuesEnterKeyListener() { if (enterKeyActionListener != null) { values.getEditor().removeActionListener(enterKeyActionListener); values.getEditor().addActionListener(enterKeyActionListener); } } public void setSearchingBusyCursor() { RootPaneContainer root = (RootPaneContainer)getTopLevelAncestor(); root.getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); root.getGlassPane().setVisible(true); } public void setSearchingDefaultCursor() { RootPaneContainer root = (RootPaneContainer)getTopLevelAncestor(); root.getGlassPane().setCursor(Cursor.getDefaultCursor()); root.getGlassPane().setVisible(false); } private void setValuesEditor() { final Object selectedProperty = filteredPropertiesComponent.getSelectedItem(); final IElementaryConditionController conditionController = filterController.getConditionFactory() .getConditionController(selectedProperty); final NamedObject selectedCondition = (NamedObject) elementaryConditions.getSelectedItem(); final boolean canSelectValues = conditionController .canSelectValues(selectedProperty, selectedCondition); values.setEnabled(canSelectValues); values.setEditable(false); values.setModel(conditionController.getValuesForProperty(selectedProperty, selectedCondition)); final ComboBoxEditor valueEditor = conditionController.getValueEditor(selectedProperty, selectedCondition); values.setEditor(valueEditor != null ? valueEditor : new FixedBasicComboBoxEditor()); setValuesEnterKeyListener(); final ListCellRenderer valueRenderer = conditionController.getValueRenderer(selectedProperty, selectedCondition); values.setRenderer(valueRenderer != null ? valueRenderer : filterController.getConditionRenderer()); values.setEditable(conditionController.canEditValues(selectedProperty, selectedCondition)); if (values.getModel().getSize() > 0) { values.setSelectedIndex(0); } caseSensitive.setEnabled(canSelectValues && conditionController.isCaseDependent(selectedProperty, selectedCondition)); approximateMatching.setEnabled(canSelectValues && conditionController.supportsApproximateMatching(selectedProperty, selectedCondition)); } /** * */ private static final long serialVersionUID = 1L; private static final String PROPERTY_FILTER_MATCH_CASE = "filter_match_case"; private static final String PROPERTY_FILTER_MATCH_CASE_TOOLTIP = "filter_match_case_tooltip"; private static final String PROPERTY_FILTER_APPROXIMATE_MATCH = "filter_match_approximately"; private static final String PROPERTY_FILTER_APPROXIMATE_MATCH_TOOLTIP = "filter_match_approximately_tooltip"; final private JCheckBox caseSensitive; final private JCheckBox approximateMatching; final private JComboBox elementaryConditions; final private FilterController filterController; final private JComboBox filteredPropertiesComponent; final private ExtendedComboBoxModel filteredPropertiesModel; private WeakReference<MapModel> lastMap; final private JComboBox values; private ActionListener enterKeyActionListener; public FilterConditionEditor(final FilterController filterController) { this(filterController, 5, false); } public FilterConditionEditor(final FilterController filterController, final int borderWidth, final boolean horizontal) { super(); setLayout(new GridBagLayout()); final GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.NORTH; gridBagConstraints.insets = new Insets(0, borderWidth, 0, borderWidth); this.filterController = filterController; //Basic layout //Item to search for filteredPropertiesComponent = new JComboBox(); filteredPropertiesModel = new ExtendedComboBoxModel(); filteredPropertiesComponent.setModel(filteredPropertiesModel); filteredPropertiesComponent.addItemListener(new FilteredPropertyChangeListener()); add(Box.createHorizontalGlue(), gridBagConstraints); gridBagConstraints.gridx++; filteredPropertiesComponent.setAlignmentY(Component.TOP_ALIGNMENT); add(filteredPropertiesComponent, gridBagConstraints); gridBagConstraints.gridx++; filteredPropertiesComponent.setRenderer(filterController.getConditionRenderer()); //Search condition elementaryConditions = new JComboBox(); elementaryConditions.addItemListener(new ElementaryConditionChangeListener()); elementaryConditions.setAlignmentY(Component.TOP_ALIGNMENT); add(elementaryConditions, gridBagConstraints); gridBagConstraints.gridx++; elementaryConditions.setRenderer(filterController.getConditionRenderer()); //Search value values = new JComboBox(); values.setPreferredSize(new Dimension(240,20)); gridBagConstraints.anchor = GridBagConstraints.WEST; add(values, gridBagConstraints); if(horizontal){ gridBagConstraints.gridx++; } else{ gridBagConstraints.gridy++; } values.setEditable(true); setValuesEnterKeyListener(); JPanel ignoreCaseAndApproximateMatchingPanel = new JPanel(); ignoreCaseAndApproximateMatchingPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); // Ignore case checkbox caseSensitive = new JCheckBox(); caseSensitive.setModel(filterController.getCaseSensitiveButtonModel()); caseSensitive.setToolTipText(TextUtils.getRawText(PROPERTY_FILTER_MATCH_CASE_TOOLTIP)); //add(caseSensitive, gridBagConstraints); ignoreCaseAndApproximateMatchingPanel.add(caseSensitive); //gridBagConstraints.gridx++; MenuBuilder.setLabelAndMnemonic(caseSensitive,TextUtils.getRawText(PROPERTY_FILTER_MATCH_CASE)); caseSensitive.setSelected(ResourceController.getResourceController().getBooleanProperty( PROPERTY_FILTER_MATCH_CASE)); // add approximate matching checkbox approximateMatching = new JCheckBox(); approximateMatching.setModel(filterController.getApproximateMatchingButtonModel()); approximateMatching.setToolTipText(TextUtils.getRawText(PROPERTY_FILTER_APPROXIMATE_MATCH_TOOLTIP)); MenuBuilder.setLabelAndMnemonic(approximateMatching, TextUtils.getRawText(PROPERTY_FILTER_APPROXIMATE_MATCH)); //add(approximateMatching, gridBagConstraints); ignoreCaseAndApproximateMatchingPanel.add(approximateMatching); approximateMatching.setSelected(ResourceController.getResourceController().getBooleanProperty( PROPERTY_FILTER_APPROXIMATE_MATCH)); mapChanged(Controller.getCurrentController().getMap()); add(ignoreCaseAndApproximateMatchingPanel, gridBagConstraints); } public void focusInputField(final boolean selectAll) { if (values.isEnabled()) { values.requestFocusInWindow(); final Component editorComponent = values.getEditor().getEditorComponent(); if (selectAll && editorComponent instanceof JTextComponent) { ((JTextComponent) editorComponent).selectAll(); } return; } } public boolean isInputFieldFocused(){ if (values.isFocusOwner()) return true; if (values.isPopupVisible() || values.getEditor().getEditorComponent().isFocusOwner()) return true; return false; } public ASelectableCondition getCondition() { ASelectableCondition newCond; Object value; if(values.isEditable()){ value = values.getEditor().getItem(); } else{ value = values.getSelectedItem(); } if (value == null) { value = ""; } final NamedObject simpleCond = (NamedObject) elementaryConditions.getSelectedItem(); final boolean matchCase = caseSensitive.isSelected(); final boolean matchApproximately = approximateMatching.isSelected(); ResourceController.getResourceController().setProperty(PROPERTY_FILTER_MATCH_CASE, matchCase); final Object selectedItem = filteredPropertiesComponent.getSelectedItem(); newCond = filterController.getConditionFactory().createCondition(selectedItem, simpleCond, value, matchCase, matchApproximately); if (values.isEditable()) { if (!value.equals("")) { DefaultComboBoxModel list = (DefaultComboBoxModel) values.getModel(); int indexOfValue = list.getIndexOf(value); if(indexOfValue > 0) list.removeElementAt(indexOfValue); if(indexOfValue == -1 || list.getIndexOf(value) != indexOfValue){ values.insertItemAt(value, 0); values.setSelectedIndex(0); } else if(indexOfValue != -1){ values.setSelectedIndex(indexOfValue); } if (values.getItemCount() >= 10) { values.removeItemAt(9); } } } return newCond; } /** */ public void mapChanged(final MapModel newMap) { if (newMap != null) { if (lastMap != null && lastMap.get() == newMap) { return; } filteredPropertiesModel.removeAllElements(); final Iterator<IElementaryConditionController> conditionIterator = filterController.getConditionFactory() .conditionIterator(); while (conditionIterator.hasNext()) { final IElementaryConditionController next = conditionIterator.next(); filteredPropertiesModel.addExtensionList(next.getFilteredProperties()); filteredPropertiesModel.setSelectedItem(filteredPropertiesModel.getElementAt(0)); } } else { filteredPropertiesComponent.setSelectedIndex(-1); filteredPropertiesModel.setExtensionList(null); } lastMap = new WeakReference<MapModel>(newMap); } public void setEnterKeyActionListener(ActionListener enterKeyActionListener) { if (enterKeyActionListener == null) { throw new NullPointerException("null value in setEnterKeyActionListener()!"); } if (this.enterKeyActionListener != null) { values.getEditor().removeActionListener(this.enterKeyActionListener); } this.enterKeyActionListener = enterKeyActionListener; values.getEditor().addActionListener(enterKeyActionListener); } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); for(int i = 0; i < getComponentCount(); i++){ Component c = getComponent(i); c.setEnabled(enabled); if (c instanceof JComboBox) ((JComboBox)c).getEditor().getEditorComponent().setEnabled(enabled); } } }