fix for #86200. add search to the subscribe dialog (and remove typedown.)

like 4.x, the text area is disabled for IMAP servers.

for news servers, when you type we show you the list of newsgroups that contain the substring.

r=naving, sr=mscott
This commit is contained in:
sspitzer%netscape.com 2001-06-26 05:08:26 +00:00
Родитель ac21c4b967
Коммит 5a43b8700a
12 изменённых файлов: 690 добавлений и 349 удалений

Просмотреть файл

@ -76,5 +76,9 @@ interface nsISubscribableServer : nsISupports {
void getChildren(in string path, in nsISupportsArray array);
// if path is null, use the root
void getFirstChildURI(in string path, out string result);
// for searching
void setSearchValue(in string searchValue);
readonly attribute boolean supportsSubscribeSearch;
};

Просмотреть файл

@ -5,18 +5,21 @@ var gServerURI = null;
var gSubscribableServer = null;
var gStatusBar = null;
var gNameField = null;
var gNameFieldLabel = null;
var gFolderDelimiter = ".";
var gStatusFeedback = new nsMsgStatusFeedback;
var gSubscribeDeck = null;
var gSearchView = null;
var gSearchOutlinerBoxObject = null;
// the rdf service
var RDF = '@mozilla.org/rdf/rdf-service;1'
RDF = Components.classes[RDF].getService();
RDF = RDF.QueryInterface(Components.interfaces.nsIRDFService);
var subscribeDS = RDF.GetDataSource("rdf:subscribe");
// used for caching the tree children (in typedown)
var lastTreeChildrenValue = null;
var lastTreeChildren = null;
// get the "subscribed" atom
var atomService = Components.classes["@mozilla.org/atom-service;1"].getService().QueryInterface(Components.interfaces.nsIAtomService);
var gSubscribedAtom = atomService.getAtom("subscribed").QueryInterface(Components.interfaces.nsISupports);
var gSubscribeBundle;
@ -34,21 +37,17 @@ function Stop()
function SetServerTypeSpecificTextValues()
{
if (!gServerURI) return;
if (!gServerURI) return;
var serverType = GetMsgFolderFromUri(gServerURI).server.type;
var serverType = GetMsgFolderFromUri(gServerURI).server.type;
//set the server specific ui elements
var element = document.getElementById("foldertextlabel");
var stringName = "foldertextfor-" + serverType;
var stringval = gSubscribeBundle.getString(stringName);
element.setAttribute('value',stringval);
stringName = "foldersheaderfor-" + serverType;
stringval = gSubscribeBundle.getString(stringName);
element = document.getElementById("foldersheaderlabel");
element.setAttribute('label',stringval);
// set the server specific ui elements
var stringName = "foldersheaderfor-" + serverType;
var stringval = gSubscribeBundle.getString(stringName);
var element = document.getElementById("foldersheaderlabel");
element.setAttribute('label',stringval);
element = document.getElementById("nameCol");
element.setAttribute('label',stringval);
//set the delimiter
try {
@ -116,35 +115,36 @@ function SetUpTree(forceToServer)
{
//dump("SetUpTree()\n");
// forget the cached tree children
lastTreeChildrenValue = null;
lastTreeChildren = null;
gStatusBar = document.getElementById('statusbar-icon');
if (!gServerURI) return;
var folder = GetMsgFolderFromUri(gServerURI);
var server = folder.server;
try {
gSubscribableServer = server.QueryInterface(Components.interfaces.nsISubscribableServer);
gSubscribeTree.setAttribute('ref',null);
gSubscribableServer = server.QueryInterface(Components.interfaces.nsISubscribableServer);
gSubscribeTree.setAttribute('ref',null);
// clear out the text field when switching server
gNameField.setAttribute('value',"");
// enable (or disable) the search related UI
EnableSearchUI();
gSubscribeTree.database.RemoveDataSource(subscribeDS);
gSubscribableServer.subscribeListener = MySubscribeListener;
// clear out the text field when switching server
gNameField.setAttribute('value',"");
gStatusFeedback.showProgress(0);
gStatusFeedback.showStatusString(gSubscribeBundle.getString("pleaseWaitString"));
gStatusBar.setAttribute("mode","undetermined");
// since there is no text, switch to the non-search view...
SwitchToNormalView();
gSubscribableServer.startPopulating(msgWindow, forceToServer);
gSubscribeTree.database.RemoveDataSource(subscribeDS);
gSubscribableServer.subscribeListener = MySubscribeListener;
gStatusFeedback.showProgress(0);
gStatusFeedback.showStatusString(gSubscribeBundle.getString("pleaseWaitString"));
gStatusBar.setAttribute("mode","undetermined");
gSubscribableServer.startPopulating(msgWindow, forceToServer);
}
catch (ex) {
//dump("failed to populate subscribe ds: " + ex + "\n");
//dump("failed to populate subscribe ds: " + ex + "\n");
}
}
@ -159,19 +159,34 @@ function SubscribeOnUnload()
}
}
function EnableSearchUI()
{
if (gSubscribableServer.supportsSubscribeSearch) {
gNameField.removeAttribute('disabled');
gNameFieldLabel.removeAttribute('disabled');
}
else {
gNameField.setAttribute('disabled',true);
gNameFieldLabel.setAttribute('disabled',true);
}
}
function SubscribeOnLoad()
{
//dump("SubscribeOnLoad()\n");
//dump("SubscribeOnLoad()\n");
gSubscribeBundle = document.getElementById("bundle_subscribe");
gSubscribeTree = document.getElementById('subscribetree');
gNameField = document.getElementById('namefield');
gSubscribeTree = document.getElementById('subscribetree');
gSearchOutlinerBoxObject = document.getElementById("searchOutliner").boxObject.QueryInterface(Components.interfaces.nsIOutlinerBoxObject);
gNameField = document.getElementById('namefield');
gNameFieldLabel = document.getElementById('namefieldlabel');
gSubscribeDeck = document.getElementById("subscribedeck");
msgWindow = Components.classes[msgWindowContractID].createInstance(Components.interfaces.nsIMsgWindow);
msgWindow.statusFeedback = gStatusFeedback;
msgWindow.SetDOMWindow(window);
msgWindow = Components.classes[msgWindowContractID].createInstance(Components.interfaces.nsIMsgWindow);
msgWindow.statusFeedback = gStatusFeedback;
msgWindow.SetDOMWindow(window);
doSetOKCancel(subscribeOK,subscribeCancel);
doSetOKCancel(subscribeOK,subscribeCancel);
// look in arguments[0] for parameters
if (window.arguments && window.arguments[0]) {
@ -189,6 +204,8 @@ function SubscribeOnLoad()
//dump("folder.server="+folder.server+"\n");
try {
gSubscribableServer = folder.server.QueryInterface(Components.interfaces.nsISubscribableServer);
// enable (or disable) the search related UI
EnableSearchUI();
gServerURI = folder.server.serverURI;
}
catch (ex) {
@ -236,28 +253,26 @@ function subscribeOK()
function subscribeCancel()
{
//dump("in subscribeCancel()\n");
Stop();
if (gSubscribableServer) {
gSubscribableServer.subscribeCleanup();
}
return true;
Stop();
if (gSubscribableServer) {
gSubscribableServer.subscribeCleanup();
}
return true;
}
function SetState(name,state)
{
//dump("SetState(" + name + "," + state + ")\n");
var changed = gSubscribableServer.setState(name, state);
if (changed) {
StateChanged(name,state);
}
var changed = gSubscribableServer.setState(name, state);
if (changed) {
StateChanged(name,state);
}
}
function changeTableRecord(server, name, state) {
this.server = server;
this.name = name;
this.state = state;
function changeTableRecord(server, name, state)
{
this.server = server;
this.name = name;
this.state = state;
}
function StateChanged(name,state)
@ -278,35 +293,112 @@ function StateChanged(name,state)
}
}
function InSearchMode()
{
// search is the second card in the deck
return (gSubscribeDeck.getAttribute("index") == "1");
}
function SearchOnClick(event)
{
var t = event.originalTarget;
if (t.localName == "outlinerbody") {
var row = new Object;
var colID = new Object;
var childElt = new Object;
gSearchOutlinerBoxObject.getCellAt(event.clientX, event.clientY, row, colID, childElt);
// if they are clicking on empty rows, drop the event
if (row.value + 1 > gSearchView.rowCount) return;
if (colID.value == "subscribedCol") {
if (event.detail != 2) {
// single clicked on the check box
// (in the "subscribedCol" column) reverse state
// if double click, do nothing
ReverseStateFromRow(row.value);
}
}
else if (event.detail == 2) {
// double clicked on a row, reverse state
ReverseStateFromRow(row.value);
}
}
}
function ReverseStateFromRow(row)
{
// to determine if the row is subscribed or not,
// we get the properties for the "subscribedCol" cell in the row
// and look for the "subscribed" property
// if the "subscribed" atom is in the list of properties
// we are subscribed
var properties = Components.classes["@mozilla.org/supports-array;1"].createInstance(Components.interfaces.nsISupportsArray);
gSearchView.getCellProperties(row, "subscribedCol", properties);
var isSubscribed = (properties.GetIndexOf(gSubscribedAtom) != -1);
var name = gSearchView.getCellText(row,"nameCol");
// we need to escape the name because
// some news servers have newsgroups with non ASCII names
// we need to escape those name before calling SetState()
SetState(escape(name), !isSubscribed);
}
function SetSubscribeState(state)
{
try {
var groupList = gSubscribeTree.selectedItems;
for (var i=0;i<groupList.length;i++) {
var group = groupList[i];
var name = group.getAttribute('name');
SetState(name,state);
}
if (InSearchMode()) {
// if we are in "search" mode, we need to iterate over the
// outliner selection, and set the state for all elements
// in the selection
var outlinerSelection = gSearchView.selection;
for (var i=0;i<outlinerSelection.getRangeCount();i++) {
var start = new Object;
var end = new Object;
outlinerSelection.getRangeAt(i,start,end);
for (var k=start.value;k<=end.value;k++) {
var name = gSearchView.getCellText(k,"nameCol");
// we need to escape the name because
// some news servers have newsgroups with non ASCII names
// we need to escape those name before calling SetState()
SetState(escape(name),state);
}
}
// force a repaint of the outliner since states have changed
InvalidateSearchOutliner();
}
else {
// we are in the "normal" mode
var groupList = gSubscribeTree.selectedItems;
for (var i=0;i<groupList.length;i++) {
var group = groupList[i];
var name = group.getAttribute('name');
SetState(name,state);
}
}
}
catch (ex) {
//dump("SetSubscribedState failed: " + ex + "\n");
//dump("SetSubscribedState failed: " + ex + "\n");
}
}
function ReverseStateFromNode(node)
{
var state;
var state;
if (node.getAttribute('Subscribed') == "true") {
state = false;
}
else {
state = true;
}
var uri = node.getAttribute('id');
var name = node.getAttribute('name');
SetState(name, state);
if (node.getAttribute('Subscribed') == "true") {
state = false;
}
else {
state = true;
}
var uri = node.getAttribute('id');
var name = node.getAttribute('name');
SetState(name, state);
}
@ -340,10 +432,6 @@ function SubscribeOnClick(event)
return;
}
var name = t.parentNode.parentNode.getAttribute('name');
if (name && (name.length > 0)) {
gNameField.setAttribute('value',name);
}
}
}
}
@ -354,144 +442,34 @@ function Refresh()
SetUpTree(true);
}
function trackGroupInTree()
function InvalidateSearchOutliner()
{
var portion = gNameField.value;
selectNodeByName( portion );
gSearchOutlinerBoxObject.invalidate();
}
function selectNodeByName( aMatchString )
function SwitchToNormalView()
{
var lastDot = aMatchString.lastIndexOf(gFolderDelimiter);
var nodeValue = lastDot != -1 ? aMatchString.substring(0, lastDot) : aMatchString;
var chain = aMatchString.split(gFolderDelimiter);
var node;
if( chain.length == 1 ) {
if (lastTreeChildrenValue != "") {
node = getTreechildren(gSubscribeTree);
if( !node ) return;
lastTreeChildrenValue = "";
lastTreeChildren = node;
//dump("cache miss!\n");
}
else {
node = lastTreeChildren;
//dump("cache hit!\n");
}
// the first card in the deck is the "normal" view
gSubscribeDeck.setAttribute("index","0");
}
function SwitchToSearchView()
{
// the second card in the deck is the "search" view
gSubscribeDeck.setAttribute("index","1");
}
function Search()
{
var searchValue = gNameField.value;
if (searchValue.length && gSubscribableServer.supportsSubscribeSearch) {
SwitchToSearchView();
gSubscribableServer.setSearchValue(searchValue);
gSearchView = gSubscribableServer.QueryInterface(Components.interfaces.nsIOutlinerView);
gSearchOutlinerBoxObject.view = gSearchView;
}
else {
// if we can, use the cached tree children
if (nodeValue != lastTreeChildrenValue) {
try {
node = gSubscribeTree.getElementsByAttribute("name",nodeValue)[0];
}
catch (ex) {
// this can happen if you do "spoon.foo" and there is no "spoon"
return;
}
// expand the node, if we need to
if( node.getAttribute("container") == "true" &&
node.getAttribute("open") != "true" ) {
node.setAttribute("open","true");
}
node = getTreechildren(node);
lastTreeChildren = node;
lastTreeChildrenValue = nodeValue;
//dump("cache miss!\n");
}
else {
//dump("cache hit!\n");
node = lastTreeChildren;
}
}
// find the match, using a binary search.
var totalItems = node.childNodes.length;
if (totalItems == 0) return;
var lastLow = 0;
var lastHigh = totalItems;
while (true) {
var i = Math.floor((lastHigh + lastLow) / 2);
//dump(i+","+lastLow+","+lastHigh+"\n");
var currItem = node.childNodes[i];
var currValue = (currItem.getAttribute("name")).substring(0,aMatchString.length);
//dump(currValue+" vs "+aMatchString+"\n");
if (currValue > aMatchString) {
if (lastHigh == i) return;
lastHigh = i;
}
else if (currValue < aMatchString) {
if (lastLow == i) return;
lastLow = i;
}
else {
SelectFirstMatch(lastLow, i, node.childNodes, aMatchString);
return;
}
SwitchToNormalView();
}
}
function SelectFirstMatch(startNode, endNode, nodes, matchStr)
{
// this code is to make sure we select the alphabetically first match
// not just any match (see bug #60242)
// find the match, using a binary search.
var lastMatch = nodes[endNode];
var totalItems = endNode - startNode;
if (totalItems == 0) {
gSubscribeTree.selectItem( lastMatch );
gSubscribeTree.ensureElementIsVisible( lastMatch );
return;
}
var lastLow = startNode;
var lastHigh = endNode;
while (true) {
var i = Math.floor((lastHigh + lastLow) / 2);
//dump(i+","+lastLow+","+lastHigh+"\n");
var currItem = nodes[i];
var currValue = (currItem.getAttribute("name")).substring(0,matchStr.length);
//dump(currValue+" vs "+matchStr+"\n");
if (currValue > matchStr) {
gSubscribeTree.selectItem( lastMatch );
gSubscribeTree.ensureElementIsVisible( lastMatch );
return;
}
else if (currValue < matchStr) {
if (lastLow == i) {
gSubscribeTree.selectItem( lastMatch );
gSubscribeTree.ensureElementIsVisible( lastMatch );
return;
}
lastLow = i;
}
else {
lastMatch = currItem;
if (lastHigh == i) {
gSubscribeTree.selectItem( lastMatch );
gSubscribeTree.ensureElementIsVisible( lastMatch );
return;
}
lastHigh = i;
}
}
}
function getTreechildren( aTreeNode )
{
if( aTreeNode.childNodes )
{
for( var i = 0; i < aTreeNode.childNodes.length; i++ )
{
if( aTreeNode.childNodes[i].localName.toLowerCase() == "treechildren" )
return aTreeNode.childNodes[i];
}
return aTreeNode;
}
return null;
}

Просмотреть файл

@ -81,8 +81,8 @@ Rights Reserved.
</menulist>
</row>
<row>
<text class="label" id="foldertextlabel" value="..." for="namefield"/>
<textbox id="namefield" flex="1" oninput="trackGroupInTree();"/>
<text class="label" id="namefieldlabel" value="&namefield.label;" for="namefield"/>
<textbox id="namefield" flex="1" oninput="Search();"/>
</row>
</rows>
</grid>
@ -93,6 +93,8 @@ Rights Reserved.
<spring/>
</row>
<row flex="1">
<deck id="subscribedeck" index="0">
<box id="normalview">
<tree class="inset" flex="1"
id="subscribetree"
datasources="rdf:null"
@ -127,6 +129,18 @@ Rights Reserved.
</treerow>
</treehead>
</tree>
</box>
<box id="searchview">
<outliner id="searchOutliner" flex="1" onclick="SearchOnClick(event);">
<outlinercol id="nameCol" label="..." class="outlinercol-header outlinercol-inset-header" flex="5" width="0" persist="hidden width" />
<splitter class="tree-splitter" />
<outlinercol id="subscribedCol" fixed="true" persist="hidden" class="outlinercol-header outlinercol-image outlinercol-inset-header subscribedColumnHeader" label="&subscribedHeader.label;" />
<splitter class="tree-splitter" />
<outlinercol id="messagesCol" label="&messagesHeader.label;" class="outlinercol-header outlinercol-inset-header" flex="1" width="0" persist="hidden width" />
<outlinerbody id="searchOutlinerBody" flex="1" />
</outliner>
</box>
</deck>
<box orient="vertical">
<button id="subscribe" class="dialog" label="&subscribeButton.label;" oncommand="SetSubscribeState(true)"/>
<button id="unsubscribe" class="dialog" label="&unsubscribeButton.label;" oncommand="SetSubscribeState(false)"/>

Просмотреть файл

@ -26,3 +26,4 @@ Rights Reserved.
<!ENTITY server.label "Server:">
<!ENTITY subscribedHeader.label "Subscribe">
<!ENTITY messagesHeader.label "Messages">
<!ENTITY namefield.label "Show items that contain:">

Просмотреть файл

@ -18,10 +18,7 @@
# Contributor(s):
# Seth Spitzer <sspitzer@netscape.com>
#
foldertextfor-nntp=Newsgroup:
foldersheaderfor-nntp=Newsgroup name
foldertextfor-imap=Folder:
foldersheaderfor-imap=Folder name
doneString=Done.
pleaseWaitString=Please wait...

Просмотреть файл

@ -798,3 +798,14 @@ nsSubscribableServer::CommitSubscribeChanges()
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsSubscribableServer::SetSearchValue(const char *searchValue)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsSubscribableServer::GetSupportsSubscribeSearch(PRBool *retVal)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

Просмотреть файл

@ -3131,3 +3131,15 @@ nsImapIncomingServer::GetFormattedName(const PRUnichar *prettyName, PRUnichar **
return rv;
}
NS_IMETHODIMP
nsImapIncomingServer::SetSearchValue(const char *searchValue)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsImapIncomingServer::GetSupportsSubscribeSearch(PRBool *retVal)
{
*retVal = PR_FALSE;
return NS_OK;
}

Просмотреть файл

@ -39,12 +39,12 @@
#include "nsMsgUtils.h"
#define INVALID_VERSION 0
#define VALID_VERSION 1
#define NEW_NEWS_DIR_NAME "News"
#define PREF_MAIL_NEWSRC_ROOT "mail.newsrc_root"
#define HOSTINFO_FILE_NAME "hostinfo.dat"
#define VALID_VERSION 1
#define NEW_NEWS_DIR_NAME "News"
#define PREF_MAIL_NEWSRC_ROOT "mail.newsrc_root"
#define HOSTINFO_FILE_NAME "hostinfo.dat"
#define NEWS_DELIMITER '.'
#define NEWS_DELIMITER '.'
// this platform specific junk is so the newsrc filenames we create
// will resemble the migrated newsrc filenames.
@ -71,6 +71,7 @@ NS_INTERFACE_MAP_BEGIN(nsNntpIncomingServer)
NS_INTERFACE_MAP_ENTRY(nsINntpIncomingServer)
NS_INTERFACE_MAP_ENTRY(nsIUrlListener)
NS_INTERFACE_MAP_ENTRY(nsISubscribableServer)
NS_INTERFACE_MAP_ENTRY(nsIOutlinerView)
NS_INTERFACE_MAP_END_INHERITING(nsMsgIncomingServer)
nsNntpIncomingServer::nsNntpIncomingServer() : nsMsgLineBuffer(nsnull, PR_FALSE)
@ -94,12 +95,16 @@ nsNntpIncomingServer::nsNntpIncomingServer() : nsMsgLineBuffer(nsnull, PR_FALSE)
mPostingAllowed = PR_FALSE;
mLastUpdatedTime = 0;
// these atoms are used for subscribe search
mSubscribedAtom = getter_AddRefs(NS_NewAtom("subscribed"));
mNntpAtom = getter_AddRefs(NS_NewAtom("nntp"));
SetupNewsrcSaveTimer();
}
nsNntpIncomingServer::~nsNntpIncomingServer()
{
nsresult rv;
nsresult rv;
if (mGroupsEnumerator) {
delete mGroupsEnumerator;
@ -118,10 +123,10 @@ nsNntpIncomingServer::~nsNntpIncomingServer()
}
rv = ClearInner();
NS_ASSERTION(NS_SUCCEEDED(rv), "ClearInner failed");
NS_ASSERTION(NS_SUCCEEDED(rv), "ClearInner failed");
rv = CloseCachedConnections();
NS_ASSERTION(NS_SUCCEEDED(rv), "CloseCachedConnections failed");
NS_ASSERTION(NS_SUCCEEDED(rv), "CloseCachedConnections failed");
}
NS_IMPL_SERVERPREF_BOOL(nsNntpIncomingServer, NotifyOn, "notify.on");
@ -132,53 +137,52 @@ NS_IMPL_SERVERPREF_INT(nsNntpIncomingServer, MaxArticles, "max_articles");
NS_IMETHODIMP
nsNntpIncomingServer::GetNewsrcFilePath(nsIFileSpec **aNewsrcFilePath)
{
nsresult rv;
rv = GetFileValue("newsrc.file", aNewsrcFilePath);
if (NS_SUCCEEDED(rv) && *aNewsrcFilePath) return rv;
nsresult rv;
rv = GetFileValue("newsrc.file", aNewsrcFilePath);
if (NS_SUCCEEDED(rv) && *aNewsrcFilePath) return rv;
nsCOMPtr<nsIFileSpec> path;
nsCOMPtr<nsIFileSpec> path;
rv = GetNewsrcRootPath(getter_AddRefs(path));
if (NS_FAILED(rv)) return rv;
rv = GetNewsrcRootPath(getter_AddRefs(path));
if (NS_FAILED(rv)) return rv;
nsXPIDLCString hostname;
rv = GetHostName(getter_Copies(hostname));
if (NS_FAILED(rv)) return rv;
nsXPIDLCString hostname;
rv = GetHostName(getter_Copies(hostname));
if (NS_FAILED(rv)) return rv;
// set the leaf name to "dummy", and then call MakeUnique with a suggested leaf name
rv = path->AppendRelativeUnixPath("dummy");
if (NS_FAILED(rv)) return rv;
nsCAutoString newsrcFileName(NEWSRC_FILE_PREFIX);
newsrcFileName.Append(hostname);
newsrcFileName.Append(NEWSRC_FILE_SUFFIX);
rv = path->MakeUniqueWithSuggestedName((const char *)newsrcFileName);
if (NS_FAILED(rv)) return rv;
// set the leaf name to "dummy", and then call MakeUnique with a suggested leaf name
rv = path->AppendRelativeUnixPath("dummy");
if (NS_FAILED(rv)) return rv;
nsCAutoString newsrcFileName(NEWSRC_FILE_PREFIX);
newsrcFileName.Append(hostname);
newsrcFileName.Append(NEWSRC_FILE_SUFFIX);
rv = path->MakeUniqueWithSuggestedName((const char *)newsrcFileName);
if (NS_FAILED(rv)) return rv;
rv = SetNewsrcFilePath(path);
if (NS_FAILED(rv)) return rv;
rv = SetNewsrcFilePath(path);
if (NS_FAILED(rv)) return rv;
*aNewsrcFilePath = path;
NS_ADDREF(*aNewsrcFilePath);
*aNewsrcFilePath = path;
NS_ADDREF(*aNewsrcFilePath);
return NS_OK;
return NS_OK;
}
NS_IMETHODIMP
nsNntpIncomingServer::SetNewsrcFilePath(nsIFileSpec *spec)
{
nsresult rv;
nsresult rv;
if (!spec) {
return NS_ERROR_FAILURE;
}
PRBool exists;
rv = spec->Exists(&exists);
if (!exists) {
rv = spec->Touch();
if (NS_FAILED(rv)) return rv;
}
return NS_ERROR_FAILURE;
}
PRBool exists;
rv = spec->Exists(&exists);
if (!exists) {
rv = spec->Touch();
if (NS_FAILED(rv)) return rv;
}
return SetFileValue("newsrc.file", spec);
}
@ -470,19 +474,19 @@ nsresult
nsNntpIncomingServer::CreateProtocolInstance(nsINNTPProtocol ** aNntpConnection, nsIURI *url,
nsIMsgWindow *aMsgWindow)
{
// create a new connection and add it to the connection cache
// we may need to flag the protocol connection as busy so we don't get
// a race
// condition where someone else goes through this code
nsNNTPProtocol * protocolInstance = new nsNNTPProtocol(url, aMsgWindow);
// create a new connection and add it to the connection cache
// we may need to flag the protocol connection as busy so we don't get
// a race
// condition where someone else goes through this code
nsNNTPProtocol * protocolInstance = new nsNNTPProtocol(url, aMsgWindow);
if (!protocolInstance)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = protocolInstance->QueryInterface(NS_GET_IID(nsINNTPProtocol), (void **) aNntpConnection);
// take the protocol instance and add it to the connectionCache
if (NS_SUCCEEDED(rv) && *aNntpConnection)
m_connectionCache->AppendElement(*aNntpConnection);
return rv;
// take the protocol instance and add it to the connectionCache
if (NS_SUCCEEDED(rv) && *aNntpConnection)
m_connectionCache->AppendElement(*aNntpConnection);
return rv;
}
/* By default, allow the user to open at most this many connections to one news host */
@ -492,9 +496,9 @@ NS_IMETHODIMP
nsNntpIncomingServer::GetNntpConnection(nsIURI * aUri, nsIMsgWindow *aMsgWindow,
nsINNTPProtocol ** aNntpConnection)
{
nsresult rv = NS_OK;
nsCOMPtr<nsINNTPProtocol> connection;
nsCOMPtr<nsINNTPProtocol> freeConnection;
nsresult rv = NS_OK;
nsCOMPtr<nsINNTPProtocol> connection;
nsCOMPtr<nsINNTPProtocol> freeConnection;
PRBool isBusy = PR_TRUE;
@ -512,8 +516,8 @@ nsNntpIncomingServer::GetNntpConnection(nsIURI * aUri, nsIMsgWindow *aMsgWindow,
}
*aNntpConnection = nsnull;
// iterate through the connection cache for a connection that can handle this url.
PRUint32 cnt;
// iterate through the connection cache for a connection that can handle this url.
PRUint32 cnt;
nsCOMPtr<nsISupports> aSupport;
rv = m_connectionCache->Count(&cnt);
@ -522,11 +526,11 @@ nsNntpIncomingServer::GetNntpConnection(nsIURI * aUri, nsIMsgWindow *aMsgWindow,
printf("XXX there are %d nntp connections in the conn cache.\n", (int)cnt);
#endif
for (PRUint32 i = 0; i < cnt && isBusy; i++)
{
{
aSupport = getter_AddRefs(m_connectionCache->ElementAt(i));
connection = do_QueryInterface(aSupport);
if (connection)
rv = connection->GetIsBusy(&isBusy);
if (connection)
rv = connection->GetIsBusy(&isBusy);
if (NS_FAILED(rv))
{
connection = nsnull;
@ -536,22 +540,22 @@ nsNntpIncomingServer::GetNntpConnection(nsIURI * aUri, nsIMsgWindow *aMsgWindow,
{
freeConnection = connection;
}
}
}
if (ConnectionTimeOut(freeConnection))
freeConnection = nsnull;
// if we got here and we have a connection, then we should return it!
if (!isBusy && freeConnection)
{
*aNntpConnection = freeConnection;
// if we got here and we have a connection, then we should return it!
if (!isBusy && freeConnection)
{
*aNntpConnection = freeConnection;
freeConnection->SetIsCachedConnection(PR_TRUE);
NS_IF_ADDREF(*aNntpConnection);
}
else // have no queueing mechanism - just create the protocol instance.
{
rv = CreateProtocolInstance(aNntpConnection, aUri, aMsgWindow);
}
NS_IF_ADDREF(*aNntpConnection);
}
else // have no queueing mechanism - just create the protocol instance.
{
rv = CreateProtocolInstance(aNntpConnection, aUri, aMsgWindow);
}
return rv;
}
@ -569,14 +573,14 @@ NS_IMETHODIMP nsNntpIncomingServer::RemoveConnection(nsINNTPProtocol *aNntpConne
NS_IMETHODIMP
nsNntpIncomingServer::PerformExpand(nsIMsgWindow *aMsgWindow)
{
nsresult rv;
nsresult rv;
nsCOMPtr<nsINntpService> nntpService = do_GetService(NS_NNTPSERVICE_CONTRACTID, &rv);
nsCOMPtr<nsINntpService> nntpService = do_GetService(NS_NNTPSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv,rv);
rv = nntpService->UpdateCounts(this, aMsgWindow);
rv = nntpService->UpdateCounts(this, aMsgWindow);
NS_ENSURE_SUCCESS(rv,rv);
return NS_OK;
return NS_OK;
}
// remove this when news supports filters
@ -589,7 +593,7 @@ nsNntpIncomingServer::GetFilterList(nsIMsgFilterList **aResult)
NS_IMETHODIMP
nsNntpIncomingServer::GetNumGroupsNeedingCounts(PRInt32 *aNumGroupsNeedingCounts)
{
nsresult rv;
nsresult rv;
nsCOMPtr<nsIEnumerator> subFolders;
nsCOMPtr<nsIFolder> rootFolder;
@ -597,23 +601,23 @@ nsNntpIncomingServer::GetNumGroupsNeedingCounts(PRInt32 *aNumGroupsNeedingCounts
rv = GetRootFolder(getter_AddRefs(rootFolder));
if (NS_FAILED(rv)) return rv;
PRBool hasSubFolders = PR_FALSE;
rv = rootFolder->GetHasSubFolders(&hasSubFolders);
if (NS_FAILED(rv)) return rv;
if (!hasSubFolders) {
*aNumGroupsNeedingCounts = 0;
return NS_OK;
}
rv = rootFolder->GetSubFolders(getter_AddRefs(subFolders));
PRBool hasSubFolders = PR_FALSE;
rv = rootFolder->GetHasSubFolders(&hasSubFolders);
if (NS_FAILED(rv)) return rv;
if (mGroupsEnumerator) {
delete mGroupsEnumerator;
mGroupsEnumerator = nsnull;
}
mGroupsEnumerator = new nsAdapterEnumerator(subFolders);
if (!hasSubFolders) {
*aNumGroupsNeedingCounts = 0;
return NS_OK;
}
rv = rootFolder->GetSubFolders(getter_AddRefs(subFolders));
if (NS_FAILED(rv)) return rv;
if (mGroupsEnumerator) {
delete mGroupsEnumerator;
mGroupsEnumerator = nsnull;
}
mGroupsEnumerator = new nsAdapterEnumerator(subFolders);
if (mGroupsEnumerator == nsnull) return NS_ERROR_OUT_OF_MEMORY;
PRUint32 count = 0;
@ -718,7 +722,7 @@ checkIfSubscribedFunction(nsCString &aElement, void *aData)
NS_IMETHODIMP
nsNntpIncomingServer::ContainsNewsgroup(const char *name, PRBool *containsGroup)
{
NS_ASSERTION(name && PL_strlen(name),"no name");
NS_ASSERTION(name && nsCRT::strlen(name),"no name");
if (!name || !containsGroup) return NS_ERROR_NULL_POINTER;
if (!nsCRT::strlen(name)) return NS_ERROR_FAILURE;
@ -731,7 +735,7 @@ nsNntpIncomingServer::SubscribeToNewsgroup(const char *name)
{
nsresult rv;
NS_ASSERTION(name && PL_strlen(name),"no name");
NS_ASSERTION(name && nsCRT::strlen(name),"no name");
if (!name) return NS_ERROR_NULL_POINTER;
if (!nsCRT::strlen(name)) return NS_ERROR_FAILURE;
@ -1045,32 +1049,33 @@ nsNntpIncomingServer::SetDelimiter(char aDelimiter)
{
nsresult rv = EnsureInner();
NS_ENSURE_SUCCESS(rv,rv);
return mInner->SetDelimiter(aDelimiter);
return mInner->SetDelimiter(aDelimiter);
}
NS_IMETHODIMP
nsNntpIncomingServer::SetAsSubscribed(const char *path)
{
mTempSubscribed.AppendCString(nsCAutoString(path));
nsresult rv = EnsureInner();
NS_ENSURE_SUCCESS(rv,rv);
return mInner->SetAsSubscribed(path);
return mInner->SetAsSubscribed(path);
}
PRBool
setAsSubscribedFunction(nsCString &aElement, void *aData)
{
nsresult rv = NS_OK;
nsresult rv = NS_OK;
nsNntpIncomingServer *server;
server = (nsNntpIncomingServer *)aData;
NS_ASSERTION(server, "no server");
if (!server) {
// todo is this correct?
return PR_FALSE;
}
rv = server->SetAsSubscribed((const char *)aElement);
NS_ASSERTION(NS_SUCCEEDED(rv),"SetAsSubscribed failed");
return PR_TRUE;
rv = server->SetAsSubscribed((const char *)aElement);
NS_ASSERTION(NS_SUCCEEDED(rv),"SetAsSubscribed failed");
return PR_TRUE;
}
NS_IMETHODIMP
@ -1078,6 +1083,7 @@ nsNntpIncomingServer::UpdateSubscribed()
{
nsresult rv = EnsureInner();
NS_ENSURE_SUCCESS(rv,rv);
mTempSubscribed.Clear();
mSubscribedNewsgroups.EnumerateForwards((nsCStringArrayEnumFunc)setAsSubscribedFunction, (void *)this);
return NS_OK;
}
@ -1088,20 +1094,20 @@ nsNntpIncomingServer::AddTo(const char *aName, PRBool addAsSubscribed, PRBool ch
nsresult rv = EnsureInner();
NS_ENSURE_SUCCESS(rv,rv);
nsAutoString newsgroupName;
newsgroupName.AssignWithConversion(aName);
nsAutoString newsgroupName;
newsgroupName.AssignWithConversion(aName);
char *escapedName = nsEscape(NS_ConvertUCS2toUTF8(newsgroupName.get()).get(), url_Path);
if (!escapedName) return NS_ERROR_OUT_OF_MEMORY;
rv = AddGroupOnServer(escapedName);
NS_ENSURE_SUCCESS(rv,rv);
rv = AddGroupOnServer(escapedName);
NS_ENSURE_SUCCESS(rv,rv);
rv = mInner->AddTo(escapedName,addAsSubscribed,changeIfExists);
NS_ENSURE_SUCCESS(rv,rv);
NS_ENSURE_SUCCESS(rv,rv);
PR_FREEIF(escapedName);
return rv;
return rv;
}
NS_IMETHODIMP
@ -1263,7 +1269,15 @@ nsNntpIncomingServer::SetState(const char *path, PRBool state, PRBool *stateChan
{
nsresult rv = EnsureInner();
NS_ENSURE_SUCCESS(rv,rv);
return mInner->SetState(path, state, stateChanged);
rv = mInner->SetState(path, state, stateChanged);
if (*stateChanged) {
if (state)
mTempSubscribed.AppendCString(nsCAutoString(path));
else
mTempSubscribed.RemoveCString(nsCAutoString(path));
}
return rv;
}
NS_IMETHODIMP
@ -1566,6 +1580,252 @@ nsNntpIncomingServer::GetOfflineSupportLevel(PRInt32 *aSupportLevel)
return NS_OK;
}
PRBool
buildSubscribeSearchResult(nsCString &aElement, void *aData)
{
nsresult rv = NS_OK;
nsNntpIncomingServer *server;
server = (nsNntpIncomingServer *)aData;
NS_ASSERTION(server, "no server");
if (!server) {
return PR_FALSE;
}
rv = server->AppendIfSearchMatch(aElement.get());
NS_ASSERTION(NS_SUCCEEDED(rv),"AddSubscribeSearchResult failed");
return PR_TRUE;
}
nsresult
nsNntpIncomingServer::AppendIfSearchMatch(const char *newsgroupName)
{
// we've converted mSearchValue to lower case
// do the same to the newsgroup name before we do our strstr()
// this way searches will be case independant
nsCAutoString lowerCaseName(newsgroupName);
lowerCaseName.ToLowerCase();
if (PL_strstr(lowerCaseName.get(), mSearchValue.get())) {
mSubscribeSearchResult.AppendCString(nsCAutoString(newsgroupName));
}
return NS_OK;
}
NS_IMETHODIMP
nsNntpIncomingServer::SetSearchValue(const char *searchValue)
{
mSearchValue = searchValue;
// force the search string to be lower case
// so that we can do case insensitive searching
mSearchValue.ToLowerCase();
mSubscribeSearchResult.Clear();
mGroupsOnServer.EnumerateForwards((nsCStringArrayEnumFunc)buildSubscribeSearchResult, (void *)this);
if (mOutliner) mOutliner->Invalidate();
return NS_OK;
}
NS_IMETHODIMP
nsNntpIncomingServer::GetSupportsSubscribeSearch(PRBool *retVal)
{
*retVal = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsNntpIncomingServer::GetRowCount(PRInt32 *aRowCount)
{
*aRowCount = mSubscribeSearchResult.Count();
return NS_OK;
}
NS_IMETHODIMP
nsNntpIncomingServer::GetSelection(nsIOutlinerSelection * *aSelection)
{
*aSelection = mOutlinerSelection;
NS_IF_ADDREF(*aSelection);
return NS_OK;
}
NS_IMETHODIMP
nsNntpIncomingServer::SetSelection(nsIOutlinerSelection * aSelection)
{
mOutlinerSelection = aSelection;
return NS_OK;
}
NS_IMETHODIMP
nsNntpIncomingServer::GetRowProperties(PRInt32 index, nsISupportsArray *properties)
{
return NS_OK;
}
NS_IMETHODIMP
nsNntpIncomingServer::GetCellProperties(PRInt32 row, const PRUnichar *colID, nsISupportsArray *properties)
{
if (colID[0] == 's') {
// if <name> is in our temporary list of subscribed groups
// add the "subscribed" property so the check mark shows up
// in the "subscribedCol"
nsCString name;
mSubscribeSearchResult.CStringAt(row, name);
if (mTempSubscribed.IndexOf(name) != -1) {
properties->AppendElement(mSubscribedAtom);
}
}
else if (colID[0] == 'n') {
// add the "nntp" property to the "nameCol"
// so we get the news folder icon in the search view
properties->AppendElement(mNntpAtom);
}
return NS_OK;
}
NS_IMETHODIMP
nsNntpIncomingServer::GetColumnProperties(const PRUnichar *colID, nsIDOMElement *colElt, nsISupportsArray *properties)
{
return NS_OK;
}
NS_IMETHODIMP
nsNntpIncomingServer::IsContainer(PRInt32 index, PRBool *_retval)
{
*_retval = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsNntpIncomingServer::IsContainerOpen(PRInt32 index, PRBool *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNntpIncomingServer::IsContainerEmpty(PRInt32 index, PRBool *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNntpIncomingServer::IsSorted(PRBool *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNntpIncomingServer::CanDropOn(PRInt32 index, PRBool *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNntpIncomingServer::CanDropBeforeAfter(PRInt32 index, PRBool before, PRBool *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNntpIncomingServer::Drop(PRInt32 row, PRInt32 orientation)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNntpIncomingServer::GetParentIndex(PRInt32 rowIndex, PRInt32 *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNntpIncomingServer::HasNextSibling(PRInt32 rowIndex, PRInt32 afterIndex, PRBool *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNntpIncomingServer::GetLevel(PRInt32 index, PRInt32 *_retval)
{
*_retval = 0;
return NS_OK;
}
NS_IMETHODIMP
nsNntpIncomingServer::GetCellText(PRInt32 row, const PRUnichar *colID, PRUnichar **_retval)
{
if (colID[0] == 'n') {
nsCString str;
mSubscribeSearchResult.CStringAt(row, str);
// some servers have newsgroup names that are non ASCII. we store those as escaped
// unescape here so the UI is consistent
nsresult rv = NS_MsgDecodeUnescapeURLPath(str.get(), _retval);
NS_ENSURE_SUCCESS(rv,rv);
}
return NS_OK;
}
NS_IMETHODIMP
nsNntpIncomingServer::SetOutliner(nsIOutlinerBoxObject *outliner)
{
mOutliner = outliner;
return NS_OK;
}
NS_IMETHODIMP
nsNntpIncomingServer::ToggleOpenState(PRInt32 index)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNntpIncomingServer::CycleHeader(const PRUnichar *colID, nsIDOMElement *elt)
{
return NS_OK;
}
NS_IMETHODIMP
nsNntpIncomingServer::SelectionChanged()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNntpIncomingServer::CycleCell(PRInt32 row, const PRUnichar *colID)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNntpIncomingServer::IsEditable(PRInt32 row, const PRUnichar *colID, PRBool *_retval)
{
*_retval = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsNntpIncomingServer::SetCellText(PRInt32 row, const PRUnichar *colID, const PRUnichar *value)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNntpIncomingServer::PerformAction(const PRUnichar *action)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNntpIncomingServer::PerformActionOnRow(const PRUnichar *action, PRInt32 row)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNntpIncomingServer::PerformActionOnCell(const PRUnichar *action, PRInt32 row, const PRUnichar *colID)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNntpIncomingServer::GetDefaultCopiesAndFoldersPrefsToServer(PRBool *aCopiesAndFoldersOnServer)
{

Просмотреть файл

@ -41,78 +41,97 @@
#include "nsITimer.h"
#include "nsFileStream.h"
#include "nsIOutlinerView.h"
#include "nsIOutlinerSelection.h"
#include "nsIAtom.h"
class nsINntpUrl;
class nsIMsgMailNewsUrl;
/* get some implementation from nsMsgIncomingServer */
class nsNntpIncomingServer : public nsMsgIncomingServer,
public nsINntpIncomingServer,
public nsIUrlListener,
public nsISubscribableServer,
public nsMsgLineBuffer
public nsIUrlListener,
public nsISubscribableServer,
public nsMsgLineBuffer,
public nsIOutlinerView
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSINNTPINCOMINGSERVER
NS_DECL_NSIURLLISTENER
NS_DECL_NSISUBSCRIBABLESERVER
NS_DECL_NSIOUTLINERVIEW
nsNntpIncomingServer();
virtual ~nsNntpIncomingServer();
NS_IMETHOD GetLocalStoreType(char * *type);
NS_IMETHOD CloseCachedConnections();
NS_IMETHOD PerformBiff();
NS_IMETHOD PerformBiff();
NS_IMETHOD PerformExpand(nsIMsgWindow *aMsgWindow);
NS_IMETHOD GetFilterList(nsIMsgFilterList **aResult);
// for nsMsgLineBuffer
virtual PRInt32 HandleLine(char *line, PRUint32 line_size);
// for nsMsgLineBuffer
virtual PRInt32 HandleLine(char *line, PRUint32 line_size);
// override to clear all passwords associated with server
NS_IMETHODIMP ForgetPassword();
NS_IMETHOD GetCanSearchMessages(PRBool *canSearchMessages);
NS_IMETHOD GetOfflineSupportLevel(PRInt32 *aSupportLevel);
NS_IMETHOD GetDefaultCopiesAndFoldersPrefsToServer(PRBool *aCopiesAndFoldersOnServer);
nsresult AppendIfSearchMatch(const char *newsgroupName);
protected:
nsresult CreateProtocolInstance(nsINNTPProtocol ** aNntpConnection, nsIURI *url,
nsresult CreateProtocolInstance(nsINNTPProtocol ** aNntpConnection, nsIURI *url,
nsIMsgWindow *window);
PRBool ConnectionTimeOut(nsINNTPProtocol* aNntpConnection);
nsCOMPtr<nsISupportsArray> m_connectionCache;
NS_IMETHOD GetServerRequiresPasswordForBiff(PRBool *_retval);
nsByteArray mHostInfoInputStream;
NS_IMETHOD GetServerRequiresPasswordForBiff(PRBool *_retval);
nsByteArray mHostInfoInputStream;
nsresult SetupNewsrcSaveTimer();
static void OnNewsrcSaveTimer(nsITimer *timer, void *voidIncomingServer);
private:
nsCStringArray mSubscribedNewsgroups;
nsCStringArray mGroupsOnServer;
nsCStringArray mSubscribedNewsgroups;
nsCStringArray mGroupsOnServer;
nsCStringArray mSubscribeSearchResult;
// the list of of subscribed newsgroups within a given
// subscribed dialog session.
// we need to keep track of them so we know what to show as "checked"
// in the search view
nsCStringArray mTempSubscribed;
nsCOMPtr<nsIAtom> mSubscribedAtom;
nsCOMPtr<nsIAtom> mNntpAtom;
PRBool mHasSeenBeginGroups;
nsresult WriteHostInfoFile();
nsresult LoadHostInfoFile();
nsCString mSearchValue;
nsCOMPtr<nsIOutlinerBoxObject> mOutliner;
nsCOMPtr<nsIOutlinerSelection> mOutlinerSelection;
PRBool mHasSeenBeginGroups;
nsresult WriteHostInfoFile();
nsresult LoadHostInfoFile();
nsresult AddGroupOnServer(const char *name);
PRBool mNewsrcHasChanged;
nsAdapterEnumerator *mGroupsEnumerator;
PRBool mHostInfoLoaded;
PRBool mHostInfoHasChanged;
nsCOMPtr <nsIFileSpec> mHostInfoFile;
PRUint32 mLastGroupDate;
PRTime mFirstNewDate;
PRInt32 mUniqueId;
PRBool mPushAuth;
nsAdapterEnumerator *mGroupsEnumerator;
PRBool mHostInfoLoaded;
PRBool mHostInfoHasChanged;
nsCOMPtr <nsIFileSpec> mHostInfoFile;
PRUint32 mLastGroupDate;
PRTime mFirstNewDate;
PRInt32 mUniqueId;
PRBool mPushAuth;
PRUint32 mLastUpdatedTime;
PRInt32 mVersion;
PRInt32 mVersion;
PRBool mPostingAllowed;
nsCOMPtr<nsITimer> mNewsrcSaveTimer;
nsCOMPtr <nsIMsgWindow> mMsgWindow;
nsCOMPtr <nsIMsgWindow> mMsgWindow;
nsCOMPtr <nsISubscribableServer> mInner;
nsCOMPtr <nsISubscribableServer> mInner;
nsresult EnsureInner();
nsresult ClearInner();

Просмотреть файл

@ -59,3 +59,17 @@
#subscribetree {
margin: 0px 0px 0px 0px !important;
}
/* for search */
outlinerbody:-moz-outliner-image(nameCol, nntp) {
list-style-image: url("chrome://messenger/skin/folder-newsgroup.gif");
}
outlinerbody:-moz-outliner-image(subscribedCol) {
list-style-image: url("chrome://messenger/skin/dot.gif");
}
outlinerbody:-moz-outliner-image(subscribedCol, subscribed) {
list-style-image: url("chrome://messenger/skin/check.gif");
}

Просмотреть файл

@ -59,3 +59,18 @@
#subscribetree {
margin: 0px 0px 0px 0px !important;
}
/* for search */
outlinerbody:-moz-outliner-image(nameCol, nntp) {
list-style-image: url("chrome://messenger/skin/folder-newsgroup.gif");
}
outlinerbody:-moz-outliner-image(subscribedCol) {
list-style-image: url("chrome://messenger/skin/dot.gif");
}
outlinerbody:-moz-outliner-image(subscribedCol, subscribed) {
list-style-image: url("chrome://messenger/skin/check.gif");
}

Просмотреть файл

@ -68,3 +68,19 @@
#subscribetree {
margin: 0px 0px 0px 0px !important;
}
/* for search */
outlinerbody:-moz-outliner-image(nameCol, nntp) {
list-style-image: url("chrome://messenger/skin/icons/folder-newsgroup.gif");
}
outlinerbody:-moz-outliner-image(subscribedCol) {
list-style-image: url("chrome://messenger/skin/icons/dot.gif");
}
outlinerbody:-moz-outliner-image(subscribedCol, subscribed) {
list-style-image: url("chrome://messenger/skin/icons/check.gif");
}