Modifications to StringLib. It now functions like the Unix version where we have all of the strings in a giant case statement instead of in resources. This is necessary for moving to Pro4 and reducing the number of resources in the Mac Navigator. git-svn-id: svn://10.0.0.236/trunk@11033 18797224-902f-48f8-a5cc-f745e15eee43
553 lines
15 KiB
C++
553 lines
15 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
// errmgr.cp, Mac front end ErrorManager
|
|
|
|
// Editorial comments:
|
|
//
|
|
// Viewing some of this code may make you scream in panic
|
|
// Don't try this at home
|
|
// Use only under medical supervision
|
|
|
|
#include "uerrmgr.h"
|
|
|
|
#include <UDesktop.h>
|
|
#include "uapp.h"
|
|
#include "PascalString.h"
|
|
#include "xpassert.h"
|
|
#include "macutil.h"
|
|
#include "resgui.h"
|
|
#include "xp_error.h"
|
|
#include "UTextBox.h"
|
|
#include "resdef.h"
|
|
#include "macfeprefs.h"
|
|
// Apple
|
|
#include <Notification.h>
|
|
#include <Resources.h>
|
|
#include <AppleEvents.h>
|
|
#include <Dialogs.h>
|
|
|
|
#include <Icons.h>
|
|
|
|
#include "libi18n.h"
|
|
|
|
static void InitializeStrings(); // Need proto to use before declaration
|
|
|
|
OSType ErrorManager::sAlertApp = emSignature;
|
|
|
|
// Converts an OSErr to appropriate string.
|
|
// Just prints the number for now, might do something more
|
|
// useful in the future
|
|
void ErrorManager::OSNumToStr(OSErr err, CStr255 &outString)
|
|
{
|
|
NumToString((long)err, outString);
|
|
}
|
|
|
|
// PrepareToInteract makes sure that this is the frontmost application.
|
|
// If Netscape is not in the foreground, it blinks the small icon in
|
|
// the menu bar until the user brings us to front
|
|
void ErrorManager::PrepareToInteract()
|
|
{
|
|
TryToInteract(10000000);
|
|
}
|
|
|
|
// TryToInteract tries to bring Netscape to foreground (like PrepareToInteract)
|
|
// If user does not bring Netscape to foreground in 900 seconds,
|
|
// it returns FALSE;
|
|
Boolean ErrorManager::TryToInteract(long wait)
|
|
{
|
|
ProcessSerialNumber netscapeProcess, frontProcess;
|
|
OSErr err = ::GetCurrentProcess(&netscapeProcess);
|
|
Boolean inFront = IsFrontApplication();
|
|
if (!inFront)
|
|
{
|
|
unsigned long start, currentTime;
|
|
::GetDateTime(&start);
|
|
currentTime = start;
|
|
NMRec nmRec;
|
|
Handle iconSuite;
|
|
err = ::GetIconSuite (&iconSuite, 128,svAllSmallData);
|
|
nmRec.qLink = 0;
|
|
nmRec.qType = nmType;
|
|
nmRec.nmMark = true;
|
|
nmRec.nmIcon = iconSuite;
|
|
nmRec.nmStr = NULL;
|
|
nmRec.nmSound = (Handle)-1;
|
|
nmRec.nmResp = NULL;
|
|
err = ::NMInstall(&nmRec); // Remove the call automatically
|
|
if (err == noErr)
|
|
{
|
|
while (!inFront && ((currentTime - start) < wait))
|
|
{
|
|
EventRecord event;
|
|
::WaitNextEvent(0, &event, 30, NULL);
|
|
::GetFrontProcess(&frontProcess);
|
|
::GetDateTime(¤tTime);
|
|
::SameProcess(&frontProcess, &netscapeProcess, &inFront);
|
|
}
|
|
::NMRemove(&nmRec);
|
|
}
|
|
#if defined(DEBUG) && defined(ALEKS)
|
|
XP_Abort();
|
|
#endif
|
|
UDesktop::Resume(); // Because the resume event gets eaten up by dialog box
|
|
// Now, process any update events, so that our windows get refreshed properly
|
|
EventRecord event;
|
|
while (::WaitNextEvent(updateEvt, &event, 1, NULL))
|
|
(CFrontApp::GetApplication())->DispatchEvent(event);
|
|
}
|
|
return inFront;
|
|
}
|
|
|
|
// Class that resizes the alert dialog
|
|
|
|
// Resizes
|
|
void ShrinkToFitAlertDialog(cstring & temp);
|
|
void ShrinkToFitAlertDialog(cstring & temp)
|
|
{
|
|
Handle ditl = ::GetResource('DITL', ALRT_PlainAlert);
|
|
StHandleLocker lock(ditl);
|
|
Handle alrt = ::GetResource('ALRT', ALRT_PlainAlert);
|
|
StHandleLocker lock2(alrt);
|
|
|
|
// ¥¥¥ WARNING ¥¥¥ <ftang>
|
|
// You need to consider the PAD byte after each string
|
|
#define IncludePadByte(a) (((a) & 1) ? ((a) +1) : (a))
|
|
|
|
// This ugliness happens because my pointer arithmetic was messed up otherwise
|
|
UInt32 tmp = (UInt32)*ditl;
|
|
Rect * okRect = (Rect*)(tmp + 0x6);
|
|
// Offset + length of the OK string
|
|
Rect * editRect = (Rect*)(tmp + 0x14 + IncludePadByte(*(uint8*)(tmp + 0xF)));
|
|
StTextState textState;
|
|
TextFont(0);
|
|
TextSize(12);
|
|
short height = UTextBox::TextBoxDialogHeight((char*)temp, temp.length(), editRect,
|
|
teForceLeft, 0);
|
|
if (height < 50) // Need to make place for the icon
|
|
height = 50;
|
|
editRect->bottom = editRect->top + height;
|
|
okRect->top = editRect->bottom + 8;
|
|
okRect->bottom = okRect->top + 20;
|
|
// Get the window resource
|
|
// Strange thing here: after ALRT is called for the first time,
|
|
// altrRect gets altered. Its top/left are strange (>30000)
|
|
// So I reset them, and everything seems to work
|
|
// I bet that the toolbox guys are storing alert state in these
|
|
Rect * alrtRect = (Rect*)*alrt;
|
|
alrtRect->top = 100;
|
|
alrtRect->bottom = alrtRect->top+ okRect->bottom + 8;
|
|
alrtRect->left = 185;
|
|
alrtRect->right = 577;
|
|
}
|
|
|
|
void ShrinkToFitYorNDialog(cstring & temp);
|
|
void ShrinkToFitYorNDialog(cstring & temp)
|
|
{
|
|
Handle ditl = ::GetResource('DITL', ALRT_YorNAlert);
|
|
StHandleLocker lock(ditl);
|
|
Handle alrt = ::GetResource('ALRT', ALRT_YorNAlert);
|
|
StHandleLocker lock2(alrt);
|
|
// This ugliness happens because my pointer arithmetic was messed up otherwise
|
|
UInt32 base = (UInt32)*ditl;
|
|
|
|
// ¥¥¥ WARNING ¥¥¥ <ftang>
|
|
// You need to consider the PAD byte after each string
|
|
|
|
Rect * yesRect = (Rect*)(base + 0x6);
|
|
UInt8 * yesLen = (UInt8 *)(base + 0xF);
|
|
|
|
Rect * noRect = (Rect*)(base + 0x14 + IncludePadByte(*yesLen));
|
|
UInt8 * noLen = (UInt8 *)(base + 0x1D + IncludePadByte(*yesLen));
|
|
Rect * editRect = (Rect*)(base + 0x22 + IncludePadByte(*yesLen) + IncludePadByte(*noLen));
|
|
StTextState textState;
|
|
TextFont(0);
|
|
TextSize(12);
|
|
short height = UTextBox::TextBoxDialogHeight((char*)temp, temp.length(), editRect,
|
|
teForceLeft, 0);
|
|
if (height < 50) // Need to make place for the icon
|
|
height = 50;
|
|
editRect->bottom = editRect->top + height;
|
|
yesRect->top = editRect->bottom + 8;
|
|
yesRect->bottom = yesRect->top + 20;
|
|
noRect->top = editRect->bottom + 8;
|
|
noRect->bottom = noRect->top + 20;
|
|
// Get the window resource
|
|
// Strange thing here: after ALRT is called for the first time,
|
|
// altrRect gets altered. Its top/left are strange (>30000)
|
|
// So I reset them, and everything seems to work
|
|
// I bet that the toolbox guys are storing alert state in these
|
|
Rect * alrtRect = (Rect*)*alrt;
|
|
alrtRect->top = 185;
|
|
alrtRect->bottom = alrtRect->top+ yesRect->bottom + 8;
|
|
alrtRect->left = 185;
|
|
alrtRect->right = 590;
|
|
}
|
|
|
|
// Displays a vanilla alert. All strings inside the alert are
|
|
// supplied by caller
|
|
void ErrorManager::PlainAlert(const CStr255& s1, const char * s2, const char * s3, const char * s4)
|
|
{
|
|
if (sAlertApp != emSignature)
|
|
return;
|
|
if (!TryToInteract(900)) // If we time out, go away
|
|
return;
|
|
CStr255 S1(s1);
|
|
CStr255 S2(s2);
|
|
CStr255 S3(s3);
|
|
CStr255 S4(s4);
|
|
ConvertCRtoLF(S1);
|
|
ConvertCRtoLF(S2);
|
|
ConvertCRtoLF(S3);
|
|
ConvertCRtoLF(S4);
|
|
ParamText(S1, S2, S3, S4);
|
|
cstring temp;
|
|
temp += s1;
|
|
temp += s2;
|
|
temp += s3;
|
|
temp += s4;
|
|
ShrinkToFitAlertDialog(temp);
|
|
UDesktop::Deactivate();
|
|
::CautionAlert(ALRT_PlainAlert, NULL);
|
|
UDesktop::Activate();
|
|
}
|
|
|
|
void ErrorManager::PlainAlert( short resID )
|
|
{
|
|
InitializeStrings();
|
|
|
|
if (sAlertApp != emSignature)
|
|
return;
|
|
|
|
CStr255 cstr[ 4 ];
|
|
StringHandle strings[ 4 ];
|
|
|
|
if ( !TryToInteract(900))
|
|
return;
|
|
|
|
for ( short i = 0; i <= 3; i++ )
|
|
{
|
|
strings[ i ] = GetString( resID + i );
|
|
if ( strings[ i ] )
|
|
cstr[ i ] = **( (CStr255**)strings[ i ] );
|
|
}
|
|
|
|
ParamText( cstr[ 0 ], cstr[ 1 ], cstr[ 2 ], cstr[ 3 ] );
|
|
cstring temp;
|
|
temp += cstr[ 0 ];
|
|
temp += cstr[ 1 ];
|
|
temp += cstr[ 2 ];
|
|
temp += cstr[ 3 ];
|
|
ShrinkToFitAlertDialog(temp); // Size the dalog
|
|
UDesktop::Deactivate();
|
|
::CautionAlert( ALRT_PlainAlert, NULL );
|
|
UDesktop::Activate();
|
|
}
|
|
|
|
// Displays a yes or no alert. All strings inside the alert are
|
|
// supplied by caller
|
|
Boolean ErrorManager::PlainConfirm(const char * s1, const char * s2, const char * s3, const char * s4)
|
|
{
|
|
if (sAlertApp != emSignature)
|
|
return FALSE;
|
|
|
|
if (!TryToInteract(900)) // If we time out, go away
|
|
return false;
|
|
CStr255 S1(s1);
|
|
CStr255 S2(s2);
|
|
CStr255 S3(s3);
|
|
CStr255 S4(s4);
|
|
ConvertCRtoLF(S1);
|
|
ConvertCRtoLF(S2);
|
|
ConvertCRtoLF(S3);
|
|
ConvertCRtoLF(S4);
|
|
|
|
// pkc (6/6/96) Hack to stuff s1 into CStr255's if it's the
|
|
// only string passed in.
|
|
if( S1.Length() < strlen(s1) && s2 == NULL )
|
|
{
|
|
int storedLength = S1.Length();
|
|
S2 += (s1 + storedLength);
|
|
ConvertCRtoLF(S2);
|
|
storedLength += S2.Length();
|
|
if( storedLength < strlen(s1) )
|
|
{
|
|
S3 += (s1 + storedLength);
|
|
ConvertCRtoLF(S3);
|
|
storedLength += S3.Length();
|
|
if( storedLength < strlen(s1) )
|
|
{
|
|
S4 += (s1 + storedLength);
|
|
ConvertCRtoLF(S4);
|
|
}
|
|
}
|
|
}
|
|
|
|
cstring temp;
|
|
temp += s1;
|
|
temp += s2;
|
|
temp += s3;
|
|
temp += s4;
|
|
ParamText(S1, S2, S3, S4);
|
|
ShrinkToFitYorNDialog(temp);
|
|
UDesktop::Deactivate();
|
|
int confirm = ::CautionAlert(ALRT_YorNAlert, NULL);
|
|
UDesktop::Activate();
|
|
return (confirm == 1);
|
|
}
|
|
|
|
void ErrorManager::ErrorNotify(OSErr err, const CStr255& message)
|
|
{
|
|
if (sAlertApp != emSignature)
|
|
return;
|
|
CStr255 errNum;
|
|
|
|
OSNumToStr(err, errNum);
|
|
PlainAlert(message, errNum);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
static void XPStringsNotFoundAlert()
|
|
//----------------------------------------------------------------------------------------
|
|
{
|
|
Str255 stringsFileName;
|
|
|
|
GetIndString(stringsFileName, 14000, 2); // From Bootstrap.rsrc.
|
|
ParamText(stringsFileName, NULL, NULL, NULL);
|
|
Alert (14003, NULL);
|
|
ExitToShell();
|
|
}
|
|
|
|
char * XP_GetBuiltinString(long i);
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
char * XP_GetString( int xpStringID )
|
|
//----------------------------------------------------------------------------------------
|
|
{
|
|
/*
|
|
// Add the offset (the one added by the perl script) but leave it as 32 bits, so
|
|
// we can check the range.
|
|
int32 resID = xpStringID + RES_OFFSET;
|
|
// Check for wraparound. If this happens, some xp person has started to use some
|
|
// range of values that we can't handle. See also my comment at the top of
|
|
// allxpstr.h - jrm 98/04/01.
|
|
if (resID < 128 || resID > SHRT_MAX )
|
|
{
|
|
XPStringsNotFoundAlert();
|
|
}
|
|
// BEWARE! This calls CString::operator char*() const,
|
|
// which uses a stack of 8 static strings into which the
|
|
// C string is copied, and you are returned a pointer to
|
|
// one of these buffers. This result is volatile; 8 more
|
|
// calls of this operator will overwrite the string pointed
|
|
// to by the char* returned.
|
|
// You should call XP_STRDUP or otherwise store the string if you
|
|
// want it to persist
|
|
return GetCString(resID);
|
|
*/
|
|
|
|
static char buf[128];
|
|
static char strclass[128];
|
|
char *ret;
|
|
char *type;
|
|
//XrmValue value;
|
|
|
|
/*
|
|
(void) PR_snprintf(buf, sizeof (buf),
|
|
"%s.strings.%d", fe_progclass, xpStringID + RES_OFFSET);
|
|
(void) PR_snprintf(strclass, sizeof (strclass),
|
|
"%s.Strings.Number", fe_progclass);
|
|
if (fe_display && ((database = XtDatabase(fe_display))) &&
|
|
XrmGetResource(database, buf, strclass, &type, &value))
|
|
{
|
|
return value.addr;
|
|
}
|
|
|
|
if ((ret = mcom_cmd_xfe_xfe_err_h_strings (i + RES_OFFSET)))
|
|
{
|
|
return ret;
|
|
}
|
|
*/
|
|
return XP_GetBuiltinString((long)xpStringID);
|
|
|
|
}
|
|
|
|
extern "C" char * mcom_include_merrors_i_strings (long);
|
|
extern "C" char * mcom_include_secerr_i_strings (long);
|
|
extern "C" char * mcom_include_sec_dialog_strings(long);
|
|
extern "C" char * mcom_include_sslerr_i_strings (long);
|
|
extern "C" char * mcom_include_xp_error_i_strings(long);
|
|
extern "C" char * mcom_include_xp_msg_i_strings (long);
|
|
|
|
char * XP_GetBuiltinString(long i);
|
|
//----------------------------------------------------------------------------------------
|
|
char *
|
|
XP_GetBuiltinString(long i)
|
|
//----------------------------------------------------------------------------------------
|
|
{
|
|
static char buf[128];
|
|
char *ret;
|
|
|
|
i += RES_OFFSET;
|
|
if
|
|
(
|
|
((ret = (mcom_include_merrors_i_strings (i)) )) ||
|
|
((ret = (mcom_include_secerr_i_strings (i)) )) ||
|
|
((ret = (mcom_include_sec_dialog_strings(i)) )) ||
|
|
((ret = (mcom_include_sslerr_i_strings (i)) )) ||
|
|
((ret = (mcom_include_xp_error_i_strings(i)) )) ||
|
|
((ret = (mcom_include_xp_msg_i_strings (i)) ))
|
|
)
|
|
{
|
|
return ret;
|
|
}
|
|
(void) sprintf(buf, "XP_GetBuiltinString: %d not found", i);
|
|
|
|
return buf;
|
|
}
|
|
|
|
//-----------------------------------
|
|
static void InitializeStrings()
|
|
//-----------------------------------
|
|
{
|
|
/*
|
|
static Boolean initialized = false;
|
|
if (initialized)
|
|
return;
|
|
|
|
initialized = true;
|
|
|
|
// Locate and load all the XP string resources
|
|
// in the "Netscape Resources" file
|
|
// inside the "Essential Files" folder.
|
|
|
|
FSSpec stringsFolderSpec;
|
|
|
|
if (FindGutsFolder(&stringsFolderSpec) != noErr)
|
|
XPStringsNotFoundAlert();
|
|
|
|
CInfoPBRec pb;
|
|
|
|
pb.dirInfo.ioNamePtr = stringsFolderSpec.name;
|
|
pb.dirInfo.ioVRefNum = stringsFolderSpec.vRefNum;
|
|
pb.dirInfo.ioFDirIndex = 0;
|
|
pb.dirInfo.ioDrDirID = stringsFolderSpec.parID;
|
|
|
|
if (PBGetCatInfoSync(&pb) != noErr)
|
|
XPStringsNotFoundAlert();
|
|
|
|
Str255 stringFileName;
|
|
GetIndString(stringFileName, 14000, 2);
|
|
|
|
FSSpec stringsFileSpec;
|
|
if (FSMakeFSSpec(pb.dirInfo.ioVRefNum, pb.dirInfo.ioDrDirID,
|
|
stringFileName, &stringsFileSpec) != noErr)
|
|
XPStringsNotFoundAlert();
|
|
|
|
short currentFileRefNum = CurResFile();
|
|
short stringsFileRefNum = FSpOpenResFile(&stringsFileSpec, fsCurPerm);
|
|
|
|
if (ResError() != noErr)
|
|
XPStringsNotFoundAlert();
|
|
|
|
MoveResourceMapBelowApp();
|
|
|
|
UseResFile(currentFileRefNum);
|
|
*/
|
|
} // InitializeStrings
|
|
|
|
void MoveResourceMapBelowApp()
|
|
{
|
|
#if PRAGMA_ALIGN_SUPPORTED
|
|
#pragma options align=mac68k
|
|
#else
|
|
#error "There'll probably be a bug here."
|
|
#endif
|
|
|
|
// Partial definition of "private" Resource Manager structure.
|
|
struct ResourceMap
|
|
{
|
|
char header[16];
|
|
ResourceMap **next;
|
|
short fileRefNum;
|
|
};
|
|
|
|
#if PRAGMA_ALIGN_SUPPORTED
|
|
#pragma options align=reset
|
|
#endif
|
|
|
|
short applicationRefNum = LMGetCurApRefNum();
|
|
ResourceMap **stringsFileMap = (ResourceMap **)LMGetTopMapHndl();
|
|
|
|
// Find the application's resource map.
|
|
for (ResourceMap **map = stringsFileMap; map; map = (*map)->next)
|
|
{
|
|
if ((*map)->fileRefNum == applicationRefNum)
|
|
{
|
|
// Move the strings file below the application
|
|
// in the current resource chain.
|
|
// (Kids, don't do this at home!)
|
|
ResourceMap **top = (*stringsFileMap)->next;
|
|
LMSetTopMapHndl((Handle)top);
|
|
LMSetCurMap((*top)->fileRefNum);
|
|
(*stringsFileMap)->next = (*map)->next;
|
|
(*map)->next = stringsFileMap;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------
|
|
char* GetCString( short resID )
|
|
//-----------------------------------
|
|
{
|
|
CStr255 pstring = GetPString(resID);
|
|
return (char*)pstring; // BEWARE! This calls CString::operator char*() const,
|
|
// which uses a stack of 8 static strings into which the
|
|
// C string is copied, and you are returned a pointer to
|
|
// one of these buffers. This result is volatile; 8 more
|
|
// calls of this operator will overwrite the strings pointed
|
|
// to by the char* returned.
|
|
} // GetCString
|
|
|
|
//-----------------------------------
|
|
CStr255 GetPString( ResIDT resID )
|
|
//-----------------------------------
|
|
{
|
|
InitializeStrings();
|
|
StringHandle sh = GetString( resID );
|
|
if (sh && *sh)
|
|
{
|
|
//StHandleLocker aLock((Handle)sh); // (probably) not necessary, hence removed
|
|
CStr255 fullResult(*sh);
|
|
return fullResult;
|
|
}
|
|
|
|
CStr255 emptyResult; // initialized to empty by constructor.
|
|
return emptyResult; // This copies the string to the caller's string.
|
|
} // GetPString
|
|
|
|
char * INTL_ResourceCharSet(void)
|
|
{
|
|
char *cbuf;
|
|
cbuf = (char *)GetCString(CHARSET_RESID);
|
|
if (cbuf[0] == '\0')
|
|
return "x-mac-roman";
|
|
return cbuf;
|
|
}
|