⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 contacts.c

📁 CD_《Palm OS编程实践》
💻 C
📖 第 1 页 / 共 4 页
字号:
// 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(),
								&currentDate );
								
						// 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 + -