📄 contacts.c
字号:
// CH.2 The super-include for the Palm OS
#include <Pilot.h>
// CH.5 Added for the call to GrfSetState()
#include <Graffiti.h>
// CH.3 Our resource file
#include "Contacts_res.h"
// CH.4 Prototypes for our event handler functions
static Boolean contactDetailHandleEvent( EventPtr event );
static Boolean aboutHandleEvent( EventPtr event );
static Boolean enterTimeHandleEvent( EventPtr event );
static Boolean contactListHandleEvent( EventPtr event );
static Boolean menuEventHandler( EventPtr event );
// CH.4 Constants for ROM revision
#define ROM_VERSION_2 0x02003000
#define ROM_VERSION_MIN ROM_VERSION_2
// CH.5 Prototypes for utility functions
static void newRecord( void );
static VoidPtr getObject( FormPtr, Word );
static void setFields( void );
static void getFields( void );
static void setText( FieldPtr, CharPtr );
static void getText( FieldPtr, VoidPtr, Word );
static void setDateTrigger( void );
static void setTimeTrigger( void );
static void setTimeControls( void );
static Int sortFunc( CharPtr, CharPtr, Int );
static void drawTable( void );
static void drawCell( VoidPtr table, Word row, Word column,
RectanglePtr bounds );
static void initIndexes( void );
static void scrollIndexes( Int amount );
static UInt findIndex( UInt scrollValue );
static void find( Ptr params );
// CH.5 Our open database reference
static DmOpenRef contactsDB;
static ULong numRecords;
static UInt cursor;
static Boolean isDirty;
static VoidHand hrecord;
// CH.5 Constants that define the database record
#define DB_ID_START 0
#define DB_ID_SIZE (sizeof( ULong ))
#define DB_DATE_TIME_START (DB_ID_START +\
DB_ID_SIZE)
#define DB_DATE_TIME_SIZE (sizeof( DateTimeType ))
#define DB_FIRST_NAME_START (DB_DATE_TIME_START +\
DB_DATE_TIME_SIZE)
#define DB_FIRST_NAME_SIZE 16
#define DB_LAST_NAME_START (DB_FIRST_NAME_START +\
DB_FIRST_NAME_SIZE)
#define DB_LAST_NAME_SIZE 16
#define DB_PHONE_NUMBER_START (DB_LAST_NAME_START +\
DB_LAST_NAME_SIZE)
#define DB_PHONE_NUMBER_SIZE 16
#define DB_RECORD_SIZE (DB_PHONE_NUMBER_START +\
DB_PHONE_NUMBER_SIZE)
// CH.6 Storage for the record's date and time in expanded form
static DateTimeType dateTime;
static Word timeSelect;
#define NO_DATE 0
#define NO_TIME 0x7fff
// CH.7 The error exit macro
#define errorExit(alert) { ErrThrow( alert ); }
// CH.7 The sort order variable and constants
static Int sortBy;
// CH.7 NOTE: These items match the popup list entries!
#define SORTBY_DATE_TIME 0
#define SORTBY_FIRST_NAME 1
#define SORTBY_LAST_NAME 2
// CH.8 Table constants
#define TABLE_NUM_COLUMNS 3
#define TABLE_NUM_ROWS 11
#define TABLE_COLUMN_DATE 0
#define TABLE_COLUMN_TIME 1
#define TABLE_COLUMN_NAME 2
#define BLACK_UP_ARROW "\x01"
#define BLACK_DOWN_ARROW "\x02"
#define GRAY_UP_ARROW "\x03"
#define GRAY_DOWN_ARROW "\x04"
// CH.9 Category variables
static Word listCat = dmAllCategories; // CH.9 The current category ID
static Word detailCat; // CH.9 Category ID for details
static UInt tableIndex[TABLE_NUM_ROWS]; // CH.9 Record indexes for rows
// CH.9 Goto variable
static Boolean upStack;
// CH.2 The main entry point
DWord PilotMain( Word cmd, Ptr params, Word )
{
DWord romVersion; // CH.4 ROM version
LocalID dbID; // CH.9 Local ID of the database
UInt cardNum; // CH.9 Card number
LocalID appInfoID; // CH.9 Local ID of the app info block
VoidHand hAppInfo; // CH.9 Handle to the app info block
AppInfoPtr pAppInfo; // CH.9 Points to the app info block
FormPtr form; // CH.2 A pointer to our form structure
EventType event; // CH.2 Our event structure
Word error; // CH.3 Error word
// CH.4 Get the ROM version
romVersion = 0;
FtrGet( sysFtrCreator, sysFtrNumROMVersion, &romVersion );
// CH.4 If we are below our minimum acceptable ROM revision
if( romVersion < ROM_VERSION_MIN )
{
// CH.4 Display the alert
FrmAlert( LowROMVersionErrorAlert );
// CH.4 PalmOS 1.0 will continuously re-launch this app
// unless we switch to another safe one
if( romVersion < ROM_VERSION_2 )
{
AppLaunchWithCommand( sysFileCDefaultApp,
sysAppLaunchCmdNormalLaunch, NULL );
}
return( 0 );
}
// CH.9 Respond to launches
switch( cmd )
{
// CH.2 Normal launch
case sysAppLaunchCmdNormalLaunch:
break;
// CH.9 System find
case sysAppLaunchCmdFind:
find( params );
return( 0 );
// CH.9 Go to item from find
case sysAppLaunchCmdGoTo:
break;
// CH.2 We don't handle what's being asked for
default:
return( 0 );
}
// CH.5 Create a new database in case there isn't one
if( ((error = DmCreateDatabase( 0, "ContactsDB-PPGU", 'PPGU', 'ctct',
false )) != dmErrAlreadyExists) && (error != 0) )
{
// CH.5 Handle db creation error
FrmAlert( DBCreationErrorAlert );
return( 0 );
}
// CH.9 Open the database if it isn't already open
if( contactsDB == NULL )
{
contactsDB = DmOpenDatabaseByTypeCreator( 'ctct', 'PPGU',
dmModeReadWrite );
}
else
upStack = true;
// CH.9 Get the ID and card number
DmOpenDatabaseInfo( contactsDB, &dbID, NULL, NULL, &cardNum, NULL);
// CH.9 Get the app info pointer if any
DmDatabaseInfo( cardNum, dbID, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, &appInfoID, NULL, NULL, NULL );
// CH.9 If there is no application info block, create one
if( appInfoID == 0 )
{
// CH.9 Allocate an application info block
if( (hAppInfo = DmNewHandle( contactsDB,
sizeof( AppInfoType ) )) == NULL )
errorExit( MemoryErrorAlert );
// CH.9 Translate the handle to a local ID
appInfoID = MemHandleToLocalID( hAppInfo );
// CH.9 Set the application info block
DmSetDatabaseInfo( cardNum, dbID, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, &appInfoID, NULL, NULL, NULL );
// CH.9 Translate the local ID to a pointer
pAppInfo = MemLocalIDToLockedPtr( appInfoID, cardNum );
// CH.9 Clear it
DmSet( pAppInfo, 0, sizeof( AppInfoType ), 0 );
// CH.9 Initialize the categories
CategoryInitialize( pAppInfo, CategoryLabelsAppInfoStr );
// CH.9 Unlock the application info block
MemPtrUnlock( pAppInfo );
}
// CH.5 Get the number of records in the database
numRecords = DmNumRecords( contactsDB );
// CH.5 Initialize the record number
cursor = 0;
// CH.7 Choose our starting page
// CH.5 If there are no records, create one
if( numRecords == 0 )
{
newRecord();
FrmGotoForm( ContactDetailForm );
}
else
// CH.9 We are going to a particular record
if( cmd == sysAppLaunchCmdGoTo )
{
// CH.9 In case our app was running before the find
FrmCloseAllForms();
// CH.9 Point the cursor to the found item
cursor = ((GoToParamsPtr)params)->recordNum;
// CH.9 Go to the details page
FrmGotoForm( ContactDetailForm );
// CH.9 If we are running on top of ourselves,
// return to the original event loop
if( upStack )
{
upStack = false;
return( 0 );
}
}
else
// CH.7 Display the list
FrmGotoForm( ContactListForm );
// CH.7 Begin the try block
ErrTry {
// CH.2 Our event loop
do
{
// CH.2 Get the next event
EvtGetEvent( &event, -1 );
// CH.2 Handle system events
if( SysHandleEvent( &event ) )
continue;
// CH.3 Handle menu events
if( MenuHandleEvent( NULL, &event, &error ) )
continue;
// CH.4 Handle form load events
if( event.eType == frmLoadEvent )
{
// CH.4 Initialize our form
switch( event.data.frmLoad.formID )
{
// CH.4 Contact Detail form
case ContactDetailForm:
form = FrmInitForm( ContactDetailForm );
FrmSetEventHandler( form, contactDetailHandleEvent );
break;
// CH.4 About form
case AboutForm:
form = FrmInitForm( AboutForm );
FrmSetEventHandler( form, aboutHandleEvent );
break;
// CH.6 Enter Time form
case EnterTimeForm:
form = FrmInitForm( EnterTimeForm );
FrmSetEventHandler( form, enterTimeHandleEvent );
break;
// CH.7 Contact List form
case ContactListForm:
form = FrmInitForm( ContactListForm );
FrmSetEventHandler( form, contactListHandleEvent );
break;
}
FrmSetActiveForm( form );
}
// CH.2 Handle form events
FrmDispatchEvent( &event );
// CH.2 If it's a stop event, exit
} while( event.eType != appStopEvent );
// CH.7 End the try block and do the catch block
}
ErrCatch( errorAlert )
{
// CH.7 Display the appropriate alert
FrmAlert( errorAlert );
} ErrEndCatch
// CH.5 Close all open forms
FrmCloseAllForms();
// CH.5 Close the database
DmCloseDatabase( contactsDB );
// CH.2 We're done
return( 0 );
}
// CH.4 Our Contact Detail form handler function
static Boolean contactDetailHandleEvent( EventPtr event )
{
FormPtr form; // CH.3 A pointer to our form structure
VoidPtr precord; // CH.6 Points to a database record
Char catName[dmCategoryLength]; // CH.9 Category name
// CH.3 Get our form pointer
form = FrmGetActiveForm();
// CH.4 Parse events
switch( event->eType )
{
// CH.4 Form open event
case frmOpenEvent:
{
// CH.2 Draw the form
FrmDrawForm( form );
// CH.5 Draw the database fields
setFields();
}
break;
// CH.5 Form close event
case frmCloseEvent:
{
// CH.5 Store away any modified fields
getFields();
}
break;
// CH.5 Parse the button events
case ctlSelectEvent:
{
// CH.5 Store any field changes
getFields();
switch( event->data.ctlSelect.controlID )
{
// CH.5 First button
case ContactDetailFirstButton:
{
// CH.5 Set the cursor to the first record
if( cursor > 0 )
cursor = 0;
}
break;
// CH.5 Previous button
case ContactDetailPrevButton:
{
// CH.5 Move the cursor back one record
if( cursor > 0 )
cursor--;
}
break;
// CH.5 Next button
case ContactDetailNextButton:
{
// CH.5 Move the cursor up one record
if( cursor < (numRecords - 1) )
cursor++;
}
break;
// CH.5 Last button
case ContactDetailLastButton:
{
// CH.5 Move the cursor to the last record
if( cursor < (numRecords - 1) )
cursor = numRecords - 1;
}
break;
// CH.5 Delete button
case ContactDetailDeleteButton:
{
// CH.5 Remove the record from the database
DmRemoveRecord( contactsDB, cursor );
// CH.5 Decrease the number of records
numRecords--;
// CH.5 Place the cursor at the first record
cursor = 0;
// CH.5 If there are no records left, create one
if( numRecords == 0 )
newRecord();
}
break;
// CH.5 New button
case ContactDetailNewButton:
{
// CH.5 Create a new record
newRecord();
}
break;
// CH.7 Done button
case ContactDetailDoneButton:
{
// CH.7 Load the contact list
FrmGotoForm( ContactListForm );
}
break;
// CH.6 Date selector trigger
case ContactDetailDateSelTrigger:
{
// CH.6 Initialize the date if necessary
if( dateTime.year == NO_DATE )
{
DateTimeType currentDate;
// CH.6 Get the current date
TimSecondsToDateTime( TimGetSeconds(),
¤tDate );
// CH.6 Copy it
dateTime.year = currentDate.year;
dateTime.month = currentDate.month;
dateTime.day = currentDate.day;
}
// CH.6 Pop up the system date selection form
SelectDay( selectDayByDay, &(dateTime.month),
&(dateTime.day), &(dateTime.year),
"Enter Date" );
// CH.6 Get the record
hrecord = DmQueryRecord( contactsDB, cursor );
// CH.6 Lock it down
precord = MemHandleLock( hrecord );
// CH.6 Write the date time field
DmWrite( precord, DB_DATE_TIME_START, &dateTime,
sizeof( DateTimeType ) );
// CH.6 Unlock the record
MemHandleUnlock( hrecord );
// CH.6 Mark the record dirty
isDirty = true;
}
break;
// CH.6 Time selector trigger
case ContactDetailTimeSelTrigger:
{
// CH.6 Pop up our selection form
FrmPopupForm( EnterTimeForm );
}
break;
// CH.9 Catch a tap on the category trigger
case ContactDetailCategoryPopupPopTrigger:
{
UInt recAttrs; // CH.9 The record attribs
// CH.9 Palm OS will present the popup list for us.
CategorySelect( contactsDB, form,
ContactDetailCategoryPopupPopTrigger,
ContactDetailCategoryListList,
false, &detailCat, catName, 1, 0 );
// CH.9 Get the record attributes
DmRecordInfo( contactsDB, cursor, &recAttrs,
NULL, NULL );
// CH.9 Put in the category bits
recAttrs &= ~dmRecAttrCategoryMask;
recAttrs |= detailCat;
// CH.9 Set the record attributes
DmSetRecordInfo( contactsDB, cursor, &recAttrs,
NULL );
}
// CH.9 Set fields and return true in this case
setFields();
return( true );
}
// CH.5 Sync the current record to the fields
setFields();
}
break;
// CH.5 Respond to field tap
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -