summaryrefslogtreecommitdiffstats
path: root/mailnews/base/src/nsMsgDBView.h
blob: feba5f14fe82faff248eaad3a451bc15c8fcd7e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef _nsMsgDBView_H_
#define _nsMsgDBView_H_

#include "nsIMsgDBView.h"
#include "nsIMsgWindow.h"
#include "nsIMessenger.h"
#include "nsIMsgDatabase.h"
#include "nsIMsgHdr.h"
#include "MailNewsTypes.h"
#include "nsIDBChangeListener.h"
#include "nsITreeView.h"
#include "nsITreeBoxObject.h"
#include "nsITreeSelection.h"
#include "nsIMsgFolder.h"
#include "nsIMsgThread.h"
#include "nsIDateTimeFormat.h"
#include "nsIDOMElement.h"
#include "nsIAtom.h"
#include "nsIImapIncomingServer.h"
#include "nsIWeakReference.h"
#include "nsIMsgFilterPlugin.h"
#include "nsIStringBundle.h"
#include "nsMsgTagService.h"
#include "nsCOMArray.h"
#include "nsTArray.h"
#include "nsTHashtable.h"
#include "nsHashKeys.h"
#include "nsIMsgCustomColumnHandler.h"
#include "nsAutoPtr.h"
#include "nsIWeakReferenceUtils.h"
#define MESSENGER_STRING_URL       "chrome://messenger/locale/messenger.properties"

typedef AutoTArray<nsMsgViewIndex, 1> nsMsgViewIndexArray;
static_assert(nsMsgViewIndex(nsMsgViewIndexArray::NoIndex) ==
  nsMsgViewIndex_None, "These need to be the same value.");

enum eFieldType {
    kCollationKey,
    kU32
};

// this is used in an nsTArray<> to keep track of a multi-column sort
class MsgViewSortColumnInfo
{
public:
  MsgViewSortColumnInfo(const MsgViewSortColumnInfo &other);
  MsgViewSortColumnInfo() {}
  bool operator == (const MsgViewSortColumnInfo &other) const;
  nsMsgViewSortTypeValue mSortType;
  nsMsgViewSortOrderValue mSortOrder;
  // if mSortType == byCustom, info about the custom column sort
  nsString mCustomColumnName;
  nsCOMPtr <nsIMsgCustomColumnHandler> mColHandler;
} ;

// reserve the top 8 bits in the msg flags for the view-only flags.
#define MSG_VIEW_FLAGS 0xEE000000
#define MSG_VIEW_FLAG_HASCHILDREN 0x40000000
#define MSG_VIEW_FLAG_DUMMY 0x20000000
#define MSG_VIEW_FLAG_ISTHREAD 0x8000000
#define MSG_VIEW_FLAG_OUTGOING 0x2000000
#define MSG_VIEW_FLAG_INCOMING 0x1000000

/* There currently only 5 labels defined */
#define PREF_LABELS_MAX 5
#define PREF_LABELS_DESCRIPTION  "mailnews.labels.description."
#define PREF_LABELS_COLOR  "mailnews.labels.color."

#define LABEL_COLOR_STRING " lc-"
#define LABEL_COLOR_WHITE_STRING "#FFFFFF"

struct IdUint32
{
  nsMsgKey    id;
  uint32_t    bits;
  uint32_t    dword;
  nsIMsgFolder* folder;
};

struct IdKey : public IdUint32
{
  // actually a variable length array, whose actual size is determined
  // when the struct is allocated.
  uint8_t     key[1];
};

struct IdKeyPtr : public IdUint32
{
  uint8_t     *key;
};

// This is an abstract implementation class.
// The actual view objects will be instances of sub-classes of this class
class nsMsgDBView : public nsIMsgDBView, public nsIDBChangeListener,
                    public nsITreeView,
                    public nsIJunkMailClassificationListener
{
public:
  nsMsgDBView();

  NS_DECL_ISUPPORTS
  NS_DECL_NSIMSGDBVIEW
  NS_DECL_NSIDBCHANGELISTENER
  NS_DECL_NSITREEVIEW
  NS_DECL_NSIJUNKMAILCLASSIFICATIONLISTENER

  nsMsgViewIndex GetInsertIndexHelper(nsIMsgDBHdr *msgHdr, nsTArray<nsMsgKey> &keys,
                                      nsCOMArray<nsIMsgFolder> *folders,
                                        nsMsgViewSortOrderValue sortOrder,
                                        nsMsgViewSortTypeValue sortType);
  int32_t  SecondarySort(nsMsgKey key1, nsISupports *folder1, nsMsgKey key2, nsISupports *folder2,
                         class viewSortInfo *comparisonContext);

protected:
  virtual ~nsMsgDBView();

  static nsrefcnt gInstanceCount;

  static char16_t* kHighestPriorityString;
  static char16_t* kHighPriorityString;
  static char16_t* kLowestPriorityString;
  static char16_t* kLowPriorityString;
  static char16_t* kNormalPriorityString;

  static nsIAtom* kJunkMsgAtom;
  static nsIAtom* kNotJunkMsgAtom;

  static char16_t* kReadString;
  static char16_t* kRepliedString;
  static char16_t* kForwardedString;
  static char16_t* kNewString;

  nsCOMPtr<nsITreeBoxObject> mTree;
  nsCOMPtr<nsITreeSelection> mTreeSelection;
  uint32_t mNumSelectedRows; // we cache this to determine when to push command status notifications.
  bool           mSuppressMsgDisplay; // set when the message pane is collapsed
  bool           mSuppressCommandUpdating;
  bool           mRemovingRow; // set when we're telling the outline a row is being removed. used to suppress msg loading.
                        // during delete/move operations.
  bool          mCommandsNeedDisablingBecauseOfSelection;
  bool          mSuppressChangeNotification;
  bool          mGoForwardEnabled;
  bool          mGoBackEnabled;
  
  virtual const char * GetViewName(void) {return "MsgDBView"; }
  nsresult FetchAuthor(nsIMsgDBHdr * aHdr, nsAString &aAuthorString);
  nsresult FetchRecipients(nsIMsgDBHdr * aHdr, nsAString &aRecipientsString);
  nsresult FetchSubject(nsIMsgDBHdr * aMsgHdr, uint32_t aFlags, nsAString &aValue);
  nsresult FetchDate(nsIMsgDBHdr * aHdr, nsAString & aDateString, bool rcvDate = false);
  nsresult FetchStatus(uint32_t aFlags, nsAString &aStatusString);
  nsresult FetchSize(nsIMsgDBHdr * aHdr, nsAString & aSizeString);
  nsresult FetchPriority(nsIMsgDBHdr *aHdr, nsAString & aPriorityString);
  nsresult FetchLabel(nsIMsgDBHdr *aHdr, nsAString & aLabelString);
  nsresult FetchTags(nsIMsgDBHdr *aHdr, nsAString & aTagString);
  nsresult FetchKeywords(nsIMsgDBHdr *aHdr, nsACString & keywordString);
  nsresult FetchRowKeywords(nsMsgViewIndex aRow, nsIMsgDBHdr *aHdr,
                            nsACString & keywordString);
  nsresult FetchAccount(nsIMsgDBHdr * aHdr, nsAString& aAccount);
  bool IsOutgoingMsg(nsIMsgDBHdr * aHdr);
  nsresult CycleThreadedColumn(nsIDOMElement * aElement);

  // The default enumerator is over the db, but things like
  // quick search views will enumerate just the displayed messages.
  virtual nsresult GetMessageEnumerator(nsISimpleEnumerator **enumerator);
  // this is a message enumerator that enumerates based on the view contents
  virtual nsresult GetViewEnumerator(nsISimpleEnumerator **enumerator);

  // Save and Restore Selection are a pair of routines you should
  // use when performing an operation which is going to change the view
  // and you want to remember the selection. (i.e. for sorting). 
  // Call SaveAndClearSelection and we'll give you an array of msg keys for
  // the current selection. We also freeze and clear the selection. 
  // When you are done changing the view, 
  // call RestoreSelection passing in the same array
  // and we'll restore the selection AND unfreeze selection in the UI.
  nsresult SaveAndClearSelection(nsMsgKey *aCurrentMsgKey, nsTArray<nsMsgKey> &aMsgKeyArray);
  nsresult RestoreSelection(nsMsgKey aCurrentmsgKey, nsTArray<nsMsgKey> &aMsgKeyArray);

  // this is not safe to use when you have a selection
  // RowCountChanged() will call AdjustSelection() 
  // it should be called after SaveAndClearSelection() and before
  // RestoreSelection()
  nsresult AdjustRowCount(int32_t rowCountBeforeSort, int32_t rowCountAfterSort);

  nsresult GetSelectedIndices(nsMsgViewIndexArray& selection);
  nsresult GenerateURIForMsgKey(nsMsgKey aMsgKey, nsIMsgFolder *folder, nsACString &aURI);
// routines used in building up view
  virtual bool WantsThisThread(nsIMsgThread * thread);
  virtual nsresult AddHdr(nsIMsgDBHdr *msgHdr, nsMsgViewIndex *resultIndex = nullptr);
  bool GetShowingIgnored() {return (m_viewFlags & nsMsgViewFlagsType::kShowIgnored) != 0;}
  bool OperateOnMsgsInCollapsedThreads();

  virtual nsresult OnNewHeader(nsIMsgDBHdr *aNewHdr, nsMsgKey parentKey, bool ensureListed);
  virtual nsMsgViewIndex GetInsertIndex(nsIMsgDBHdr *msgHdr);
  nsMsgViewIndex GetIndexForThread(nsIMsgDBHdr *hdr);
  nsMsgViewIndex GetThreadRootIndex(nsIMsgDBHdr *msgHdr);
  virtual nsresult GetMsgHdrForViewIndex(nsMsgViewIndex index, nsIMsgDBHdr **msgHdr);
  // given a view index, return the index of the top-level msg in the thread.
  nsMsgViewIndex GetThreadIndex(nsMsgViewIndex msgIndex);

  virtual void InsertMsgHdrAt(nsMsgViewIndex index, nsIMsgDBHdr *hdr,
                              nsMsgKey msgKey, uint32_t flags, uint32_t level);
  virtual void SetMsgHdrAt(nsIMsgDBHdr *hdr, nsMsgViewIndex index, 
                              nsMsgKey msgKey, uint32_t flags, uint32_t level);
  virtual bool InsertEmptyRows(nsMsgViewIndex viewIndex, int32_t numRows);
  virtual void RemoveRows(nsMsgViewIndex viewIndex, int32_t numRows);
  nsresult ToggleExpansion(nsMsgViewIndex index, uint32_t *numChanged);
  nsresult ExpandByIndex(nsMsgViewIndex index, uint32_t *pNumExpanded);
  nsresult CollapseByIndex(nsMsgViewIndex index, uint32_t *pNumCollapsed);
  nsresult ExpandAll();
  nsresult CollapseAll();
  nsresult ExpandAndSelectThread();

  // helper routines for thread expanding and collapsing.
  nsresult GetThreadCount(nsMsgViewIndex viewIndex, uint32_t *pThreadCount);
  /**
   * Retrieve the view index of the first displayed message in the given thread.
   * @param threadHdr The thread you care about.
   * @param allowDummy Should dummy headers be returned when the non-dummy
   *     header is available?  If the root node of the thread is a dummy header
   *     and you pass false, then we will return the first child of the thread
   *     unless the thread is elided, in which case we will return the root.
   *     If you pass true, we will always return the root.
   * @return the view index of the first message in the thread, if any.
   */
  nsMsgViewIndex GetIndexOfFirstDisplayedKeyInThread(nsIMsgThread *threadHdr,
      bool allowDummy=false);
  virtual nsresult GetFirstMessageHdrToDisplayInThread(nsIMsgThread *threadHdr, nsIMsgDBHdr **result);
  virtual nsMsgViewIndex ThreadIndexOfMsg(nsMsgKey msgKey,
                            nsMsgViewIndex msgIndex = nsMsgViewIndex_None,
                            int32_t *pThreadCount = nullptr,
                            uint32_t *pFlags = nullptr);
  nsMsgViewIndex ThreadIndexOfMsgHdr(nsIMsgDBHdr *msgHdr,
                                 nsMsgViewIndex msgIndex = nsMsgViewIndex_None,
                                 int32_t *pThreadCount = nullptr,
                                 uint32_t *pFlags = nullptr);
  nsMsgKey GetKeyOfFirstMsgInThread(nsMsgKey key);
  int32_t CountExpandedThread(nsMsgViewIndex index);
  virtual  nsresult ExpansionDelta(nsMsgViewIndex index, int32_t *expansionDelta);
  void ReverseSort();
  void ReverseThreads();
  nsresult SaveSortInfo(nsMsgViewSortTypeValue sortType, nsMsgViewSortOrderValue sortOrder);
  nsresult RestoreSortInfo();
  nsresult PersistFolderInfo(nsIDBFolderInfo **dbFolderInfo);
  void     SetMRUTimeForFolder(nsIMsgFolder *folder);

  nsMsgKey  GetAt(nsMsgViewIndex index)
                  {return m_keys.SafeElementAt(index, nsMsgKey_None);}
  nsMsgViewIndex FindViewIndex(nsMsgKey  key)
     {return FindKey(key, false);}
  /**
   * Find the message header if it is visible in this view.  (Messages in
   *     threads/groups that are elided will not be
   * @param msgHdr Message header to look for.
   * @param startIndex The index to start looking from.
   * @param allowDummy Are dummy headers acceptable?  If yes, then for a group
   *     with a dummy header, we return the root of the thread (the dummy
   *     header), otherwise we return the actual "content" header for the
   *     message.
   * @return The view index of the header found, if any.
   */
  virtual nsMsgViewIndex FindHdr(nsIMsgDBHdr *msgHdr, nsMsgViewIndex startIndex = 0,
                                 bool allowDummy=false);
  virtual nsMsgViewIndex FindKey(nsMsgKey key, bool expand);
  virtual nsresult GetDBForViewIndex(nsMsgViewIndex index, nsIMsgDatabase **db);
  virtual nsCOMArray<nsIMsgFolder>* GetFolders();
  virtual nsresult GetFolderFromMsgURI(const char *aMsgURI, nsIMsgFolder **aFolder);

  virtual nsresult ListIdsInThread(nsIMsgThread *threadHdr, nsMsgViewIndex viewIndex, uint32_t *pNumListed);
  nsresult ListUnreadIdsInThread(nsIMsgThread *threadHdr, nsMsgViewIndex startOfThreadViewIndex, uint32_t *pNumListed);
  nsMsgViewIndex FindParentInThread(nsMsgKey parentKey, nsMsgViewIndex startOfThreadViewIndex);
  virtual nsresult ListIdsInThreadOrder(nsIMsgThread *threadHdr,
                                        nsMsgKey parentKey, uint32_t level,
                                        nsMsgViewIndex *viewIndex,
                                        uint32_t *pNumListed);
  uint32_t GetSize(void) {return(m_keys.Length());}

  // notification api's
  void  NoteStartChange(nsMsgViewIndex firstlineChanged, int32_t numChanged,
                        nsMsgViewNotificationCodeValue changeType);
  void  NoteEndChange(nsMsgViewIndex firstlineChanged, int32_t numChanged,
                        nsMsgViewNotificationCodeValue changeType);

  // for commands
  virtual nsresult ApplyCommandToIndices(nsMsgViewCommandTypeValue command, nsMsgViewIndex* indices,
                                         int32_t numIndices);
  virtual nsresult ApplyCommandToIndicesWithFolder(nsMsgViewCommandTypeValue command, nsMsgViewIndex* indices,
                    int32_t numIndices, nsIMsgFolder *destFolder);
  virtual nsresult CopyMessages(nsIMsgWindow *window, nsMsgViewIndex *indices, int32_t numIndices, bool isMove, nsIMsgFolder *destFolder);
  virtual nsresult DeleteMessages(nsIMsgWindow *window, nsMsgViewIndex *indices, int32_t numIndices, bool deleteStorage);
  nsresult GetHeadersFromSelection(uint32_t *indices, uint32_t numIndices, nsIMutableArray *messageArray);
  virtual nsresult ListCollapsedChildren(nsMsgViewIndex viewIndex,
                                         nsIMutableArray *messageArray);

  nsresult SetMsgHdrJunkStatus(nsIJunkMailPlugin *aJunkPlugin,
                               nsIMsgDBHdr *aMsgHdr,
                               nsMsgJunkStatus aNewClassification);
  nsresult ToggleReadByIndex(nsMsgViewIndex index);
  nsresult SetReadByIndex(nsMsgViewIndex index, bool read);
  nsresult SetThreadOfMsgReadByIndex(nsMsgViewIndex index, nsTArray<nsMsgKey> &keysMarkedRead, bool read);
  nsresult SetFlaggedByIndex(nsMsgViewIndex index, bool mark);
  nsresult SetLabelByIndex(nsMsgViewIndex index, nsMsgLabelValue label);
  nsresult OrExtraFlag(nsMsgViewIndex index, uint32_t orflag);
  nsresult AndExtraFlag(nsMsgViewIndex index, uint32_t andflag);
  nsresult SetExtraFlag(nsMsgViewIndex index, uint32_t extraflag);
  virtual nsresult RemoveByIndex(nsMsgViewIndex index);
  virtual void OnExtraFlagChanged(nsMsgViewIndex /*index*/, uint32_t /*extraFlag*/) {}
  virtual void OnHeaderAddedOrDeleted() {}	
  nsresult ToggleWatched( nsMsgViewIndex* indices,	int32_t numIndices);
  nsresult SetThreadWatched(nsIMsgThread *thread, nsMsgViewIndex index, bool watched);
  nsresult SetThreadIgnored(nsIMsgThread *thread, nsMsgViewIndex threadIndex, bool ignored);
  nsresult SetSubthreadKilled(nsIMsgDBHdr *header, nsMsgViewIndex msgIndex, bool ignored);
  nsresult DownloadForOffline(nsIMsgWindow *window, nsMsgViewIndex *indices, int32_t numIndices);
  nsresult DownloadFlaggedForOffline(nsIMsgWindow *window);
  nsMsgViewIndex	GetThreadFromMsgIndex(nsMsgViewIndex index, nsIMsgThread **threadHdr);
  /// Should junk commands be enabled for the current message in the view?
  bool JunkControlsEnabled(nsMsgViewIndex aViewIndex);

  // for sorting
  nsresult GetFieldTypeAndLenForSort(nsMsgViewSortTypeValue sortType,
                                        uint16_t *pMaxLen,
                                        eFieldType *pFieldType,
                                        nsIMsgCustomColumnHandler* colHandler = nullptr);
  nsresult GetCollationKey(nsIMsgDBHdr *msgHdr,
                             nsMsgViewSortTypeValue sortType,
                             uint8_t **result,
                             uint32_t *len,
                             nsIMsgCustomColumnHandler* colHandler = nullptr);
  nsresult GetLongField(nsIMsgDBHdr *msgHdr,
                          nsMsgViewSortTypeValue sortType,
                          uint32_t *result,
                          nsIMsgCustomColumnHandler* colHandler = nullptr);

  static int FnSortIdKey(const void *pItem1, const void *pItem2, void *privateData);
  static int FnSortIdKeyPtr(const void *pItem1, const void *pItem2, void *privateData);
  static int FnSortIdUint32(const void *pItem1, const void *pItem2, void *privateData);

  nsresult GetStatusSortValue(nsIMsgDBHdr *msgHdr, uint32_t *result);
  nsresult GetLocationCollationKey(nsIMsgDBHdr *msgHdr, uint8_t **result, uint32_t *len);
  void PushSort(const MsgViewSortColumnInfo &newSort);
  nsresult EncodeColumnSort(nsString &columnSortString);
  nsresult DecodeColumnSort(nsString &columnSortString);
  // for view navigation
  nsresult NavigateFromPos(nsMsgNavigationTypeValue motion, nsMsgViewIndex startIndex, nsMsgKey *pResultKey, 
              nsMsgViewIndex *pResultIndex, nsMsgViewIndex *pThreadIndex, bool wrap);
  nsresult FindNextFlagged(nsMsgViewIndex startIndex, nsMsgViewIndex *pResultIndex);
  nsresult FindFirstNew(nsMsgViewIndex *pResultIndex);
  nsresult FindPrevUnread(nsMsgKey startKey, nsMsgKey *pResultKey, nsMsgKey *resultThreadId);
  nsresult FindFirstFlagged(nsMsgViewIndex *pResultIndex);
  nsresult FindPrevFlagged(nsMsgViewIndex startIndex, nsMsgViewIndex *pResultIndex);
  nsresult MarkThreadOfMsgRead(nsMsgKey msgId, nsMsgViewIndex msgIndex, nsTArray<nsMsgKey> &idsMarkedRead, bool bRead);
  nsresult MarkThreadRead(nsIMsgThread *threadHdr, nsMsgViewIndex threadIndex, nsTArray<nsMsgKey> &idsMarkedRead, bool bRead);
  bool IsValidIndex(nsMsgViewIndex index);
  nsresult ToggleIgnored(nsMsgViewIndex * indices, int32_t numIndices, nsMsgViewIndex *resultIndex, bool *resultToggleState);
  nsresult ToggleMessageKilled(nsMsgViewIndex * indices, int32_t numIndices, nsMsgViewIndex *resultIndex, bool *resultToggleState);
  bool OfflineMsgSelected(nsMsgViewIndex * indices, int32_t numIndices);
  bool NonDummyMsgSelected(nsMsgViewIndex * indices, int32_t numIndices);
  char16_t * GetString(const char16_t *aStringName);
  nsresult GetPrefLocalizedString(const char *aPrefName, nsString& aResult);
  nsresult GetLabelPrefStringAndAtom(const char *aPrefName, nsString& aColor, nsIAtom** aColorAtom);
  nsresult AppendKeywordProperties(const nsACString& keywords, nsAString& properties, bool addSelectedTextProperty);
  nsresult InitLabelStrings(void);
  nsresult CopyDBView(nsMsgDBView *aNewMsgDBView, nsIMessenger *aMessengerInstance, nsIMsgWindow *aMsgWindow, nsIMsgDBViewCommandUpdater *aCmdUpdater);
  void InitializeAtomsAndLiterals();
  virtual int32_t FindLevelInThread(nsIMsgDBHdr *msgHdr, nsMsgViewIndex startOfThread, nsMsgViewIndex viewIndex);
  nsresult GetImapDeleteModel(nsIMsgFolder *folder);
  nsresult UpdateDisplayMessage(nsMsgViewIndex viewPosition);
  nsresult GetDBForHeader(nsIMsgDBHdr *msgHdr, nsIMsgDatabase **db);

  bool AdjustReadFlag(nsIMsgDBHdr *msgHdr, uint32_t *msgFlags);
  void FreeAll(nsTArray<void*> *ptrs);
  void ClearHdrCache();
  nsTArray<nsMsgKey> m_keys;
  nsTArray<uint32_t> m_flags;
  nsTArray<uint8_t> m_levels;
  nsMsgImapDeleteModel mDeleteModel;

  // cache the most recently asked for header and corresponding msgKey.
  nsCOMPtr <nsIMsgDBHdr>  m_cachedHdr;
  nsMsgKey                m_cachedMsgKey;

  // we need to store the message key for the message we are currenty displaying to ensure we
  // don't try to redisplay the same message just because the selection changed (i.e. after a sort)
  nsMsgKey                m_currentlyDisplayedMsgKey;
  nsCString               m_currentlyDisplayedMsgUri;
  nsMsgViewIndex          m_currentlyDisplayedViewIndex;
  // if we're deleting messages, we want to hold off loading messages on selection changed until the delete is done
  // and we want to batch notifications.
  bool m_deletingRows;
  // for certain special folders 
  // and decendents of those folders
  // (like the "Sent" folder, "Sent/Old Sent")
  // the Sender column really shows recipients.

  // Server types for this view's folder
  bool mIsNews;             // we have special icons for news
  bool mIsRss;              // rss affects enabling of junk commands
  bool mIsXFVirtual;        // a virtual folder with multiple folders

  bool mShowSizeInLines;    // for news we show lines instead of size when true
  bool mSortThreadsByRoot;  // as opposed to by the newest message
  bool m_sortValid;
  bool m_checkedCustomColumns;
  bool mSelectionSummarized;
  // we asked the front end to summarize the selection and it did not.
  bool mSummarizeFailed;
  uint8_t      m_saveRestoreSelectionDepth;

  nsCOMPtr <nsIMsgDatabase> m_db;
  nsCOMPtr <nsIMsgFolder> m_folder;
  nsCOMPtr <nsIMsgFolder> m_viewFolder; // for virtual folders, the VF db.
  nsString mMessageType;
  nsTArray <MsgViewSortColumnInfo> m_sortColumns;
  nsMsgViewSortTypeValue  m_sortType;
  nsMsgViewSortOrderValue m_sortOrder;
  nsString m_curCustomColumn;
  nsMsgViewSortTypeValue m_secondarySort;
  nsMsgViewSortOrderValue m_secondarySortOrder;
  nsString m_secondaryCustomColumn;
  nsMsgViewFlagsTypeValue m_viewFlags;

  // I18N date formatter service which we'll want to cache locally.
  nsCOMPtr<nsIDateTimeFormat> mDateFormatter;
  nsCOMPtr<nsIMsgTagService> mTagService;
  nsWeakPtr mMessengerWeak;
  nsWeakPtr mMsgWindowWeak;
  nsCOMPtr<nsIMsgDBViewCommandUpdater> mCommandUpdater; // we push command update notifications to the UI from this.
  nsCOMPtr<nsIStringBundle> mMessengerStringBundle;  

  // used for the preference labels
  nsString mLabelPrefDescriptions[PREF_LABELS_MAX];
  nsString mLabelPrefColors[PREF_LABELS_MAX];
  // used to cache the atoms created for each color to be displayed
  static nsIAtom* mLabelPrefColorAtoms[PREF_LABELS_MAX];

  // used to determine when to start and end
  // junk plugin batches
  uint32_t mNumMessagesRemainingInBatch;

  // these are the headers of the messages in the current
  // batch/series of batches of messages manually marked
  // as junk
  nsCOMPtr<nsIMutableArray> mJunkHdrs;
  
  nsTArray<uint32_t> mIndicesToNoteChange;

  nsTHashtable<nsCStringHashKey> mEmails;

  // the saved search views keep track of the XX most recently deleted msg ids, so that if the 
  // delete is undone, we can add the msg back to the search results, even if it no longer
  // matches the search criteria (e.g., a saved search over unread messages).
  // We use mRecentlyDeletedArrayIndex to treat the array as a list of the XX
  // most recently deleted msgs.
  nsTArray<nsCString> mRecentlyDeletedMsgIds;
  uint32_t mRecentlyDeletedArrayIndex;
  void RememberDeletedMsgHdr(nsIMsgDBHdr *msgHdr);
  bool WasHdrRecentlyDeleted(nsIMsgDBHdr *msgHdr);
  
  //these hold pointers (and IDs) for the nsIMsgCustomColumnHandler object that constitutes the custom column handler
  nsCOMArray <nsIMsgCustomColumnHandler> m_customColumnHandlers;
  nsTArray<nsString> m_customColumnHandlerIDs;
  
  nsIMsgCustomColumnHandler* GetColumnHandler(const char16_t*);
  nsIMsgCustomColumnHandler* GetCurColumnHandler();
  bool CustomColumnsInSortAndNotRegistered();
  void EnsureCustomColumnsValid();

#ifdef DEBUG_David_Bienvenu
void InitEntryInfoForIndex(nsMsgViewIndex i, IdKeyPtr &EntryInfo);
void ValidateSort();
#endif

protected:
  static nsresult   InitDisplayFormats();

private:
  static nsDateFormatSelector  m_dateFormatDefault;
  static nsDateFormatSelector  m_dateFormatThisWeek;
  static nsDateFormatSelector  m_dateFormatToday;
  bool ServerSupportsFilterAfterTheFact();

  nsresult PerformActionsOnJunkMsgs(bool msgsAreJunk);
  nsresult DetermineActionsForJunkChange(bool msgsAreJunk,
                                         nsIMsgFolder *srcFolder,
                                         bool &moveMessages,
                                         bool &changeReadState,
                                         nsIMsgFolder** targetFolder);

  class nsMsgViewHdrEnumerator final : public nsISimpleEnumerator
  {
  public:
    NS_DECL_ISUPPORTS

    // nsISimpleEnumerator methods:
    NS_DECL_NSISIMPLEENUMERATOR

    // nsMsgThreadEnumerator methods:
    explicit nsMsgViewHdrEnumerator(nsMsgDBView *view);

    RefPtr<nsMsgDBView> m_view;
    nsMsgViewIndex m_curHdrIndex;

  private:
    ~nsMsgViewHdrEnumerator();
  };
};

#endif