1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Pierre Phaneuf <pp@ludusdesign.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsIServiceManager.h"
40 #include "nsIComponentManager.h"
42 #include "nsIRDFDataSource.h"
43 #include "nsIRDFService.h"
44 #include "nsIRDFContainerUtils.h"
46 #include "nsXPIDLString.h"
47 #include "nsCharsetMenu.h"
48 #include "nsICharsetConverterManager.h"
49 #include "nsICollation.h"
50 #include "nsCollationCID.h"
51 #include "nsLocaleCID.h"
52 #include "nsIGenericFactory.h"
53 #include "nsILocaleService.h"
54 #include "nsIPrefService.h"
55 #include "nsIPrefBranch.h"
56 #include "nsIPrefBranch2.h"
57 #include "nsIPrefLocalizedString.h"
58 #include "nsICurrentCharsetListener.h"
59 #include "nsQuickSort.h"
60 #include "nsIObserver.h"
61 #include "nsStringEnumerator.h"
62 #include "nsVoidArray.h"
63 #include "nsIObserverService.h"
64 #include "nsIRequestObserver.h"
65 #include "nsITimelineService.h"
68 #include "nsCycleCollectionParticipant.h"
70 //----------------------------------------------------------------------------
71 // Global functions and data [declaration]
73 static NS_DEFINE_CID(kRDFServiceCID
, NS_RDFSERVICE_CID
);
74 static NS_DEFINE_CID(kRDFInMemoryDataSourceCID
, NS_RDFINMEMORYDATASOURCE_CID
);
75 static NS_DEFINE_CID(kRDFContainerUtilsCID
, NS_RDFCONTAINERUTILS_CID
);
76 static NS_DEFINE_CID(kRDFContainerCID
, NS_RDFCONTAINER_CID
);
78 static const char kURINC_BrowserAutodetMenuRoot
[] = "NC:BrowserAutodetMenuRoot";
79 static const char kURINC_BrowserCharsetMenuRoot
[] = "NC:BrowserCharsetMenuRoot";
80 static const char kURINC_BrowserMoreCharsetMenuRoot
[] = "NC:BrowserMoreCharsetMenuRoot";
81 static const char kURINC_BrowserMore1CharsetMenuRoot
[] = "NC:BrowserMore1CharsetMenuRoot";
82 static const char kURINC_BrowserMore2CharsetMenuRoot
[] = "NC:BrowserMore2CharsetMenuRoot";
83 static const char kURINC_BrowserMore3CharsetMenuRoot
[] = "NC:BrowserMore3CharsetMenuRoot";
84 static const char kURINC_BrowserMore4CharsetMenuRoot
[] = "NC:BrowserMore4CharsetMenuRoot";
85 static const char kURINC_BrowserMore5CharsetMenuRoot
[] = "NC:BrowserMore5CharsetMenuRoot";
86 static const char kURINC_BrowserUnicodeCharsetMenuRoot
[] = "NC:BrowserUnicodeCharsetMenuRoot";
87 static const char kURINC_MaileditCharsetMenuRoot
[] = "NC:MaileditCharsetMenuRoot";
88 static const char kURINC_MailviewCharsetMenuRoot
[] = "NC:MailviewCharsetMenuRoot";
89 static const char kURINC_ComposerCharsetMenuRoot
[] = "NC:ComposerCharsetMenuRoot";
90 static const char kURINC_DecodersRoot
[] = "NC:DecodersRoot";
91 static const char kURINC_EncodersRoot
[] = "NC:EncodersRoot";
92 DEFINE_RDF_VOCAB(NC_NAMESPACE_URI
, NC
, Name
);
93 DEFINE_RDF_VOCAB(NC_NAMESPACE_URI
, NC
, Checked
);
94 DEFINE_RDF_VOCAB(NC_NAMESPACE_URI
, NC
, BookmarkSeparator
);
95 DEFINE_RDF_VOCAB(NC_NAMESPACE_URI
, NC
, CharsetDetector
);
96 DEFINE_RDF_VOCAB(RDF_NAMESPACE_URI
, NC
, type
);
98 // Note here that browser and mailview have the same static area and cache
99 // size but the cache itself is separate.
101 #define kBrowserStaticPrefKey "intl.charsetmenu.browser.static"
102 #define kBrowserCachePrefKey "intl.charsetmenu.browser.cache"
103 #define kBrowserCacheSizePrefKey "intl.charsetmenu.browser.cache.size"
105 #define kMailviewStaticPrefKey "intl.charsetmenu.browser.static"
106 #define kMailviewCachePrefKey "intl.charsetmenu.mailview.cache"
107 #define kMailviewCacheSizePrefKey "intl.charsetmenu.browser.cache.size"
109 #define kComposerStaticPrefKey "intl.charsetmenu.browser.static"
110 #define kComposerCachePrefKey "intl.charsetmenu.composer.cache"
111 #define kComposerCacheSizePrefKey "intl.charsetmenu.browser.cache.size"
113 #define kMaileditPrefKey "intl.charsetmenu.mailedit"
115 static void CloneCStringArray(const nsCStringArray
& src
, nsCStringArray
& dest
)
117 PRUint32 count
= src
.Count();
119 for (i
=0; i
<count
; i
++) {
120 dest
.AppendCString(*src
.CStringAt(i
));
124 //----------------------------------------------------------------------------
125 // Class nsMenuEntry [declaration]
128 * A little class holding all data needed for a menu item.
130 * @created 18/Apr/2000
131 * @author Catalin Rotaru [CATA]
136 // memory & ref counting & leak prevention stuff
137 nsMenuEntry() { MOZ_COUNT_CTOR(nsMenuEntry
); }
138 ~nsMenuEntry() { MOZ_COUNT_DTOR(nsMenuEntry
); }
140 nsCAutoString mCharset
;
144 //----------------------------------------------------------------------------
145 // Class nsCharsetMenu [declaration]
148 * The Charset Converter menu.
150 * God, our GUI programming disgusts me.
152 * @created 23/Nov/1999
153 * @author Catalin Rotaru [CATA]
155 class nsCharsetMenu
: public nsIRDFDataSource
, public nsICurrentCharsetListener
157 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
158 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsCharsetMenu
, nsIRDFDataSource
)
161 static nsIRDFResource
* kNC_BrowserAutodetMenuRoot
;
162 static nsIRDFResource
* kNC_BrowserCharsetMenuRoot
;
163 static nsIRDFResource
* kNC_BrowserMoreCharsetMenuRoot
;
164 static nsIRDFResource
* kNC_BrowserMore1CharsetMenuRoot
;
165 static nsIRDFResource
* kNC_BrowserMore2CharsetMenuRoot
;
166 static nsIRDFResource
* kNC_BrowserMore3CharsetMenuRoot
;
167 static nsIRDFResource
* kNC_BrowserMore4CharsetMenuRoot
;
168 static nsIRDFResource
* kNC_BrowserMore5CharsetMenuRoot
;
169 static nsIRDFResource
* kNC_BrowserUnicodeCharsetMenuRoot
;
170 static nsIRDFResource
* kNC_MaileditCharsetMenuRoot
;
171 static nsIRDFResource
* kNC_MailviewCharsetMenuRoot
;
172 static nsIRDFResource
* kNC_ComposerCharsetMenuRoot
;
173 static nsIRDFResource
* kNC_DecodersRoot
;
174 static nsIRDFResource
* kNC_EncodersRoot
;
175 static nsIRDFResource
* kNC_Name
;
176 static nsIRDFResource
* kNC_Checked
;
177 static nsIRDFResource
* kNC_CharsetDetector
;
178 static nsIRDFResource
* kNC_BookmarkSeparator
;
179 static nsIRDFResource
* kRDF_type
;
181 static nsIRDFDataSource
* mInner
;
183 PRPackedBool mInitialized
;
184 PRPackedBool mBrowserMenuInitialized
;
185 PRPackedBool mMailviewMenuInitialized
;
186 PRPackedBool mComposerMenuInitialized
;
187 PRPackedBool mMaileditMenuInitialized
;
188 PRPackedBool mSecondaryTiersInitialized
;
189 PRPackedBool mAutoDetectInitialized
;
190 PRPackedBool mOthersInitialized
;
192 nsVoidArray mBrowserMenu
;
193 PRInt32 mBrowserCacheStart
;
194 PRInt32 mBrowserCacheSize
;
195 PRInt32 mBrowserMenuRDFPosition
;
197 nsVoidArray mMailviewMenu
;
198 PRInt32 mMailviewCacheStart
;
199 PRInt32 mMailviewCacheSize
;
200 PRInt32 mMailviewMenuRDFPosition
;
202 nsVoidArray mComposerMenu
;
203 PRInt32 mComposerCacheStart
;
204 PRInt32 mComposerCacheSize
;
205 PRInt32 mComposerMenuRDFPosition
;
207 nsCOMPtr
<nsIRDFService
> mRDFService
;
208 nsCOMPtr
<nsICharsetConverterManager
> mCCManager
;
209 nsCOMPtr
<nsIPrefBranch
> mPrefs
;
210 nsCOMPtr
<nsIObserver
> mCharsetMenuObserver
;
211 nsCStringArray mDecoderList
;
214 nsresult
SetCharsetCheckmark(nsString
* aCharset
, PRBool aValue
);
216 nsresult
FreeResources();
218 nsresult
InitStaticMenu(nsCStringArray
& aDecs
,
219 nsIRDFResource
* aResource
,
221 nsVoidArray
* aArray
);
222 nsresult
InitCacheMenu(nsCStringArray
& aDecs
,
223 nsIRDFResource
* aResource
,
225 nsVoidArray
* aArray
);
227 nsresult
InitMoreMenu(nsCStringArray
& aDecs
,
228 nsIRDFResource
* aResource
,
231 nsresult
InitMoreSubmenus(nsCStringArray
& aDecs
);
233 static nsresult
SetArrayFromEnumerator(nsIUTF8StringEnumerator
* aEnumerator
,
234 nsCStringArray
& aArray
);
236 nsresult
AddCharsetToItemArray(nsVoidArray
* aArray
,
237 const nsAFlatCString
& aCharset
,
238 nsMenuEntry
** aResult
,
240 nsresult
AddCharsetArrayToItemArray(nsVoidArray
&aArray
,
241 const nsCStringArray
& aCharsets
);
242 nsresult
AddMenuItemToContainer(nsIRDFContainer
* aContainer
,
243 nsMenuEntry
* aItem
, nsIRDFResource
* aType
, const char * aIDPrefix
,
245 nsresult
AddMenuItemArrayToContainer(nsIRDFContainer
* aContainer
,
246 nsVoidArray
* aArray
, nsIRDFResource
* aType
);
247 nsresult
AddCharsetToContainer(nsVoidArray
* aArray
,
248 nsIRDFContainer
* aContainer
,
249 const nsAFlatCString
& aCharset
,
250 const char * aIDPrefix
,
251 PRInt32 aPlace
, PRInt32 aRDFPlace
);
253 nsresult
AddFromPrefsToMenu(nsVoidArray
* aArray
,
254 nsIRDFContainer
* aContainer
,
256 nsCStringArray
& aDecs
,
257 const char * aIDPrefix
);
258 nsresult
AddFromNolocPrefsToMenu(nsVoidArray
* aArray
,
259 nsIRDFContainer
* aContainer
,
261 nsCStringArray
& aDecs
,
262 const char * aIDPrefix
);
263 nsresult
AddFromStringToMenu(char * aCharsetList
,
264 nsVoidArray
* aArray
,
265 nsIRDFContainer
* aContainer
,
266 nsCStringArray
& aDecs
,
267 const char * aIDPrefix
);
269 nsresult
AddSeparatorToContainer(nsIRDFContainer
* aContainer
);
270 nsresult
AddCharsetToCache(const nsAFlatCString
& aCharset
,
271 nsVoidArray
* aArray
,
272 nsIRDFResource
* aRDFResource
,
273 PRInt32 aCacheStart
, PRInt32 aCacheSize
,
276 nsresult
WriteCacheToPrefs(nsVoidArray
* aArray
, PRInt32 aCacheStart
,
278 nsresult
UpdateCachePrefs(const char * aCacheKey
, const char * aCacheSizeKey
,
279 const char * aStaticKey
, const PRUnichar
* aCharset
);
281 nsresult
ClearMenu(nsIRDFContainer
* aContainer
, nsVoidArray
* aArray
);
282 nsresult
RemoveLastMenuItem(nsIRDFContainer
* aContainer
,
283 nsVoidArray
* aArray
);
285 nsresult
RemoveFlaggedCharsets(nsCStringArray
& aList
, const nsString
& aProp
);
286 nsresult
NewRDFContainer(nsIRDFDataSource
* aDataSource
,
287 nsIRDFResource
* aResource
, nsIRDFContainer
** aResult
);
288 void FreeMenuItemArray(nsVoidArray
* aArray
);
289 PRInt32
FindMenuItemInArray(const nsVoidArray
* aArray
,
290 const nsAFlatCString
& aCharset
,
291 nsMenuEntry
** aResult
);
292 nsresult
ReorderMenuItemArray(nsVoidArray
* aArray
);
293 nsresult
GetCollation(nsICollation
** aCollation
);
297 virtual ~nsCharsetMenu();
300 nsresult
InitBrowserMenu();
301 nsresult
InitMaileditMenu();
302 nsresult
InitMailviewMenu();
303 nsresult
InitComposerMenu();
304 nsresult
InitOthers();
305 nsresult
InitSecondaryTiers();
306 nsresult
InitAutodetMenu();
307 nsresult
RefreshBrowserMenu();
308 nsresult
RefreshMailviewMenu();
309 nsresult
RefreshMaileditMenu();
310 nsresult
RefreshComposerMenu();
312 //--------------------------------------------------------------------------
313 // Interface nsICurrentCharsetListener [declaration]
315 NS_IMETHOD
SetCurrentCharset(const PRUnichar
* aCharset
);
316 NS_IMETHOD
SetCurrentMailCharset(const PRUnichar
* aCharset
);
317 NS_IMETHOD
SetCurrentComposerCharset(const PRUnichar
* aCharset
);
319 //--------------------------------------------------------------------------
320 // Interface nsIRDFDataSource [declaration]
322 NS_DECL_NSIRDFDATASOURCE
325 //----------------------------------------------------------------------------
326 // Global functions and data [implementation]
328 NS_IMETHODIMP
NS_NewCharsetMenu(nsISupports
* aOuter
, const nsIID
& aIID
,
332 return NS_ERROR_NULL_POINTER
;
336 return NS_ERROR_NO_AGGREGATION
;
338 nsCharsetMenu
* inst
= new nsCharsetMenu();
341 return NS_ERROR_OUT_OF_MEMORY
;
343 nsresult res
= inst
->QueryInterface(aIID
, aResult
);
344 if (NS_FAILED(res
)) {
351 struct charsetMenuSortRecord
{
358 static int CompareMenuItems(const void* aArg1
, const void* aArg2
, void *data
)
361 nsICollation
* collation
= (nsICollation
*) data
;
362 charsetMenuSortRecord
*rec1
= (charsetMenuSortRecord
*) aArg1
;
363 charsetMenuSortRecord
*rec2
= (charsetMenuSortRecord
*) aArg2
;
365 collation
->CompareRawSortKey(rec1
->key
, rec1
->len
, rec2
->key
, rec2
->len
, &res
);
371 nsCharsetMenu::SetArrayFromEnumerator(nsIUTF8StringEnumerator
* aEnumerator
,
372 nsCStringArray
& aArray
)
377 rv
= aEnumerator
->HasMore(&hasMore
);
380 while (NS_SUCCEEDED(rv
) && hasMore
) {
381 rv
= aEnumerator
->GetNext(value
);
382 if (NS_SUCCEEDED(rv
))
383 aArray
.AppendCString(value
);
385 rv
= aEnumerator
->HasMore(&hasMore
);
391 //----------------------------------------------------------------------------
392 // Class nsCharsetMenuObserver
394 class nsCharsetMenuObserver
: public nsIObserver
{
400 nsCharsetMenuObserver(nsCharsetMenu
* menu
)
405 virtual ~nsCharsetMenuObserver() {}
408 nsCharsetMenu
* mCharsetMenu
;
411 NS_IMPL_ISUPPORTS1(nsCharsetMenuObserver
, nsIObserver
)
413 NS_IMETHODIMP
nsCharsetMenuObserver::Observe(nsISupports
*aSubject
, const char *aTopic
, const PRUnichar
*someData
)
415 NS_TIMELINE_START_TIMER("nsCharsetMenu:Observe");
419 if (!nsCRT::strcmp(aTopic
, "charsetmenu-selected")) {
420 nsDependentString
nodeName(someData
);
421 rv
= mCharsetMenu
->Init();
422 if (nodeName
.EqualsLiteral("browser")) {
423 rv
= mCharsetMenu
->InitBrowserMenu();
425 if (nodeName
.EqualsLiteral("composer")) {
426 rv
= mCharsetMenu
->InitComposerMenu();
428 if (nodeName
.EqualsLiteral("mailview")) {
429 rv
= mCharsetMenu
->InitMailviewMenu();
431 if (nodeName
.EqualsLiteral("mailedit")) {
432 rv
= mCharsetMenu
->InitMaileditMenu();
433 rv
= mCharsetMenu
->InitOthers();
435 if (nodeName
.EqualsLiteral("more-menu")) {
436 rv
= mCharsetMenu
->InitSecondaryTiers();
437 rv
= mCharsetMenu
->InitAutodetMenu();
439 if (nodeName
.EqualsLiteral("other")) {
440 rv
= mCharsetMenu
->InitOthers();
441 rv
= mCharsetMenu
->InitMaileditMenu();
446 if (!nsCRT::strcmp(aTopic
, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
)) {
447 nsDependentString
prefName(someData
);
449 if (prefName
.EqualsLiteral(kBrowserStaticPrefKey
)) {
450 // refresh menus which share this pref
451 rv
= mCharsetMenu
->RefreshBrowserMenu();
452 NS_ENSURE_SUCCESS(rv
, rv
);
453 rv
= mCharsetMenu
->RefreshMailviewMenu();
454 NS_ENSURE_SUCCESS(rv
, rv
);
455 rv
= mCharsetMenu
->RefreshComposerMenu();
457 else if (prefName
.EqualsLiteral(kMaileditPrefKey
)) {
458 rv
= mCharsetMenu
->RefreshMaileditMenu();
462 NS_TIMELINE_STOP_TIMER("nsCharsetMenu:Observe");
463 NS_TIMELINE_MARK_TIMER("nsCharsetMenu:Observe");
467 //----------------------------------------------------------------------------
468 // Class nsCharsetMenu [implementation]
470 NS_IMPL_CYCLE_COLLECTION_CLASS(nsCharsetMenu
)
471 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsCharsetMenu
)
472 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCharsetMenu
)
473 cb
.NoteXPCOMChild(nsCharsetMenu::mInner
);
474 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
476 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsCharsetMenu
, nsIRDFDataSource
)
477 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsCharsetMenu
, nsIRDFDataSource
)
478 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCharsetMenu
)
479 NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource
)
480 NS_INTERFACE_MAP_ENTRY(nsICurrentCharsetListener
)
481 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIRDFDataSource
)
484 nsIRDFDataSource
* nsCharsetMenu::mInner
= NULL
;
485 nsIRDFResource
* nsCharsetMenu::kNC_BrowserAutodetMenuRoot
= NULL
;
486 nsIRDFResource
* nsCharsetMenu::kNC_BrowserCharsetMenuRoot
= NULL
;
487 nsIRDFResource
* nsCharsetMenu::kNC_BrowserMoreCharsetMenuRoot
= NULL
;
488 nsIRDFResource
* nsCharsetMenu::kNC_BrowserMore1CharsetMenuRoot
= NULL
;
489 nsIRDFResource
* nsCharsetMenu::kNC_BrowserMore2CharsetMenuRoot
= NULL
;
490 nsIRDFResource
* nsCharsetMenu::kNC_BrowserMore3CharsetMenuRoot
= NULL
;
491 nsIRDFResource
* nsCharsetMenu::kNC_BrowserMore4CharsetMenuRoot
= NULL
;
492 nsIRDFResource
* nsCharsetMenu::kNC_BrowserMore5CharsetMenuRoot
= NULL
;
493 nsIRDFResource
* nsCharsetMenu::kNC_BrowserUnicodeCharsetMenuRoot
= NULL
;
494 nsIRDFResource
* nsCharsetMenu::kNC_MaileditCharsetMenuRoot
= NULL
;
495 nsIRDFResource
* nsCharsetMenu::kNC_MailviewCharsetMenuRoot
= NULL
;
496 nsIRDFResource
* nsCharsetMenu::kNC_ComposerCharsetMenuRoot
= NULL
;
497 nsIRDFResource
* nsCharsetMenu::kNC_DecodersRoot
= NULL
;
498 nsIRDFResource
* nsCharsetMenu::kNC_EncodersRoot
= NULL
;
499 nsIRDFResource
* nsCharsetMenu::kNC_Name
= NULL
;
500 nsIRDFResource
* nsCharsetMenu::kNC_Checked
= NULL
;
501 nsIRDFResource
* nsCharsetMenu::kNC_CharsetDetector
= NULL
;
502 nsIRDFResource
* nsCharsetMenu::kNC_BookmarkSeparator
= NULL
;
503 nsIRDFResource
* nsCharsetMenu::kRDF_type
= NULL
;
505 nsCharsetMenu::nsCharsetMenu()
506 : mInitialized(PR_FALSE
),
507 mBrowserMenuInitialized(PR_FALSE
),
508 mMailviewMenuInitialized(PR_FALSE
),
509 mComposerMenuInitialized(PR_FALSE
),
510 mMaileditMenuInitialized(PR_FALSE
),
511 mSecondaryTiersInitialized(PR_FALSE
),
512 mAutoDetectInitialized(PR_FALSE
),
513 mOthersInitialized(PR_FALSE
)
515 NS_TIMELINE_START_TIMER("nsCharsetMenu::nsCharsetMenu");
516 nsresult res
= NS_OK
;
518 //get charset manager
519 mCCManager
= do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID
, &res
);
521 //initialize skeleton RDF source
522 mRDFService
= do_GetService(kRDFServiceCID
, &res
);
524 if (NS_SUCCEEDED(res
)) {
525 mRDFService
->RegisterDataSource(this, PR_FALSE
);
527 CallCreateInstance(kRDFInMemoryDataSourceCID
, &mInner
);
529 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserCharsetMenuRoot
),
530 &kNC_BrowserCharsetMenuRoot
);
534 nsCOMPtr
<nsIPrefService
> PrefService
= do_GetService(NS_PREFSERVICE_CONTRACTID
, &res
);
535 if (NS_SUCCEEDED(res
))
536 res
= PrefService
->GetBranch(nsnull
, getter_AddRefs(mPrefs
));
538 //register event listener
539 mCharsetMenuObserver
= new nsCharsetMenuObserver(this);
541 if (mCharsetMenuObserver
) {
542 nsCOMPtr
<nsIObserverService
> observerService
=
543 do_GetService("@mozilla.org/observer-service;1", &res
);
545 if (NS_SUCCEEDED(res
))
546 res
= observerService
->AddObserver(mCharsetMenuObserver
,
547 "charsetmenu-selected",
551 NS_ASSERTION(NS_SUCCEEDED(res
), "Failed to initialize nsCharsetMenu");
552 NS_TIMELINE_STOP_TIMER("nsCharsetMenu::nsCharsetMenu");
553 NS_TIMELINE_MARK_TIMER("nsCharsetMenu::nsCharsetMenu");
556 nsCharsetMenu::~nsCharsetMenu()
560 FreeMenuItemArray(&mBrowserMenu
);
561 FreeMenuItemArray(&mMailviewMenu
);
562 FreeMenuItemArray(&mComposerMenu
);
567 // XXX collapse these 2 in one
569 nsresult
nsCharsetMenu::RefreshBrowserMenu()
571 nsresult res
= NS_OK
;
573 nsCOMPtr
<nsIRDFContainer
> container
;
574 res
= NewRDFContainer(mInner
, kNC_BrowserCharsetMenuRoot
, getter_AddRefs(container
));
575 if (NS_FAILED(res
)) return res
;
578 res
= ClearMenu(container
, &mBrowserMenu
);
579 if (NS_FAILED(res
)) return res
;
582 nsCOMPtr
<nsIUTF8StringEnumerator
> decoders
;
583 res
= mCCManager
->GetDecoderList(getter_AddRefs(decoders
));
584 if (NS_FAILED(res
)) return res
;
587 SetArrayFromEnumerator(decoders
, decs
);
589 res
= AddFromPrefsToMenu(&mBrowserMenu
, container
, kBrowserStaticPrefKey
,
591 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing static charset menu from prefs");
593 // mark the end of the static area, the rest is cache
594 mBrowserCacheStart
= mBrowserMenu
.Count();
596 // Remove "notForBrowser" entries before populating cache menu
597 res
= RemoveFlaggedCharsets(decs
, NS_LITERAL_STRING(".notForBrowser"));
598 NS_ASSERTION(NS_SUCCEEDED(res
), "error removing flagged charsets");
600 res
= InitCacheMenu(decs
, kNC_BrowserCharsetMenuRoot
, kBrowserCachePrefKey
,
602 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing browser cache charset menu");
607 nsresult
nsCharsetMenu::RefreshMailviewMenu()
609 nsresult res
= NS_OK
;
611 nsCOMPtr
<nsIRDFContainer
> container
;
612 res
= NewRDFContainer(mInner
, kNC_MailviewCharsetMenuRoot
, getter_AddRefs(container
));
613 if (NS_FAILED(res
)) return res
;
616 res
= ClearMenu(container
, &mMailviewMenu
);
617 if (NS_FAILED(res
)) return res
;
619 nsCOMPtr
<nsIUTF8StringEnumerator
> decoders
;
620 res
= mCCManager
->GetDecoderList(getter_AddRefs(decoders
));
621 if (NS_FAILED(res
)) return res
;
624 SetArrayFromEnumerator(decoders
, decs
);
626 res
= AddFromPrefsToMenu(&mMailviewMenu
, container
, kMailviewStaticPrefKey
,
628 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing static charset menu from prefs");
630 // mark the end of the static area, the rest is cache
631 mMailviewCacheStart
= mMailviewMenu
.Count();
633 res
= InitCacheMenu(decs
, kNC_MailviewCharsetMenuRoot
,
634 kMailviewCachePrefKey
, &mMailviewMenu
);
635 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing mailview cache charset menu");
640 nsresult
nsCharsetMenu::RefreshMaileditMenu()
644 nsCOMPtr
<nsIRDFContainer
> container
;
645 res
= NewRDFContainer(mInner
, kNC_MaileditCharsetMenuRoot
, getter_AddRefs(container
));
646 NS_ENSURE_SUCCESS(res
, res
);
648 nsCOMPtr
<nsISimpleEnumerator
> enumerator
;
649 res
= container
->GetElements(getter_AddRefs(enumerator
));
650 NS_ENSURE_SUCCESS(res
, res
);
653 nsCOMPtr
<nsIRDFNode
> node
;
654 while (NS_SUCCEEDED(enumerator
->GetNext(getter_AddRefs(node
)))) {
656 res
= mInner
->Unassert(kNC_MaileditCharsetMenuRoot
, kNC_Name
, node
);
657 NS_ENSURE_SUCCESS(res
, res
);
659 res
= container
->RemoveElement(node
, PR_FALSE
);
660 NS_ENSURE_SUCCESS(res
, res
);
663 // get a list of available encoders
664 nsCOMPtr
<nsIUTF8StringEnumerator
> encoders
;
665 res
= mCCManager
->GetEncoderList(getter_AddRefs(encoders
));
666 NS_ENSURE_SUCCESS(res
, res
);
669 SetArrayFromEnumerator(encoders
, encs
);
671 // add menu items from pref
672 res
= AddFromPrefsToMenu(NULL
, container
, kMaileditPrefKey
, encs
, NULL
);
673 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing mailedit charset menu from prefs");
678 nsresult
nsCharsetMenu::RefreshComposerMenu()
680 nsresult res
= NS_OK
;
682 nsCOMPtr
<nsIRDFContainer
> container
;
683 res
= NewRDFContainer(mInner
, kNC_ComposerCharsetMenuRoot
, getter_AddRefs(container
));
684 if (NS_FAILED(res
)) return res
;
687 res
= ClearMenu(container
, &mComposerMenu
);
688 if (NS_FAILED(res
)) return res
;
690 nsCOMPtr
<nsIUTF8StringEnumerator
> decoders
;
691 res
= mCCManager
->GetDecoderList(getter_AddRefs(decoders
));
692 if (NS_FAILED(res
)) return res
;
695 SetArrayFromEnumerator(decoders
, decs
);
697 res
= AddFromPrefsToMenu(&mComposerMenu
, container
, kComposerStaticPrefKey
,
699 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing static charset menu from prefs");
701 // mark the end of the static area, the rest is cache
702 mComposerCacheStart
= mComposerMenu
.Count();
704 res
= InitCacheMenu(decs
, kNC_ComposerCharsetMenuRoot
,
705 kComposerCachePrefKey
, &mComposerMenu
);
706 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing composer cache charset menu");
711 nsresult
nsCharsetMenu::Init()
713 nsresult res
= NS_OK
;
718 nsCOMPtr
<nsIUTF8StringEnumerator
> decoders
;
719 res
= mCCManager
->GetDecoderList(getter_AddRefs(decoders
));
720 if (NS_FAILED(res
)) return res
;
722 SetArrayFromEnumerator(decoders
, mDecoderList
);
724 //initialize all remaining RDF template nodes
725 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserAutodetMenuRoot
),
726 &kNC_BrowserAutodetMenuRoot
);
727 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMoreCharsetMenuRoot
),
728 &kNC_BrowserMoreCharsetMenuRoot
);
729 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMore1CharsetMenuRoot
),
730 &kNC_BrowserMore1CharsetMenuRoot
);
731 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMore2CharsetMenuRoot
),
732 &kNC_BrowserMore2CharsetMenuRoot
);
733 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMore3CharsetMenuRoot
),
734 &kNC_BrowserMore3CharsetMenuRoot
);
735 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMore4CharsetMenuRoot
),
736 &kNC_BrowserMore4CharsetMenuRoot
);
737 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMore5CharsetMenuRoot
),
738 &kNC_BrowserMore5CharsetMenuRoot
);
739 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserUnicodeCharsetMenuRoot
),
740 &kNC_BrowserUnicodeCharsetMenuRoot
);
741 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_MaileditCharsetMenuRoot
),
742 &kNC_MaileditCharsetMenuRoot
);
743 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_MailviewCharsetMenuRoot
),
744 &kNC_MailviewCharsetMenuRoot
);
745 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_ComposerCharsetMenuRoot
),
746 &kNC_ComposerCharsetMenuRoot
);
747 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_DecodersRoot
),
749 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_EncodersRoot
),
751 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_Name
),
753 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_Checked
),
755 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_CharsetDetector
),
756 &kNC_CharsetDetector
);
757 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_BookmarkSeparator
),
758 &kNC_BookmarkSeparator
);
759 mRDFService
->GetResource(NS_LITERAL_CSTRING(kURINC_type
), &kRDF_type
);
761 nsIRDFContainerUtils
* rdfUtil
= NULL
;
762 res
= CallGetService(kRDFContainerUtilsCID
, &rdfUtil
);
763 if (NS_FAILED(res
)) goto done
;
765 res
= rdfUtil
->MakeSeq(mInner
, kNC_BrowserAutodetMenuRoot
, NULL
);
766 if (NS_FAILED(res
)) goto done
;
767 res
= rdfUtil
->MakeSeq(mInner
, kNC_BrowserCharsetMenuRoot
, NULL
);
768 if (NS_FAILED(res
)) goto done
;
769 res
= rdfUtil
->MakeSeq(mInner
, kNC_BrowserMoreCharsetMenuRoot
, NULL
);
770 if (NS_FAILED(res
)) goto done
;
771 res
= rdfUtil
->MakeSeq(mInner
, kNC_BrowserMore1CharsetMenuRoot
, NULL
);
772 if (NS_FAILED(res
)) goto done
;
773 res
= rdfUtil
->MakeSeq(mInner
, kNC_BrowserMore2CharsetMenuRoot
, NULL
);
774 if (NS_FAILED(res
)) goto done
;
775 res
= rdfUtil
->MakeSeq(mInner
, kNC_BrowserMore3CharsetMenuRoot
, NULL
);
776 if (NS_FAILED(res
)) goto done
;
777 res
= rdfUtil
->MakeSeq(mInner
, kNC_BrowserMore4CharsetMenuRoot
, NULL
);
778 if (NS_FAILED(res
)) goto done
;
779 res
= rdfUtil
->MakeSeq(mInner
, kNC_BrowserMore5CharsetMenuRoot
, NULL
);
780 if (NS_FAILED(res
)) goto done
;
781 res
= rdfUtil
->MakeSeq(mInner
, kNC_BrowserUnicodeCharsetMenuRoot
, NULL
);
782 if (NS_FAILED(res
)) goto done
;
783 res
= rdfUtil
->MakeSeq(mInner
, kNC_MaileditCharsetMenuRoot
, NULL
);
784 if (NS_FAILED(res
)) goto done
;
785 res
= rdfUtil
->MakeSeq(mInner
, kNC_MailviewCharsetMenuRoot
, NULL
);
786 if (NS_FAILED(res
)) goto done
;
787 res
= rdfUtil
->MakeSeq(mInner
, kNC_ComposerCharsetMenuRoot
, NULL
);
788 if (NS_FAILED(res
)) goto done
;
789 res
= rdfUtil
->MakeSeq(mInner
, kNC_DecodersRoot
, NULL
);
790 if (NS_FAILED(res
)) goto done
;
791 res
= rdfUtil
->MakeSeq(mInner
, kNC_EncodersRoot
, NULL
);
792 if (NS_FAILED(res
)) goto done
;
795 NS_IF_RELEASE(rdfUtil
);
796 if (NS_FAILED(res
)) return res
;
798 mInitialized
= NS_SUCCEEDED(res
);
802 nsresult
nsCharsetMenu::Done()
804 nsresult res
= NS_OK
;
805 res
= mRDFService
->UnregisterDataSource(this);
807 NS_IF_RELEASE(kNC_BrowserAutodetMenuRoot
);
808 NS_IF_RELEASE(kNC_BrowserCharsetMenuRoot
);
809 NS_IF_RELEASE(kNC_BrowserMoreCharsetMenuRoot
);
810 NS_IF_RELEASE(kNC_BrowserMore1CharsetMenuRoot
);
811 NS_IF_RELEASE(kNC_BrowserMore2CharsetMenuRoot
);
812 NS_IF_RELEASE(kNC_BrowserMore3CharsetMenuRoot
);
813 NS_IF_RELEASE(kNC_BrowserMore4CharsetMenuRoot
);
814 NS_IF_RELEASE(kNC_BrowserMore5CharsetMenuRoot
);
815 NS_IF_RELEASE(kNC_BrowserUnicodeCharsetMenuRoot
);
816 NS_IF_RELEASE(kNC_MaileditCharsetMenuRoot
);
817 NS_IF_RELEASE(kNC_MailviewCharsetMenuRoot
);
818 NS_IF_RELEASE(kNC_ComposerCharsetMenuRoot
);
819 NS_IF_RELEASE(kNC_DecodersRoot
);
820 NS_IF_RELEASE(kNC_EncodersRoot
);
821 NS_IF_RELEASE(kNC_Name
);
822 NS_IF_RELEASE(kNC_Checked
);
823 NS_IF_RELEASE(kNC_CharsetDetector
);
824 NS_IF_RELEASE(kNC_BookmarkSeparator
);
825 NS_IF_RELEASE(kRDF_type
);
826 NS_IF_RELEASE(mInner
);
831 nsresult
nsCharsetMenu::SetCharsetCheckmark(nsString
* aCharset
,
834 nsresult res
= NS_OK
;
835 nsCOMPtr
<nsIRDFContainer
> container
;
836 nsCOMPtr
<nsIRDFResource
> node
;
838 res
= NewRDFContainer(mInner
, kNC_BrowserCharsetMenuRoot
, getter_AddRefs(container
));
839 if (NS_FAILED(res
)) return res
;
841 // find RDF node for given charset
842 res
= mRDFService
->GetUnicodeResource(*aCharset
, getter_AddRefs(node
));
843 if (NS_FAILED(res
)) return res
;
845 // set checkmark value
846 nsCOMPtr
<nsIRDFLiteral
> checkedLiteral
;
847 nsAutoString checked
; checked
.AssignWithConversion((aValue
== PR_TRUE
) ? "true" : "false");
848 res
= mRDFService
->GetLiteral(checked
.get(), getter_AddRefs(checkedLiteral
));
849 if (NS_FAILED(res
)) return res
;
850 res
= Assert(node
, kNC_Checked
, checkedLiteral
, PR_TRUE
);
851 if (NS_FAILED(res
)) return res
;
857 * Free the resources no longer needed by the component.
859 nsresult
nsCharsetMenu::FreeResources()
861 nsresult res
= NS_OK
;
863 if (mCharsetMenuObserver
) {
864 nsCOMPtr
<nsIPrefBranch2
> pbi
= do_QueryInterface(mPrefs
);
866 pbi
->RemoveObserver(kBrowserStaticPrefKey
, mCharsetMenuObserver
);
867 pbi
->RemoveObserver(kMaileditPrefKey
, mCharsetMenuObserver
);
869 /* nsIObserverService has to have released nsCharsetMenu already */
879 nsresult
nsCharsetMenu::InitBrowserMenu()
881 NS_TIMELINE_START_TIMER("nsCharsetMenu::InitBrowserMenu");
883 nsresult res
= NS_OK
;
885 if (!mBrowserMenuInitialized
) {
886 nsCOMPtr
<nsIRDFContainer
> container
;
887 res
= NewRDFContainer(mInner
, kNC_BrowserCharsetMenuRoot
, getter_AddRefs(container
));
888 if (NS_FAILED(res
)) return res
;
891 // how to clone mDecoderList??
892 nsCStringArray browserDecoderList
;
893 CloneCStringArray(mDecoderList
, browserDecoderList
);
895 res
= InitStaticMenu(browserDecoderList
, kNC_BrowserCharsetMenuRoot
,
896 kBrowserStaticPrefKey
, &mBrowserMenu
);
897 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing browser static charset menu");
899 // mark the end of the static area, the rest is cache
900 mBrowserCacheStart
= mBrowserMenu
.Count();
901 mPrefs
->GetIntPref(kBrowserCacheSizePrefKey
, &mBrowserCacheSize
);
903 // compute the position of the menu in the RDF container
904 res
= container
->GetCount(&mBrowserMenuRDFPosition
);
905 if (NS_FAILED(res
)) return res
;
906 // this "1" here is a correction necessary because the RDF container
907 // elements are numbered from 1 (why god, WHY?!?!?!)
908 mBrowserMenuRDFPosition
-= mBrowserCacheStart
- 1;
910 // Remove "notForBrowser" entries before populating cache menu
911 res
= RemoveFlaggedCharsets(browserDecoderList
, NS_LITERAL_STRING(".notForBrowser"));
912 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing static charset menu from prefs");
914 res
= InitCacheMenu(browserDecoderList
, kNC_BrowserCharsetMenuRoot
, kBrowserCachePrefKey
,
916 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing browser cache charset menu");
918 // register prefs callback
919 nsCOMPtr
<nsIPrefBranch2
> pbi
= do_QueryInterface(mPrefs
);
921 res
= pbi
->AddObserver(kBrowserStaticPrefKey
, mCharsetMenuObserver
, PR_FALSE
);
924 mBrowserMenuInitialized
= NS_SUCCEEDED(res
);
926 NS_TIMELINE_STOP_TIMER("nsCharsetMenu::InitBrowserMenu");
927 NS_TIMELINE_MARK_TIMER("nsCharsetMenu::InitBrowserMenu");
932 nsresult
nsCharsetMenu::InitMaileditMenu()
934 NS_TIMELINE_START_TIMER("nsCharsetMenu::InitMaileditMenu");
936 nsresult res
= NS_OK
;
938 if (!mMaileditMenuInitialized
) {
939 nsCOMPtr
<nsIRDFContainer
> container
;
940 res
= NewRDFContainer(mInner
, kNC_MaileditCharsetMenuRoot
, getter_AddRefs(container
));
941 if (NS_FAILED(res
)) return res
;
944 // this would bring in a whole bunch of 'font encoders' as well as genuine
945 // charset encoders, but it's safe because we rely on prefs to filter
946 // them out. Moreover, 'customize' menu lists only genuine charset
947 // encoders further guarding against 'font encoders' sneaking in.
948 nsCOMPtr
<nsIUTF8StringEnumerator
> encoders
;
949 res
= mCCManager
->GetEncoderList(getter_AddRefs(encoders
));
950 if (NS_FAILED(res
)) return res
;
952 nsCStringArray maileditEncoderList
;
953 SetArrayFromEnumerator(encoders
, maileditEncoderList
);
955 res
= AddFromPrefsToMenu(NULL
, container
, kMaileditPrefKey
, maileditEncoderList
, NULL
);
956 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing mailedit charset menu from prefs");
958 // register prefs callback
959 nsCOMPtr
<nsIPrefBranch2
> pbi
= do_QueryInterface(mPrefs
);
961 res
= pbi
->AddObserver(kMaileditPrefKey
, mCharsetMenuObserver
, PR_FALSE
);
964 mMaileditMenuInitialized
= NS_SUCCEEDED(res
);
966 NS_TIMELINE_STOP_TIMER("nsCharsetMenu::InitMaileditMenu");
967 NS_TIMELINE_MARK_TIMER("nsCharsetMenu::InitMaileditMenu");
972 nsresult
nsCharsetMenu::InitMailviewMenu()
974 NS_TIMELINE_START_TIMER("nsCharsetMenu::InitMailviewMenu");
976 nsresult res
= NS_OK
;
978 if (!mMailviewMenuInitialized
) {
979 nsCOMPtr
<nsIRDFContainer
> container
;
980 res
= NewRDFContainer(mInner
, kNC_MailviewCharsetMenuRoot
, getter_AddRefs(container
));
981 if (NS_FAILED(res
)) return res
;
983 nsCStringArray mailviewDecoderList
;
984 CloneCStringArray(mDecoderList
, mailviewDecoderList
);
986 res
= InitStaticMenu(mailviewDecoderList
, kNC_MailviewCharsetMenuRoot
,
987 kMailviewStaticPrefKey
, &mMailviewMenu
);
988 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing mailview static charset menu");
990 // mark the end of the static area, the rest is cache
991 mMailviewCacheStart
= mMailviewMenu
.Count();
992 mPrefs
->GetIntPref(kMailviewCacheSizePrefKey
, &mMailviewCacheSize
);
994 // compute the position of the menu in the RDF container
995 res
= container
->GetCount(&mMailviewMenuRDFPosition
);
996 if (NS_FAILED(res
)) return res
;
997 // this "1" here is a correction necessary because the RDF container
998 // elements are numbered from 1 (why god, WHY?!?!?!)
999 mMailviewMenuRDFPosition
-= mMailviewCacheStart
- 1;
1001 res
= InitCacheMenu(mailviewDecoderList
, kNC_MailviewCharsetMenuRoot
,
1002 kMailviewCachePrefKey
, &mMailviewMenu
);
1003 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing mailview cache charset menu");
1006 mMailviewMenuInitialized
= NS_SUCCEEDED(res
);
1008 NS_TIMELINE_STOP_TIMER("nsCharsetMenu::InitMailviewMenu");
1009 NS_TIMELINE_MARK_TIMER("nsCharsetMenu::InitMailviewMenu");
1014 nsresult
nsCharsetMenu::InitComposerMenu()
1016 NS_TIMELINE_START_TIMER("nsCharsetMenu::InitComposerMenu");
1018 nsresult res
= NS_OK
;
1020 if (!mComposerMenuInitialized
) {
1021 nsCOMPtr
<nsIRDFContainer
> container
;
1022 res
= NewRDFContainer(mInner
, kNC_ComposerCharsetMenuRoot
, getter_AddRefs(container
));
1023 if (NS_FAILED(res
)) return res
;
1025 nsCStringArray composerDecoderList
;
1026 CloneCStringArray(mDecoderList
, composerDecoderList
);
1028 // even if we fail, the show must go on
1029 res
= InitStaticMenu(composerDecoderList
, kNC_ComposerCharsetMenuRoot
,
1030 kComposerStaticPrefKey
, &mComposerMenu
);
1031 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing composer static charset menu");
1033 // mark the end of the static area, the rest is cache
1034 mComposerCacheStart
= mComposerMenu
.Count();
1035 mPrefs
->GetIntPref(kComposerCacheSizePrefKey
, &mComposerCacheSize
);
1037 // compute the position of the menu in the RDF container
1038 res
= container
->GetCount(&mComposerMenuRDFPosition
);
1039 if (NS_FAILED(res
)) return res
;
1040 // this "1" here is a correction necessary because the RDF container
1041 // elements are numbered from 1 (why god, WHY?!?!?!)
1042 mComposerMenuRDFPosition
-= mComposerCacheStart
- 1;
1044 res
= InitCacheMenu(composerDecoderList
, kNC_ComposerCharsetMenuRoot
,
1045 kComposerCachePrefKey
, &mComposerMenu
);
1046 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing composer cache charset menu");
1049 mComposerMenuInitialized
= NS_SUCCEEDED(res
);
1051 NS_TIMELINE_STOP_TIMER("nsCharsetMenu::InitComposerMenu");
1052 NS_TIMELINE_MARK_TIMER("nsCharsetMenu::InitComposerMenu");
1057 nsresult
nsCharsetMenu::InitOthers()
1059 NS_TIMELINE_START_TIMER("nsCharsetMenu::InitOthers");
1061 nsresult res
= NS_OK
;
1063 if (!mOthersInitialized
) {
1064 nsCStringArray othersDecoderList
;
1065 CloneCStringArray(mDecoderList
, othersDecoderList
);
1067 res
= InitMoreMenu(othersDecoderList
, kNC_DecodersRoot
, ".notForBrowser");
1068 if (NS_FAILED(res
)) return res
;
1070 // Using mDecoderList instead of GetEncoderList(), we can avoid having to
1071 // tag a whole bunch of 'font encoders' with '.notForOutgoing' in
1072 // charsetData.properties file.
1073 nsCStringArray othersEncoderList
;
1074 CloneCStringArray(mDecoderList
, othersEncoderList
);
1076 res
= InitMoreMenu(othersEncoderList
, kNC_EncodersRoot
, ".notForOutgoing");
1077 if (NS_FAILED(res
)) return res
;
1080 mOthersInitialized
= NS_SUCCEEDED(res
);
1082 NS_TIMELINE_STOP_TIMER("nsCharsetMenu::InitOthers");
1083 NS_TIMELINE_MARK_TIMER("nsCharsetMenu::InitOthers");
1089 * Inits the secondary tiers of the charset menu. Because currently all the CS
1090 * menus are sharing the secondary tiers, one should call this method only
1091 * once for all of them.
1093 nsresult
nsCharsetMenu::InitSecondaryTiers()
1095 NS_TIMELINE_START_TIMER("nsCharsetMenu::InitSecondaryTiers");
1097 nsresult res
= NS_OK
;
1099 if (!mSecondaryTiersInitialized
) {
1100 nsCStringArray secondaryTiersDecoderList
;
1101 CloneCStringArray(mDecoderList
, secondaryTiersDecoderList
);
1103 res
= InitMoreSubmenus(secondaryTiersDecoderList
);
1104 NS_ASSERTION(NS_SUCCEEDED(res
), "err init browser charset more submenus");
1106 res
= InitMoreMenu(secondaryTiersDecoderList
, kNC_BrowserMoreCharsetMenuRoot
, ".notForBrowser");
1107 NS_ASSERTION(NS_SUCCEEDED(res
), "err init browser charset more menu");
1110 mSecondaryTiersInitialized
= NS_SUCCEEDED(res
);
1112 NS_TIMELINE_STOP_TIMER("nsCharsetMenu::InitSecondaryTiers");
1113 NS_TIMELINE_MARK_TIMER("nsCharsetMenu::InitSecondaryTiers");
1118 nsresult
nsCharsetMenu::InitStaticMenu(nsCStringArray
& aDecs
,
1119 nsIRDFResource
* aResource
,
1121 nsVoidArray
* aArray
)
1123 NS_TIMELINE_START_TIMER("nsCharsetMenu::InitStaticMenu");
1125 nsresult res
= NS_OK
;
1126 nsCOMPtr
<nsIRDFContainer
> container
;
1128 res
= NewRDFContainer(mInner
, aResource
, getter_AddRefs(container
));
1129 if (NS_FAILED(res
)) return res
;
1131 // XXX work around bug that causes the submenus to be first instead of last
1132 res
= AddSeparatorToContainer(container
);
1133 NS_ASSERTION(NS_SUCCEEDED(res
), "error adding separator to container");
1135 res
= AddFromPrefsToMenu(aArray
, container
, aKey
, aDecs
, "charset.");
1136 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing static charset menu from prefs");
1138 NS_TIMELINE_STOP_TIMER("nsCharsetMenu::InitStaticMenu");
1139 NS_TIMELINE_MARK_TIMER("nsCharsetMenu::InitStaticMenu");
1144 nsresult
nsCharsetMenu::InitCacheMenu(
1145 nsCStringArray
& aDecs
,
1146 nsIRDFResource
* aResource
,
1148 nsVoidArray
* aArray
)
1150 NS_TIMELINE_START_TIMER("nsCharsetMenu::InitCacheMenu");
1152 nsresult res
= NS_OK
;
1153 nsCOMPtr
<nsIRDFContainer
> container
;
1155 res
= NewRDFContainer(mInner
, aResource
, getter_AddRefs(container
));
1156 if (NS_FAILED(res
)) return res
;
1158 res
= AddFromNolocPrefsToMenu(aArray
, container
, aKey
, aDecs
, "charset.");
1159 NS_ASSERTION(NS_SUCCEEDED(res
), "error initializing cache charset menu from prefs");
1161 NS_TIMELINE_STOP_TIMER("nsCharsetMenu::InitCacheMenu");
1162 NS_TIMELINE_MARK_TIMER("nsCharsetMenu::InitCacheMenu");
1167 nsresult
nsCharsetMenu::InitAutodetMenu()
1169 NS_TIMELINE_START_TIMER("nsCharsetMenu::InitAutodetMenu");
1171 nsresult res
= NS_OK
;
1173 if (!mAutoDetectInitialized
) {
1174 nsVoidArray chardetArray
;
1175 nsCOMPtr
<nsIRDFContainer
> container
;
1176 nsCStringArray detectorArray
;
1178 res
= NewRDFContainer(mInner
, kNC_BrowserAutodetMenuRoot
, getter_AddRefs(container
));
1179 if (NS_FAILED(res
)) return res
;
1181 nsCOMPtr
<nsIUTF8StringEnumerator
> detectors
;
1182 res
= mCCManager
->GetCharsetDetectorList(getter_AddRefs(detectors
));
1183 if (NS_FAILED(res
)) goto done
;
1185 res
= SetArrayFromEnumerator(detectors
, detectorArray
);
1186 if (NS_FAILED(res
)) goto done
;
1188 res
= AddCharsetArrayToItemArray(chardetArray
, detectorArray
);
1189 if (NS_FAILED(res
)) goto done
;
1191 // reorder the array
1192 res
= ReorderMenuItemArray(&chardetArray
);
1193 if (NS_FAILED(res
)) goto done
;
1195 res
= AddMenuItemArrayToContainer(container
, &chardetArray
,
1196 kNC_CharsetDetector
);
1197 if (NS_FAILED(res
)) goto done
;
1200 // free the elements in the VoidArray
1201 FreeMenuItemArray(&chardetArray
);
1204 mAutoDetectInitialized
= NS_SUCCEEDED(res
);
1206 NS_TIMELINE_STOP_TIMER("nsCharsetMenu::InitAutodetMenu");
1207 NS_TIMELINE_MARK_TIMER("nsCharsetMenu::InitAutodetMenu");
1212 nsresult
nsCharsetMenu::InitMoreMenu(nsCStringArray
& aDecs
,
1213 nsIRDFResource
* aResource
,
1216 NS_TIMELINE_START_TIMER("nsCharsetMenu::InitMoreMenu");
1218 nsresult res
= NS_OK
;
1219 nsCOMPtr
<nsIRDFContainer
> container
;
1220 nsVoidArray moreMenu
;
1222 res
= NewRDFContainer(mInner
, aResource
, getter_AddRefs(container
));
1223 if (NS_FAILED(res
)) goto done
;
1225 // remove charsets "not for browser"
1226 res
= RemoveFlaggedCharsets(aDecs
, NS_ConvertASCIItoUTF16(aFlag
));
1227 if (NS_FAILED(res
)) goto done
;
1229 res
= AddCharsetArrayToItemArray(moreMenu
, aDecs
);
1230 if (NS_FAILED(res
)) goto done
;
1232 // reorder the array
1233 res
= ReorderMenuItemArray(&moreMenu
);
1234 if (NS_FAILED(res
)) goto done
;
1236 res
= AddMenuItemArrayToContainer(container
, &moreMenu
, NULL
);
1237 if (NS_FAILED(res
)) goto done
;
1240 // free the elements in the VoidArray
1241 FreeMenuItemArray(&moreMenu
);
1243 NS_TIMELINE_STOP_TIMER("nsCharsetMenu::InitMoreMenu");
1244 NS_TIMELINE_MARK_TIMER("nsCharsetMenu::InitMoreMenu");
1249 // XXX please make this method more general; the cut&pasted code is laughable
1250 nsresult
nsCharsetMenu::InitMoreSubmenus(nsCStringArray
& aDecs
)
1252 NS_TIMELINE_START_TIMER("nsCharsetMenu::InitMoreSubmenus");
1254 nsresult res
= NS_OK
;
1256 nsCOMPtr
<nsIRDFContainer
> container1
;
1257 nsCOMPtr
<nsIRDFContainer
> container2
;
1258 nsCOMPtr
<nsIRDFContainer
> container3
;
1259 nsCOMPtr
<nsIRDFContainer
> container4
;
1260 nsCOMPtr
<nsIRDFContainer
> container5
;
1261 nsCOMPtr
<nsIRDFContainer
> containerU
;
1262 const char key1
[] = "intl.charsetmenu.browser.more1";
1263 const char key2
[] = "intl.charsetmenu.browser.more2";
1264 const char key3
[] = "intl.charsetmenu.browser.more3";
1265 const char key4
[] = "intl.charsetmenu.browser.more4";
1266 const char key5
[] = "intl.charsetmenu.browser.more5";
1267 const char keyU
[] = "intl.charsetmenu.browser.unicode";
1269 res
= NewRDFContainer(mInner
, kNC_BrowserMore1CharsetMenuRoot
,
1270 getter_AddRefs(container1
));
1271 if (NS_FAILED(res
)) return res
;
1272 AddFromPrefsToMenu(NULL
, container1
, key1
, aDecs
, NULL
);
1274 res
= NewRDFContainer(mInner
, kNC_BrowserMore2CharsetMenuRoot
,
1275 getter_AddRefs(container2
));
1276 if (NS_FAILED(res
)) return res
;
1277 AddFromPrefsToMenu(NULL
, container2
, key2
, aDecs
, NULL
);
1279 res
= NewRDFContainer(mInner
, kNC_BrowserMore3CharsetMenuRoot
,
1280 getter_AddRefs(container3
));
1281 if (NS_FAILED(res
)) return res
;
1282 AddFromPrefsToMenu(NULL
, container3
, key3
, aDecs
, NULL
);
1284 res
= NewRDFContainer(mInner
, kNC_BrowserMore4CharsetMenuRoot
,
1285 getter_AddRefs(container4
));
1286 if (NS_FAILED(res
)) return res
;
1287 AddFromPrefsToMenu(NULL
, container4
, key4
, aDecs
, NULL
);
1289 res
= NewRDFContainer(mInner
, kNC_BrowserMore5CharsetMenuRoot
,
1290 getter_AddRefs(container5
));
1291 if (NS_FAILED(res
)) return res
;
1292 AddFromPrefsToMenu(NULL
, container5
, key5
, aDecs
, NULL
);
1294 res
= NewRDFContainer(mInner
, kNC_BrowserUnicodeCharsetMenuRoot
,
1295 getter_AddRefs(containerU
));
1296 if (NS_FAILED(res
)) return res
;
1297 AddFromPrefsToMenu(NULL
, containerU
, keyU
, aDecs
, NULL
);
1299 NS_TIMELINE_STOP_TIMER("nsCharsetMenu::InitMoreSubmenus");
1300 NS_TIMELINE_MARK_TIMER("nsCharsetMenu::InitMoreSubmenus");
1305 nsresult
nsCharsetMenu::AddCharsetToItemArray(nsVoidArray
*aArray
,
1306 const nsAFlatCString
& aCharset
,
1307 nsMenuEntry
** aResult
,
1310 nsresult res
= NS_OK
;
1311 nsMenuEntry
* item
= NULL
;
1313 if (aResult
!= NULL
) *aResult
= NULL
;
1315 item
= new nsMenuEntry();
1317 res
= NS_ERROR_OUT_OF_MEMORY
;
1321 item
->mCharset
= aCharset
;
1323 res
= mCCManager
->GetCharsetTitle(aCharset
.get(), item
->mTitle
);
1324 if (NS_FAILED(res
)) {
1325 item
->mTitle
.AssignWithConversion(aCharset
.get());
1328 if (aArray
!= NULL
) {
1330 res
= aArray
->AppendElement(item
);
1331 if (NS_FAILED(res
)) goto done
;
1333 res
= aArray
->InsertElementAt(item
, aPlace
);
1334 if (NS_FAILED(res
)) goto done
;
1338 if (aResult
!= NULL
) *aResult
= item
;
1340 // if we have made another reference to "item", do not delete it
1341 if ((aArray
!= NULL
) || (aResult
!= NULL
)) item
= NULL
;
1344 if (item
!= NULL
) delete item
;
1350 nsCharsetMenu::AddCharsetArrayToItemArray(nsVoidArray
& aArray
,
1351 const nsCStringArray
& aCharsets
)
1353 PRUint32 count
= aCharsets
.Count();
1355 for (PRUint32 i
= 0; i
< count
; i
++) {
1357 nsCString
* str
= aCharsets
.CStringAt(i
);
1359 nsresult res
= AddCharsetToItemArray(&aArray
, *str
, NULL
, -1);
1361 if (NS_FAILED(res
)) return res
;
1368 // aPlace < -1 for Remove
1369 // aPlace < 0 for Append
1370 nsresult
nsCharsetMenu::AddMenuItemToContainer(
1371 nsIRDFContainer
* aContainer
,
1372 nsMenuEntry
* aItem
,
1373 nsIRDFResource
* aType
,
1374 const char * aIDPrefix
,
1377 nsresult res
= NS_OK
;
1378 nsCOMPtr
<nsIRDFResource
> node
;
1381 if (aIDPrefix
!= NULL
) id
.Assign(aIDPrefix
);
1382 id
.Append(aItem
->mCharset
);
1384 // Make up a unique ID and create the RDF NODE
1385 res
= mRDFService
->GetResource(id
, getter_AddRefs(node
));
1386 if (NS_FAILED(res
)) return res
;
1388 const PRUnichar
* title
= aItem
->mTitle
.get();
1391 nsCOMPtr
<nsIRDFLiteral
> titleLiteral
;
1392 res
= mRDFService
->GetLiteral(title
, getter_AddRefs(titleLiteral
));
1393 if (NS_FAILED(res
)) return res
;
1396 res
= Unassert(node
, kNC_Name
, titleLiteral
);
1397 if (NS_FAILED(res
)) return res
;
1399 res
= Assert(node
, kNC_Name
, titleLiteral
, PR_TRUE
);
1400 if (NS_FAILED(res
)) return res
;
1403 if (aType
!= NULL
) {
1405 res
= Unassert(node
, kRDF_type
, aType
);
1406 if (NS_FAILED(res
)) return res
;
1408 res
= Assert(node
, kRDF_type
, aType
, PR_TRUE
);
1409 if (NS_FAILED(res
)) return res
;
1413 // Add the element to the container
1415 res
= aContainer
->RemoveElement(node
, PR_TRUE
);
1416 if (NS_FAILED(res
)) return res
;
1417 } else if (aPlace
< 0) {
1418 res
= aContainer
->AppendElement(node
);
1419 if (NS_FAILED(res
)) return res
;
1421 res
= aContainer
->InsertElementAt(node
, aPlace
, PR_TRUE
);
1422 if (NS_FAILED(res
)) return res
;
1428 nsresult
nsCharsetMenu::AddMenuItemArrayToContainer(
1429 nsIRDFContainer
* aContainer
,
1430 nsVoidArray
* aArray
,
1431 nsIRDFResource
* aType
)
1433 PRUint32 count
= aArray
->Count();
1434 nsresult res
= NS_OK
;
1436 for (PRUint32 i
= 0; i
< count
; i
++) {
1437 nsMenuEntry
* item
= (nsMenuEntry
*) aArray
->ElementAt(i
);
1438 if (item
== NULL
) return NS_ERROR_UNEXPECTED
;
1440 res
= AddMenuItemToContainer(aContainer
, item
, aType
, NULL
, -1);
1441 if (NS_FAILED(res
)) return res
;
1447 nsresult
nsCharsetMenu::AddCharsetToContainer(nsVoidArray
*aArray
,
1448 nsIRDFContainer
* aContainer
,
1449 const nsAFlatCString
& aCharset
,
1450 const char * aIDPrefix
,
1454 nsresult res
= NS_OK
;
1455 nsMenuEntry
* item
= NULL
;
1457 res
= AddCharsetToItemArray(aArray
, aCharset
, &item
, aPlace
);
1458 if (NS_FAILED(res
)) goto done
;
1460 res
= AddMenuItemToContainer(aContainer
, item
, NULL
, aIDPrefix
,
1461 aPlace
+ aRDFPlace
);
1462 if (NS_FAILED(res
)) goto done
;
1464 // if we have made another reference to "item", do not delete it
1465 if (aArray
!= NULL
) item
= NULL
;
1468 if (item
!= NULL
) delete item
;
1473 nsresult
nsCharsetMenu::AddFromPrefsToMenu(
1474 nsVoidArray
* aArray
,
1475 nsIRDFContainer
* aContainer
,
1477 nsCStringArray
& aDecs
,
1478 const char * aIDPrefix
)
1480 nsresult res
= NS_OK
;
1482 nsCOMPtr
<nsIPrefLocalizedString
> pls
;
1483 res
= mPrefs
->GetComplexValue(aKey
, NS_GET_IID(nsIPrefLocalizedString
), getter_AddRefs(pls
));
1484 if (NS_FAILED(res
)) return res
;
1487 nsXPIDLString ucsval
;
1488 pls
->ToString(getter_Copies(ucsval
));
1489 NS_ConvertUTF16toUTF8
utf8val(ucsval
);
1491 res
= AddFromStringToMenu(utf8val
.BeginWriting(), aArray
,
1492 aContainer
, aDecs
, aIDPrefix
);
1499 nsCharsetMenu::AddFromNolocPrefsToMenu(nsVoidArray
* aArray
,
1500 nsIRDFContainer
* aContainer
,
1502 nsCStringArray
& aDecs
,
1503 const char * aIDPrefix
)
1505 nsresult res
= NS_OK
;
1507 char * value
= NULL
;
1508 res
= mPrefs
->GetCharPref(aKey
, &value
);
1509 if (NS_FAILED(res
)) return res
;
1511 if (value
!= NULL
) {
1512 res
= AddFromStringToMenu(value
, aArray
, aContainer
, aDecs
, aIDPrefix
);
1513 nsMemory::Free(value
);
1519 nsresult
nsCharsetMenu::AddFromStringToMenu(
1520 char * aCharsetList
,
1521 nsVoidArray
* aArray
,
1522 nsIRDFContainer
* aContainer
,
1523 nsCStringArray
& aDecs
,
1524 const char * aIDPrefix
)
1526 nsresult res
= NS_OK
;
1527 char * p
= aCharsetList
;
1530 for (; (*q
!= ',') && (*q
!= ' ') && (*q
!= 0); q
++) {;}
1534 // if this charset is not on the accepted list of charsets, ignore it
1536 index
= aDecs
.IndexOfIgnoreCase(nsCAutoString(p
));
1539 // else, add it to the menu
1540 res
= AddCharsetToContainer(aArray
, aContainer
, nsDependentCString(p
),
1542 NS_ASSERTION(NS_SUCCEEDED(res
), "cannot add charset to menu");
1543 if (NS_FAILED(res
)) break;
1545 res
= aDecs
.RemoveCStringAt(index
);
1546 NS_ASSERTION(NS_SUCCEEDED(res
), "cannot remove atom from array");
1550 for (; (*q
== ',') || (*q
== ' '); q
++) {;}
1557 nsresult
nsCharsetMenu::AddSeparatorToContainer(nsIRDFContainer
* aContainer
)
1560 str
.AssignLiteral("----");
1562 // hack to generate unique id's for separators
1563 static PRInt32 u
= 0;
1568 item
.mCharset
= str
;
1569 item
.mTitle
.AssignWithConversion(str
.get());
1571 return AddMenuItemToContainer(aContainer
, &item
, kNC_BookmarkSeparator
,
1576 nsCharsetMenu::AddCharsetToCache(const nsAFlatCString
& aCharset
,
1577 nsVoidArray
* aArray
,
1578 nsIRDFResource
* aRDFResource
,
1579 PRInt32 aCacheStart
,
1584 nsresult res
= NS_OK
;
1586 i
= FindMenuItemInArray(aArray
, aCharset
, NULL
);
1587 if (i
>= 0) return res
;
1589 nsCOMPtr
<nsIRDFContainer
> container
;
1590 res
= NewRDFContainer(mInner
, aRDFResource
, getter_AddRefs(container
));
1591 if (NS_FAILED(res
)) return res
;
1593 // iff too many items, remove last one
1594 if (aArray
->Count() - aCacheStart
>= aCacheSize
){
1595 res
= RemoveLastMenuItem(container
, aArray
);
1596 if (NS_FAILED(res
)) return res
;
1599 res
= AddCharsetToContainer(aArray
, container
, aCharset
, "charset.",
1600 aCacheStart
, aRDFPlace
);
1605 nsresult
nsCharsetMenu::WriteCacheToPrefs(nsVoidArray
* aArray
,
1606 PRInt32 aCacheStart
,
1609 nsresult res
= NS_OK
;
1611 // create together the cache string
1612 nsCAutoString cache
;
1613 nsCAutoString
sep(NS_LITERAL_CSTRING(", "));
1614 PRInt32 count
= aArray
->Count();
1616 for (PRInt32 i
= aCacheStart
; i
< count
; i
++) {
1617 nsMenuEntry
* item
= (nsMenuEntry
*) aArray
->ElementAt(i
);
1619 cache
.Append(item
->mCharset
);
1620 if (i
< count
- 1) {
1627 res
= mPrefs
->SetCharPref(aKey
, cache
.get());
1632 nsresult
nsCharsetMenu::UpdateCachePrefs(const char * aCacheKey
,
1633 const char * aCacheSizeKey
,
1634 const char * aStaticKey
,
1635 const PRUnichar
* aCharset
)
1637 nsresult rv
= NS_OK
;
1638 nsXPIDLCString cachePrefValue
;
1639 nsXPIDLCString staticPrefValue
;
1640 NS_LossyConvertUTF16toASCII
currentCharset(aCharset
);
1641 PRInt32 cacheSize
= 0;
1643 mPrefs
->GetCharPref(aCacheKey
, getter_Copies(cachePrefValue
));
1644 mPrefs
->GetCharPref(aStaticKey
, getter_Copies(staticPrefValue
));
1645 rv
= mPrefs
->GetIntPref(aCacheSizeKey
, &cacheSize
);
1647 if (NS_FAILED(rv
) || cacheSize
<= 0)
1648 return NS_ERROR_UNEXPECTED
;
1650 if ((cachePrefValue
.Find(currentCharset
) == kNotFound
) &&
1651 (staticPrefValue
.Find(currentCharset
) == kNotFound
)) {
1653 if (!cachePrefValue
.IsEmpty())
1654 cachePrefValue
.Insert(", ", 0);
1656 cachePrefValue
.Insert(currentCharset
, 0);
1657 if (cacheSize
< (PRInt32
) cachePrefValue
.CountChar(',') + 1)
1658 cachePrefValue
.Truncate(cachePrefValue
.RFindChar(','));
1660 rv
= mPrefs
->SetCharPref(aCacheKey
, cachePrefValue
);
1666 nsresult
nsCharsetMenu::ClearMenu(nsIRDFContainer
* aContainer
,
1667 nsVoidArray
* aArray
)
1669 nsresult res
= NS_OK
;
1671 // clean the RDF data source
1672 PRInt32 count
= aArray
->Count();
1673 for (PRInt32 i
= 0; i
< count
; i
++) {
1674 nsMenuEntry
* item
= (nsMenuEntry
*) aArray
->ElementAt(i
);
1676 res
= AddMenuItemToContainer(aContainer
, item
, NULL
, "charset.", -2);
1677 if (NS_FAILED(res
)) return res
;
1681 // clean the internal data structures
1682 FreeMenuItemArray(aArray
);
1687 nsresult
nsCharsetMenu::RemoveLastMenuItem(nsIRDFContainer
* aContainer
,
1688 nsVoidArray
* aArray
)
1690 nsresult res
= NS_OK
;
1692 PRInt32 last
= aArray
->Count() - 1;
1694 nsMenuEntry
* item
= (nsMenuEntry
*) aArray
->ElementAt(last
);
1696 res
= AddMenuItemToContainer(aContainer
, item
, NULL
, "charset.", -2);
1697 if (NS_FAILED(res
)) return res
;
1699 res
= aArray
->RemoveElementAt(last
);
1700 if (NS_FAILED(res
)) return res
;
1707 nsresult
nsCharsetMenu::RemoveFlaggedCharsets(nsCStringArray
& aList
,
1708 const nsString
& aProp
)
1710 nsresult res
= NS_OK
;
1713 count
= aList
.Count();
1714 if (NS_FAILED(res
)) return res
;
1718 for (PRUint32 i
= 0; i
< count
; i
++) {
1720 charset
= aList
.CStringAt(i
);
1721 if (!charset
) continue;
1723 res
= mCCManager
->GetCharsetData(charset
->get(), aProp
.get(), str
);
1724 if (NS_FAILED(res
)) continue;
1726 aList
.RemoveCStringAt(i
);
1735 nsresult
nsCharsetMenu::NewRDFContainer(nsIRDFDataSource
* aDataSource
,
1736 nsIRDFResource
* aResource
,
1737 nsIRDFContainer
** aResult
)
1739 nsresult res
= CallCreateInstance(kRDFContainerCID
, aResult
);
1740 if (NS_FAILED(res
)) return res
;
1742 res
= (*aResult
)->Init(aDataSource
, aResource
);
1743 if (NS_FAILED(res
)) NS_RELEASE(*aResult
);
1748 void nsCharsetMenu::FreeMenuItemArray(nsVoidArray
* aArray
)
1750 PRUint32 count
= aArray
->Count();
1751 for (PRUint32 i
= 0; i
< count
; i
++) {
1752 nsMenuEntry
* item
= (nsMenuEntry
*) aArray
->ElementAt(i
);
1760 PRInt32
nsCharsetMenu::FindMenuItemInArray(const nsVoidArray
* aArray
,
1761 const nsAFlatCString
& aCharset
,
1762 nsMenuEntry
** aResult
)
1764 PRUint32 count
= aArray
->Count();
1766 for (PRUint32 i
=0; i
< count
; i
++) {
1767 nsMenuEntry
* item
= (nsMenuEntry
*) aArray
->ElementAt(i
);
1768 if (item
->mCharset
== aCharset
) {
1769 if (aResult
!= NULL
) *aResult
= item
;
1774 if (aResult
!= NULL
) *aResult
= NULL
;
1778 nsresult
nsCharsetMenu::ReorderMenuItemArray(nsVoidArray
* aArray
)
1780 nsresult res
= NS_OK
;
1781 nsCOMPtr
<nsICollation
> collation
;
1782 PRUint32 count
= aArray
->Count();
1785 // we need to use a temporary array
1786 charsetMenuSortRecord
*array
= new charsetMenuSortRecord
[count
];
1787 NS_ENSURE_TRUE(array
, NS_ERROR_OUT_OF_MEMORY
);
1788 for (i
= 0; i
< count
; i
++)
1789 array
[i
].key
= nsnull
;
1791 res
= GetCollation(getter_AddRefs(collation
));
1795 for (i
= 0; i
< count
&& NS_SUCCEEDED(res
); i
++) {
1796 array
[i
].item
= (nsMenuEntry
*)aArray
->ElementAt(i
);
1798 res
= collation
->AllocateRawSortKey(nsICollation::kCollationCaseInSensitive
,
1799 (array
[i
].item
)->mTitle
, &array
[i
].key
, &array
[i
].len
);
1802 // reorder the array
1803 if (NS_SUCCEEDED(res
)) {
1804 NS_QuickSort(array
, count
, sizeof(*array
), CompareMenuItems
, collation
);
1806 // move the elements from the temporary array into the the real one
1808 for (i
= 0; i
< count
; i
++) {
1809 aArray
->AppendElement(array
[i
].item
);
1814 for (i
= 0; i
< count
; i
++) {
1815 PR_FREEIF(array
[i
].key
);
1821 nsresult
nsCharsetMenu::GetCollation(nsICollation
** aCollation
)
1823 nsresult res
= NS_OK
;
1824 nsCOMPtr
<nsILocale
> locale
= nsnull
;
1825 nsICollationFactory
* collationFactory
= nsnull
;
1827 nsCOMPtr
<nsILocaleService
> localeServ
=
1828 do_GetService(NS_LOCALESERVICE_CONTRACTID
, &res
);
1829 if (NS_FAILED(res
)) return res
;
1831 res
= localeServ
->GetApplicationLocale(getter_AddRefs(locale
));
1832 if (NS_FAILED(res
)) return res
;
1834 res
= CallCreateInstance(NS_COLLATIONFACTORY_CONTRACTID
, &collationFactory
);
1835 if (NS_FAILED(res
)) return res
;
1837 res
= collationFactory
->CreateCollation(locale
, aCollation
);
1838 NS_RELEASE(collationFactory
);
1842 //----------------------------------------------------------------------------
1843 // Interface nsICurrentCharsetListener [implementation]
1845 NS_IMETHODIMP
nsCharsetMenu::SetCurrentCharset(const PRUnichar
* aCharset
)
1847 NS_TIMELINE_START_TIMER("nsCharsetMenu:SetCurrentCharset");
1848 nsresult res
= NS_OK
;
1850 if (mBrowserMenuInitialized
) {
1851 // Don't add item to the cache if it's marked "notForBrowser"
1853 res
= mCCManager
->GetCharsetData(NS_LossyConvertUTF16toASCII(aCharset
).get(),
1854 NS_LITERAL_STRING(".notForBrowser").get(), str
);
1855 if (NS_SUCCEEDED(res
)) // succeeded means attribute exists
1856 return res
; // don't throw
1858 res
= AddCharsetToCache(NS_LossyConvertUTF16toASCII(aCharset
),
1859 &mBrowserMenu
, kNC_BrowserCharsetMenuRoot
,
1860 mBrowserCacheStart
, mBrowserCacheSize
,
1861 mBrowserMenuRDFPosition
);
1862 if (NS_FAILED(res
)) {
1863 NS_TIMELINE_LEAVE("nsCharsetMenu:SetCurrentCharset");
1867 res
= WriteCacheToPrefs(&mBrowserMenu
, mBrowserCacheStart
,
1868 kBrowserCachePrefKey
);
1870 res
= UpdateCachePrefs(kBrowserCachePrefKey
, kBrowserCacheSizePrefKey
,
1871 kBrowserStaticPrefKey
, aCharset
);
1873 NS_TIMELINE_STOP_TIMER("nsCharsetMenu:SetCurrentCharset");
1874 NS_TIMELINE_MARK_TIMER("nsCharsetMenu:SetCurrentCharset");
1878 NS_IMETHODIMP
nsCharsetMenu::SetCurrentMailCharset(const PRUnichar
* aCharset
)
1880 NS_TIMELINE_START_TIMER("nsCharsetMenu:SetCurrentMailCharset");
1881 nsresult res
= NS_OK
;
1883 if (mMailviewMenuInitialized
) {
1884 res
= AddCharsetToCache(NS_LossyConvertUTF16toASCII(aCharset
),
1885 &mMailviewMenu
, kNC_MailviewCharsetMenuRoot
,
1886 mMailviewCacheStart
, mMailviewCacheSize
,
1887 mMailviewMenuRDFPosition
);
1888 if (NS_FAILED(res
)) return res
;
1890 res
= WriteCacheToPrefs(&mMailviewMenu
, mMailviewCacheStart
,
1891 kMailviewCachePrefKey
);
1893 res
= UpdateCachePrefs(kMailviewCachePrefKey
, kMailviewCacheSizePrefKey
,
1894 kMailviewStaticPrefKey
, aCharset
);
1896 NS_TIMELINE_STOP_TIMER("nsCharsetMenu:SetCurrentMailCharset");
1897 NS_TIMELINE_MARK_TIMER("nsCharsetMenu:SetCurrentMailCharset");
1901 NS_IMETHODIMP
nsCharsetMenu::SetCurrentComposerCharset(const PRUnichar
* aCharset
)
1903 NS_TIMELINE_START_TIMER("nsCharsetMenu:SetCurrentComposerCharset");
1904 nsresult res
= NS_OK
;
1906 if (mComposerMenuInitialized
) {
1908 res
= AddCharsetToCache(NS_LossyConvertUTF16toASCII(aCharset
),
1909 &mComposerMenu
, kNC_ComposerCharsetMenuRoot
,
1910 mComposerCacheStart
, mComposerCacheSize
,
1911 mComposerMenuRDFPosition
);
1912 if (NS_FAILED(res
)) return res
;
1914 res
= WriteCacheToPrefs(&mComposerMenu
, mComposerCacheStart
,
1915 kComposerCachePrefKey
);
1917 res
= UpdateCachePrefs(kComposerCachePrefKey
, kComposerCacheSizePrefKey
,
1918 kComposerStaticPrefKey
, aCharset
);
1920 NS_TIMELINE_STOP_TIMER("nsCharsetMenu:SetCurrentComposerCharset");
1921 NS_TIMELINE_MARK_TIMER("nsCharsetMenu:SetCurrentComposerCharset");
1925 //----------------------------------------------------------------------------
1926 // Interface nsIRDFDataSource [implementation]
1928 NS_IMETHODIMP
nsCharsetMenu::GetURI(char ** uri
)
1930 if (!uri
) return NS_ERROR_NULL_POINTER
;
1932 *uri
= nsCRT::strdup("rdf:charset-menu");
1933 if (!(*uri
)) return NS_ERROR_OUT_OF_MEMORY
;
1938 NS_IMETHODIMP
nsCharsetMenu::GetSource(nsIRDFResource
* property
,
1941 nsIRDFResource
** source
)
1943 return mInner
->GetSource(property
, target
, tv
, source
);
1946 NS_IMETHODIMP
nsCharsetMenu::GetSources(nsIRDFResource
* property
,
1949 nsISimpleEnumerator
** sources
)
1951 return mInner
->GetSources(property
, target
, tv
, sources
);
1954 NS_IMETHODIMP
nsCharsetMenu::GetTarget(nsIRDFResource
* source
,
1955 nsIRDFResource
* property
,
1957 nsIRDFNode
** target
)
1959 return mInner
->GetTarget(source
, property
, tv
, target
);
1962 NS_IMETHODIMP
nsCharsetMenu::GetTargets(nsIRDFResource
* source
,
1963 nsIRDFResource
* property
,
1965 nsISimpleEnumerator
** targets
)
1967 return mInner
->GetTargets(source
, property
, tv
, targets
);
1970 NS_IMETHODIMP
nsCharsetMenu::Assert(nsIRDFResource
* aSource
,
1971 nsIRDFResource
* aProperty
,
1972 nsIRDFNode
* aTarget
,
1975 // TODO: filter out asserts we don't care about
1976 return mInner
->Assert(aSource
, aProperty
, aTarget
, aTruthValue
);
1979 NS_IMETHODIMP
nsCharsetMenu::Unassert(nsIRDFResource
* aSource
,
1980 nsIRDFResource
* aProperty
,
1981 nsIRDFNode
* aTarget
)
1983 // TODO: filter out unasserts we don't care about
1984 return mInner
->Unassert(aSource
, aProperty
, aTarget
);
1988 NS_IMETHODIMP
nsCharsetMenu::Change(nsIRDFResource
* aSource
,
1989 nsIRDFResource
* aProperty
,
1990 nsIRDFNode
* aOldTarget
,
1991 nsIRDFNode
* aNewTarget
)
1993 // TODO: filter out changes we don't care about
1994 return mInner
->Change(aSource
, aProperty
, aOldTarget
, aNewTarget
);
1997 NS_IMETHODIMP
nsCharsetMenu::Move(nsIRDFResource
* aOldSource
,
1998 nsIRDFResource
* aNewSource
,
1999 nsIRDFResource
* aProperty
,
2000 nsIRDFNode
* aTarget
)
2002 // TODO: filter out changes we don't care about
2003 return mInner
->Move(aOldSource
, aNewSource
, aProperty
, aTarget
);
2007 NS_IMETHODIMP
nsCharsetMenu::HasAssertion(nsIRDFResource
* source
,
2008 nsIRDFResource
* property
,
2009 nsIRDFNode
* target
, PRBool tv
,
2010 PRBool
* hasAssertion
)
2012 return mInner
->HasAssertion(source
, property
, target
, tv
, hasAssertion
);
2015 NS_IMETHODIMP
nsCharsetMenu::AddObserver(nsIRDFObserver
* n
)
2017 return mInner
->AddObserver(n
);
2020 NS_IMETHODIMP
nsCharsetMenu::RemoveObserver(nsIRDFObserver
* n
)
2022 return mInner
->RemoveObserver(n
);
2026 nsCharsetMenu::HasArcIn(nsIRDFNode
*aNode
, nsIRDFResource
*aArc
, PRBool
*result
)
2028 return mInner
->HasArcIn(aNode
, aArc
, result
);
2032 nsCharsetMenu::HasArcOut(nsIRDFResource
*source
, nsIRDFResource
*aArc
, PRBool
*result
)
2034 return mInner
->HasArcOut(source
, aArc
, result
);
2037 NS_IMETHODIMP
nsCharsetMenu::ArcLabelsIn(nsIRDFNode
* node
,
2038 nsISimpleEnumerator
** labels
)
2040 return mInner
->ArcLabelsIn(node
, labels
);
2043 NS_IMETHODIMP
nsCharsetMenu::ArcLabelsOut(nsIRDFResource
* source
,
2044 nsISimpleEnumerator
** labels
)
2046 return mInner
->ArcLabelsOut(source
, labels
);
2049 NS_IMETHODIMP
nsCharsetMenu::GetAllResources(nsISimpleEnumerator
** aCursor
)
2051 return mInner
->GetAllResources(aCursor
);
2054 NS_IMETHODIMP
nsCharsetMenu::GetAllCmds(
2055 nsIRDFResource
* source
,
2056 nsISimpleEnumerator
/*<nsIRDFResource>*/** commands
)
2058 NS_NOTYETIMPLEMENTED("write me!");
2059 return NS_ERROR_NOT_IMPLEMENTED
;
2062 NS_IMETHODIMP
nsCharsetMenu::IsCommandEnabled(
2063 nsISupportsArray
/*<nsIRDFResource>*/* aSources
,
2064 nsIRDFResource
* aCommand
,
2065 nsISupportsArray
/*<nsIRDFResource>*/* aArguments
,
2068 NS_NOTYETIMPLEMENTED("write me!");
2069 return NS_ERROR_NOT_IMPLEMENTED
;
2072 NS_IMETHODIMP
nsCharsetMenu::DoCommand(nsISupportsArray
* aSources
,
2073 nsIRDFResource
* aCommand
,
2074 nsISupportsArray
* aArguments
)
2076 NS_NOTYETIMPLEMENTED("write me!");
2077 return NS_ERROR_NOT_IMPLEMENTED
;
2080 NS_IMETHODIMP
nsCharsetMenu::BeginUpdateBatch()
2082 return mInner
->BeginUpdateBatch();
2085 NS_IMETHODIMP
nsCharsetMenu::EndUpdateBatch()
2087 return mInner
->EndUpdateBatch();
2090 // Module definitions
2092 static const nsModuleComponentInfo components
[] = {
2093 { "nsCharsetMenu", NS_CHARSETMENU_CID
,
2094 NS_RDF_DATASOURCE_CONTRACTID_PREFIX NS_CHARSETMENU_PID
,
2095 NS_NewCharsetMenu
},
2098 NS_IMPL_NSGETMODULE(nsXPIntlModule
, components
)