#!/usr/bin/wish -f ## ## Tk SCRIPT NAME: find_and_mediaPlayer_FrontEnd.tk ## ##+####################################################################### ## PURPOSE: This Tk script provides a GUI for ## 1)) finding a 'batch' of media files (video and/or audio) ## according to user-specified criteria that are prompted ## for via entry widgets and radiobutton widgets on the GUI, ## AND ## 2) starting up a movie/audio player program --- such as ## 'mplayer' or 'totem' or 'VLC' or 'gmplayer' ## or 'smplayer' or 'ffplay' --- to play the 'batch' ## of media files that were found, via the 'find' command. ## ## Hence, the GUI is a 'front-end' for the 'find' command and ## a media playing 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 mplayer' or ## 'man totem' or 'man vlc' or 'man gmplayer' or 'man smplayer' ## or 'man ffplay' commands --- and other 'find' and media-player ## documentation, for example, via web searches. ## ## The intent of this utility is to allow the user to easily ## specify movie/audio files to be played --- 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 - whether to search based on file-type, according to ## output from the 'file' command. ## ## In addition, the GUI allows the user to specify: ## - which of several media-player programs to use ## - whether to run the media-player program at fullscreen-size. ## ## NOTE that most movie/audio-players, like 'mplayer' and more ## complex 'media' players, are oriented toward playing a single ## movie/audio file --- or playing files selected from ## movie/audio names (and associated filenames) in a ## 'playlist'. In contrast ... ## ## This utility is oriented toward AUTO-SELECTING 'media' files ## (based on 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. ## ## This utility SORTS the selected files ACCORDING TO their ## filenames and then starts playing the files. ## ##+###################### ## NOTES ON MOVIE PLAYERS: ## ## Most movie players are 'media' players that play ## - audio-only files, and ## - video-only files, and ## - video+audio ('talkie' movie) files. ## In other words, most movie players are also audio players. ## ## One consequence of this is that this GUI front-end could be ## used to select audio files for playing, instead of movie files. ## ## Some movie players are GUI front-ends for a command-line ## movie player program that does not provide a GUI. Example: ## 'gnome-mplayer' and 'smplayer' and 'gmplayer' are GUI ## front-ends for the 'mplayer' program. ## ## And some movie/media players are 'bare bones' players without ## a lot of startup or play options --- such as 'ffplay'. ## ## Almost any kind of movie player program, like the ones mentioned ## above, could be used as the player program for this utility. ## ## Note that this utility is designed so that the user is required ## to close the media-player window when finished playing a movie ## or audio file. When the player window closes, the media-player is ## started up on the next media-file in the sequence. Any ## media-player that is used in this utility would need to ## support that type of operating mode. ## ## At least 3 movie-and-audio-players are selectable via the GUI. ## Other 'media' players could be switched for players currently ## made selectable on the GUI. For example, 'smplayer' could ## be used in place of 'gnome-mplayer'. To perform the switch ... ## ## The 'core' media-player changes would be to the shell script --- ## 'getMediaFiles_andCountListOrPlay.sh' --- ## that this Tk script calls. That shell script currently offers ## several media-players to use, along with the 'find' command ## --- and along with parameters supplied from this GUI. ## ## Only a 'superficial' change would be required to the Tk GUI ## script --- changing the player-name on the GUI --- in a text ## string for a 'radiobutton' widget. ## ##+################ ## THE GUI WIDGETS: ## ## The GUI offers a generous set of user specifications. ## The options available to the user are compactly indicated ## by the following 'text-sketch' of the GUI: ## ## --------------------------------------------------------------------------- ## 'find'-mediaplayer Front End - a Tk Multi-Movie/Audio-File-Player Utility [window title] ## --------------------------------------------------------------------------- ## ## {Exit} {Help} {LaunchPlayerJob} {CountFilenames} {ShowFilenames} ## ## Full Filename Mask (for movie/audio): ________________________ {Browse...} ## ## MediaPlayer : O 'mplayer' O 'ffplay' O 'gnome-mplayer' O 'totem' O 'VLC' ## ## DisplaySize: O DEFAULT-size (up to fullscreen) O FULLSCREEN (without toolbars) ## ## Search Levels for Mask: O ONE O ALL subdirectories of selected directory ## ## Case Sense for Mask Search: O case-sensitive O case-INsensitive ## ## File Size (KiloBytes): _________ O bigger-than O smaller-than ## ## File Age (Days) : ________________ O older-than O younger-than ## ## File Type: ___________ (Warning: SLOW) Examples: 'MPEG v4' or 'MPEG sequence' ## or 'Flash' or 'Apple QuickTime' or 'Microsoft ASF' or 'layer III' or 'PCM' ## --------------------------------------------------------------------------------------------------------------- ## ## 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 at the 'MediaPlayer:' and 'DisplaySize:' prompts ## are there parameters involving the media-player. ## ## The other parameters (the majority of the 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 ## - 9 label widgets ## - 4 entry widgets ## - 15 radiobutton widgets in 6 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/tkBatchMediaPlayer. ## ## 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 Tk 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 several radiobuttons, with a label ## 'fRdisplaySize' 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 ## 'fRfiletype2' for a label (continuation) ## ## 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 ## ## 'findFiles_andCountListOrPlay' - called by the 'LaunchPlayerJob' 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 2013dec15 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 2014jan07 Chgd filesize MB to KB. ## 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 ## 'findFiles_andCountPrintOrView.sh' ## to 'findMediaFiles_forCriteria.sh' and ## changed the arguments passed to the ## shell script. ## 5) Changed the 'count', 'list', and ## 'play' sections of proc ## 'findFiles_andCountListOrPlay' ## 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 'findMediaFiles_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-mediaPlayer FrontEnd, to batch-select & play movie/audio files" wm iconname . "BatchMediaPlay" # 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) "LaunchPlayerJob" # set aRtext(buttonKILLJOB) "KillPlayerJob" set aRtext(buttonCOUNT) "CountFilenames" set aRtext(buttonPRINT) "ShowFilenames" ## For '.fRfileMask' frame: set aRtext(labelFILEMASK) "Full Filename Mask (for movie/audio):" set aRtext(buttonBROWSE) "Browse..." ## For '.fRdisplayPgm' frame: set aRtext(labelDISPLAYPGM) "MediaPlayer:" set aRtext(radbuttDPGM1) "1 mplayer" set aRtext(radbuttDPGM2) "2 ffplay" set aRtext(radbuttDPGM3) "3 totem" set aRtext(radbuttDPGM4) "4 gmplayer" set aRtext(radbuttDPGM5) "5 VLC" ## For '.fRdisplaySize' frame: set aRtext(labelDISPLAYSIZE) "DisplaySize:" set aRtext(radbuttDSIZEFULL) "FULLSCREEN (no toolbars)" set aRtext(radbuttDSIZEDEFAULT) "DEFAULT-size, up to fullscreen" ## 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) "(Warning: SLOW) Examples: 'MPEG v4' or 'MPEG sequence'" ## For '.fRfileType2' frame: set aRtext(labelFILETYPE3) \ "or 'MPEG' or 'Flash Video' or 'Apple QuickTime' or 'Microsoft ASF' or 'layer III' or 'PCM'" ## 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 '.fRdisplaySize' 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 ## 1 char high for the '.fRfileType2' frame ## -------- ## 10 chars high for the 10 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 --- 10 chars high for the 10 frames. set charHeightPx [font metrics fontTEMP_varwidth -linespace] set minWinHeightPx [expr {10 * $charHeightPx}] ## Add about 20 pixels for top-and-bottom window decoration -- ## and some pixels for top-and-bottom of frame/widget borders ## (~10 widgets x 4 pixels/widget = 32 pixels). set minWinHeightPx [expr {60 + $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 several radiobuttons, with a label ## 'fRdisplaySize' 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 ## 'fRfileType2' for a label widget (continuation) ##+#################################################################### ##+#################################################################### ## 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 .fRdisplaySize -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 frame .fRfileType2 -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 .fRdisplaySize \ -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 pack .fRfileType2 \ -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 player process. ## NOT NEEDED. See 'Kill' button attempt below. # set PlayerPID "" button .fRbuttons.buttLAUNCH \ -text "$aRtext(buttonLAUNCH)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {findFiles_andCountListOrPlay play} ##+######################################################## ## THE FOLLOWING ATTEMPT DID NOT WORK OUT. ## The intent was to use a 'Kill' button on the GUI to allow ## for killing the 'getMediaFiles_andCountListOrPlay.sh' script ## --- if it finds lots of files to play 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 ## 'getMediaFiles_andCountListOrPlay.sh' script, to run the ## command that starts the media playing sequence. ## Closing the 'xterm' window 'kills' the playing sequence. ##+########################################################## 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' ## http://wiki.tcl.tk/735 - 'getPid' ##+########################################################### button .fRbuttons.buttKILLJOB \ -text "$aRtext(buttonKILLJOB)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command { global PlayerPID puts "Trying to kill PlayerPID: $PlayerPID" if {"$PlayerPID" != ""} { # exec kill -TERM $PlayerPID exec kill -15 $PlayerPID # exec kill -KILL $PlayerPID exec kill -9 $PlayerPID # set PlayerPID "" } # 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 {findFiles_andCountListOrPlay count} button .fRbuttons.buttPRINT \ -text "$aRtext(buttonPRINT)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {findFiles_andCountListOrPlay 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 ## several 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 program : 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 radiobutton .fRdisplayPgm.radbuttDPGM4 \ -text "$aRtext(radbuttDPGM4)" \ -font fontTEMP_varwidth \ -anchor w \ -variable RADVARdisplaypgm \ -value "4" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd $BDwidthPx_radbutt radiobutton .fRdisplayPgm.radbuttDPGM5 \ -text "$aRtext(radbuttDPGM5)" \ -font fontTEMP_varwidth \ -anchor w \ -variable RADVARdisplaypgm \ -value "5" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd $BDwidthPx_radbutt ## RADVARdisplaypgm is the var for these 2 or 3 radiobuttons. ## Set an initial value. set RADVARdisplaypgm "1" # set RADVARdisplaypgm "2" # set RADVARdisplaypgm "3" # set RADVARdisplaypgm "4" # set RADVARdisplaypgm "5" ## PACK the widgets in the 'fRdisplayPgm' frame. pack .fRdisplayPgm.labelDISPLAYPGM \ .fRdisplayPgm.radbuttDPGM1 \ .fRdisplayPgm.radbuttDPGM2 \ .fRdisplayPgm.radbuttDPGM3 \ .fRdisplayPgm.radbuttDPGM4 \ .fRdisplayPgm.radbuttDPGM5 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRdisplaySize' frame -- DEFINE ## 2 RADIOBUTTONS, preceded by a LABEL widget. ##+######################################################## label .fRdisplaySize.labelDISPLAYSIZE \ -text "$aRtext(labelDISPLAYSIZE)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## DEFINE Radiobuttons for display sizes : radiobutton .fRdisplaySize.radbuttDSIZEDEFAULT \ -text "$aRtext(radbuttDSIZEDEFAULT)" \ -font fontTEMP_varwidth \ -anchor w \ -variable RADVARdisplaysize \ -value "default" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd $BDwidthPx_radbutt radiobutton .fRdisplaySize.radbuttDSIZEFULL \ -text "$aRtext(radbuttDSIZEFULL)" \ -font fontTEMP_varwidth \ -anchor w \ -variable RADVARdisplaysize \ -value "fullscreen" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd $BDwidthPx_radbutt ## RADVARdisplaysize is the var for these 2 radiobuttons. ## Set an initial value. set RADVARdisplaysize "default" # set RADVARdisplaysize "fullscreen" ## PACK the widgets in the 'fRdisplaySize' frame. pack .fRdisplaySize.labelDISPLAYSIZE \ .fRdisplaySize.radbuttDSIZEDEFAULT \ .fRdisplaySize.radbuttDSIZEFULL \ -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. ## PACK them. ##+######################################################## 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 ##+######################################################## ## IN THE 'fRfileType2' frame -- DEFINE ## one LABEL widget. PACK it. ##+######################################################## label .fRfileType2.labelFILETYPE3 \ -text "$aRtext(labelFILETYPE3)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## PACK the widgets in the 'fRfileType2' frame: pack .fRfileType2.labelFILETYPE3 \ -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??? {??proc??} # bind .fR?????.???widget??? {??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. ## ('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 \ {.fRfileMask.entryFILEMASK xview insert} ## FOR TESTING: # bind .fRfileMask.entryFILEMASK { # set entFILEMASKxview [.fRfileMask.entryFILEMASK xview] # puts ".fRfileMask.entryFILEMASK 'offset' and 'span': $entFILEMASKxview" # } ## An alternative? # bind .fRfileMask.entryFILEMASK \ # {.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 ## 'findFiles_andCountPrintOrView' ## ## 'findFiles_andCountListOrPlay' - called by the 'LaunchPlayerJob' 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 character "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 findFiles_andCountListOrPlay ## ## 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 'play'. ## ## 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 PLAYING ## the filenames found via a 'find' command and the ## user-specified find-criteria. The PLAYING is ## provided via the user-specified PLAYER 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 'findMediaFiles_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 'findMediaFiles_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 'PLAY' OPTION: ## ## The 'play' option uses a 'forLoop_playListOfMediaFiles.sh' ## shell script, run in another 'xterm' window, to play ## the media files from '$outFILE' in a sequence. ## ## The 'xterm' provides the user a way to kill the 'play' ## process/sequence if the user wants to stop the playing. ## ### THIS PROC IS CALLED BY: ## - a 'Count' button with option='count', OR ## - a 'List' button with option='print', OR ## - a 'Launch' button with option='play' ##+############################################################# proc findFiles_andCountListOrPlay {option} { global DIRscripts ENTRYfileMask RADVARdisplaypgm RADVARdisplaysize \ RADVARlevels RADVARcasesense \ RADVARfilesize ENTRYfileSize \ RADVARfileage ENTRYfileAge \ ENTRYfileType outFILE FindPID PlayerPID \ 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, RADVARdisplaysize, ## 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 'findMediaFiles_forCriteria.sh' to put found ## media 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/findMediaFiles_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 'findMediaFiles_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_tkBatchMediaPlayer_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. ############################################################ 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 = 'play', ## run the 'forLoop_playListOfMediaFiles.sh' shell script to run ## the specified media player program on the selected files. ############################################################### ## Attempts were made to use the 'PlayerPID' process ID ## which is set below, to allow the user to cancel the ## playing 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\" &} PlayerPID ## ## set RETcode [ catch {eval exec ${feDIR}/tkGUIs/shofil.tk \ ## "$FULFILname" &} PlayerPID ] ## ## 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" == "play"} { ## 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 media 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 player command in variable 'PLAYERcmd', along with ## some parameters such as whether to run at fullscreen-size. ############################################################# if {"$RADVARdisplaypgm" == "1"} { if {"$RADVARdisplaysize" == "fullscreen"} { set PLAYERcmd "/usr/bin/mplayer -fs" } else { set PLAYERcmd "/usr/bin/mplayer -geometry +15+30" } } elseif {"$RADVARdisplaypgm" == "2"} { ## With 'ffplay', user can interactively toggle fullscreen ## with the 'f' key. set PLAYERcmd "/usr/bin/ffplay" } elseif {"$RADVARdisplaypgm" == "3"} { if {"$RADVARdisplaysize" == "fullscreen"} { set PLAYERcmd "/usr/bin/totem --fullscreen" } else { set PLAYERcmd "/usr/bin/totem" } } elseif {"$RADVARdisplaypgm" == "4"} { # if {"$RADVARdisplaysize" == "fullscreen"} { # set PLAYERcmd "/usr/bin/gnome-mplayer --fullscreen" # } else { # set PLAYERcmd "/usr/bin/gnome-mplayer" # } ## 'gnome-mplayer' is buggy. Use 'gmplayer' instead. if {"$RADVARdisplaysize" == "fullscreen"} { set PLAYERcmd "/usr/bin/gmplayer -fs" } else { set PLAYERcmd "/usr/bin/gmplayer" } } elseif {"$RADVARdisplaypgm" == "5"} { if {"$RADVARdisplaysize" == "fullscreen"} { set PLAYERcmd "/usr/bin/vlc --fullscreen" } else { set PLAYERcmd "/usr/bin/vlc" } } ## END OF if {"$RADVARdisplaypgm" == "1"} ################################################################## ## Run the 'forLoop_playListOfMediaFiles.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 SEQUENCE of PLAYING media files, close this window." \ -geometry 105x5-30-30 -e \ $DIRscripts/forLoop_playListOfMediaFiles.sh \ "$PLAYERcmd" "$outFILE" &} PlayerPID] ## FOR TESTING: # puts "PlayerPID: $PlayerPID" if { $RETcode != 0 } then { set ERRmsg \ "ERROR from attempt to run the 'forLoop_playListOfMediaFiles.sh' script. RETcode: $RETcode" popup_msgVarWithScroll .topErr "$ERRmsg" return } ## END OF if { $RETcode != 0 } } ## END OF if {"$option" == "play"} } ## END OF proc 'findFiles_andCountListOrPlay' ##+######################################################################## ## 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-MediaPlay' Utility ** ** essentially a 'wrapper' for the 'find' command and a 'media' player ** This utility provides a GUI for 1) finding a 'batch' of 'media' files (video or audio) according to user-specified criteria that are prompted for via entry widgets and radiobutton widgets on the GUI, AND 2) starting up a movie/audio player program --- such as 'mplayer' or 'totem' or 'vlc' or 'gmplayer' or 'ffplay' or 'smplayer' --- to view the 'batch' of media files (movie files and/or audio files) that were found, via the 'find' command. Hence, the GUI is a 'front-end' for the 'find' command and a movie/audio 'player' 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 mplayer' or 'man totem' or 'man vlc' or 'man gmplayer' or 'man ffplay' or 'man smplayer' commands --- nor other 'find'/'mplayer'/'totem'/'vlc'/'gmplayer'/'ffplay'/'smplayer' documentation, for example, via web searches. A different media player program could be added by some simple changes in the Tk script 'find_and_mediaPlayer_FrontEnd.tk'. The intent of this utility is to allow the user to easily specify movie or audio files to be played --- 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 (such as 'MPEG v4' or 'QuickTime'). These are parameters for the 'find' operation. In addition, the GUI prompts for - which media-player program to use and - whether to play the movie (or audio 'fireworks' display) at fullscreen-size. NOTE that most movie/audio-players, like 'mplayer' and more complex 'media' players, are oriented toward playing a single movie/audio file --- or playing files selected from movie/audio names (and associated filenames) in a 'playlist'. In contrast ... This utility is oriented toward AUTO-SELECTING 'media' files (based on 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. This utility SORTS the selected files ACCORDING TO their filenames and then starts playing the files. NOTE that a single movie/audio file can be played by selecting a single filename and NOT changing the name to a mask --- like *.mp4 OR A*.WMV OR *beatles*.mp3. ****************** NOTES ON 'PLAYERS': ****************** Most movie players are 'media' players that play - audio-only files, and - video-only files, and - video+audio ('talkie' movie) files. In other words, most movie players are also audio players. One consequence of this is that this GUI front-end could be used to select audio files for playing, instead of movie files. Some movie players are GUI front-ends for a command-line movie player program that does not provide a GUI. Example: 'gnome-mplayer' and 'smplayer' and 'gmplayer' are GUI front-ends for the 'mplayer' program (or the utility routines used by the 'mplayer' program). And some movie/media players are 'bare bones' players without a lot of startup or play options --- such as 'ffplay'. Almost any kind of movie player program, like the ones mentioned above, could be used as the player program for this utility. Note that this utility is designed so that the user is required to close the media-player window when finished playing a movie or audio file. When the player window closes, the media-player is started up on the next media-file in the sequence. Any media-player that is used in this utility would need to support that type of operating mode. *************** THE GUI WIDGETS: *************** The GUI offers a generous set of hints, help, and options for the user. In fact, the GUI consists of about - 9 label widgets - 5 button widgets - 4 entry widgets - 15 radiobutton widgets in 6 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 24 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: *.mpg OR Reunion*.mp4 OR *school*.mov OR *erosmith*.mp3 Before clicking on the 'LaunchPlayerJob' 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. The FileType field is useful if you are dealing with movie files that may have been named with the wrong suffix --- or movie files that have no suffix at all. However, be aware that using this option will generally be much slower that using a file-mask, because the 'file' command is run for each file in the chosen directory structure, in order to determine its file type. ****************************** 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 'MPEG v4' or 'QuickTime' or 'layer III'. 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 MOVIE files: Typical file suffix 'find' output ------------------- ----------------------------------------- mp4 ISO Media, MPEG v4 system, version 1 mpg or mpeg MPEG sequence, v1, system multiplex flv Macromedia Flash Video mov ISO Media, Apple QuickTime movie wmv Microsoft ASF and 'file' returns text strings like the following on AUDIO files: Typical suffix 'find' output ------- ----------------------------------------- mp3 MPEG ADTS, layer III, v1, 128 kbps, 44.1 kHz, Stereo wav RIFF (little-endian) data, WAVE audio, Microsoft PCM, 8 bit, mono 22050 Hz A movie file actually consists of 3 formats: - the video stream format - the audio stream format - the 'container' format. The 'file' command is typically reporting on the 'container' format of movie files. 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 'MPEG v4' to retrieve movie files that are packaged in that container format. Or enter 'MPEG' to retrieve movie files of 'MPEG v4' and 'MPEG sequence' format. And you may enter 'layer III' in order to retrieve audio files that are typically called 'mp3' files. NOTE: The first time a query is done on a directory containing many-many files, a count/list/play 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/tkBatchMediaPlayer. 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 media 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 2 'external' utility shell scripts should be ## in. This directory is used to call the 2 shell scripts --- ## to 'find' media files and to 'play' them. ##+######################################################################## ## FOR TESTING: # puts "argv0: $argv0" # set DIRscripts "." # set DIRscripts "[pwd]" # set DIRscripts "$env(HOME)/apps/tkBatchMediaPlayer" 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)}_tkBatchMediaPlayer_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/*.mp4" # set ENTRYfileMask "$curDIR/*.mpg" # set ENTRYfileMask "$curDIR/*.mp3" ## Make sure the end of the filename is in view. .fRfileMask.entryFILEMASK xview end