# Text widget search/find module.
# Rick Smereka, Copyright (C) 2004-2005.

# 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, get a copy via the Internet at
# http://gnu.org/copyleft/gpl.html or write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307 USA

# You can contact the author via email at rsmereka@future-lab.com

# Initial tcl version. Feb/2004, Rick Smereka
# This version based on code in the book 'Graphical Applications with
# Tcl & Tk' second edition by Eric Foster-Johnson.
# This module will display a find dialog box and perform the search
# through a text widget.
global find_last_indx
set find_last_indx 1.0

proc finddialog {textwidget} {
   # Present a non-modal find dialog. Procedure exits when dialog is destroyed
   # (upon close). Returns nothing.
   global find_case find_last_indx

   # check for already existing find window open
   if {[info commands .finddialog] != {}} {
      wm deiconify .finddialog
      raise .finddialog
      return
   }

   # don't require exact case match
   set find_case 0

   # last place searched, line 1 column 0 (start)
   set find_last_indx 1.0

   # create font dialog window
   set dlg .finddialog
   toplevel $dlg
   wm protocol $dlg WM_DELETE_WINDOW "destroy $dlg"
   wm title $dlg Find
   label $dlg.l_findwhat -text "Find what:" -anchor w
   entry $dlg.findwhat
   bind $dlg.findwhat <Key-Return> \
      "findtext $dlg.findwhat $textwidget"
   grid config $dlg.l_findwhat -column 0 -row 0 \
      -sticky w -pady 8
   grid config $dlg.findwhat -column 1 -row 0 \
      -sticky snew -pady 8
   checkbutton $dlg.matchcase -text "Match case" \
      -variable find_case
   grid config $dlg.matchcase -column 1 -row 1 \
      -sticky w
   set fr $dlg.buttons
   frame $fr -bd 0
   button $fr.findnext -text "Find Next" \
      -command "findtext $dlg.findwhat $textwidget"
   button $fr.cancel -text "Cancel" \
      -command "destroy $dlg"
   pack $fr.findnext -side top -fill x
   pack $fr.cancel -side top -fill x -pady 6
   grid config $fr -column 2 -row 0 -rowspan 4 \
      -padx 8 -pady 8
   focus $dlg.findwhat
}

proc findtext {entrywidget textwidget} {
   # Search through the text widget. 'entrywidget' is the name of the
   # find dialog text entry box. Returns nothing.
   global find_case find_last_indx

   # get search pattern
   set pattern [$entrywidget get]
   set length [string length $pattern]
   set options ""

   if {$find_case == 0} {
      append options "-nocase"
   }

   if {$options == ""} {
      set indx [$textwidget search $pattern \
         $find_last_indx end]
   } else {
      set indx [$textwidget search $options $pattern \
         $find_last_indx end]
   }
 
   if {$indx == ""} {
      set find_last_indx 1.0

      if {$options == ""} {
         set indx [$textwidget search $pattern \
            $find_last_indx end]
      } else {
         set indx [$textwidget search $options $pattern \
            $find_last_indx end]
      }
   }

   if {$indx != ""} {
      catch {
         # remove old tags
         $textwidget tag remove sel sel.first sel.last
      }

      # select text found
      $textwidget tag add sel $indx "$indx + $length chars"

      # place insertion cursor at start of selected area
      $textwidget mark set insert $indx

      # make sure text is visible
      $textwidget see $indx

      # set focus back to text widget
      focus $textwidget

      # keep index for next search
      set find_last_indx "$indx + 1 char"
   } else {
      # reset to search from beginning
      set find_last_indx 1.0

      # display not found dialog
      tk_messageBox -type ok -icon info -parent $textwidget \
         -title "Not Found" -message \
         "'$pattern' was not found."
   }
}
