gecko-dev/cmd/macfe/gui/macutil.cp
1998-09-29 17:28:06 +00:00

2032 lines
52 KiB
C++
Raw Blame History

/* -*- 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.
*/
/***********************************************************************************
* macutil.cp
*
* Various mac utility routines
*
***********************************************************************************/
#include <stdarg.h>
#include <Traps.h>
#include <LPlaceHolder.h>
#include <LHandleStream.h>
//#include <LTextEngine.h>
#include "macutil.h"
#include "resgui.h"
#include "uprefd.h"
#include "ufilemgr.h"
#include "uerrmgr.h"
#include "xp.h"
#include "cstring.h"
#include "xpassert.h"
#include "xp_trace.h"
#include "macgui.h"
#include "prefapi.h"
#include "MoreDesktopMgr.h"
extern "C" {
#include "asyncCursors.h"
}
#ifndef MOZ_NGLAYOUT
#include "CSimpleTextView.h"
#endif
#include "mfinder.h" // needed for workaround function to bug in Apple's
// ::TruncText and ::TruncString - andrewb 6/20/97
#include "MoreMixedMode.h"
#include "PascalString.h"
/*-----------------------------------------------------------------------------
Layout Utilities
-----------------------------------------------------------------------------*/
// Another mlanett special
static void GetImageRect( LView* view, SPoint32* topLeft, SPoint32* botRight );
static void GetImageRect( LView* view, SPoint32* topLeft, SPoint32* botRight )
{
/*
Return the visible image of this view.
*/
SPoint32 frameLocation;
SDimension16 frameSize;
SPoint32 imageLocation;
view->GetFrameLocation( frameLocation );
view->GetFrameSize( frameSize );
view->GetImageLocation( imageLocation );
// convert local rectangle to image rectangle
topLeft->h = frameLocation.h - imageLocation.h; // frameLocation.h - portOrigin.h - imageLocation.h;
botRight->h = topLeft->h + frameSize.width;
topLeft->v = frameLocation.v - imageLocation.v; // frameLocation.v - portOrigin.v - imageLocation.v;
botRight->v = topLeft->v + frameSize.height;
}
void RevealInImage( LView* view, SPoint32 selTopLeft, SPoint32 selBotRight )
{
/*
Scroll the minimum amount necessary to reveal this image rectangle.
In this diagram, the selection is scrolled above the visible rectangle.
Therefore selection-top is less than image-top, so we need to scroll
down by above-amount.
/---\
/---| |
| \---/
v
/--------------\
| |
| |
| |
| |
\--------------/
*/
SPoint32 iTopLeft;
SPoint32 iBotRight;
GetImageRect( view, &iTopLeft, &iBotRight );
Int32 aboveAmount = selTopLeft.v - 20 - iTopLeft.v;
Int32 belowAmount = selTopLeft.v + 20 - iTopLeft.v;
Int32 leftAmount = selTopLeft.h - iTopLeft.h;
Int32 rightAmount = selBotRight.h - iBotRight.h;
if ( aboveAmount < 0 )
view->ScrollImageBy( 0, aboveAmount, TRUE );
else if ( ( selBotRight.v - iBotRight.v ) > 0 )
{
// don't scroll the top off!
// belowAmount and aboveAmount are negative
// belowAmount must be (absolute) less than aboveAmount
view->ScrollImageBy( 0, belowAmount > aboveAmount ? aboveAmount : belowAmount, TRUE );
}
if ( leftAmount < 0 )
view->ScrollImageBy( leftAmount, 0, TRUE );
else if ( rightAmount > 0 )
{
// don't scroll the left off!
// belowAmount and leftAmount are negative
// belowAmount must be (absolute) less than aboveAmount
view->ScrollImageBy( rightAmount > leftAmount? leftAmount: rightAmount, 0, TRUE );
}
}
Boolean TooDifferent( const Point& a, const Point& b )
{
return abs( b.h - a.h ) >= MOUSE_HYSTERESIS || abs( b.v - a.v ) >= MOUSE_HYSTERESIS;
}
short WaitForMouseAction( const Point& initial, long clickStart, long delay )
{
Point current;
long now;
while ( ::StillDown() )
{
::GetMouse( &current );
if ( TooDifferent( initial, current ) )
return MOUSE_DRAGGING;
now = ::TickCount();
if ( abs( now - clickStart ) > delay)
return MOUSE_TIMEOUT;
}
return MOUSE_UP_EARLY;
}
int // offset
CalcCurrentSelected (lo_FormElementSelectData * selectData, Boolean fromDefaults)
{
int offset = 0;
lo_FormElementOptionData * optionData;
PA_LOCK(optionData, lo_FormElementOptionData *, selectData->options);
for (int i=0; i<selectData->option_cnt; i++) {
char * itemName = NULL;
PA_LOCK(itemName, char*, optionData[i].text_value);
if (fromDefaults) {
if (optionData[i].def_selected) {
offset = i;
break;
}
}
else {
if (optionData[i].selected) {
offset = i;
break;
}
}
PA_UNLOCK(optionData[i].text_value);
}
PA_UNLOCK(selectData->options);
return offset;
}
/*-----------------------------------------------------------------------------
Generic Utilities
-----------------------------------------------------------------------------*/
Rect CenterInRect( Point thing, Rect destSpace )
{
Point destSize;
Point centeredSize;
Rect centeredThing;
destSize.h = destSpace.right - destSpace.left;
destSize.v = destSpace.bottom - destSpace.top;
centeredSize.h = MIN( destSize.h, thing.h );
centeredSize.v = MIN( destSize.v, thing.v );
centeredThing.left = destSpace.left + ( destSize.h - centeredSize.h ) / 2;
centeredThing.top = destSpace.top + ( destSize.v - centeredSize.v ) / 2;
centeredThing.right = centeredThing.left + centeredSize.h;
centeredThing.bottom = centeredThing.top + centeredSize.v;
return centeredThing;
}
/*-----------------------------------------------------------------------------
String Copying
-----------------------------------------------------------------------------*/
unsigned char* CopyString( unsigned char* destination, const unsigned char* source )
{
BlockMove (source, destination, source[0]+1);
return destination;
}
unsigned char* CopyString( unsigned char* destination, const char* source )
{
destination[0] = strlen (source);
BlockMove (source, destination + 1, destination[0]);
return destination;
}
char* CopyString( char* destination, const unsigned char* source )
{
BlockMove (source + 1, destination, source[0]);
destination[source[0]] = 0;
return destination;
}
char* CopyString( char* destination, const char* source )
{
register int length = strlen (source);
BlockMove (source, destination, length + 1);
return destination;
}
void CopyAlloc(char ** destination, StringPtr source)
{
// NET_SACopy frees a non-null destination itself
//if (*destination != NULL)
// XP_FREE(*destination);
p2cstr(source);
// We don't really want to delete any existing storage for destination so borrow
// some code from NET_SACopy and skip the XP_FREE of destination
//NET_SACopy(destination, (char*)source);
if (! source)
{
*destination = NULL;
}
else
{
*destination = (char *) XP_ALLOC (XP_STRLEN((const char *)source) + 1);
if (*destination != NULL)
XP_STRCPY (*destination, (const char *)source);
}
c2pstr((char*)source);
}
// Takes colons out of a string
void StripColons( CStr31& fileName )
{
short count;
for ( count = 1; count <= fileName.Length(); count++ )
if ( fileName[count] == ':' )
fileName[count] = ' ';
}
// strips single instances of ch from the given string.
// If ch appears twice in a row, the second one is not removed.
void StripChar( CStr255& str, char ch )
{
int len = str.Length();
for (short i = 1; i <= len; i++)
if (str[i] == ch) {
BlockMoveData(&str[i + 1], &str[i], len - i);
i++;
len -= 1;
}
str[0] = len;
}
// <20> Takes a string of text (dragged/pasted), and turns
// it into a URL (strips CR, whitespace preceeding/trailing <>
void CleanUpTextToURL(char* text)
{
if (text == NULL)
return;
long len = XP_STRLEN(text);
int i=0;
if (text[0] == '<') // Swallow the surrounding '<' and '>'
::BlockMoveData(&text[1], &text[0], len);
while (text[i] != 0) // Loop till whitespace
{
if (XP_IS_SPACE(text[i]))
break;
i++;
}
if (text[i-1] == '>') // Swallow the ending '>'
i--;
text[i] = 0;
}
void CleanUpLocationString (CStr255 & url)
{
// Strips spaces & returns at end of url (happens often
// when you paste into url box)
int last;
while ((last = url.Length()) != 0) {
if (url[last] == '\n' || url[last] == ' ' || url[last] == '\r')
url.Length()--;
else break;
}
}
// TRUE if the key is down. Bypasses the event loop
Boolean IsThisKeyDown(const UInt8 theKey)
{
KeyMap map;
GetKeys(map);
return ((*((UInt8 *)map + (theKey >> 3)) >> (theKey & 7)) & 1) != 0;
} // IsThisKeyDown - don's improved non-union (as in struct) version
// A mess that figures out if cmd-. was pressed
/* Borrowed from tech note 263 */
#define kMaskModifiers 0xFE00 // we need the modifiers without the
// command key for KeyTrans
#define kMaskVirtualKey 0x0000FF00 // get virtual key from event message
// for KeyTrans
#define kUpKeyMask 0x0080
#define kShiftWord 8 // we shift the virtual key to mask it
// into the keyCode for KeyTrans
#define kMaskASCII1 0x00FF0000 // get the key out of the ASCII1 byte
#define kMaskASCII2 0x000000FF // get the key out of the ASCII2 byte
#define kPeriod 0x2E // ascii for a period
Boolean CmdPeriod()
{
EvQElPtr eventQ = (EvQElPtr)LMGetEventQueue()->qHead;
while (eventQ != NULL)
{
EventRecord * theEvent = (EventRecord *)&eventQ->evtQWhat;
UInt16 keyCode;
UInt32 state;
long virtualKey, keyInfo, lowChar, highChar, keyCId;
Handle hKCHR;
Ptr KCHRPtr;
if (((*theEvent).what == keyDown) || ((*theEvent).what == autoKey)) {
// see if the command key is down. If it is, find out the ASCII
// equivalent for the accompanying key.
if ((*theEvent).modifiers & cmdKey ) {
virtualKey = ((*theEvent).message & kMaskVirtualKey) >> kShiftWord;
// And out the command key and Or in the virtualKey
keyCode = short(((*theEvent).modifiers & kMaskModifiers) | virtualKey);
state = 0;
hKCHR = nil; /* set this to nil before starting */
KCHRPtr = (Ptr)GetScriptManagerVariable(smKCHRCache);
if ( !KCHRPtr ) {
keyCId = ::GetScriptVariable(short(GetScriptManagerVariable(smKeyScript)), smScriptKeys);
hKCHR = GetResource('KCHR',short(keyCId));
KCHRPtr = *hKCHR;
}
if (KCHRPtr) {
keyInfo = KeyTranslate(KCHRPtr, keyCode, &state);
if (hKCHR)
ReleaseResource(hKCHR);
} else
keyInfo = (*theEvent).message;
lowChar = keyInfo & kMaskASCII2;
highChar = (keyInfo & kMaskASCII1) >> 16;
if (lowChar == kPeriod || highChar == kPeriod)
return TRUE;
} // end the command key is down
} // end key down event
eventQ = (EvQElPtr)eventQ->qLink;
}
return FALSE;
}
// Sets button state and redraws it
void SetEnable( LPane* button, Boolean enable )
{
if ( !button->IsEnabled() && enable )
button->Enable();
else if ( button->IsEnabled() && !enable )
button->Disable();
}
// Changes the string to something acceptable to mac menu manager
void CreateMenuString( CStr255& itemName )
{
itemName=NET_UnEscape(itemName);
if ( itemName.Length() > 50 ) // Cut it down to reasonable size
{
itemName.Length() = 50;
itemName += "...";
}
if ( itemName.Length() && itemName[ 1 ] == '-' )
itemName[ 1 ] = '<EFBFBD>';
}
// TextHandleToHardLineBreaks
// converts TextEdit handle to text handle that has hard carriage returns.
Handle TextHandleToHardLineBreaks( CSimpleTextView &inTextView )
{
Handle theOldText = inTextView.GetTextHandle();
ThrowIfNULL_(theOldText);
SInt32 theTotalLength = inTextView.GetTextLength();
// TextRangeT theTotalRange = inEngine->GetTotalRange();
// Int32 theLineCount = inEngine->CountParts(theTotalRange, cLine);
Int32 theLineCount = inTextView.CountLines();
// text will expand by at most as many line breaks as there are lines
Handle theNewText = ::NewHandle(theTotalLength + theLineCount);
ThrowIfNULL_(theNewText);
// Lock down both text buffers
StHandleLocker theOldLock(theOldText);
StHandleLocker theNewLock(theNewText);
Int32 theBreakCount = 0;
Int32 theNewTextOffset = 0;
SInt32 lineStart = 0;
SInt32 lineEnd = 0;
Boolean bEatAgain = false;
for (Int32 theIndex = 1; theIndex <= theLineCount; theIndex++)
{
// TextRangeT theLineRange;
// inEngine->FindNthPart(theTotalRange, cLine, theIndex, &theLineRange);
// Waste appears to be Zero based rather than 1
inTextView.GetLineRange( theIndex - 1, &lineStart, &lineEnd );
::BlockMoveData(*theOldText + lineStart, *theNewText + theNewTextOffset, lineEnd - lineStart );
theNewTextOffset += lineEnd - lineStart;
Boolean eatNextLine = ((theIndex + 1) < theLineCount) && // This is to prevent overflow on end
(((*theOldText)[lineStart] == '>' &&
(*theOldText)[lineEnd + 1] != '>')) ||
bEatAgain;
if ((*theNewText)[theNewTextOffset -1 ] == CR)
{
(*theNewText)[theNewTextOffset - 1] = CR;
bEatAgain = false;
}
else
{
if (eatNextLine)
bEatAgain = true; // Only
else
{
(*theNewText)[++theNewTextOffset - 1] = CR;
bEatAgain = false;
}
}
}
::SetHandleSize(theNewText, theNewTextOffset); // Reduce the size of the handle
return theNewText;
}
void ConstrainTo( const long& min, const long& max, long& value )
{
XP_WARN_ASSERT( min <= value && value <= max );
if ( value < min )
value = min;
else if ( value > max )
value = max;
}
void * StructCopy(const void * struc, UInt32 size)
{
if (struc == NULL)
return NULL;
void * newStruct = XP_ALLOC(size);
if (newStruct == NULL)
return NULL;
::BlockMoveData(struc, newStruct, size);
return newStruct;
}
void SetMenuSize( LStdPopupMenu* popup, short shouldBe )
{
MenuHandle menu;
short count;
menu = popup->GetMacMenuH();
count = ::CountMItems( menu );
while ( shouldBe > count )
{
InsertMenuItem( menu, "\p ", count );
count++;
}
while ( shouldBe < count )
{
DeleteMenuItem( menu, count );
count--;
}
popup->SetMinValue( 1 );
popup->SetMaxValue( shouldBe );
}
void SetMenuSizeForLGAPopup( LGAPopup* popup, short shouldBe )
{
MenuHandle menu;
short count;
menu = popup->GetMacMenuH();
count = ::CountMItems( menu );
while ( shouldBe > count )
{
InsertMenuItem( menu, "\p ", count );
count++;
}
while ( shouldBe < count )
{
DeleteMenuItem( menu, count );
count--;
}
popup->SetMinValue( 1 );
popup->SetMaxValue( shouldBe );
}
void SetMenuItem( CommandT whichItem, Boolean toState )
{
ResIDT menuID;
MenuHandle menu = NULL;
Int16 item;
LMenuBar* currentMenuBar;
currentMenuBar = LMenuBar::GetCurrentMenuBar();
if (currentMenuBar)
currentMenuBar->FindMenuItem( whichItem, menuID, menu, item );
if (menu)
{
if ( toState )
SetItemMark( menu, item, checkMark );
else
SetItemMark( menu, item, noMark );
}
}
// ---------------------------------------------------------------------------
// <09> myStringToNum [static]
// ---------------------------------------------------------------------------
// Utility used the USizeMenu routines to convert strings to numbers that
// ignores anything that's not a number
#define IsNumber_( x ) (( x ) >= '0' && ( x ) <= '9')
void myStringToNum( const CStr255& inString, Int32* outNum )
{
CStr255 temp;
short j = 1;
for ( short i = 1; i <= inString[ 0 ]; i++ )
{
if ( IsNumber_( inString[ i ] ) )
temp[ j++ ] = inString[ i ];
}
temp[0] = j - 1;
if (temp.Length() > 0)
StringToNum( temp, outNum );
}
short PointsToPixels( short inPoints, short iRes )
{
return ( (float)inPoints / 120.0 ) * iRes;
}
void SetCaptionDescriptor( LCaption* captionToSet, const CStr255& newText,
const TruncCode trunc )
{
XP_ASSERT( captionToSet );
CStr255 tempText( newText );
SDimension16 captionSize;
captionToSet->GetFrameSize( captionSize );
// DANGER! There is a hideous crashing bug in Apple's ::TruncString
// (and ::TruncText) when called with TruncMiddle
if (trunc == truncMiddle)
MiddleTruncationThatWorks(tempText, captionSize.width - 4);
else
TruncString( captionSize.width - 4, tempText, trunc );
captionToSet->SetDescriptor( tempText );
captionToSet->Refresh();
}
void GetDateTimeString( CStr255& dateTime )
{
unsigned long dt;
::GetDateTime( &dt );
::DateString( dt, longDate, dateTime, NULL );
}
unsigned short GetTextLengthInPixels( LTextEditView* textEdit );
unsigned short GetTextLengthInPixels( LTextEditView* textEdit )
{
XP_ASSERT( textEdit );
unsigned short width = 0;
TEHandle macTEH = NULL;
Handle text = NULL;
short length = 0;
// <20> this sets up the current port with the right text traits
if ( textEdit->FocusDraw() )
{
macTEH = textEdit->GetMacTEH();
XP_ASSERT( macTEH );
text = (*macTEH)->hText;
if ( text )
{
length = (*macTEH)->teLength;
HLock( text );
width = TextWidth( *text, 0, length );
HUnlock( text );
}
}
return width;
}
// Could be optimized
char * GetPaneDescriptor(LPane * pane)
{
char * ret = nil;
CStr255 ptempStr;
pane->GetDescriptor(ptempStr);
cstring ctempStr((unsigned char*)ptempStr);
if (ctempStr.length() > 0)
StrAllocCopy(ret, ctempStr);
return ret;
}
void TurnOn( LControl* control )
{
control->SetValue( TRUE );
control->BroadcastMessage( msg_ControlClicked, (void*)control );
}
Boolean SetPopupToNamedItem( LStdPopupMenu* whichMenu, const CStr255& itemText )
{
MenuHandle menuH;
short menuSize;
Str255 fontName;
menuH = whichMenu->GetMacMenuH();
menuSize = CountMItems( menuH );
for ( short i = 1; i <= menuSize; i++ )
{
::GetMenuItemText( menuH, i, fontName );
if ( itemText == (CStr255)fontName )
{
whichMenu->SetValue( i );
return TRUE;
}
}
return FALSE;
}
Boolean SetLGAPopupToNamedItem( LGAPopup* whichMenu, const CStr255& itemText )
{
MenuHandle menuH;
short menuSize;
Str255 fontName;
menuH = whichMenu->GetMacMenuH();
menuSize = CountMItems( menuH );
for ( short i = 1; i <= menuSize; i++ )
{
::GetMenuItemText( menuH, i, fontName );
if ( itemText == (CStr255)fontName )
{
whichMenu->SetValue( i );
return TRUE;
}
}
return FALSE;
}
unsigned long GetFreeSpaceInBytes( short vRefNum )
{
HVolumeParam pb;
OSErr err;
unsigned long result;
pb.ioCompletion = NULL;
pb.ioVolIndex = 0;
pb.ioNamePtr = NULL;
pb.ioVRefNum = vRefNum;
err = PBHGetVInfoSync( (HParmBlkPtr)&pb );
if ( err == noErr )
result = pb.ioVFrBlk * pb.ioVAlBlkSiz;
else
result = 0;
return result;
}
// <20> force a window to appear on the desktop
void ForceWindowOnScreen( LWindow* window )
{
// <20><>get the desktop region
StRegion desktopRgn( LMGetGrayRgn() );
Rect windowFrame;
window->CalcPortFrameRect( windowFrame );
windowFrame = PortToGlobalRect( window, windowFrame );
StRegion windowRgn( windowFrame );
StRegion destRgn;
Rect newRect;
::SectRgn( windowRgn, desktopRgn, destRgn );
if ( ::EmptyRgn( destRgn ) ||
!::EqualRgn( destRgn, windowRgn ) )
{
newRect = (**(static_cast<RgnHandle>(destRgn))).rgnBBox;
// <20> add 20 for title, 20 for menu bar
newRect.top = 40 + 2;
newRect.bottom = newRect.top + ( windowFrame.bottom - windowFrame.top );
newRect.left = 2;
newRect.right = newRect.left + ( windowFrame.right - windowFrame.left );
window->DoSetBounds( newRect );
}
}
void GrowWindowToScreenHeight( LWindow* win )
{
GDHandle device;
Rect windowFrame;
win->CalcPortFrameRect( windowFrame );
windowFrame = PortToGlobalRect( win, windowFrame );
device = WindowOnSingleDevice( win );
if ( device )
{
windowFrame.bottom = (**device).gdRect.bottom - 5;
win->DoSetBounds( windowFrame );
}
}
static
Boolean WillBeVisible( Rect& windowRect )
{
Rect newRect;
Boolean result = FALSE;
StRegion desktopRgn( LMGetGrayRgn() );
StRegion windowRgn( windowRect );
StRegion destRgn;
::SectRgn( windowRgn, desktopRgn, destRgn );
newRect = (**static_cast<RgnHandle>(destRgn)).rgnBBox;
if ( EmptyRgn( destRgn ) )
result = FALSE;
else if ( !EqualRect( &newRect, &windowRect ) )
result = FALSE;
else
result = TRUE;
return result;
}
void StaggerWindow( LWindow* win )
{
WindowPtr nextWindow;
LWindow* similarWindow;
Rect similarBounds;
Rect bounds;
Boolean changed = FALSE;
win->CalcPortFrameRect( bounds );
bounds = PortToGlobalRect( win, bounds );
// <20><>find the window with the same ID
// if it has the same top left corner, offset our rect by 20, 5
nextWindow = ::FrontWindow();
while ( nextWindow )
{
similarWindow = LWindow::FetchWindowObject( nextWindow );
nextWindow = (WindowPtr)( (WindowPeek)nextWindow )->nextWindow;
if ( similarWindow &&
similarWindow->GetPaneID() == win->GetPaneID() )
{
similarWindow->CalcPortFrameRect( similarBounds );
similarBounds = PortToGlobalRect( similarWindow, similarBounds );
if ( ( similarBounds.top == bounds.top ) &&
( similarBounds.left == bounds.left ) )
{
::OffsetRect( &bounds, 5, 20) ;
changed = TRUE;
// <20> loop again, because we might run into another window
nextWindow = ::FrontWindow();
}
}
}
if ( changed )
win->DoSetBounds( bounds );
}
GDHandle WindowOnSingleDevice( LWindow* win )
{
// <20> loop thru all GDevices
Rect windowFrame;
GDHandle device;
win->CalcPortFrameRect( windowFrame );
windowFrame = PortToGlobalRect( win, windowFrame );
device = GetDeviceList();
while ( device )
{
if ( UDrawingUtils::IsActiveScreenDevice( device ) )
{
Rect intersection;
// <20> find intersection of Window with this active screen Device
if ( ::SectRect( &windowFrame, &(**device).gdRect, &intersection ) )
{
// <20> window intersects this Device
if ( ::EqualRect( &windowFrame, &intersection ) )
return device;
}
}
device = GetNextDevice( device );
}
return NULL;
}
#define SAVE_VERSION 23
// <20> saving/restoring of the window's default state
Boolean RestoreDefaultWindowState(LWindow* inWindow)
{
if (inWindow == NULL)
return false;
// We are responsible for disposing of the window data
Handle theWindowData = CPrefs::ReadWindowData(inWindow->GetPaneID());
if (theWindowData == NULL)
return false;
// The destructor of the stream will kill the window data
LHandleStream stream(theWindowData);
Int32 version;
stream.ReadData(&version, sizeof( version ) );
if ( version != SAVE_VERSION )
return false;
Rect theWindowBounds;
stream.ReadData(&theWindowBounds, sizeof(theWindowBounds));
if (theWindowBounds.right > theWindowBounds.left &&
theWindowBounds.bottom > theWindowBounds.top &&
WillBeVisible(theWindowBounds) )
inWindow->DoSetBounds(theWindowBounds);
inWindow->RestorePlace(&stream);
ForceWindowOnScreen(inWindow);
return true;
}
void StoreDefaultWindowState( LWindow* win )
{
if ( !win )
return;
LHandleStream stream;
Rect windowBounds;
Int32 version = SAVE_VERSION;
stream.WriteData( &version, sizeof( version ) );
win->EstablishPort();
win->CalcPortFrameRect( windowBounds );
windowBounds = PortToGlobalRect( win, windowBounds );
stream.WriteData( &windowBounds, sizeof( windowBounds ) );
win->SavePlace( &stream );
CPrefs::WriteWindowData( stream.GetDataHandle(), win->GetPaneID() );
}
// Is front window modal? Used for command enabling
Boolean IsFrontWindowModal()
{
return UDesktop::FrontWindowIsModal();
}
// <20><>Fetch a window title resource and fill in the current profile name
void GetUserWindowTitle(short id, CStr255& title)
{
char profileName[32] = "";
int len = 32;
PREF_GetCharPref("profile.name", profileName, &len);
::GetIndString( title, WINDOW_TITLES_RESID, id );
StringParamText(title, profileName);
}
// Returns true if we are the front application
Boolean IsFrontApplication()
{
ProcessSerialNumber netscapeProcess;
ProcessSerialNumber frontProcess;
Boolean inFront;
OSErr err = ::GetCurrentProcess( &netscapeProcess );
if ( err != noErr )
return FALSE;
err = ::GetFrontProcess( &frontProcess );
if ( err != noErr )
return FALSE;
err = ::SameProcess( &frontProcess, &netscapeProcess, &inFront );
if ( err != noErr )
return FALSE;
return inFront;
}
void MakeFrontApplication()
{
ProcessSerialNumber netscapeProcess;
OSErr err = ::GetCurrentProcess( &netscapeProcess );
if (err == noErr)
SetFrontProcess(&netscapeProcess);
}
void FrameSubpaneSubtle( LView* view, LPane* pane )
{
Rect subFrame;
GetSubpaneRect( view, pane, subFrame );
::InsetRect( &subFrame, -1, -1 );
UGraphics::FrameRectSubtle( subFrame, true );
}
void GetSubpaneRgn( LView* view, LPane* pane, RgnHandle rgn )
{
Rect frame;
GetSubpaneRect( view, pane, frame );
::RectRgn( rgn, &frame );
}
void GetSubpaneRect( LView* view, LPane* pane, Rect& frame )
{
XP_ASSERT( view );
XP_ASSERT( pane );
pane->CalcPortFrameRect( frame );
view->PortToLocalPoint( *(Point*)&( frame.top ) );
view->PortToLocalPoint( *(Point*)&( frame.bottom) );
}
void WriteVersionTag( LStream* stream, Int32 version )
{
stream->WriteData( &version, sizeof( version ) );
}
Boolean ReadVersionTag( LStream* stream, Int32 version )
{
Int32 versionTag;
stream->ReadData( &versionTag, sizeof( versionTag ) );
return ( versionTag == version );
}
void TrySetCursor( int whichCursor )
{
Cursor** c = GetCursor( whichCursor );
if ( c )
SetCursor( *c );
#ifdef DEBUG
else
SysBeep( 1 );
#endif
}
void StripNewline( CStr255& msg )
{
if ( msg[ msg.Length() ] == '\n' )
msg[ msg.Length() ] = 0;
}
void StripDoubleCRs( CStr255& msg )
{
Boolean lastCR = FALSE;
for ( UInt32 i = 1; i < msg.Length(); i++ )
{
if ( msg[ i ] == CR)
{
if ( lastCR )
{
msg[ i - 1 ] = ' ';
lastCR = FALSE;
}
else
lastCR = TRUE;
}
else
lastCR = FALSE;
}
}
int ConvertCRtoLF(CStr255 & msg)
{
int ret = 0;
for ( long i = 1; i <= msg[0]; i++ )
if ( msg[ i ] == LF )
{
msg[ i ] = CR;
ret++;
}
return ret;
}
void RectFromTwoPoints( Point p1, Point p2, Rect &outRect)
{
outRect.top = MIN( p1.v, p2.v );
outRect.bottom = MAX( p1.v, p2.v );
outRect.left = MIN( p1.h, p2.h );
outRect.right = MAX( p1.h, p2.h );
}
// Return true if inEnclosingRect encloses any portion of inCheckRect
Boolean RectInRect(const Rect *inCheckRect, const Rect *inEnclosingRect) {
return (!::EmptyRect(inEnclosingRect) &&
!((inCheckRect->right <= inEnclosingRect->left) ||
(inCheckRect->bottom <= inEnclosingRect->top) ||
(inCheckRect->left >= inEnclosingRect->right) ||
(inCheckRect->top >= inEnclosingRect->bottom)));
}
const RGBColor rgbBlack = { 0x0000, 0x0000, 0x0000 };
const RGBColor rgbWhite = { 0xFFFF, 0xFFFF, 0xFFFF };
void DrawAntsRect( Rect&r, short mode )
{
::PenPat( &(UQDGlobals::GetQDGlobals()->gray) );
::PenMode( mode );
::RGBForeColor( &rgbBlack );
::RGBBackColor( &rgbWhite );
::FrameRect( &r );
}
void SafeGetFontInfo(ResIDT textTraits, FontInfo &outFontInfo)
{
StTextState textState;
UTextTraits::SetPortTextTraits(textTraits);
::GetFontInfo(&outFontInfo);
}
void FrameButton( const Rect& box, Boolean pushed )
{
UGraphics::FrameRectSubtle(box, pushed);
}
void HiliteRect( const Rect& r )
{
LMSetHiliteMode( LMGetHiliteMode() & ! ( 1 << hiliteBit ) ) ;
::InvertRect( &r );
}
void HiliteRgn( const RgnHandle& r )
{
LMSetHiliteMode( LMGetHiliteMode() & ! ( 1 << hiliteBit ) ) ;
::InvertRgn( r );
}
LPane* FindPaneHitBy( const Point& globalMouse )
{
Int16 part;
WindowPtr macWindowP;
LPane* inPane = NULL;
part = ::FindWindow( globalMouse, &macWindowP );
if ( macWindowP && part == inContent )
{
LWindow* whichWin;
whichWin = LWindow::FetchWindowObject( macWindowP );
if ( whichWin )
{
Point localMouse;
LPane* nextPane;
localMouse = globalMouse;
whichWin->GlobalToPortPoint( localMouse );
inPane = whichWin->FindSubPaneHitBy( localMouse.h, localMouse.v );
nextPane = inPane;
while ( nextPane )
{
inPane = nextPane;
nextPane = nextPane->FindSubPaneHitBy( localMouse.h, localMouse.v );
}
}
}
return inPane;
}
// ---------------------------------------------------------------
// Good 'ol Mac File Utilities
// ---------------------------------------------------------------
/*----------------------------------------------------------------------
Get a full pathname given a sig and type
In: sig of process to look for ('MOSS' for nav but should use emSignature instead)
type of process to look for (typically APPL)
Out:Returns the file path as a nul-terminated allocated block
that must be freed by the caller using XP_FREE.
Returns NULL on error;
------------------------------------------------------------------------*/
char *PathURLFromProcessSignature (OSType sig, OSType type)
{
ProcessSerialNumber targetPSN; // return process number
FSSpec targetFileSpec; // return file spec
char *appPath = NULL;
char *urlPath = NULL;
char prefix[] = "file://";
OSErr err;
// Get the file spec of our app
err = FindProcessBySignature(sig, type, targetPSN, &targetFileSpec);
if (err != noErr) return NULL;
appPath = CFileMgr::EncodedPathNameFromFSSpec(targetFileSpec, true);
if (appPath == NULL) return NULL;
urlPath = (char *)XP_ALLOC(strlen(appPath) + strlen(prefix) + 1);
if (urlPath == NULL) {
XP_FREE(appPath);
return NULL;
}
XP_STRCPY(urlPath, prefix);
XP_STRCPY(urlPath + strlen(prefix), appPath),
XP_FREE(appPath);
return urlPath;
}
// Given a process signature, gets its serial number
ProcessSerialNumber GetPSNBySig( OSType sig )
{
OSErr err;
FSSpec fileSpec;
ProcessInfoRec info;
ProcessSerialNumber psn;
info.processAppSpec = &fileSpec;
psn.highLongOfPSN = 0;
psn.lowLongOfPSN = kNoProcess;
while ( GetNextProcess( &psn ) == noErr)
{
info.processInfoLength = sizeof( ProcessInfoRec );
info.processName = NULL;
err= GetProcessInformation( &psn, &info );
if ( info.processSignature == sig )
return psn;
}
Throw_( paramErr );
return psn;
}
#define NO_PROCESS -1 // Constant used to indicate that there is no process in the PSN
// Creates an NoProcess serial number
ProcessSerialNumber MakeNoProcessPSN()
{
ProcessSerialNumber psn;
psn.highLongOfPSN = NO_PROCESS;
psn.lowLongOfPSN = NO_PROCESS;
return psn;
}
// Do we have a process
Boolean HasProcess( const ProcessSerialNumber& psn )
{
return ( ( psn.highLongOfPSN != NO_PROCESS ) ||
( psn.lowLongOfPSN!=NO_PROCESS ) );
}
// Given an application signature, finds the process
OSErr FindProcessBySignature(OSType sig,
OSType processType,
ProcessSerialNumber& psn,
FSSpec* fileSpec)
{
OSErr err;
ProcessInfoRec info;
psn.highLongOfPSN = 0;
psn.lowLongOfPSN = kNoProcess;
do
{
err= GetNextProcess(&psn);
if( err == noErr )
{
info.processInfoLength = sizeof(ProcessInfoRec);
info.processName = NULL;
info.processAppSpec = fileSpec;
err= GetProcessInformation(&psn, &info);
}
} while( (err == noErr) &&
((info.processSignature != sig) ||
(info.processType != processType)));
if( err == noErr )
psn = info.processNumber;
return err;
} // FindProcessBySignature
extern Boolean HasAppleEventObjects();
// On the 68K, the OSL glue checks to see whether it is
// installed. If it's not, the functions do nothing. On the PPC,
// if the Code Fragment Manager is unable to resolve an OSL
// stub, it performs an ExitToShell. Therefore we must
// insure that the OSL is available before calling any of
// its functions. These are called throughout PowerPlant's
// LModel* classes.
// gestaltObjectSupportLibraryInSystem = 1,
// gestaltObjectSupportLibraryPowerPCSupport = 2
// gestaltAppleEventsPresent
// gestaltScriptingSupport
// gestaltOSLInSystem <20><><EFBFBD> not gestaltObjectSupportLibraryPowerPCSupport
Boolean HasAppleEventObjects()
{
static Boolean isKnown = false, isInstalled = false;
if (!isKnown)
{
long attr = 0;
Boolean ae = UEnvironment::HasGestaltAttribute(gestaltAppleEventsAttr, gestaltAppleEventsPresent);
Boolean ppc = UEnvironment::HasGestaltAttribute(gestaltAppleEventsAttr, gestaltOSLInSystem);
#ifdef powerc
isInstalled = ae && ppc;
#else
isInstalled = 1; // we're linked with glue which always works
#endif
isKnown = true;
}
return isInstalled;
}
/*----------------------------------------------------------------------------
GetDropLocationDirectory
Given an 'alis' drop location AEDesc, return the volume reference
number and directory ID of the directory.
Entry: dropLocation = pointer to 'alis' AEDesc record.
Exit: function result = error code.
*volumeID = volume reference number.
*directoryID = directory ID.
From Apple "HFS Drag Sample" sample code.
----------------------------------------------------------------------------*/
OSErr GetDropLocationDirectory (AEDesc *dropLocation, long *directoryID, short *volumeID)
{
OSErr result;
AEDesc targetDescriptor; // 'fss ' descriptor for target directory
FSSpec targetLocation; // FSSpec for target directory
CInfoPBRec getTargetInfo; // paramBlock to get targetDirID
// Coerce the 'alis' descriptor to a 'fss ' descriptor
result = AECoerceDesc(dropLocation, typeFSS, &targetDescriptor);
if (result != noErr)
return (result);
// Extract the FSSpec from targetDescriptor
BlockMoveData((Ptr)(*targetDescriptor.dataHandle), (Ptr)&targetLocation, sizeof(FSSpec));
result = AEDisposeDesc(&targetDescriptor);
if (result != noErr)
return (result);
// Use PBGetCatInfo to get the directoryID of the target directory from the FSSpec
getTargetInfo.dirInfo.ioNamePtr = targetLocation.name;
getTargetInfo.dirInfo.ioVRefNum = targetLocation.vRefNum;
getTargetInfo.dirInfo.ioFDirIndex = 0;
getTargetInfo.dirInfo.ioDrDirID = targetLocation.parID;
result = PBGetCatInfoSync(&getTargetInfo);
if (result != noErr)
return (result);
// return directory ID and volume reference number
*directoryID = getTargetInfo.dirInfo.ioDrDirID;
*volumeID = targetLocation.vRefNum;
return result;
}
/*----------------------------------------------------------------------------
DragTargetWasTrash
Check to see if the target of a drag and drop was the Finder trashcan.
Entry: dragRef = drag reference.
Exit: function result = true if target was trash.
----------------------------------------------------------------------------*/
Boolean DragTargetWasTrash (DragReference dragRef)
{
AEDesc dropLocation;
OSErr err = noErr;
long dropDirID, trashDirID;
short dropVRefNum, trashVRefNum;
err = GetDropLocation(dragRef, &dropLocation);
if (err != noErr) return false;
if (dropLocation.descriptorType == typeNull) goto exit;
err = GetDropLocationDirectory(&dropLocation, &dropDirID, &dropVRefNum);
if (err != noErr) goto exit;
err = FindFolder(dropVRefNum, kTrashFolderType, false, &trashVRefNum,
&trashDirID);
if (err != noErr) goto exit;
if (dropVRefNum != trashVRefNum || dropDirID != trashDirID) goto exit;
AEDisposeDesc(&dropLocation);
return true;
exit:
AEDisposeDesc(&dropLocation);
return false;
}
long LArrowControl::fLastTicks = 0;
long LArrowControl::fDelay = 20;
long LArrowControl::fHits = 0;
LArrowControl::LArrowControl( const SPaneInfo& inPaneInfo, MessageT valueMessage ):
LControl( inPaneInfo, valueMessage, 0, 0, 0 )
{
mCurrPict = mArrowsPict;
}
void LArrowControl::HiliteControl( Int16 inHotSpot, Boolean inCurrInside )
{
if ( inCurrInside )
{
if ( inHotSpot == mTopHalf )
mCurrPict = mArrowsTopLit;
else if ( inHotSpot == mBottomHalf )
mCurrPict = mArrowsBotLit;
}
else
mCurrPict = mArrowsPict;
DrawSelf();
}
void LArrowControl::DrawSelf()
{
PicHandle macPictureH = GetPicture( mCurrPict );
if ( macPictureH )
{
Rect pictureBounds;
CalcLocalFrameRect( pictureBounds );
::DrawPicture( macPictureH, &pictureBounds );
}
}
Boolean LArrowControl::PointInHotSpot( Point inPoint, Int16 inHotSpot ) const
{
Rect localFrame;
Int16 midPoint;
CalcLocalFrameRect( localFrame );
midPoint = ( localFrame.bottom - localFrame.top ) / 2;
if ( inHotSpot == mTopHalf )
localFrame.bottom = midPoint;
else
localFrame.top = midPoint;
return PtInRect( inPoint, &localFrame );
}
Int16 LArrowControl::FindHotSpot( Point inPoint ) const
{
Rect localFrame;
Int16 midPoint;
CalcLocalFrameRect( localFrame );
midPoint = ( localFrame.bottom - localFrame.top ) / 2;
if ( inPoint.v < midPoint )
return mTopHalf;
else
return mBottomHalf;
}
void LArrowControl::HotSpotAction( Int16 inHotSpot, Boolean inCurrInside, Boolean inPrevInside )
{
if ( inCurrInside != inPrevInside )
{
FocusDraw();
HiliteControl( inHotSpot, inCurrInside );
}
if ( inCurrInside )
{
if ( ( ::TickCount() - fLastTicks ) < fDelay )
return;
if ( fDelay == 0 )
fDelay = 20;
fHits++;
if ( fHits > 6 )
fDelay = 5;
fLastTicks = TickCount();
BroadcastMessage( mValueMessage, &inHotSpot );
}
else
{
fHits = 0;
fDelay = 20;
}
}
void LArrowControl::HotSpotResult( Int16 /*inHotSpot*/ )
{
mCurrPict = mArrowsPict;
DrawSelf();
fHits = 0;
fDelay = 0;
}
/*=============================================================================
File & Stream Classes Utilities
=============================================================================*/
/*-----------------------------------------------------------------------------
StOpenResFile opens the resource fork and closes it later
-----------------------------------------------------------------------------*/
StOpenResFile::StOpenResFile (LFile *file, short perms)
{
fFile = file;
file->OpenResourceFork (perms);
}
StOpenResFile::~StOpenResFile ()
{
// LAM may not be required to UpdateResFile
// CloseResFile is supposed to call UpdateResFile
//::UpdateResFile (fFile->GetResourceForkRefNum());
fFile->CloseResourceFork();
}
/*-----------------------------------------------------------------------------
StUseResFile uses an open resource fork and stops using it later.
-----------------------------------------------------------------------------*/
StUseResFile::StUseResFile( short refnum )
{
fPrevResFile = CurResFile();
if (refnum != -1)
UseResFile( refnum );
}
StUseResFile::~StUseResFile()
{
UseResFile( fPrevResFile );
}
//========================================================================================
// CLASS CStringListRsrc
//========================================================================================
typedef short** IntegerHandle;
//----------------------------------------------------------------------------------------
// CStringListRsrc::GetString:
//----------------------------------------------------------------------------------------
void CStringListRsrc::GetString(short index, CStr255& theString) const
{
if (fStrListID != 0)
GetIndString(theString, fStrListID, index);
} // CStringListRsrc::GetString
//----------------------------------------------------------------------------------------
// CStringListRsrc::FindString:
//----------------------------------------------------------------------------------------
short CStringListRsrc::FindString(const CStr255& theString, Boolean addString)
{
CStr255 testString;
short numStrings = this->CountStrings();
for (short i = 1; i <= numStrings; ++i)
{
this->GetString(i, testString);
if (testString == theString)
return i; // found it! return the index
}
// CString is not found, should we add it?
if (addString == kAddString)
return this->AppendString(theString); // added it! return the index
// CString not found...sigh!
return 0;
} // CStringListRsrc::FindString
//----------------------------------------------------------------------------------------
// CStringListRsrc::AppendString:
//----------------------------------------------------------------------------------------
short CStringListRsrc::AppendString(const CStr255& theString)
{
long result;
short totalStringLength = theString.Length() + kLengthByte;
Handle aHandle = Get1Resource('STR#', fStrListID);
if (aHandle)
{
if (!*aHandle)
::LoadResource(aHandle);
if (*aHandle)
{
SInt8 flags = ::HGetState(aHandle);
::HNoPurge(aHandle);
Size itsSize = GetHandleSize(aHandle);
if (itsSize > 0)
{
short numStrings = this->CountStrings();
SetHandleSize(aHandle, itsSize + totalStringLength);
(**((IntegerHandle) aHandle)) = ++numStrings; // increment the count of strings in the STR# resource
// needs a failure handler
result = Munger(aHandle, itsSize, NULL, totalStringLength, &theString, totalStringLength);
if (result > 0)
{
// mark it as changed
ChangedResource(aHandle);
::HSetState(aHandle, flags);
return numStrings;
}
::HSetState(aHandle, flags);
}
}
}
else
{
// must create the resource...
aHandle = NewHandle(sizeof(short) + totalStringLength);
(**((IntegerHandle) aHandle)) = 1; // set the count of strings in the STR# resource
result = Munger(aHandle, sizeof(short), NULL, totalStringLength, &theString, totalStringLength);
if (result > 0)
{
AddResource(aHandle, 'STR#', fStrListID, fStrListRsrcName);
ThrowIfResError_(); // if fails, it's most likely because the file is read-only
SetResAttrs(aHandle, resPurgeable);
// Need the following ChangedResource call because the SetResAttrs call on the previous
// line cleared the "resChanged" attribute of the resource.
ChangedResource(aHandle);
return 1;
}
}
return 0;
} // CStringListRsrc::AppendString
//----------------------------------------------------------------------------------------
// CStringListRsrc::ClearAll:
//----------------------------------------------------------------------------------------
void CStringListRsrc::ClearAll()
{
Handle aHandle = Get1Resource('STR#', fStrListID);
if (aHandle)
{
if (!*aHandle)
::LoadResource(aHandle);
if (*aHandle)
{
SInt8 flags = ::HGetState(aHandle);
::HNoPurge(aHandle);
SetHandleSize(aHandle, sizeof(short));
(**((IntegerHandle) aHandle)) = 0; // set the count of strings in the STR# resource
// mark it as changed
ChangedResource(aHandle);
::HSetState(aHandle, flags);
}
}
} // CStringListRsrc::ClearAll
//----------------------------------------------------------------------------------------
// CStringListRsrc::CountStrings:
//----------------------------------------------------------------------------------------
short CStringListRsrc::CountStrings() const
{
// return the leading integer in the STR# resource:
//
// type 'STR#' {
// integer = $$Countof(StringArray);
// array StringArray {
// pstring;
// };
// };
Handle aHandle = Get1Resource('STR#', fStrListID);
if (aHandle)
{
if (!*aHandle)
::LoadResource(aHandle);
if (*aHandle)
return **((IntegerHandle) aHandle);
}
return 0;
} // CStringListRsrc::CountStrings
//----------------------------------------------------------------------------------------
// CStringListRsrc::GetListName:
//----------------------------------------------------------------------------------------
void CStringListRsrc::GetListName(CStr255& theString)
{
// Do we have the name in our field?
if ( fStrListRsrcName.Length () > 0 )
theString = fStrListRsrcName;
else // We don't have the name so try and get it from the resource
{
short itsRsrcID;
CStr255 itsName;
ResType itsType;
// Get the resource's handle
Handle aHandle = Get1Resource('STR#', fStrListID);
if (aHandle)
{
// Extract the resource info from the handle
GetResInfo ( aHandle, &itsRsrcID, &itsType, itsName );
if ( itsName.Length () > 0 )
{
theString = itsName;
// Store the name in our field
fStrListRsrcName = theString;
}
ReleaseResource ( aHandle );
}
else // Sorry we don't have anything so return an empty CString
theString = CStr255::sEmptyString;
}
} // CStringListRsrc::GetListName
//----------------------------------------------------------------------------------------
// CStringListRsrc::RemoveAt:
//----------------------------------------------------------------------------------------
void CStringListRsrc::RemoveAt(short index)
{
if ((index > 0) && (index <= this->CountStrings()))
{
Handle aHandle = Get1Resource('STR#', fStrListID);
if (aHandle)
{
if (!*aHandle)
::LoadResource(aHandle);
if (*aHandle)
{
SInt8 flags = ::HGetState(aHandle);
::HNoPurge(aHandle);
Size originalSize = GetHandleSize(aHandle);
// determine the accumulated size
Size accumulatedSize = sizeof(short); // the accumulated size is the size of the count
for (short i = 1; i < index; ++i)
accumulatedSize += (*((CStringPtr) (*aHandle + accumulatedSize))).Length() + kLengthByte;
// determine the actual CString size
Size stringSize = (*((CStringPtr) (*aHandle + accumulatedSize))).Length() + kLengthByte;
// move the the data in the handle
BlockMoveData(*aHandle + accumulatedSize + stringSize, *aHandle + accumulatedSize,
originalSize - accumulatedSize - stringSize);
// trim the handle down to its new size
SetHandleSize(aHandle, originalSize - stringSize);
// decrement count of strings in STR# resource
--(**((IntegerHandle) aHandle));
// mark it as changed
ChangedResource(aHandle);
::HSetState(aHandle, flags);
}
#if qDebugMsg
else
fprintf(stderr, "CStringListRsrc::RemoveAt can't load STR# = %d.\n", fStrListID);
#endif
}
#if qDebugMsg
else
fprintf(stderr, "CStringListRsrc::RemoveAt can't find STR# = %d.\n", fStrListID);
#endif
}
#if qDebugMsg
else
fprintf(stderr, "CStringListRsrc::RemoveAt there's no CString at %d to remove!\n", index);
#endif
} // CStringListRsrc::RemoveAt
//----------------------------------------------------------------------------------------
// CStringListRsrc::ReplaceAt:
//----------------------------------------------------------------------------------------
void CStringListRsrc::ReplaceAt(const CStr255& theString, short index)
{
if ((index > 0) && (index <= this->CountStrings()))
{
Handle aHandle = Get1Resource('STR#', fStrListID);
if (aHandle)
{
if (!*aHandle)
::LoadResource(aHandle);
if (*aHandle)
{
SInt8 flags = ::HGetState(aHandle);
::HNoPurge(aHandle);
Size newStringSize = theString.Length() + kLengthByte; // the actual CString size
Size originalSize = GetHandleSize(aHandle);
// determine the accumulated size of the valid portion of the resource
Size accumulatedSize = sizeof(short); // the accumulated size is the size of the count
for (short i = 1; i < index; ++i)
accumulatedSize += (*((CStringPtr) (*aHandle + accumulatedSize))).Length() + kLengthByte;
// determine the actual CString size
Size oldStringSize = (*((CStringPtr) (*aHandle + accumulatedSize))).Length() + kLengthByte;
// determine the new handle size
Size newHandleSize = originalSize + (newStringSize - oldStringSize);
// determine whether to grow or shrink the handle?
if (newStringSize > oldStringSize)
{
// grow the handle
SetHandleSize(aHandle, newHandleSize);
// move the bytes
BlockMoveData(*aHandle + accumulatedSize + oldStringSize, *aHandle + accumulatedSize + newStringSize,
originalSize - accumulatedSize - oldStringSize);
}
else if (oldStringSize > newStringSize)
{
// move the bytes
BlockMoveData(*aHandle + accumulatedSize + oldStringSize, *aHandle + accumulatedSize + newStringSize,
originalSize - accumulatedSize - oldStringSize);
// shrink the handle
SetHandleSize(aHandle, newHandleSize);
}
// assign the CString
*((CStr255*) (*aHandle + accumulatedSize)) = theString;
// mark it as changed
ChangedResource(aHandle);
::HSetState(aHandle, flags);
}
#if qDebugMsg
else
fprintf(stderr, "CStringListRsrc::ReplaceAt can't load STR# = %d.\n", fStrListID);
#endif
}
#if qDebugMsg
else
fprintf(stderr, "CStringListRsrc::ReplaceAt can't find STR# = %d.\n", fStrListID);
#endif
}
#if qDebugMsg
else
fprintf(stderr, "CStringListRsrc::ReplaceAt there's no CString at %d to replace!\n", index);
#endif
} // CStringListRsrc::ReplaceAt
StWatchCursor::StWatchCursor() { ::SetCursor( (CursPtr)*(::GetCursor(watchCursor)) ); }
StWatchCursor::~StWatchCursor() { ::SetCursor( &(UQDGlobals::GetQDGlobals()->arrow) ); }
//-----------------------------------
void StringParamText(
CStr255& ioFormatString,
SInt32 inReplaceNumber0,
SInt32 inReplaceNumber1,
SInt32 inReplaceNumber2,
SInt32 inReplaceNumber3)
// Replace the characters "^0" ..."^3"within ioString with numerals.
// If "^0" or "^1" is not found in ioString, the method does nothing.
//-----------------------------------
{
char t0[15], t1[15], t2[15], t3[15];
sprintf(t0, "%ld", inReplaceNumber0);
sprintf(t1, "%ld", inReplaceNumber1);
sprintf(t2, "%ld", inReplaceNumber2);
sprintf(t3, "%ld", inReplaceNumber3);
::StringParamText(ioFormatString, t0, t1, t2, t3);
}
//-----------------------------------
void StringParamText(
CStr255& ioFormatString,
const char* inReplaceText0,
const char* inReplaceText1,
const char* inReplaceText2,
const char* inReplaceText3)
// Replace the substrings "^0" ..."^3" within ioString with inReplaceText0 ... inReplaceText3.
// (substring is just removed if inReplaceTextn is null).
// If any of the substrings "^0"..."^3" is not found in ioString, nothing happens there.
//-----------------------------------
{
LStr255 resultString = (ConstStringPtr)&ioFormatString;
char target[] = "^0";
const char* replaceString[] = {
inReplaceText0,
inReplaceText1,
inReplaceText2,
inReplaceText3 };
for (int i = 0; i < 4; i++)
{
UInt8 position = resultString.Find(target, 1);
if ( position )
{
const char* rs = replaceString[i];
if ( rs )
resultString.Replace(position, 2, rs, strlen(rs));
else
resultString.Remove(position, 2);
}
target[1]++; // morph it into "^1" etc. ASCII standard supports this.
}
ioFormatString = (ConstStringPtr)resultString;
}
// This code is taken from June 97 Dev.CD
enum
{
kPromisedFlavor = 'fssP',
kPromisedFlavorFindFile = 'rWm1'
};
static Size MinimumBytesForFSSpec (const FSSpec *fss)
{
//
// Some senders don't bother sending the unused bytes of the
// file name. This function helps make sure the FSSpec is
// minimally sane by computing the minimum number of bytes it
// would take to store it.
//
// THIS FUNCTION CANNOT MOVE MEMORY.
//
return sizeof (*fss) - sizeof (fss->name) + *(fss->name) + 1;
}
OSErr GetHFSFlavorFromPromise
(DragReference dragRef, ItemReference itemRef,
HFSFlavor *hfs, Boolean isSupposedlyFromFindFile)
{
OSErr err = noErr;
PromiseHFSFlavor phfs;
Size size = sizeof (phfs);
err = GetFlavorData
(dragRef,itemRef,flavorTypePromiseHFS,&phfs,&size,0);
if (!err)
{
if (size != sizeof (phfs))
err = cantGetFlavorErr;
else
{
Boolean isFromFindFile =
phfs.promisedFlavor == kPromisedFlavorFindFile;
if (isSupposedlyFromFindFile != isFromFindFile)
err = paramErr;
else
{
size = sizeof (hfs->fileSpec);
err = GetFlavorData
(dragRef,itemRef,phfs.promisedFlavor,
&(hfs->fileSpec),&size,0);
if (!err)
{
Size minSize = MinimumBytesForFSSpec
(&(hfs->fileSpec));
if (size < minSize)
err = cantGetFlavorErr;
else
{
hfs->fileType = phfs.fileType;
hfs->fileCreator = phfs.fileCreator;
hfs->fdFlags = phfs.fdFlags;
}
}
}
}
}
return err;
}
// End of cut and paste
StSpinningBeachBallCursor::StSpinningBeachBallCursor ()
{
startAsyncCursors();
}
StSpinningBeachBallCursor::~StSpinningBeachBallCursor()
{
stopAsyncCursors();
}