add support for custom thread pane columns, patch by nachmore@gmail.com, sr=bienvenu 348504

This commit is contained in:
bienvenu%nventure.com 2006-09-02 18:23:29 +00:00
Родитель 9c09b56560
Коммит 772e04ab89
6 изменённых файлов: 325 добавлений и 16 удалений

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

@ -537,8 +537,23 @@ function ConvertColumnIDToSortType(columnID)
sortKey = nsMsgViewSortType.byAttachments;
break;
default:
dump("unsupported sort column: " + columnID + "\n");
sortKey = 0;
//no predefined column handler - lets check if there is a custom column handler
try {
//try to grab the columnHandler (an error is thrown if it does not exist)
columnHandler = gDBView.getColumnHandler(columnID);
//it exists - save this column ID in the customSortCol property of dbFolderInfo
//for later use (see nsIMsgDBView.cpp)
gDBView.db.dBFolderInfo.setProperty('customSortCol', columnID);
sortKey = nsMsgViewSortType.byCustom;
}
catch(err)
{
dump("unsupported sort column: " + columnID + " - no custom handler installed. (Error was: " + err + ")\n");
sortKey = 0;
}
break;
}
return sortKey;
@ -601,6 +616,20 @@ function ConvertSortTypeToColumnID(sortKey)
case nsMsgViewSortType.byAttachments:
columnID = "attachmentCol";
break;
case nsMsgViewSortType.byCustom:
//TODO: either change try() catch to if (property exists) or restore the getColumnHandler() check
try //getColumnHandler throws an errror when the ID is not handled
{
columnID = gDBView.db.dBFolderInfo.getProperty('customSortCol');
}
catch (err) { //error - means no handler
dump("ConvertSortTypeToColumnID: custom sort key but no handler for column '" + columnID + "'\n");
columnID = "dateCol";
}
break;
default:
dump("unsupported sort key: " + sortKey + "\n");
columnID = "dateCol";

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

@ -98,6 +98,7 @@ XPIDLSRCS = \
nsIMsgMdnGenerator.idl \
nsISpamSettings.idl \
nsIMapiRegistry.idl \
nsIMsgCustomColumnHandler.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk

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

@ -0,0 +1,65 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* The Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Oren Nachmore <nachmore@gmail.com>
* David Bienvenu <bienvenu@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsITreeView.idl"
interface nsIMsgDBHdr;
/* //TODO JavaDoc
When implementing a custom column handler (of type nsITreeView) you must implement the following
functions:
1. isEditable
2. GetCellProperties
3. GetImageSrc
4. GetCellText
5. CycleCell
6. GetSortStringForRow
7. GetSortLongForRow
8. isString
*/
[scriptable, uuid(33ef10af-54fb-42ce-95d0-52d8f6f1e681)]
interface nsIMsgCustomColumnHandler : nsITreeView
{
AString getSortStringForRow(in nsIMsgDBHdr aHdr);
unsigned long getSortLongForRow(in nsIMsgDBHdr aHdr);
boolean isString();
};

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

@ -46,6 +46,8 @@ interface nsIMsgDBViewCommandUpdater;
interface nsIMsgDatabase;
interface nsIMsgSearchSession;
interface nsISimpleEnumerator;
interface nsITreeView;
interface nsIMsgCustomColumnHandler;
typedef long nsMsgViewNotificationCodeValue;
typedef long nsMsgViewCommandCheckStateValue;
@ -104,6 +106,7 @@ interface nsMsgViewSortType
const nsMsgViewSortTypeValue byJunkStatus = 0x1f;
const nsMsgViewSortTypeValue byAttachments = 0x20;
const nsMsgViewSortTypeValue byAccount = 0x21;
const nsMsgViewSortTypeValue byCustom = 0x22;
};
[scriptable, uuid(255d1c1e-fde7-11d4-a5be-0060b0fc04b7)]
@ -250,7 +253,7 @@ interface nsMsgNavigationType
};
[scriptable, uuid(704c7d28-fd1a-11d4-a5be-0060b0fc04b7)]
[scriptable, uuid(7a49bcaa-5367-476d-a3da-7f305b7afb90)]
interface nsIMsgDBView : nsISupports
{
void open(in nsIMsgFolder folder, in nsMsgViewSortTypeValue sortType, in nsMsgViewSortOrderValue sortOrder, in nsMsgViewFlagsTypeValue viewFlags, out long count);
@ -333,6 +336,17 @@ interface nsIMsgDBView : nsISupports
// use lines or kB for size?
readonly attribute boolean usingLines;
// Custom Column Implementation note: see nsIMsgCustomColumnHandler
// attaches a custom column handler to a specific column (can be a new column or a built in)
void addColumnHandler(in AString aColumn, in nsIMsgCustomColumnHandler aHandler);
// removes a custom column handler leaving the column to be handled by the system
void removeColumnHandler(in AString aColumn);
// returns the custom column handler attached to a specific column - if any
nsIMsgCustomColumnHandler getColumnHandler(in AString aColumn);
};
/* this interface is rapidly morphing from a command updater interface into a more generic

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

@ -39,6 +39,7 @@
#include "msgCore.h"
#include "nsReadableUtils.h"
#include "nsIMsgCustomColumnHandler.h"
#include "nsMsgDBView.h"
#include "nsISupports.h"
#include "nsIMsgFolder.h"
@ -910,6 +911,18 @@ nsresult nsMsgDBView::CycleThreadedColumn(nsIDOMElement * aElement)
NS_IMETHODIMP nsMsgDBView::IsEditable(PRInt32 row, nsITreeColumn* col, PRBool* _retval)
{
//attempt to retreive a custom column handler. If it exists call it and return
const PRUnichar* colID;
col->GetIdConst(&colID);
nsIMsgCustomColumnHandler* colHandler = GetColumnHandler(colID);
if (colHandler)
{
colHandler->IsEditable(row, col, _retval);
return NS_OK;
}
*_retval = PR_FALSE;
return NS_OK;
}
@ -1350,6 +1363,16 @@ NS_IMETHODIMP nsMsgDBView::GetCellProperties(PRInt32 aRow, nsITreeColumn *col, n
}
}
//custom column handlers are called at the end of getCellProperties
//to make life easier for extension writers
nsIMsgCustomColumnHandler* colHandler = GetColumnHandler(colID);
if (colHandler != nsnull)
{
colHandler->GetCellProperties(aRow, col, properties);
return NS_OK;
}
return NS_OK;
}
@ -1505,6 +1528,18 @@ nsresult nsMsgDBView::GetDBForViewIndex(nsMsgViewIndex index, nsIMsgDatabase **d
NS_IMETHODIMP nsMsgDBView::GetImageSrc(PRInt32 aRow, nsITreeColumn* aCol, nsAString& aValue)
{
//attempt to retreive a custom column handler. If it exists call it and return
const PRUnichar* colID;
aCol->GetIdConst(&colID);
nsIMsgCustomColumnHandler* colHandler = GetColumnHandler(colID);
if (colHandler)
{
colHandler->GetImageSrc(aRow, aCol, aValue);
return NS_OK;
}
return NS_OK;
}
@ -1519,6 +1554,82 @@ NS_IMETHODIMP nsMsgDBView::GetCellValue(PRInt32 aRow, nsITreeColumn* aCol, nsASt
return NS_OK;
}
//add a custom column handler
NS_IMETHODIMP nsMsgDBView::AddColumnHandler(const nsAString& column, nsIMsgCustomColumnHandler* handler)
{
PRInt32 index = m_customColumnHandlerIDs.IndexOf(column);
nsAutoString strColID(column);
//does not exist
if (index == -1)
{
m_customColumnHandlerIDs.AppendString(strColID);
m_customColumnHandlers.AppendObject(handler);
}
else
{
//insert new handler into the appropriate place in the COMPtr array
//no need to replace the column ID (it's the same)
m_customColumnHandlers.ReplaceObjectAt(handler, index);
}
return NS_OK;
}
//remove a custom column handler
NS_IMETHODIMP nsMsgDBView::RemoveColumnHandler(const nsAString& aColID)
{
PRInt32 index = m_customColumnHandlerIDs.IndexOf(aColID);
if (index != -1)
{
m_customColumnHandlerIDs.RemoveStringAt(index);
m_customColumnHandlers.RemoveObjectAt(index);
return NS_OK;
}
return NS_ERROR_FAILURE; //can't remove a column that isn't currently custom handled
}
//TODO: NS_ENSURE_SUCCESS
nsIMsgCustomColumnHandler* nsMsgDBView::GetCurColumnHandlerFromDBInfo()
{
nsresult rv;
nsCOMPtr<nsIDBFolderInfo> dbInfo;
m_db->GetDBFolderInfo(getter_AddRefs(dbInfo));
nsAutoString colID;
rv = dbInfo->GetProperty("customSortCol", colID);
return GetColumnHandler(colID.get());
}
nsIMsgCustomColumnHandler* nsMsgDBView::GetColumnHandler(const PRUnichar *colID)
{
nsIMsgCustomColumnHandler* columnHandler = nsnull;
PRInt32 index = m_customColumnHandlerIDs.IndexOf(nsDependentString(colID));
if (index > -1)
columnHandler = m_customColumnHandlers[index];
return columnHandler;
}
NS_IMETHODIMP nsMsgDBView::GetColumnHandler(const nsAString& aColID, nsIMsgCustomColumnHandler** aHandler)
{
NS_ENSURE_ARG_POINTER(aHandler);
nsAutoString column(aColID);
NS_IF_ADDREF(*aHandler = GetColumnHandler(column.get()));
return (*aHandler) ? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsMsgDBView::GetCellText(PRInt32 aRow, nsITreeColumn* aCol, nsAString& aValue)
{
nsresult rv = NS_OK;
@ -1529,7 +1640,8 @@ NS_IMETHODIMP nsMsgDBView::GetCellText(PRInt32 aRow, nsITreeColumn* aCol, nsAStr
nsCOMPtr <nsIMsgDBHdr> msgHdr;
rv = GetMsgHdrForViewIndex(aRow, getter_AddRefs(msgHdr));
if (NS_FAILED(rv) || !msgHdr) {
if (NS_FAILED(rv) || !msgHdr)
{
ClearHdrCache();
return NS_MSG_INVALID_DBVIEW_INDEX;
}
@ -1541,6 +1653,16 @@ NS_IMETHODIMP nsMsgDBView::GetCellText(PRInt32 aRow, nsITreeColumn* aCol, nsAStr
const PRUnichar* colID;
aCol->GetIdConst(&colID);
//attempt to retreive a custom column handler. If it exists call it and return
nsIMsgCustomColumnHandler* colHandler = GetColumnHandler(colID);
if (colHandler)
{
colHandler->GetCellText(aRow, aCol, aValue);
return NS_OK;
}
switch (colID[0])
{
case 's':
@ -1673,6 +1795,16 @@ NS_IMETHODIMP nsMsgDBView::CycleCell(PRInt32 row, nsITreeColumn* col)
const PRUnichar* colID;
col->GetIdConst(&colID);
//attempt to retreive a custom column handler. If it exists call it and return
nsIMsgCustomColumnHandler* colHandler = GetColumnHandler(colID);
if (colHandler)
{
colHandler->CycleCell(row, col);
return NS_OK;
}
switch (colID[0])
{
case 'u': // unreadButtonColHeader
@ -3150,7 +3282,8 @@ nsresult nsMsgDBView::GetFieldTypeAndLenForSort(nsMsgViewSortTypeValue sortType,
NS_ENSURE_ARG_POINTER(pMaxLen);
NS_ENSURE_ARG_POINTER(pFieldType);
switch (sortType) {
switch (sortType)
{
case nsMsgViewSortType::bySubject:
*pFieldType = kCollationKey;
*pMaxLen = kMaxSubjectKey;
@ -3182,6 +3315,28 @@ nsresult nsMsgDBView::GetFieldTypeAndLenForSort(nsMsgViewSortTypeValue sortType,
*pFieldType = kU32;
*pMaxLen = 0;
break;
case nsMsgViewSortType::byCustom:
{
nsIMsgCustomColumnHandler* colHandler = GetCurColumnHandlerFromDBInfo();
if (colHandler != nsnull)
{
PRBool isString;
colHandler->IsString(&isString);
if (isString)
{
*pFieldType = kCollationKey;
*pMaxLen = kMaxRecipientKey; //80 - do we need a seperate k?
}
else
{
*pFieldType = kU32;
*pMaxLen = 0;
}
}
break;
}
default:
return NS_ERROR_UNEXPECTED;
}
@ -3226,7 +3381,7 @@ nsresult nsMsgDBView::GetStatusSortValue(nsIMsgDBHdr *msgHdr, PRUint32 *result)
return NS_OK;
}
nsresult nsMsgDBView::GetLongField(nsIMsgDBHdr *msgHdr, nsMsgViewSortTypeValue sortType, PRUint32 *result)
nsresult nsMsgDBView::GetLongField(nsIMsgDBHdr *msgHdr, nsMsgViewSortTypeValue sortType, PRUint32 *result, nsIMsgCustomColumnHandler* colHandler)
{
nsresult rv;
NS_ENSURE_ARG_POINTER(msgHdr);
@ -3294,6 +3449,18 @@ nsresult nsMsgDBView::GetLongField(nsIMsgDBHdr *msgHdr, nsMsgViewSortTypeValue s
else
rv = msgHdr->GetDateInSeconds(result);
break;
case nsMsgViewSortType::byCustom:
if (colHandler != nsnull)
{
colHandler->GetSortLongForRow(msgHdr, result);
rv = NS_OK;
}
else
{
NS_ASSERTION(PR_FALSE, "should not be here (Sort Type: byCustom (Long), but no custom handler)");
rv = NS_ERROR_UNEXPECTED;
}
break;
case nsMsgViewSortType::byId:
// handled by caller, since caller knows the key
default:
@ -3306,9 +3473,8 @@ nsresult nsMsgDBView::GetLongField(nsIMsgDBHdr *msgHdr, nsMsgViewSortTypeValue s
return NS_OK;
}
nsresult
nsMsgDBView::GetCollationKey(nsIMsgDBHdr *msgHdr, nsMsgViewSortTypeValue sortType, PRUint8 **result, PRUint32 *len)
nsMsgDBView::GetCollationKey(nsIMsgDBHdr *msgHdr, nsMsgViewSortTypeValue sortType, PRUint8 **result, PRUint32 *len, nsIMsgCustomColumnHandler* colHandler)
{
nsresult rv;
NS_ENSURE_ARG_POINTER(msgHdr);
@ -3345,6 +3511,22 @@ nsMsgDBView::GetCollationKey(nsIMsgDBHdr *msgHdr, nsMsgViewSortTypeValue sortTyp
rv = dbToUse->CreateCollationKey(str, result, len);
}
break;
case nsMsgViewSortType::byCustom:
if (colHandler != nsnull)
{
nsAutoString strKey;
rv = colHandler->GetSortStringForRow(msgHdr, strKey);
NS_ASSERTION(NS_SUCCEEDED(rv),"failed to get sort string for custom row");
nsAutoString strTemp(strKey);
rv = m_db->CreateCollationKey(strKey, result, len);
}
else
{
NS_ASSERTION(PR_FALSE,"should not be here (Sort Type: byCustom (String), but no custom handler)");
//rv = NS_ERROR_UNEXPECTED;
}
break;
default:
rv = NS_ERROR_UNEXPECTED;
break;
@ -3502,11 +3684,15 @@ NS_IMETHODIMP nsMsgDBView::Sort(nsMsgViewSortTypeValue sortType, nsMsgViewSortOr
msgHdr = nsnull;
}
//check if a custom column handler exists. If it does then grab it and pass it in
//to either GetCollationKey or GetLongField
nsIMsgCustomColumnHandler* colHandler = GetCurColumnHandlerFromDBInfo();
// could be a problem here if the ones that appear here are different than the ones already in the array
PRUint32 actualFieldLen = 0;
if (fieldType == kCollationKey)
{
rv = GetCollationKey(msgHdr, sortType, &keyValue, &actualFieldLen);
rv = GetCollationKey(msgHdr, sortType, &keyValue, &actualFieldLen, colHandler);
NS_ENSURE_SUCCESS(rv,rv);
longValue = actualFieldLen;
@ -3519,7 +3705,7 @@ NS_IMETHODIMP nsMsgDBView::Sort(nsMsgViewSortTypeValue sortType, nsMsgViewSortOr
}
else
{
rv = GetLongField(msgHdr, sortType, &longValue);
rv = GetLongField(msgHdr, sortType, &longValue, colHandler);
NS_ENSURE_SUCCESS(rv,rv);
}
}
@ -4166,10 +4352,15 @@ nsMsgViewIndex nsMsgDBView::GetInsertIndexHelper(nsIMsgDBHdr *msgHdr, nsMsgKeyAr
int (* PR_CALLBACK comparisonFun) (const void *pItem1, const void *pItem2, void *privateData)=nsnull;
int retStatus = 0;
msgHdr->GetMessageKey(&EntryInfo1.id);
//check if a custom column handler exists. If it does then grab it and pass it in
//to either GetCollationKey or GetLongField
nsIMsgCustomColumnHandler* colHandler = GetCurColumnHandlerFromDBInfo();
switch (fieldType)
{
case kCollationKey:
rv = GetCollationKey(msgHdr, sortType, &EntryInfo1.key, &EntryInfo1.dword);
rv = GetCollationKey(msgHdr, sortType, &EntryInfo1.key, &EntryInfo1.dword, colHandler);
NS_ASSERTION(NS_SUCCEEDED(rv),"failed to create collation key");
comparisonFun = FnSortIdKeyPtr;
comparisonContext = m_db.get();
@ -4178,7 +4369,7 @@ nsMsgViewIndex nsMsgDBView::GetInsertIndexHelper(nsIMsgDBHdr *msgHdr, nsMsgKeyAr
if (sortType == nsMsgViewSortType::byId)
EntryInfo1.dword = EntryInfo1.id;
else
GetLongField(msgHdr, sortType, &EntryInfo1.dword);
GetLongField(msgHdr, sortType, &EntryInfo1.dword, colHandler);
comparisonFun = FnSortIdDWord;
break;
default:
@ -4198,7 +4389,7 @@ nsMsgViewIndex nsMsgDBView::GetInsertIndexHelper(nsIMsgDBHdr *msgHdr, nsMsgKeyAr
if (fieldType == kCollationKey)
{
PR_FREEIF(EntryInfo2.key);
rv = GetCollationKey(tryHdr, sortType, &EntryInfo2.key, &EntryInfo2.dword);
rv = GetCollationKey(tryHdr, sortType, &EntryInfo2.key, &EntryInfo2.dword, colHandler);
NS_ASSERTION(NS_SUCCEEDED(rv),"failed to create collation key");
}
else if (fieldType == kU32)
@ -4207,7 +4398,7 @@ nsMsgViewIndex nsMsgDBView::GetInsertIndexHelper(nsIMsgDBHdr *msgHdr, nsMsgKeyAr
EntryInfo2.dword = EntryInfo2.id;
}
else {
GetLongField(tryHdr, sortType, &EntryInfo2.dword);
GetLongField(tryHdr, sortType, &EntryInfo2.dword, colHandler);
}
}
retStatus = (*comparisonFun)(&pValue1, &pValue2, comparisonContext);

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

@ -65,6 +65,7 @@
#include "nsIMsgFilterPlugin.h"
#include "nsIStringBundle.h"
#include "nsMsgTagService.h"
#include "nsCOMArray.h"
#define MESSENGER_STRING_URL "chrome://messenger/locale/messenger.properties"
@ -290,8 +291,10 @@ protected:
// for sorting
nsresult GetFieldTypeAndLenForSort(nsMsgViewSortTypeValue sortType, PRUint16 *pMaxLen, eFieldType *pFieldType);
nsresult GetCollationKey(nsIMsgDBHdr *msgHdr, nsMsgViewSortTypeValue sortType, PRUint8 **result, PRUint32 *len);
nsresult GetLongField(nsIMsgDBHdr *msgHdr, nsMsgViewSortTypeValue sortType, PRUint32 *result);
nsresult GetCollationKey(nsIMsgDBHdr *msgHdr, nsMsgViewSortTypeValue sortType, PRUint8 **result,
PRUint32 *len, nsIMsgCustomColumnHandler* colHandler = nsnull);
nsresult GetLongField(nsIMsgDBHdr *msgHdr, nsMsgViewSortTypeValue sortType, PRUint32 *result,
nsIMsgCustomColumnHandler* colHandler = nsnull);
nsresult GetStatusSortValue(nsIMsgDBHdr *msgHdr, PRUint32 *result);
nsresult GetLocationCollationKey(nsIMsgDBHdr *msgHdr, PRUint8 **result, PRUint32 *len);
@ -387,6 +390,12 @@ protected:
nsUInt32Array mIndicesToNoteChange;
//these hold pointers (and IDs) for the nsIMsgCustomColumnHandler object that constitutes the custom column handler
nsCOMArray <nsIMsgCustomColumnHandler> m_customColumnHandlers;
nsStringArray m_customColumnHandlerIDs;
nsIMsgCustomColumnHandler* GetColumnHandler(const PRUnichar*);
nsIMsgCustomColumnHandler* GetCurColumnHandlerFromDBInfo();
protected:
static nsresult InitDisplayFormats();