tkImageViewer - for Mask-Selecting Images from a Directory Hierarchy

uniquename - 2013dec10

On my 'bio' page at uniquename, I have a 'to do' list in the 'CFE' section --- in a bigger section at the bottom of that page --- a section of Tk 'scripts done and to-do'.

The 'CFE' stands for 'Code for Front Ends'. The 'to-do' scripts in that section are 'start up' front ends for utility programs like 'mplayer', 'ffmpeg', 'find', 'du' (directory usage), and others.

In sketching out the GUI layouts for programs like 'mplayer', 'ffmeg', and 'find', I found that there are so many command-line options for these programs that the GUI's are going to contain a lot of widgets --- and they will probably require multiple 'panels' of 'prompting widgets'.

In doing my first 'CFE' script, I wanted to start out with a GUI that was not quite so complex.

In the past year, I have made some shell scripts for sweeping through sub-directories and selecting image files to display with a simple image display program --- like Image Magick 'display' --- or 'ffplay' --- or 'eog' (Eye of Gnome) --- on Linux. These scripts use the 'find' command to sweep through sub-directories, looking for image files.

I decided to layout a Tk GUI as a 'front end' for such an image-viewing utility. It turned out that the GUI could fit on one screen --- without using 'multiple panels of options'.

My 'text-sketch' for the GUI (after several revisions) was as follows.

  ------------------------------------------------------------------
  'display'/'ffplay' Front End  --- a Tk Image Viewer Utility  [window title]
  ------------------------------------------------------------------

  {Exit} {Help} {LaunchViewerJob}      {CountFilenames} {ShowFilenames}

  Full Filename Mask (for image/s): ___________________  {Browse...}

  Viewer program : O ImageMagick 'display'    O 'ffplay'   O 'eog'

  Search Levels for Mask:  O ONE   O ALL subdirectories of selected dir

  Case Sense for Mask Search:  O case-sensitive  O case-INsensitive

  Files Size (MegaBytes):  _____  O bigger-than  O smaller-than

  Files Age (Days) : ______ O older-than  O younger-than

  --------------------------------------------------------

where

   Braces indicate a Tk 'button' widget.
   Underscores indicate a Tk 'entry' widget.
   A colon indicates that the text before the colon is on a 'label' widget.
   Capital-O indicates a Tk 'radiobutton' widget.
   Capital-X indicates a Tk 'checkbutton' widget.
   Square brackets indicate a comment (not to be placed on the GUI).

---

GUI Components

From the GUI 'sketch' above, it is seen that the GUI consists of about

   -  5 button widgets
   -  6 label widgets
   -  3 entry widgets
   - 11 radiobutton widgets in 5 groups
   -  0 checkbutton widgets
   -  0 scale widgets
   -  0 listbox widgets
   -  0 canvas widgets

This is relatively simple compared to the front end GUI's that I plan to use for 'mplayer', 'ffmpeg', and 'find'.

---

Front-End-for-Two ; the Viewers ; Beauty (or lack thereof)

This 'Front End' GUI is essentially a 'wrapper' for TWO commands --- the 'find' command and the command that implements the image viewer.

   I was seeking to use suitable commands that are available on my operating
   system (Ubuntu 9.10, 2009 October, 'Karmic Koala'). I found that
   the 'find' command in combination with a simple image viewer program
   would 'fill the bill'.

On the GUI, NOTE that only 'Viewer Program' is a parameter involving the image viewer. The other parameters are for the 'find' command.

---

The 'display', 'ffplay' and 'eog' programs come close to working OK as an image viewer --- but each one has a few drawbacks. So I still have my eye out for another simple image viewer program to use, as mentioned further below (in some comments in the code).

When animated GIF files are displayed, some image viewers behave differently from others. The 'display' program shows each image within the animated GIF, whereas 'eof' shows only one image. So you may wish to take advantage of certain features of image viewers --- or avoid certain features.

---

I should point out here that I was not especially interested in coming up with a 'beautiful utility'. I just wanted a utility that would be able to sweep through a hierarchy of sub-directories and pick out image files to show based on a rather 'rich' set of selection capabilities --- such as 'file-mask' and/or 'file-size' and/or 'file-age'.

(I may add a 'file-type' capability based on using the 'file' command, in a future enhancement to this utility.)


SOME GUI IMAGES

On the basis of the sketch above, I ended up with the GUI seen in the following image.

tkImageViewer_initial_screenshot_576x242.jpg

Note that there are a couple of radiobuttons that allow you to choose whether application of the file-mask is 'case-sensitive' or 'case-INsensitive'. For example, if you chose 'case-INsensitive' and the mask were set to '*.jpg', then files with the suffix '.JPG' would also be selected.

And there are a couple of radiobuttons that allow you to choose whether to do the 'mask-search' at the current directory level only --- or to sweep through all sub-directories of the current 'base' directory, looking for images that satisfy the criteria chosen via this GUI.

Here is another place where I MAY make a future enhancement: I may change the 'ONE' radiobutton to an 'N-levels' radiobutton --- and if that radiobutton is selected, an entry field will be activated where the user can enter a choice of N (with the entry field being initialized with '1').

---

Here is another image of the GUI, showing a different setting of most of the radiobuttons --- and entries placed in the file-size and file-age entry fields.

tkImageViewer_radbuttChanges_screenshot_575x241.jpg

NOTE that most image-viewers, like 'eog' and more complex image viewers, are oriented toward scanning through ALL image files in a SINGLE directory.

This utility is oriented toward SELECTING image files (based on criteria such as a file-mask, file-size, and/or file-age) from an ENTIRE HIERARCHY OF SUB-DIRECTORIES --- as well as allowing mask-search in a SINGLE directory.

Furthermore, this utility can be used to view a single file. Just select a full filename and do not change the last part of the filename to a mask. Then click the 'Launch' button.

---

This utility can be useful without even using any of the viewer programs. Say you want to know the number or names of the image files satisfying a set of criteria (file-mask, file-size, file-age). Then set the criteria and click on the 'CountFilenames' or 'ShowFilenames' button.


The code

Below, I provide the Tk script code for this 'multi-subdirectory tkImageViewer' utility.

I follow my usual 'canonical' structure for Tk code for this Tk script:

  0) Set general window & widget parms (win-name, win-position,
     win-color-scheme, fonts, widget-geometry-parms, win-size-control,
     text-array-for-labels-etc).

  1a) Define ALL frames (and sub-frames, if any).
  1b) Pack   ALL frames and sub-frames.

  2) Define & pack all widgets in the frames, frame by frame.
              Within each frame, define ALL the widgets.
              Then pack the widgets.

  3) Define keyboard and mouse/touchpad/touch-sensitive-screen action
     BINDINGS, if needed.

  4) Define PROCS, if needed.

  5) Additional GUI initialization (typically with one or more of
     the procs), if needed.

This Tk coding structure is discussed in more detail on the page A Canonical Structure for Tk Code --- and variations.

This structure makes it easy for me to find code sections --- while generating and testing a Tk script, and when looking for code snippets to include in other scripts (code re-use).

I call your attention to step-zero. One thing that I have started doing in 2013 is using a text-array for text in labels, buttons, and other widgets in the GUI. This can make it easier for people to internationalize my scripts. I will be using a text-array like this in most of my scripts in the future.


Experimenting with the GUI

As in all my scripts that use the 'pack' geometry manager (which is all of my 100-plus scripts, so far), I provide the four main pack parameters --- '-side', '-anchor', '-fill', '-expand' --- on all of the 'pack' commands for the frames and widgets.

That helps me when I am initially testing the behavior of a GUI (the various widgets within it) as I resize the main window.

I think that I have used a pretty nice choice of the 'pack' parameters. The label and button and radiobutton widgets stay fixed in size and relative-location if the window is re-sized --- while the entry widgets expand/contract horizontally whenever the window is re-sized horizontally.

You can experiment with the '-side', '-anchor', '-fill', and '-expand' parameters on the 'pack' commands for the various frames and widgets --- to get the widget behavior that you want.

___

Additional experimentation: You might want to change the fonts used for the various GUI widgets. For example, you could change '-weight' from 'bold' to 'normal' --- or '-slant' from 'roman' to 'italic'. Or change font families.

In fact, you may NEED to change the font families, because the families I used may not be available on your computer --- and the default font that the 'wish' interpreter chooses may not be very pleasing.

I use variables to set geometry parameters of widgets --- parameters such as border-widths and padding. And I have included the '-relief' parameter on the definitions of frames and widgets. Feel free to experiment with those 'appearance' parameters as well.

If you find the gray 'palette' of the GUI is not to your liking, you can change the value of the RGB parameter supplied to the 'tk_setPalette' command near the top of the code.


Some features in the code

That said, here's the code --- with plenty of comments to describe what most of the code-sections are doing.

You can look at the top of the PROCS section of the code to see a list of the procs used in this script, along with brief descriptions of how they are called and what they do.

The main procs are

  'get_filemask'         - called by the 'Browse...' button
                           next to the filemask entry field

  'getImages_andCountPrintOrView'
                         - called by the 'LaunchViewJob', 'CountFilenames',
                           and 'ShowFilenames' buttons

  'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var.
                             Also used via the 'CountFilenames' and
                             'ShowFilenames' buttons.

One unique thing about this Tk GUI that is different from the 40-plus scripts that I have contributed (so far) to this wiki:

I used the following statement to allow the GUI to be expanded in the x-direction, but NOT the y-direction.

   wm resizable . 1 0

It is my hope that the copious comments in the code will help Tcl-Tk coding 'newbies' get started in making GUI's like this.

Without the comments, potential young Tcler's might be tempted to return to their iPhones and iPads and iPods --- to watch videos of puppies and kittens.

That's nice. BUT ... How is that going to help the world develop the engineers, computer-scientists, and other scientists that are needed in a very challenging future world? (We need people to help deal with that as-yet-undetected next-huge-asteroid that is on a collision course with the Earth --- perhaps sooner than most people think.)

   Imagine what is going to happen when a medium-sized space-rock hits
   one of the 140-plus nuclear power plants we have in the U.S.
   Of course, it may happen that an earthquake, from fracking, or
   a flood, like the one that recently almost inundated a nuke plant
   in Nebraska, may be more likely than a space-rock hit. But we
   need properly trained and educated people to handle those distinct
   possibilities as well.

 Code for Tk script 'find_and_imageViewer_FrontEnd.tk' : (the 'front end')

#!/usr/bin/wish -f
##
## Tk SCRIPT NAME: find_and_imageViewer_FrontEnd.tk
##
##+#######################################################################
## PURPOSE:  This Tk script provides a GUI for
##           1) finding a 'batch' of image files according to
##              user-specified criteria that are prompted for via
##              entry widgets and radiobutton widgets on the GUI,
##           AND
##           2) starting up an image file viewer program --- like the
##              ImageMagick 'display' program or the 'ffplay' program or
##              the 'eog' (Eye of Gnome) program --- to view the 'batch'
##              of image files that were found, via the 'find' command.
##
##           Hence, the GUI is a 'front-end' for the 'find' command and
##           an image viewing command.
##
##           The GUI is intended to make the user aware of the main
##           (most useful) options available without the user needing
##           to reference the 'man find' command and 'man display' or
##           'man ffplay' or 'man eog' commands --- nor other
##           'find'/'display'/'ffplay'/'eog' documentation, for example,
##           via web searches.
##
##           The intent of this utility is to allow the user to
##           easily specify files to be viewed --- via specifying:
##            1  - a directory-and-filename (the latter is typically a 'mask'),
##            2  - whether files in sub-directories should be mask-searched,
##            3  - whether the mask-search should be case-INsensitive,
##            4  - whether to use a file-size limitation,
##            5  - whether to use a file-age limitation,
##            6  - which of several viewer programs to use.
##
##           NOTE that most image-viewers, like 'eog' and more complex
##           image viewers, are oriented toward scanning through ALL
##           image files in a SINGLE directory.
##
##           This utility is oriented toward SELECTING image files (based
##           on criteria such as a file-mask, file-size, and/or file-age)
##           from an ENTIRE HIERARCHY OF SUB-DIRECTORIES --- as well as
##           allowing mask-search in a SINGLE directory. 
##            
##+######################
## NOTES ON OTHER VIEWERS:
##           As an alternative to 'eog', it would be easy to use
##           the 'Eye of MATE' ('eom') image viewer instead. 'eom' is the
##           image viewer that the MATE desktop project forked from
##           'eog'. Reference: www.mate-desktop.org
##
##           Circa 2010, some Argentinians decided to fork the
##           Gnome 2.x desktop environment --- when the Gnome 3
##           project abandoned many of the features of Gnome 2 and its
##           associated applications, like the 'Nautilus' file
##           manager and the 'Eye of Gnome' image viewer. (The fork
##           of the 'Nautilus' file manager is called 'Caja' --- Spanish
##           for 'box' or 'gift'.)
##
##           Of course, still other 'light-weight' image viewers could be
##           used with very few changes to this system. The 'core' changes would
##           be to the shell script --- 'findImages_andCountPrintOrView.sh' ---
##           that this Tk script calls. That shell script currently uses
##           'display' or 'ffplay' or 'eog', along with the 'find' command
##           --- and along with parameters supplied from this GUI.
##
##+#################
## THE GUI WIDGETS:
##           The GUI offers a generous set of user specifications.
##           The options available to the user are compactly indicated
##           by the following 'sketch' of the GUI:
##
##  ------------------------------------------------------------------
##  'display'/'ffplay' Front End  --- a Tk Image Viewer Utility
##  [window title]
##  ------------------------------------------------------------------
##
##  {Exit} {Help} {LaunchViewerJob}      {CountFilenames} {ShowFilenames}
##  
##  Full Filename Mask (for image/s): ___________________  {Browse...}
##  
##  Viewer program : O ImageMagick 'display'    O 'ffplay'   O 'eog'
##  
##  Search Levels for Mask:  O ONE   O ALL subdirectories of selected dir
##  
##  Case Sense for Mask Search:  O case-sensitive  O case-INsensitive
##  
##  Files Size (KiloBytes):  _____  O bigger-than  O smaller-than
##  
##  Files Age (Days) : ______ O older-than  O younger-than
##
## --------------------------------------------------------
##
## Square brackets indicate a comment (not to be placed on the GUI).
## Braces indicate a Tk 'button' widget.
## Underscores indicate a Tk 'entry' widget.
## A colon indicates that the text before the colon is on a 'label' widget.
## Capital-O indicates a Tk 'radiobutton' widget.
## Capital-X indicates a Tk 'checkbutton' widget.
##
## NOTE that only 'Viewer Program' is a parameter involving the image viewer.
## The other parameters are for the 'find' command.
##
##+##############
## GUI components:
##
## From the GUI 'sketch' above, it is seen that the GUI consists of
## about
##   
##   -  5 button widgets
##   -  6 label widgets
##   -  3 entry widgets
##   - 11 radiobutton widgets in 5 groups
##   -  0 checkbutton widgets
##   -  0 scale widgets
##   -  0 listbox widgets
##
##+#####################################################################
## CALLED BY:  This script could be put in a sub-directory of the
##             user's home directory, such as $HOME/apps/tkBatchImgViewer.
##
##             Then the user can use their desktop system (such as
##             Gnome or KDE) to set up the script as an icon on the
##             desktop. Then the user can click on the icon to
##             startup the script.
##+########################################################################
## STRUCTURE OF THIS CODE:
##
##  0) Set general window parms (win-name, win-position, win-color-scheme,
##     fonts, widget-geom-parms, win-size-control, text-array-for-labels-etc).
##
##  1a) Define ALL frames (and sub-frames, if any).
##  1b) Pack the frames.
##
##  2) Define & pack all widgets in the frames, frame by frame.
##     After all the widgets for a frame are defined, pack them in the frame.
##
##  3) Define keyboard and/or mouse/touchpad/touch-sensitive-screen 'event'
##     BINDINGS, if needed.
##  4) Define PROCS, if needed.
##  5) Additional GUI INITIALIZATION (typically with one or more of
##     the procs), if needed.
##
## In more detail:
##
##  1a) Define ALL frames -- and sub-frames:
## 
##   Top-level :
##       'fRbuttons'     for Exit, Help, Launch, ... buttons
##       'fRfileMask'    for a directory-and-filemask entry field
##       'fRdisplayPgm'  for 2 or 3 radiobuttons, with a label
##       'fRlevels'      for 2 radiobuttons, with a label
##       'fRsense'       for 2 radiobuttons, with a label
##       'fRfileSize'    for 1 entry field and 2 radiobuttons, with a label
##       'fRfileAge'     for 1 entry field and 2 radiobuttons, with a label
##       'fRfiletype'    for 1 entry field, with a label before and after 
##
##  1b) Pack ALL frames, including sub-frames (if any).
##
##  2) Define & pack all widgets in the frames -- basically going through
##     frames & their interiors in  left-to-right, top-to-bottom order:
##
##  3) Define bindings:  See BINDINGS section below.
##
##  4) Define procs:
##
##    'get_filemask'          - called by the 'Browse...' button
##
##    'findImages_andCountPrintOrView'    - called by the 'LaunchViewer' button,
##                                         and by the 'CountFilenames' and the
##                                         'ShowFilenames' buttons.                    
##
##   'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var.
##                                         Also used via the 'CountFilenames'
##                                         and 'ShowFilenames' buttons.
##
##     For other procs, see the PROCS section below.
##
##  5) Additional GUI initialization:  See this section at the bottom
##                                     of this script.
##+#######################################################################
## DEVELOPED WITH: Tcl-Tk 8.5 on Ubuntu 9.10 (2009-october, 'Karmic Koala')
##
##   $ wish
##   % puts "$tcl_version $tk_version"
##
## showed
##     8.5 8.5
## but this script should work in most previous 8.x versions, and probably
## even in some 7.x versions (if font handling is made 'old-style').
##+########################################################################
## MAINTENANCE HISTORY:
## Started by: Blaise Montandon 2013dec08 Started development, on Ubuntu 9.10,
##                                        based on the code of a Tk script
##                                        of mine that contains most of the
##                                        widgets needed.
## Updated by: Blaise Montandon 2013dec13 Added an 'entry' widget to allow
##                                        for filtering on file-type via
##                                        the 'file' command.
## Updated by: Blaise Montandon 2014jan07 Chgd filesize from MB to KB.
## Updated by: Blaise Montandon 2014feb27 Chgd name of this script from
##                                        'imageViewer_FrontEnd.tk' to
##                                        'find_and_imageViewer_FrontEnd.tk'.
##                                        Chgd window title.
## Updated by: Blaise Montandon 2014apr25 1) Set the filename of a temporary file
##                                           to be used to hold the names of
##                                           image files found by the 'find' in
##                                           variable 'outFILE'.
##                                        2) Added PREV variables to be used to
##                                           indicate when the user has changed a
##                                           'find' criterion.
##                                        3) Added proc 'check_for_criterion_change'
##                                           to determine if a criterion variable
##                                           has been changed.
##                                        4) Changed the shell script
##                                           'findImages_andCountPrintOrView.sh'
##                                           to 'findImages_forCriteria.sh' and
##                                           changed the arguments passed to the
##                                           shell script.
##                                        5) Changed the 'count', 'print', and
##                                           'view' sections of proc
##                                           'findImages_andCountPrintOrView' 
##                                           to use file '$outFILE' if no
##                                           criterion was changed --- and to
##                                           (re)load '$outFILE' if a criterion
##                                           was changed.
##                                        6) Provided an 'xterm' window to the 'exec'
##                                           statement for the 'findImages_forCriteria.sh'
##                                           shell script, to allow for better visibility
##                                           of how a lengthy 'find' is progressing.
##+#######################################################################

##+######################################################
## Set WINDOW TITLE and POSITION.
##+######################################################

wm title    . "'find'-and-imageViewer FrontEnd, to batch-select & show imgs"

# wm title  . "tkBatchImageViewer ... with a choice of viewers"

wm iconname . "BatchImgView"

# wm geometry . +15+30
# wm geometry . +250+285
wm geometry . -10-10


##+######################################################
## Set the COLOR SCHEME for the window and its widgets ---
## such as listbox and entry field background color.
##+######################################################

tk_setPalette "#e0e0e0"


  set entryBKGD "#ffffff"
  set textBKGD  "#f0f0f0"
  set radbuttBKGD  "#ffffff"
# set chkbuttBKGD  "#ffffff"
# set scaleBKGD   "#f0f0f0"
# set listboxBKGD "#f0f0f0"


##+########################################################
## DEFINE (temporary) FONT NAMES.
##
## We use a VARIABLE-WIDTH font for text on LABEL and
## BUTTON widgets.
##
## We use a FIXED-WIDTH font for LISTBOX lists,
## for text in ENTRY fields --- and often for text in
## TEXT widgets.
##+########################################################

font create fontTEMP_varwidth \
   -family {comic sans ms} \
   -size -14 \
   -weight bold \
   -slant roman

font create fontTEMP_SMALL_varwidth \
   -family {comic sans ms} \
   -size -12 \
   -weight bold \
   -slant roman

## Some other possible (similar) variable width fonts:
##  Arial
##  Bitstream Vera Sans
##  DejaVu Sans
##  Droid Sans
##  FreeSans
##  Liberation Sans
##  Nimbus Sans L
##  Trebuchet MS
##  Verdana


font create fontTEMP_fixedwidth  \
   -family {liberation mono} \
   -size -14 \
   -weight bold \
   -slant roman

font create fontTEMP_SMALL_fixedwidth  \
   -family {liberation mono} \
   -size -12 \
   -weight bold \
   -slant roman

## Some other possible fixed width fonts (esp. on Linux):
##  Andale Mono
##  Bitstream Vera Sans Mono
##  Courier 10 Pitch
##  DejaVu Sans Mono
##  Droid Sans Mono
##  FreeMono
##  Nimbus Mono L
##  TlwgMono


##+###########################################################
## SET GEOM VARS FOR THE VARIOUS WIDGET DEFINITIONS.
## (e.g. width and height of canvas, and padding for Buttons)
##+###########################################################

## LABEL widget geom settings:

set PADXpx_label 0
set PADYpx_label 0
set BDwidthPx_label 2


## BUTTON widget geom settings:

set PADXpx_button 0
set PADYpx_button 0
set BDwidthPx_button 2


## ENTRY widget geom settings:

set BDwidthPx_entry 2


## RADIOBUTTON widget geom settings:

set PADXpx_radbutton 0
set PADYpx_radbutton 0
set BDwidthPx_radbutt 2


## CHECKBUTTON widget geom settings:

# set PADXpx_chkbutton 0
# set PADYpx_chkbutton 0
# set BDwidthPx_chkbutt 2

## TEXT widget geom settings:

set BDwidthPx_text 2


## SCALE widget geom parameters:

# set BDwidthPx_scale 2
# set scaleThicknessPx 10


##+##############################################################
## Set a TEXT-ARRAY to hold text for buttons & labels on the GUI.
##     NOTE: This can aid INTERNATIONALIZATION. This array can
##           be set according to a nation/region parameter.
##+##############################################################

## if { "$VARlocale" == "en"}

## For '.fRbuttons' frame:

set aRtext(buttonEXIT)    "Exit"
set aRtext(buttonHELP)    "Help"
set aRtext(buttonLAUNCH)  "LaunchViewerJob"
# set aRtext(buttonKILLJOB) "KillViewerJob"

set aRtext(buttonCOUNT)  "CountFilenames"
set aRtext(buttonPRINT)  "ShowFilenames"

## For '.fRfileMask' frame:

set aRtext(labelFILEMASK) "Full Filename Mask (for image/s):"
set aRtext(buttonBROWSE)  "Browse..."


## For '.fRdisplayPgm' frame:

set aRtext(labelDISPLAYPGM)   "Viewer Program:"
set aRtext(radbuttDPGM1) "1 - ImageMagick 'display'"
set aRtext(radbuttDPGM2) "2 - 'ffplay'"
set aRtext(radbuttDPGM3) "3 - 'eog'"

## For '.fRlevels' frame:

set aRtext(labelLEVELS)       "Search LEVELS for mask:"
set aRtext(radbuttLEVELSone)  "ONE"
set aRtext(radbuttLEVELSall)  "ALL subdirectories of selected directory"

## For '.fRsense' frame:

set aRtext(labelCASESENSE) "Case Sense for Mask Search:"
set aRtext(radbuttSENSE)     "case-sensitive"
set aRtext(radbuttNOSENSE)   "case-INsensitive"


## For '.fRfileSize' frame:

set aRtext(labelFILESIZE)   "Files Size (KiloBytes):"
set aRtext(radbuttBIGGER)   "bigger-than"
set aRtext(radbuttSMALLER)  "smaller-than"

## For '.fRfileAge' frame:

set aRtext(labelFILEAGE)  "Files Age (Days):"
set aRtext(radbuttOLDER)  "older-than"
set aRtext(radbuttYOUNGER)  "younger-than"

## For '.fRfileType' frame:

set aRtext(labelFILETYPE)  "Files Type:"
set aRtext(labelFILETYPE2) "Examples: JPEG or GIF or PNG or SVG or TIFF or BMP (Warning: SLOW)"

## END OF  if { "$VARlocale" == "en"}


##+######################################################################
## Set a MIN-SIZE of the window (roughly).
##
## For WIDTH, allow for the min-width of the '.fRbuttons' frame.
##
## For HEIGHT, allow for the stacked frames:
##      1 char   high for the '.fRbuttons'     frame
##      1 char   high for the '.fRfileMask'    frame
##      1 char   high for the '.fRdisplayPgm'  frame
##      1 char   high for the '.fRlevels'      frame
##      1 char   high for the '.fRsense'       frame   
##      1 char   high for the '.fRfileSize'    frame
##      1 char   high for the '.fRfileAge'     frame
##      1 char   high for the '.fRfileType'    frame
##    --------
##      8 chars  high for the 8 frames
##+#####################################################################

## FOR WIDTH: (allow for widgets in the '.fRbuttons' or '.fRfileMask' frame)

set minWidthPx [font measure fontTEMP_varwidth \
   " $aRtext(buttonEXIT) $aRtext(buttonHELP) $aRtext(buttonLAUNCH) \
$aRtext(buttonCOUNT) $aRtext(buttonPRINT) "]

## We add some pixels to account for right-left-size of
## window-manager decoration (~8 pixels) and some pixels for
## frame/widget borders (~5 widgets x 4 pixels/widget = 20 pixels).

set minWinWidthPx [expr {28 + $minWidthPx}]


## For HEIGHT --- for
##      1 char   high for the '.fRbuttons'     frame
##      1 char   high for the '.fRfileMask'    frame
##      1 char   high for the '.fRdisplayPgm'  frame
##      1 char   high for the '.fRlevels'      frame
##      1 char   high for the '.fRsense'       frame
##      1 char   high for the '.fRfileSize'    frame
##      1 char   high for the '.fRfileAge'     frame 
##      1 char   high for the '.fRfileType'    frame 
##    --------
##      8 chars  high for the 8 frames

set charHeightPx [font metrics fontTEMP_varwidth -linespace]

set minWinHeightPx [expr {8 * $charHeightPx}]


## Add about 20 pixels for top-and-bottom window decoration --
## and some pixels for top-and-bottom of frame/widget borders
## (~8 widgets x 4 pixels/widget = 32 pixels).

set minWinHeightPx [expr {52 + $minWinHeightPx}]


## FOR TESTING:
#   puts "minWinWidthPx = $minWinWidthPx"
#   puts "minWinHeightPx = $minWinHeightPx"

wm minsize . $minWinWidthPx $minWinHeightPx


## We may allow the window to be resizable.  We pack the canvases
## (and the frames that contain them) with '-fill both -expand 1'
## so that the canvases can be enlarged by enlarging the window.

## If you want to make the window un-resizable, 
## you can use the following statement.
#   wm resizable . 0 0

## We fix the y-size of the window, but allow the x-size to vary.
wm resizable . 1 0


##+####################################################################
##+####################################################################
## DEFINE *ALL* THE FRAMES:
##
##   Top-level :
##       'fRbuttons'     for Exit, Help, and Launch buttons
##       'fRfileMask'    for a filename/mask entry field
##       'fRdisplayPgm'  for 2 radiobuttons, with a label
##       'fRlevels'      for 2 radiobuttons, with a label
##       'fRsense'       for 2 radiobuttons, with a label
##       'fRfileSize'    for 1 entry field and 2 radiobuttons, with a label
##       'fRfileAge'     for 1 entry field and 2 radiobuttons, with a label
##       'fRfileType'    for 1 entry field, with a label before and after
##+####################################################################
##+####################################################################

## FOR TESTING of expansion of frames (esp. during window expansion):

# set feRELIEF_frame raised
# set feBDwidth_frame 2

 set feRELIEF_frame flat
 set feBDwidth_frame 0

frame .fRbuttons     -relief $feRELIEF_frame  -bd $feBDwidth_frame

frame .fRfileMask    -relief raised           -bd 2

frame .fRdisplayPgm -relief raised           -bd 2

frame .fRlevels      -relief $feRELIEF_frame  -bd $feBDwidth_frame
# frame .fRlevels      -relief raised           -bd 2

frame .fRsense       -relief $feRELIEF_frame  -bd $feBDwidth_frame
# frame .fRsense       -relief raised           -bd 2

frame .fRfileSize    -relief raised           -bd 2

frame .fRfileAge     -relief raised           -bd 2

frame .fRfileType    -relief raised           -bd 2


##+########################################################
## PACK *ALL* the FRAMES.
##+########################################################

pack .fRbuttons \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRfileMask \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRdisplayPgm \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRlevels \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRsense \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRfileSize \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRfileAge \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRfileType \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0


##+################################################################
##+################################################################
## START DEFINING & PACKING WIDGETS WITHIN THEIR FRAMES. 
##+################################################################
##+################################################################

##+########################################################
## IN THE '.fRbuttons' frame -- DEFINE several buttons
## --- Exit, Help, Launch.
##+########################################################

button .fRbuttons.buttEXIT \
   -text "$aRtext(buttonEXIT)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {exit}

button .fRbuttons.buttHELP \
   -text "$aRtext(buttonHELP)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {popup_msgVarWithScroll .topHelp "$HELPtext"}

## Set a variable to hold the process-ID of the viewer process.
## NOT NEEDED. See 'Kill' button attempt below.
# set ViewerPID ""

button .fRbuttons.buttLAUNCH \
   -text "$aRtext(buttonLAUNCH)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {findImages_andCountPrintOrView view}


##+########################################################
## THE FOLLOWING ATTEMPT DID NOT WORK OUT.
## The intent was to use a 'Kill' button on the GUI
## to allow for killing the 'findImages_andCountPrintOrView.sh' script
## --- if it finds lots of files to view and the user wants out.
##
## It seems the process-ID of the script soon disappeared,
## leaving the 'find' process, which had a different 
## process-ID. 
##
## It turned out to be easier to add an 'xterm' window in
## the 'findImages_andCountPrintOrView.sh' script, to run the
## 'find' command that starts the image viewing sequence.
## Closing the 'xterm' window 'kills' the 'find' command.
##+##########################################################

if {0} {

##+############################################################
## We could try using various kill signals:
##          -HUP/-SIGHUP/-1 (to kill all child processes too)
## AND/OR   -KILL/-SIGKILL/-9
## AND/OR   -TERM/-SIGTERM/-15
##+###########################################################
## References: 'man signal' and 'man kill' and 'kill -l'
##             https://wiki.tcl-lang.org/735 - 'getPid'
##+###########################################################

button .fRbuttons.buttKILLJOB \
   -text "$aRtext(buttonKILLJOB)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {
      global ViewerPID
         puts "Trying to kill ViewerPID: $ViewerPID"
      if {"$ViewerPID" != ""} {
         # exec kill -TERM $ViewerPID
         exec kill -15 $ViewerPID
         # exec kill -KILL $ViewerPID
         exec kill -9 $ViewerPID
         # set ViewerPID ""
      }
      # exit
    }

}
## END OF 'if {0}'


button .fRbuttons.buttCOUNT \
   -text "$aRtext(buttonCOUNT)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {findImages_andCountPrintOrView count}

button .fRbuttons.buttPRINT \
   -text "$aRtext(buttonPRINT)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {findImages_andCountPrintOrView print}

##+########################################
## Pack the widgets in the 'fRbuttons' frame
##+########################################

pack .fRbuttons.buttEXIT \
     .fRbuttons.buttHELP \
     .fRbuttons.buttLAUNCH \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

#     .fRbuttons.buttKILLJOB \

pack .fRbuttons.buttPRINT \
     .fRbuttons.buttCOUNT \
   -side right \
   -anchor e \
   -fill none \
   -expand 0


##+########################################################
## IN THE '.fRfileMask' frame -- DEFINE 1 LABEL widget,
## 1 ENTRY widget, and 1 BUTTON.
##+########################################################

label .fRfileMask.labelFILEMASK \
   -text "$aRtext(labelFILEMASK)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRfileMask.entryFILEMASK \
   -textvariable ENTRYfileMask \
   -bg $entryBKGD \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

## An initial value of the 'ENTRYfileMask' variable
## is set in the 'Additional GUI Initialization' section
## at the bottom of this script.

button .fRfileMask.buttBROWSE \
   -text "$aRtext(buttonBROWSE)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {get_filemask}

## PACK the widgets in the 'fRfileMask' frame.

pack  .fRfileMask.labelFILEMASK \
   -side left \
   -anchor w \
   -fill none \
   -expand 0 

pack .fRfileMask.entryFILEMASK \
   -side left \
   -anchor w \
   -fill x \
   -expand 1 

pack .fRfileMask.buttBROWSE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0 


##+########################################################
## IN THE '.fRdisplayPgm' frame -- DEFINE
##  2 RADIOBUTTONS, preceded by a LABEL widget.
##+########################################################

label .fRdisplayPgm.labelDISPLAYPGM \
   -text "$aRtext(labelDISPLAYPGM)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## DEFINE Radiobuttons for display sizes :

radiobutton  .fRdisplayPgm.radbuttDPGM1 \
   -text "$aRtext(radbuttDPGM1)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARdisplaypgm \
   -value "1" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

radiobutton  .fRdisplayPgm.radbuttDPGM2 \
   -text "$aRtext(radbuttDPGM2)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARdisplaypgm \
   -value "2" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

radiobutton  .fRdisplayPgm.radbuttDPGM3 \
   -text "$aRtext(radbuttDPGM3)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARdisplaypgm \
   -value "3" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

## RADVARdisplaypgm is the var for these several radiobuttons.
## Set an initial value.
  set RADVARdisplaypgm "1"
# set RADVARdisplaypgm "2"
# set RADVARdisplaypgm "3"

## PACK the widgets in the 'fRdisplayPgm' frame.

pack  .fRdisplayPgm.labelDISPLAYPGM \
      .fRdisplayPgm.radbuttDPGM1 \
      .fRdisplayPgm.radbuttDPGM2 \
      .fRdisplayPgm.radbuttDPGM3 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0 



##+########################################################
## IN THE '.fRlevels' frame -- DEFINE
## 2 RADIOBUTTONS, preceded by a LABEL widget.
##+########################################################

label .fRlevels.labelLEVELS \
   -text "$aRtext(labelLEVELS)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## DEFINE Radiobuttons for Levels :

radiobutton  .fRlevels.radbuttLEVELSone \
   -text "$aRtext(radbuttLEVELSone)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARlevels \
   -value "one" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

radiobutton  .fRlevels.radbuttLEVELSall \
   -text "$aRtext(radbuttLEVELSall)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARlevels \
   -value "all" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

## RADVARlevels is the var for these 2 radiobuttons.
## Set an initial value.
  set RADVARlevels "one"
# set RADVARlevels "all"

## PACK the widgets in the 'fRlevels' frame.

pack  .fRlevels.labelLEVELS \
      .fRlevels.radbuttLEVELSone \
      .fRlevels.radbuttLEVELSall \
   -side left \
   -anchor w \
   -fill none \
   -expand 0 


##+########################################################
## IN THE 'fRsense' frame -- DEFINE
## 2 RADIOBUTTONS, preceded by a LABEL widget.
##+########################################################

label .fRsense.labelCASESENSE \
   -text "$aRtext(labelCASESENSE)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## DEFINE Radiobuttons for CaseSensitivity :

radiobutton  .fRsense.radbuttSENSE \
   -text "$aRtext(radbuttSENSE)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARcasesense \
   -value "case-sensitive" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

radiobutton  .fRsense.radbuttNOSENSE \
   -text "$aRtext(radbuttNOSENSE)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARcasesense \
   -value "case-INsensitive" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt


## RADVARcasesense is the var for these 2 radiobuttons.
## Set an initial value.
  set RADVARcasesense "case-sensitive"
# set RADVARcasesense "case-INsensitive"


## PACK the widgets in the 'fRsense' frame:

pack  .fRsense.labelCASESENSE \
      .fRsense.radbuttSENSE \
      .fRsense.radbuttNOSENSE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+############################################################
## IN THE 'fRfileSize' frame -- DEFINE
## 1 ENTRY field and 2 RADIOBUTTONS, preceded by a LABEL widget.
##+############################################################

label .fRfileSize.labelFILESIZE \
   -text "$aRtext(labelFILESIZE)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRfileSize.entryFILESIZE \
   -textvariable ENTRYfileSize \
   -bg $entryBKGD \
   -width 10 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

## DEFINE Radiobuttons for File Size :

radiobutton  .fRfileSize.radbuttBIGGER \
   -text "$aRtext(radbuttBIGGER)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARfilesize \
   -value "bigger" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

radiobutton  .fRfileSize.radbuttSMALLER \
   -text "$aRtext(radbuttSMALLER)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARfilesize \
   -value "smaller" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt


## RADVARfilesize is the var for these 2 radiobuttons.
## Set an initial value.
  set RADVARfilesize "bigger"
# set RADVARfilesize "smaller"


## PACK the widgets in the 'fRfileSize' frame:
## (in such a way that we can experiment with
##  letting the entry field expand)

pack .fRfileSize.labelFILESIZE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRfileSize.entryFILESIZE \
   -side left \
   -anchor w \
   -fill x \
   -expand 1

pack .fRfileSize.radbuttBIGGER \
     .fRfileSize.radbuttSMALLER \
   -side left \
   -anchor w \
   -fill none \
   -expand 0



##+########################################################
## IN THE 'fRfileAge' frame -- DEFINE 
## 1 ENTRY field and 2 RADIOBUTTONS, preceded by a LABEL widget.
##+########################################################

label .fRfileAge.labelFILEAGE \
   -text "$aRtext(labelFILEAGE)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRfileAge.entryFILEAGE \
   -textvariable ENTRYfileAge \
   -bg $entryBKGD \
   -width 10 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry


## DEFINE Radiobuttons for File Age :

radiobutton  .fRfileAge.radbuttOLDER \
   -text "$aRtext(radbuttOLDER)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARfileage \
   -value "older" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

radiobutton  .fRfileAge.radbuttYOUNGER \
   -text "$aRtext(radbuttYOUNGER)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable RADVARfileage \
   -value "younger" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt


## RADVARfileage is the var for these 2 radiobuttons.
## Set an initial value.
  set RADVARfileage "older"
# set RADVARfileage "younger"


## PACK the widgets in the 'fRfileAge' frame:
## (in such a way that we can experiment with
##  letting the entry field expand)

pack .fRfileAge.labelFILEAGE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRfileAge.entryFILEAGE \
   -side left \
   -anchor w \
   -fill x \
   -expand 1

pack .fRfileAge.radbuttOLDER \
     .fRfileAge.radbuttYOUNGER \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+########################################################
## IN THE 'fRfileType' frame -- DEFINE 
## 1 ENTRY field, with 2 LABEL widgets, before and after.
##+########################################################

label .fRfileType.labelFILETYPE \
   -text "$aRtext(labelFILETYPE)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRfileType.entryFILETYPE \
   -textvariable ENTRYfileType \
   -bg $entryBKGD \
   -width 10 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRfileType.labelFILETYPE2 \
   -text "$aRtext(labelFILETYPE2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label


## PACK the widgets in the 'fRfileType' frame:
## (in such a way that we can experiment with
##  letting the entry field expand)

pack .fRfileType.labelFILETYPE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRfileType.entryFILETYPE \
   -side left \
   -anchor w \
   -fill x \
   -expand 1

pack .fRfileType.labelFILETYPE2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+#####################################################################
## END OF SECTION TO DEFINE AND PACK THE GUI WIDGETS.
##+#####################################################################

##+#####################################################################
##+#####################################################################
## DEFINE BINDINGS:  button1-release bindings on some widgets ???
##                   Return-key bindings on some entry widgets ???
##+#####################################################################

# bind .fR?????.???widget???  <ButtonRelease-1>  {??proc??}
# bind .fR?????.???widget???  <Return>  {??proc??}

## As the user types in the file-mask entry field (KeyRelease events), make sure
## the area near the insertion cursor or the character entry is showing.
## (Strange? 'KeyRelease' works, but 'KeyPress' leaves the insert cursor at the
## end of the field and ALWAYS slightly out of view to the right. It's as if
## a backspace occurs after the KeyPress.)

bind .fRfileMask.entryFILEMASK <KeyRelease> \
   {.fRfileMask.entryFILEMASK xview insert}

## FOR TESTING:
#   bind .fRfileMask.entryFILEMASK <KeyPress> {
#      set entFILEMASKxview [.fRfileMask.entryFILEMASK xview]
#      puts ".fRfileMask.entryFILEMASK 'offset' and 'span': $entFILEMASKxview"
#   }

## An alternative?
# bind .fRfileMask.entryFILEMASK <KeyRelease> \
#     {.fRfileMask.entryFILEMASK xview moveto 1.0}


##+#####################################################################
##+#####################################################################
## DEFINE PROCEDURES:
##
##  'get_filemask'         - called by the 'Browse...' button
##                           next to the filemask entry field
##
##  'get_chars_before_last'  - called by proc 'get_filemask'
##
##  'check_for_criterion_change' - called by the proc
##                                 'findImages_andCountPrintOrView'
##
##  'findImages_andCountPrintOrView'   - called by the 'LaunchViewer' button
##                                      --- and the 'CountFilenames' and
##                                      'ShowFilenames' buttons
##
##  'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var.
##                             Also called via the  'CountFilenames' and
##                             'ShowFilenames' buttons
##+#####################################################################
##+#####################################################################

##+#####################################################################
## Proc 'get_filemask'
##
## PURPOSE: To get the fully-qualified name of a file and put the
##          name into global var 'ENTRYfileMask'.
##
##          The user may change the filename (after the end of the
##          directory name) to change it into a file-mask. 
##
## CALLED BY: the '-command' option of the 'Browse ...' button.
##+#####################################################################


proc get_filemask {} {

   global ENTRYfileMask env curDIR

   ## Get a file name (possibly to make a mask).

   set fName [tk_getOpenFile -parent .  \
      -title "Select Directory-and-Filename - the latter as basis for a mask" \
      -initialdir "$curDIR" ]

   ## FOR TESTING:
   #   puts "fName : $fName"

   ## Check if fName var is empty.

   if {"$fName" == ""} {return}

   ## Put $fName in ENTRYfileMask. Reset the curDIR var.

   if {[file exists "$fName"]} {
      set ENTRYfileMask "$fName"

      ## Put the end of the filename in view.
      .fRfileMask.entryFILEMASK xview end

      set curDIR [ get_chars_before_last / in "$ENTRYfileMask" ]
   }
   ## END OF if directory-exists

}
## END OF proc 'get_filemask'


##+###################################################################
## PROC  'get_chars_before_last'
##+###################################################################
## INPUT:  A character 'char' and a string 'strng'.
##         Note: The "in" parameter is there only for clarity.
##
## OUTPUT: Returns all of the characters in the string "strng" that
##         are BEFORE the last occurence of the characater "char".
##
## CALLED BY: proc 'get_img_filename'
##+##################################################################

proc get_chars_before_last { char in strng } {

   set endIDX [ expr [string last $char $strng ] - 1 ]
   set output [ string range $strng 0 $endIDX ]

   ## FOR TESTING:
   # puts "From 'get_chars_before_last' proc:"
   # puts "STRING: $strng"
   # puts "CHAR: $char"
   # puts "RANGE up to LAST CHAR - start: 0   endIDX: $endIDX"

   return $output

}
## END OF 'get_chars_before_last' PROCEDURE


##+#############################################################
## PROC  'check_for_criterion_change'
##+#############################################################
## PURPOSE: Returns 1 or 0 depending on whether the 'find' criteria
##          have been changed or not.
##
## CALLED BY: proc 'findImages_andCountPrintOrView'
##+#################################################################

proc check_for_criterion_change {} {

   ## INPUT globals:
   global ENTRYfileMask RADVARlevels RADVARcasesense \
          RADVARfilesize ENTRYfileSize \
          RADVARfileage ENTRYfileAge ENTRYfileType \
          PREV_ENTRYfileMask PREV_RADVARlevels PREV_RADVARcasesense \
          PREV_RADVARfilesize PREV_ENTRYfileSize \
          PREV_RADVARfileage PREV_ENTRYfileAge PREV_ENTRYfileType

   ## FOR TESTING:
   if {0} {
      puts "Entering proc 'check_for_criterion_change'."
      puts "PREV_ENTRYfileMask: $PREV_ENTRYfileMask       ENTRYfileMask: $ENTRYfileMask"
      puts "PREV_RADVARlevels: $PREV_RADVARlevels         RADVARlevels: $RADVARlevels"
      puts "PREV_RADVARcasesense: $PREV_RADVARcasesense   RADVARcasesense: $RADVARcasesense"
      puts "PREV_RADVARfilesize: $PREV_RADVARfilesize     RADVARfilesize: $RADVARfilesize"
      puts "PREV_ENTRYfileSize: $PREV_ENTRYfileSize       ENTRYfileSize: $ENTRYfileSize"
      puts "PREV_RADVARfileage: $PREV_RADVARfileage       RADVARfileage: $RADVARfileage"
      puts "PREV_ENTRYfileAge: $PREV_ENTRYfileAge         ENTRYfileAge: $ENTRYfileAge"
      puts "PREV_ENTRYfileType: $PREV_ENTRYfileType       ENTRYfileType: $ENTRYfileType"
   }

   ## Return 1 if at least one of the criteria has been changed.
   ## Return 0 otherwise.

   if {"$PREV_ENTRYfileMask" != "$ENTRYfileMask"} {
      return 1
   } elseif {"$PREV_RADVARlevels" != "$RADVARlevels"} {
      return 1
   } elseif {"$PREV_RADVARcasesense" != "$RADVARcasesense"} {
         return 1
   } elseif {"$PREV_RADVARfilesize" != "$RADVARfilesize"} {
      return 1
   } elseif {"$PREV_ENTRYfileSize" != "$ENTRYfileSize"} {
      return 1
   } elseif {"$PREV_RADVARfileage" != "$RADVARfileage"} {
      return 1
   } elseif {"$PREV_ENTRYfileAge" != "$ENTRYfileAge"} {
      return 1
   } elseif {"$PREV_ENTRYfileType" != "$ENTRYfileType"} {
      return 1
   } else {
      return 0
   }

}
## END OF 'check_for_criterion_change' PROCEDURE


##+#############################################################
## PROC  'findImages_andCountPrintOrView'
##+#############################################################
## PURPOSE: The function of this proc depends on the value of
##          the 'option' parm passed to this proc. Its values
##          can be 'count' or 'print' or 'view'.
##
##          For option='count', this proc provides a COUNT
##          of the filenames found via a 'find' command and the
##          user-specified find-criteria. The COUNT is provided
##          in a popup GUI window.
##
##          For option='print', this proc provides a LIST
##          of the filenames found via a 'find' command and the
##          user-specified find-criteria. The LIST is provided
##          in a popup GUI window.
##
##          For option='view', this proc starts DISPLAYING
##          the filenames found via a 'find' command and the
##          user-specified find-criteria. The DISPLAY is
##          provided via the user-specified DISPLAY PROGRAM.
##
## CRITERIA CHECKING:
##
##          For any of the 3 options passed to this proc, this proc
##          does some checking of the GUI interface parameters,
##          especially from the 'entry' widgets.
##
## THE METHOD:
##
##          Since the user may be searching a deep directory hierarchy
##          that may contain thousands of image files, for each of the
##          3 'count/print/view' options, this proc checks if the
##          find-criteria have been changed by the user.
##
##          IF THERE IS A CHANGE in the 'find'-criteria (or if no
##          'find' run has been performed yet), a shell script,
##          'findImages_forCriteria.sh', is run to put the
##          image filenames in a file '$outFILE'.
##
##          The user-specified 'find' criteria from the GUI are passed as
##          arguments to the 'findImages_forCriteria.sh' shell script.
##
##          ON THE OTHER HAND,
##          if there is NO CHANGE in find-criteria, the 'count/print/view'
##          processing is performed using the '$outFILE' that contains the
##          (image) filenames returned by a previous 'find' run.
##
## PROGRESS AND KILL CAPABILITIES:
##
##          Whenever the 'findImages_forCriteria.sh' shell script is run,
##          the script is started in an 'xterm' --- to provide the user an
##          easy way to kill the 'find' process if the user wants to
##          interrupt a long running 'find' command.
##
##          Also, the 'xterm' provides a way to indicate the progress of
##          the 'find' command, by displaying filenames (or a shorter
##          indicator) of the files being found.
##
## THE 'COUNT' OPTION:
##
##          The 'count' option applies the 'wc -l' command to '$outFILE'
##          in a Tcl 'exec' statement, to get the count for display
##          in a popup Tk window.
##
## THE 'PRINT' OPTION:
##
##          The 'print' option applies the 'cat' command to '$outFILE'
##          in a Tcl 'exec' statement, to get the list of filenames
##          for display in a popup Tk window.
##
## THE 'VIEW' OPTION:
##
##          The 'view' option uses a 'forLoop_displayImgsInFile.sh'
##          shell script, run in another 'xterm' window, to display
##          the image files from '$outFILE' in a sequence.
##
##          The 'xterm' provides the user a way to kill the 'display'
##          process/sequence if the user wants to stop the display.
##
## THIS PROC IS CALLED BY:
##            - a 'Count'  button with option='count', OR
##            - a 'List'   button with option='print', OR
##            - a 'Launch' button with option='view'
##+#############################################################

proc findImages_andCountPrintOrView {option} {

   global DIRscripts ENTRYfileMask RADVARdisplaypgm \
      RADVARlevels RADVARcasesense \
      RADVARfilesize ENTRYfileSize \
      RADVARfileage  ENTRYfileAge \
      ENTRYfileType outFILE FindPID ViewerPID \
      PREV_ENTRYfileMask PREV_RADVARlevels PREV_RADVARcasesense \
      PREV_RADVARfilesize PREV_ENTRYfileSize \
      PREV_RADVARfileage PREV_ENTRYfileAge PREV_ENTRYfileType

   #######################################################
   ## Remove trailing and leading blanks (if any) from the
   ## user entries in the 'entry' widgets.
   #######################################################

   set ENTRYfileMask [string trim $ENTRYfileMask]
   set ENTRYfileSize [string trim $ENTRYfileSize]
   set ENTRYfileAge  [string trim $ENTRYfileAge]
   set ENTRYfileType [string trim $ENTRYfileType]

   #################################################################
   ## The variables RADVARdisplaypgm, RADVARlevels, RADVARcasesense,
   ## RADVARfilesize, and RADVARfileage are set as single
   ## words in this script and should not need any editing
   ## or checking (if bug-free).
   #################################################################

   ##########################################################
   ## Check that ENTRYfileSize and ENTRYfileAge are integers,
   ## if they are not blank (null).
   ##########################################################

   if {"$ENTRYfileSize" != ""} {
      if {![string is integer -strict "$ENTRYfileSize"]} {
         popup_msgVarWithScroll .topErr \
            "File Size: $ENTRYfileSize  is NOT NUMERIC."
         return
      }
   }
   

   if {"$ENTRYfileAge" != ""} {
      if {![string is integer -strict "$ENTRYfileAge"]} {
         popup_msgVarWithScroll .topErr \
            "File Age: $ENTRYfileAge  is NOT NUMERIC."
         return
      }
   }


   ## FOR TESTING:  (to dummy out the rest of this proc)

   # return

   ################################################################
   ## Check if the criteria have changed. If so, run the
   ## shell script 'findImages_forCriteria.sh' to put found
   ## image filenames in file '$outFILE'.
   ################################################################

   ## FOR TESTING:
   #   set Change0or1 [check_for_criterion_change]
   #   puts "Change0or1: $Change0or1"

   if {[check_for_criterion_change] == 1} {

      ## Reset the PREV variables since there has been at least one
      ## criterion change.

      set PREV_ENTRYfileMask   "$ENTRYfileMask"
      set PREV_RADVARlevels    "$RADVARlevels"
      set PREV_RADVARcasesense "$RADVARcasesense"
      set PREV_RADVARfilesize  "$RADVARfilesize"
      set PREV_ENTRYfileSize   "$ENTRYfileSize"
      set PREV_RADVARfileage   "$RADVARfileage"
      set PREV_ENTRYfileAge    "$ENTRYfileAge"
      set PREV_ENTRYfileType   "$ENTRYfileType"

      ## Make sure we put the output in a new (empty) output file.

      catch {exec rm "$outFILE"}

      #############################################################
      ## Run the 'find' script in an 'xterm' so that 'progress
      ## indicators' can be seen. Do not use '-hold' on 'xterm'
      ## so that the user does not have to close the 'xterm' window.
      ## Run the xterm-and-find-script in the foreground --- to
      ## prevent another 'find' from being started.
      #############################################################

      set RETcode [catch {exec xterm -fg white -bg black \
         -title "To 'kill' the FIND of image files, close this window." \
         -geometry 90x5-30-30 -e \
         $DIRscripts/findImages_forCriteria.sh "$ENTRYfileMask" \
         "$RADVARlevels" "$RADVARcasesense" \
         "$RADVARfilesize" "$ENTRYfileSize" \
         "$RADVARfileage"  "$ENTRYfileAge" \
         "$ENTRYfileType"  "$outFILE"}  FindPID]

      ## FOR TESTING:
      #   puts "FindPID: $FindPID"

      if { $RETcode != 0 } then {
         set ERRmsg \
         "ERROR from attempt to run the 'findImages_forCriteria.sh' script.

RETcode: $RETcode
Message: $FindPID"
         popup_msgVarWithScroll .topErr "$ERRmsg"
         return
      }
      ## END OF   if { $RETcode != 0 }
   }

   ###############################################################
   ## If option = 'count', use 'wc -l' on file "$outFILE" to
   ## return a count of the 'found' filenames, displayed
   ## in a small popup Tk window. Example output from 'wc -l':
   ## 22 /tmp/fred_tkBatchImgViewer_filenames.lis
   ###############################################################

   if {"$option" == "count"} {
      set wcOUT [exec wc -l "$outFILE"]
      set VARlist [ split "$wcOUT" " " ]
      set FILEScount [lindex $VARlist 0]

      set COUNTmsg "$FILEScount files 'found' with the
current file mask:
   $ENTRYfileMask

and other GUI settings."
      popup_msgVarWithScroll .topCount "$COUNTmsg"
      return
   }
   ## END OF  if {"$option" == "count"}


   ###############################################################
   ## If option = 'print', use 'cat' on file "$outFILE" to
   ## return a list of the 'found' filenames, displayed
   ## in a popup Tk window.
   ###############################################################
   ## NOTE: We could change this function slightly to
   ##       let the user put the filenames in a text file,
   ##       say in a '/tmp' directory. This would be better
   ##       in cases when the list is huge.
   ############################################################

   if {"$option" == "print"} {
      set FILESlist [exec cat "$outFILE"]

      if {"$FILESlist" == "" } {set FILESlist "NONE"}
         set FILESmsg "Filenames that were 'found' with the
current file mask:
   $ENTRYfileMask

and other GUI settings:

$FILESlist"
      popup_msgVarWithScroll .topList "$FILESmsg"
      return
   }
   ## END OF  if {"$option" == "print"}


   ###############################################################
   ## If option = 'view',
   ## run the 'forLoop_displayImgsInFile.sh' shell script to run
   ## the specified image viewer program on the selected files.
   ###############################################################
   ## Attempts were made to use the 'ViewerPID' process ID
   ## which is set below, to allow the user to cancel the
   ## viewing sequence by means of a 'Kill' button on this GUI.
   ## THOSE ATTEMPTS DID NOT WORK.
   ####################################################################
   ## SOME SYNTAX NOTES on storing the process-ID from a Tcl 'exec':
   ##
   ## A couple of examples of using a PID (process ID) with Tcl:
   ##
   ## catch {eval exec $feREADER_text \"$FULFILname\"  &} ViewerPID
   ##
   ## set RETcode [ catch {eval exec ${feDIR}/tkGUIs/shofil.tk \
   ##    "$FULFILname" &} ViewerPID ]
   ##
   ## An alternative from of trying 'exec':
   ##    exec  /bin/sh -c "$...."
   #######################################################################
   ## From page 107 of 4th edition of 'Practical Programming in Tcl & Tk',
   ## on the Tcl 'exec' command:
   ## "A trailing & causes the program to run in the background.
   ##  In this case, the process identifier is returned by the 'exec'
   ##  command. Otherwise, the 'exec' command blocks during execution
   ##  of the program, and the standard output of the program is the
   ##  return code of 'exec'."
   ## Page 83 of the same book says:
   ## "'catch' returns zero if there was no error caught,
   ##   or a nonzero error code if it did catch an error."
   ###############################################################

   if {"$option" == "view"} {

      ######################################################
      ## Check that there is at least one file to display.
      ######################################################

      set wcOUT [exec wc -l "$outFILE"]
      set VARlist [ split "$wcOUT" " " ]
      set FILEScount [lindex $VARlist 0]
      if {$FILEScount < 1 } {
         set ERRmsg "No image filenames were 'found' with the
current file mask:
   $ENTRYfileMask

and other GUI settings."
         popup_msgVarWithScroll .topList "$ERRmsg"
         return
      }
      ## END OF if {$FILEScount < 1 } 


      ######################################################
      ## Set the image viewer command, along with parameters
      ## to be used in the command.
      ######################################################

      set IMGVIEWcmd "/usr/bin/display -geometry +15+30"

      if {"$RADVARdisplaypgm" == "2"} {
         ## Unfortunately, 'ffplay' does not support '-geometry'.
         set IMGVIEWcmd "/usr/bin/ffplay"
      } elseif {"$RADVARdisplaypgm" == "3"} {
         ## 'eog' automatically centers the display on the screen.
         ## 'eog' command-line Options:
         ##  -f, --fullscreen                Open in fullscreen mode
         ##  -c, --disable-image-collection  Disable image collection
         ##  -s, --slide-show                Open in slide show mode
         ##  -n, --new-instance              Start a new instance instead of
         ##                                  reusing an existing one
         set IMGVIEWcmd "/usr/bin/eog -c -n -f"
      }


      #################################################################
      ## Run the 'forLoop_displayImgsInFile.sh' shell script
      ## in an 'xterm' --- to allow for killing the play sequence and
      ## allow for messages indicating how many files have been played.
      #################################################################

      set RETcode [catch {exec xterm -fg white -bg black \
         -title "To 'kill' the DISPLAY SEQUENCE of image files, close this window." \
         -geometry 100x5-30-30 -e \
         $DIRscripts/forLoop_displayImgsInFile.sh \
         "$IMGVIEWcmd" "$outFILE" &}  ViewerPID]

      ## FOR TESTING:
      #   puts "ViewerPID: $ViewerPID"

      if { $RETcode != 0 } then {
         set ERRmsg \
         "ERROR from attempt to run the 'forLoop_displayImgsInFile.sh' script.

RETcode: $RETcode
Message: $ViewerPID"
         popup_msgVarWithScroll .topErr "$ERRmsg"
         return
      }
      ## END OF   if { $RETcode != 0 }

   }
   ## END OF  if {"$option" == "view"}

}
## END OF proc 'findImages_andCountPrintOrView'


##+########################################################################
## PROC 'popup_msgVarWithScroll'
##+########################################################################
## PURPOSE: Report help or error conditions to the user.
##
##       We do not use focus,grab,tkwait in this proc,
##       because we use it to show help when the GUI is idle,
##       and we may want the user to be able to keep the Help
##       window open while doing some other things with the GUI
##       such as putting a filename in the filename entry field
##       or clicking on a radiobutton.
##
##       For a similar proc with focus-grab-tkwait added,
##       see the proc 'popup_msgVarWithScroll_wait' in a
##       3DterrainGeneratorExaminer Tk script.
##
## REFERENCE: page 602 of 'Practical Programming in Tcl and Tk',
##            4th edition, by Welch, Jones, Hobbs.
##
## ARGUMENTS: A toplevel frame name (such as .fRhelp or .fRerrmsg)
##            and a variable holding text (many lines, if needed).
##
## CALLED BY: 'help' button
##+########################################################################
## To have more control over the formatting of the message (esp.
## words per line), we use this 'toplevel-text' method, 
## rather than the 'tk_dialog' method -- like on page 574 of the book 
## by Hattie Schroeder & Mike Doyel,'Interactive Web Applications
## with Tcl/Tk', Appendix A "ED, the Tcl Code Editor".
##+########################################################################

proc popup_msgVarWithScroll { toplevName VARtext } {

   ## global fontTEMP_varwidth #; Not needed. 'wish' makes this global.
   ## global env

   # bell
   # bell
  
   #################################################
   ## Set VARwidth & VARheight from $VARtext.
   #################################################
   ## To get VARheight,
   ##    split at '\n' (newlines) and count 'lines'.
   #################################################
 
   set VARlist [ split $VARtext "\n" ]

   ## For testing:
   #  puts "VARlist: $VARlist"

   set VARheight [ llength $VARlist ]

   ## For testing:
   #  puts "VARheight: $VARheight"


   #################################################
   ## To get VARwidth,
   ##    loop through the 'lines' getting length
   ##     of each; save max.
   #################################################

   set VARwidth 0

   #############################################
   ## LOOK AT EACH LINE IN THE LIST.
   #############################################
   foreach line $VARlist {

      #############################################
      ## Get the length of the line.
      #############################################
      set LINEwidth [ string length $line ]

      if { $LINEwidth > $VARwidth } {
         set VARwidth $LINEwidth 
      }

   }
   ## END OF foreach line $VARlist

   ## For testing:
   #    puts "VARwidth: $VARwidth"


   ###############################################################
   ## NOTE: VARwidth works for a fixed-width font used for the
   ##       text widget ... BUT the programmer may need to be
   ##       careful that the contents of VARtext are all
   ##       countable characters by the 'string length' command.
   ###############################################################


   #####################################
   ## SETUP 'TOP LEVEL' HELP WINDOW.
   #####################################

   catch {destroy $toplevName}
   toplevel  $toplevName

   # wm geometry $toplevName 600x400+100+50

   wm geometry $toplevName +100+50

   wm title     $toplevName "Note"
   # wm title   $toplevName "Note to $env(USER)"

   wm iconname  $toplevName "Note"


   #####################################
   ## In the frame '$toplevName' -
   ## DEFINE THE TEXT WIDGET and
   ## its two scrollbars --- and
   ## DEFINE an OK BUTTON widget.
   #####################################

   if {$VARheight > 10 || $VARwidth > 100} {
      text $toplevName.text \
         -wrap none \
         -font fontTEMP_fixedwidth \
         -width  $VARwidth \
         -height $VARheight \
         -bg "#f0f0f0" \
         -relief raised \
         -bd 2 \
         -yscrollcommand "$toplevName.scrolly set" \
         -xscrollcommand "$toplevName.scrollx set"

      scrollbar $toplevName.scrolly \
         -orient vertical \
         -command "$toplevName.text yview"

      scrollbar $toplevName.scrollx \
         -orient horizontal \
         -command "$toplevName.text xview"
   } else {
      text $toplevName.text \
         -wrap none \
         -font fontTEMP_fixedwidth \
         -width  $VARwidth \
         -height $VARheight \
         -bg "#f0f0f0" \
         -relief raised \
         -bd 2 
   }

   button $toplevName.butt \
      -text "OK" \
      -font fontTEMP_varwidth \
      -command  "destroy $toplevName"

   ###############################################
   ## PACK *ALL* the widgets in frame '$toplevName'.
   ###############################################

   ## Pack the bottom button BEFORE the
   ## bottom x-scrollbar widget,

   pack  $toplevName.butt \
      -side bottom \
      -anchor center \
      -fill none \
      -expand 0


   if {$VARheight > 10 || $VARwidth > 100} {
      ## Pack the scrollbars BEFORE the text widget,
      ## so that the text does not monopolize the space.

      pack $toplevName.scrolly \
         -side right \
         -anchor center \
         -fill y \
         -expand 0

      ## DO NOT USE '-expand 1' HERE on the Y-scrollbar.
      ## THAT ALLOWS Y-SCROLLBAR TO EXPAND AND PUTS
      ## BLANK SPACE BETWEEN Y-SCROLLBAR & THE TEXT AREA.
                
      pack $toplevName.scrollx \
         -side bottom \
         -anchor center \
         -fill x  \
         -expand 0

      ## DO NOT USE '-expand 1' HERE on the X-scrollbar.
      ## THAT KEEPS THE TEXT AREA FROM EXPANDING.

      pack $toplevName.text \
         -side top \
         -anchor center \
         -fill both \
         -expand 1
   } else {
      pack $toplevName.text \
         -side top \
         -anchor center \
         -fill both \
         -expand 1
   }


   #####################################
   ## LOAD MSG INTO TEXT WIDGET.
   #####################################

   ##  $toplevName.text delete 1.0 end
 
   $toplevName.text insert end $VARtext
   
   $toplevName.text configure -state disabled
  
}
## END OF PROC 'popup_msgVarWithScroll'


##+########################
## END of PROC definitions.
##+########################
## Set HELPtext var.
##+########################


set HELPtext \
"   ** HELP for this 'Tk Batch-find-and-Image-View' Utility **

** essentially a 'wrapper' for the 'find' command and an image viewer **

This utility provides a GUI for

1) finding a 'batch' of image files according to
   user-specified criteria that are prompted for via
   entry widgets and radiobutton widgets on the GUI,

AND

2) starting up an image file viewer program --- like the
   ImageMagick 'display' program or the 'ffplay' program or
   the 'eog' (Eye of Gnome) program --- to view the 'batch'
   of image files that were found, via the 'find' command.

Hence, the GUI is a 'front-end' for the 'find' command and
an image viewing command.

The GUI is intended to make the user aware of the main
(most useful) options available without the user needing
to reference the 'man find' command and 'man display' or
'man ffplay' or 'man eog' commands --- nor other
'find'/'display'/'ffplay'/'eog' documentation, for example,
via web searches.

A different image viewer program could be added by some simple
changes in the Tk script 'find_and_imageViewer_FrontEnd.tk'.

The intent of this utility is to allow the user to
easily specify image files to be viewed --- via specifying:
 1  - a directory-and-filename (the latter is typically a 'mask')
 2  - whether files in sub-directories should be mask-searched
 3  - whether the mask-search should be case-INsensitive
 4  - an optional file-size limitation
 5  - an optional file-age limitation
 6  - an optional file-type string (typically JPEG or GIF or PNG).
These are parameters for the 'find' operation.

In addition, the GUI prompts for
 7  - which of several image viewer programs to use.

NOTE that most image-viewers are oriented toward scanning
through ALL image files in a SINGLE directory.

This utility is oriented toward SELECTING image files (based
criteria such as a file-mask, file-size, file-age, and/or file-type)
from an ENTIRE HIERARCHY OF SUB-DIRECTORIES --- as well as
allowing mask-search in a SINGLE directory.

And a single file can be viewed by selecting a single filename
and NOT changing the name to a mask --- a mask like *.jpg  OR
*blue*.gif  OR  a*.PNG. 
           
**********************
NOTES ON OTHER VIEWERS:
**********************

As an alternative to 'eog', it would be easy to use
the 'Eye of MATE' (say 'eom') image viewer instead.
'eom' is the image viewer that the MATE desktop project
forked from 'eog'. Reference: www.mate-desktop.org

Circa 2010, some Argentinians decided to fork the
Gnome 2.x desktop environment --- when the Gnome 3
project abandoned many of the features of Gnome 2 and its
associated applications --- applications like the 'Nautilus'
file manager and the 'Eye of Gnome' image viewer.

  (The fork of the 'Nautilus' file manager is called 'Caja'
   --- Spanish for 'box' or 'gift'.)

Of course, still other 'light-weight' image viewers
could be used with very few changes. The 'core' changes would
be to the Tk script 'find_and_imageViewer_FrontEnd.tk'.

The Tk script was initially programmed to use 'display' or
'ffplay' or 'eog' for the image viewer --- along with
the 'find' command --- and along with parameters
supplied from this GUI. Any of those three viewers could
easily be replaced by another viewer program.

***************
THE GUI WIDGETS:
***************

The GUI offers a generous set of hints, help, and options
for the user.  In fact, the GUI consists of about

   -  8 label widgets
   -  5 button widgets
   -  4 entry widgets
   - 11 radiobutton widgets in 5 groups
   -  0 checkbutton widgets
   -  0 scale widgets
   -  0 listbox widgets

The main controls are via the 'button', 'entry', and 'radiobutton'
widgets. Hence there are about 20 control options available.

*************
TYPICAL USAGE:
*************

You can use the 'Browse...' button to retrieve a full filename
to the file/mask name entry field. This allows one to establish
a 'base' directory for the 'find' command. And the user can change
the filename after the directory name, to a mask. Examples:
Reunion*.JPG   OR   *.gif   OR   *OLD*.png

Before clicking on the 'LaunchViewerJob' button,
you can also change radiobutton settings as needed --- and
enter an integer in the FileSize and/or FileAge entry fields,
if you want to use size or age to reduce the filenames found
via the specified mask.

******************************
FILE-TYPE Field Considerations:
******************************

If you want to select files via the FileType entry field
(rather than a file-mask involving a file-suffix), you can
make the file mask something like '*' or '*OLD*' (no file
suffix) and put a string in the file-type field ---
typically JPEG or GIF or PNG.

When you put an entry in the 'FileType' field, the 'file' command
is executed on every file scanned, throughout the directory structure.
The 'file' command returns text strings like the following (on image files):

Typical
Suffix    'file' output
-------   -----------------------------------

.gif      GIF image data, version 89a, 256 x 352
.jpg      JPEG image data, JFIF standard 1.01
.png      PNG image, 1024 x 768, 8-bit/color RGB, non-interlaced
.svg      SVG Scalable Vector Graphics image
.tif      TIFF image data, little-endian
.xpm      X pixmap image text
.ico      MS Windows icon resource - 1 icon
.pgm      Netpbm PGM \"rawbits\" image data
.ppm      Netpbm PPM \"rawbits\" image data
.bmp      PC bitmap, Windows 3.x format, 26 x 26 x 24
.xbm      ASCII C program text

The string that you entered for file-type is compared against the
'file' command output for each file, to see if 'your string' is in
that output string. So you may enter JPEG or GIF or PNG, in order
to view files of type JPEG or GIF or PNG, respectively.

Note that you could use another string such as '89a' or '8-bit'
or 'RGB' or 'non-interlaced', but that type of specific image
file-type search is not very common.

NOTE: The first time a query is done on a directory containing
many-many files, a count/print/view operation may respond very
SLOWLY --- when there is an entry in the FileType field and the
file mask is '*'.  This is because applying the 'file' command
to every file in the directory hierarchy can slow down the
search process considerably.

***********************
INSTALLING THIS UTILITY:
***********************

The set of scripts for this utility (a Tk script and 2 shell scripts
that are called by the Tk script) could be put in a sub-directory of
the user's home directory, such as \$HOME/apps/tkBatchImgViewer.

Then the user can use their desktop system (such as
Gnome or KDE) to set up the Tk script as an icon on the
desktop.

Then, whenever the user wants to search a directory hierarchy
for image files, the user can click on the icon to startup
the Tk GUI script.
"


##+######################################################
## ADDITIONAL GUI INITIALIZATION section.
##+######################################################

##+#############################################################
## Initialize 'PREV' variables that will be used to determine
## when the user has changed a 'find' criterion.
##+#############################################################

set PREV_ENTRYfileMask ""
set PREV_RADVARlevels ""
set PREV_RADVARcasesense ""
set PREV_RADVARfilesize ""
set PREV_ENTRYfileSize ""
set PREV_RADVARfileage ""
set PREV_ENTRYfileAge ""
set PREV_ENTRYfileType ""

##+#############################################################
## Get the directory that this Tk script is in. That will be the
## directory that the 'external' utility shell script(s) should
## be in. This directory is used to call the shell script that
## is used for the 'view', 'count', and 'print' options.
##+#############################################################

## FOR TESTING:
#  puts "argv0: $argv0"

# set DIRscripts "."
# set DIRscripts "[pwd]"
# set DIRscripts "$env(HOME)/apps/tkUtils"
  set DIRscripts "[file dirname $argv0]"


##+#############################################################
## Set the directory and filename for a temporary' file that
## will be used in the shell script(s) to hold the list of
## 'found' files.
##+#############################################################

set tempDIR "/tmp"
set outFILE "${tempDIR}/${env(USER)}_tkBatchImgViewer_filenames.lis"

##+#############################################################
## Set the initial directory and filename-mask for the
## filename-mask entry field.
##+#############################################################

set curDIR "$env(HOME)"

## FOR TESTING:
#   set curDIR [pwd]

set ENTRYfileMask "$curDIR/*.jpg"

## Make sure the end of the filename is in view.

.fRfileMask.entryFILEMASK xview end


Shell script #1 (called by the Tk script) :

And here is the code for the shell script called by this Tk script. This is a wrapper script for the 'find' command.

You can put this script in the same directory with the Tk script. The Tk script includes some code (involving the 'argv0' variable) to determine the location of the shell script by extracting the name of the directory in which the Tk script lies.

 Code for shell-script-1 'findImages_forCriteria.sh' :

#!/bin/sh
##
## SCRIPT NAME: findImages_forCriteria.sh
##
##+#######
## PURPOSE:
##  This script finds a set of user-specified files --- according to
##  a fully-qualified file mask (directory and mask) and about seven other
##  'find' parameters passed to this script
##
##  This shell script is meant to be issued from the Tk GUI 'wrapper' script
##  --- 'find_and_imageViewer_FrontEnd.tk'.
##  That Tk script is to get parameters for the 'find' command.
##
##+######
## INPUTS:
##
##  The parameters passed to this script, from the 'imageViewer_FrontEnd.tk'
##  Tk GUI script, are:
## 
##   Var1: 'Base'-directory name and file mask. 
##          Example: /home/fred/IMAGE_CAPTURES/*river*.jpg
##
##   Var2: A 'levels' indicator from a Tk radiobuttons var
##         (possible values: 'one' or 'all').
##
##   Var3: A 'case-sensitivity' indicator from a Tk radiobuttons var
##         (possible values: 'case-sensitive' or 'case-INsensitive')
##
##   Var4: A 'bigger/smaller' indicator from a Tk radiobuttons var
##.        (possible values: 'bigger' or 'smaller')
##
##   Var5: An integer file-size-cutoff value (in KiloBytes)
##         (could be null, indicating no size limitation)
##
##   Var6: An 'older/younger' indicator from a Tk radiobuttons var
##.        (possible values: 'older' or 'younger')
##
##   Var7: An integer file-age-cutoff value (in days)
##         (could be null, indicating no age limitation)
##
##   Var8: A file-type string --- typically JPEG or GIF or PNG.
##
##   Var9: The name of a (temporary) output file to be used to
##         hold the filenames found by the 'find' command.
##
## In this script, we will put those parameters in shell script variables
## VARfilemask, VARlevels, VARsense,
## VARbigsmall,  VARfilesize,
## VARoldyoung,  VARfileage,
## VARfiletype,  VARoutfile  --- respectively.
##
##+#########################################################################
## MAINTENANCE HISTORY:
## Started by: Blaise Montandon 2014apr25 Made this 'findImages_forCriteria.sh'
##                                        shell script by revising shell script
##                                        'findImages_andCountPrintOrView.sh'
##                                        (which was started 2013dec08) to
##                                        do the 'find' command but eliminate
##                                        the count/print/view logic.
## Updated by: Blaise Montandon 2014
##+#########################################################################

## FOR TESTING: (to show statements as they execute)
#  set -x

VARfilemask="$1"
VARlevels="$2" 
VARsense="$3"
VARbigsmall="$4"
VARfilesize="$5"
VARoldyoung="$6"
VARfileage="$7"
VARfiletype="$8"
VARoutfile="$9"

## FOR TESTING of this script without the Tk wrapper:
## (For stand-alone testing, change 'if test 1 = 0' to 'if test 1 = 1'.)

if test 1 = 0
then

   # VARfilemask="$HOME/apps/tkGooies_linux_PREP/tkGUIs/.PREP_tkGooies/00_CFE_eog_FrontEnd_2013dec_PREP/*.jpg"
   VARfilemask="$HOME/IMAGE_CAPTURE/*.gif"
   # VARfilemask="$HOME/IMAGE_CAPTURE/*"

   VARlevels="one"
   # VARlevels="all"

   VARsense="case-sensitive"
   # VARsense="case-INsensitive"

   VARbigsmall="bigger"
   VARbigsmall="smaller"

   VARfilesize=""

   VARoldyoung="older"
   # VARoldyoung="younger"

   VARfileage=""

   # VARfiletype="JPEG"
   VARfiletype="GIF"
   # VARfiletype="PNG"

   VARoutfile="/tmp/${USER}_tkBatchImgViewer_filenames.lis"
fi

## FOR TESTING:
#   echo "VARfilemask: $VARfilemask"


## Simply exit if there is no filemask passed to this script.

if test "$VARfilemask" = ""
then
   exit
fi

DIRNAME=`dirname "$VARfilemask"`
FILEMASK=`basename "$VARfilemask"`


if test "$VARlevels" = "one"
then 
   DEPTHPARM="-maxdepth 1"
else
   DEPTHPARM=""
fi


if test "$VARsense" = "case-sensitive"
then 
   NAMEPARM="-name"
else
   NAMEPARM="-iname"
fi


## The FILESIZE_PARM can be a parameter like
##      -size +${SIZE_MINinBYTES}c
## for the 'find' command.

if test "$VARfilesize" = ""
then
   FILESIZE_PARM=""
else
   SIZEinBYTES=`expr $VARfilesize \* 1000`
   if test "$VARbigsmall" = "bigger"
   then
      # FILESIZE_PARM="-size +${SIZEinBYTES}c"
      FILESIZE_PARM="( -size +${SIZEinBYTES}c -o -size ${SIZEinBYTES}c )"
      ## Note that we do not need to 'escape' the parentheses like we
      ## do in a 'find' command entered at a shell command prompt, because
      ## the parentheses are 'protected' by being within a variable,
      ## rather than being 'exposed' in a command string.
   else
      FILESIZE_PARM="-size -${SIZEinBYTES}c"
   fi
fi


## The FILEAGE_PARM can be a parameter like
##     -mtime +$NDAYS
## for the 'find' command.

if test "$VARfileage" = ""
then
   FILEAGE_PARM=""
else
   if test "$VARoldyoung" = "older"
   then
      FILEAGE_PARM="-mtime +$VARfileage"
   else
      FILEAGE_PARM="-mtime -$VARfileage"
   fi
fi


#############################################################
## Prepare to use the temp filename to hold the filenames.
## Make sure we start with a new (empty) output file.
#############################################################

rm -f "$VARoutfile"


##+#######################################################
## Call on the 'find' command, which puts the
## 'found' filenames, SORTED, in file "$VARoutfile".
##
## We use a '-type d -fprint /dev/stderr' clause in the
## 'find' command to show directories being searched,
## in the 'xterm' that runs this script.
## This gives a kind of 'progress indicator' to let the
## user know how far/fast the 'find' command is progressing.
##
## We also use the 'tee' command to output 'found' filenames 
## to 'stdout', as a means of providing a 'progress
## indicator' in the 'xterm' that runs this script.
## However, if not many filenames are found and then the
## 'xterm' closes quickly, the user may not get much
## of a progress indicator by this.
##
## The directory-name output is probably going to be
## the better progress indicator in most cases.
##+#######################################################
## NOTE: Do not escape the quotes around $FILEMASK.
##       If you do, no filenames are returned.
##+######################################################

## FOR TESTING: (to show the 'find' command that is called)
## (When called from within the Tk wrapper script,
##  this output may interfere with proper processing.)
#  set -x

if test "$VARfiletype" = ""
then
   find "$DIRNAME" \
      \( -type d -fprint /dev/stderr \) , \
      \( $DEPTHPARM  -type f $NAMEPARM "$FILEMASK" \
      $FILESIZE_PARM $FILEAGE_PARM -print \) | sort | \
      tee "$VARoutfile"
else
   find "$DIRNAME" \
      \( -type d -fprint /dev/stderr \) , \
      \( $DEPTHPARM  -type f  $NAMEPARM "$FILEMASK" \
      $FILESIZE_PARM $FILEAGE_PARM -exec file {} \; \) | \
      grep ":.*$VARfiletype" | cut -d: -f1 | sort | \
      tee "$VARoutfile"
fi


Shell script #2 (called by the Tk script) :

And here is the code for the shell script that provides the 'for' loop that feeds each image filename to the chosen viewer program.

You can put this script in the same directory with the Tk script. Shell script #1 includes some code (involving the '$0' variable) to determine the location of the directory containing this shell script (and all 3 scripts) by extracting the name of the directory in which shell-script-1 lies.

 Code for shell-script-2 'forLoop_displayImgsInFile.sh' :

#!/bin/sh
##
## SCRIPT: forLoop_displayImgsInFile.sh
##
## PURPOSE: For a given
##          1) image-viewer command string (program and some arguments)
##          and
##          2) a text-file name (in which the file contains the
##             fully-qualified names of image files).
##          this script uses a 'for' loop to show each of the
##          image files via the image-viewer command string.
##
##          It is assumed that the image-viewer works such that
##          when the user closes the image-viewer window, the
##          next image is shown.
##
## CALLED BY: a 'wrapper' Tk script:
##            find_and_imageViewer_FrontEnd.tk.
##
##+#######################################################################
## Created: 2013dec12 For use in a calling shell script:
##                       getImages_andCountPrintOrView.sh
##                    which in turn, is called by a 'wrapper' Tk script:
##                       find_and_imageViewer_FrontEnd.tk.
## Changed: 2014apr25 Add TOTALfiles and CNT variables, and add
##                    an 'echo' of those numbers to stdout.
##+#######################################################################

## FOR TESTING: (show statements as they execute)
#  set -x

##+##########################################################
## Put the 2 arguments into variables with descriptive names.
##+##########################################################

IMGVIEWER="$1"
TEMPFILE="$2"

##+##########################################################
## Get the number of files in file $2.
##+##########################################################

TOTALfiles=`cat "$TEMPFILE" | wc -l`

##+##########################################################
## Initialize an image count variable.
##+##########################################################

CNT=1

##+######################################################
## Use the image-viewer program (and any parms that are to
## be used with it) to show each of the image files whose
## names are in $TEMPFILE.
##+######################################################

for FILENAME in `cat  "$TEMPFILE"`
do
   echo "Showing $CNT of $TOTALfiles."
   $IMGVIEWER "$FILENAME" 2> /dev/null
   CNT=`expr $CNT + 1`
done


INSTALLING THESE SCRIPTS:

This set of 3 scripts could be put in a sub-directory of the user's home directory, such as $HOME/apps/tkImageViewer.

Then the user can use their desktop system (such as Gnome or KDE) to set up the Tk script as an icon on the desktop. Then the user can click on the icon to startup the 'front end'.


SOME ENHANCEMENTS :

This set of scripts provides a start to my 'to-do' list --- at the bottom of my 'bio' page at uniquename --- in the 'CFE' (Code for Front Ends) group. I plan to work on front ends for 'mplayer', 'ffmpeg', and 'find'. But I may return to this set of scripts to provide some enhancements.

sort

It would be convenient to simply call on the viewer program via the '-exec' option of 'find', which is how the viewer program was implemented in the initial release of this utility. However, one finds that the sequence in which the image files are shown is not what the user will typically want. The files seem to show in a rather random sequence, rather than showing up according to a filename sort. This is probably because the 'find' command searches through files according to their 'inode' numbers rather than according to an alphanumeric sort order of their filenames.

Similarly, the 'ShowFilenames' option shows the files in a seemingly random order, rather than in an alphanumeric order by filename. A sort is not needed with the 'CountFilenames' option, but I find that it is going to be desirable to incur the extra processing of the 'sort' command and insert a 'sort-pipe' after the 'find' command --- for the 'LaunchViewer' and the 'ShowFilenames' options.

For the 'view' option, one way to implement the 'pipe' is to pipe '-print' output from the 'find' command into the 'sort' command and then into the 'xargs' command. But there can be problems in using the 'xargs' command when there are embedded spaces in filenames and when filenames are separated by line-feeds --- as is discussed on page 169-170 of the book 'Unix Power Tools' from publisher O'Reilly and Associates.

The output of 'man xargs' on my machine says that 'find ... -print | xargs ...' "will work incorrectly if there are any filenames containing newlines or spaces". It suggests using 'find ... -print0 | xargs -0 ...', but I am not having success with that. Since different versions of 'xargs' may behave differently, I may find that it is better to process the sorted filenames from 'find' with a 'for' loop, rather than using 'xargs'.

I will update the shell script presented on this page when I have an improvement to offer.

File-type

As I indicated near the top of this page, I may add another 'entry' widget to the GUI --- to support a 'file-type' search capability, based on using the 'file' command.

In that 'entry' widget, the user could enter keywords such as 'JPEG' or 'GIF' or 'PNG' to retrieve files for which the 'file' command returns text strings like the following:

 Typical
 file suffix  'file' output
 -----------  ---------------------------------------

 jpg or jpeg  JPEG image data, JFIF standard 1.01
 gif          GIF image data, version 89a, 256 x 352
 png          PNG image, 1024 x 768, 8-bit/color RGB, non-interlaced

              JPEG = Joint Photographic Experts Group
              GIF = Graphics Interchange Format
              PNG = Portable Network Graphics

 Other, less-used image formats:

 pgm          Netpbm PGM "rawbits" image data
 ppm          Netpbm PPM "rawbits" image data
 tga          Targa image data - RGB - RLE 2000 x 2000
 tif or tiff  TIFF image data, big-endian
 xpm          X pixmap image text

 bmp          ASCII C program text  [not very distinctive, but 'BM' in first 2 chars of this binary file]  
 svg          ASCII English text    [not very distinctive, but '<svg' in top few lines of this text file] 
 xbm          ASCII C program text  [not very distinctive, but '#define' in top line of this text file]

The file-mask could be set to '*' --- to look for files of a specified type (JPEG, GIF, PNG, PGM, PPM, TIFF, Targa, 'X pixmap') , in one or more sub-directory levels.

Adding 'file' command processing to every file processed by the 'find' command will add a lot of processing to the find-search. But this capability is worth implementing when one is dealing with image files for which the wrong suffix was supplied, or image files that were not even provided with a suffix like '.jpg' or '.gif' or '.png'.

maxdepth N

I also indicated near the top of this page that I may change the 'ONE' radiobutton to an 'N-levels' radiobutton. If that radiobutton is selected, an entry field will be activated where the user can enter a choice of N (with the entry field being initialized with '1'). This capability would be implemented via the '-maxdepth' parameter of the 'find' command.

There is also a '-mindepth' parameter of the 'find' command. But I have never encountered a situation where I felt I needed to use that parameter.

---

There are a lot of parameters available with the 'find' command, but I think I have probably implemented the ones that are most useful to use for this 'multiple-subdirectory image-select-and-display' utility. (On second thought, a '-prune' capability might be handy.)

---

Note that it is quite easy for you to switch out any of these viewer programs/commands to replace them with another (simple) image viewer that is available in your operating environment.

Simply change a 'radiobutton-text' assignment statement in the Tk script, and change an 'if-statement' in the 'getImages' shell script, to change the image-viewer-program-and-optional-arguments in an assignment statement for the IMGVIEWER variable.


IN CONCLUSION

As I have said on several other code-donation pages on this wiki ...

There's a lot to like about a utility that is 'free freedom' --- that is, no-cost and open-source so that you can modify/enhance/fix it without having to wait for someone else to do it for you (which may be never).

A BIG THANK YOU to Ousterhout for starting Tcl-Tk, and a BIG THANK YOU to the Tcl-Tk developers and maintainers who have kept the simply MAH-velous 'wish' interpreter going.


RFox - 2013-12-10 19:09:04

"That's nice. BUT ... How is that going to help the world develop the engineers, computer-scientists, and other scientists that are needed in a very challenging future world? (We need people to help deal with that asteroid that is on a collision course with the Earth --- perhaps sooner than most people think.)"

It might not help but at least we'll be looking at some kick-*ss images when the world ends.


uniquename 2013dec11

That watching-iPads-while-the-world-ends observation led me to a mind-image of a twerker-generation teenager --- or an iPad-loving soccer-mom --- saying "You can have my iPad when you pry it from my cold, dead hand." (Sounds like something you would hear from a spokesman for the NIA --- the National iPad Association.)


uniquename UPDATE 2013dec13

I have added the 'File-Type' entry field to the GUI, as I indicated I might do in discussing 'SOME ENHANCEMENTS', above. At the same time, I handled the 'sort' issue discussed above --- by using a 'for' loop technique rather than a 'pipe-to-xargs' technique. The 'xargs' technique was problematic, and is likely to be problematic in various Linux/BSD/Mac/Unix operating system environments.

The following image shows the new 'File-Type' entry field being employed. See the entry at the bottom of the GUI --- and the file-mask being used in the entry field near the top of the GUI.

tkImageViewer_entryInFileTypeField_screenshot_576x272.jpg

Actually, I put a high priority on solving the 'sort' issue --- and decided to go ahead and add the File-Type-filter feature at the same time.

In order to implement the 'for' loop (to handle passing SORTED filenames to the user-selected image viewer program), I employed an additional shell script, which is called after the 'find' command gathers together a sorted list of filenames --- in the case that the 'LaunchViewer' button is used.

I have provided the new 'forLoop' shell script above --- and replaced the Tk script and the 'getImages' shell script, that were there before, with new versions. This new set of 3 scripts now handle the 'sort' and 'File-type' enhancements that were discussed above.

I renamed the 'getImages' shell script to indicate that it handles the 'count' and 'print' options as well as the 'view' option --- and to indicate that it is responsible for getting the names of the image-files that are to be counted/printed/viewed.

The Help-text of the GUI has been updated to discuss the File-Type feature.

I leave the 'N-levels' and '-prune' enhancements to a future date. These two features are similar in that they allow the user avoid 'dropping into' a (large) sub-directory of image files which the user does not wish to process.

To implement the '-prune' feature would require adding yet another entry widget to the GUI --- to allow for entering one or more sub-directory names (or masks).

   I was wondering if one could actually use a mask in specifying
   directories to prune. Most examples do not show using a mask-name
   for a prune-directory --- only complete directory-names. But I did a
   web search and found an example that indicates masks should be allowed:

   find . -type d -name '.git*' -prune -o -type f -print

In coming months, if I find a need for either the 'N-levels' or 'prune' features, I may implement them and update the code here.

After the current 'sort' and 'file-type' enhancements, I think this utility has reached a point of being far more than half-baked.

By the way, I have installed these 3 scripts in a $HOME/apps/tkImageViewer directory, as suggested above in an 'install' section. And I have defined an icon on my desktop by which I can start up this GUI and keep testing it in coming months --- until I hit the need for a '-prune' option. :-)


uniquename UPDATE 2014jan08

In doing some testing for a 'front end' Tk GUI for the 'find' command, I found that the 'find' command does some unexpected 'round off' stuff when processing a '-size' parameter. For example, if one has a size parameter like '-size +1M', this asks for files that are greater than 1 Megabyte in size. However, as the 'find' command checks each file, it apparently rounds off its size to the nearest Megabyte BEFORE the comparison. Hence any file less than 1.5 Megabytes in size is not included in the 'found' list.

Furthermore, unlike the age test (example: '-mtime +$Ndays') which does a greater-than-or-equal-to test triggered by the plus sign, the 'plus' size test does a greater-than test --- no equal-to test.

So I have made several changes to the Tk script and the shell script above --- to improve the size-checking:

   - Changed the 'granularity' of the size prompt of the Tk GUI ---
     from Megabytes to Kilobytes.

   - Changed the '-size +${Nmeg}M' *MEGABYTES* size check in the shell
     script to a '-size +${Nbytes}c' *CHARACTERS* size check --- by
     converting the kilobytes (entered by a user) to bytes. 

   - Covered the unlikely case of a file being exactly N kilobytes in size
     when the user enters N in the Kilobytes entry field --- by adding
     an 'equal to' check to the 'greater than' (plus) check of the size
     parameter. More precisely, I changed the statement
         -size +${SIZEinBYTES}c
     to
        ( -size +${SIZEinBYTES}c -o -size ${SIZEinBYTES}c ).

Now there should be no 'holes' in the search for files of a 'bigger or smaller' size.

I have replaced the code for the Tk script and the shell script above with the new code with the few lines of changes.


uniquename UPDATE 2014apr26

In using this 'tkBatchImageViewer' on 'deep' directories --- that is, a 'find' search on about 200-plus subdirectories with 2,000-plus files in those subdirectories --- I found a few improvements that I needed to make in this Tk script and 2 associated shell scripts.

I found the following 'needs'.

1) When I used the 'CountFilenames' and 'ShowFilenames' and 'LaunchViewerJob' buttons with the same 'find' criteria, the same long 'find' search would have to be repeated --- unnecessarily. I needed to save the 'found-filenames' in an output file, and work off of that list of files when the 'find' criteria had not been changed by the user.

2) On a long 'find' search, a 'progress indicator' was needed to let the user know if the 'find' command was doing its job --- and to let the user know how far/fast the search was proceeding. Similarly, a 'progress indicator' was needed to let the user know which 'found-image' was being shown when hundreds of image files were being displayed.

To handle these needs, I made the following changes to the 3 scripts.

*** In the Tk script, set the filename of a temporary file to be used to hold the names of image files found by the 'find' search --- in variable 'outFILE'.

*** In the Tk script, added 'PREV' variables to be used to hold about 8 previous 'find' search criteria --- to be used to indicate when the user has changed a 'find' criterion.

*** In the Tk script, added a proc called 'check_for_criterion_change' --- to determine if a criterion variable has been changed by the user.

*** In the Tk script, replaced the 'getImages_andCountPrintOrView.sh' shell script --- that had 'count', 'print', and 'view' sections --- by a 'findImages_forCriteria.sh' shell script that performs just the 'find' search and puts the found-files in a temporary '$outFILE' file --- only if one of the 'find' search criteria was changed by the user.

*** Made the 'findImages_forCriteria.sh' shell script from the 'getImages_andCountPrintOrView.sh' shell script. Changed the arguments passed to the shell script to be just the 'find' search criteria variables --- not the image-viewer variables.

*** In the Tk script, provided an 'xterm' window to the 'exec' statement for the 'findImages_forCriteria.sh' shell script, to allow for better visibility of how a lengthy 'find' is progressing. The 'find' command in the 'findImages_forCriteria.sh' shell script was changed to show directories being searched, as well as files being found, in order to provide a better 'progress indicator'.

*** In the 'forLoop_displayImgsInFile.sh' script, added 'CNT' and 'TOTALfiles' variables and an 'echo' statement --- so that the 'xterm' window that is used to 'exec' this script in the Tk script will display to the user a count of how many of the 'found-image-files' have been displayed so far.

I have made these changes and replaced the Tk script and the 2 shell scripts above. (Now I am feeling like this is a quite robust utility.)