TMGIOUTL ;TMG/kst/IO Utilities -- File browser ;05/16/09
         ;;1.0;TMG-LIB;**1**;05/16/09

 ;"TMG IO UTILITIES
 ;"Kevin Toppenberg MD
 ;"GNU General Public License (GPL) applies
 ;"5/16/09

 ;"=======================================================================
 ;" API -- Public Functions.
 ;"=======================================================================
 ;"FBrowse(Option,OutPath,OutName) query the user to select a filename

 ;"=======================================================================
 ;"Private API calls
 ;"=======================================================================
 ;"LoadDir(pArray,curDir,TMGMask,Option) -- load curDir entries into pArray
 ;"HndOnSel(pArray,Option,Info) -- handle ON SELECT event from Scroller
 ;"HndlOnCmd(pArray,Option,Info) -- handle ON SELECT event from Scroller
 ;"ShowHelp -- show help for file browser

 ;"=======================================================================

test
        new option
        set option("MSG")="Hello there!"
        set option("PATH")="/home/kdt0p"
        set option("SELECT DIR")=0
        write $$FBrowse(.option)
        quit

FBrowse(Option,OutPath,OutName)
        ;"SCOPE: PUBLIC
        ;"Purpose: To query the user, to get a filename back
        ;"          Supplies optional directory listing.
        ;"Input: Option [OPTIONAL].  Format as follows.  All entries are optional
        ;"           Option("MSG") A message to show user prior to name prompt.
        ;"                         May contain "\n" character for line wrapping.
        ;"           Option("PATH") Initial default path
        ;"           Option("NAME") Initial default filename
        ;"           Option("NodeDiv") The character that separates folders (e.g. "/")
        ;"                             If not supplied, then default value is "/"
        ;"           Option("MATCH","*.m")="" -- e.g. use filter '*.m'
        ;"           Option("MATCH","*.txt")="" -- e.g. use filter '*.txt"
        ;"               NOTE: Filters are combined by AND, i.e.  files matching one of the specified matches
        ;"           Option("PROMPT") A prompt for user to enter filename/directory name
        ;"           Option("SHOW HIDDEN")=1  Show files hidden (e.g. '.name')
        ;"           Option("SELECT DIR")=1  if 1 then mode is to select directories, not files
        ;"        OutPath: [OPTIONAL] Pass by reference, filled with selected path
        ;"        OutName: [OPTIONAL] Pass by reference, filled with selected name
        ;"Result: returns user specified filename (with path), or "" if aborted

        write # ;"clear screen
        new ScrlFiles,done
        new selDir set selDir=+$get(Option("SELECT DIR"))
        new width set width=60
        new line set $piece(line,"-",width-2)="-"
        set Option("HEADER",1)="+"_line_"+"
        new banner set banner="--== Please Select "_$select(selDir:"Directory",1:"File")_" ==--"
        set Option("HEADER",2)="|"_$$CJ^XLFSTR(banner,width-2)_"|"
        set Option("FOOTER",1)="Enter ? for help"
        if $get(Option("PROMPT"))'="" set Option("FOOTER",2)=Option("PROMPT")
        set Option("SCRN WIDTH")=width
        set Option("ON SELECT")="HndOnSel^TMGIOUT2" ;"code to call based on user input
        set Option("ON CMD")="HndlOnCmd^TMGIOUT2"    ;"code to execute for number entry

        new msg set msg=$get(Option("MSG"))
        if msg'="" do
        . do PopupBox^TMGUSRIF("Message:",msg)
        . do PressToCont^TMGUSRIF

        new StackCaller set StackCaller=$$Caller^TMGMISC
        new nodeDiv set nodeDiv=$get(Option("nodeDiv"),"/")
        set Option("nodeDiv")=nodeDiv ;" in case it wasn't there initially
        new curDir set curDir=$get(Option("PATH"))
        if (curDir="")&($data(^TMG("TMP","SETTINGS","FBrowse",StackCaller))) do
        . set curDir=$get(^TMG("TMP","SETTINGS","FBrowse",StackCaller))
        if curDir="" set curDir=nodeDiv
        set curDir=$$EnsureTrailDiv^TMGIOUTL(curDir,nodeDiv)
        if $$IsDir^TMGKERNL(curDir)=0 set curDir=nodeDiv

        new TMGSelect set TMGSelect=""
L1      do LoadDir("ScrlFiles",curDir,.Option)
        set Option("HEADER",3)="|"_$$CJ^XLFSTR("Current Dir: "_curDir,width-2)_"|"
        set TMGSelect=""
        do Scroller^TMGUSRIF("ScrlFiles",.Option) ;"Event handler should set TMGSelect
        if TMGSelect="" goto LQ
        if selDir set done=0 do  goto:done LQ
        . new Menu,UsrSlct
        . set Menu(0)="What do you want to do with this directory?"
        . set Menu(1)="Choose "_TMGSelect_" as selected directory"_$char(9)_"done"
        . set Menu(2)="Browse INTO it"_$char(9)_"into"
        . write !
        . set UsrSlct=$$Menu^TMGUSRIF(.Menu,2)
        . write #
        . if UsrSlct="done" set done=1
        if $$IsDir^TMGKERNL(TMGSelect) set curDir=TMGSelect goto L1 ;"browse into directory
        do SplitFNamePath^TMGIOUTL(TMGSelect,.OutPath,.OutName,nodeDiv)

        set ^TMG("TMP","SETTINGS","FBrowse",StackCaller)=OutPath ;"store for future use.
LQ      write # ;"clear screen
        quit TMGSelect

LoadDir(pArray,curDir,Option)
        ;"Purpose: load curDir entries into pArray
        ;"Input: pArray -- PASS BY NAME.  An OUT PARAMETER.  Filled in as follows
        ;"         @pArray@(1,DisplayText)=Return Text <-- note: must be numbered 1,2,3 etc.
        ;"         @pArray@(2,DisplayText)=Return Text
        ;"         @pArray@(3,DisplayText)=Return Text
        ;"       curDir -- the directory to get files from
        ;"       TMGMask -- PASS BY REFERENCE.  The mask array (See FBrowse)
        ;"       Option [OPTIONAL].  Format as follows.  All entries are optional
        ;"           Option("MATCH","*.m")="" -- e.g. use filter '*.m'
        ;"           Option("MATCH","*.txt")="" -- e.g. use filter '*.txt"
        ;"               NOTE: Filters are combined by AND, i.e.  files matching one of the specified matches
        ;"           Option("NodeDiv") The character that separates folders (e.g. "/")
        ;"                             If not supplied, then default value is "/"
        ;"           Option("SHOW HIDDEN")=1  Show files hidden (e.g. '.name')
        ;"           Option("SELECT DIR")=1  if 1 then mode is to select directories, not files
        ;"       nodeDiv -- The character that separates folders (e.g. "/")
        ;"       ShowHidden -- OPTIONAL. Default=0  If 1, then show hidden files
        ;"Results: none
        ;
        new TMGFiles,tempFiles
        new count set count=1
        kill @pArray
        new nodeDiv set nodeDiv=$get(Option("nodeDiv"),"/")
        set nodeDiv=$get(nodDiv,"/")
        set ShowHidden=+$get(Option("SHOW HIDDEN"))
        new selDir set selDir=+$get(Option("SELECT DIR"))
        set curDir=$get(curDir,nodeDiv)
        set curDir=$$EnsureTrailDiv^TMGIOUTL(curDir,nodeDiv)
        if $$IsDir^TMGKERNL(curDir)=0 goto LDQuit
        ;"Note: Filter/Mask would apply to directory names too, so must
        ;"      ask for list of files with mask applied **AND** also with
        ;"      a mask of '*' to be sure to get directory names
        new tempMask set tempMask("*")=""
        if $$LIST^%ZISH(curDir,"tempMask","TMGFiles")=0 goto LDQuit
        new index set index=""
        for  set index=$order(TMGFiles(index)) quit:(index="")  do
        . if ($extract(index,1)=".")&(ShowHidden=0) quit
        . new FName,FPName
        . set FName=index
        . set FPName=curDir_FName
        . if $$IsDir^TMGKERNL(FPName) set tempFiles("DIRS","<"_FName_">")=FPName
        . else  set tempFiles("FILES",FName)=FPName
        ;
        ;"Now get files again with user-supplied filter
        merge TMGMask=Option("MATCH")
        if $data(TMGMask)=0 goto LD2  ;"use FILES node already created
        kill tempFiles("FILES")  ;"needs to be reloaded with mask applied.
        if $$LIST^%ZISH(curDir,"TMGMask","TMGFiles")=0 goto LDQuit
        new index set index=""
        for  set index=$order(TMGFiles(index)) quit:(index="")  do
        . if ($extract(index,1)=".")&(ShowHidden=0) quit
        . new FName,FPName
        . set FName=index
        . set FPName=curDir_FName
        . if $get(tempFiles("DIRS","<"_FName_">"))'="" quit
        . set tempFiles("FILES",FName)=FPName
        ;
LD2     set index=""
        if curDir'=nodeDiv do
        . set @pArray@(count,".. <UP>")=$$UpPath^TMGIOUTL(curDir)
        . set count=count+1
        for  set index=$order(tempFiles("DIRS",index)) quit:(index="")  do
        . set @pArray@(count,index)=$get(tempFiles("DIRS",index))
        . set count=count+1
        if selDir=1 goto LDQuit ;"skip showing files.
        ;
        set index=""
        for  set index=$order(tempFiles("FILES",index)) quit:(index="")  do
        . set @pArray@(count,index)=$get(tempFiles("FILES",index))
        . set count=count+1
        ;
LDQuit  quit

HndOnSel(pArray,Option,Info)
        ;"Purpose: handle ON SELECT event from Scroller
        ;"Input: pArray,Option,Info -- see documentation in Scroller
        ;"       Info has this:
        ;"          Info("CURRENT LINE","NUMBER")=number currently highlighted line
        ;"          Info("CURRENT LINE","TEXT")=Text of currently highlighted line
        ;"          Info("CURRENT LINE","RETURN")=return value of currently highlighted line
        ;"Globally-scoped var used: TMGSelect,TMGSCLRMSG
        new text set text=$get(Info("CURRENT LINE","TEXT"))
        set TMGSelect=$get(Info("CURRENT LINE","RETURN"))
        set TMGSCLRMSG="^"
        quit

HndlOnCmd(pArray,Option,Info)
        ;"Purpose: handle ON SELECT event from Scroller
        ;"Input: pArray,Option,Info -- see documentation in Scroller
        ;"       Info has this:
        ;"          Info("USER INPUT")=input
        ;"          Info("CURRENT LINE","NUMBER")=number currently highlighted line
        ;"          Info("CURRENT LINE","TEXT")=Text of currently highlighted line
        ;"          Info("CURRENT LINE","RETURN")=return value of currently highlighted line
	new done set done=0
        new rtn set rtn=$get(Info("CURRENT LINE","RETURN"))
	new path set path=rtn
        new UsrInput set UsrInput=$get(Info("USER INPUT"))
	new cmd set cmd=$$UP^XLFSTR($piece(UsrInput," ",1))
        if $extract(path,$length(path))'=nodeDiv do
        . set path=$$UpPath^TMGIOUTL(path)  ;"Trim off filename
        if cmd="CD" do  goto:done HOCDone
	. new newDir set newDir=$piece(UsrInput," ",2)
	. if newDir=".." set UsrInput=".." quit
	. set done=1
	. if $extract(newDir,1)'="/" set newDir=path_newDir
	. if $$IsDir^TMGKERNL(newDir)=0 do  quit
	. . write newDir," is not a valid existing directory.",!
	. . do PressToCont^TMGUSRIF
        . set TMGSelect=newDir
        . set TMGSCLRMSG="^"
	if cmd="MKDIR" do  goto:done HOCDone
	. new newDir set newDir=$piece(UsrInput," ",2)
	. set done=1
	. if $extract(newDir,1)'="/" set newDir=path_newDir
	. write !,"Create NEW directory: ",newDir
	. new % set %=2 
	. do YN^DICN write !
	. if %=1 if $$mkdir^TMGKERNL(newDir)
	. write #
        . set TMGSelect=path
        . set TMGSCLRMSG="^"
	if cmd="RMDIR" do  goto:done HOCDone
	. new newDir set newDir=$piece(UsrInput," ",2)
	. set done=1
	. if $extract(newDir,1)'="/" set newDir=path_newDir
	. write !,"DELETE directory: ",newDir
	. new % set %=2 
	. do YN^DICN write !
	. if %=1 if $$rmdir^TMGKERNL(newDir)
        . set TMGSelect=path
        . set TMGSCLRMSG="^"
	. write #
        if (UsrInput="{LEFT}")!(UsrInput="..") do  goto HOCDone
        . new nodeDiv set nodeDiv=$get(Option("nodeDiv"),"/") ;"extra info passed
        . set TMGSelect=$$UpPath^TMGIOUTL(path)
        . set TMGSCLRMSG="^"
        if UsrInput="{RIGHT}" do  goto HOCDone
        . set TMGSelect=$get(Info("CURRENT LINE","RETURN"))
        . set TMGSCLRMSG="^"
        ;"Later, I could put some stuff here to let the command line choose filters etc.
        ;"or perhaps jump to a given directory etc.  Perhaps later...
        if UsrInput["?" do  goto HOCDone
        . do ShowHelp(.Option)
        else  do
	. new newName set newName=path_UsrInput
	. new % set %=2 
	. if $$FileExists^TMGIOUTL(newName) set %=1
        . else  do
	. . write !,"Use NEW filename: ",newName
	. . do YN^DICN write !
	. . if %'=1 write #
	. if %=1 do
	. . set TMGSelect=newName
        . . set TMGSCLRMSG="^"
HOCDone quit


ShowHelp(Option)
        ;"Purpose: show help for file browser
	;"Input: Option -- see documentation in Scroller
        write !
        write "Use [UP], [DOWN], [PgUp], or [PgDown] keys to scroll",!
        write "Use [ENTER] to select file name",!
        write "Use [ENTER] or [RIGHT] key to browse into a directory",!
        write "Use [LEFT] key to back up one level",!
        write "Use ^ to abort without selecting a file",!
	if $get(Option("SELECT DIR"))'=1 do
	. write "To create/select a NEW file, just type new name and [ENTER]",!
	write "type: 'cd <DirName>' to change directory",!
	write "type: 'mkdir <DirName>' to create a NEW directory",!
	write "type: 'rmdir <DirName>' to DELETE a new directory",!
        do PressToCont^TMGUSRIF
        write #
        quit
