📄 addresslookup.c
字号:
/******************************************************************************
*
* Copyright (c) 1995-2003 PalmSource, Inc. All rights reserved.
*
* File: AddressLookup.c
*
* Release: Palm OS 5 SDK (68K) R3.
*
* Description:
* This is the Address Book's Lookup module. This module
* handles looking up address book information for other apps.
*
*****************************************************************************/
#include <ErrorMgr.h>
#include <SoundMgr.h>
#include <StringMgr.h>
#include <TraceMgr.h>
#include <PalmUtils.h>
#include "AddressLookup.h"
#include "AddressDB.h"
#include "AddrTools.h"
#include "AddressRsc.h"
#include "AddrDefines.h"
/***********************************************************************
*
* Defines
*
***********************************************************************/
// Address lookup table columns
#define field1Column 0
#define field2Column 1
/***********************************************************************
*
* Internal Functions
*
***********************************************************************/
static Boolean PrvLookupViewHandleEvent (LookupVariablesPtr vars);
static void PrvLookupViewInit (LookupVariablesPtr vars);
static void PrvLookupDrawRecordFields (LookupVariablesPtr vars, AddrDBRecordPtr record, Int16 field, RectanglePtr bounds, WChar * phoneLabelLetters);
static void PrvLookupViewDrawRecord (void * table, Int16 row, Int16 column, RectanglePtr bounds);
static void PrvLookupViewUpdateScrollButtons (LookupVariablesPtr vars);
static void PrvLookupLoadTable (LookupVariablesPtr vars);
static void PrvLookupViewScroll (LookupVariablesPtr vars, WinDirectionType direction, Boolean oneLine);
static void PrvLookupViewSelectRecord (LookupVariablesPtr vars, UInt16 recordNum, UInt16 phoneNum);
static Boolean PrvLookupViewLookupString (LookupVariablesPtr vars, EventType * event);
static void PrvLookupClearLookupString ();
static Boolean PrvLookupViewUseSelection (LookupVariablesPtr vars);
static AddressFields PrvLookupFindPhoneField (LookupVariablesPtr vars, AddrDBRecordPtr recordP, AddressLookupFields lookupField, UInt16 phoneNum);
static Char* PrvLookupResizeResultString (MemHandle resultStringH, UInt16 newSize);
static MemHandle PrvLookupCreateResultString (LookupVariablesPtr vars, UInt16 recordNum, UInt16 phoneNum);
/***********************************************************************
*
* FUNCTION: Lookup
*
* DESCRIPTION: Present a list of records for the user to select and return
* a string formatted to include information from the selected record.
*
* PARAMETERS: params - address lookup launch command parameters
*
* RETURNED: nothing
* The params will contain a string for the matching record.
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* Roger 7/1/96 Initial Revision
* meg 2/3/99 added beep param to vars struct...default to true
* peter 09/20/00 Disable attention indicator because title is custom.
***********************************************************************/
void Lookup(AddrLookupParamsType * params)
{
Err err;
DmOpenRef dbP;
AddrAppInfoPtr appInfoPtr;
UInt16 cardNo=0;
LocalID dbID;
DmSearchStateType searchState;
FormPtr frm;
FormPtr originalForm;
LookupVariablesType vars;
Boolean uniqueMatch;
Boolean completeMatch;
UInt16 mode;
TraceOutput(TL(appErrorClass,"Lookup() - title = %s, pasteButtonText = %s, lookupString = %s, field1 = %hu, field2 = %hu, field2Optional = %hu, userShouldInteract = %hu, formatStringP = %s, resultStringH = %lu, uniqueID = %lu", params->title, params->pasteButtonText, params->lookupString, params->field1, params->field2, params->field2Optional, params->userShouldInteract, params->formatStringP, params->resultStringH, params->uniqueID));
// Check the parameters
ErrFatalDisplayIf(params->field1 > addrLookupListPhone &&
params->field1 != addrLookupNoField, "Bad Lookup request - field1");
ErrFatalDisplayIf(params->field2 > addrLookupListPhone &&
params->field2 != addrLookupNoField, "Bad Lookup request - field2");
// Find the application's data file.
err = DmGetNextDatabaseByTypeCreator (true, &searchState, addrDBType,
sysFileCAddress, true, &cardNo, &dbID);
if (err)
{
params->resultStringH = 0;
return;
}
// Obey the secret records setting. Also, we only need to
// read from the database.
if (PrefGetPreference(prefHidePrivateRecordsV33))
mode = dmModeReadOnly;
else
mode = dmModeReadOnly | dmModeShowSecret;
// Open the address database.
dbP = DmOpenDatabase(cardNo, dbID, mode);
if (! dbP)
{
params->resultStringH = 0;
params->uniqueID = 0;
return;
}
// Initialize some of the lookup variables (those needed)
vars.params = params;
vars.dbP = dbP;
vars.beepOnFail = true;
// Find how the database is sorted.
appInfoPtr = (AddrAppInfoPtr) AddrDBAppInfoGetPtr(dbP);
vars.sortByCompany = appInfoPtr->misc.sortByCompany;
ToolsInitPhoneLabelLetters(appInfoPtr, vars.phoneLabelLetters);
MemPtrUnlock(appInfoPtr);
// Set the mappings from AddressLookupFields to AddressFields. It is
// necessary to initialize the mappings at runtime because static
// global variables are not available to this launch code routine.
vars.lookupFieldMap[addrLookupName] = name;
vars.lookupFieldMap[addrLookupFirstName] = firstName;
vars.lookupFieldMap[addrLookupCompany] = company;
vars.lookupFieldMap[addrLookupAddress] = address;
vars.lookupFieldMap[addrLookupCity] = city;
vars.lookupFieldMap[addrLookupState] = state;
vars.lookupFieldMap[addrLookupZipCode] = zipCode;
vars.lookupFieldMap[addrLookupCountry] = country;
vars.lookupFieldMap[addrLookupTitle] = title;
vars.lookupFieldMap[addrLookupCustom1] = custom1;
vars.lookupFieldMap[addrLookupCustom2] = custom2;
vars.lookupFieldMap[addrLookupCustom3] = custom3;
vars.lookupFieldMap[addrLookupCustom4] = custom4;
vars.lookupFieldMap[addrLookupNote] = note;
// Check to see if the lookup string is sufficient for a unique match.
// If so we skip presenting the user a lookup dialog and just use the match.
AddrDBLookupLookupString(vars.dbP, params->lookupString, vars.sortByCompany,
vars.params->field1, vars.params->field2, &vars.currentRecord, &vars.currentPhone,
vars.lookupFieldMap, &completeMatch, &uniqueMatch);
if (completeMatch && uniqueMatch)
{
PrvLookupCreateResultString(&vars, vars.currentRecord, vars.currentPhone + firstPhoneField);
goto Exit;
}
// If the user isn't allowed to select a record then return without
// a match.
if (!params->userShouldInteract)
{
params->resultStringH = 0;
params->uniqueID = 0;
goto Exit;
}
// Initialize more of the lookup variables
vars.currentRecord = noRecord;
vars.currentPhone = 0;
vars.topVisibleRecord = 0;
vars.topVisibleRecordPhone = 0;
vars.hideSecretRecords = PrefGetPreference(prefHidePrivateRecordsV33);
// Custom title doesn't support attention indicator.
// Disable indicator before switching forms.
AttnIndicatorEnable(false);
// Remember the original form
originalForm = FrmGetActiveForm();
// Initialize the dialog.
frm = FrmInitForm (LookupView);
vars.frm = frm;
// Set the title
if (params->title)
FrmSetTitle(frm, params->title);
// Set the paste button
if (params->pasteButtonText)
CtlSetLabel (FrmGetObjectPtr (frm, FrmGetObjectIndex (frm, LookupPasteButton)), params->pasteButtonText);
FrmSetActiveForm (frm);
PrvLookupViewInit (&vars);
// Enter the lookup string
if (params->lookupString && *params->lookupString != '\0')
{
FldInsert (FrmGetObjectPtr (frm, FrmGetObjectIndex (frm, LookupLookupField)), params->lookupString, StrLen(params->lookupString));
PrvLookupViewLookupString(&vars, NULL);
}
FrmDrawForm (frm);
FrmSetFocus (frm, FrmGetObjectIndex (frm, LookupLookupField));
// Handle events until the user picks a record or cancels
if (PrvLookupViewHandleEvent (&vars))
{
PrvLookupCreateResultString(&vars, vars.currentRecord, vars.currentPhone);
}
else
{
params->resultStringH = 0;
params->uniqueID = 0;
}
AttnIndicatorEnable(true); // Custom title doesn't support attention indicator.
FrmSetFocus (frm, noFocus);
FrmEraseForm (frm);
FrmDeleteForm (frm);
FrmSetActiveForm (originalForm);
Exit:
DmCloseDatabase (dbP);
}
#pragma mark -
/***********************************************************************
*
* FUNCTION: PrvLookupViewHandleEvent
*
* DESCRIPTION: This is the event handler for the "Lookup View"
* of the Address Book application.
*
* PARAMETERS: vars - variables used by the lookup code.
*
* RETURNED: true if a record was selected and false if not.
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* Roger 7/8/96 Initial Revision
* CSS 06/22/99 Standardized keyDownEvent handling
* (TxtCharIsHardKey, commandKeyMask, etc.)
*
***********************************************************************/
Boolean PrvLookupViewHandleEvent (LookupVariablesPtr vars)
{
EventType event;
Boolean handled;
while (true)
{
EvtGetEvent (&event, evtWaitForever);
// Cancel if something is going to switch apps.
if ( (event.eType == keyDownEvent)
&& (!TxtCharIsHardKey( event.data.keyDown.modifiers, event.data.keyDown.chr))
&& (EvtKeydownIsVirtual(&event))
&& (event.data.keyDown.chr == vchrFind))
{
EvtAddEventToQueue(&event);
return false;
}
if (SysHandleEvent (&event))
continue;
handled = false;
// Clear the lookup string because the user is selecting an item.
if (event.eType == appStopEvent)
{
EvtAddEventToQueue(&event);
return false;
}
else if (event.eType == tblSelectEvent)
{
// Doing the next call sends a fldChangedEvent which remove's the
// table's selection. Set a flag to not handle the event.
PrvLookupClearLookupString ();
vars->ignoreEmptyLookupField = true;
handled = true;
}
else if (event.eType == ctlSelectEvent)
{
if (event.data.ctlSelect.controlID == LookupPasteButton)
return PrvLookupViewUseSelection(vars);
else if (event.data.ctlSelect.controlID == LookupCancelButton)
return false;
}
else if (event.eType == ctlRepeatEvent)
{
if (event.data.ctlRepeat.controlID == LookupUpButton)
{
PrvLookupViewScroll (vars, winUp, false);
PrvLookupClearLookupString ();
// leave unhandled so the buttons can repeat
}
else if (event.data.ctlRepeat.controlID == LookupDownButton)
{
PrvLookupViewScroll (vars, winDown, false);
PrvLookupClearLookupString ();
// leave unhandled so the buttons can repeat
}
}
else if (event.eType == keyDownEvent)
{
if (TxtCharIsHardKey(event.data.keyDown.modifiers, event.data.keyDown.chr))
{
// SysHandleEvent saw these keys and is now switching apps.
// Leave the Lookup function.
return false;
}
else if (EvtKeydownIsVirtual(&event))
{
if (event.data.keyDown.chr == vchrPageUp)
{
PrvLookupViewScroll (vars, winUp, false);
PrvLookupClearLookupString ();
handled = true;
}
else if (event.data.keyDown.chr == vchrPageDown)
{
PrvLookupViewScroll (vars, winDown, false);
PrvLookupClearLookupString ();
handled = true;
}
else
{
handled = false;
}
}
else if (event.data.keyDown.chr == chrLineFeed)
{
return PrvLookupViewUseSelection(vars);
}
else
{
//user entered a new char...beep if it's not valid
vars->beepOnFail = true;
handled = PrvLookupViewLookupString(vars, &event);
// If the field becomes empty, handle it.
vars->ignoreEmptyLookupField = false;
}
}
else if (event.eType == fldChangedEvent)
{
if (!(vars->ignoreEmptyLookupField &&
FldGetTextLength(FrmGetObjectPtr (vars->frm,
FrmGetObjectIndex(vars->frm, LookupLookupField))) == 0))
{
// dont set the beep...this way, if the calling app sent in a multiple char
// string, we only beep once even if we will remove all chars from the lookup field
PrvLookupViewLookupString(vars, NULL);
}
vars->ignoreEmptyLookupField = false;
handled = true;
}
// Check if the form can handle the event
if (!handled)
FrmHandleEvent (vars->frm, &event);
}
}
/***********************************************************************
*
* FUNCTION: PrvLookupViewInit
*
* DESCRIPTION: This routine initializes the "Lookup View" of the
* Address application.
*
* PARAMETERS: vars - variables used by the lookup code.
*
* RETURNED: true if the event has handle and should not be passed
* to a higher level handler.
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* Roger 7/9/96 Initial Revision
*
***********************************************************************/
void PrvLookupViewInit (LookupVariablesPtr vars)
{
UInt16 row;
UInt16 rowsInTable;
TablePtr table;
RectangleType bounds;
// Initialize the address list table.
table = FrmGetObjectPtr (vars->frm, FrmGetObjectIndex (vars->frm, LookupTable));
rowsInTable = TblGetNumberOfRows (table);
for (row = 0; row < rowsInTable; row++)
{
TblSetItemStyle (table, row, field1Column, customTableItem);
TblSetRowUsable (table, row, false);
}
TblSetColumnUsable (table, 0, true);
// Set the callback routine that will draw the records.
TblSetCustomDrawProcedure (table, field1Column, PrvLookupViewDrawRecord);
// Load records into the address list.
PrvLookupLoadTable (vars);
// Turn on the cursor in the lookup field.
// FrmSetFocus(vars->frm, FrmGetObjectIndex (vars->frm, LookupLookupField));
// Set the bounds of the title, so that the title will draw across the
// entire display.
FrmGetFormBounds(vars->frm, &bounds);
// Note: '0' should be FrmGetObjectIndex (vars->frm, LookupTitle), but that fails
// because frmTitleObjects do not have the resource ID stored in them.
FrmSetObjectBounds (vars->frm, 0, &bounds);
// Respond to an empty lookup field.
vars->ignoreEmptyLookupField = false;
}
/***********************************************************************
*
* FUNCTION: PrvLookupDrawRecordFields
*
* DESCRIPTION: Draws the name and phone number (plus which phone)
* within the screen bounds passed.
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -