Displaying Directories "An intellectual is someone who can listen to the William Tell overture and not think of the Lone Ranger." Anonymous The Toolkit includes two entirely different object families for dis- playing directory listings. The objects ListDirOBJ and ListDirSortOBJ are descendant from ListOBJ and should be used when you want to display the directory in a stretchable window, or let the user select multiple files. The DirWinOBJ should be used when you want to display a file selection dialog box and allow the user to choose a single file. Displaying Directory List Windows The totLIST unit includes the ListDirOBJ object which is an adaptation of ListOBJ. ListDirOBJ is designed to display files and directories in a stretchable window. ListDirOBJ is a descendant of ListOBJ, and inher- its all the following ListOBJ methods: Init SetTopPick SetActivePick SetTagging SetColWidth Show Go LastKey GetHiString Win^ Done Some of the list defaults are influenced by LookTOT^ methods. Refer back to page 9-20 for a full description of these methods. In addition to the inherited methods, ListDirOBJ includes the following important method: ReadFiles(Filemasks:string; FileAttrib:word); This method must be called before the Go method. ReadFiles instructs the object to read all the files matching the first parameter. The filemask should include wild cards, e.g. *.pas, *.*, bob?.tit, etc., and may optionally include a drive and path. If a drive/path is not specified, all matching files in the default directory will be read. Note that the string may include more than one file specification sepa- rated by spaces, e.g. '*.pas *.asm'. The second parameter identifies the attributes of the files to include in the list. 10-2 User's Guide -------------------------------------------------------------------------------- The Turbo Pascal DOS unit includes the following file attribute con- stants: ReadOnly = $01 Hidden = $02 SysFile = $04 VolumeID = $08 Directory = $10 Archive = $20 AnyFile = $3F Specify any of the desired file types by summing these constants and passing them as the second parameter. For example, the following method call will list all the .TXT files that can be edited: ReadFiles('*.TXT',Anyfile-ReadOnly-Hidden); Note that the Toolkit automatically removes the VolumeID file from the list. In summary, to display a basic file listing, all you have to do is declare an instance of ListDirOBJ, and then call the methods Init, ReadFiles and Go. The chosen file can be determined by calling the function method GetHiString. Listed below is the demo file DEMDR1.PAS which displays a simple directory, followed by figure 10.1 showing the resultant list. program DemoDirectoryOne; {demdr1 - the default directory list} Uses DOS, CRT, totFAST, totLIST; Var ListWin: ListDirObj; begin Screen.Clear(white,'°'); {paint the screen} with ListWin do begin Init; ReadFiles('*.*',AnyFile); Go; Win^.Remove; if (LastKey = 27) or (Lastkey = 600) then writeln('You escaped!') Else writeln('You chose file '+GetHiString); Done; end; end. Displaying Directories 10-3 -------------------------------------------------------------------------------- Figure 10.1 [SCREEN] A Basic Directory List Determining Tagged Files By default, the user can select multiple files by hitting the [KEYCAP] or clicking the left mouse button on a filename. The method SetTagging can be used to enable or disable multiple file tagging. The ListDirOBJ object implements the methods GetStatus and SetStatus to provide access to tagged files. These methods work in precisely the same way as their namesakes in the DLLOBJ family. Full descriptions can be found on page 9-27, but in brief, GetStatus returns a boolean to indicate whether the file has been tagged, and is passed two parame- ters; the first parameter is the number of the file in the list, and the second is the flag ID which should be set to 0 (zero) to check the status of the tag flag. Each ListDirOBJ instance includes a FileDLLOBJ object which is a linked list holding all the file details. The ListDirOBJ object provides the method FileList which returns a pointer to the FileDLLOBJ list. This is useful when you want to directly manipulate the file linked list. You may recall that all DLLOBJ objects have a method TotalNodes which returns a longint identifying the number of entries in the list. The ListDirOBJ method FileList^.TotalNodes therefore returns the total num- ber of files in the list. The demo program DEMDR2.PAS, listed below, shows how the methods GetS- tatus and FileList^.TotalFiles can be used to ascertain which files the user tagged. Notice that you must access the tagged files before calling the method Done - otherwise, the list will be disposed of before you can access it! Following the listing are figures 10.2 and 10.3 which provide an example of the output generated by the program. Note that the highlighted file will only be included in the list if the file is tagged. program DemoDirectoryTwo; {demdr2 - determining chosen files} Uses DOS, CRT, totFAST, totLIST; Var ListWin: ListDirObj; Tot,L:longint; begin Screen.Clear(white,'°'); {paint the screen} with ListWin do begin 10-4 User's Guide -------------------------------------------------------------------------------- Init; ReadFiles('*.*',AnyFile); Go; Win^.Remove; if (LastKey = 27) or (Lastkey = 600) then writeln('You escaped!') Else begin writeln('The highlighted file was '+GetHiString); writeln('The tagged files were: '); Tot := FileList^.TotalNodes; for L := 1 to Tot do if GetStatus(L,0) then writeln(GetString(L,0,0)); end; Done; end; end. Figure 10.2 [SCREEN] Tagging Multiple Files Figure 10.3 [SCREEN] Displaying the Tagged Files Advanced Directory Management In the previous section you learned that the method FileList returns a pointer to an instance of type FileDLLOBJ which contains a list of all the files selected for display. In addition to the TotalNodes method, you can call any of the other FileDLLOBJ methods. Remember that these methods must be called via the FileList method using the syntax: FileList^.method Sorting The Sort method can be used to sort the directory listing. This method is described on page 9-6, and has the following syntax: FileList^.Sort(SortID:shortint;Ascending:boolean); When used with a FileDLLOBJ object, the first parameter instructs the Toolkit about which element of the file to sort by. The permissible values are as follows: Displaying Directories 10-5 -------------------------------------------------------------------------------- 0 DOS (unsorted) 1 Name 2 Ext 3 Size 4 Time For example, calling the method Sort(2,false) will sort the files by filename extension in descending order. Accessing File Details The totLINK unit includes the following type declaration: tFileInfo = record Filename: string[12]; Attr: byte; Time:longint; Size:longint; LoadID: longint; end; Every node in a FileDLLOBJ list contains such a record, describing all the file details. The first four fields in the record are the same as the corresponding fields in the Turbo Pascal SearchRec record. The fifth record LoadID is the node number when the file was added to the list. This field is required so the list can be sorted in DOS order, i.e. the order in which the files are stored in the DOS directory. The FileDLLOBJ method GetFileRecord can be used to access a file's record, and the method GetLongStr can be used to access a string detailing the file information. The syntax of these methods is as fol- lows: FileList^.GetFileRecord(var Info:tFileInfo; NodeNumber:longint); The first parameter must be a variable of type tFileInfo. This variable is updated with the file details for the file specified by the second parameter. FileList^.GetLongStr(Node:DLLNodePtr): string; This method is passed a pointer to the list node, and returns a for- matted string representing the node's file details. Remember that the method FileList^.NodePtr can be used to return a node pointer. 10-6 User's Guide -------------------------------------------------------------------------------- Refreshing the File List In the last chapter you learned that you can intercept all characters pressed while a list is active, by assigning a character hook, or by creating a descendant method and replacing the virtual method CharTask. Thanks to OOP inheritance, these techniques can also be used with List- DirOBJ objects. The FileList linked list can be directly modified using some FileDLLOBJ methods. Ordinarily, you wouldn't need to call these methods, but if you want to modify the displayed list "on the fly" from a character hook, you can use the following methods: FileList^.GetFileMask:string; This function returns the currently active file mask. FileList^.SetFileDetails(FileMasks:string; FileAttrib:word); Specifies a new set of file masks and file attributes. This method must be called prior to FillList. FileList^.FillList; Empties the list (if it already contains files), and re-populates the list with the new category of files. FileList^.FillNewMask(Filemasks:string); This method re-populates the list with all files matching the FileMasks parameter, which have the same attributes that were used when the list was last filled. Example The demo program DEMDR3.PAS, listed below, illustrates some of the techniques discussed in this section. Figure 10.4 shows the resultant output. program DemoDirectoryThree; {demdr3 - a customized directory list} Uses DOS, CRT, totFAST, totLINK, totLIST; Var ListWin: ListDirObj; FileInfo: tFileInfo; Displaying Directories 10-7 -------------------------------------------------------------------------------- begin Screen.Clear(white,'°'); {paint the screen} with ListWin do begin Init; SetTagging(false); ReadFiles('*.*',AnyFile - directory); {exclude directories} FileList^.Sort(1,true); {sort in name order} Win^.SetTitle(' Choose a file '); Go; Win^.Remove; if (LastKey = 27) or (Lastkey = 600) then writeln('You escaped!') Else begin writeln('You chose file '+GetHiString); writeln(FileList^.GetLongStr(FileList^.ActiveNodePtr)); FileList^.GetFileRecord(FileInfo, FileList^.ActiveNodeNumber); with FileInfo do begin writeln('Name: ', FileName); writeln('Attr: ', Attr); writeln('Packed Time: ', Time); writeln('Size: ', Size); writeln('Directory entry:',LoadID); end; end; Done; end; end. Figure 10.4 [SCREEN] Advanced Directory Control Displaying Sortable Directories ListDirSortOBJ is a descendant of ListDirOBJ, and shares all the meth- ods of its ancestor. ListDirSort works in just the same way as ListDi- rOBJ, with one added bonus - the user can press the right mouse button or [KEYCAP] to display a sort dialog box. This allows the end user to sort the file list in any order. Listed below is the demo program DEMDR4.PAS, followed by figure 10.5 showing the sort dialog box. 10-8 User's Guide -------------------------------------------------------------------------------- program DemoDirFour; {demdr4 - a user sortable directory listing} Uses DOS, CRT, totFAST, totLIST; Var ListWin: ListDirSortOBJ; begin Screen.Clear(white,'°'); {paint the screen} Screen.WriteCenter(25,white,' Press S or Right Mouse Button for Sort Options '); with ListWin do begin Init; ReadFiles('*.*',AnyFile); Go; Done; end; end. Figure 10.5 [SCREEN] The Sort Dialog Box Displaying Directories 10-9 -------------------------------------------------------------------------------- Displaying a Directory Dialog Window In the unit totDIR, the Toolkit provides an alternative object for displaying a directory dialog box. Figure 10.6 shows how the dialog box looks to the user. The display is generated using a DirWinOBJ, and it is ideal for prompting the user to enter a filename. The user can enter a file name, or a file mask, into the filename field. If a file mask is entered, the file list is automatically updated to reflect the new mask. The user can move from field to field by pressing the [KEYCAP] and [KEYCAP] keys. As in the Turbo 6 environ- ment, the user can choose a file from the file list by cursoring to the desired file and pressing [KEYCAP]. The user can change directories or drives by tabbing to the directory list, highlighting the desired directory, and pressing [KEYCAP]. The user can also tab to the buttons and select OK, Cancel or Help. Alternatively, the buttons can be selected by pressing one of the hotkeys [KEYCAP], [KEYCAP] or [KEYCAP]. A mouse user simply clicks on a field to activate it, and double-clicks to choose a specific file or directory. Figure 10.6 [SCREEN] A Pop-up Directory Window Displaying a Basic Directory Window The DirWinOBJ is very easy to use, and has the following four main methods: Init; As always, this methods initializes the instance and must always be called first. Go:tAction; This is the "do it" method which instructs the Toolkit to display the dialog window and wait for the user to choose a file. Go returns a member of the enumerated type tAction to indicate whether the user chose a file or escaped. This function will only return Finished or Escaped. GetChosenFile:string; 10-10 User's Guide -------------------------------------------------------------------------------- This function method should be called after Go, to determine which file the user selected. The function returns the name the user entered in the input field, or the active filename in the file list. Note you should check the value returned by Go to check whether the user escaped. Done; This function should be called to dispose of the instance, and should be called after the method GetChosenFile. Listed below is the program DEMDR5.PAS which generated the display shown in figure 10.6. program DemoDirFive; {demdr5 - the directory dialog box} Uses DOS, CRT, totFAST, totDir, totIO1; Var DirWin: DirWinObj; Result: tAction; begin Screen.Clear(white,'°'); {paint the screen} with DirWin do begin Init; Result := Go; if Result = Finished then writeln('You chose file: ',GetChosenFile) else writeln('You escaped!'); Done; end; end. Customizing the Window To provide further display control, the DirWinOBJ object also includes the following customization methods: SetFileDetails(StartDir:string; FileMasks:string; FileAttrib: word); By default, the Toolkit will display any file with a mask of '*.*' in the default directory. Use this method to override the defaults. The first parameter specifies the initial drive and directory to search. The second parameter identifies the file mask which may include multi- Displaying Directories 10-11 -------------------------------------------------------------------------------- ple file masks separated by spaces, e.g. '*.bat *.exe *.com'. The third parameter specifies the attributes of the files to be included in the list (see the file attribute list on page 10.2). SetSortDetails(SortID:byte; SortOrder: boolean); Ordinarily, the files are sorted in name order. Use this method to specify an alternate sort order. Refer to the sorting discussion on page 10.5 for further information. Win^:MoveWinPtr; The method Win returns a pointer to the MoveWinOBJ instance on which the window is drawn. By calling any MoveWinOBJ method using the syntax Win^.method, you control the appearance of the window. Note: the DirWinOBJ is a hybrid of a number of other Toolkit objects, and the way to control all the colors is not obvious. The overall background, title, box border and file details are con- trolled by the window, and the color is set with the method Win^.SetColors. All other aspects of the dialog box are controlled by the object IOTOT. The following IOTOT methods control the directory display colors: IOTOT^.SetColLabel (changes the box labels, e.g. Name:) IOTOT^.SetColList (changes the file and dir lists) IOTOT^.SetColField (changes the filename input field IOTOT^.SetColButtons (changes the buttons) IOTOT is discussed fully in the next chapter. Listed below is the demo program DEMDR6.PAS which illustrates how to customize the directory display using the above methods, and figure 10.7 shows the resultant output: program DemoDirSix; {demdr6 - customizing the directory dialog box} Uses DOS, CRT, totFAST, totDir, totIO1; Var DirWin: DirWinObj; Result: tAction; begin Screen.Clear(white,'°'); {paint the screen} 10-12 User's Guide -------------------------------------------------------------------------------- with DirWin do begin Init; SetFileDetails('','*.EXE *.COM *.BAT',AnyFile); SetSortDetails(2,true); Win^.SetColors(15,15,15,11); IOTOT^.SetColLabel(15,15,15,15); IOTOT^.SetColList(7,7,112,112); IOTOT^.SetColField(7,112,8,8); IOTOT^.SetColButton(112,126,127,126); Result := Go; if Result = Finished then writeln('You chose file: ',GetChosenFile) else writeln('You escaped!'); Done; end; end. Figure 10.7 [SCREEN] Customizing the Directory Window On-Screen Help By default, the Help key displays a simple message window describing how to select a file (see figure 10.8). You can substitute your own help dialog if necessary. Figure 10.8 [SCREEN] The Default Help Display In the next chapter, you will learn all about the Toolkit's very power- ful full screen input facility. The totDIR unit makes extensive use of the totIO units to build the directory dialog box. To override the default directory help, you need to access the full screen input man- ager object. You will be very familiar with the manager by the end of the next chapter, but for now, all you need to concentrate on is the help facility. The DirWinOBJ object includes the function method Action which returns a pointer to the dialog manager. By calling the dialog manager's own method SetHelpHook, you can assign a special procedure to be called when the user asks for help. Displaying Directories 10-13 -------------------------------------------------------------------------------- To create customized help, all you have to do is create a procedure following some specific rules, and then call the DirWinOBJ method Action^.SetHelpHook to instruct the Toolkit to use your procedure. For a procedure to be eligible as a help hook, it must adhere to the following rules: Rule 1 The procedure must be declared as a FAR procedure. This can be achieved by preceding the procedure with a {$F+} compiler directive, and following the procedure with a {$F-} direc- tive. Alternatively, Turbo 6 users can use the new keyword FAR following the procedure statement. Rule 2 The procedure must be declared with one passed parameter of type word. This parameter indicates which field was high- lighted when help was pressed. The directory dialog fields have the following IDs: 1 File mask field 2 File list field 3 Directory list field 4 OK button 5 Cancel button 65335 Help button (constant HelpID) Rule 3 The procedure must be at the root level, i.e. the procedure cannot be nested within another procedure. The following procedure declaration follows these rules: {$F+} procedure MyHelpHook(ID:word); .....{procedure statements} end; {$F-} The following method Action^.SetHelpHook is then called to instruct the Toolkit to call your procedure when the user asks for help: Action^.SetHelpHook(PassedProc:HelpProc); This method is passed the procedure name of a procedure declared using the rules outlined above. The demo program DEMDR7.PAS, listed below, illustrates how to customize the directory help. Figure 10.9 shows the help screen! program DemoDirSeven; {demdr7 - customizing directory help} 10-14 User's Guide -------------------------------------------------------------------------------- Uses DOS, CRT, totFAST, totDir, totIO1, totMSG; Var DirWin: DirWinObj; Result: tAction; {$F+} procedure NewHelp(ID:word); {} var HelpWin: MessageOBJ; begin with HelpWin do begin Init(1,' Not Much Help '); AddLine(''); Addline(' Honey, if you need help here, we got big problems! '); AddLine(''); Show; Done; end; end; {NewHelp} {$F-} begin Screen.Clear(white,'°'); {paint the screen} with DirWin do begin Init; Action^.SetHelpHook(NewHelp); Result := Go; if Result = Finished then writeln('You chose file: ',GetChosenFile) else writeln('You escaped!'); Done; end; end. Figure 10.9 [SCREEN] Customized Help