contacts.c

来自「CD_《Palm OS编程实践》」· C语言 代码 · 共 1,566 行 · 第 1/3 页

C
1,566
字号
// 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 );

// 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.2 The main entry point
DWord PilotMain( Word cmd, Ptr, Word )
{
    DWord 		romVersion;	// CH.4 ROM version
	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.2 If this is not a normal launch, don't launch
	if( cmd != sysAppLaunchCmdNormalLaunch )
		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.5 Open the database
	contactsDB = DmOpenDatabaseByTypeCreator( 'ctct', 'PPGU',
			dmModeReadWrite );

	// 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
		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

	// 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.5 Sync the current record to the fields
			setFields();
		}
		break;
		
		// CH.5 Respond to field tap
		case fldEnterEvent:
			isDirty = true;
		break;
		
		// CH.3 Parse menu events
		case menuEvent:
			return( menuEventHandler( event ) );
		break;
	}

	// CH.2 We're done
	return( false );
}

// CH.4 Our About form event handler function
static Boolean aboutHandleEvent( EventPtr event )
{
	FormPtr		form;	// CH.4 A pointer to our form structure

	// CH.4 Get our form pointer
	form = FrmGetActiveForm();

	// CH.4 Respond to the Open event
	if( event->eType == frmOpenEvent )
	{
		// CH.4 Draw the form
		FrmDrawForm( form );
	}
	
	// CH.4 Return to the calling form
    if( event->eType == ctlSelectEvent )
    {
		FrmReturnToForm( 0 );
		
		// CH.4 Always return true in this case
		return( true );
	}
	
	// CH.4 We're done
	return( false );
}

// CH.6 Our Enter Time form event handler function
static Boolean enterTimeHandleEvent( EventPtr event )
{
	FormPtr				form;		// CH.6 A form structure pointer
	static DateTimeType	oldTime;	// CH.6 The original time

	// CH.6 Get our form pointer
	form = FrmGetActiveForm();

	// CH.6 Switch on the event
	switch( event->eType )
	{
		// CH.6 Initialize the form
		case frmOpenEvent:
		{
			// CH.6 Store the time value
			oldTime = dateTime;
			
			// CH.6 Draw it
			FrmDrawForm( form );
			
			// CH.6 Set the time controls
			setTimeControls();
		}
		break;
		
		// CH.6 If a button was repeated
		case ctlRepeatEvent:
		// CH.6 If a button was pushed
		case ctlSelectEvent:
		{
			Word	buttonID;	// CH.6 The ID of the button
		
			// CH.6 Set the ID
			buttonID = event->data.ctlSelect.controlID;
		
			// CH.6 Switch on button ID
			switch( buttonID )
			{
				// CH.6 Hours button
				case EnterTimeHoursPushButton:
				// CH.6 Minute Tens button
				case EnterTimeMinuteTensPushButton:
				// CH.6 Minute Ones button
				case EnterTimeMinuteOnesPushButton:
				{
					// CH.6 If no time was set
					if( dateTime.hour == NO_TIME )
					{
						// CH.6 Set the time to 12 PM
						dateTime.hour = 12;
						dateTime.minute = 0;
						
						// CH.6 Set the controls
						setTimeControls();
					}	
					
					// CH.6 Clear the old selection if any
					if( timeSelect )
						CtlSetValue( getObject( form, timeSelect ),
								false );
				
					// CH.6 Set the new selection
					CtlSetValue( getObject( form, buttonID ), true );
					timeSelect = buttonID;
				}	
				break;
				
				// CH.6 Up button
				case EnterTimeTimeUpRepeating:
				{
					// CH.6 If there's no time, do nothing
					if( dateTime.hour == NO_TIME )
						break;
					
					// CH.6 Based on what push button is selected
					switch( timeSelect )
					{
						// CH.6 Increase hours
						case EnterTimeHoursPushButton:
						{
							// CH.6 Increment hours
							dateTime.hour++;
							
							// CH.6 If it was 11 AM, make it 12 AM
							if( dateTime.hour == 12 )
								dateTime.hour = 0;
								
							// CH.6 If it was 11 PM, make it 12 PM
							if( dateTime.hour == 24 )
								dateTime.hour = 12;
						}
						break;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?