unit preferences; { This unit defines class cPreferences, which provides mostly-automated } { handling of an application's user-settable preferences. } { } { iPreferences - Initialize a new preferences object. PrefFileName } { is the name for the preferences file. UseSystem } { indicates, it true, that the Preferences folder in } { the system folder is to be used (System 7 and later),} { otherwise the preferences file is created/opened in } { the folder specified by theVRef (0=app folder). If } { autoCreate is true a new preferences file will be } { created if one can't be found (giving the new file } { the type "PREF" and the creator type specified. } { getPreferences - Fetch the preferences and return a handle to them. } { setPreferences - Set the preferences to the data referenced by the } { given handle. } { updatePreferences - writes the preferences to the preferences file. } { copyToDialog - Copy the data from the preferences into the fields } { of the preferences dialog box. Override this to } { customize for the specifics of the preferences. } { copyFromDialog - Copy user-modified data from the dialog fields into } { the preferences data. Override this to customize } { for specific preferences. } { shouldCopyFromDialog - Returns true if the item selected by the user } { indicates that the preferences should be updated, ie,} { the user clicked "OK", false if the changes should } { be ignored (user clicked "Cancel"). Override this } { unless item 1=OK and all others mean Cancel. } { dialogFinished - Returns true if the item that the user selected } { should cause the dialog to be dismissed. } { doPreferencesDialog - Copies the preference data into the dialog } { fields using copyToDialog, displays and handles the } { the dialog, and calls copyFromDialog if shouldCopy- } { FromDialog returns true. } { makeNewPreferences - Returns a handle to the preferences. Override } { this to return a handle to the appropriate data. } { defaultField - Return the item number of the field to be selected } { when the dialog first opens. Override. } { selectDefaultField - hilite the edit field returned by defaultField. } interface uses objIntf, Dialogs, Folders; const prefsFileType = 'PREF'; type cPreferences = object(tObject) itsData: handle; itsRefNum: integer; itsFileName: str255; itsVRef: integer; function iPreferences (prefFileName: str255; theVRef: integer; useSystem, autoCreate: boolean; creator: OSType): OSErr; function getPreferences: handle; procedure setPreferences (newData: handle; disposeOldData: boolean); function updatePreferences: OSErr; procedure copyToDialog (theData: handle; theDialog: dialogPtr); procedure copyFromDialog (theData: handle; theDialog: dialogPtr); function shouldCopyFromDialog (theDialog: dialogPtr; theItem: integer): boolean; procedure doPreferencesDialog (prefID: integer); function makeNewPreferences: handle; procedure selectDefaultField (theDialog: dialogPtr); function defaultField: integer; function dialogFinished (theDialog: dialogPtr; theItem: integer): boolean; procedure free; override; end; implementation procedure showDefaultSelection (theDialog: dialogPtr; item: integer); { Draw a bold line around the ³default² selection in a dialog box } var defaultType: integer; defaultHandle: handle; defaultRect: rect; begin setPort(theDialog); getDialogItem(theDialog, item, defaultType, defaultHandle, defaultRect); insetRect(defaultRect, -4, -4); penSize(3, 3); frameRoundRect(defaultRect, 16, 16); end; { showDefaultSelection } function cPreferences.defaultField: integer; { Return non-zero if a field should be selected in the dialog when first displayed. } { Override this. } begin defaultField := 0; end; { cPreferences.defaultField } function cPreferences.dialogFinished (theDialog: dialogPtr; theItem: integer): boolean; { Return true if clicking on theItem means the dialog should be put away. Override. } begin dialogFinished := true; end; { cPreferences.dialogFinished } procedure cPreferences.selectDefaultField (theDialog: dialogPtr); { Highlight the first edit field } var theField: integer; begin theField := self.defaultField; if theField <> 0 then SelectDialogItemText(theDialog, theField, 0, maxint); end; function cPreferences.makeNewPreferences: handle; { Create a new preferences resource } begin makeNewPreferences := nil; end; { cPreferences.makeNewPreferences } function cPreferences.iPreferences (prefFileName: str255; theVRef: integer; useSystem, autoCreate: boolean; creator: OSType): OSErr; { Initialize a preferences object } var err: OSErr; theDirID: longint; numBytes: longint; begin itsFileName := prefFileName; itsVRef := theVRef; itsData := makeNewPreferences; if useSystem then begin err := FindFolder(kOnSystemDisk, kPreferencesFolderType, autoCreate, itsVRef, theDirID); if err = noErr then begin err := HOpen(itsVRef, theDirID, itsFileName, fsWrPerm, itsRefNum); if (err = fnfErr) & autoCreate then begin err := HCreate(itsVRef, theDirID, itsFileName, creator, prefsFileType); if err = noErr then begin err := HOpen(itsVRef, theDirID, itsFileName, fsWrPerm, itsRefNum); if err = noErr then begin numBytes := getHandleSize(itsData); err := SetFPos(itsRefNum, fsFromStart, 0); err := FSWrite(itsRefNum, numBytes, itsData^); end; end; end; end; end else begin err := FSOpen(itsFileName, itsVRef, itsRefNum); if (err = fnfErr) & autoCreate then begin err := create(itsFileName, itsVRef, creator, prefsFileType); if err = noErr then begin err := FSOpen(itsFileName, itsVRef, itsRefNum); if err = noErr then begin numBytes := getHandleSize(itsData); err := SetFPos(itsRefNum, fsFromStart, 0); err := FSWrite(itsRefNum, numBytes, itsData^); end; end; end; end; if err = noErr then begin err := SetFPos(itsRefNum, fsFromStart, 0); if err = noErr then begin err := GetEOF(itsRefNum, numBytes); if err = noErr then begin itsData := newHandle(numBytes); err := FSRead(itsRefNum, numBytes, itsData^); end; end; end; iPreferences := err; end; { cPreferences.iPreferences } procedure cPreferences.free; var err: OSErr; begin err := FSClose(itsRefNum); disposeHandle(itsData); inherited free; end; { cPreferences.free } procedure cPreferences.doPreferencesDialog (prefID: integer); { Display the preferences dialog } var savePort: grafPtr; theDialog: dialogPtr; theItem: integer; err: OSErr; begin getPort(savePort); theDialog := getNewDialog(prefID, nil, pointer(-1)); self.copyToDialog(itsData, theDialog); showDefaultSelection(theDialog, 1); selectDefaultField(theDialog); repeat ModalDialog(nil, theItem); until dialogFinished(theDialog, theItem); if shouldCopyFromDialog(theDialog, theItem) then begin copyFromDialog(itsData, theDialog); err := updatePreferences; end; DisposeDialog(theDialog); setPort(savePort); end; { cPreferences.doPreferencesDialog } procedure cPreferences.copyToDialog (theData: handle; theDialog: dialogPtr); begin end; { cPreferences.copyToDialog } procedure cPreferences.copyFromDialog (theData: handle; theDialog: dialogPtr); begin end; { cPreferences.copyFromDialog } function cPreferences.shouldCopyFromDialog (theDialog: dialogPtr; theItem: integer): boolean; begin shouldCopyFromDialog := theItem = 1; end; { cPreferences.shouldCopyFromDialog } function cPreferences.getPreferences: handle; begin getPreferences := itsData; end; { cPreferences.getPreferences } procedure cPreferences.setPreferences (newData: handle; disposeOldData: boolean); begin if disposeOldData then disposeHandle(itsData); itsData := newData; end; { cPreferences.setPreferences } function cPreferences.updatePreferences: OSErr; var err: OSErr; numBytes: longint; begin err := SetFPos(itsRefNum, fsFromStart, 0); if err = noErr then begin numBytes := getHandleSize(itsData); err := FSWrite(itsRefNum, numBytes, itsData^); end; updatePreferences := err; end; { cPreferences.updatePreferences } end.