//************************************************************************************** // Filename: NibEncodingsDialog.cp // Copyright © 2003 _tk_. All rights reserved. // // Description: // //************************************************************************************** // Revision History: // Sunday, August 24, 2003 - Original //************************************************************************************** #include "NibEncodingsDialog.h" #include "ATabControl.h" #include "AControls.h" #include "ACFString.h" #include "CFObjDel.h" #include "CConverter.h" #include extern CyclonePrefs *gPrefs; const TextEncoding sStandardsArr[] = {kStandardMac, kStandardUnicode, kStandardISO, kStandardDOS, kStandardWindows, kStandardOther}; NibEncodingsDialog::NibEncodingsDialog(CFStringRef inNibName, CFStringRef inDlogWindowName) : NibModalDialog(inNibName, inDlogWindowName), mStandardPopup(NULL), mEncodingPopup(NULL), mVariantPopup(NULL), mOutStandardPopup(NULL), mOutEncodingPopup(NULL), mOutVariantPopup(NULL), mLineBreaksPopup(NULL), mCurrentStandardIndx(0), mCurrentEncodingIndx(0), mLineBreaksIndex(0), mOutCurrentStandardIndx(0), mOutCurrentEncodingIndx(0), mDefaultEncoding(kTextEncodingMacRoman) { } NibEncodingsDialog::NibEncodingsDialog(CFBundleRef inBundleRef, CFStringRef inNibName, CFStringRef inDlogWindowName) : NibModalDialog(inBundleRef, inNibName, inDlogWindowName), mStandardPopup(NULL), mEncodingPopup(NULL), mVariantPopup(NULL), mOutStandardPopup(NULL), mOutEncodingPopup(NULL), mOutVariantPopup(NULL), mLineBreaksPopup(NULL), mCurrentStandardIndx(0), mCurrentEncodingIndx(0), mLineBreaksIndex(0), mOutCurrentStandardIndx(0), mOutCurrentEncodingIndx(0), mDefaultEncoding(kTextEncodingMacRoman) { } NibEncodingsDialog::~NibEncodingsDialog(void) { delete mStandardPopup; delete mEncodingPopup; delete mVariantPopup; delete mOutStandardPopup; delete mOutEncodingPopup; delete mOutVariantPopup; delete mLineBreaksPopup; } void NibEncodingsDialog::Setup() { ControlID thePopID = {'Enco', 10}; mStandardPopup = new APopupButton (mWindow, thePopID); thePopID.id = 11; mEncodingPopup = new APopupButton (mWindow, thePopID); thePopID.id = 12; mVariantPopup = new APopupButton (mWindow, thePopID); thePopID.id = 20; mOutStandardPopup = new APopupButton (mWindow, thePopID); thePopID.id = 21; mOutEncodingPopup = new APopupButton (mWindow, thePopID); thePopID.id = 22; mOutVariantPopup = new APopupButton (mWindow, thePopID); thePopID.id = 23; mLineBreaksPopup = new APopupButton (mWindow, thePopID); mCurrentStandardIndx = 1; mCurrentEncodingIndx = 1; MenuRef theMenu = mStandardPopup->Menu(); if(theMenu != NULL) { UInt16 menuItemCount = ::CountMenuItems(theMenu); for(UInt16 i= menuItemCount; i > 0 ; i--) ::CheckMenuItem(theMenu, i, false); } mStandardPopup->SetValue(mCurrentStandardIndx); mOutCurrentStandardIndx = 1; mOutCurrentEncodingIndx = 1; theMenu = mOutStandardPopup->Menu(); if(theMenu != NULL) { UInt16 menuItemCount = ::CountMenuItems(theMenu); for(UInt16 i= menuItemCount; i > 0 ; i--) ::CheckMenuItem(theMenu, i, false); } mOutStandardPopup->SetValue(mOutCurrentStandardIndx); theMenu = mLineBreaksPopup->Menu(); if(theMenu != NULL) { UInt16 menuItemCount = ::CountMenuItems(theMenu); for(UInt16 i= menuItemCount; i > 0 ; i--) ::CheckMenuItem(theMenu, i, false); } mLineBreaksIndex = kLineBreakNoChange; mLineBreaksPopup->SetValue(mLineBreaksIndex); if( (gPrefs->flags & kExplicitLineBreakChange) == 0 ) {//auto or no change - hide item mLineBreaksPopup->Hide(); ControlID labelID = {'Enco', 24}; AControl theLabel(mWindow, labelID); theLabel.Hide(); } mDefaultEncoding = ::ResolveDefaultTextEncoding(kTextEncodingMacRoman); mEncodingVariantArr.SetKeepSorted(true);//keep sorted - use standard long comparator mOutEncodingVariantArr.SetKeepSorted(true);//keep sorted - use standard long comparator EncodingChanged(kInput, true); EncodingChanged(kOutput, true); if( (gPrefs->flags & kExplicitLineBreakChange) != 0 ) {//only when explicit //disable PS for non-Unicode encodings MenuRef macMenuH = mLineBreaksPopup->Menu(); if(macMenuH != NULL) { TextEncoding enc = GetEncoding(kOutput); TextEncodingBase theBase = ::GetTextEncodingBase(enc); if( (theBase >= kStandardUnicode) && (theBase < kStandardISO) ) {//when Unicode ::EnableMenuItem( macMenuH, 5 ); } else {//not unicode if( mLineBreaksPopup->Value() == kLineBreakUnicode) { mLineBreaksIndex = kLineBreakNoChange; mLineBreaksPopup->SetValue(mLineBreaksIndex); } ::DisableMenuItem( macMenuH, 5 ); } } } } //returns noErr if command handled otherwise should return eventNotHandledErr OSStatus NibEncodingsDialog::ProcessCommand() { OSStatus outErr = eventNotHandledErr; switch (mCommand.commandID) { case 'EStd': StandardChanged(kInput); break; case 'ESt1': StandardChanged(kOutput); break; case 'Enco': EncodingChanged(kInput); break; case 'Enc1': EncodingChanged(kOutput); break; case 'LnBr': mLineBreaksIndex = mLineBreaksPopup->Value(); } return outErr; } void NibEncodingsDialog::SetInitialDialogOptions(TextEncoding inputTextEnc, TextEncoding outputTextEnc, UInt16 inLineBreak, CFStringRef inFileName) { if(mWindow == NULL) return; Setup(); const ControlID fileNameID = {'Enco', 3}; AStaticText fileName(mWindow, fileNameID); if(inFileName == NULL) inFileName = CFSTR("Unknown"); fileName.SetText(inFileName); SetDefaultEncoding(kInput, inputTextEnc); SetDefaultEncoding(kOutput, outputTextEnc); SetLineBreak(inLineBreak); } void NibEncodingsDialog::GetClosingDialogOptions(TextEncoding &outInputTextEnc, TextEncoding &outOutputTextEnc, UInt16 &outLineBreak) { outInputTextEnc = GetEncoding(kInput); outOutputTextEnc = GetEncoding(kOutput); outLineBreak = GetLineBreak(); } TextEncoding NibEncodingsDialog::GetEncoding(UInt32 inSelector) { TArray &array = (inSelector == kInput) ? mEncodingVariantArr : mOutEncodingVariantArr; APopupButton *popup = (inSelector == kInput) ? mVariantPopup : mOutVariantPopup; TextEncoding outEnc; array.FetchItemAt( popup->Value(), outEnc); return outEnc; } void NibEncodingsDialog::StandardChanged(UInt32 inSelector) { APopupButton *popup = (inSelector == kInput) ? mStandardPopup : mOutStandardPopup; SInt32 *currIndexPtr = (inSelector == kInput) ? &mCurrentStandardIndx : &mOutCurrentStandardIndx; SInt32 newValue = popup->Value(); if(newValue != *currIndexPtr) { *currIndexPtr = newValue; EncodingChanged(inSelector, true); if( (inSelector == kOutput) && ((gPrefs->flags & kExplicitLineBreakChange) != 0) ) { MenuRef macMenuH = mLineBreaksPopup->Menu(); if(macMenuH != NULL) { TextEncoding enc = GetEncoding(kOutput); TextEncodingBase theBase = ::GetTextEncodingBase(enc); if( (theBase >= kStandardUnicode) && (theBase < kStandardISO) ) { ::EnableMenuItem( macMenuH, 5 ); } else { if( mLineBreaksPopup->Value() == kLineBreakUnicode) { mLineBreaksIndex = kLineBreakNoChange; mLineBreaksPopup->SetValue(mLineBreaksIndex); } ::DisableMenuItem( macMenuH, 5 ); } } } } } void NibEncodingsDialog::EncodingChanged(UInt32 inSelector, Boolean inForceRebulid) { CEncodingArray &baseArr = (inSelector == kInput) ? mEncodingBaseArr : mOutEncodingBaseArr; TArray &varArr = (inSelector == kInput) ? mEncodingVariantArr : mOutEncodingVariantArr; APopupButton *encPop = (inSelector == kInput) ? mEncodingPopup : mOutEncodingPopup; APopupButton *varPop = (inSelector == kInput) ? mVariantPopup : mOutVariantPopup; SInt32 *currIndexPtr = (inSelector == kInput) ? &mCurrentEncodingIndx : &mOutCurrentEncodingIndx; ArrayIndexT index = LArray::index_Bad; if(inForceRebulid) { RebuildEncodings(inSelector); ResolveDefaultEncoding(inSelector, 1); index = baseArr.FetchIndexByEncodingBase( mDefaultEncoding );//we are interested in base only if(index == LArray::index_Bad) index = 1;//if something goes wrong - set to the first item *currIndexPtr = index; encPop->SetValue(index); RebuildVariants(inSelector); } else { SInt32 newValue = encPop->Value(); if(newValue != *currIndexPtr) { *currIndexPtr = newValue; RebuildVariants(inSelector); ResolveDefaultEncoding(inSelector, *currIndexPtr ); } } index = varArr.FetchIndexOf( mDefaultEncoding ); if(index == LArray::index_Bad) index = 1;//if something goes wrong - set to the first item varPop->SetValue(index); } void NibEncodingsDialog::RebuildEncodings(UInt32 inSelector) { CEncodingArray &baseArr = (inSelector == kInput) ? mEncodingBaseArr : mOutEncodingBaseArr; APopupButton *encPop = (inSelector == kInput) ? mEncodingPopup : mOutEncodingPopup; SInt32 *currStdIndexPtr = (inSelector == kInput) ? &mCurrentStandardIndx : &mOutCurrentStandardIndx; // LArray *allEncArray = (inSelector == kInput) ? CConverter::sAllTextEncodingsArr : mAllPossibleDestArr; LArray *allEncArray = CConverter::sAllTextEncodingsArr; if(allEncArray == nil) return; UInt32 start, end; CConverter::GetSpecifiedEncodingsRange(allEncArray, sStandardsArr[*currStdIndexPtr - 1], start, end); if( (start == 0) && (end == 0) ) return; //delete from array if( baseArr.GetCount() > 0 ) baseArr.RemoveAllItemsAfter(0); //delete from menu MenuRef theMenuH = encPop->Menu(); short itemCnt = ::CountMenuItems( theMenuH ); if(itemCnt > 0) { for(short i= itemCnt; i > 0 ; i--) ::DeleteMenuItem( theMenuH, i ); } TextEncodingBase previousEncodingBase = 0xFFFFFFFF;//make sure the first item is different TextEncodingBase currEncBase; TextEncoding textEnc; UInt32 j = 1; for(UInt32 i = start; i<=end; i++)//take encodings from the range and put them one by one into array { //but skip encodings with the same base (take first encoding in the block) allEncArray->FetchItemAt( i, &textEnc); currEncBase = ::GetTextEncodingBase(textEnc); if( currEncBase != previousEncodingBase ) { //add to array previousEncodingBase = currEncBase; ArrayIndexT currIndx = baseArr.AddEncoding( textEnc );//must add real encoding, not base only } } for(UInt32 j = 1; j <= baseArr.GetCount(); j++) { //add to menu ::MacInsertMenuItem(theMenuH, "\px", j-1); Str255 encodingName; if( baseArr.FetchEncNameAt(j, encodingName) ) { ::SetMenuItemText(theMenuH, (SInt16) j, encodingName ); } else { SignalStringLiteral_( "Could not fetch encoding name" ); } } encPop->SetMinValue(1); encPop->SetMaxValue( ::CountMenuItems( theMenuH ) ); } void NibEncodingsDialog::RebuildVariants(UInt32 inSelector) { CEncodingArray &baseArr = (inSelector == kInput) ? mEncodingBaseArr : mOutEncodingBaseArr; TArray &varArr = (inSelector == kInput) ? mEncodingVariantArr : mOutEncodingVariantArr; APopupButton *encPop = (inSelector == kInput) ? mEncodingPopup : mOutEncodingPopup; APopupButton *varPop = (inSelector == kInput) ? mVariantPopup : mOutVariantPopup; // SInt32 *currEncIndexPtr = (inSelector == kInput) ? &mCurrentEncodingIndx : &mOutCurrentEncodingIndx; // LArray *allEncArray = (inSelector == kInput) ? CConverter::sAllTextEncodingsArr : mAllPossibleDestArr; LArray *allEncArray = CConverter::sAllTextEncodingsArr; if(allEncArray == nil) return; //delete from array if( varArr.GetCount() > 0 ) varArr.RemoveAllItemsAfter(0); //delete from menu MenuRef theMenuH = varPop->Menu(); short itemCnt = ::CountMenuItems( theMenuH ); if(itemCnt > 0) { for(short i= itemCnt; i > 0 ; i--) ::DeleteMenuItem( theMenuH, i ); } SInt32 indx = encPop->Value(); TextEncoding textEnc; if( ! baseArr.FetchEncValueAt(indx, &textEnc) ) return; ArrayIndexT foundEncIndx = allEncArray->FetchIndexOf( &textEnc ); Assert_(foundEncIndx != LArray::index_Bad); TextEncodingBase theBase = ::GetTextEncodingBase( textEnc ); //search down and up indx = foundEncIndx; do { varArr.AddItem( textEnc ); indx--; allEncArray->FetchItemAt( indx, &textEnc); } while( (indx > 0) && (::GetTextEncodingBase( textEnc ) == theBase) ); indx = foundEncIndx + 1; allEncArray->FetchItemAt( indx, &textEnc); UInt32 allEncoCount = allEncArray->GetCount(); while( (indx <= allEncoCount) && (::GetTextEncodingBase( textEnc ) == theBase) ) { varArr.AddItem( textEnc ); indx++; allEncArray->FetchItemAt( indx, &textEnc); } //add to menu for(UInt32 j = 1; j <= varArr.GetCount(); j++) { ::MacInsertMenuItem(theMenuH, "\px", j-1); Str255 variantName, formatName; TextEncoding currEncoding = *(varArr.FetchItemPtr(j)); CConverter::GetEncodingName( currEncoding, kTextEncodingFormatName, formatName ); CConverter::GetEncodingName( currEncoding, kTextEncodingVariantName, variantName ); LStringRef theStr( sizeof(Str255), formatName); if(formatName[0] != 0 && variantName[0] != 0) theStr += ' '; theStr += variantName; if(formatName[0] == 0) { TextEncodingVariant theVar = ::GetTextEncodingVariant( currEncoding ); if(theVar == kTextEncodingDefaultVariant) ::GetIndString(formatName, rMiscStrings, 18); else theStr = (SInt32) j;//assign number } ::SetMenuItemText(theMenuH, (SInt16) j, formatName ); } short itemsCount = ::CountMenuItems( theMenuH ); varPop->SetMaxValue(1); varPop->SetMaxValue( itemsCount ); if(itemsCount < 2 ) varPop->Disable(); else varPop->Enable(); } void NibEncodingsDialog::ResolveDefaultEncoding(UInt32 inSelector, ArrayIndexT index) { CEncodingArray &baseArr = (inSelector == kInput) ? mEncodingBaseArr : mOutEncodingBaseArr; TextEncoding textEnc; if( ! baseArr.FetchEncValueAt(index, &textEnc) ) return; TextEncodingBase currEncBase = ::GetTextEncodingBase(textEnc); if( (currEncBase >= kStandardUnicode) && (currEncBase < kStandardISO) )//special case for Unicode to make it default correctly mDefaultEncoding = ::ResolveDefaultTextEncoding( kTextEncodingUnicodeDefault ); else mDefaultEncoding = ::ResolveDefaultTextEncoding( currEncBase ); } void NibEncodingsDialog::SetDefaultEncoding(UInt32 inSelector, TextEncoding textEnc) { CEncodingArray &baseArr = (inSelector == kInput) ? mEncodingBaseArr : mOutEncodingBaseArr; TArray &varArr = (inSelector == kInput) ? mEncodingVariantArr : mOutEncodingVariantArr; APopupButton *stdPop = (inSelector == kInput) ? mStandardPopup : mOutStandardPopup; APopupButton *encPop = (inSelector == kInput) ? mEncodingPopup : mOutEncodingPopup; APopupButton *varPop = (inSelector == kInput) ? mVariantPopup : mOutVariantPopup; //resolve default values if any TextEncoding resolvedEnc; if( (::GetTextEncodingVariant( textEnc ) == kTextEncodingDefaultVariant) || (::GetTextEncodingFormat( textEnc ) == kTextEncodingDefaultFormat)) resolvedEnc = ::ResolveDefaultTextEncoding( textEnc ); else resolvedEnc = textEnc; //check if we have to change standard to set default: TextEncodingBase theBase = ::GetTextEncodingBase(resolvedEnc); ArrayIndexT newIndex = 0; if(theBase >= kStandardMac && theBase < kStandardUnicode) newIndex = 1; else if(theBase >= kStandardUnicode && theBase < kStandardISO) newIndex = 2; else if(theBase >= kStandardISO && theBase < kStandardDOS) newIndex = 3; else if(theBase >= kStandardDOS && theBase < kStandardWindows) newIndex = 4; else if(theBase >= kStandardWindows && theBase < kStandardOther) newIndex = 5; else if(theBase >= kStandardOther && theBase < 0xFFFF) newIndex = 6; if(newIndex == 0)//wrong value - return without changing anything return; stdPop->SetValue(newIndex); StandardChanged(inSelector); //now we assume that standard is set and encodigs are rebuilt - now set the encoding newIndex = baseArr.FetchIndexByEncodingBase( resolvedEnc ); if(newIndex != LArray::index_Bad) { encPop->SetValue(newIndex); EncodingChanged(inSelector); //now we assume that te encoding is changed and variants are rebuilt newIndex = varArr.FetchIndexOf( resolvedEnc ); if(newIndex != LArray::index_Bad) varPop->SetValue(newIndex); } } void NibEncodingsDialog::SetLineBreak(UInt16 inLineBreaksIndex) { if(inLineBreaksIndex == kLineBreakAutoChange) inLineBreaksIndex = kLineBreakNoChange; if( (gPrefs->flags & kExplicitLineBreakChange) != 0 ) {//explicit breaks if( inLineBreaksIndex == kLineBreakUnicode ) { TextEncoding enc = GetEncoding(kOutput); TextEncodingBase theBase = ::GetTextEncodingBase(enc); if( (theBase < kStandardUnicode) || (theBase >= kStandardISO) )//not unicode inLineBreaksIndex = kLineBreakNoChange; } mLineBreaksIndex = inLineBreaksIndex; mLineBreaksPopup->SetValue(mLineBreaksIndex); } else { mLineBreaksIndex = kLineBreakNoChange; mLineBreaksPopup->SetValue(mLineBreaksIndex);//when no line break or automatic line break } } UInt16 NibEncodingsDialog::GetLineBreak() { if( (gPrefs->flags & kAutoChangeLineBreaks) != 0 ) return kLineBreakAutoChange; return (UInt16)mLineBreaksIndex; }