Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
MainWindow.c
/* |
File: MainWindow.c |
Description: |
routines for managing the main window. |
Author: JM |
Copyright: Copyright (c) 2003 Apple Computer, Inc. All rights reserved. |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
("Apple") in consideration of your agreement to the following terms, and your |
use, installation, modification or redistribution of this Apple software |
constitutes acceptance of these terms. If you do not agree with these terms, |
please do not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject |
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs |
copyrights in this original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or without |
modifications, in source and/or binary forms; provided that if you redistribute |
the Apple Software in its entirety and without modifications, you must retain |
this notice and the following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks or logos of |
Apple Computer, Inc. may be used to endorse or promote products derived from the |
Apple Software without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any patent rights that |
may be infringed by your derivative works or by other works in which the Apple |
Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Change History (most recent first): |
Fri, Aug 29, 2000 -- created |
*/ |
#include "MainWindow.h" |
#include "ScriptSupport.h" |
#include "MyScriptsGlue.h" |
#include "FinderCommentWindow.h" |
/* We use an AEDescList to contain the items that are displayed |
in the list in the main window. |
The scripts that construct this list create a list formatted |
as a list of two element lists (the first element being the name |
of a file/folder and the second being an alias referencing the |
file/folder). Here is the general format: |
{ |
{ name of item 1, alias to item 1 }, |
{ name of item 2, alias to item 2 }, |
... |
{ name of item n, alias to item n } |
} |
The handlers getfolderItems and getfinderselection create this |
list. They are defined in the file AddOnScripts.applescript. For |
more information, take a look at that file. |
In the databrowser, we use item id numbers numbered starting |
at 1, 2, 3, ..., n. These numbers also used as indexes into |
the list stored in this array. */ |
AEDescList gFolderItems; /* a list pairs (see above). */ |
Boolean gFolderItemsExists = false; /* does the list exist? */ |
/* DataBrowserDataCallback is a callback we defined for providing |
data to the data browser while it is drawing the list displayed |
in the main window. Essentially, this routine provides a translation |
function between data browser item id numbers and the strings we |
want to display in the list. Item id numbers are set up so they are |
indexes into the list stored in gFolderItems. */ |
static pascal OSStatus DataBrowserDataCallback(ControlRef browser, DataBrowserItemID itemID, |
DataBrowserPropertyID property, DataBrowserItemDataRef itemData, |
Boolean changeValue) { |
OSStatus err = noErr; |
switch ( property ) { |
case 'item': |
/* in interface builder we defined one column with the property |
id value of 'item'. Here we are being asked to either retrieve the |
string to be displayed for the itemID in the column identified by |
this property id. */ |
if ( changeValue ) { |
/* this would involve renaming the file. we don't want to do |
that here. */ |
err = errDataBrowserPropertyNotSupported; |
} else { |
CFStringRef text; |
AEKeyword theAEKeyword; |
AEDescList nthPair; |
AEDesc nthName; |
/* get the requested pair from the list of items. Here the itemID is |
used as the index. */ |
err = AEGetNthDesc( &gFolderItems, itemID, typeWildCard, &theAEKeyword, &nthPair ); |
if ( noErr == err ) { |
/* from the pair of items returned, we know that the first item in |
the pair will be the 'display name' of the item in the list. */ |
err = AEGetNthDesc( &nthPair, 1, typeWildCard, &theAEKeyword, &nthName); |
if ( noErr == err ) { |
/* convert the name into a string for the data browser to use */ |
err = AEDescToCFString( &nthName, &text ); |
if ( noErr == err ) { |
/* send the string to the data browser */ |
err = SetDataBrowserItemDataText( itemData, text ); |
/* the data browser makes a copy, so we can |
release our reference */ |
CFRelease(text); |
} |
/* done with the name descriptor */ |
AEDisposeDesc(&nthName); |
} |
/* done with the pair's descriptor */ |
AEDisposeDesc(&nthPair); |
} |
} |
break; |
/* the remainder of these are essentially for |
handling generic data browser inquiries and they're not |
essential for understanding the sample. comments included |
for the interested... */ |
case kDataBrowserItemIsActiveProperty: |
if ( ! changeValue ) /* is it active? yes */ |
err = SetDataBrowserItemDataBooleanValue( itemData, true); |
break; |
case kDataBrowserItemIsSelectableProperty: |
if ( ! changeValue ) /* can we select it? yes */ |
err = SetDataBrowserItemDataBooleanValue( itemData, true); |
break; |
case kDataBrowserContainerIsSortableProperty: |
case kDataBrowserItemIsEditableProperty: |
case kDataBrowserItemIsContainerProperty: |
if ( ! changeValue ) /* can we edit it, sort it, or put things in it? no */ |
err = SetDataBrowserItemDataBooleanValue( itemData, false); |
break; |
default: /* unrecognized property */ |
err = errDataBrowserPropertyNotSupported; |
break; |
} |
/* send result */ |
return err; |
} |
/* DataBrowserNotificationCallback is called by the data browser |
control to notify clients of changes in the state of the control. |
We are only interested in cases where the user double clicks |
on an item. In that case, we open the item that was clicked on |
and display the finder comment for editing in a finder comment window. */ |
static pascal void DataBrowserNotificationCallback( |
ControlRef browser, |
DataBrowserItemID item, |
DataBrowserItemNotification message) { |
if ( message == kDataBrowserItemDoubleClicked ) { |
AliasHandle localAlias; |
AEKeyword theAEKeyword; |
AEDescList nthPair; |
AEDesc nthName; |
OSStatus err; |
/* retrieve the nth pair from the list of items being displayed */ |
err = AEGetNthDesc( &gFolderItems, item, typeWildCard, &theAEKeyword, &nthPair ); |
if ( noErr == err ) { |
/* the second item in the pair is the alias record referencing |
the file on disk. let's get that one */ |
err = AEGetNthDesc( &nthPair, 2, typeWildCard, &theAEKeyword, &nthName); |
if ( noErr == err ) { |
/* convert the item into an alias record */ |
err = AEDescToAlias( &nthName, &localAlias ); |
if ( noErr == err ) { |
/* open a finder comment window to display the item. */ |
err = OpenFinderCommentWindow( localAlias ); |
/* done with the alias */ |
DisposeHandle((Handle) localAlias); |
} |
/* done with the alias descriptor. */ |
AEDisposeDesc(&nthName); |
} |
/* done with the pair descriptor */ |
AEDisposeDesc(&nthPair); |
} |
} |
} |
/* MainWindowEventHandler is the Carbon Event handler we install on our |
application's main window. Here we handle all of the events we are |
interested in that can occur for the main window. */ |
static pascal OSStatus MainWindowEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData) { |
OSStatus err, returnedResult; |
UInt32 eclass, ekind; |
/* set up locals */ |
eclass = GetEventClass(inEvent); |
ekind = GetEventKind(inEvent); |
/* default result */ |
returnedResult = eventNotHandledErr; |
/* dispatch the event */ |
if (eclass == kEventClassWindow && ekind == kEventWindowClose) { |
/* exit from RunApplicationEventLoop */ |
QuitApplicationEventLoop(); |
/* good to go */ |
returnedResult = noErr; |
} else if ( eclass == kEventClassCommand && ekind == kEventProcessCommand ) { |
HICommandExtended command; |
err = GetEventParameter( inEvent, kEventParamDirectObject, |
typeHICommand, NULL, sizeof(command), NULL, &command); |
if (err == noErr) { |
switch ( command.commandID ) { |
case 'SMSG': /* the "Show Message" button in the main window */ |
{ WindowRef window; |
ControlID controlID = { 'MESG', 0}; |
ControlRef control; |
CFStringRef theMessageString; |
/* we stored a reference to our window in |
the user data parameter, let's use that now... */ |
window = (WindowRef) inUserData; |
/* find the messaage text control */ |
err = GetControlByID( window, &controlID, &control ); |
if ( noErr == err ) { |
/* extract the message text from the control */ |
err = GetControlData( control, kControlEntireControl, |
kControlEditTextCFStringTag, sizeof(theMessageString), |
&theMessageString, NULL); |
if ( noErr == err ) { |
/* call the displaymessage script handler to go about |
displaying the message, interacting with the user, etc... */ |
script_displaymessage(theMessageString); |
/* done with the string now */ |
CFRelease(theMessageString); |
} |
} |
} |
/* we handled the event */ |
returnedResult = noErr; |
break; |
case 'GINF': /* the "Finder 'Get Info...' Comment..." button in the main window */ |
{ AliasHandle theFile; |
/* call the selectfile script to ask the user to select a file */ |
err = script_selectfile(CFSTR("Get the Finder comment for which file?"), &theFile); |
if ( noErr == err ) { |
/* open a window to display the file. */ |
err = OpenFinderCommentWindow(theFile); |
/* done with the alias */ |
DisposeHandle((Handle) theFile); |
} |
} |
/* we handled the event */ |
returnedResult = noErr; |
break; |
case 'FNDR': /* the 'Get Finder Selection' button in the main window */ |
case 'FOLD': /* The 'list folder...' button in the main window */ |
{ AEDescList newFolderItems; |
/* list a folder using one of our listing scripts. one uses |
the finder selection, the other prompts the user for a file. */ |
if ( 'FNDR' == command.commandID ) { |
/* use the finder selection */ |
err = script_callnamedhandler("getfinderselection", &newFolderItems); |
} else { |
/* prompt the user for a folder and list the items*/ |
err = script_getfolderitems(CFSTR("Select a folder to list."), &newFolderItems); |
} |
if ( noErr == err ) { |
WindowRef window; |
ControlID controlID = { 'LIST', 0 }; |
ControlRef control; |
long theCount; |
/* release the old list of items */ |
if ( gFolderItemsExists ) { |
AEDisposeDesc(&gFolderItems); |
} |
/* save the new items. */ |
gFolderItems = newFolderItems; |
gFolderItemsExists = true; |
/* we stored a reference to our window in |
the user data parameter, let's use that now... */ |
window = (WindowRef) inUserData; |
/* get the sibling 'list' control in the main window.*/ |
err = GetControlByID( window, &controlID, &control ); |
if ( noErr == err ) { |
/* remove all of the items currently displayed in |
the list. */ |
RemoveDataBrowserItems( control, kDataBrowserNoItem, |
0, NULL, kDataBrowserItemNoProperty); |
/* count the number of items in the list returned |
by our script. */ |
err = AECountItems(&gFolderItems, &theCount); |
if ( noErr == err) { |
/* add the new items to the data browser control. Worthy |
of note is the NULL value passed to the items parameter |
below. What this means to the data browser's AddDataBrowserItems |
routine is that it should automatically generate data item |
id numbers numbering them 1, 2, 3, ..., n. Coincidentally, |
item indexes used by the AEDescList accessing routines use those |
same numbers as indexes into the list. So, the data browser item |
id numbers will be used as indexes into the gFolderItems AEDescList |
when we want to access those items. */ |
err = AddDataBrowserItems( control, kDataBrowserNoItem, |
theCount, NULL, kDataBrowserItemNoProperty); |
} |
} |
} |
} |
/* we handled the event */ |
returnedResult = noErr; |
break; |
case 'SHOW': /* the 'display a file in the finder' button in the main window */ |
{ AliasHandle theFile; |
/* ask the user to select a file for display. */ |
err = script_selectfile(CFSTR("Display a file in the Finder."), &theFile); |
if ( noErr == err ) { |
/* call the script to display the file */ |
err = script_displayfile( theFile ); |
/* done with the alias */ |
DisposeHandle((Handle) theFile); |
} |
} |
/* we handled the event */ |
returnedResult = noErr; |
break; |
} |
} |
} |
return returnedResult; |
} |
/* OpenTheMainWindow does exactly what you may |
expect that it does if you were to use its name |
as a clue. */ |
OSStatus OpenTheMainWindow(void) { |
OSStatus err; |
IBNibRef nibRef; |
/* Create a Nib reference passing the name of the nib |
file (without the .nib extension) CreateNibReference |
only searches into the application bundle. */ |
err = CreateNibReference(CFSTR("main"), &nibRef); |
if ( noErr == err ) { |
WindowRef window; |
/* Then create a window. "MainWindow" is the name of the |
window object. This name is set in InterfaceBuilder when |
the nib is created. */ |
err = CreateWindowFromNib(nibRef, CFSTR("MainWindow"), &window); |
/* install our window's close handler */ |
if ( noErr == err ) { |
EventTypeSpec mainWindowCloseEvent[] = { |
{ kEventClassWindow, kEventWindowClose }, |
{ kEventClassCommand, kEventProcessCommand } }; |
/* Install a carbon event handler on the main window. NOTE: we store |
a copy of the window reference in the user data parameter so we can |
get a copy of it inside of our handler. */ |
err = InstallWindowEventHandler(window, NewEventHandlerUPP(MainWindowEventHandler), |
(sizeof(mainWindowCloseEvent)/sizeof(EventTypeSpec)), mainWindowCloseEvent, window, NULL); |
} |
/* The list that is being displayed in the window requires a |
few programmatic support routines to hook it up to the program. We'll |
install those routines now. */ |
if ( noErr == err ) { |
ControlID controlID = { 'LIST', 0 }; |
ControlRef control; |
DataBrowserCallbacks dataBrowserHooks; |
/* retrieve the list control from the window */ |
err = GetControlByID( window, &controlID, &control ); |
if ( noErr == err ) { |
/* initialize the callback structure to the default |
values. */ |
dataBrowserHooks.version = kDataBrowserLatestCallbacks; |
InitDataBrowserCallbacks(&dataBrowserHooks); |
/* the first hook is for providing strings displayed in the list. Essentially |
it translates indexes referencing items in the list into the list of items |
returned by our scripts. */ |
dataBrowserHooks.u.v1.itemDataCallback = NewDataBrowserItemDataUPP(DataBrowserDataCallback); |
/* the second is a notification routine we use for detecting double |
clicks. we use double clicks for opening finder comment editing windows |
for items in the list when they are double clicked on. */ |
dataBrowserHooks.u.v1.itemNotificationCallback = NewDataBrowserItemNotificationUPP(DataBrowserNotificationCallback); |
/* install the callbacks structure in the list control */ |
err = SetDataBrowserCallbacks(control, &dataBrowserHooks); |
} |
} |
/* The window was created hidden so show it. */ |
if ( noErr == err ) { |
ShowWindow( window ); |
} |
/* done with our nib file */ |
DisposeNibReference(nibRef); |
} |
/* we're done */ |
return err; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-09-04