home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / src / FolderDropdown.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  12.6 KB  |  551 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.    FolderDropdown.cpp --- a combo box for selecting folders/newsgroups
  20.    Created: Chris Toshok <toshok@netscape.com>, 6-Mar-97
  21.  */
  22.  
  23.  
  24.  
  25. #include "FolderFrame.h"
  26. #include "FolderDropdown.h"
  27. #include "MozillaApp.h"
  28.  
  29. #undef DEBUG_dora
  30. #ifdef DEBUG_toshok
  31. #define D(x) x
  32. #else
  33. #define D(x)
  34. #endif
  35.  
  36. #ifdef DEBUG_dora
  37. #define DD(x) x
  38. #else
  39. #define DD(x)
  40. #endif
  41.  
  42.  
  43. const char * XFE_FolderDropdown::folderSelected = "XFE_FolderDropdown::folderSelected";
  44.  
  45. XFE_FolderDropdown::XFE_FolderDropdown(XFE_Component *toplevel_component,
  46.                                        Widget parent,
  47.                                        XP_Bool allowServerSelection,
  48.                                        XP_Bool showNewsgroups,
  49.                                        XP_Bool boldWithNew)
  50.     : XFE_Component(toplevel_component)
  51. {
  52.     m_popupServer = True;
  53.  
  54.     Widget combo;
  55.     Colormap cmap;
  56.     Cardinal depth;
  57.     Visual *v;
  58.  
  59.     XtVaGetValues(getToplevel()->getBaseWidget(),
  60.                   XmNvisual, &v,
  61.                   XmNcolormap, &cmap,
  62.                   XmNdepth, &depth,
  63.                   NULL);
  64.  
  65.     m_allowServerSelection = allowServerSelection;
  66.     m_showNewsgroups = showNewsgroups;
  67.     m_boldWithNew = boldWithNew;
  68.     m_foldersHaveChanged = FALSE;
  69.  
  70.     combo = XtVaCreateWidget("folderDropdown",
  71.                              dtComboBoxWidgetClass,
  72.                              parent,
  73.                              XmNshadowThickness, 1,
  74.                              XmNmarginWidth, 0,
  75.                              XmNmarginHeight, 0,
  76.                              XmNarrowType, XmMOTIF,
  77.                              XmNtype, XmDROP_DOWN_LIST_BOX,
  78.                              XmNcolumns, 30,
  79.                              XmNvisibleItemCount, 20,
  80.                              XmNvisual, v,
  81.                              XmNcolormap, cmap,
  82.                              XmNdepth, depth,
  83.                              NULL);
  84.  
  85.     m_lastSelectedPosition = 0;
  86.     m_numNewsHosts = 0;
  87.     m_numinfos = 0;
  88.     m_infos = 0;
  89.  
  90.     XFE_MozillaApp::theApp()->registerInterest(XFE_MNView::foldersHaveChanged,
  91.                                                this,
  92.                                                (XFE_FunctionNotification)rebuildFolderDropdown_cb);
  93.     XFE_MozillaApp::theApp()->registerInterest(XFE_MNView::newsgroupsHaveChanged,
  94.                                                this,
  95.                                                (XFE_FunctionNotification)rebuildFolderDropdown_cb);
  96.     if (m_boldWithNew)
  97.         XFE_MozillaApp::theApp()->registerInterest(XFE_MNView::folderChromeNeedsUpdating,
  98.                                                    this,
  99.                                                    (XFE_FunctionNotification)boldFolderInfo_cb);
  100.  
  101.     XtAddCallback(combo, XmNselectionCallback, folderSelect_cb, this);
  102.     XtAddCallback(combo, XmNmenuPostCallback, folderMenuPost_cb, this);
  103.  
  104.     setBaseWidget(combo);
  105.     installDestroyHandler();
  106.  
  107.     resyncDropdown();
  108. }
  109.  
  110.  
  111. XFE_FolderDropdown::~XFE_FolderDropdown()
  112. {
  113.     if (m_infos)
  114.         delete [] m_infos;
  115.  
  116.     XFE_MozillaApp::theApp()->unregisterInterest(XFE_MNView::foldersHaveChanged,
  117.                                                  this,
  118.                                                  (XFE_FunctionNotification)rebuildFolderDropdown_cb);
  119.     XFE_MozillaApp::theApp()->unregisterInterest(XFE_MNView::newsgroupsHaveChanged,
  120.                                                  this,
  121.                                                  (XFE_FunctionNotification)rebuildFolderDropdown_cb);
  122.     if (m_boldWithNew)
  123.         XFE_MozillaApp::theApp()->unregisterInterest(XFE_MNView::folderChromeNeedsUpdating,
  124.                                                      this,
  125.                                                      (XFE_FunctionNotification)boldFolderInfo_cb);
  126. }
  127.  
  128. void 
  129. XFE_FolderDropdown::setPopupServer(XP_Bool p)
  130. {
  131.     m_popupServer = p;
  132. }
  133.  
  134. MSG_FolderInfo *
  135. XFE_FolderDropdown::getSelectedFolder()
  136. {
  137.     int info;
  138.  
  139.     if (m_infos == NULL) return NULL;
  140.  
  141.     XtVaGetValues(m_widget,
  142.                   XmNselectedPosition, &info,
  143.                   NULL);
  144.  
  145.     if (info < 0 || info > m_numinfos)
  146.         return NULL;
  147.     else
  148.         return m_infos[info];
  149. }
  150.  
  151. void
  152. XFE_FolderDropdown::selectFolder(MSG_FolderInfo *info, Boolean notify)
  153. {
  154.     int i;
  155.  
  156.     if (m_foldersHaveChanged)
  157.       {
  158.         m_foldersHaveChanged = FALSE;
  159.         resyncDropdown();
  160.       }
  161.  
  162.     for (i = 0; i < m_numinfos; i ++)
  163.         {
  164.             if (info == m_infos[i])
  165.                 {
  166.                     if ( notify )
  167.                         folderSelect(i);
  168.                     else
  169.                     {
  170.                     m_lastSelectedPosition = i;
  171.                     }
  172.  
  173.                     XtVaSetValues(m_widget,
  174.                                   XmNselectedPosition, i,
  175.                                   0);
  176.                     return;
  177.                 }
  178.         }
  179.  
  180.     /* we might really want to know if the folder isn't there in the list,
  181.        but this actually can happen frequently if the user deletes folders */
  182.     //XP_ASSERT(0);
  183. }
  184.  
  185. void
  186. XFE_FolderDropdown::buildList(MSG_FolderInfo *info, int *position)
  187. {
  188.  
  189.  
  190.     int num_children = MSG_GetFolderChildren(fe_getMNMaster(),
  191.                                              info,
  192.                                              NULL, 0);
  193.  
  194. #ifdef DEBUG_dora
  195.     // For debugging P0 bug on XP only.
  196.     MSG_FolderLine line;
  197.  
  198.     printf("buildList %x\n", info);
  199.     printf("num_children %d\n", num_children);
  200.  
  201.     if ( info )
  202.      {
  203.     MSG_GetFolderLineById(fe_getMNMaster(), info, &line);
  204.  
  205.      if ( line.name)
  206.             printf("folder name=%s\n", line.name);
  207.     else printf("no folder name...\n");
  208.     }
  209.  
  210. #endif
  211.     if (num_children == 0) 
  212.         {
  213.             return;
  214.         }
  215.     else
  216.         {
  217.             MSG_FolderInfo **tmp;
  218.             int i;
  219.             
  220.             tmp = new MSG_FolderInfo* [num_children];
  221.  
  222.             /* first we handle local mail stuff. */
  223.             MSG_GetFolderChildren(fe_getMNMaster(),
  224.                                   info,
  225.                                   tmp,
  226.                                   num_children);
  227.             
  228.             for (i = 0; i < num_children; i ++)
  229.                 {
  230.                     if (*position >= m_numinfos) return;
  231.  
  232.                     m_infos[*position] = tmp[i];
  233.                     *position += 1;
  234.  
  235.                     XP_ASSERT(tmp[i]);
  236.                     buildList(tmp[i], position);
  237.                 }
  238.             
  239.             delete [] tmp;
  240.         }
  241. }
  242.  
  243. void
  244. XFE_FolderDropdown::syncFolderList()
  245. {
  246.     MSG_Master *master = fe_getMNMaster();
  247.  
  248.     int num_infos;
  249.  
  250.     if (m_infos) delete [] m_infos;
  251.  
  252.     /* this should be the number of MSG_FolderInfo's for mail,
  253.        including servers. */
  254.     num_infos = MSG_GetFoldersWithFlag(master,
  255.                                        MSG_FOLDER_FLAG_MAIL,
  256.                                        NULL, 0);
  257.  
  258.     if (m_showNewsgroups)
  259.         {
  260.             num_infos += MSG_GetFoldersWithFlag(master,
  261.                                                 MSG_FOLDER_FLAG_NEWSGROUP,
  262.                                                 NULL, 0);
  263.  
  264.             m_numNewsHosts = MSG_GetFoldersWithFlag(master,
  265.                                                     MSG_FOLDER_FLAG_NEWS_HOST,
  266.                                                     NULL, 0);
  267.             num_infos += m_numNewsHosts;
  268.         }
  269.  
  270.     m_numinfos = num_infos;
  271.     m_infos = new MSG_FolderInfo* [num_infos];
  272.  
  273.     int pos = 0;
  274.  
  275.     /* build the default mail tree */
  276.     buildList(NULL, &pos);
  277.  
  278.     /* now we build each newshost */
  279.     if (m_numNewsHosts > 0)
  280.     {
  281.         MSG_FolderInfo **news_hosts;
  282.         int i;
  283.  
  284.         news_hosts = new MSG_FolderInfo* [m_numNewsHosts];
  285.  
  286.         MSG_GetFoldersWithFlag(master,
  287.                                MSG_FOLDER_FLAG_NEWS_HOST,
  288.                                news_hosts, m_numNewsHosts);
  289.  
  290.         for (i = 0; i < m_numNewsHosts; i++)
  291.             buildList(news_hosts[i], &pos);
  292.  
  293.         delete [] news_hosts;
  294.     }
  295.     DD(printf("\nold m_numinfos = %d new numinfos %d\n", 
  296.         m_numinfos, pos);)
  297.     
  298.     m_numinfos = pos;
  299. }
  300.  
  301. void
  302. XFE_FolderDropdown::syncCombo()
  303. {
  304.     int i;
  305.     XmStringTable xmstrings;
  306.     XmStringTable old_xmstrings = NULL;
  307.  
  308.     DtComboBoxDeleteAllItems(m_widget);
  309.  
  310.     m_lastSelectedPosition = -1;
  311.  
  312.     D(printf ("In syncCombo().  There are %d entries\n", m_numinfos);)
  313.  
  314.     xmstrings = (XmString*)XtCalloc(m_numinfos, sizeof(XmString));
  315.     
  316.     for (i = 0; i < m_numinfos; i ++)
  317.         {
  318.             MSG_FolderLine line;
  319.             
  320.             if ( !m_infos[i] ) 
  321.                 {  
  322.                     // This block is just workaround for temp fix on the P0 crash
  323.                     // bug when trying to bring up ThreadWindow.
  324.                     
  325.                     // This is to prevent a P0 crash in XP code.
  326.                     // We found that the all (subscribed & non-subscribed) news
  327.                     // group was parsed when we tried to genterate a
  328.                     // Combobox of all subscribed newsgroup.
  329.                     
  330.                     // MSG_GetFolderChildren() should not try to parse
  331.                     // unsubscribed newsgroup....
  332.                     // David B. will investigate this further
  333.  
  334.                     DD(printf("[XFE_FolderDropdown Warning:]! Hitting NULL FolderInfo\n");)
  335.  
  336.                     for (i = 0; i < m_numinfos; i ++)
  337.                         {
  338.                             if (xmstrings[i])
  339.                                 XmStringFree(xmstrings[i]);
  340.                         }
  341.                     XtFree((char*)xmstrings);
  342.  
  343.                     return;
  344.                 }
  345.  
  346.             MSG_GetFolderLineById(fe_getMNMaster(), m_infos[i], &line);
  347.             
  348.             xmstrings[i] = makeListItemFromLine(&line);
  349.         }
  350.  
  351.     XtVaGetValues(m_widget, XmNitems, &old_xmstrings, NULL);
  352.  
  353.     if (old_xmstrings)
  354.         XtFree((char*)old_xmstrings);
  355.  
  356.     XtVaSetValues(m_widget, XmNitems, xmstrings, XmNitemCount, m_numinfos, NULL);
  357. }
  358.  
  359. void
  360. XFE_FolderDropdown::resyncDropdown()
  361. {
  362.     MSG_FolderInfo *saved_info = getSelectedFolder();
  363.  
  364.     syncFolderList();
  365.     syncCombo();
  366.  
  367.     if (saved_info)
  368.         selectFolder(saved_info);
  369. }
  370.  
  371. XFE_CALLBACK_DEFN(XFE_FolderDropdown, rebuildFolderDropdown)(XFE_NotificationCenter *,
  372.                                                              void *,
  373.                                                              void *)
  374. {
  375.     resyncDropdown();
  376.  
  377.     m_foldersHaveChanged = TRUE;
  378. }
  379.  
  380. XFE_CALLBACK_DEFN(XFE_FolderDropdown, boldFolderInfo)(XFE_NotificationCenter *,
  381.                                                       void *,
  382.                                                       void *cd)
  383. {
  384.     /* This is wasteful and duplicates much of syncCombo above, but only for
  385.        one folder info */
  386.     MSG_FolderInfo *info = (MSG_FolderInfo*)cd;
  387.     MSG_FolderLine line;
  388.  
  389.     int index;
  390.     Widget list;
  391.     Boolean isSelected;
  392.  
  393.     if (m_foldersHaveChanged)
  394.       {
  395.         m_foldersHaveChanged = FALSE;
  396.         resyncDropdown();
  397.       }
  398.  
  399.     for (index = 0; index < m_numinfos; index ++)
  400.         {
  401.             if (info == m_infos[ index ])
  402.                 {
  403.                     break;
  404.                 }
  405.         }
  406.  
  407.     /* not found */
  408.     if (index == m_numinfos) return;
  409.     
  410.     if (!MSG_GetFolderLineById(fe_getMNMaster(), info, &line))
  411.         return;
  412.  
  413.     XmString both = makeListItemFromLine(&line);    
  414.             
  415.     XtVaGetValues(m_widget, XmNlist, &list, NULL);
  416.  
  417.     isSelected = XmListPosSelected(list, index + 1);
  418.  
  419.     XmListReplaceItemsPos(list, &both, 1, index + 1);
  420.  
  421.     if (isSelected)
  422.         XmListSelectPos(list, index + 1, False);
  423.  
  424.     XmStringFree(both);
  425. }
  426.  
  427. void
  428. XFE_FolderDropdown::folderSelect(int row)
  429. {
  430.     MSG_FolderLine line;
  431.  
  432.     XP_ASSERT(row >= 0 && row < m_numinfos);
  433.  
  434.     if (!MSG_GetFolderLineById(fe_getMNMaster(),
  435.                                m_infos[row],
  436.                                &line))
  437.         return;
  438.  
  439.     if (line.level == 1) // it's a server '    
  440.         {
  441.             if (m_popupServer)
  442.                 fe_showFoldersWithSelected(XtParent(getToplevel()->getBaseWidget()),
  443.                                            NULL,
  444.                                            NULL,
  445.                                            m_infos[row]);
  446.             if (!m_allowServerSelection)
  447.                 /* do not allow select; revert it!
  448.                  */
  449.                 row = m_lastSelectedPosition;
  450.     
  451.  
  452.             if (row == -1)
  453.                 /* We shall loop through our list to 
  454.                  * retrieve the first non-server entry instead of hard-wire it...
  455.                  */
  456.                 row = 0;
  457.  
  458.             XtVaSetValues(m_widget,
  459.                           XmNselectedPosition, row,
  460.                           NULL);
  461.         }
  462.  
  463.     m_lastSelectedPosition = row;
  464.  
  465.     notifyInterested(XFE_FolderDropdown::folderSelected,
  466.                      (void*)m_infos[row]);
  467. }
  468.  
  469. void
  470. XFE_FolderDropdown::folderMenuPost()
  471. {
  472.     if (m_foldersHaveChanged)
  473.       {
  474.         m_foldersHaveChanged = FALSE;
  475.         resyncDropdown();
  476.       }
  477. }
  478.  
  479. void
  480. XFE_FolderDropdown::folderSelect_cb(Widget, XtPointer clientData, XtPointer cd)
  481. {
  482.     DtComboBoxCallbackStruct *cbs = (DtComboBoxCallbackStruct*)cd;
  483.     XFE_FolderDropdown *obj = (XFE_FolderDropdown*)clientData;
  484.  
  485.     obj->folderSelect(cbs->item_position);
  486. }
  487.  
  488. void
  489. XFE_FolderDropdown::folderMenuPost_cb(Widget, XtPointer clientData, XtPointer)
  490. {
  491.   XFE_FolderDropdown *obj = (XFE_FolderDropdown*)clientData;
  492.  
  493.   obj->folderMenuPost();
  494. }
  495.  
  496. XmString
  497. XFE_FolderDropdown::makeListItemFromLine(MSG_FolderLine* line)
  498. {
  499.     char buf[500];
  500.     memset(buf, 32, line->level - 1);
  501.     
  502.     buf[line->level - 1] = 0;
  503.  
  504.     XmString space;    
  505.     space = XmStringCreate(buf, "BOLD");
  506.     
  507.     if (line->prettyName)
  508.         PR_snprintf(buf, sizeof(buf), "%s", line->prettyName);
  509.     else
  510.         PR_snprintf(buf, sizeof(buf), "%s", line->name);
  511.     
  512.     XmString xmstr;
  513.     if (m_boldWithNew && line->unseen > 0)
  514.         xmstr = XmStringCreate(buf, "BOLD");
  515.     else
  516.         xmstr = XmStringCreate(buf, XmFONTLIST_DEFAULT_TAG);
  517.     
  518.     XmString both;
  519.     both = XmStringConcat(space, xmstr);
  520.     
  521.     XmStringFree(space);
  522.     XmStringFree(xmstr);
  523.  
  524.     return     both;        
  525. }
  526.  
  527. void
  528. XFE_FolderDropdown::selectFolder(char *name)
  529. {
  530.     if (name && XP_STRLEN(name)) {
  531.         const char *this_folder_name;
  532.         for (int i=0; i < m_numinfos; i++) {
  533.             MSG_FolderLine line;
  534.  
  535.             MSG_GetFolderLineById(fe_getMNMaster(), m_infos[i], &line);
  536.             this_folder_name = MSG_GetFolderNameFromID(m_infos[i]);
  537.             if (this_folder_name && (XP_STRCMP(this_folder_name,name) == 0)) {
  538.  
  539.                 XP_ASSERT(line.prettyName || line.name);
  540.                 XmString both = makeListItemFromLine(&line);
  541.                 DtComboBoxSelectItem(m_widget, both);
  542.                 XmStringFree(both);
  543.                 m_lastSelectedPosition = i;
  544.                 break;
  545.             }/* if */
  546.         }/* for i*/
  547.     }/* if */
  548. }
  549.  
  550.  
  551.