TweetFollow Us on Twitter

November 91 - User Selected Folders & Indexing Through Directories

User Selected Folders & Indexing Through Directories

Dan Wendin

MacApp 2 programmers can usually ignore working directories; however, you need to use them when the user selects a folder and your program accesses the files in it without further user interaction. Selecting a folder gives you a real directory and MacApp 2 usually expects a working directory.

Working directories were introduced with the Hierarchical File System (HFS) in 1986 as a way to maintain compatibility with the original flat file system. They are returned by the standard file dialogs and passed to the MacApp 2 file methods that deal with opening files.

Most applications let MacApp 2 take care of this. And the file manager chapter in Inside Mac Volume IV covers working directories in gruesome detail, making it difficult to sort out what you need to know. Hence this article.

To set the stage, suppose your file-based application has an Export function to generate a text file for a 4D data base application. To make things easier on the 4D application, the user can export any number of files into a single export file with a fixed name. The user puts all the files to be processed into one folder before starting your application. In your application, the user selects a folder and you take care of everything from that point on.

I have implemented a set of file based objects similar to Tom Becker's approach in his April Frameworks article and which (hopefully) anticipate MacApp 3. This is reflected to some extent in the sample code on the FrameWorks Disk.

CHOOSING A FOLDER

I adapted the code in DTS's sample code SC.018.StdFile to work with MacApp 2. This puts up a slightly modified version of the selection dialog used by MPW's Set Directory command (Figure 1). This dialog is a real DLOG/DITL resource pair, not a MacApp dialog. Its definition must be copied into one of your myApp.r files and then created using Res.

Once you have it in a myApp.rsrc file, you can change it using ResEdit or AppMaker (the standard AppMaker version 1.1, not the MacApp version 1.2). ViewEdit cannot access these resources.

The Select Button completes the selection process. Double clicking on a folder (or clicking the Open button) opens the folder and displays the folders one level down. The Select Current Folder button keeps the user from having to go up one level to select the current folder.

The call to SFPGetFile that displays the dialog looks like this:

SFPGetFile(where, '', @FoldersOnly, numTypes, pTypeList^,
            @FolderHook, gFolderReply, kGetFoldersDlgId, nil);

FoldersOnly and FolderHook are filter functions. These functions, and any variables they need to access, must be global within their unit. They can't be methods, nor can they be local to the procedure containing SFPGetFile. Tech Note 265, "Pascal To C-PROCEDURE Parameters," explains why-it has to do with limitations in the toolbox with respect to nested procedures.

The FoldersOnly function simply tests the ioFlAttrib field of the parameter block passed to it and returns true if a folder. The parameter numTypes is -1 to tell StdFile to consider all types filtered by FoldersOnly. The pTypeList parameter is ignored-except that it must point to a valid memory location.

The FolderHook function does the real work. The tricky part is that there are only two states for the gFolderReply.good field-true or false-and there is no way to set it to true because the Open button doesn't exit. So FolderHook sets a global flag to true and then acts as if the Cancel button was hit. The Cancel button sets this flag to false. In either case, gFolderReply.good is false, so it is ignored.

FolderHook puts the directory and vRefnum in globals for return to the client. These are the real directory and the real vRefnum. The vRefnum is obtained from low memory location $214, which contains the negative of the current vRefnum. The directory hilighted in the list is in gFolderReply.fType. This is returned in the global if the user clicks the Select button. The current directory is in low memory location $398 and this is returned if the user clicks the Select Current Folder button.

Are there files in the folder? The function ThereAreFiles asks for the first file of the required type using the same function GetFileInFolder that is used to index through the files in the folder. (This is discussed in detail below.)

index := 1;
ThereAreFiles := Self.fFolderDoc.GetFileInFolder(fDirectory,
                                    index, anAppFile, kFileType);

GetFileInFolder returns true if a file is found, and the parameter anAppFile identifies the file. It's ignored here, since we only care whether or not there is a file.

Does the output file already exist?

Because the same file name is used for all export files, I don't want to let the user to destroy an existing file, as the normal SFPPutFile would allow him to do. So, the code needs to check for that case and prevent him from going further. My ThisFileExistsInDir method does this using the toolbox call PBHGetFInfo to get the file's Finder info. The real vRefnum and directory ID are passed in the parameter block's ioVRefnum and ioDirID fields. If successful, then the file exists, and the method returns true:
with pBlock, theAppFile do {an HParamBlockRec}
begin
    ioNamePtr := @fName;
    ioFDirIndex := 0;
    ioVRefnum := vRefnum; {real vRefNum}
    ioDirID := theDirectory
end;
err := PBHGetFInfo(@pBlock, false);
ThisFileExistsInDir := err = noErr

OPENING THE OUTPUT FILE

Now it's time to worry about the distinction between real and working directories. The MacApp methods and utility functions that open files expect working directories as their vRefnum parameters. The first thing they do is convert to a real directory and vRefnum. In allocating and opening a file based object, fOutputFile, we switch to a working directory, open the new file and then switch back.
Self.SwitchToWorkDir(theAppFile, itsDirectory);
Self.OpenNewFile(theAppFile);
Self.RestoreVRefnum(theAppFile);

My SwitchToWorkDir method uses the toolbox call PBOpenWD to open a working directory. It passes the real vRefnum and directory ID, and the application's signature in the parameter block's ioVRefnum, ioWDDirID and ioWDProcID fields, respectively, and gets back the working directory ID in the ioVRefnum field.

with pBlock do {a WDPBRec}
begin
    ioNamePtr := nil;
    ioVRefNum := anAppFile.vRefnum; {the real vRefNum}
    ioWDDirID := theDirectory; {the real directory}
    {program signature}
    ioWDProcID := longint(kSignature); 
    {assign a working ID}
    err := PBOpenWD(@pBlock, false); 
    {switch vRefnum to Working Directory}
    anAppFile.vRefnum := ioVRefNum 
end {with}

This working directory is passed as the vRefnum to OpenNewFile. Because of this doubling up of the ioVRefnum field, the real vRefnum must be available for restoring after the file is opened. OpenNewFile is an adaptation of the MacApp 2 open new file method moved from TApplication.

There are perhaps 40 working directories available to all applications open under MultiFinder under System 6; there are fewer in System 7. There is only one working directory for each file regardless of which application is accessing the file.

Working directories that aren't in use (that is, have no active file buffers associated with them) are closed when the application that opened them quits or if an application explicitly closes them with no active file buffers associated. Therefore, there is the potential of stepping on another application if we explicitly close a working directory. However, I chose to do this rather than risk causing my application and others to run out of working directories. In reality, I have a number of extract files open and, as shown below, we have to do the same thing for the existing files we process.

My RestoreVRefnum method uses the toolbox call PBCloseWD to close the working directory, passing the working directory. It then restores the original vRefnum.

with pBlock do {a WDPBRec}
begin
    ioVRefNum := anAppFile.vRefnum; {the working directory}
    err := PBCloseWD(@pBlock, false); {release working ID}
end;

INDEXING THROUGH THE FILES

I use the GetFileInFolder method, mentioned above, to index through the file. The index is set to 1 before calling. The method returns the next file of the requested type and its index. Subsequent calls move the index on to the next file, returning false when the list is exhausted.
index := 1;
repeat
fileReturned := aFolderDoc.GetFileInFolder(fDirectory,
                                index, theAppFile, kFileType);
if fileReturned then
    begin
      {allocate an object for the file, which opens the file}
        New(anExtractDoc);
        FailNil(anExtractDoc);
        anExtractDoc.ICFExtractDoc(kFileType, kSignature,
                    theAppFile, itsDir, kFileExists, cancelled);

            {process this file if no problem opening}
        if not cancelled then
            anExtractDoc.ProcessFile(Self.fOutputFile);

        FreeIfObject(anExtractDoc)
    end
until not fileReturned;

My GetFileInFolder method first uses the toolbox call PBGetCatInfo to determine if there is an item for the current index and, if so, whether it is a directory or a file. It passes the real vRefnum (from $214), directory and index in the parameter block's ioVRefnum, ioDrDirID and ioFDirIndex fields, respectively. If there is an item, it gets back a pointer to the name and file attributes in the ioNamePtr and ioFlAttrib fields. It returns to the caller with false if there are no more items in the list. It moves on to the next item if ioFlAttrib indicates a directory, not a file.

with block do {a CInfoPBRec}
begin
    ioNamePtr := @theName; {returns file or directory name}
    ioVRefNum := -(SFSaveDisk^); {current volume refnum}
    ioFDirIndex := index;
    ioDrDirID := theDirectory;
    err := PBGetCatInfo(@Block, false)
end;

The toolbox call PBHGetFInfo gets the file type, passing the same fields (the directory is passed in the ioDirID field). The file type in the finder info is returned in ioFlFndrInfo.fdType. If it matches, the real vRefnum and file name are returned to the caller. Otherwise, it moves on to the next item.

with fblock do {HParamBlockRec}
begin
ioNamePtr := @theName; {file name}
ioVRefNum := block.ioVRefNum; {real}
ioFDirIndex := index;
ioDirID := theDirectory;
ferr := PBHGetFInfo(@fBlock, false);

    {continue if not the type requested or an error}
stillLooking := (ferr <> NoErr) or
(ioFlFndrInfo.fdType <> theFileType)
end;

Because TDocument's ReadFromFile method wants a working directory, it is surrounded by calls to SwitchToWorkDir and RestoreVRefnum.

Don't forget to free the file object at the end of the repeat loop. Happy file indexing!

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

calibre 2.69.0 - Complete e-book library...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital librarian... Read more
Evernote 6.9.1 - Create searchable notes...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
jAlbum Pro 13.5 - Organize your digital...
jAlbum Pro has all the features you love in jAlbum, but comes with a commercial license. You can create gorgeous custom photo galleries for the Web without writing a line of code! Beginner-friendly... Read more
jAlbum 13.5 - Create custom photo galler...
With jAlbum, you can create gorgeous custom photo galleries for the Web without writing a line of code! Beginner-friendly, with pro results - Simply drag and drop photos into groups, choose a design... Read more
Google Chrome 53.0.2785.143 - Modern and...
Google Chrome is a Web browser by Google, created to be a modern platform for Web pages and applications. It utilizes very fast loading of Web pages and has a V8 engine, which is a custom built... Read more
Chromium 53.0.2785.143 - Fast and stable...
Chromium is an open-source browser project that aims to build a safer, faster, and more stable way for all Internet users to experience the web. Version 53.0.2785.143: [Security Fix] High CVE-2016-... Read more
QuickBooks 2015 16.1.7.1524 R8 - Financi...
Save 20% on QuickBooks Pro for Mac today through this special discount link QuickBooks 2015 helps you manage your business easily and efficiently. Organize your finances all in one place, track... Read more
Sierra Cache Cleaner 11.0.1 - Clear cach...
Sierra Cache Cleaner is an award-winning general purpose tool for macOS X. SCC makes system maintenance simple with an easy point-and-click interface to many macOS X functions. Novice and expert... Read more
Default Folder X 5.0.7 - Enhances Open a...
Default Folder X attaches a toolbar to the right side of the Open and Save dialogs in any OS X-native application. The toolbar gives you fast access to various folders and commands. You just click on... Read more
Safari Technology Preview 10.1 - The new...
Safari Technology Preview contains the most recent additions and improvements to WebKit and the latest advances in Safari web technologies. And once installed, you will receive notifications of... Read more

Pumped BMX 3: Beginner tips and tricks
There’s a whole lot more to Pumped BMX 3 than meets the eye. Your goal is to perform a wide array of sweet flips and tricks, but that’s easier said than done. It takes well practiced timing and coordination, and the game doesn’t really explain that... | Read more »
Cybird’s latest release - BFB Champions...
Launched in the UK in early September, BFB Champions’ newest update is loaded with great new features, and looks set to outshine the original version by taking it out of soft launch and giving it a new lease of life. | Read more »
3 apps to boost your focus
As someone who works from home, my workspace is a minefield of distraction. Cats, tasty snacks, the wind blowing past my window, that cleaning that I suddenly can’t put off any longer. If I let distraction takes its course, I find that soon half... | Read more »
Pumped BMX 3 (Games)
Pumped BMX 3 1.0 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0 (iTunes) Description: The final instalment of the smash hit #1 rated BMX game is here! Following on from the insane success of Pumped BMX 2, Pumped 3... | Read more »
4 games like Burly Men at Sea to inspire...
Burly Men at Sea is out today and it looks a treat. It tells the tale of three Scandinavian fishermen who leave the humdrum of their daily lives to go exploring. It’s a beautiful folksy story that unfurls as you interact with the environment... | Read more »
3 reasons you need to play Kingdom: New...
Developed by a tag team of indie developers - Thomas "Noio" van den Berg and Marco "Licorice" Bancale - Kingdom is a vibrant medieval fantasy adventure that casts players as a king or queen who must expand their empire by exploring the vasts lands... | Read more »
JoyCity have launched a brand new King o...
Great news for all of you Game of Dice fans out there - JoyCity have just released a brand new limited edition pack with a really cool twist. The premise of Game of Dice is fairly straightforward, asking you to roll dice to navigate your way around... | Read more »
Burly Men at Sea (Games)
Burly Men at Sea 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Burly Men at Sea is a folktale about a trio of large, bearded fishermen who step away from the ordinary to seek adventure. | Read more »
3 tips for catching the gnarliest waves...
Like a wave breaking on the shore, Tidal Rider swept its way onto the App Store charts this week settling firmly in the top 10. It’s a one-touch high score-chaser in which you pull surfing stunts while dodging seagulls and collecting coins. The... | Read more »
The beginner's guide to destroying...
Age of Heroes: Conquest is 5th Planet Games’ all new turn-based multiplayer RPG, full of fantasy exploration, guild building, and treasure hunting. It’s pretty user-friendly as far as these games go, but when you really get down to it, you’ll find... | Read more »

Price Scanner via MacPrices.net

CAZE Annouces New Zero 5 Case for Jet Black i...
Hong Kong basd CAZE has announced Zero 5 case for iPhone 7/ 7 Plus, one of the world’s thinnest clear hard cases, measuring just 0.5 millimeters. CAZE has been producing and improving the Zero 5... Read more
Nest Egg Inventory App for iOS Offers Conven...
Campbell, California based Winprogger LLC has announced the release and immediate availability of Nest Egg – Inventory 4.1.22, an important update to their easy-to-use, yet comprehensive inventory... Read more
Factor4, LLC Launches Apple iOS and Android G...
Factor4, LLC, which offers gift and loyalty services to the SMB marketplace, has released free mobile applications that enable merchants to process via all Apple and Android devices. The Apple and... Read more
15-inch Retina MacBook Pros on sale for $200...
B&H Photo has 15″ Retina Apple MacBook Pros on sale for $200 off MSRP. Shipping is free, and B&H charges NY tax only: - 15″ 2.2GHz Retina MacBook Pro: $1799 $200 off MSRP - 15″ 2.5GHz Retina... Read more
Apple refurbished iMacs available for up to $...
Apple has Certified Refurbished 2015 21″ & 27″ iMacs available for up to $350 off MSRP. Apple’s one-year warranty is standard, and shipping is free. The following models are available: - 21″ 3.... Read more
Check Apple prices on any device with the iTr...
MacPrices is proud to offer readers a free iOS app (iPhones, iPads, & iPod touch) and Android app (Google Play and Amazon App Store) called iTracx, which allows you to glance at today’s lowest... Read more
Apple price trackers, updated continuously
Scan our Apple Price Trackers for the latest information on sales, bundles, and availability on systems from Apple’s authorized internet/catalog resellers. We update the trackers continuously: - 15″... Read more
Apple refurbished 2016 13-inch MacBook Airs a...
Apple has Certified Refurbished 2016 13″ MacBook Airs available starting at $849. An Apple one-year warranty is included with each MacBook, and shipping is free: - 2016 13″ 1.6GHz/8GB/128GB MacBook... Read more
1.4GHz Mac mini on sale for $449, save $50
Adorama has the 1.4GHz Mac mini on sale for $50 off MSRP including free shipping plus NY & NJ sales tax only: - 1.4GHz Mac mini (Apple sku# MGEM2LL/A): $449 $50 off MSRP To purchase a mini at... Read more
Apple refurbished 2015 13-inch MacBook Airs a...
Apple has Certified Refurbished 2015 13″ MacBook Airs available starting at $759. An Apple one-year warranty is included with each MacBook, and shipping is free: - 2015 13″ 1.6GHz/4GB/128GB MacBook... Read more

Jobs Board

*Apple* Retail - Multiple Positions- Akron,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Hardware Design Validation Engineer - *Apple...
Changing the world is all in a day's work at Apple . If you love innovation, here's your chance to make a career of it. You'll work hard. But the job comes with more Read more
Systems Architecture Prototyping - *Apple*...
Changing the world is all in a day's work at Apple . If you love innovation, here's your chance to make a career of it. You'll work hard. But the job comes with more Read more
*Apple* Retail - Multiple Positions- South B...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Restaurant Manager (Neighborhood Captain) - A...
…in every aspect of daily operation. WHY YOU'LL LIKE IT: You'll be the Big Apple . You'll solve problems. You'll get to show your ability to handle the stress and Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.