/*
* org.openmicroscopy.shoola.agents.treeviewer.finder.Finder
*
*------------------------------------------------------------------------------
* Copyright (C) 2006 University of Dundee. All rights reserved.
*
*
* 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*------------------------------------------------------------------------------
*/
package org.openmicroscopy.shoola.agents.treeviewer.finder;
//Java imports
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Point;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
//Third-party libraries
//Application-internal dependencies
import org.openmicroscopy.shoola.agents.treeviewer.TreeViewerAgent;
import org.openmicroscopy.shoola.agents.treeviewer.view.TreeViewer;
import org.openmicroscopy.shoola.env.ui.UserNotifier;
import org.openmicroscopy.shoola.util.ui.RegExFactory;
/**
* The Finder component.
*
* @author Jean-Marie Burel
* <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
* @version 2.2
* <small>
* (<b>Internal version:</b> $Revision$Date: )
* </small>
* @since OME2.2
*/
public class Finder
extends JPanel
{
/** Bound property indicating that some text has been entered. */
public static final String TEXT_ENTERED_PROPERTY = "textEntered";
/** Bound property indicating the find level. */
public static final String LEVEL_PROPERTY = "level";
/** Bound property indicating the number of elements retrieved. */
public static final String RETRIEVED_PROPERTY = "retrieved";
/** The UI delegate. */
private FinderUI uiDelegate;
/** The Model. */
private FinderModel model;
/** The control. */
private FinderControl controller;
/** Indicates if we already search for the phrase. */
private boolean found;
/** Builds and lays out the GUI. */
private void buildGUI()
{
setLayout(new BorderLayout(5, 5));
setBorder(BorderFactory.createEmptyBorder());
add(uiDelegate, BorderLayout.CENTER);
}
/**
* Creates a new instance.
*
* @param parentComponent Back pointer to the parent's model.
* Mustn't be <code>null</code>.
*/
public Finder(TreeViewer parentComponent)
{
if (parentComponent == null)
throw new IllegalArgumentException("No parent component.");
found = false;
model = new FinderModel(parentComponent);
controller = new FinderControl(this);
parentComponent.addPropertyChangeListener(
TreeViewer.FINDER_VISIBLE_PROPERTY, controller);
uiDelegate = new FinderUI(this, controller, model);
controller.initialize(uiDelegate);
buildGUI();
}
/**
* Sets to <code>true</code> if the find action applies to the name
* field, <code>false</code> otherwise.
*
* @param b The value to set.
*/
void setNameSelected(boolean b)
{
if (b == model.isNameSelected()) return;
found = false;
Boolean oldValue =
model.isNameSelected() ? Boolean.TRUE : Boolean.FALSE,
newValue = b ? Boolean.TRUE : Boolean.FALSE;
model.setNameSelected(b);
firePropertyChange(LEVEL_PROPERTY, oldValue, newValue);
}
/**
* Sets to <code>true</code> if the find action applies to the description
* field, <code>false</code> otherwise.
*
* @param b The value to set.
*/
void setDescriptionSelected(boolean b)
{
if (b == model.isDescriptionSelected()) return;
found = false;
Boolean oldValue =
model.isDescriptionSelected() ? Boolean.TRUE : Boolean.FALSE,
newValue = b ? Boolean.TRUE : Boolean.FALSE;
model.setDescriptionSelected(b);
firePropertyChange(LEVEL_PROPERTY, oldValue, newValue);
}
/**
* Sets to <code>true</code> if the find action applies to the annotation
* field, <code>false</code> otherwise.
*
* @param b The value to set.
*/
void setAnnotationSelected(boolean b)
{
if (b == model.isAnnotationSelected()) return;
found = false;
Boolean oldValue =
model.isAnnotationSelected() ? Boolean.TRUE : Boolean.FALSE,
newValue = b ? Boolean.TRUE : Boolean.FALSE;
model.setAnnotationSelected(b);
firePropertyChange(LEVEL_PROPERTY, oldValue, newValue);
}
/**
* Sets the text.
*
* @param text The text to set.
*/
void setTextUpdate(String text)
{
found = false;
String oldValue = model.getFindText();
model.setFindText(text);
firePropertyChange(TEXT_ENTERED_PROPERTY, oldValue, text);
}
/**
* Sets the value of the case sensitive field.
*
* @param b The value to set.
*/
void setCaseSensitive(boolean b)
{
if (b == model.isCaseSensitive()) return;
found = false;
model.setCaseSensitive(b);
}
/**
* Returns the value of the case sensitive field.
*
* @return See above.
*/
boolean isCaseSensitive() { return model.isCaseSensitive(); }
/**
* Returns <code>true</code> if there is some text is entered in the text
* area, <code>false</code> if no text selected.
*
* @return See above.
*/
boolean isTextEmpty()
{
return (model.getFindText().length() == 0);
}
/** Removes the component from the display. */
void close()
{
if (!model.isDisplay()) return;
model.getParentComponent().showFinder(false);
}
/**
* Returns <code>true</code> if the find action applies to the name
* field, <code>false</code> otherwise.
*
* @return See above.
*/
boolean isNameSelected() { return model.isNameSelected(); }
/**
* Returns <code>true</code> if the find action applies to the description
* field, <code>false</code> otherwise.
*
* @return See above.
*/
boolean isDescriptionSelected() { return model.isDescriptionSelected(); }
/**
* Returns <code>true</code> if the find action applies to the annotation
* field, <code>false</code> otherwise.
*
* @return See above.
*/
boolean isAnnotationSelected() { return model.isAnnotationSelected(); }
/**
* Brings up the popup menu on top of the specified component at the
* specified point.
*
* @param c The component that requested the popup menu.
* @param p The point at which to display the menu, relative to the
* <code>component</code>'s coordinates.
*/
void showMenu(Component c, Point p)
{
if (c == null) throw new IllegalArgumentException("No component.");
if (p == null) throw new IllegalArgumentException("No point.");
uiDelegate.showPopup(c, p);
}
/** Finds the phrase in the currently selected browser. */
void find()
{
TreeViewer pc = model.getParentComponent();
if (pc.getSelectedBrowser() == null) return;
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
try {
String findText = model.getFindText();
Pattern p;
if (!model.isCaseSensitive())
p = RegExFactory.createCaseInsensitivePattern(findText);
else p = RegExFactory.createPattern(findText);
RegExVisitor visitor = new RegExVisitor(this, p);
pc.getSelectedBrowser().accept(visitor);
Set set = visitor.getFoundNodes();
pc.getSelectedBrowser().setFoundInBrowser(set);
found = true;
model.addToHistory(findText);
firePropertyChange(RETRIEVED_PROPERTY, Integer.valueOf(-1),
Integer.valueOf(set.size()));
} catch (PatternSyntaxException pse) {
UserNotifier un = TreeViewerAgent.getRegistry().getUserNotifier();
un.notifyInfo("Find", "The phrase contains non valid characters.");
}
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
/** Finds the next occurence of the phrase. */
void findNext()
{
if (!found) find();
else {
TreeViewer pc = model.getParentComponent();
if (pc.getSelectedBrowser() == null) return;
pc.getSelectedBrowser().findNext();
}
}
/** Finds the previous occurence of the phrase. */
void findPrevious()
{
if (!found) find();
else {
TreeViewer pc = model.getParentComponent();
if (pc.getSelectedBrowser() == null) return;
pc.getSelectedBrowser().findPrevious();
}
}
/**
* Sets the following value.
*
* @param b The value to set.
*/
void setDisplay(boolean b) { model.setDisplay(b); }
/**
* Returns <code>true</code> if the {@link Finder} is visible,
* <code>false</code> otherwise.
*
* @return See above.
*/
public boolean isDisplay() { return model.isDisplay(); }
}