// =========================================================================== // CAppearanceApp.cp ©1994-2000 Metrowerks Inc. All rights reserved. // =========================================================================== // This file contains the starter code for a basic PowerPlant project #include "CAppearanceApp.h" #include #include #include #include #include #include #include #include #include #if PP_StdDialogs_Option == PP_StdDialogs_Conditional #include #endif #include #include #include #include #include #include #include #include #include #if PP_Debug #include // Only needed for LDebugStream #include #include #include #include #endif #include #include #include #if PP_Debug #include "MetroNubUtils.h" #endif #include //_tk_ #include #include "UCustomRegistry.h" #include "CConverter.h" #include "CStreamConverter.h" #include "PrefsDlg.h" #include "SmartPreferences.h" #include "CInputBuffer.h" #include "COutputBuffer.h" #include "Alert.h" #include "CErrorLog.h" #include #include "CEncodingArray.h" #if PP_Target_Carbon const long ae_ShowPreferences = 1006; #define kXCommandPreferences 'pref' #define kXCommandQuit 'quit' #endif CyclonePrefs *gPrefs = nil; //_tk_ UAnimateColorCursor *gCursorAnimator = nil; StrFileName gCurrFileName; Boolean gMultiFileConversion = false; Boolean gNoAlerts = false; CErrorLog *gErrorLog = nil; #if PP_Target_Carbon bool gAquaPresent = false; #endif // --------------------------------------------------------------------------- // Prototypes void AppMain(); // main loop void PP_NewHandler() throw (PP_STD::bad_alloc); // defined in PPDebug_New.cp // =========================================================================== // ¥ main // =========================================================================== int main() { // First things first. Install a new_handler. (void)PP_STD::set_new_handler(PP_NewHandler); // Don't let exceptions propagate outside of main try { AppMain(); } catch (...) { SignalStringLiteral_("Exception caught in main"); } return 0; } // --------------------------------------------------------------------------- // ¥ AppMain // --------------------------------------------------------------------------- void AppMain() { UEnvironment::InitEnvironment(); #if PP_Debug // If under the debugger, use the debugger for everything // (throw, signal, DebugNew), else use alerts. if (AmIBeingMWDebugged()) { UDebugging::SetDebugThrow(debugAction_Debugger); UDebugging::SetDebugSignal(debugAction_Debugger); } else { // Not under the MW Debug, so use alerts. If you use // another debugger, you could set this up the same way. Point // is to use the debugger's facilities when under the debugger, // else alerts. UDebugging::SetDebugThrow(debugAction_Alert); UDebugging::SetDebugSignal(debugAction_Alert); // Use our own error handler for DebugNew which uses alerts // instead of DebugStr calls. PP_DebugNewInstallPPErrorHandler_(); } #else // In final build mode so nothing should be seen. These are // commented out because gDebugThrow and gDebugSignal are // initialized to debugAction_Nothing -- assignment here is // unnecessary (but left in as a comment for illustration). UDebugging::SetDebugThrow(debugAction_Nothing); UDebugging::SetDebugSignal(debugAction_Alert); #endif // Clean up any "leaks" that might have occured at static // initialization time. { SLResetLeaks_(); DebugNewForgetLeaks_(); } // Normal initializations InitializeHeap(5); UQDGlobals::InitializeToolbox(); ::InitCursor(); ::FlushEvents(everyEvent, nil); // Check Debugging environment #if PP_Debug UDebugUtils::CheckEnvironment(); #endif // Install a GrowZone to catch low-memory situations LGrowZone* theGZ = NEW LGrowZone(20000); ValidateObject_(theGZ); SignalIf_(theGZ->MemoryIsLow()); // Create the application object and run. The scope of // the object is limited as we need to control when // the object's destructor is called (in relation to // the code that follows it). { CAppearanceApp theApp; theApp.Run(); } #if PP_Debug // This cleanup isn't necessary (they are items that are to // remain for the duration of the application's run time. When // the app quits and the Process Manager reclaims the heap, // the memory occupied by these items will be released). This // is just done to keep things like DebugNew and Spotlight // quiet. LMenuBar* theBar = LMenuBar::GetCurrentMenuBar(); delete theBar; URegistrar::DisposeClassTable(); LPeriodical::DeleteIdlerAndRepeaterQueues(); UMemoryEater::DeleteMemoryLists(); LModelDirector* theDirector = LModelDirector::GetModelDirector(); delete theDirector; LModelObject::DestroyLazyList(); UScreenPort::Dispose(); DisposeOf_(theGZ); LComparator* theCompare = LComparator::GetComparator(); delete theCompare; LLongComparator* theLongCompare = LLongComparator::GetComparator(); delete theLongCompare; CEncValueComparator *encComp = CEncValueComparator::GetComparator(); delete encComp; CEncNameComparator *encNameComp = CEncNameComparator::GetComparator(); delete encNameComp; #endif DebugNewReportLeaks_(); } // --------------------------------------------------------------------------- // ¥ CDocumentApp [public] // --------------------------------------------------------------------------- // Application object constructor CAppearanceApp::CAppearanceApp() { mInputBuffer = nil; mOutputBuffer = nil; gCurrFileName[0] = 0; gMultiFileConversion = false; gErrorLog = nil; mSavePrefs = true; //ok - try to find american version of TextEncodingConverter short foundVRefNum; long foundDirID; OSErr err = ::FindFolder(kOnSystemDisk, kExtensionFolderType, kDontCreateFolder, &foundVRefNum, &foundDirID); if(err == noErr) { Str255 name = "\pText Encoding Converter"; FSSpec spec; err = ::FSMakeFSSpec(foundVRefNum, foundDirID, name, &spec); if(err == fnfErr) { if( UEnvironment::GetOSVersion() >= 0x0800 )//ok - not found, but if we are under System 8 we may check for folder { err = ::FindFolder(kOnSystemDisk, kTextEncodingsFolderType, kDontCreateFolder, &foundVRefNum, &foundDirID); if(err != noErr) { StopAlertResID(1, err);//This application requires Text Encoding Converter. Throw_(err); } } //else - we cannot determine if TEC is present - we just go and try :-( } } //this is critical to our application that is why we call it so early: if( ! CConverter::GetAllEncodingMappings() ) { StopAlertResID(2, kTECMissingTableErr);//Cannot get Text Encoding Converter maps. Throw_(kTECMissingTableErr); } // Register ourselves with the Appearance Manager if (UEnvironment::HasFeature(env_HasAppearance)) { ::RegisterAppearanceClient(); } // Register the Appearance Manager/GA classes UCustomRegistry::RegisterClasses(); // Preload facilities for the Standard Dialogs PP_StandardDialogs::Load(); // Require at least Navigation Services 1.1. See comments // above SetTryNavServices in UConditionalDialogs.cp for why // you might wish to do this. #if PP_StdDialogs_Option == PP_StdDialogs_Conditional UConditionalDialogs::SetTryNavServices(0x01108000); #endif #if PP_Target_Carbon long response; err = ::Gestalt(gestaltMenuMgrAttr, &response); gAquaPresent = ((err == noErr) && (response & gestaltMenuMgrAquaLayoutMask)); #endif //_tk_ test, use GA implementations and classic open/save dialogs: // UEnvironment::SetFeature(env_HasAppearance, false); // UCustomRegistry::RegisterGAClasses(); mPrefs = NEW SmartPreferences(); mPrefs->GetPrefs(); gPrefs = &(mPrefs->mCyclonePrefs); //no memory allocations yet try { mOutputBuffer = NEW COutputBuffer(); mInputBuffer = NEW CInputBuffer(mOutputBuffer); } catch(const LException& inException) { if(mOutputBuffer != NULL) delete mOutputBuffer; if(mInputBuffer != NULL) delete mInputBuffer; StopAlertResID(3, inException.GetErrorCode()); throw;//re-throw it up to force exit } // gCursorAnimator = NEW UAnimateColorCursor( 129, 8, 10, 0 );//first id, total no, interval, init delay mInputTextEncoding = kTextEncodingMacRoman; mOutputTextEncoding = kTextEncodingMacRoman; mLineBreak = kLineBreakNoChange; mAskForConversion = true; mStopMultipleConversion = false; //test: /* static Str255 theTest[] = { "\pCP932", "\pCP936", "\pCP950", "\pX-MAC-TIBETAN", "\pX-MAC-JAPANESE", "\pX-MAC-CHINESETRAD", "\pX-MAC-KOREAN", "\pX-MAC-DEVANAGARI", "\pX-MAC-GURMUKHI", "\pX-MAC-GUJARATI", "\pX-MAC-CHINESESIMP", "\pX-MAC-VT100", "\pUNICODE-2-0-UTF-7", "\pUNICODE-2-0-UTF-8", "\pJIS_C6226-1983", "\pcsISO58GB231280", "\pX-GBK", "\pcsKSC56011987", "\pX-EUC-TW", "\pX-NEXTSTEP" }; long theCount = sizeof(theTest)/ sizeof(Str255); for(long i = 0; i < theCount; i++) { // Str255 encName = "\pUTF-16"; TextEncoding encValue = 0xFFFFFFFF; OSStatus stat = ::TECGetTextEncodingFromInternetName( &encValue, theTest[i]); Assert_(stat == noErr); Assert_(encValue != 0xFFFFFFFF); } */ } // --------------------------------------------------------------------------- // ¥ ~CAppearanceApp [public, virtual] // --------------------------------------------------------------------------- // Application object destructor CAppearanceApp::~CAppearanceApp() { // Clean up after Standard Dialogs PP_StandardDialogs::Unload(); if(mInputBuffer) delete mInputBuffer; if( mOutputBuffer ) delete mOutputBuffer; CConverter::DisposeAllEncodingMappings(); if(mSavePrefs) mPrefs->SavePrefs(); delete mPrefs; // if(gCursorAnimator) // delete gCursorAnimator; ::LoadScrap(); } // --------------------------------------------------------------------------- // ¥ StartUp [protected, virtual] // --------------------------------------------------------------------------- // Perform an action in response to the Open Application AppleEvent. // Here, issue the New command to open a window. void CAppearanceApp::StartUp() { #if PP_Target_Carbon UInt32 modifiers = ::GetCurrentKeyModifiers(); #else EventRecord macEvent; ::OSEventAvail(0, &macEvent); EventModifiers modifiers = macEvent.modifiers; #endif if( (gPrefs->flags & kRunningForTheFirstTime) || (modifiers & cmdKey) ) { PrefsDlg theDlg(this); theDlg.ShowDialog(); } if( gPrefs->flags & kAskAtStartup ) ObeyCommand(cmd_New, nil); } void CAppearanceApp::OpenOrPrintDocList( const AEDescList& inDocList, SInt32 inAENumber) { SInt32 numDocs; OSErr err = ::AECountItems(&inDocList, &numDocs); ThrowIfOSErr_(err); // Loop through all items in the list // Extract descriptor for the document // Coerce descriptor data into a FSSpec // Tell Program object to open document mAskForConversion = true;//ask for conversion at least once! mStopMultipleConversion = false; //reset value if(gErrorLog != nil) { delete gErrorLog; gErrorLog = nil; } if( numDocs > 1 ) { gMultiFileConversion = true; if( (gPrefs->flags & kSuppressMsgGenLog) ) gErrorLog = NEW CErrorLog(); } else gMultiFileConversion = false; FSSpec theFileSpec; for (SInt32 i = 1; i <= numDocs; i++) { AEKeyword theKey; DescType theType; Size theSize; err = ::AEGetNthPtr(&inDocList, i, typeFSS, &theKey, &theType, (Ptr) &theFileSpec, sizeof(FSSpec), &theSize); if(err == noErr ) { if (inAENumber == ae_OpenDoc) { try { OpenDocument(&theFileSpec); } catch(const LException& inException) { //nothing here - all alerts should be done before } } else { PrintDocument(&theFileSpec); } if( mStopMultipleConversion ) break; } } if(gErrorLog) { try { gErrorLog->SaveLog(theFileSpec); } catch(const LException& inException) { //alert? } delete gErrorLog; } gErrorLog = nil; } LModelObject* CAppearanceApp::MakeNewDocument() { LFileTypeList fileTypes(fileTypes_All); PP_StandardDialogs::LFileChooser chooser; NavDialogOptionFlags flags = kNavDefaultNavDlogOptions | kNavDontAutoTranslate | kNavNoTypePopup | kNavAllowMultipleFiles; NavDialogOptions* options = chooser.GetDialogOptions(); if(options != nil) { options->dialogOptionFlags = flags; ::GetIndString( options->windowTitle, STRx_Standards, 3); } //release memory occupied by our buffers (they will restore it when needed) mInputBuffer->Free(); mOutputBuffer->Free(); if (chooser.AskOpenFile(fileTypes)) { Boolean skipThisFile = false; FSSpec currSpec; SInt32 numberOfFiles = chooser.GetNumberOfFiles(); mAskForConversion = true;//ask for conversion at least once! mStopMultipleConversion = false; //reset value if(gErrorLog != nil) { delete gErrorLog; gErrorLog = nil; } if( numberOfFiles > 1 ) { gMultiFileConversion = true; if( (gPrefs->flags & kSuppressMsgGenLog) ) gErrorLog = NEW CErrorLog(); } else gMultiFileConversion = false; for(SInt32 i = 1; i<= numberOfFiles; i++) { try { chooser.GetFileSpec(i, currSpec); } catch(const LException& inException) { skipThisFile = true; } if( !skipThisFile) { try { OpenDocument( &currSpec );//may set mStopMultipleConversion to true } catch(const LException& inException) { //nothing here - all alerts should be done before } } skipThisFile = false; if(mStopMultipleConversion) break; } if(gErrorLog) { try { gErrorLog->SaveLog(currSpec); } catch(const LException& inException) { //alert? } delete gErrorLog; } gErrorLog = nil; } return nil; } Boolean CAppearanceApp::ObeyCommand( CommandT inCommand, void* ioParam) { Boolean cmdHandled = true; switch (inCommand) { case 'CvCp': { gMultiFileConversion = false; gCurrFileName[0] = 0; OSErr iErr = ::UnloadScrap();//make some space TextEncoding inputEncoding = kTextEncodingMacRoman; TextEncoding outputEncoding; if( gPrefs->flags & kUseSniffers ) { TextEncoding suggestedEncoding; if( CConverter::SniffClipboardContent(suggestedEncoding) ) inputEncoding = suggestedEncoding; } Str255 theStr; ::GetIndString(theStr, rMiscStrings, 14);//"Clipboard" UInt16 lineBreak = kLineBreakNoChange; if( CConverter::AskForConversionType(inputEncoding, outputEncoding, lineBreak, theStr, this) ) { OSStatus status = noErr; //release memory occupied by our buffers (they will restore it when needed) mInputBuffer->Free(); mOutputBuffer->Free(); try { status = CConverter::ConvertClipboard( inputEncoding, outputEncoding, lineBreak);//all alerts are done inside except for some throws } catch(const LException& inException) { StopAlertResID(4, inException.GetErrorCode());//Clipboard conversion failed. } } } break; case cmd_Preferences: { PrefsDlg theDlg(this); theDlg.ShowDialog(); } break; default: cmdHandled = LDocApplication::ObeyCommand(inCommand, ioParam); break; } return cmdHandled; } void CAppearanceApp::FindCommandStatus( CommandT inCommand, Boolean& outEnabled, Boolean& outUsesMark, UInt16& outMark, Str255 outName) { switch (inCommand) { #if PP_Target_Carbon case 'pref': { outEnabled = true; } break; #endif case 'CvCp': { bool isUnicodeDontCare; outEnabled = ClipboardHasText(isUnicodeDontCare); } break; case cmd_Preferences: outEnabled = true; break; default: LDocApplication::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName); break; } } void CAppearanceApp::OpenDocument(FSSpec* ioMacFSSpec) { FSSpec theOrigSpec = *ioMacFSSpec;//copy original spec //zero the output spec - in case of any error it will stay like this - invalid ioMacFSSpec->vRefNum = 0; ioMacFSSpec->parID = 0; ioMacFSSpec->name[0] = 0; LString::CopyPStr(theOrigSpec.name, gCurrFileName, sizeof(StrFileName) ); if( mAskForConversion ) { if( (gPrefs->flags & kAskEncForEachFile) == 0 ) mAskForConversion = false;//do not ask next time you enter here! if( gPrefs->flags & kUseSniffers ) { TextEncoding suggestedEncoding; if( CConverter::SniffFileContent( theOrigSpec, suggestedEncoding) ) mInputTextEncoding = suggestedEncoding; } if( !CConverter::AskForConversionType(mInputTextEncoding, mOutputTextEncoding, mLineBreak, theOrigSpec.name, this) ) { mStopMultipleConversion = true; return; } } { FSSpec newFileSpec; if( SaveFileAs( &newFileSpec, &theOrigSpec) ) { CStreamConverter *theConverter = nil; try { theConverter = NEW CStreamConverter(mInputTextEncoding, mOutputTextEncoding, mLineBreak, &theOrigSpec, &newFileSpec, mInputBuffer, mOutputBuffer); } catch(const LException& inException) { if( kAlertCancel == StopAlertResIDName(5, inException.GetErrorCode() ) )//Could not create the converter for the given encodings. mStopMultipleConversion = true; if(theConverter) delete theConverter; throw;//re-throw up } try { theConverter->Convert(); } catch(const LException& inException) { if( kAlertCancel == StopAlertResIDName(6, inException.GetErrorCode() ) )//Conversion failed. mStopMultipleConversion = true; if(theConverter) delete theConverter; throw;//re-throw up } delete theConverter; *ioMacFSSpec = newFileSpec;//copy output spec } else mStopMultipleConversion = true; } } Boolean CAppearanceApp::ChooseOneFile(FSSpec *outSpec) { LFileTypeList fileTypes(fileTypes_All); PP_StandardDialogs::LFileChooser chooser; NavDialogOptionFlags flags = kNavDefaultNavDlogOptions | kNavDontAutoTranslate | kNavNoTypePopup; flags &= ~kNavAllowMultipleFiles; // Can't select multiple files NavDialogOptions* options = chooser.GetDialogOptions(); if( options != nil ) { options->dialogOptionFlags = flags; ::GetIndString( options->windowTitle, STRx_Standards, 3); } if (chooser.AskOpenFile(fileTypes)) { chooser.GetFileSpec(1, *outSpec); return true; } return false; } Boolean CAppearanceApp::SaveFileAs(FSSpec *outSpec, FSSpec *inputSpec) { Boolean isOK = false; Boolean replacing = false; OSStatus status = noErr; OSType theFileType = kTextFileType; if( gPrefs->flags & kSaveDontAsk ) { *outSpec = *inputSpec; if( MakeNewSpec( outSpec ) ) return true; //else - we coud not create the different file name - fall back to save-as } StrFileName tempName; LString::CopyPStr(inputSpec->name, tempName, sizeof(StrFileName) ); if(tempName[0] < 31) tempName[0]++; tempName[ tempName[0] ] = '¥'; PP_StandardDialogs::LFileDesignator designator; designator.SetFileType( theFileType ); NavDialogOptions* options = designator.GetDialogOptions(); if(options != nil) { options->dialogOptionFlags = kNavDefaultNavDlogOptions | kNavNoTypePopup | kNavDontAutoTranslate; ::GetIndString( options->windowTitle, STRx_Standards, 2);//save file as } isOK = designator.AskDesignateFile( tempName ); if (isOK) { designator.GetFileSpec( *outSpec ); replacing = designator.IsReplacing(); if(replacing) { if( LFile::EqualFileSpec( *outSpec, *inputSpec) ) { StopAlertResIDName(7, dupFNErr);//Source and destination must be different. return false; } status = ::FSpDelete( outSpec );//delete it if( status != noErr && status != fnfErr) { StopAlertResIDStr(8, outSpec->name, status); return false;//could not remove file! } } } return isOK; } void CAppearanceApp::CatchException( const LException& inException) { LStr255 msg( rErrorStrings, 9);//Unknown error occured. StopAlertStringName( msg, inException.GetErrorCode() ); } void CAppearanceApp::CatchExceptionCode( ExceptionCode inError) { LStr255 msg( rErrorStrings, 9);//Unknown error occured. StopAlertStringName( msg , inError); } Boolean CAppearanceApp::MakeNewSpec(FSSpec *ioSpec) { OSErr err = noErr; short j = ioSpec->name[0]; short i = ioSpec->name[0]; FSSpec tempSpec = *ioSpec; do { if(i < 31) { i++; tempSpec.name[i] = '¥';//add to the end tempSpec.name[0] = i; } else if( j >= 1 ) { tempSpec.name[j] = '¥'; //replace chars beginning from the end j--; } err = ::FSMakeFSSpec( tempSpec.vRefNum, tempSpec.parID, tempSpec.name, &tempSpec); } while( (err == noErr) && ((i<31) || (j>0) ) );//we are waiting for fnfErr ! if(err != noErr) *ioSpec = tempSpec; return (err != noErr); } void CAppearanceApp::HandleAppleEvent( const AppleEvent& inAppleEvent, AppleEvent& outAEReply, AEDesc& outResult, long inAENumber) { switch (inAENumber) { #if PP_Target_Carbon case ae_ShowPreferences: { ProcessCommand(cmd_Preferences); } break; #endif case 4001: { DoAEConvertDoc(inAppleEvent, outResult, inAENumber); mSavePrefs = false; } break; case 4002: { DoAEConvertClipboard( inAppleEvent, outResult ); mSavePrefs = false; } break; case 4003: { DoAESetAlertMode( inAppleEvent, outResult ); } break; case 4004: { DoAEConvertText( inAppleEvent, outResult ); mSavePrefs = false; } break; default: LDocApplication::HandleAppleEvent(inAppleEvent, outAEReply, outResult, inAENumber); break; } } // Respond to an AppleEvent to convert a Document list void CAppearanceApp::DoAEConvertDoc( const AppleEvent& inAppleEvent, AEDesc& outResult, SInt32 /*inAENumber*/) { StAEDescriptor docList; OSErr err = ::AEGetParamDesc(&inAppleEvent, keyDirectObject, typeAEList, docList); ThrowIfOSErr_(err); err = ::AECreateList( nil, 0, false, &outResult ); ThrowIfOSErr_(err); // DescType theType; // Size theSize; mInputTextEncoding = GetEncodingFromAppleEventParam(inAppleEvent, FOUR_CHAR_CODE('from') ); mOutputTextEncoding = GetEncodingFromAppleEventParam(inAppleEvent, FOUR_CHAR_CODE('to ') ); mLineBreak = kLineBreakNoChange; GetLineBreakOptionFromAppleEventParam( inAppleEvent, mLineBreak ); SInt32 numDocs; err = ::AECountItems(docList, &numDocs); ThrowIfOSErr_(err); // Loop through all items in the list // Extract descriptor for the document // Coerce descriptor data into a FSSpec // Tell Program object to open document mAskForConversion = false;//do not ask for conversion mStopMultipleConversion = false; //reset value if(gErrorLog != nil) { delete gErrorLog; gErrorLog = nil; } if( numDocs > 1 ) { gMultiFileConversion = true; if( (gPrefs->flags & kSuppressMsgGenLog) ) gErrorLog = NEW CErrorLog(); } else gMultiFileConversion = false; FSSpec theFileSpec; for (SInt32 i = 1; i <= numDocs; i++) { AEKeyword theKey; DescType theType; Size theSize; err = ::AEGetNthPtr(docList, i, typeFSS, &theKey, &theType, (Ptr) &theFileSpec, sizeof(FSSpec), &theSize); if(err == noErr ) { //Assert_ (inAENumber == 4001); try { OpenDocument(&theFileSpec); } catch(const LException& inException) { //nothing here - all alerts should be done before } AEDesc fileDesc; err = ::AECreateDesc( typeFSS, &theFileSpec, sizeof(FSSpec), &fileDesc ); err = ::AEPutDesc( &outResult, 0, &fileDesc );//add to end if( mStopMultipleConversion ) break; } } if(gErrorLog) { try { gErrorLog->SaveLog(theFileSpec); } catch(const LException& inException) { //alert? } delete gErrorLog; } gErrorLog = nil; } void CAppearanceApp::DoAEConvertClipboard(const AppleEvent& inAppleEvent, AEDesc& outResult) { #pragma unused (outResult) mInputTextEncoding = GetEncodingFromAppleEventParam(inAppleEvent, FOUR_CHAR_CODE('from') ); mOutputTextEncoding = GetEncodingFromAppleEventParam(inAppleEvent, FOUR_CHAR_CODE('to ') ); mLineBreak = kLineBreakNoChange; GetLineBreakOptionFromAppleEventParam( inAppleEvent, mLineBreak ); gMultiFileConversion = false; gCurrFileName[0] = 0; OSErr err = ::UnloadScrap();//make some space ThrowIfOSErr_(err); OSStatus status = noErr; //release memory occupied by our buffers (they will restore it when needed) mInputBuffer->Free(); mOutputBuffer->Free(); //try //{ status = CConverter::ConvertClipboard( mInputTextEncoding, mOutputTextEncoding, mLineBreak);//this may throw, but it is OK to throw from here ThrowIfOSErr_(status); //} //catch(const LException& inException) //{ // status = inException.GetErrorCode(); //} //no alert - we just return an apple event with error // err = ::AECreateDesc('long', &status, sizeof(long), &outResult); } bool CAppearanceApp::ClipboardHasText(bool &outIsUnicode) { outIsUnicode = false; bool hasData = false; try { hasData = UScrap::HasData( ResType_Text );//this may throw if( !hasData ) { hasData = UScrap::HasData( typeUnicodeText );//this may throw if( hasData ) { outIsUnicode = true;//unicode found! } } } catch(...) { } return hasData; } void CAppearanceApp::DoAESetAlertMode(const AppleEvent& inAppleEvent, AEDesc& /*outResult*/) { DescType theType; Size theSize; unsigned long mode = 0x00000001;//init to show alerts with no log OSErr err = ::AEGetParamPtr(&inAppleEvent, keyDirectObject, typeEnumerated, &theType, &mode, sizeof(long), &theSize); ThrowIfOSErr_(err); if( (mode & 0x00000001) == 0x00000001) //show alerts gNoAlerts = false; else gNoAlerts = true; if( (mode & 0x00000002) == 0x00000002) //do log for multiple files gPrefs->flags |= kSuppressMsgGenLog; else gPrefs->flags &= ~kSuppressMsgGenLog; } void CAppearanceApp::DoAEConvertText(const AppleEvent& inAppleEvent, AEDesc& outResult) { DescType theType = typeChar; StAEDescriptor inputText; OSErr err = ::AEGetParamDesc(&inAppleEvent, keyDirectObject, typeWildCard, inputText); ThrowIfOSErr_(err); if(inputText.mDesc.dataHandle == nil) { unsigned char noData = 0; err = ::AECreateDesc(typeChar, &noData, 0, &outResult); ThrowIfOSErr_(err); return; } mInputTextEncoding = GetEncodingFromAppleEventParam(inAppleEvent, FOUR_CHAR_CODE('from') ); mOutputTextEncoding = GetEncodingFromAppleEventParam(inAppleEvent, FOUR_CHAR_CODE('to ') ); mLineBreak = kLineBreakNoChange; GetLineBreakOptionFromAppleEventParam( inAppleEvent, mLineBreak ); gMultiFileConversion = false; gCurrFileName[0] = 0; OSStatus status = noErr; //release memory occupied by our buffers (they will restore it when needed) mInputBuffer->Free(); mOutputBuffer->Free(); #if PP_Target_Carbon Size theSize = ::AEGetDescDataSize( (const AEDesc*)inputText ); Handle srcH = ::NewHandle( theSize ); ThrowIfMemError_(); StHandleLocker srcLock(srcH); ::AEGetDescData( (const AEDesc*)inputText, *srcH, theSize ); srcLock.Release(); #else Handle srcH = inputText.mDesc.dataHandle;//non nil - this is checked before Size theSize = ::GetHandleSize(srcH); #endif Handle destH = ::NewHandle( theSize ); ThrowIfMemError_(); // if(destH != nil) // { StHandleBlock srcDel(destH); StHandleBlock destDel(destH); status = CConverter::ConvertFromOneEncodingToAnother( mInputTextEncoding, mOutputTextEncoding, srcH, destH); ThrowIfOSErr_(status); //line breaks correction ByteCount destLen = ::GetHandleSize(destH); ByteCount destBuffSize = destLen; if(mLineBreak == kLineBreakAutoChange) { TextEncodingBase theBase = ::GetTextEncodingBase(mOutputTextEncoding); if((theBase >= kStandardDOS) && (theBase < kStandardOther)) { destBuffSize = 2*destLen; ::SetHandleSize(destH, destBuffSize ); ThrowIfMemError_(); } StHandleLocker destLock(destH); CConverter::AutoCorrectBreaks( (TextPtr)*destH, destLen, destBuffSize, mOutputTextEncoding); } else { if(mLineBreak == kLineBreakWindows) { destBuffSize = 2*destLen; ::SetHandleSize(destH, destBuffSize ); ThrowIfMemError_(); } StHandleLocker destLock(destH); CConverter::ChangeBreaks( (TextPtr)*destH, destLen, destBuffSize, mOutputTextEncoding, mLineBreak); } if( destLen != ::GetHandleSize(destH) ) {//the buffer may be longer after line break change - cut it now ::SetHandleSize(destH, destLen ); ThrowIfMemError_(); } if( CConverter::IsTwoByteUnicode( mOutputTextEncoding ) ) theType = typeUnicodeText; else theType = typeChar; StHandleLocker destLock(destH); err = ::AECreateDesc(theType, *destH, ::GetHandleSize(destH), &outResult); ThrowIfOSErr_(err); destLock.Release(); return; // } /* //error situation exit (should not happen) StopAlertResID(11, nilHandleErr);//Not enough memory to perform conversion. unsigned char noData = 0; ::AECreateDesc(typeChar, &noData, 0, &outResult); */ } TextEncoding CAppearanceApp::GetEncodingFromAppleEventParam(const AppleEvent& inAppleEvent, AEKeyword inKey) { TextEncoding enc; DescType theType; Size theSize; OSErr err = ::AEGetParamPtr(&inAppleEvent, inKey, typeEnumerated, &theType, &enc, sizeof(long), &theSize); if( err == noErr ) { if(enc == kTextEncodingUnicodeDefault) enc = ::ResolveDefaultTextEncoding(kTextEncodingUnicodeDefault); return enc; } err = ::AEGetParamPtr(&inAppleEvent, inKey, typeLongInteger, &theType, &enc, sizeof(long), &theSize); if( err == noErr) { if(enc == kTextEncodingUnicodeDefault) enc = ::ResolveDefaultTextEncoding(kTextEncodingUnicodeDefault); return enc; } Str255 encInternetName; err = ::AEGetParamPtr(&inAppleEvent, inKey, typeChar, &theType, &(encInternetName[1]), sizeof(Str255)-1, &theSize); if( (err == noErr) && (theSize > 0) && (theSize < 255) ) { encInternetName[0] = (unsigned char)theSize; if(theSize == 6)//check for UTF-16, which is not resolved properly by TECGetTextEncodingFromInternetName { const Str255 utf16Name = "\pUTF-16"; if( 0 == ::RelString( encInternetName, utf16Name, false, true ) )//ignore case, but not diacritical marks { enc = ::ResolveDefaultTextEncoding(kTextEncodingUnicodeDefault); return enc; } } OSStatus status = ::TECGetTextEncodingFromInternetName( &enc, encInternetName); if(status == noErr) { if(enc == kTextEncodingUnicodeDefault) enc = ::ResolveDefaultTextEncoding(kTextEncodingUnicodeDefault); return enc; } } return 0xFFFFFFFF; } void CAppearanceApp::GetLineBreakOptionFromAppleEventParam( const AppleEvent& inAppleEvent, UInt16 &outLineBreak ) { UInt32 lineBreak; DescType theType; Size theSize; OSErr err = ::AEGetParamPtr( &inAppleEvent, 'with', typeEnumerated, &theType, &lineBreak, sizeof(UInt32), &theSize); if( err == noErr ) { outLineBreak = (UInt16)lineBreak; } } #if PP_Target_Carbon void CAppearanceApp::MakeMenuBar() { if(gAquaPresent) { NEW LMenuBar(129); /* // if on X, accomodate Aqua Quit interface LMenuBar* menuBar = LMenuBar::GetCurrentMenuBar(); FailNIL_(menuBar); //remove Quit from file menu LMenu* fileMenu = menuBar->LMenuBar::FetchMenu(129); if(fileMenu != NULL) { fileMenu->RemoveCommand(cmd_Quit); MenuRef menuH = fileMenu->GetMacMenuH(); FailNIL_(menuH); SInt16 totalItems = ::CountMenuItems(menuH); fileMenu->RemoveItem(totalItems);//remove menu separator } */ } else { NEW LMenuBar(MBAR_Initial); } } void CAppearanceApp::UpdateMenus() { LApplication::UpdateMenus(); if(gAquaPresent) {// if on X, take care of prefs and quit enabling if(true) ::EnableMenuCommand (0, kXCommandPreferences); else ::DisableMenuCommand (0, kXCommandPreferences); if(true) ::EnableMenuCommand (0, kXCommandQuit); else ::DisableMenuCommand (0, kXCommandQuit); } } #endif