home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / utility / UMailFolderMenus.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  43.1 KB  |  1,343 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*======================================================================================
  20.     AUTHOR:            Ted Morris <tmorris@netscape.com> - 12 DEC 96
  21.  
  22.     MODIFICATIONS:
  23.  
  24.     Date            Person            Description
  25.     ----            ------            -----------
  26. ======================================================================================*/
  27.  
  28.  
  29. /*====================================================================================*/
  30.     #pragma mark INCLUDE FILES
  31. /*====================================================================================*/
  32.  
  33. #include "UMailFolderMenus.h"
  34. #include "CMailNewsContext.h"
  35. #include "PascalString.h"
  36. #include "CMessageFolderView.h"
  37. #include "CMailFolderButtonPopup.h"
  38.  
  39. #include "StSetBroadcasting.h"
  40. #include "miconutils.h"
  41. #include "MercutioAPI.h"
  42. #include "UMenuUtils.h"
  43. #include "CMessageFolder.h"
  44.  
  45. #pragma mark -
  46. /*====================================================================================*/
  47.     #pragma mark TYPEDEFS
  48. /*====================================================================================*/
  49.  
  50.  
  51. #pragma mark -
  52. /*====================================================================================*/
  53.     #pragma mark CONSTANTS
  54. /*====================================================================================*/
  55.  
  56. static const UInt16 cFolderPopupFlags = MSG_FOLDER_FLAG_MAIL;
  57. static const UInt8 cSpaceFolderMenuChar = 0x09;
  58. static const ResIDT cMenuIconIDDiff = 256;
  59. static const Int16 cItemIdentWidth = 16;
  60.  
  61. #pragma mark -
  62. /*====================================================================================*/
  63.     #pragma mark INTERNAL FUNCTION PROTOTYPES
  64. /*====================================================================================*/
  65.  
  66.  
  67. #pragma mark -
  68. /*====================================================================================*/
  69.     #pragma mark INTERNAL CLASS DECLARATIONS
  70. /*====================================================================================*/
  71.  
  72. #pragma mark -
  73. /*====================================================================================*/
  74.     #pragma mark CLASS IMPLEMENTATIONS
  75. /*====================================================================================*/
  76.  
  77. // Static class members
  78.  
  79. LArray CMailFolderMixin::sMailFolderMixinRegisterList;
  80. Boolean CMailFolderMixin::sMustRebuild = true;
  81. void* CMailFolderMixin::sMercutioCallback = nil;
  82.  
  83. //-----------------------------------
  84. CMailFolderMixin::CMailFolderMixin(Boolean inIncludeFolderIcons)
  85. :    mFolderArray(sizeof(CMessageFolder))
  86. ,    mDesiredFolderFlags((FolderChoices)(eWantPOP + eWantIMAP))
  87. ,    mInitialMenuCount(0)
  88. //-----------------------------------
  89. {
  90.  
  91.     mUseFolderIcons = inIncludeFolderIcons;
  92.     RegisterMailFolderMixin(this);
  93. } // CMailFolderMixin::CMailFolderMixin
  94.  
  95. //-----------------------------------
  96. CMailFolderMixin::~CMailFolderMixin()
  97. //-----------------------------------
  98. {
  99.     UnregisterMailFolderMixin(this);
  100.     // Delete all the CMessageFolder objects, or else we'll leak the cache!
  101.     for (ArrayIndexT i = 1; i <= mFolderArray.GetCount(); i++)
  102.     {
  103.         CMessageFolder* f = (CMessageFolder*)mFolderArray.GetItemPtr(i);
  104.         if (f)
  105.             (*(CMessageFolder*)mFolderArray.GetItemPtr(i)).CMessageFolder::~CMessageFolder();
  106.     }
  107. } // CMailFolderMixin::~CMailFolderMixin
  108.  
  109. //-----------------------------------
  110. void CMailFolderMixin::UpdateMailFolderMixins()
  111. //-----------------------------------
  112. {
  113.     sMustRebuild = true;
  114.     LCommander::SetUpdateCommandStatus(true);
  115. } // CMailFolderMixin::UpdateMailFolderMixins
  116.  
  117. //-----------------------------------
  118. void CMailFolderMixin::UpdateMailFolderMixinsNow(CMailFolderMixin *inSingleMailFolderMixin)
  119. //    Notify all registered CMailFolderMixin objects that the mail folder list has changed.
  120. //    This method should be called whenever the list changes, fo example, when the user
  121. //    adds, moves, or deletes mail folders in the Folder View window.
  122. //    
  123. //    If inSingleMailFolderMixin is not nil, only that specific CMailFolderMixin is 
  124. //    notified of the change, NOT all CMailFolderMixin objects.
  125. //    
  126. //    IMPORTANT NOTE: CMailFolderMixin::UpdateMailFolderMixinsNow(this) needs to be called
  127. //    for all subclasses after initialization is complete.
  128. //-----------------------------------
  129. {
  130.  
  131.     if (!sMustRebuild && inSingleMailFolderMixin == nil)
  132.         return;
  133.     if (sMailFolderMixinRegisterList.GetCount() == 0 && inSingleMailFolderMixin == nil)
  134.         return;    // No reason to do anything!
  135.     
  136.     MSG_Master *master = CMailNewsContext::GetMailMaster();
  137.     FailNIL_(master);
  138.     
  139.     // Get a list and count of all current mail folders. You can only ask for one flag
  140.     // at a time (ALL bits must match for positive test in this call).    
  141.     Int32 numFoldersMail = ::MSG_GetFoldersWithFlag(master, MSG_FOLDER_FLAG_MAIL, nil, 0);
  142.     Assert_(numFoldersMail > 0);    // Should have at least some permanent mail folders!
  143.     Int32 numNewsgroups = 0;
  144.     Int32 numNewsHosts = 0;
  145.     if (
  146.         !inSingleMailFolderMixin
  147.     || (inSingleMailFolderMixin->mDesiredFolderFlags & (eWantNews|eWantHosts))
  148.             == (eWantNews|eWantHosts)
  149.         )
  150.         numNewsHosts = ::MSG_GetFoldersWithFlag(master, MSG_FOLDER_FLAG_NEWS_HOST, nil, 0);
  151.     if (!inSingleMailFolderMixin
  152.     || (inSingleMailFolderMixin->mDesiredFolderFlags & eWantNews) != 0)
  153.         numNewsgroups = ::MSG_GetFoldersWithFlag(master, MSG_FOLDER_FLAG_NEWSGROUP|MSG_FOLDER_FLAG_SUBSCRIBED, nil, 0);
  154.  
  155.     Int32 numFolders = numFoldersMail + numNewsgroups + numNewsHosts;    
  156.     StPointerBlock folderInfoData(sizeof(MSG_FolderInfo *) * numFolders);
  157.     MSG_FolderInfo **folderInfo = (MSG_FolderInfo **) folderInfoData.mPtr;
  158.     
  159.     Int32 numFolders2 = ::MSG_GetFoldersWithFlag(master, MSG_FOLDER_FLAG_MAIL, folderInfo, numFoldersMail);
  160.     Assert_(numFolders2 > 0);    // Should have at least some permanent mail folders!
  161.     Assert_(numFolders2 == numFoldersMail);
  162.     
  163.     // Handle the news hosts and groups, filling in the remaining pointers in the array.
  164.     MSG_FolderInfo** currentInfo = folderInfo + numFoldersMail;
  165.     if (numNewsHosts && numNewsgroups)
  166.     {
  167.         // The difficult case.
  168.         // Get the list of hosts and the list of groups into separate lists.
  169.         StPointerBlock newsHostInfoData(sizeof(MSG_FolderInfo *) * numNewsHosts);
  170.         MSG_FolderInfo **newsHostInfo = (MSG_FolderInfo **) newsHostInfoData.mPtr;
  171.         numFolders2 = ::MSG_GetFoldersWithFlag(
  172.             master,
  173.             MSG_FOLDER_FLAG_NEWS_HOST,
  174.             newsHostInfo,
  175.             numNewsHosts);
  176.         Assert_(numFolders2 == numNewsHosts);
  177.         
  178.         StPointerBlock newsgroupInfoData(sizeof(MSG_FolderInfo *) * numNewsgroups);
  179.         MSG_FolderInfo **newsgroupInfo = (MSG_FolderInfo **) newsgroupInfoData.mPtr;
  180.         numFolders2 = ::MSG_GetFoldersWithFlag(
  181.             master,
  182.             MSG_FOLDER_FLAG_NEWSGROUP|MSG_FOLDER_FLAG_SUBSCRIBED,
  183.             newsgroupInfo,
  184.             numNewsgroups);
  185.         Assert_(numFolders2 == numNewsgroups);
  186.         
  187.         // Loop over the hosts, copying one host, then all its groups
  188.         if (numNewsHosts)
  189.         {
  190.             for (int i = 0; i < numNewsHosts; i++)
  191.             {
  192.                 // Copy over all the news groups for this host
  193.                 *currentInfo++ = newsHostInfo[i];
  194.                 for (int j = 0; j < numNewsgroups; j++)
  195.                 {
  196.                     // Are the two hosts the same?
  197.                     if (::MSG_GetHostForFolder(newsgroupInfo[j])
  198.                         == ::MSG_GetHostForFolder(newsHostInfo[i]))
  199.                     {
  200.                         *currentInfo++ = newsgroupInfo[j];
  201.                     }        
  202.                 } // inner loop
  203.             } // outer loop
  204.         }
  205.     }
  206.     else if (numNewsgroups)
  207.     {
  208.         numFolders2 = ::MSG_GetFoldersWithFlag(
  209.             master,
  210.             MSG_FOLDER_FLAG_NEWSGROUP|MSG_FOLDER_FLAG_SUBSCRIBED,
  211.             currentInfo,
  212.             numNewsgroups);
  213.     }
  214.     else if (numNewsHosts)
  215.     {
  216.         numFolders2 = ::MSG_GetFoldersWithFlag(
  217.             master,
  218.             MSG_FOLDER_FLAG_NEWS_HOST,
  219.             currentInfo,
  220.             numNewsHosts);
  221.     }
  222.     // Notify all registered CMailFolderMixin objects, or only the specified object
  223.     if ( inSingleMailFolderMixin == nil )
  224.     {
  225.         LArrayIterator iterator(sMailFolderMixinRegisterList);
  226.         while ( iterator.Next(&inSingleMailFolderMixin) )
  227.             inSingleMailFolderMixin->MPopulateWithFolders(folderInfo, numFolders);
  228.         sMustRebuild = false;
  229.     }
  230.     else
  231.         inSingleMailFolderMixin->MPopulateWithFolders(folderInfo, numFolders);
  232. } // CMailFolderMixin::UpdateMailFolderMixinsNow
  233.  
  234. //-----------------------------------
  235. Boolean CMailFolderMixin::MSetSelectedFolderName(
  236.     const char *inName,
  237.     Boolean inDoBroadcast)
  238. //    Set the currently selected item in the menu to the item represented by inName. If
  239. //    inName is nil, empty, or cannot be found, the value of the menu is set to 0.
  240. //    Return true if the specified folder name was found in the menu.
  241. //-----------------------------------
  242. {
  243.     const ArrayIndexT numItems = mFolderArray.GetCount();
  244.     ArrayIndexT curIndex;
  245.     if ( !inName || !*inName)
  246.         curIndex = numItems + 1;
  247.     else
  248.     {
  249.         for (curIndex = 1; curIndex <= numItems; ++curIndex)
  250.         {
  251.             const char* itemPath = MGetFolderName(curIndex);
  252.             if ( ::strcasecomp(inName, itemPath) == 0 )
  253.                 break;
  254.         }
  255.     }
  256.  
  257.     if ( curIndex <= numItems )
  258.     {
  259.         MSetSelectedMenuItem(curIndex, inDoBroadcast);
  260.         return true;
  261.     }
  262.     else
  263.     {
  264.         MSetSelectedMenuItem(0, inDoBroadcast);
  265.         return false;
  266.     }
  267. }
  268.  
  269. //-----------------------------------
  270. Boolean CMailFolderMixin::MSetSelectedFolder(
  271.     const CMessageFolder& inFolder,
  272.     Boolean /*inDoBroadcast*/)
  273. //-----------------------------------
  274. {
  275.     return MSetSelectedFolder(inFolder.GetFolderInfo());
  276. }
  277.  
  278. //-----------------------------------
  279. Boolean CMailFolderMixin::MSetSelectedFolder(
  280.     const MSG_FolderInfo* inInfo,
  281.     Boolean inDoBroadcast)
  282. //-----------------------------------
  283. {
  284.     const ArrayIndexT numItems = mFolderArray.GetCount();
  285.     Assert_(mFolderArray.GetCount() == (MGetNumMenuItems() - mInitialMenuCount));
  286.         // Not synced otherwise    
  287.     ArrayIndexT curIndex;
  288.     if (inInfo == nil)
  289.         curIndex = numItems + 1;
  290.     else
  291.     {
  292.         mFolderArray.Lock();
  293.         for (curIndex = 1; curIndex <= numItems; ++curIndex)
  294.         {
  295.             CMessageFolder* curFolder = (CMessageFolder*)mFolderArray.GetItemPtr(curIndex);
  296.             if (inInfo == curFolder->GetFolderInfo())
  297.                 break;
  298.         }
  299.         mFolderArray.Unlock();
  300.     }
  301.  
  302.     if ( curIndex <= numItems )
  303.     {
  304.         MSetSelectedMenuItem(curIndex, inDoBroadcast);
  305.         return true;
  306.     }
  307.     else
  308.     {
  309.         MSetSelectedMenuItem(0, inDoBroadcast);
  310.         return false;
  311.     }
  312. }
  313.  
  314. //-----------------------------------
  315. const char* CMailFolderMixin::MGetFolderName(ArrayIndexT inItemNumber)
  316. //    Get the currently selected folder name in the menu. Return a reference to head of 
  317. //    the returned c-string.
  318. //-----------------------------------
  319. {
  320.     CMessageFolder folder = MGetFolder(inItemNumber);
  321.     MSG_FolderInfo* info = folder.GetFolderInfo();
  322.     if (info)
  323.     {
  324.         const char * str = ::MSG_GetFolderNameFromID(info);
  325.  
  326.         // Make sure that the name is fully escaped
  327.         static char escapedName[256];
  328.         XP_STRCPY(escapedName, str);
  329.         NET_UnEscape(escapedName);
  330.         char * temp = NET_Escape(escapedName, URL_PATH);
  331.         if (temp)
  332.         {
  333.             XP_STRCPY(escapedName, temp);
  334.             XP_FREE(temp);
  335.         }
  336.         return escapedName;
  337.     }
  338.     return nil;
  339. }
  340.  
  341.  
  342. //-----------------------------------
  343. const char* CMailFolderMixin::MGetSelectedFolderName()
  344. //    Get the currently selected folder name in the menu. Return a reference to head of 
  345. //    the returned c-string.
  346. //-----------------------------------
  347. {
  348.     ArrayIndexT index = MGetSelectedMenuItem();
  349.     if (index)
  350.         return MGetFolderName(index);
  351.     return nil;
  352. }
  353.  
  354. //-----------------------------------
  355. CMessageFolder CMailFolderMixin::MGetFolder(ArrayIndexT inItemNumber)
  356. //-----------------------------------
  357. {
  358.     CMessageFolder result(nil);
  359.     Assert_(mFolderArray.GetCount() == (MGetNumMenuItems() - mInitialMenuCount));    // Not synced otherwise
  360.     if ( (mFolderArray.GetCount() > 0) && (inItemNumber > 0) )
  361.     {
  362.         if ( mFolderArray.ValidIndex(inItemNumber) )
  363.         {
  364.             mFolderArray.Lock();
  365.             result = *(CMessageFolder*) mFolderArray.GetItemPtr(inItemNumber);
  366.             mFolderArray.Unlock();
  367.         }
  368.     }
  369.     return result;
  370. }
  371.  
  372. //-----------------------------------
  373. CMessageFolder CMailFolderMixin::MGetFolderFromMenuItem(ArrayIndexT inItemNumber)
  374. //-----------------------------------
  375. {
  376.     // convert the menu item number in to an index into the folder array
  377.     CMessageFolder result(nil);
  378.     if (inItemNumber - mInitialMenuCount > 0)
  379.     {    // If (inItemNumber - mInitialMenuCount) is 0 or less then we are trying to
  380.         // find folder info on a previously existing menu item.
  381.         result = MGetFolder(inItemNumber - mInitialMenuCount);
  382.     }
  383.     return result;
  384. }
  385.  
  386.  
  387. //-----------------------------------
  388. CMessageFolder CMailFolderMixin::MGetSelectedFolder()
  389. //-----------------------------------
  390. {
  391.     return MGetFolder(MGetSelectedMenuItem());
  392. }
  393.  
  394. //-----------------------------------
  395. ResIDT CMailFolderMixin::GetMailFolderIconID(UInt16 inFlags)
  396. //-----------------------------------
  397. {
  398.  
  399.     if ((inFlags & MSG_FOLDER_FLAG_MAIL) != 0)
  400.         return 0;
  401.     UInt16 folderType = inFlags & (
  402.         MSG_FOLDER_FLAG_TRASH | MSG_FOLDER_FLAG_SENTMAIL | 
  403.         MSG_FOLDER_FLAG_DRAFTS | MSG_FOLDER_FLAG_QUEUE |
  404.         MSG_FOLDER_FLAG_INBOX
  405.         );
  406.     switch ( folderType )
  407.     {    
  408.         case MSG_FOLDER_FLAG_TRASH:        return 286;
  409.         case MSG_FOLDER_FLAG_SENTMAIL:    return 284;
  410.         case MSG_FOLDER_FLAG_DRAFTS:    return 285;
  411.         case MSG_FOLDER_FLAG_QUEUE:        return 283;
  412.         case MSG_FOLDER_FLAG_INBOX:        return 282;
  413.         default:
  414.             if ( inFlags & MSG_FOLDER_FLAG_IMAPBOX )
  415.                 return 287;    // Online folder?
  416.             return 281;
  417.     }    
  418. }
  419.  
  420. /*======================================================================================
  421.     Register the specified inMailFolderMixin so that it is automatically notified
  422.     when changes are made to the mail folder list. The specified inMailFolderMixin
  423.     is only added to the list if it is not already there.
  424. ======================================================================================*/
  425.  
  426. void CMailFolderMixin::RegisterMailFolderMixin(CMailFolderMixin *inMailFolderMixin) {
  427.  
  428.     Assert_(inMailFolderMixin != nil);
  429.  
  430.     if ( sMailFolderMixinRegisterList.FetchIndexOf(&inMailFolderMixin) == LArray::index_Bad ) {
  431.         sMailFolderMixinRegisterList.InsertItemsAt(1, LArray::index_Last, &inMailFolderMixin);
  432.     }
  433. }
  434.  
  435.  
  436.  
  437. /*======================================================================================
  438.     Unregister the specified inMailFolderMixin so that it is no longer notified
  439.     when changes are made to the mail folder list. If the specified inMailFolderMixin
  440.     is not in the list, this method does nothing.
  441. ======================================================================================*/
  442.  
  443. void CMailFolderMixin::UnregisterMailFolderMixin(CMailFolderMixin *inMailFolderMixin) {
  444.  
  445.     sMailFolderMixinRegisterList.Remove(&inMailFolderMixin);
  446. }
  447.  
  448. //-----------------------------------
  449. void CMailFolderMixin::MGetCurrentMenuItemName(Str255 outItemName)
  450. //    Get the name of the menu item that is currently selected, minus any indentation.
  451. //-----------------------------------
  452. {
  453.     outItemName[0] = 0;
  454.     MGetMenuItemName(MGetSelectedMenuItem(), outItemName);
  455.     if ( outItemName[0] != 0 )
  456.     {
  457.         UInt8 *curChar = &outItemName[1], *endChar = curChar + outItemName[0];
  458.         do
  459.         {
  460.             if ( *curChar != cSpaceFolderMenuChar ) break;
  461.         } while ( ++curChar < endChar );
  462.  
  463.         Int8 numLeading = curChar - (&outItemName[1]);
  464.         
  465.         if ( numLeading != 0 )
  466.         {
  467.             outItemName[0] -= numLeading;
  468.             if ( outItemName[0] != 0 )
  469.             {
  470.                 ::BlockMoveData(&outItemName[numLeading + 1], &outItemName[1], outItemName[0]);
  471.             }
  472.         }
  473.     }
  474. } // CMailFolderMixin::MGetCurrentMenuItemName
  475.  
  476. //-----------------------------------
  477. Boolean CMailFolderMixin::FolderFilter(const CMessageFolder& folder)
  478. //    Return true iff you want this folder included in the list. This function should
  479. //    handle all known cases, but we may want to make this virtual and override it in the
  480. //    future.
  481. //-----------------------------------
  482. {
  483.     Boolean    result;
  484.  
  485.     if (folder.GetLevel() > 1)
  486.     {
  487.         UInt32    folderFlags = folder.GetFolderFlags();
  488.         Boolean    isPOP, isIMAP, isNews;
  489.  
  490.         isNews = folderFlags & MSG_FOLDER_FLAG_NEWSGROUP ? true: false;
  491.         isIMAP = folderFlags & MSG_FOLDER_FLAG_IMAPBOX ? true: false;
  492.         isPOP = (!isIMAP && (folderFlags & MSG_FOLDER_FLAG_MAIL)) ? true: false;
  493.  
  494.         if (isPOP && (mDesiredFolderFlags & eWantPOP))
  495.         {
  496.             result = true;
  497.         }
  498.         else if (isIMAP && (mDesiredFolderFlags & eWantIMAP))
  499.         {
  500.             result = true;
  501.         }
  502.         else if (isNews && (mDesiredFolderFlags & eWantNews))
  503.         {
  504.             result = true;
  505.         }
  506.         else
  507.         {
  508.             result = false;
  509.         }
  510.     }
  511.     else
  512.     {
  513.         // level <= 1, we are filtering a host/ server.
  514.         result = (mDesiredFolderFlags & eWantHosts) != 0;
  515.     }
  516.  
  517.     return result;
  518. } // CMailFolderMixin::FolderFilter
  519.  
  520. //-----------------------------------
  521. pascal void MyMercutioCallback(
  522.     Int16                    menuID,
  523.     Int16                    /*previousModifiers*/,
  524.     RichItemDataYadaYada&    inItemData)
  525. //-----------------------------------
  526. {
  527.     // This function is called continuously when the user clicks the 
  528.     // folder popup in a Thread window. Static variables have been added
  529.     // for performance reasons.
  530.  
  531.     RichItemData& itemData = (RichItemData&)inItemData;
  532.     itemData.flags &= ~kChangedByCallback; // clear bit
  533.  
  534.     // Find the mixin object, if any, belonging to this menu
  535.     CMailFolderMixin* mixin = nil;
  536.     Boolean found = false;
  537.  
  538.     static Int16 prevMenuID = 0;
  539.     static MenuRef prevMenuH = nil;
  540.     static UInt32 prevTicks = 0;
  541.     MenuRef menuh;
  542.  
  543.     Boolean sameMenuAsBefore = (menuID == prevMenuID
  544.                                 && prevMenuH != nil
  545.                                 && (::TickCount() - prevTicks < 30));
  546.     // Don't reuse the same menu after a short delay because we can't tell
  547.     // whether the user is still clicking the same popup as before: he may
  548.     // have selected another window since the last time (and unfortunately,
  549.     // all the folder popups in the different windows have the same ID).
  550.     prevTicks = ::TickCount();
  551.  
  552.     if (sameMenuAsBefore)
  553.         menuh = prevMenuH;
  554.     else
  555.     {
  556.         menuh = ::GetMenuHandle(menuID);
  557.         prevMenuH = menuh;
  558.         prevMenuID = menuID;
  559.     }
  560.  
  561.     if (menuh)
  562.     {
  563.         LArrayIterator iterator(CMailFolderMixin::sMailFolderMixinRegisterList);
  564.         while (iterator.Next(&mixin))
  565.         {
  566.             if (mixin->MGetSystemMenuHandle() == menuh)
  567.             {
  568.                 found = true;
  569.                 break;
  570.             }
  571.         }
  572.     }
  573.     if (!found || !mixin || !mixin->mUseFolderIcons)
  574.         return;
  575.  
  576.     static ArrayIndexT prevItemID = 0;
  577.     static CMessageFolder prevFolder(nil);
  578.     CMessageFolder currentFolder(nil);
  579.     if (sameMenuAsBefore && itemData.itemID == prevItemID && prevFolder.GetFolderInfo() != nil)
  580.         currentFolder = prevFolder;
  581.     else
  582.     {
  583.         currentFolder = mixin->MGetFolderFromMenuItem(itemData.itemID);
  584.         prevFolder = currentFolder;
  585.         prevItemID = itemData.itemID;
  586.     }
  587.     if (currentFolder.GetFolderInfo() == NULL)
  588.         return;
  589.  
  590.     switch (itemData.cbMsg)
  591.     {
  592.         case cbBasicDataOnlyMsg:
  593.             itemData.flags |=
  594.                 (ksameAlternateAsLastTime|kIconIsSmall|kHasIcon/*|kChangedByCallback*/|kdontDisposeIcon);
  595.             itemData.flags &= ~(kIsDynamic);
  596.  
  597.             return;
  598.  
  599.         case cbIconOnlyMsg:
  600.             break; // look out below!
  601.  
  602.         default:
  603.             return;
  604.     }
  605.  
  606.     // OK, calculate the icon and check whether it's changed.
  607.  
  608.     static ResIDT prevIconID = 0;
  609.     static Handle prevIconSuite = nil;
  610.     ResIDT iconID = currentFolder.GetIconID();
  611.     Handle newIconSuite;
  612.     if (iconID == prevIconID && prevIconSuite != nil)
  613.         newIconSuite = prevIconSuite;
  614.     else
  615.     {
  616.         newIconSuite = CIconList::GetIconSuite(iconID);
  617.         prevIconSuite = newIconSuite;
  618.         prevIconID = iconID;
  619.     }
  620.     if (newIconSuite && newIconSuite != itemData.hIcon)
  621.     {
  622.         // It's changed.  Modify the data record for Mercutio.
  623.         itemData.hIcon = newIconSuite;
  624.         itemData.iconType = 'suit';
  625.         if (::LMGetSysFontFam() != systemFont) // no bold for Chicago - it sucketh
  626.         {
  627.             if (currentFolder.HasNewMessages())
  628.                 itemData.textStyle.s |= bold;
  629.             else
  630.                 itemData.textStyle.s &= ~bold;
  631.         }
  632. //        itemData.flags |= kChangedByCallback; // set bit
  633.  
  634.         // indent the item by shifting the left side
  635.         const Int16 baseLevel
  636.             = (mixin->mDesiredFolderFlags & CMailFolderMixin::eWantHosts)
  637.                  ? kRootLevel : kRootLevel + 1;
  638.         itemData.itemRect.left
  639.             = itemData.itemRect.right
  640.             - (*menuh)->menuWidth
  641.             + ((currentFolder.GetLevel() - baseLevel) * cItemIdentWidth);
  642.     }
  643. } // MyMercutioCallback
  644.  
  645. //-----------------------------------
  646. void CMailFolderMixin::GetFolderNameForDisplay(char * inName, CMessageFolder& folder)
  647. //-----------------------------------
  648. {
  649.     const char* geekName = (char*)folder.GetName();
  650.     const char* prettyName = (char*)folder.GetPrettyName();
  651.     Boolean isNewsFolder = ((folder.GetFolderType() & (MSG_FOLDER_FLAG_NEWSGROUP | MSG_FOLDER_FLAG_NEWS_HOST)) != 0);
  652.  
  653.     if (isNewsFolder && prettyName != nil && *prettyName != '\0')
  654.     {
  655. #if 0
  656. //        sprintf(inName, "%s (%s)", geekName, prettyName);
  657.         Int16 strLen = ::strlen(geekName);
  658.         ::strcpy(inName, geekName);
  659.         inName[strLen ++] = ' ';
  660.         inName[strLen ++] = '(';
  661.         ::strcpy(&inName[strLen], prettyName);
  662.         strLen += ::strlen(prettyName);
  663.         inName[strLen ++] = ')';
  664.         inName[strLen ++] = '\0';
  665. #endif
  666.         ::strcpy(inName, prettyName);
  667.     }
  668.     else
  669.         ::strcpy(inName, geekName);
  670. } // GetFolderNameForDisplay
  671.  
  672. inline void *operator new(size_t,void *p) { return p; }
  673.  
  674. //-----------------------------------
  675. Boolean CMailFolderMixin::MPopulateWithFolders(const MSG_FolderInfo **inFolderInfoArray,
  676.                                                Int32 inNumFolders)
  677. //    Populate the folder menu popup with the specified list of mail folders. This method
  678. //    can be called at anytime after object creation; it does the right thing.
  679. //    
  680. //    The inFolderInfoArray contains a list of (MSG_FolderInfo *) pointer representing
  681. //    the current list of mail folders. inNumFolders is the number of items in the
  682. //    array, 0 if none.
  683. //    
  684. //    This method tries to keep the currently selected folder, but if changed, sets the 
  685. //    menu value to 0.
  686. //-----------------------------------
  687. {
  688.     MSG_Master *master = CMailNewsContext::GetMailMaster();
  689.     FailNIL_(master);
  690.     
  691.     MenuRef menuh = MGetSystemMenuHandle();
  692.  
  693.     const Int16 startNumItems = MGetNumMenuItems() - mInitialMenuCount;
  694.     Assert_(mFolderArray.GetCount() == startNumItems);    // Should be equal
  695.  
  696.     Boolean didChange = false;
  697.     
  698.     Int16 addedItems = 0;
  699.     
  700.     // Store the currently selected folder
  701.     
  702.     CMessageFolder selectedFolder = MGetSelectedFolder();
  703.     
  704.     // Set menu items
  705.     MSG_FolderInfo** curInfo = (MSG_FolderInfo**)inFolderInfoArray;
  706.     const Int16 baseLevel = (mDesiredFolderFlags & eWantHosts) ? kRootLevel : kRootLevel + 1;
  707.     const Int16 spacesPerFolderLevel = (cItemIdentWidth / ::CharWidth(cSpaceFolderMenuChar)) + 1;
  708.     CMessageFolder folder(nil);
  709.     for (Int16 curItem = 0; curItem < inNumFolders; curItem++, curInfo++)
  710.     {
  711.         CMessageFolder previousFolder = folder;
  712.         folder = CMessageFolder(*curInfo);
  713.         if (FolderFilter(folder))
  714.         {
  715.  
  716.             // Insert a gray line in the menu for host-level stuff we're not inserting.        
  717.             if (addedItems && previousFolder.GetLevel() == 1 && !(mDesiredFolderFlags & eWantHosts))
  718.             {
  719.                 if ( ++addedItems <= startNumItems )
  720.                 {
  721.                     if ( MUpdateMenuItem(addedItems + mInitialMenuCount, "\p-", /*iconID*/0) )
  722.                         didChange = true;
  723.                     new (mFolderArray.GetItemPtr(addedItems)) CMessageFolder(nil);
  724.                 }
  725.                 else
  726.                 {
  727.                     didChange = true;
  728.                     MAppendMenuItem("\p-", /*iconID*/0);
  729.                     mFolderArray.InsertItemsAt(1, addedItems, &folder);
  730.                     // Now we have to store it again, this time properly, using the copy
  731.                     // constructor.  Otherwise, the refcount of CCachedFolderLine is not incremented
  732.                     // because the previous line just does a bitwise copy.
  733.                     new (mFolderArray.GetItemPtr(addedItems)) CMessageFolder(nil);
  734.                 }
  735.                 // Ask for a callback so we can set the icon
  736.                 if (mUseFolderIcons && MDEF_IsCustomMenu(menuh))
  737.                     ::SetItemStyle(menuh, addedItems + mInitialMenuCount, condense);
  738.             }
  739.  
  740.             // add spaces at the end of the name to make the menu larger
  741.             // and reserve some room for the identation    
  742.             char tempString[cMaxMailFolderNameLength + 1];
  743.             GetFolderNameForDisplay(tempString, folder);
  744.  
  745.             Int16 nameLen = ::strlen(tempString);
  746.             Int16 numSpaces = ((folder.GetLevel() - baseLevel) * spacesPerFolderLevel);
  747.             if ( numSpaces > (sizeof(tempString) - nameLen) )
  748.                 numSpaces = sizeof(tempString) - nameLen;
  749.             if ( numSpaces > 0 )
  750.                 ::memset(tempString + nameLen, cSpaceFolderMenuChar, numSpaces);
  751.             tempString[nameLen + numSpaces] = '\0';
  752.             NET_UnEscape(tempString);
  753.  
  754.             CStr255 menuString(tempString);
  755.             
  756.             // Update or append the current menu item            
  757.             if ( ++addedItems <= startNumItems )
  758.             {
  759.                 if ( MUpdateMenuItem(addedItems + mInitialMenuCount, menuString, /*iconID*/0) )
  760.                     didChange = true;
  761.                 (*(CMessageFolder*)mFolderArray.GetItemPtr(addedItems)).CMessageFolder::~CMessageFolder();
  762.                 new (mFolderArray.GetItemPtr(addedItems)) CMessageFolder(folder);
  763.             }
  764.             else
  765.             {
  766.                 didChange = true;
  767.                 MAppendMenuItem(menuString, /*iconID*/0);
  768.                 mFolderArray.InsertItemsAt(1, addedItems, &folder);
  769.                 // Now we have to store it again, this time properly, using the copy
  770.                 // constructor.  Otherwise, the refcount of CCachedFolderLine is not incremented
  771.                 // because the previous line just does a bitwise copy.
  772.                 new (mFolderArray.GetItemPtr(addedItems)) CMessageFolder(folder);
  773.             }
  774.             // Ask for a callback so we can set the icon
  775.             if (mUseFolderIcons && MDEF_IsCustomMenu(menuh))
  776.                 ::SetItemStyle(menuh, addedItems + mInitialMenuCount, condense);
  777.         } // if (FolderFilter(folder))
  778.     } // for
  779.     
  780.     // Get rid of any remaining menu items
  781.     if (addedItems < startNumItems)
  782.     {
  783.         didChange = true;
  784.         MClipMenuItems(addedItems + 1 + mInitialMenuCount);
  785.         for (ArrayIndexT i = addedItems + 1; i <= mFolderArray.GetCount(); i++)
  786.         {
  787.             CMessageFolder* f = (CMessageFolder*)mFolderArray.GetItemPtr(i);
  788.             if (f)
  789.                 (*(CMessageFolder*)mFolderArray.GetItemPtr(i)).CMessageFolder::~CMessageFolder();
  790.         }
  791.         mFolderArray.RemoveItemsAt(LArray::index_Last, addedItems + 1);
  792.     }
  793.     
  794.     // Set the originally selected item (try to keep original folder), 
  795.     // or 0 if the folder was deleted
  796.     if (didChange && inNumFolders > 0 )
  797.     {
  798.         // Don't broadcast anything here
  799.         if ( !MSetSelectedFolder(selectedFolder, false) )
  800.             MSetSelectedMenuItem(0, false);
  801.     }
  802.  
  803.     // Set up for callback so we can set the icon
  804.     if (mUseFolderIcons && MDEF_IsCustomMenu(menuh))
  805.     {
  806.         if (!sMercutioCallback)
  807.             sMercutioCallback = NewMercutioCallback(MyMercutioCallback);
  808.         FailNIL_(sMercutioCallback);
  809.         MDEF_SetCallbackProc(menuh, (MercutioCallbackUPP)sMercutioCallback);
  810.         MenuPrefsRec myPrefs;
  811.         ::memset(&myPrefs, 0, sizeof(myPrefs));
  812.         myPrefs.useCallbackFlag.s = condense;
  813.         MDEF_SetMenuPrefs(menuh, &myPrefs);
  814.     }
  815.  
  816.     // Refresh on change
  817.     if (didChange)
  818.         MRefreshMenu();
  819.     return didChange;
  820. } // MPopulateWithFolders
  821.  
  822.  
  823. #pragma mark -
  824.  
  825. /*======================================================================================
  826.     Get the number of menu items.
  827. ======================================================================================*/
  828.  
  829. Int16 CMailFolderPopupMixin::MGetNumMenuItems(void)
  830. {
  831.     return MGetControl()->GetMaxValue();
  832. }
  833.  
  834.  
  835. /*======================================================================================
  836.     Get the selected menu item.
  837. ======================================================================================*/
  838.  
  839. Int16 CMailFolderPopupMixin::MGetSelectedMenuItem(void)
  840. {
  841.     return MGetControl()->GetValue();
  842. }
  843.  
  844.  
  845. /*======================================================================================
  846.     Set the selected menu item. Refresh the menu if the selection changes.
  847. ======================================================================================*/
  848.  
  849. void CMailFolderPopupMixin::MSetSelectedMenuItem(Int16 inIndex, Boolean inDoBroadcast)
  850. {
  851.  
  852.     StSetBroadcasting setBroadcasting(
  853.         MGetControl(),
  854.         inDoBroadcast && MGetControl()->IsBroadcasting()
  855.         );
  856.     MGetControl()->SetValue(inIndex);
  857. }
  858.  
  859.  
  860. /*======================================================================================
  861.     Update the current menu item. If any of the input parameters are different from
  862.     the current menu item parameters, return true and reset the menu item; otherwise,
  863.     return false and don't modify the menu. If inIconID is non-zero, set the icon for
  864.     the menu item to that resource. Don't refresh the menu display in anyway.
  865. ======================================================================================*/
  866.  
  867. Boolean CMailFolderPopupMixin::MUpdateMenuItem(Int16 inMenuItem, ConstStr255Param inName, 
  868.                                                   ResIDT inIconID)
  869. {
  870.     LControl *theControl = MGetControl();
  871. //    StEmptyVisRgn emptyRgn(theControl->GetMacPort());    // Make changes invisible
  872.  
  873.     Boolean changed = false;
  874.     MenuHandle menuH = MGetSystemMenuHandle();
  875.     Assert_(menuH != nil);
  876.     Assert_((inIconID > cMenuIconIDDiff) || (inIconID == 0));
  877.     
  878.     Assert_(::CountMItems(menuH) == MGetNumMenuItems());
  879.     Assert_((inMenuItem > 0) && (inMenuItem <= MGetNumMenuItems()));
  880.     
  881.     Str255 currentText;
  882.     ::GetMenuItemText(menuH, inMenuItem, currentText);
  883.     
  884.     changed = !::EqualString(currentText, inName, true, true);
  885.     if ( changed ) ::SetMenuItemText(menuH, inMenuItem, inName);
  886.     
  887.     if ( inIconID ) inIconID -= cMenuIconIDDiff;
  888.     Int16 iconID;
  889.     ::GetItemIcon(menuH, inMenuItem, &iconID);
  890.     if ( iconID != inIconID ) {
  891.         changed = true;
  892.         ::SetItemIcon(menuH, inMenuItem, inIconID);
  893.     }
  894.     
  895.     return changed;
  896. }
  897.  
  898.  
  899. /*======================================================================================
  900.     Append the specified menu item to the end of the menu. If inIconID is non-zero, set 
  901.     the icon for the menu item to that resource. Don't refresh the menu display in 
  902.     anyway.
  903. ======================================================================================*/
  904.  
  905. void CMailFolderPopupMixin::MAppendMenuItem(ConstStr255Param inName, ResIDT inIconID) {
  906.  
  907.     LControl *theControl = MGetControl();
  908. //    StEmptyVisRgn emptyRgn(theControl->GetMacPort());    // Make changes invisible
  909.  
  910.     MenuHandle menuH = MGetSystemMenuHandle();
  911.     Assert_(menuH != nil);
  912.     Assert_((inIconID > cMenuIconIDDiff) || (inIconID == 0));
  913.     Int16 numMenuItems = MGetNumMenuItems() + 1;
  914.     
  915.     Assert_(::CountMItems(menuH) == MGetNumMenuItems());
  916.     
  917.     UMenuUtils::AppendMenuItem(menuH, inName);
  918.     
  919.     if ( inIconID ) {
  920.         ::SetItemIcon(menuH, numMenuItems, inIconID - cMenuIconIDDiff);
  921.     }
  922.     theControl->SetMaxValue(numMenuItems);
  923. }
  924.  
  925.  
  926. /*======================================================================================
  927.     Remove menu items from the end of the current menu, beginning with the item at
  928.     inStartClipItem. Don't refresh the menu display in anyway.
  929. ======================================================================================*/
  930.  
  931. void CMailFolderPopupMixin::MClipMenuItems(Int16 inStartClipItem) {
  932.  
  933.     LControl *theControl = MGetControl();
  934. //    StEmptyVisRgn emptyRgn(theControl->GetMacPort());    // Make changes invisible
  935.  
  936.     MenuHandle menuH = MGetSystemMenuHandle();
  937.     Assert_(menuH != nil);
  938.     Int16 numMenuItems = MGetNumMenuItems();
  939.     
  940.     Assert_(::CountMItems(menuH) == numMenuItems);
  941.     Assert_((inStartClipItem > 0) && (inStartClipItem <= numMenuItems));
  942.     
  943.     while ( numMenuItems >= inStartClipItem ) {
  944.         ::DeleteMenuItem(menuH, numMenuItems--);
  945.     }
  946.     inStartClipItem -= 1;
  947.  
  948.     if ( MGetSelectedMenuItem() > inStartClipItem ) theControl->SetValue(inStartClipItem);
  949.     theControl->SetMaxValue(inStartClipItem);
  950. }
  951.  
  952.  
  953. /*======================================================================================
  954.     Get the current menu text for the specified item.
  955. ======================================================================================*/
  956.  
  957. void CMailFolderPopupMixin::MGetMenuItemName(Int16 inMenuItem, Str255 outItemName) {
  958.  
  959.     MenuHandle menuH = MGetSystemMenuHandle();
  960.     Assert_(menuH != nil);
  961.     Assert_(::CountMItems(menuH) == MGetNumMenuItems());
  962.     Assert_((inMenuItem > 0) && (inMenuItem <= MGetNumMenuItems()));
  963.  
  964.     ::GetMenuItemText(menuH, inMenuItem, outItemName);
  965. }
  966.  
  967.  
  968. /*======================================================================================
  969.     Refresh the menu display.
  970. ======================================================================================*/
  971.  
  972. void CMailFolderPopupMixin::MRefreshMenu(void) {
  973.  
  974.     MGetControl()->Refresh();
  975. }
  976.  
  977.  
  978. #pragma mark -
  979.  
  980. /*======================================================================================
  981.     Get a handle to the Mac menu associated with this object.
  982. ======================================================================================*/
  983.  
  984. MenuHandle CGAIconPopupFolderMixin::MGetSystemMenuHandle(void) {
  985.  
  986.     return MGetControl()->GetMacMenuH();
  987. }
  988.  
  989.  
  990. /*======================================================================================
  991.     Refresh the menu display.
  992. ======================================================================================*/
  993.  
  994. void CGAIconPopupFolderMixin::MRefreshMenu(void) {
  995.  
  996.     MGetControl()->RefreshMenu();
  997. }
  998.  
  999.  
  1000. #pragma mark -
  1001.  
  1002. /*======================================================================================
  1003.     Get a handle to the Mac menu associated with this object.
  1004. ======================================================================================*/
  1005.  
  1006. MenuHandle CGAPopupFolderMixin::MGetSystemMenuHandle(void) {
  1007.  
  1008.     return MGetControl()->GetMacMenuH();
  1009. }
  1010.  
  1011.  
  1012. #pragma mark -
  1013.  
  1014. /*======================================================================================
  1015.     Get a handle to the Mac menu associated with this object.
  1016. ======================================================================================*/
  1017.  
  1018. MenuHandle CGAIconButtonPopupFolderMixin::MGetSystemMenuHandle(void) {
  1019.  
  1020.     return MGetControl()->GetMacMenuH();
  1021. }
  1022.  
  1023.  
  1024. /*======================================================================================
  1025.     Refresh the menu display.
  1026. ======================================================================================*/
  1027.  
  1028. void CGAIconButtonPopupFolderMixin::MRefreshMenu(void) {
  1029.  
  1030.     // Don't need to do anything since the menu is not visible unless the user has clicked
  1031.     // on it. For a displayed name alongside the button, override in descended class.
  1032. }
  1033.  
  1034.  
  1035. #pragma mark -
  1036.  
  1037. /*======================================================================================
  1038.     Get the number of menu items.
  1039. ======================================================================================*/
  1040.  
  1041. Int16 CMenuMailFolderMixin::MGetNumMenuItems(void) {
  1042.  
  1043.     MenuHandle menuH = MGetSystemMenuHandle();
  1044.     return ::CountMItems(menuH);
  1045. }
  1046.  
  1047.  
  1048. /*======================================================================================
  1049.     Get the selected menu item.
  1050. ======================================================================================*/
  1051.  
  1052. Int16 CMenuMailFolderMixin::MGetSelectedMenuItem(void) {
  1053.  
  1054.     MenuHandle menuH = MGetSystemMenuHandle();
  1055.     Int16 numMenuItems = MGetNumMenuItems();
  1056.  
  1057.     for (Int16 i = 1; i <= numMenuItems; ++i) {
  1058.         short mark;
  1059.         ::GetItemMark(menuH, i, &mark);
  1060.         if ( mark ) return i;
  1061.     }
  1062.     
  1063.     return 0;    // No item selected
  1064. }
  1065.  
  1066.  
  1067. /*======================================================================================
  1068.     Set the selected menu item. Refresh the menu if the selection changes.
  1069. ======================================================================================*/
  1070.  
  1071. void CMenuMailFolderMixin::MSetSelectedMenuItem(Int16 inIndex, Boolean)
  1072. {
  1073.  
  1074.     Int16 selectedItem = MGetSelectedMenuItem();
  1075.     if ( selectedItem != inIndex ) {
  1076.         MenuHandle menuH = MGetSystemMenuHandle();
  1077.         if ( selectedItem > 0 ) ::SetItemMark(menuH, selectedItem, noMark);
  1078.         if ( inIndex > 0 ) ::SetItemMark(menuH, inIndex, checkMark);
  1079.     }
  1080. }
  1081.  
  1082.  
  1083. /*======================================================================================
  1084.     Update the current menu item. If any of the input parameters are different from
  1085.     the current menu item parameters, return true and reset the menu item; otherwise,
  1086.     return false and don't modify the menu. If inIconID is non-zero, set the icon for
  1087.     the menu item to that resource. Don't refresh the menu display in anyway.
  1088. ======================================================================================*/
  1089.  
  1090. Boolean CMenuMailFolderMixin::MUpdateMenuItem(Int16 inMenuItem, ConstStr255Param inName, 
  1091.                                                    ResIDT inIconID) {
  1092.  
  1093.     Boolean changed = false;
  1094.     MenuHandle menuH = MGetSystemMenuHandle();
  1095.     Assert_(menuH != nil);
  1096.     Assert_((inIconID > cMenuIconIDDiff) || (inIconID == 0));
  1097.     
  1098.     Assert_(::CountMItems(menuH) == MGetNumMenuItems());
  1099.     Assert_((inMenuItem > 0) && (inMenuItem <= MGetNumMenuItems()));
  1100.     
  1101.     Str255 currentText;
  1102.     ::GetMenuItemText(menuH, inMenuItem, currentText);
  1103.     
  1104.     changed = !::EqualString(currentText, inName, true, true);
  1105.     if ( changed ) ::SetMenuItemText(menuH, inMenuItem, inName);
  1106.     
  1107.     if ( inIconID ) inIconID -= cMenuIconIDDiff;
  1108.     Int16 iconID;
  1109.     ::GetItemIcon(menuH, inMenuItem, &iconID);
  1110.     if ( iconID != inIconID ) {
  1111.         changed = true;
  1112.         ::SetItemIcon(menuH, inMenuItem, inIconID);
  1113.     }
  1114.     
  1115.     return changed;
  1116. }
  1117.  
  1118.  
  1119. /*======================================================================================
  1120.     Append the specified menu item to the end of the menu. If inIconID is non-zero, set 
  1121.     the icon for the menu item to that resource. Don't refresh the menu display in 
  1122.     anyway.
  1123. ======================================================================================*/
  1124.  
  1125. void CMenuMailFolderMixin::MAppendMenuItem(ConstStr255Param inName, ResIDT inIconID) {
  1126.  
  1127.     LMenu *theMenu = MGetMenu();
  1128.  
  1129.     MenuHandle menuH = MGetSystemMenuHandle();
  1130.     Assert_(menuH != nil);
  1131.     Assert_((inIconID > cMenuIconIDDiff) || (inIconID == 0));
  1132.     Int16 numMenuItems = MGetNumMenuItems();
  1133.     
  1134.     Assert_(::CountMItems(menuH) == MGetNumMenuItems());
  1135.     
  1136.     theMenu->InsertCommand(inName, mMenuCommand, numMenuItems);
  1137.     
  1138.     if ( inIconID ) {
  1139.         ::SetItemIcon(menuH, numMenuItems + 1, inIconID - cMenuIconIDDiff);
  1140.     }
  1141. }
  1142.  
  1143.  
  1144. /*======================================================================================
  1145.     Remove menu items from the end of the current menu, beginning with the item at
  1146.     inStartClipItem. Don't refresh the menu display in anyway.
  1147. ======================================================================================*/
  1148.  
  1149. void CMenuMailFolderMixin::MClipMenuItems(Int16 inStartClipItem) {
  1150.  
  1151.     LMenu *theMenu = MGetMenu();
  1152.  
  1153.     Int16 numMenuItems = MGetNumMenuItems();
  1154.     
  1155.     Assert_((inStartClipItem > 0) && (inStartClipItem <= numMenuItems));
  1156.     
  1157.     while ( numMenuItems >= inStartClipItem ) {
  1158.         theMenu->RemoveItem(numMenuItems--);
  1159.     }
  1160. }
  1161.  
  1162.  
  1163. /*======================================================================================
  1164.     Get the current menu text for the specified item.
  1165. ======================================================================================*/
  1166.  
  1167. void CMenuMailFolderMixin::MGetMenuItemName(Int16 inMenuItem, Str255 outItemName) {
  1168.  
  1169.     MenuHandle menuH = MGetSystemMenuHandle();
  1170.     Assert_(menuH != nil);
  1171.     Assert_(::CountMItems(menuH) == MGetNumMenuItems());
  1172.     Assert_((inMenuItem > 0) && (inMenuItem <= MGetNumMenuItems()));
  1173.  
  1174.     ::GetMenuItemText(menuH, inMenuItem, outItemName);
  1175. }
  1176.  
  1177.  
  1178. /*======================================================================================
  1179.     Refresh the menu display.
  1180. ======================================================================================*/
  1181.  
  1182. void CMenuMailFolderMixin::MRefreshMenu(void) {
  1183.  
  1184.     // Don't need to do anything since the menu is not visible unless the user has clicked
  1185.     // on it.
  1186. }
  1187.  
  1188.  
  1189. /*======================================================================================
  1190.     Get a handle to the Mac menu associated with this object.
  1191. ======================================================================================*/
  1192.  
  1193. MenuHandle CMenuMailFolderMixin::MGetSystemMenuHandle(void) {
  1194.  
  1195.     return MGetMenu()->GetMacMenuH();
  1196. }
  1197.  
  1198.  
  1199. #pragma mark -
  1200.  
  1201. static const Char16    gsPopup_SmallMark            =    'Ñ';    // Mark used for small font popups
  1202. static const Int16 gsPopup_ArrowButtonWidth     =     22;    //    Width used in drawing the arrow only
  1203.  
  1204. enum
  1205. {
  1206.     eSelectAll = 1,
  1207.     eUnselectAll = 2
  1208. };
  1209.  
  1210. CSelectFolderMenu::CSelectFolderMenu(LStream    *inStream):
  1211. LGAPopup(inStream),
  1212. mSelectedItemCount(0),
  1213. mTotalItemCount(0),
  1214. mMenuWidth(0)
  1215. {
  1216.     mDesiredFolderFlags = (FolderChoices)(eWantIMAP + eWantNews);
  1217. }
  1218.  
  1219. CSelectFolderMenu::~CSelectFolderMenu()
  1220. {
  1221.     
  1222. }
  1223.  
  1224. void CSelectFolderMenu::FinishCreateSelf()
  1225. {
  1226.     LGAPopup::FinishCreateSelf();
  1227.     mInitialMenuCount = CountMItems(GetMacMenuH());
  1228.     CMailFolderMixin::UpdateMailFolderMixinsNow(this);
  1229. //    SetArrowOnly(true);
  1230.     mTotalItemCount = MGetNumMenuItems() - mInitialMenuCount;
  1231.     for (int i = 1; i <= mTotalItemCount; ++i)
  1232.     {
  1233.         UInt32 folderPrefFlag = MGetFolder(i).GetFolderPrefFlags();
  1234.         if (folderPrefFlag & MSG_FOLDER_PREF_OFFLINE)
  1235.         {
  1236.             mSelectedItemCount++;
  1237.             Char16    mark = GetMenuFontSize () < 12 ? gsPopup_SmallMark : checkMark;
  1238.             ::SetItemMark(GetMacMenuH(), i + mInitialMenuCount, mark);
  1239.         }
  1240.     }
  1241.     UpdateCommandMarks();
  1242. }
  1243.  
  1244. void
  1245. CSelectFolderMenu::SetupCurrentMenuItem(    MenuHandle    /*inMenuH*/,
  1246.                                             Int16        /*inCurrentItem*/)
  1247. {
  1248.     // Don't muck around with our marks!
  1249. }
  1250.  
  1251. void
  1252. CSelectFolderMenu::UpdateCommandMarks()
  1253. {
  1254.     short    mark;
  1255.     if (mSelectedItemCount == mTotalItemCount && mTotalItemCount)
  1256.     {
  1257.         // Mark the SelectAllCommand.
  1258.         mark = GetMenuFontSize () < 12 ? gsPopup_SmallMark : checkMark;
  1259.     }
  1260.     else
  1261.     {
  1262.         // Unmark the SelectAllCommand.
  1263.         mark = 0;
  1264.     }
  1265.     ::SetItemMark(GetMacMenuH(), eSelectAll, mark);
  1266.     if (!mSelectedItemCount && mTotalItemCount)
  1267.     {
  1268.         // Mark the UnselectAllCommand.
  1269.         mark = GetMenuFontSize () < 12 ? gsPopup_SmallMark : checkMark;
  1270.     }
  1271.     else
  1272.     {
  1273.         // Unmark the UnselectAllCommand.
  1274.         mark = 0;
  1275.     }
  1276.     ::SetItemMark(GetMacMenuH(), eUnselectAll, mark);
  1277.     if (!mTotalItemCount)
  1278.     {
  1279.         ::DisableItem(GetMacMenuH(), eSelectAll);
  1280.         ::DisableItem(GetMacMenuH(), eUnselectAll);
  1281.     }
  1282.     else
  1283.     {
  1284.         ::EnableItem(GetMacMenuH(), eSelectAll);
  1285.         ::EnableItem(GetMacMenuH(), eUnselectAll);
  1286.     }
  1287. }
  1288.  
  1289. void
  1290. CSelectFolderMenu::CommitCurrentSelections()
  1291. {
  1292.     for (int i = 1; i <= mTotalItemCount; ++i)
  1293.     {
  1294.         CMessageFolder currentFolder = MGetFolder(i);
  1295.         UInt32 folderPrefFlag = currentFolder.GetFolderPrefFlags();
  1296.         short    mark;
  1297.         ::GetItemMark(GetMacMenuH(), i + mInitialMenuCount, &mark);
  1298.         folderPrefFlag = mark?    folderPrefFlag | MSG_FOLDER_PREF_OFFLINE:
  1299.                                 folderPrefFlag & ~MSG_FOLDER_PREF_OFFLINE;
  1300.         ::MSG_SetFolderPrefFlags(currentFolder.GetFolderInfo(), folderPrefFlag);
  1301.     }
  1302. }
  1303.  
  1304. void
  1305. CSelectFolderMenu::SetValue(Int32 inValue)
  1306. {
  1307.     short    mark;
  1308.     if (inValue > eUnselectAll)
  1309.     {
  1310.         ::GetItemMark(GetMacMenuH(), inValue, &mark);
  1311.         if (mark)
  1312.         {
  1313.             mSelectedItemCount--;
  1314.             mark = 0;
  1315.         }
  1316.         else
  1317.         {
  1318.             mSelectedItemCount++;
  1319.             mark = GetMenuFontSize () < 12 ? gsPopup_SmallMark : checkMark;
  1320.         }
  1321.         ::SetItemMark(GetMacMenuH(), inValue, mark);
  1322.     }
  1323.     else
  1324.     {
  1325.         // Optimization if this option is already checked, then don't do anything
  1326.         if (inValue == eUnselectAll)
  1327.         {
  1328.             mark = 0;
  1329.             mSelectedItemCount = 0;
  1330.         }
  1331.         if (inValue == eSelectAll)
  1332.         {
  1333.             mark = GetMenuFontSize () < 12 ? gsPopup_SmallMark : checkMark;
  1334.             mSelectedItemCount = mTotalItemCount;
  1335.         }
  1336.         for (int i = 1; i <= mTotalItemCount; ++i)
  1337.         {
  1338.             ::SetItemMark(GetMacMenuH(), i + mInitialMenuCount, mark);
  1339.         }
  1340.     }
  1341.     UpdateCommandMarks();
  1342. }
  1343.