Use internal SNAPSHOT couplings again
[trakem2.git] / TrakEM2_ / src / main / java / ini / trakem2 / utils / Search.java
blob4e93d7bfc5d411bbf3da24fc959053cc5004ecf5
1 /**
3 TrakEM2 plugin for ImageJ(C).
4 Copyright (C) 2005-2009 Albert Cardona and Rodney Douglas.
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation (http://www.gnu.org/licenses/gpl.txt )
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 You may contact Albert Cardona at acardona at ini.phys.ethz.ch
20 Institute of Neuroinformatics, University of Zurich / ETH, Switzerland.
21 **/
23 package ini.trakem2.utils;
25 import ij.gui.GenericDialog;
26 import ini.trakem2.ControlWindow;
27 import ini.trakem2.Project;
28 import ini.trakem2.display.AreaList;
29 import ini.trakem2.display.AreaTree;
30 import ini.trakem2.display.Ball;
31 import ini.trakem2.display.Connector;
32 import ini.trakem2.display.Coordinate;
33 import ini.trakem2.display.DLabel;
34 import ini.trakem2.display.Display;
35 import ini.trakem2.display.Display3D;
36 import ini.trakem2.display.Displayable;
37 import ini.trakem2.display.Dissector;
38 import ini.trakem2.display.Layer;
39 import ini.trakem2.display.LayerSet;
40 import ini.trakem2.display.Node;
41 import ini.trakem2.display.Patch;
42 import ini.trakem2.display.Pipe;
43 import ini.trakem2.display.Polyline;
44 import ini.trakem2.display.Profile;
45 import ini.trakem2.display.Tag;
46 import ini.trakem2.display.Tree;
47 import ini.trakem2.display.Treeline;
48 import ini.trakem2.display.ZDisplayable;
49 import ini.trakem2.persistence.DBObject;
50 import ini.trakem2.persistence.FSLoader;
51 import ini.trakem2.tree.ProjectThing;
53 import java.awt.Dimension;
54 import java.awt.GridBagConstraints;
55 import java.awt.GridBagLayout;
56 import java.awt.Insets;
57 import java.awt.Rectangle;
58 import java.awt.event.ActionEvent;
59 import java.awt.event.ActionListener;
60 import java.awt.event.KeyAdapter;
61 import java.awt.event.KeyEvent;
62 import java.awt.event.KeyListener;
63 import java.awt.event.MouseAdapter;
64 import java.awt.event.MouseEvent;
65 import java.awt.event.WindowAdapter;
66 import java.awt.event.WindowEvent;
67 import java.io.File;
68 import java.util.ArrayList;
69 import java.util.Collection;
70 import java.util.Collections;
71 import java.util.HashMap;
72 import java.util.HashSet;
73 import java.util.Iterator;
74 import java.util.List;
75 import java.util.Map;
76 import java.util.Set;
77 import java.util.Vector;
78 import java.util.regex.Pattern;
80 import javax.swing.JButton;
81 import javax.swing.JComboBox;
82 import javax.swing.JFrame;
83 import javax.swing.JLabel;
84 import javax.swing.JMenuItem;
85 import javax.swing.JPanel;
86 import javax.swing.JPopupMenu;
87 import javax.swing.JScrollPane;
88 import javax.swing.JTabbedPane;
89 import javax.swing.JTable;
90 import javax.swing.JTextField;
91 import javax.swing.SwingUtilities;
92 import javax.swing.table.AbstractTableModel;
93 import javax.swing.table.TableModel;
95 public class Search {
96 private JFrame search_frame = null;
97 private JTabbedPane search_tabs = null;
98 private JTextField search_field = null;
99 private JComboBox pulldown = null;
100 private KeyListener kl = null;
101 private JComboBox projects = null;
102 private Map<Project, List<JPanel>> tabMap = Collections
103 .synchronizedMap(new HashMap<Project, List<JPanel>>());
105 static private Search instance = null;
107 private Class<?>[] types = null;
109 static public final void showWindow() {
110 if (null != instance) {
111 instance.makeGUI();
112 } else {
113 instance = new Search();
117 /** Creates the GUI for searching text in any TrakEM2 element. */
118 private Search() {
119 types = new Class[] { DBObject.class, Displayable.class, DLabel.class,
120 Patch.class, AreaList.class, Profile.class, Pipe.class,
121 Ball.class, Layer.class, Dissector.class, Polyline.class,
122 Treeline.class, AreaTree.class, Connector.class };
123 makeGUI();
126 private void tryCloseTab(KeyEvent ke) {
127 switch (ke.getKeyCode()) {
128 case KeyEvent.VK_W:
129 if (!ke.isControlDown())
130 return;
131 int ntabs = search_tabs.getTabCount();
132 if (0 == ntabs) {
133 instance.destroy();
134 return;
136 search_tabs.remove(search_tabs.getSelectedIndex());
137 return;
138 default:
139 return;
143 private void makeGUI() {
144 // create GUI if not there
145 if (null == search_frame) {
146 search_frame = ControlWindow
147 .createJFrame("Search Regular Expressions");
148 search_frame.addWindowListener(new WindowAdapter() {
149 public void windowClosing(WindowEvent we) {
150 instance.destroy();
153 search_tabs = new JTabbedPane(JTabbedPane.TOP);
154 kl = new KeyAdapter() {
155 public void keyPressed(KeyEvent ke) {
156 tryCloseTab(ke);
159 search_tabs.addKeyListener(kl);
160 search_field = new JTextField(14);
161 search_field.addKeyListener(new VKEnterListener());
163 GridBagLayout gb = new GridBagLayout();
164 GridBagConstraints c = new GridBagConstraints();
165 JPanel all = new JPanel();
166 all.setLayout(gb);
167 all.setPreferredSize(new Dimension(600, 400));
169 JButton b = new JButton("Search");
170 b.addActionListener(new ButtonListener());
171 pulldown = new JComboBox(new String[] { "All", "All displayables",
172 "Labels", "Images", "Area Lists", "Profiles", "Pipes",
173 "Balls", "Layers", "Dissectors", "Polylines", "Treelines",
174 "AreaTrees", "Connectors" });
176 List<Project> ps = Project.getProjects();
177 String[] sps = new String[ps.size()];
178 int k = 0;
179 for (final Project p : ps)
180 sps[k++] = p.getTitle();
181 this.projects = new JComboBox(sps);
182 Display front = Display.getFront();
183 if (null != front)
184 this.projects.setSelectedIndex(ps.indexOf(front.getProject()));
186 c.gridx = 0;
187 c.gridy = 0;
188 c.fill = GridBagConstraints.HORIZONTAL;
189 c.weightx = 1;
190 c.insets = new Insets(4, 10, 5, 2);
191 gb.setConstraints(search_field, c);
192 all.add(search_field);
194 c.gridx = 1;
195 c.weightx = 0;
196 c.insets = new Insets(4, 2, 5, 10);
197 gb.setConstraints(b, c);
198 all.add(b);
200 c.gridx = 2;
201 gb.setConstraints(pulldown, c);
202 all.add(pulldown);
204 c.gridx = 3;
205 gb.setConstraints(projects, c);
206 all.add(projects);
208 c.gridx = 0;
209 c.gridy = 1;
210 c.gridwidth = 4;
211 c.weightx = 1;
212 c.weighty = 1;
213 c.fill = GridBagConstraints.BOTH;
214 c.insets = new Insets(0, 0, 0, 0);
215 gb.setConstraints(search_tabs, c);
216 all.add(search_tabs);
218 search_frame.getContentPane().add(all);
219 search_frame.pack();
220 javax.swing.SwingUtilities.invokeLater(new Runnable() {
221 public void run() {
222 ij.gui.GUI.center(search_frame);
223 search_frame.setVisible(true);
226 } else {
227 search_frame.toFront();
231 synchronized private void destroy() {
232 if (null != instance) {
233 if (null != search_frame)
234 search_frame.dispose();
235 search_frame = null;
236 search_tabs = null;
237 search_field = null;
238 pulldown = null;
239 types = null;
240 kl = null;
241 // deregister
242 instance = null;
243 tabMap.clear();
247 private class DisplayableTableModel extends AbstractTableModel {
248 private static final long serialVersionUID = 1L;
249 private Vector<DBObject> v_obs;
250 private Vector<String> v_txt;
251 private Vector<Coordinate<?>> v_co;
253 DisplayableTableModel(Vector<DBObject> v_obs, Vector<String> v_txt,
254 Vector<Coordinate<?>> v_co) {
255 super();
256 this.v_obs = v_obs;
257 this.v_txt = v_txt;
258 this.v_co = v_co;
261 public String getColumnName(int col) {
262 if (0 == col)
263 return "Type";
264 else if (1 == col)
265 return "Info";
266 else if (2 == col)
267 return "Matched";
268 else
269 return "";
272 public int getRowCount() {
273 return v_obs.size();
276 public int getColumnCount() {
277 return 3;
280 public Object getValueAt(int row, int col) {
281 if (0 == col)
282 return Project.getName(v_obs.get(row).getClass());
283 else if (1 == col)
284 return v_obs.get(row).getShortTitle();
285 else if (2 == col)
286 return v_txt.get(row);
287 else
288 return "";
291 public DBObject getDBObjectAt(int row) {
292 return (DBObject) v_obs.get(row);
296 * public Displayable getDisplayableAt(int row) { return
297 * (Displayable)v_obs.get(row); }
299 public Coordinate<?> getCoordinateAt(int row) {
300 return v_co.get(row);
303 public boolean isCellEditable(int row, int col) {
304 return false;
307 public void setValueAt(Object value, int row, int col) {
308 // nothing
309 // fireTableCellUpdated(row, col);
312 public boolean remove(Displayable displ) {
313 int i = v_obs.indexOf(displ);
314 if (-1 != i) {
315 v_obs.remove(i);
316 v_txt.remove(i);
317 v_co.remove(i);
318 return true;
320 return false;
323 public boolean contains(Object ob) {
324 return v_obs.contains(ob);
328 private void executeSearch() {
329 final Project project = Project.getProjects().get(
330 projects.getSelectedIndex());
331 if (null == project) {
332 // Should not happen
333 return;
335 Bureaucrat.createAndStart(new Worker.Task("Searching") {
336 public void exec() {
338 String pattern = search_field.getText();
339 if (null == pattern || 0 == pattern.length()) {
340 return;
342 // fix pattern
343 final String typed_pattern = pattern;
344 final StringBuilder sb = new StringBuilder(); // I hate java
345 if (!pattern.startsWith("^"))
346 sb.append("^.*");
347 for (int i = 0; i < pattern.length(); i++) {
348 sb.append(pattern.charAt(i));
350 if (!pattern.endsWith("$"))
351 sb.append(".*$");
352 pattern = sb.toString();
353 final Pattern pat = Pattern.compile(pattern,
354 Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
355 | Pattern.DOTALL);
356 // Utils.log2("pattern after: " + pattern);
357 final ArrayList<DBObject> al = new ArrayList<DBObject>();
358 // Utils.log("types[pulldown] = " +
359 // types[pulldown.getSelectedIndex()]);
360 find(project.getRootLayerSet(), al,
361 types[pulldown.getSelectedIndex()]);
362 // Utils.log2("found labels: " + al.size());
363 if (0 == al.size())
364 return;
365 final Vector<DBObject> v_obs = new Vector<DBObject>();
366 final Vector<String> v_txt = new Vector<String>();
367 final Vector<Coordinate<?>> v_co = new Vector<Coordinate<?>>();
368 Coordinate<?> co = null;
369 for (final DBObject dbo : al) {
370 if (Thread.currentThread().isInterrupted()) {
371 return;
373 boolean matched = false;
374 // Search in its title
375 Displayable d = null;
376 if (dbo instanceof Displayable) {
377 d = (Displayable) dbo;
379 String txt;
380 String meaningful_title = null;
381 if (null == d || Patch.class == d.getClass())
382 txt = dbo.getTitle();
383 else {
384 txt = meaningful_title = dbo.getProject()
385 .getMeaningfulTitle(d);
388 if (null == txt || 0 == txt.trim().length())
389 continue;
390 matched = pat.matcher(txt).matches();
391 if (!matched && null != d) {
392 // Search also in its annotation
393 txt = d.getAnnotation();
394 if (null != txt)
395 matched = pat.matcher(txt).matches();
397 if (!matched) {
398 // Search also in its toString()
399 txt = dbo.toString();
400 matched = pat.matcher(txt).matches();
402 if (!matched) {
403 // Search also in its id
404 txt = Long.toString(dbo.getId());
405 matched = pat.matcher(txt).matches();
406 if (matched)
407 txt = "id: #" + txt;
409 if (!matched && null != d) {
410 // Search also in its properties
411 Map<String, String> props = d.getProperties();
412 if (null != props) {
413 for (final Map.Entry<String, String> e : props
414 .entrySet()) {
415 if (pat.matcher(e.getKey()).matches()
416 || pat.matcher(e.getValue()).matches()) {
417 matched = true;
418 txt = e.getKey() + " => " + e.getValue()
419 + " [property]";
420 break;
424 if (!matched) {
425 Map<Displayable, Map<String, String>> linked_props = ((Displayable) dbo)
426 .getLinkedProperties();
427 if (null != linked_props) {
428 for (final Map.Entry<Displayable, Map<String, String>> e : linked_props
429 .entrySet()) {
430 for (final Map.Entry<String, String> ee : e
431 .getValue().entrySet()) {
432 if (pat.matcher(ee.getKey()).matches()
433 || pat.matcher(ee.getValue())
434 .matches()) {
435 matched = true;
436 txt = ee.getKey() + " => "
437 + e.getValue()
438 + " [linked property]";
439 break;
446 if (!matched && dbo instanceof Tree<?>) {
447 // search Node tags
448 Node<?> root = ((Tree<?>) dbo).getRoot();
449 if (null == root)
450 continue;
451 for (final Node<?> nd : root.getSubtreeNodes()) {
452 Set<Tag> tags = nd.getTags();
453 if (null == tags)
454 continue;
455 for (final Tag tag : tags) {
456 if (pat.matcher(tag.toString()).matches()) {
457 v_obs.add(dbo);
458 v_txt.add(new StringBuilder(tag.toString())
459 .append(" (")
460 .append(null == meaningful_title ? dbo
461 .toString()
462 : meaningful_title)
463 .append(')').toString());
464 v_co.add(createCoordinate((Tree<?>) dbo, nd));
468 continue; // all added if any
471 if (!matched)
472 continue;
474 // txt = txt.length() > 30 ? txt.substring(0, 27) + "..." :
475 // txt;
476 v_obs.add(dbo);
477 v_txt.add(txt);
478 v_co.add(co);
481 if (0 == v_obs.size()) {
482 Utils.showMessage("Nothing found.");
483 return;
485 final JPanel result = new JPanel();
486 GridBagLayout gb = new GridBagLayout();
487 result.setLayout(gb);
488 GridBagConstraints c = new GridBagConstraints();
489 c.anchor = GridBagConstraints.NORTHWEST;
490 c.fill = GridBagConstraints.HORIZONTAL;
491 c.insets = new Insets(5, 10, 5, 10);
492 String xml = "";
493 if (project.getLoader() instanceof FSLoader) {
494 String path = ((FSLoader) project.getLoader())
495 .getProjectXMLPath();
496 if (null != path) {
497 xml = " [" + new File(path).getName() + "]";
500 JLabel projectTitle = new JLabel(project.getTitle() + xml);
501 gb.setConstraints(projectTitle, c);
502 result.add(projectTitle);
503 c.insets = new Insets(0, 0, 0, 0);
504 JPanel padding = new JPanel();
505 c.weightx = 1;
506 gb.setConstraints(padding, c);
507 result.add(padding);
508 c.gridy = 1;
509 c.gridwidth = 2;
510 c.fill = GridBagConstraints.BOTH;
511 c.weighty = 1;
512 JScrollPane jsp = makeTable(new DisplayableTableModel(v_obs,
513 v_txt, v_co), project);
514 gb.setConstraints(jsp, c);
515 result.add(jsp);
516 search_tabs.addTab(typed_pattern, result);
517 search_tabs.setSelectedComponent(result);
519 synchronized (tabMap) {
520 List<JPanel> cs = tabMap.get(project);
521 if (null == cs) {
522 cs = new ArrayList<JPanel>();
523 tabMap.put(project, cs);
525 cs.add(result);
529 }, project);
532 private Coordinate<Node<?>> createCoordinate(Tree<?> tree, Node<?> nd) {
533 double x = nd.getX(), y = nd.getY();
534 if (!tree.getAffineTransform().isIdentity()) {
535 double[] dp = new double[] { x, y };
536 tree.getAffineTransform().transform(dp, 0, dp, 0, 1);
537 x = dp[0];
538 y = dp[1];
540 return new Coordinate<Node<?>>(x, y, nd.getLayer(), nd);
543 private Coordinate<Displayable> createCoordinate(final Displayable d) {
544 Rectangle r = d.getBoundingBox();
545 Layer la = d instanceof ZDisplayable ? ((ZDisplayable) d)
546 .getFirstLayer() : d.getLayer();
547 if (null == la) {
548 Display display = Display.getFront(d.getProject());
549 if (null == display)
550 la = d.getProject().getRootLayerSet().getLayer(0);
551 else
552 la = display.getLayer();
554 return new Coordinate<Displayable>(r.x + r.width / 2, r.y + r.height
555 / 2, la, d);
558 private class Results extends JTable {
559 private final Project project;
560 private Results(TableModel model, Project project) {
561 super(model);
562 this.project = project;
566 private JScrollPane makeTable(TableModel model, Project project) {
567 JTable table = new Results(model, project);
568 // java 1.6.0 only!! //table.setAutoCreateRowSorter(true);
569 table.addMouseListener(new DisplayableListListener());
570 table.addKeyListener(kl);
571 JScrollPane jsp = new JScrollPane(table);
572 jsp.setPreferredSize(new Dimension(500, 500));
573 return jsp;
576 /** Listen to the search button. */
577 private class ButtonListener implements ActionListener {
578 public void actionPerformed(ActionEvent ae) {
579 executeSearch();
583 /** Listen to the search field. */
584 private class VKEnterListener extends KeyAdapter {
585 public void keyPressed(KeyEvent ke) {
586 if (ke.getKeyCode() == KeyEvent.VK_ENTER) {
587 executeSearch();
588 return;
590 tryCloseTab(ke);
594 /** Listen to double clicks in the table rows. */
595 private class DisplayableListListener extends MouseAdapter {
596 public void mousePressed(MouseEvent me) {
597 final Results table = (Results) me.getSource();
598 final int row = table.rowAtPoint(me.getPoint());
599 final DBObject ob = ((DisplayableTableModel) table.getModel())
600 .getDBObjectAt(row);
601 final Coordinate<?> co = ((DisplayableTableModel) table.getModel())
602 .getCoordinateAt(row);
604 if (2 == me.getClickCount()) {
605 if (null != co) {
606 Display.centerAt(co);
607 } else if (ob instanceof Displayable) {
608 // no zoom
609 Display.centerAt(createCoordinate((Displayable) ob), true,
610 me.isShiftDown());
611 } else if (ob instanceof Layer) {
612 Display.showFront((Layer) ob);
613 } else {
614 Utils.log2("Search: Unhandable table selection: " + ob);
616 } else if (Utils.isPopupTrigger(me)) {
617 final int numRowsSelected = table.getSelectedRowCount();
618 if (0 == numRowsSelected)
619 return;
620 JPopupMenu popup = new JPopupMenu();
621 final String show2D = "Show";
622 final String select = "Select in display";
623 final String show3D = "Show in 3D";
624 final String openNodeTable = "Show tabular view";
625 ActionListener listener = new ActionListener() {
626 public void actionPerformed(ActionEvent ae) {
627 final String command = ae.getActionCommand();
628 if (command.equals(show2D)) {
629 if (ob instanceof Displayable) {
630 Display.centerAt(
631 createCoordinate((Displayable) ob),
632 true,
633 0 != (ae.getModifiers() & ActionEvent.SHIFT_MASK));
634 } else if (ob instanceof Layer) {
635 Display.showFront((Layer) ob);
637 } else if (command.equals(select)) {
638 if (ob instanceof Layer) {
639 Display.showFront((Layer) ob);
640 } else if (ob instanceof Displayable) {
641 // How many rows are selected?
642 if (0 == numRowsSelected) {
643 return;
644 } else if (1 == numRowsSelected) {
645 Displayable displ = (Displayable) ob;
646 if (!displ.isVisible())
647 displ.setVisible(true);
648 Display display = Display.getFront(displ
649 .getProject());
650 if (null == display)
651 return;
652 boolean shift_down = 0 != (ae
653 .getModifiers() & ActionEvent.SHIFT_MASK);
654 display.select(displ, shift_down);
655 } else {
656 Collection<Displayable> ds = new ArrayList<Displayable>();
657 Display display = null;
658 HashSet<Layer> layers = new HashSet<Layer>();
659 for (int row : table.getSelectedRows()) {
660 final DBObject dob = ((DisplayableTableModel) table
661 .getModel()).getDBObjectAt(row);
662 if (null == dob
663 || !(dob instanceof Displayable)) {
664 Utils.log("Not selecting row "
665 + row);
666 } else {
667 Displayable d = (Displayable) dob;
668 ds.add(d);
669 if (!(d instanceof ZDisplayable)) {
670 layers.add(d.getLayer());
672 if (null == display)
673 display = Display.getFront(dob
674 .getProject());
677 // Filter out Displayable not in the front
678 // layer
679 if (layers.size() > 0) {
680 GenericDialog gd = new GenericDialog(
681 "All layers?");
682 String[] s = new String[] {
683 "Only from current layer",
684 "From " + layers.size()
685 + " layers" };
686 gd.addChoice("Select objects from:", s,
687 s[0]);
688 gd.showDialog();
689 if (gd.wasCanceled())
690 return;
691 if (0 == gd.getNextChoiceIndex()) {
692 Layer la = display.getLayer();
693 for (final Iterator<Displayable> it = ds
694 .iterator(); it.hasNext();) {
695 if (it.next().getLayer() != la)
696 it.remove();
700 display.getSelection().selectAll(ds);
703 } else if (command.equals(show3D)) {
704 if (ob instanceof Displayable) {
705 ProjectThing pt = ob.getProject().findProjectThing(ob);
706 if (null != pt) {
707 Display3D.show(pt);
710 } else if (command.equals(openNodeTable)) {
711 if (ob instanceof Tree<?>) {
712 ((Tree<?>)ob).createMultiTableView();
717 JMenuItem item = new JMenuItem(show2D);
718 popup.add(item);
719 item.addActionListener(listener);
720 item = new JMenuItem(select);
721 popup.add(item);
722 item.addActionListener(listener);
723 popup.addSeparator();
724 item = new JMenuItem(show3D);
725 popup.add(item);
726 item.addActionListener(listener);
727 if (ob instanceof Tree<?>) {
728 item = new JMenuItem(openNodeTable);
729 item.addActionListener(listener);
730 popup.add(item);
732 popup.show(table, me.getX(), me.getY());
738 * Recursive search into nested LayerSet instances, accumulating instances
739 * of type into the list al.
741 private void find(final LayerSet set, final ArrayList<DBObject> al,
742 final Class<?> type) {
743 if (type == DBObject.class) {
744 al.add(set);
746 for (final ZDisplayable zd : set.getZDisplayables()) {
747 if (DBObject.class == type || Displayable.class == type) {
748 al.add(zd);
749 } else if (zd.getClass() == type) {
750 al.add(zd);
753 for (final Layer layer : set.getLayers()) {
754 if (DBObject.class == type || Layer.class == type) {
755 al.add(layer);
757 for (final Displayable ob : layer.getDisplayables()) {
758 if (DBObject.class == type || Displayable.class == type) {
759 if (ob instanceof LayerSet)
760 find((LayerSet) ob, al, type);
761 else
762 al.add(ob);
763 } else if (ob.getClass() == type) {
764 al.add(ob);
770 static public void removeTabs(final Project p) {
771 final Search search = instance;
772 if (null == search)
773 return;
774 synchronized (search.tabMap) {
775 List<JPanel> cs = search.tabMap.get(p);
776 if (null == cs)
777 return;
778 for (final JPanel c : cs) {
779 Utils.invokeLater(new Runnable() {
780 public void run() {
781 search.search_tabs.remove(c);
785 search.tabMap.remove(p);
787 if (0 == search.search_tabs.getTabCount()) {
788 search.destroy();
792 /** Remove from the tables if there. */
793 static public void remove(final Displayable displ) {
794 final Search se = instance;
795 try {
796 if (null == se || null == displ) return;
797 final List<JPanel> panels = se.tabMap.get(displ.getProject());
798 if (null == panels) return;
799 for (final JPanel p : panels) {
800 Results table = (Results) ((JScrollPane)p.getComponent(2)).getViewport().getComponent(0);
801 DisplayableTableModel data = (DisplayableTableModel) table.getModel();
802 if (data.remove(displ)) {
803 Utils.updateComponent(p); // in the event dispatch thread.
806 } catch (Exception e) {
807 IJError.print(e);
808 se.destroy();
813 * Repaint (refresh the text in the cells) only if any of the selected tabs
814 * in any of the search frames contains the given object in its rows.
816 static public void repaint(final Object ob) {
817 if (null == instance)
818 return;
819 SwingUtilities.invokeLater(new Runnable() {
820 public void run() {
821 final int selected = instance.search_tabs.getSelectedIndex();
822 if (-1 == selected)
823 return;
824 java.awt.Component c = instance.search_tabs
825 .getComponentAt(selected);
826 JTable table = (JTable) ((JScrollPane) c).getViewport()
827 .getComponent(0);
828 DisplayableTableModel data = (DisplayableTableModel) table
829 .getModel();
830 if (data.contains(ob)) {
831 Utils.updateComponent(instance.search_frame);