changeset 908:40bc2df4de7a

Implemented "search previous" in string searches
author João Ricardo Lourenço <jorl17.8@gmail.com>
date Sun, 08 Feb 2009 16:58:29 -0300
parents 35054b4e3b1b
children 20508c04260b 9c27d6594b19
files ChangeLog dw/findtext.cc dw/findtext.hh dw/layout.hh src/findbar.cc src/findbar.hh src/uicmd.cc src/uicmd.hh test/dw_find_test.cc
diffstat 9 files changed, 150 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sun Feb 08 14:02:56 2009 -0300
+++ b/ChangeLog	Sun Feb 08 16:58:29 2009 -0300
@@ -9,6 +9,8 @@
 +- Added support for numeric IPv6 addresses entered into the url bar.
  - Used the URL authority part instead of stripped default port in HTTP query.
    Patches: Justus Winter
++- Implemented "search previous" in string searches.
+   Patch: João Ricardo Lourenço
 +- Fix for file inputs without values (forms).
  - Tuned input width a bit.
  - Cleaned up resource embedding (forms)
@@ -50,7 +52,7 @@
 +- Added the "middle_click_drags_page" dillorc option.
    Patch: Jorge Arellano Cid, Thomas Orgis
 +- Set the File menu label to hide when the File menu-button is shown.
- - Trying a new iconv() test in configure.in.
+ - Set a new iconv() test in configure.in.
  - Allowed the rc parser to skip whitespace around the equal sign.
  - Fixed the parser not to call Html_tag_close_* functions twice.
  - Implemented loading of remote CSS Stylesheet.
--- a/dw/findtext.cc	Sun Feb 08 14:02:56 2009 -0300
+++ b/dw/findtext.cc	Sun Feb 08 16:58:29 2009 -0300
@@ -21,6 +21,7 @@
 
 
 #include "core.hh"
+#include "../lout/msg.h"
 
 namespace dw {
 namespace core {
@@ -66,7 +67,8 @@
    hlIterator = NULL;
 }
 
-FindtextState::Result FindtextState::search (const char *key, bool caseSens)
+FindtextState::Result FindtextState::search (const char *key, bool caseSens,
+                                             bool backwards)
 {
    if (!widget || *key == 0) // empty keys are not found
       return NOT_FOUND;
@@ -86,18 +88,25 @@
 
       if (nexttab)
          delete[] nexttab;
-      nexttab = createNexttab (key, caseSens);
+      nexttab = createNexttab (key, caseSens, backwards);
       
       if (iterator)
          delete iterator;
       iterator = new CharIterator (widget);
-      iterator->next ();
+
+      if (backwards) {
+         /* Go to end */
+         while(iterator->next () ) ;
+         iterator->prev (); //We don't want to be at CharIterator::END.
+      } else {
+         iterator->next ();
+      }
    } else
       newKey = false;
 
    bool firstTrial = !wasHighlighted || newKey;
 
-   if (search0 ()) {
+   if (search0 (backwards, firstTrial)) {
       // Highlighlighting is done with a clone.
       hlIterator = iterator->cloneCharIterator ();
       for (int i = 0; key[i]; i++)
@@ -110,16 +119,21 @@
       iterator->next ();
       return SUCCESS;
    } else {
-      if (firstTrial)
+      if (firstTrial) {
          return NOT_FOUND;
-      else {
+      } else {
          // Nothing found anymore, reset the state for the next trial.
          delete iterator;
          iterator = new CharIterator (widget);
-         iterator->next ();
-         
+         if (backwards) {
+            /* Go to end */
+            while(iterator->next ()) ;
+            iterator->prev (); //We don't want to be at CharIterator::END.
+         } else {
+            iterator->next ();
+         }
          // We expect a success.
-         Result result2 = search (key, caseSens);
+         Result result2 = search (key, caseSens, backwards);
          assert (result2 == SUCCESS);
          return RESTART;
       }
@@ -138,8 +152,29 @@
    key = NULL;  
 }
 
-int *FindtextState::createNexttab (const char *key, bool caseSens)
+/*
+ * Return a new string: with the reverse of the original.
+ */
+const char* FindtextState::rev(const char *str)
 {
+   if (!str)
+      return NULL;
+
+   int len = strlen(str);
+   char *nstr = new char[len+1];
+   for (int i = 0; i < len; ++i)
+      nstr[i] = str[len-1 -i];
+   nstr[len] = 0;
+
+   return nstr;
+}
+
+int *FindtextState::createNexttab (const char *needle, bool caseSens,
+                                   bool backwards)
+{
+   const char* key;
+
+   key = (backwards) ? rev(needle) : needle;
    int i = 0;
    int j = -1;
    int l = strlen (key);
@@ -156,6 +191,9 @@
          j = nexttab[j];
    } while (i < l - 1);
 
+   if (backwards)
+      delete [] key;
+
    return nexttab;
 }
 
@@ -179,30 +217,76 @@
       return false;
 }
 
-bool FindtextState::search0 ()
+bool FindtextState::search0 (bool backwards,  bool firstTrial)
 {
    if (iterator->getChar () == CharIterator::END)
       return false;
-
+      
+   bool ret = false;
+   const char* searchKey = (backwards) ? rev(key) : key;
    int j = 0;
    bool nextit = true;
    int l = strlen (key);
 
+   if (backwards && !firstTrial) {
+      _MSG("Having to do.");
+      /* Position correctly */
+      /* In order to achieve good results (i.e: find a word that ends within
+       * the previously searched word's limit) we have to position the
+       * iterator in the semilast character of the previously searched word.
+       *
+       * Since we know that if a word was found before it was exactly the
+       * same word as the one we are searching for now, we can apply the
+       * following expression:
+       *
+       * Where l=length of the key and n=num of positions to move:
+       *
+       * n = l - 3
+       *
+       * If n is negative, we have to move backwards, but if it is
+       * positive, we have to move forward. So, when l>=4, we start moving
+       * the iterator forward. */
+         
+      if (l==1) {
+         iterator->prev();
+         iterator->prev();
+      } else if (l==2) {
+         iterator->prev();
+      } else if (l>=4) {
+         for (int i=0; i<l-3; i++) {
+            iterator->next();
+         }
+      }
+
+   } else if (backwards && l==1) {
+      /* Particular case where we can't find the last character */
+      iterator->next();
+   }
+   
    do {
-      if (j == -1 || charsEqual (iterator->getChar (), key[j], caseSens)) {
+      if (j == -1 || charsEqual (iterator->getChar(),searchKey[j],caseSens)) {
          j++;
-         nextit = iterator->next ();
+         nextit = backwards ? iterator->prev () : iterator->next ();
       } else
          j = nexttab[j];
    } while (nextit && j < l);
    
    if (j >= l) {
-      // Go back to where the word was found.
-      for (int i = 0; i < l; i++)
-         iterator->prev ();
-      return true;
-   } else
-      return false;
+      if (backwards) {
+         //This is the location of the key
+         iterator->next();
+      } else {
+         // Go back to where the key was found.
+         for (int i = 0; i < l; i++)
+            iterator->prev ();
+      }
+      ret = true;
+   }
+
+   if (backwards)
+      delete [] searchKey;
+
+   return ret;
 }
 
 } // namespace dw
--- a/dw/findtext.hh	Sun Feb 08 14:02:56 2009 -0300
+++ b/dw/findtext.hh	Sun Feb 08 16:58:29 2009 -0300
@@ -58,10 +58,12 @@
     * NULL, when no text is highlighted.
     */
    CharIterator *hlIterator;  
-
-   static int *createNexttab (const char *key, bool caseSens);
+   
+   static const char* rev(const char* _str); /* Function to reverse a C-string */
+   
+   static int *createNexttab (const char *needle, bool caseSens, bool backwards);
    bool unhighlight ();
-   bool search0 ();
+   bool search0 (bool backwards, bool firstTrial);
 
    inline static bool charsEqual (char c1, char c2, bool caseSens)
    { return caseSens ? c1 == c2 : tolower (c1) == tolower (c2) ||
@@ -72,7 +74,7 @@
    ~FindtextState ();
 
    void setWidget (Widget *widget);
-   Result search (const char *key, bool caseSens);
+   Result search (const char *key, bool caseSens, bool backwards);
    void resetSearch ();
 };
 
--- a/dw/layout.hh	Sun Feb 08 14:02:56 2009 -0300
+++ b/dw/layout.hh	Sun Feb 08 16:58:29 2009 -0300
@@ -255,8 +255,8 @@
       emitter.connectLayout (receiver); }
 
    /** \brief See dw::core::FindtextState::search. */
-   inline FindtextState::Result search (const char *str, bool caseSens)
-      { return findtextState.search (str, caseSens); }
+   inline FindtextState::Result search (const char *str, bool caseSens, int backwards)
+      { return findtextState.search (str, caseSens, backwards); }
 
    /** \brief See dw::core::FindtextState::resetSearch. */
    inline void resetSearch () { findtextState.resetSearch (); }
--- a/src/findbar.cc	Sun Feb 08 14:02:56 2009 -0300
+++ b/src/findbar.cc	Sun Feb 08 16:58:29 2009 -0300
@@ -63,7 +63,22 @@
 
    if (key[0] != '\0')
       a_UIcmd_findtext_search(a_UIcmd_get_bw_by_widget(fb),
-                              key, case_sens);
+                              key, case_sens, false);
+}
+
+/*
+ * Find previous occurrence of input key
+ */
+void Findbar::searchBackwards_cb(Widget *, void *vfb)
+{
+   Findbar *fb = (Findbar *)vfb;
+   const char *key = fb->i->text();
+   bool case_sens = fb->check_btn->value();
+
+   if (key[0] != '\0') {
+      a_UIcmd_findtext_search(a_UIcmd_get_bw_by_widget(fb),
+                              key, case_sens, true);
+   }
 }
 
 /*
@@ -96,7 +111,7 @@
    int button_width = 70;
    int gap = 2;
    int border = 2;
-   int input_width = width - (2 * border + 3 * (button_width + gap));
+   int input_width = width - (2 * border + 4 * (button_width + gap));
    int x = border;
    height -= 2 * border;
 
@@ -121,15 +136,23 @@
     i->clear_tab_to_focus();
     i->set_click_to_focus();
 
-    // TODO: search previous would be nice
     next_btn = new HighlightButton(x, border, button_width, height, "Next");
     x += button_width + gap;
-    next_btn->tooltip("Find next occurrence of the search phrase");
+    next_btn->tooltip("Find next occurrence of the search phrase\n"
+                      "shortcut: Enter");
     next_btn->add_shortcut(ReturnKey);
     next_btn->add_shortcut(KeypadEnter);
     next_btn->callback(search_cb, this);
     next_btn->clear_tab_to_focus();
 
+    prev_btn= new HighlightButton(x, border, button_width, height, "Previous");
+    prev_btn->tooltip("Find previous occurrence of the search phrase\n"
+                      "shortcut: Shift+Enter");
+    prev_btn->add_shortcut(SHIFT+ReturnKey);
+    prev_btn->callback(searchBackwards_cb, this);
+    prev_btn->clear_tab_to_focus();
+    x += button_width + gap;
+
     check_btn = new CheckButton(x, border, 2*button_width, height,
                               "Case-sensitive");
     check_btn->clear_tab_to_focus();
--- a/src/findbar.hh	Sun Feb 08 14:02:56 2009 -0300
+++ b/src/findbar.hh	Sun Feb 08 16:58:29 2009 -0300
@@ -16,12 +16,13 @@
  */
 class Findbar : public Group {
    Button *clrb;
-   HighlightButton *hide_btn, *next_btn;
+   HighlightButton *hide_btn, *next_btn, *prev_btn;
    CheckButton *check_btn;
    xpmImage *hideImg;
    Input *i;
    
    static void search_cb (Widget *, void *);
+   static void searchBackwards_cb (Widget *, void *);
    static void search_cb2 (Widget *, void *);
    static void hide_cb (Widget *, void *);
 
--- a/src/uicmd.cc	Sun Feb 08 14:02:56 2009 -0300
+++ b/src/uicmd.cc	Sun Feb 08 16:58:29 2009 -0300
@@ -948,13 +948,13 @@
 }
 
 /*
- * Search for next occurrence of key.
+ * Search for next/previous occurrence of key.
  */
-void a_UIcmd_findtext_search(BrowserWindow *bw, const char *key, int case_sens)
+void a_UIcmd_findtext_search(BrowserWindow *bw, const char *key, int case_sens, int backwards)
 {
    Layout *l = (Layout *)bw->render_layout;
    
-   switch (l->search(key, case_sens)) {
+   switch (l->search(key, case_sens, backwards)) {
       case FindtextState::RESTART:
          a_UIcmd_set_msg(bw, "No further occurrences of \"%s\". "
                              "Restarting from the top.", key);
--- a/src/uicmd.hh	Sun Feb 08 14:02:56 2009 -0300
+++ b/src/uicmd.hh	Sun Feb 08 16:58:29 2009 -0300
@@ -34,7 +34,8 @@
 void a_UIcmd_add_bookmark(BrowserWindow *bw, const DilloUrl *url);
 void a_UIcmd_fullscreen_toggle(BrowserWindow *bw);
 void a_UIcmd_findtext_dialog(BrowserWindow *bw);
-void a_UIcmd_findtext_search(BrowserWindow *bw,const char *key,int case_sens);
+void a_UIcmd_findtext_search(BrowserWindow *bw,const char *key,int case_sens,
+                             int backwards);
 void a_UIcmd_findtext_reset(BrowserWindow *bw);
 void a_UIcmd_focus_main_area(BrowserWindow *bw);
 void a_UIcmd_focus_location(void *vbw);
--- a/test/dw_find_test.cc	Sun Feb 08 14:02:56 2009 -0300
+++ b/test/dw_find_test.cc	Sun Feb 08 16:58:29 2009 -0300
@@ -44,7 +44,7 @@
 static void findCallback (::fltk::Widget *widget, void *data)
 {
    //switch(layout->search ("worm", true)) {
-   switch(layout->search ("WORM", false)) {
+   switch(layout->search ("WORM", false, false)) {
        case FindtextState::SUCCESS:
           resultLabel->label("SUCCESS");
           break;