/* * Copyright (C) 2011 Andrea Schweer * * This file is part of the Digital Parrot. * * The Digital Parrot is free software; you can redistribute it and/or modify * it under the terms of the Eclipse Public License as published by the Eclipse * Foundation or its Agreement Steward, either version 1.0 of the License, or * (at your option) any later version. * * The Digital Parrot 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 Eclipse Public License for * more details. * * You should have received a copy of the Eclipse Public License along with the * Digital Parrot. If not, see http://www.eclipse.org/legal/epl-v10.html. * */ package net.schweerelos.parrot.ui; import java.awt.Cursor; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.Collections; import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import net.schweerelos.parrot.model.Filter; import net.schweerelos.parrot.model.NodeWrapper; import net.schweerelos.parrot.model.filters.TextFilter; @SuppressWarnings("serial") public class TextFilterComponent extends AbstractNavigatorPanel { private static final String NAME = "Search"; private static final String ACCELERATOR_KEY = "S"; private JTextField queryBox; protected TextFilter lastFilter; private JLabel resultsLabel; public TextFilterComponent() { super(); setLayout(new GridBagLayout()); GridBagConstraints constraints = new GridBagConstraints(); constraints.insets.right = 12; constraints.insets.left = 12; constraints.fill = GridBagConstraints.BOTH; constraints.anchor = GridBagConstraints.BASELINE_LEADING; constraints.gridwidth = GridBagConstraints.REMAINDER; JLabel label = new JLabel("Text:"); label.setDisplayedMnemonic('t'); constraints.fill = GridBagConstraints.NONE; constraints.gridwidth = 1; constraints.weighty = 0; add(label, constraints); queryBox = new JTextField(); queryBox.setToolTipText("Highlight everything that contains this text"); queryBox.setColumns(20); constraints.insets.right = 0; constraints.fill = GridBagConstraints.HORIZONTAL; constraints.weightx = 1; add(queryBox, constraints); label.setLabelFor(queryBox); AbstractAction queryAction = new AbstractAction("Search") { @Override public void actionPerformed(ActionEvent e) { if (getModel() == null) { return; } if (lastFilter != null) { removeFilterFromModel(lastFilter); } if (queryBox.getText() != null && !queryBox.getText().isEmpty()) { lastFilter = new TextFilter(queryBox.getText()); addFilterToModel(lastFilter); queryBox.selectAll(); } } }; queryAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_S); constraints.fill = GridBagConstraints.NONE; constraints.insets.left = 11; constraints.weightx = 0; constraints.gridwidth = GridBagConstraints.REMAINDER; add(new JButton(queryAction), constraints); queryBox.addActionListener(queryAction); resultsLabel = new JLabel(); resultsLabel.setFont(resultsLabel.getFont().deriveFont(Font.PLAIN)); clearResultsLabel(); constraints.insets.right = 12; constraints.insets.top = 11; constraints.fill = GridBagConstraints.BOTH; constraints.anchor = GridBagConstraints.FIRST_LINE_START; constraints.weighty = 1; add(resultsLabel, constraints); } private void clearResultsLabel() { setResultsLabelText(" <br> "); } private void setResultsLabelText(String text) { resultsLabel.setText("<html>" + text + "</html>"); } @Override protected void activateFilters() { if (lastFilter != null && getModel() != null) { addFilterToModel(lastFilter); } } @Override protected void deactivateFilters() { if (lastFilter != null && getModel() != null) { removeFilterFromModel(lastFilter); } } private void addFilterToModel(final Filter filter) { setResultsLabelText("Searching..."); SwingUtilities.getWindowAncestor(this).setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { @Override protected Void doInBackground() throws Exception { getModel().addFilter(filter); return null; } @Override protected void done() { int numberOfHits = lastFilter.getNumberOfMatches(); String queryString = lastFilter.getQueryString(); if (numberOfHits <= 0) { setResultsLabelText("No results for <em>" + queryString + "</em>.<br>Try adding * to your query term(s) to get partial matches."); } else if (numberOfHits == 1) { setResultsLabelText("1 result for <em>" + queryString + "</em>."); } else { setResultsLabelText(numberOfHits + " results for <em>" + queryString + "</em>."); } SwingUtilities.getWindowAncestor(TextFilterComponent.this).setCursor(Cursor.getDefaultCursor()); } }; worker.execute(); } private void removeFilterFromModel(final Filter filter) { SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { @Override protected Void doInBackground() throws Exception { getModel().removeFilter(filter); return null; } @Override protected void done() { clearResultsLabel(); } }; worker.execute(); } @Override public List<Action> getActionsForNode(NodeWrapper currentNode) { return Collections.emptyList(); } @Override public List<Action> getActionsForType(NodeWrapper type) { return Collections.emptyList(); } @Override public String getNavigatorName() { return NAME; } @Override public String getAcceleratorKey() { return ACCELERATOR_KEY; } }