Mozilla/mozilla/cmd/xfe/src/FolderDropdown.cpp
spider 957093e8c5 Normandy Merge ....
git-svn-id: svn://10.0.0.236/trunk@4231 18797224-902f-48f8-a5cc-f745e15eee43
1998-06-22 21:19:46 +00:00

556 lines
12 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
FolderDropdown.cpp --- a combo box for selecting folders/newsgroups
Created: Chris Toshok <toshok@netscape.com>, 6-Mar-97
*/
#include "FolderFrame.h"
#include "FolderDropdown.h"
#include "MozillaApp.h"
#undef DEBUG_dora
#ifdef DEBUG_toshok
#define D(x) x
#else
#define D(x)
#endif
#ifdef DEBUG_dora
#define DD(x) x
#else
#define DD(x)
#endif
const char * XFE_FolderDropdown::folderSelected = "XFE_FolderDropdown::folderSelected";
XFE_FolderDropdown::XFE_FolderDropdown(XFE_Component *toplevel_component,
Widget parent,
XP_Bool allowServerSelection,
XP_Bool showNewsgroups,
XP_Bool boldWithNew,
XP_Bool showFolders)
: XFE_Component(toplevel_component)
{
m_popupServer = True;
m_master = fe_getMNMaster();
Widget combo;
Colormap cmap;
Cardinal depth;
Visual *v;
XtVaGetValues(getToplevel()->getBaseWidget(),
XmNvisual, &v,
XmNcolormap, &cmap,
XmNdepth, &depth,
NULL);
m_allowServerSelection = allowServerSelection;
m_showNewsgroups = showNewsgroups;
m_boldWithNew = boldWithNew;
m_foldersHaveChanged = FALSE;
m_showFolders = showFolders;
combo = XtVaCreateWidget("folderDropdown",
dtComboBoxWidgetClass,
parent,
XmNshadowThickness, 1,
XmNmarginWidth, 0,
XmNmarginHeight, 0,
XmNarrowType, XmMOTIF,
XmNtype, XmDROP_DOWN_LIST_BOX,
XmNcolumns, 30,
XmNvisibleItemCount, 20,
XmNvisual, v,
XmNcolormap, cmap,
XmNdepth, depth,
NULL);
m_lastSelectedPosition = 0;
m_numNewsHosts = 0;
m_numinfos = 0;
m_infos = 0;
XFE_MozillaApp::theApp()->registerInterest(XFE_MNView::foldersHaveChanged,
this,
(XFE_FunctionNotification)rebuildFolderDropdown_cb);
XFE_MozillaApp::theApp()->registerInterest(XFE_MNView::newsgroupsHaveChanged,
this,
(XFE_FunctionNotification)rebuildFolderDropdown_cb);
if (m_boldWithNew)
XFE_MozillaApp::theApp()->registerInterest(XFE_MNView::folderChromeNeedsUpdating,
this,
(XFE_FunctionNotification)boldFolderInfo_cb);
XtAddCallback(combo, XmNselectionCallback, folderSelect_cb, this);
XtAddCallback(combo, XmNmenuPostCallback, folderMenuPost_cb, this);
setBaseWidget(combo);
installDestroyHandler();
resyncDropdown();
}
XFE_FolderDropdown::~XFE_FolderDropdown()
{
if (m_infos)
delete [] m_infos;
XFE_MozillaApp::theApp()->unregisterInterest(XFE_MNView::foldersHaveChanged,
this,
(XFE_FunctionNotification)rebuildFolderDropdown_cb);
XFE_MozillaApp::theApp()->unregisterInterest(XFE_MNView::newsgroupsHaveChanged,
this,
(XFE_FunctionNotification)rebuildFolderDropdown_cb);
if (m_boldWithNew)
XFE_MozillaApp::theApp()->unregisterInterest(XFE_MNView::folderChromeNeedsUpdating,
this,
(XFE_FunctionNotification)boldFolderInfo_cb);
}
void
XFE_FolderDropdown::setPopupServer(XP_Bool p)
{
m_popupServer = p;
}
MSG_FolderInfo *
XFE_FolderDropdown::getSelectedFolder()
{
int info;
if (m_infos == NULL) return NULL;
XtVaGetValues(m_widget,
XmNselectedPosition, &info,
NULL);
if (info < 0 || info > m_numinfos)
return NULL;
else
return m_infos[info];
}
void
XFE_FolderDropdown::selectFolder(MSG_FolderInfo *info, Boolean notify)
{
int i;
if (m_foldersHaveChanged)
{
m_foldersHaveChanged = FALSE;
resyncDropdown();
}
for (i = 0; i < m_numinfos; i ++)
{
if (info == m_infos[i])
{
if ( notify )
folderSelect(i);
else
{
m_lastSelectedPosition = i;
}
XtVaSetValues(m_widget,
XmNselectedPosition, i,
0);
return;
}
}
/* we might really want to know if the folder isn't there in the list,
but this actually can happen frequently if the user deletes folders */
//XP_ASSERT(0);
}
void
XFE_FolderDropdown::buildList(MSG_FolderInfo *info, int *position)
{
int num_children = MSG_GetFolderChildren(m_master,
info,
NULL, 0);
#ifdef DEBUG_dora
// For debugging P0 bug on XP only.
MSG_FolderLine line;
printf("buildList %x\n", info);
printf("num_children %d\n", num_children);
if ( info )
{
MSG_GetFolderLineById(m_master, info, &line);
if ( line.name)
printf("folder name=%s\n", line.name);
else printf("no folder name...\n");
}
#endif
if (num_children == 0)
{
return;
}
else
{
MSG_FolderInfo **tmp;
int i;
tmp = new MSG_FolderInfo* [num_children];
/* first we handle local mail stuff. */
MSG_GetFolderChildren(m_master,
info,
tmp,
num_children);
for (i = 0; i < num_children; i ++)
{
if (*position >= m_numinfos) return;
m_infos[*position] = tmp[i];
*position += 1;
XP_ASSERT(tmp[i]);
// don't recurse if we're at the top level (info==NULL)
// and we only want servers (m_showFolders=False)
if (info || m_showFolders)
buildList(tmp[i], position);
}
delete [] tmp;
}
}
void
XFE_FolderDropdown::syncFolderList()
{
int num_infos;
if (m_infos) delete [] m_infos;
/* this should be the number of MSG_FolderInfo's for mail,
including servers. */
num_infos = MSG_GetFoldersWithFlag(m_master,
MSG_FOLDER_FLAG_MAIL,
NULL, 0);
if (m_showNewsgroups)
{
num_infos += MSG_GetFoldersWithFlag(m_master,
MSG_FOLDER_FLAG_NEWSGROUP,
NULL, 0);
m_numNewsHosts = MSG_GetFoldersWithFlag(m_master,
MSG_FOLDER_FLAG_NEWS_HOST,
NULL, 0);
num_infos += m_numNewsHosts;
}
m_numinfos = num_infos;
m_infos = new MSG_FolderInfo* [num_infos];
int pos = 0;
/* build the default mail tree */
buildList(NULL, &pos);
/* now we build each newshost */
if (m_numNewsHosts > 0)
{
MSG_FolderInfo **news_hosts;
int i;
news_hosts = new MSG_FolderInfo* [m_numNewsHosts];
MSG_GetFoldersWithFlag(m_master,
MSG_FOLDER_FLAG_NEWS_HOST,
news_hosts, m_numNewsHosts);
for (i = 0; i < m_numNewsHosts; i++)
buildList(news_hosts[i], &pos);
delete [] news_hosts;
}
DD(printf("\nold m_numinfos = %d new numinfos %d\n",
m_numinfos, pos);)
m_numinfos = pos;
}
void
XFE_FolderDropdown::syncCombo()
{
int i;
XmStringTable xmstrings;
XmStringTable old_xmstrings = NULL;
DtComboBoxDeleteAllItems(m_widget);
m_lastSelectedPosition = -1;
D(printf ("In syncCombo(). There are %d entries\n", m_numinfos);)
xmstrings = (XmString*)XtCalloc(m_numinfos, sizeof(XmString));
for (i = 0; i < m_numinfos; i ++)
{
MSG_FolderLine line;
if ( !m_infos[i] )
{
// This block is just workaround for temp fix on the P0 crash
// bug when trying to bring up ThreadWindow.
// This is to prevent a P0 crash in XP code.
// We found that the all (subscribed & non-subscribed) news
// group was parsed when we tried to genterate a
// Combobox of all subscribed newsgroup.
// MSG_GetFolderChildren() should not try to parse
// unsubscribed newsgroup....
// David B. will investigate this further
DD(printf("[XFE_FolderDropdown Warning:]! Hitting NULL FolderInfo\n");)
for (i = 0; i < m_numinfos; i ++)
{
if (xmstrings[i])
XmStringFree(xmstrings[i]);
}
XtFree((char*)xmstrings);
return;
}
MSG_GetFolderLineById(m_master, m_infos[i], &line);
xmstrings[i] = makeListItemFromLine(&line);
}
XtVaGetValues(m_widget, XmNitems, &old_xmstrings, NULL);
if (old_xmstrings)
XtFree((char*)old_xmstrings);
XtVaSetValues(m_widget, XmNitems, xmstrings, XmNitemCount, m_numinfos, NULL);
}
void
XFE_FolderDropdown::resyncDropdown()
{
MSG_FolderInfo *saved_info = getSelectedFolder();
syncFolderList();
syncCombo();
if (saved_info)
selectFolder(saved_info);
}
XFE_CALLBACK_DEFN(XFE_FolderDropdown, rebuildFolderDropdown)(XFE_NotificationCenter *,
void *,
void *)
{
resyncDropdown();
m_foldersHaveChanged = TRUE;
}
XFE_CALLBACK_DEFN(XFE_FolderDropdown, boldFolderInfo)(XFE_NotificationCenter *,
void *,
void *cd)
{
/* This is wasteful and duplicates much of syncCombo above, but only for
one folder info */
MSG_FolderInfo *info = (MSG_FolderInfo*)cd;
MSG_FolderLine line;
int index;
Widget list;
Boolean isSelected;
if (m_foldersHaveChanged)
{
m_foldersHaveChanged = FALSE;
resyncDropdown();
}
for (index = 0; index < m_numinfos; index ++)
{
if (info == m_infos[ index ])
{
break;
}
}
/* not found */
if (index == m_numinfos) return;
if (!MSG_GetFolderLineById(m_master, info, &line))
return;
XmString both = makeListItemFromLine(&line);
XtVaGetValues(m_widget, XmNlist, &list, NULL);
isSelected = XmListPosSelected(list, index + 1);
XmListReplaceItemsPos(list, &both, 1, index + 1);
if (isSelected)
XmListSelectPos(list, index + 1, False);
XmStringFree(both);
}
void
XFE_FolderDropdown::folderSelect(int row)
{
MSG_FolderLine line;
XP_ASSERT(row >= 0 && row < m_numinfos);
if (!MSG_GetFolderLineById(m_master,
m_infos[row],
&line))
return;
if (line.level == 1) // it's a server '
{
if (m_popupServer)
fe_showFoldersWithSelected(XtParent(getToplevel()->getBaseWidget()),
NULL,
NULL,
m_infos[row]);
if (!m_allowServerSelection)
/* do not allow select; revert it!
*/
row = m_lastSelectedPosition;
if (row == -1)
/* We shall loop through our list to
* retrieve the first non-server entry instead of hard-wire it...
*/
row = 0;
XtVaSetValues(m_widget,
XmNselectedPosition, row,
NULL);
}
m_lastSelectedPosition = row;
notifyInterested(XFE_FolderDropdown::folderSelected,
(void*)m_infos[row]);
}
void
XFE_FolderDropdown::folderMenuPost()
{
if (m_foldersHaveChanged)
{
m_foldersHaveChanged = FALSE;
resyncDropdown();
}
}
void
XFE_FolderDropdown::folderSelect_cb(Widget, XtPointer clientData, XtPointer cd)
{
DtComboBoxCallbackStruct *cbs = (DtComboBoxCallbackStruct*)cd;
XFE_FolderDropdown *obj = (XFE_FolderDropdown*)clientData;
obj->folderSelect(cbs->item_position);
}
void
XFE_FolderDropdown::folderMenuPost_cb(Widget, XtPointer clientData, XtPointer)
{
XFE_FolderDropdown *obj = (XFE_FolderDropdown*)clientData;
obj->folderMenuPost();
}
XmString
XFE_FolderDropdown::makeListItemFromLine(MSG_FolderLine* line)
{
char buf[500];
memset(buf, 32, line->level - 1);
buf[line->level - 1] = 0;
XmString space;
space = XmStringCreate(buf, "BOLD");
if (line->prettyName)
PR_snprintf(buf, sizeof(buf), "%s", line->prettyName);
else
PR_snprintf(buf, sizeof(buf), "%s", line->name);
XmString xmstr;
if (m_boldWithNew && line->unseen > 0)
xmstr = XmStringCreate(buf, "BOLD");
else
xmstr = XmStringCreate(buf, XmFONTLIST_DEFAULT_TAG);
XmString both;
both = XmStringConcat(space, xmstr);
XmStringFree(space);
XmStringFree(xmstr);
return both;
}
void
XFE_FolderDropdown::selectFolder(char *name)
{
if (name && XP_STRLEN(name)) {
const char *this_folder_name;
for (int i=0; i < m_numinfos; i++) {
MSG_FolderLine line;
MSG_GetFolderLineById(m_master, m_infos[i], &line);
this_folder_name = MSG_GetFolderNameFromID(m_infos[i]);
if (this_folder_name && (XP_STRCMP(this_folder_name,name) == 0)) {
XP_ASSERT(line.prettyName || line.name);
XmString both = makeListItemFromLine(&line);
DtComboBoxSelectItem(m_widget, both);
XmStringFree(both);
m_lastSelectedPosition = i;
break;
}/* if */
}/* for i*/
}/* if */
}