Browse code

Handle multiple search results

* Always pan to the first result
* Show the number of results
* Provide a button to pan to the next result

Christian Hattemer authored on 30/04/2015 16:50:26 • Jose Fonseca committed on 17/08/2020 13:06:53
Showing 2 changed files

... ...
@@ -92,6 +92,9 @@ class Shape:
92 92
                 ya, yb = min(ya, y0), max(yb, y1)
93 93
         return xa, ya, xb, yb
94 94
 
95
+    def get_text(self):
96
+        return None
97
+
95 98
 
96 99
 class TextShape(Shape):
97 100
 
... ...
@@ -211,6 +214,9 @@ class TextShape(Shape):
211 214
         x, w, j = self.x, self.w, self.j
212 215
         return x - 0.5 * (1 + j) * w, -_inf, x + 0.5 * (1 - j) * w, _inf
213 216
 
217
+    def get_text(self):
218
+        return self.t
219
+
214 220
 
215 221
 class ImageShape(Shape):
216 222
 
... ...
@@ -494,6 +500,13 @@ class CompoundShape(Shape):
494 500
                 return True
495 501
         return False
496 502
 
503
+    def get_text(self):
504
+        for shape in self.shapes:
505
+            text = shape.get_text()
506
+            if text is not None:
507
+                return text
508
+        return None
509
+
497 510
 
498 511
 class Url(object):
499 512
 
... ...
@@ -20,6 +20,7 @@ import re
20 20
 import subprocess
21 21
 import sys
22 22
 import time
23
+import operator
23 24
 
24 25
 import gi
25 26
 gi.require_version('Gtk', '3.0')
... ...
@@ -534,6 +535,10 @@ class DotWindow(Gtk.Window):
534 535
             <toolitem action="Zoom100"/>
535 536
             <separator/>
536 537
             <toolitem name="Find" action="Find"/>
538
+            <separator name="FindNextSeparator"/>
539
+            <toolitem action="FindNext"/>
540
+            <separator name="FindStatusSeparator"/>
541
+            <toolitem name="FindStatus" action="FindStatus"/>
537 542
         </toolbar>
538 543
     </ui>
539 544
     '''
... ...
@@ -577,6 +582,7 @@ class DotWindow(Gtk.Window):
577 582
             ('ZoomOut', Gtk.STOCK_ZOOM_OUT, None, None, None, self.dotwidget.on_zoom_out),
578 583
             ('ZoomFit', Gtk.STOCK_ZOOM_FIT, None, None, None, self.dotwidget.on_zoom_fit),
579 584
             ('Zoom100', Gtk.STOCK_ZOOM_100, None, None, None, self.dotwidget.on_zoom_100),
585
+            ('FindNext', Gtk.STOCK_GO_FORWARD, 'Next Result', None, 'Move to the next search result', self.on_find_next),
580 586
         ))
581 587
 
582 588
         self.back_action = Gtk.Action('Back', None, None, Gtk.STOCK_GO_BACK)
... ...
@@ -593,6 +599,10 @@ class DotWindow(Gtk.Window):
593 599
                                          "Find a node by name", None)
594 600
         actiongroup.add_action(find_action)
595 601
 
602
+        findstatus_action = FindMenuToolAction("FindStatus", None,
603
+                                               "Number of results found", None)
604
+        actiongroup.add_action(findstatus_action)
605
+
596 606
         # Add the actiongroup to the uimanager
597 607
         uimanager.insert_action_group(actiongroup, 0)
598 608
 
... ...
@@ -619,6 +629,15 @@ class DotWindow(Gtk.Window):
619 629
         self.textentry.connect("activate", self.textentry_activate, self.textentry);
620 630
         self.textentry.connect("changed", self.textentry_changed, self.textentry);
621 631
 
632
+        uimanager.get_widget('/ToolBar/FindNextSeparator').set_draw(False)
633
+        uimanager.get_widget('/ToolBar/FindStatusSeparator').set_draw(False)
634
+        self.find_next_toolitem = uimanager.get_widget('/ToolBar/FindNext')
635
+        self.find_next_toolitem.set_sensitive(False)
636
+
637
+        self.find_count = Gtk.Label()
638
+        findstatus_toolitem = uimanager.get_widget('/ToolBar/FindStatus')
639
+        findstatus_toolitem.add(self.find_count)
640
+
622 641
         self.show_all()
623 642
 
624 643
     def find_text(self, entry_text):
... ...
@@ -628,9 +647,11 @@ class DotWindow(Gtk.Window):
628 647
         for element in dot_widget.graph.nodes + dot_widget.graph.edges:
629 648
             if element.search_text(regexp):
630 649
                 found_items.append(element)
631
-        return found_items
650
+        return sorted(found_items, key=operator.methodcaller('get_text'))
632 651
 
633 652
     def textentry_changed(self, widget, entry):
653
+        self.find_index = 0
654
+        self.find_next_toolitem.set_sensitive(False)
634 655
         entry_text = entry.get_text()
635 656
         dot_widget = self.dotwidget
636 657
         if not entry_text:
... ...
@@ -639,8 +660,14 @@ class DotWindow(Gtk.Window):
639 660
 
640 661
         found_items = self.find_text(entry_text)
641 662
         dot_widget.set_highlight(found_items, search=True)
663
+        if found_items:
664
+            self.find_count.set_label('%d nodes found' % len(found_items))
665
+        else:
666
+            self.find_count.set_label('')
642 667
 
643 668
     def textentry_activate(self, widget, entry):
669
+        self.find_index = 0
670
+        self.find_next_toolitem.set_sensitive(False)
644 671
         entry_text = entry.get_text()
645 672
         dot_widget = self.dotwidget
646 673
         if not entry_text:
... ...
@@ -649,8 +676,9 @@ class DotWindow(Gtk.Window):
649 676
 
650 677
         found_items = self.find_text(entry_text)
651 678
         dot_widget.set_highlight(found_items, search=True)
652
-        if(len(found_items) == 1):
679
+        if found_items:
653 680
             dot_widget.animate_to(found_items[0].x, found_items[0].y)
681
+        self.find_next_toolitem.set_sensitive(len(found_items) > 1)
654 682
 
655 683
     def set_filter(self, filter):
656 684
         self.dotwidget.set_filter(filter)
... ...
@@ -717,6 +745,15 @@ class DotWindow(Gtk.Window):
717 745
         dlg.run()
718 746
         dlg.destroy()
719 747
 
748
+    def on_find_next(self, action):
749
+        self.find_index += 1
750
+        entry_text = self.textentry.get_text()
751
+        # Maybe storing the search result would be better
752
+        found_items = self.find_text(entry_text)
753
+        found_item = found_items[self.find_index]
754
+        self.dotwidget.animate_to(found_item.x, found_item.y)
755
+        self.find_next_toolitem.set_sensitive(len(found_items) > self.find_index + 1)
756
+
720 757
     def on_history(self, action, has_back, has_forward):
721 758
         self.back_action.set_sensitive(has_back)
722 759
         self.forward_action.set_sensitive(has_forward)