1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/intl/nsCharsetMenu.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1797 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsIServiceManager.h" 1.10 +#include "nsIComponentManager.h" 1.11 +#include "rdf.h" 1.12 +#include "nsIRDFDataSource.h" 1.13 +#include "nsIRDFService.h" 1.14 +#include "nsIRDFContainerUtils.h" 1.15 +#include "nsRDFCID.h" 1.16 +#include "nsXPIDLString.h" 1.17 +#include "nsCharsetMenu.h" 1.18 +#include "nsICharsetConverterManager.h" 1.19 +#include "nsICollation.h" 1.20 +#include "nsCollationCID.h" 1.21 +#include "nsILocaleService.h" 1.22 +#include "nsIPrefService.h" 1.23 +#include "nsIPrefBranch.h" 1.24 +#include "nsIPrefLocalizedString.h" 1.25 +#include "nsICurrentCharsetListener.h" 1.26 +#include "nsQuickSort.h" 1.27 +#include "nsIObserver.h" 1.28 +#include "nsStringEnumerator.h" 1.29 +#include "nsTArray.h" 1.30 +#include "nsIObserverService.h" 1.31 +#include "nsIRequestObserver.h" 1.32 +#include "nsCRT.h" 1.33 +#include "prmem.h" 1.34 +#include "mozilla/ModuleUtils.h" 1.35 +#include "nsCycleCollectionParticipant.h" 1.36 + 1.37 +//---------------------------------------------------------------------------- 1.38 +// Global functions and data [declaration] 1.39 + 1.40 +static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); 1.41 +static NS_DEFINE_CID(kRDFInMemoryDataSourceCID, NS_RDFINMEMORYDATASOURCE_CID); 1.42 +static NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID); 1.43 +static NS_DEFINE_CID(kRDFContainerCID, NS_RDFCONTAINER_CID); 1.44 + 1.45 +static const char kURINC_BrowserAutodetMenuRoot[] = "NC:BrowserAutodetMenuRoot"; 1.46 +static const char kURINC_BrowserCharsetMenuRoot[] = "NC:BrowserCharsetMenuRoot"; 1.47 +static const char kURINC_BrowserMoreCharsetMenuRoot[] = "NC:BrowserMoreCharsetMenuRoot"; 1.48 +static const char kURINC_BrowserMore1CharsetMenuRoot[] = "NC:BrowserMore1CharsetMenuRoot"; 1.49 +static const char kURINC_BrowserMore2CharsetMenuRoot[] = "NC:BrowserMore2CharsetMenuRoot"; 1.50 +static const char kURINC_BrowserMore3CharsetMenuRoot[] = "NC:BrowserMore3CharsetMenuRoot"; 1.51 +static const char kURINC_BrowserMore4CharsetMenuRoot[] = "NC:BrowserMore4CharsetMenuRoot"; 1.52 +static const char kURINC_BrowserMore5CharsetMenuRoot[] = "NC:BrowserMore5CharsetMenuRoot"; 1.53 +static const char kURINC_MaileditCharsetMenuRoot[] = "NC:MaileditCharsetMenuRoot"; 1.54 +static const char kURINC_MailviewCharsetMenuRoot[] = "NC:MailviewCharsetMenuRoot"; 1.55 +static const char kURINC_ComposerCharsetMenuRoot[] = "NC:ComposerCharsetMenuRoot"; 1.56 +static const char kURINC_DecodersRoot[] = "NC:DecodersRoot"; 1.57 +static const char kURINC_EncodersRoot[] = "NC:EncodersRoot"; 1.58 +DEFINE_RDF_VOCAB(NC_NAMESPACE_URI, NC, Name); 1.59 +DEFINE_RDF_VOCAB(NC_NAMESPACE_URI, NC, BookmarkSeparator); 1.60 +DEFINE_RDF_VOCAB(NC_NAMESPACE_URI, NC, CharsetDetector); 1.61 +DEFINE_RDF_VOCAB(RDF_NAMESPACE_URI, NC, type); 1.62 + 1.63 +// Note here that browser and mailview have the same static area and cache 1.64 +// size but the cache itself is separate. 1.65 + 1.66 +#define kBrowserStaticPrefKey "intl.charsetmenu.browser.static" 1.67 +#define kBrowserCachePrefKey "intl.charsetmenu.browser.cache" 1.68 +#define kBrowserCacheSizePrefKey "intl.charsetmenu.browser.cache.size" 1.69 + 1.70 +#define kMailviewStaticPrefKey "intl.charsetmenu.browser.static" 1.71 +#define kMailviewCachePrefKey "intl.charsetmenu.mailview.cache" 1.72 +#define kMailviewCacheSizePrefKey "intl.charsetmenu.browser.cache.size" 1.73 + 1.74 +#define kComposerStaticPrefKey "intl.charsetmenu.browser.static" 1.75 +#define kComposerCachePrefKey "intl.charsetmenu.composer.cache" 1.76 +#define kComposerCacheSizePrefKey "intl.charsetmenu.browser.cache.size" 1.77 + 1.78 +#define kMaileditPrefKey "intl.charsetmenu.mailedit" 1.79 + 1.80 +//---------------------------------------------------------------------------- 1.81 +// Class nsMenuEntry [declaration] 1.82 + 1.83 +/** 1.84 + * A little class holding all data needed for a menu item. 1.85 + * 1.86 + * @created 18/Apr/2000 1.87 + * @author Catalin Rotaru [CATA] 1.88 + */ 1.89 +class nsMenuEntry 1.90 +{ 1.91 +public: 1.92 + // memory & ref counting & leak prevention stuff 1.93 + nsMenuEntry() { MOZ_COUNT_CTOR(nsMenuEntry); } 1.94 + ~nsMenuEntry() { MOZ_COUNT_DTOR(nsMenuEntry); } 1.95 + 1.96 + nsAutoCString mCharset; 1.97 + nsAutoString mTitle; 1.98 +}; 1.99 + 1.100 +//---------------------------------------------------------------------------- 1.101 +// Class nsCharsetMenu [declaration] 1.102 + 1.103 +/** 1.104 + * The Charset Converter menu. 1.105 + * 1.106 + * God, our GUI programming disgusts me. 1.107 + * 1.108 + * @created 23/Nov/1999 1.109 + * @author Catalin Rotaru [CATA] 1.110 + */ 1.111 +class nsCharsetMenu : public nsIRDFDataSource, public nsICurrentCharsetListener 1.112 +{ 1.113 + NS_DECL_CYCLE_COLLECTING_ISUPPORTS 1.114 + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsCharsetMenu, nsIRDFDataSource) 1.115 + 1.116 +private: 1.117 + static nsIRDFResource * kNC_BrowserAutodetMenuRoot; 1.118 + static nsIRDFResource * kNC_BrowserCharsetMenuRoot; 1.119 + static nsIRDFResource * kNC_BrowserMoreCharsetMenuRoot; 1.120 + static nsIRDFResource * kNC_BrowserMore1CharsetMenuRoot; 1.121 + static nsIRDFResource * kNC_BrowserMore2CharsetMenuRoot; 1.122 + static nsIRDFResource * kNC_BrowserMore3CharsetMenuRoot; 1.123 + static nsIRDFResource * kNC_BrowserMore4CharsetMenuRoot; 1.124 + static nsIRDFResource * kNC_BrowserMore5CharsetMenuRoot; 1.125 + static nsIRDFResource * kNC_MaileditCharsetMenuRoot; 1.126 + static nsIRDFResource * kNC_MailviewCharsetMenuRoot; 1.127 + static nsIRDFResource * kNC_ComposerCharsetMenuRoot; 1.128 + static nsIRDFResource * kNC_DecodersRoot; 1.129 + static nsIRDFResource * kNC_EncodersRoot; 1.130 + static nsIRDFResource * kNC_Name; 1.131 + static nsIRDFResource * kNC_CharsetDetector; 1.132 + static nsIRDFResource * kNC_BookmarkSeparator; 1.133 + static nsIRDFResource * kRDF_type; 1.134 + 1.135 + static nsIRDFDataSource * mInner; 1.136 + 1.137 + bool mInitialized; 1.138 + bool mMailviewMenuInitialized; 1.139 + bool mComposerMenuInitialized; 1.140 + bool mMaileditMenuInitialized; 1.141 + bool mSecondaryTiersInitialized; 1.142 + bool mAutoDetectInitialized; 1.143 + bool mOthersInitialized; 1.144 + 1.145 + nsTArray<nsMenuEntry*> mMailviewMenu; 1.146 + int32_t mMailviewCacheStart; 1.147 + int32_t mMailviewCacheSize; 1.148 + int32_t mMailviewMenuRDFPosition; 1.149 + 1.150 + nsTArray<nsMenuEntry*> mComposerMenu; 1.151 + int32_t mComposerCacheStart; 1.152 + int32_t mComposerCacheSize; 1.153 + int32_t mComposerMenuRDFPosition; 1.154 + 1.155 + nsCOMPtr<nsIRDFService> mRDFService; 1.156 + nsCOMPtr<nsICharsetConverterManager> mCCManager; 1.157 + nsCOMPtr<nsIPrefBranch> mPrefs; 1.158 + nsCOMPtr<nsIObserver> mCharsetMenuObserver; 1.159 + nsTArray<nsCString> mDecoderList; 1.160 + 1.161 + nsresult Done(); 1.162 + 1.163 + nsresult FreeResources(); 1.164 + 1.165 + nsresult InitStaticMenu(nsTArray<nsCString>& aDecs, 1.166 + nsIRDFResource * aResource, 1.167 + const char * aKey, 1.168 + nsTArray<nsMenuEntry*> * aArray); 1.169 + nsresult InitCacheMenu(nsTArray<nsCString>& aDecs, 1.170 + nsIRDFResource * aResource, 1.171 + const char * aKey, 1.172 + nsTArray<nsMenuEntry*> * aArray); 1.173 + 1.174 + nsresult InitMoreMenu(nsTArray<nsCString>& aDecs, 1.175 + nsIRDFResource * aResource, 1.176 + const char * aFlag); 1.177 + 1.178 + nsresult InitMoreSubmenus(nsTArray<nsCString>& aDecs); 1.179 + 1.180 + static nsresult SetArrayFromEnumerator(nsIUTF8StringEnumerator* aEnumerator, 1.181 + nsTArray<nsCString>& aArray); 1.182 + 1.183 + nsresult AddCharsetToItemArray(nsTArray<nsMenuEntry*>* aArray, 1.184 + const nsAFlatCString& aCharset, 1.185 + nsMenuEntry ** aResult, 1.186 + int32_t aPlace); 1.187 + nsresult AddCharsetArrayToItemArray(nsTArray<nsMenuEntry*> &aArray, 1.188 + const nsTArray<nsCString>& aCharsets); 1.189 + nsresult AddMenuItemToContainer(nsIRDFContainer * aContainer, 1.190 + nsMenuEntry * aItem, nsIRDFResource * aType, const char * aIDPrefix, 1.191 + int32_t aPlace); 1.192 + nsresult AddMenuItemArrayToContainer(nsIRDFContainer * aContainer, 1.193 + nsTArray<nsMenuEntry*> * aArray, nsIRDFResource * aType); 1.194 + nsresult AddCharsetToContainer(nsTArray<nsMenuEntry*> * aArray, 1.195 + nsIRDFContainer * aContainer, 1.196 + const nsAFlatCString& aCharset, 1.197 + const char * aIDPrefix, 1.198 + int32_t aPlace, int32_t aRDFPlace); 1.199 + 1.200 + nsresult AddFromPrefsToMenu(nsTArray<nsMenuEntry*> * aArray, 1.201 + nsIRDFContainer * aContainer, 1.202 + const char * aKey, 1.203 + nsTArray<nsCString>& aDecs, 1.204 + const char * aIDPrefix); 1.205 + nsresult AddFromNolocPrefsToMenu(nsTArray<nsMenuEntry*> * aArray, 1.206 + nsIRDFContainer * aContainer, 1.207 + const char * aKey, 1.208 + nsTArray<nsCString>& aDecs, 1.209 + const char * aIDPrefix); 1.210 + nsresult AddFromStringToMenu(char * aCharsetList, 1.211 + nsTArray<nsMenuEntry*> * aArray, 1.212 + nsIRDFContainer * aContainer, 1.213 + nsTArray<nsCString>& aDecs, 1.214 + const char * aIDPrefix); 1.215 + 1.216 + nsresult AddSeparatorToContainer(nsIRDFContainer * aContainer); 1.217 + nsresult AddCharsetToCache(const nsAFlatCString& aCharset, 1.218 + nsTArray<nsMenuEntry*> * aArray, 1.219 + nsIRDFResource * aRDFResource, 1.220 + uint32_t aCacheStart, uint32_t aCacheSize, 1.221 + int32_t aRDFPlace); 1.222 + 1.223 + nsresult WriteCacheToPrefs(nsTArray<nsMenuEntry*> * aArray, int32_t aCacheStart, 1.224 + const char * aKey); 1.225 + nsresult UpdateCachePrefs(const char * aCacheKey, const char * aCacheSizeKey, 1.226 + const char * aStaticKey, const char16_t * aCharset); 1.227 + 1.228 + nsresult ClearMenu(nsIRDFContainer * aContainer, nsTArray<nsMenuEntry*> * aArray); 1.229 + nsresult RemoveLastMenuItem(nsIRDFContainer * aContainer, 1.230 + nsTArray<nsMenuEntry*> * aArray); 1.231 + 1.232 + nsresult RemoveFlaggedCharsets(nsTArray<nsCString>& aList, const nsString& aProp); 1.233 + nsresult NewRDFContainer(nsIRDFDataSource * aDataSource, 1.234 + nsIRDFResource * aResource, nsIRDFContainer ** aResult); 1.235 + void FreeMenuItemArray(nsTArray<nsMenuEntry*> * aArray); 1.236 + int32_t FindMenuItemInArray(const nsTArray<nsMenuEntry*>* aArray, 1.237 + const nsAFlatCString& aCharset, 1.238 + nsMenuEntry ** aResult); 1.239 + nsresult ReorderMenuItemArray(nsTArray<nsMenuEntry*> * aArray); 1.240 + nsresult GetCollation(nsICollation ** aCollation); 1.241 + 1.242 +public: 1.243 + nsCharsetMenu(); 1.244 + virtual ~nsCharsetMenu(); 1.245 + 1.246 + nsresult Init(); 1.247 + nsresult InitMaileditMenu(); 1.248 + nsresult InitMailviewMenu(); 1.249 + nsresult InitComposerMenu(); 1.250 + nsresult InitOthers(); 1.251 + nsresult InitSecondaryTiers(); 1.252 + nsresult InitAutodetMenu(); 1.253 + nsresult RefreshMailviewMenu(); 1.254 + nsresult RefreshMaileditMenu(); 1.255 + nsresult RefreshComposerMenu(); 1.256 + 1.257 + //-------------------------------------------------------------------------- 1.258 + // Interface nsICurrentCharsetListener [declaration] 1.259 + 1.260 + NS_IMETHOD SetCurrentCharset(const char16_t * aCharset); 1.261 + NS_IMETHOD SetCurrentMailCharset(const char16_t * aCharset); 1.262 + NS_IMETHOD SetCurrentComposerCharset(const char16_t * aCharset); 1.263 + 1.264 + //-------------------------------------------------------------------------- 1.265 + // Interface nsIRDFDataSource [declaration] 1.266 + 1.267 + NS_DECL_NSIRDFDATASOURCE 1.268 +}; 1.269 + 1.270 +//---------------------------------------------------------------------------- 1.271 +// Global functions and data [implementation] 1.272 + 1.273 +nsresult 1.274 +NS_NewCharsetMenu(nsISupports * aOuter, const nsIID & aIID, 1.275 + void ** aResult) 1.276 +{ 1.277 + if (!aResult) { 1.278 + return NS_ERROR_NULL_POINTER; 1.279 + } 1.280 + if (aOuter) { 1.281 + *aResult = nullptr; 1.282 + return NS_ERROR_NO_AGGREGATION; 1.283 + } 1.284 + nsCharsetMenu* inst = new nsCharsetMenu(); 1.285 + if (!inst) { 1.286 + *aResult = nullptr; 1.287 + return NS_ERROR_OUT_OF_MEMORY; 1.288 + } 1.289 + nsresult res = inst->QueryInterface(aIID, aResult); 1.290 + if (NS_FAILED(res)) { 1.291 + *aResult = nullptr; 1.292 + delete inst; 1.293 + } 1.294 + return res; 1.295 +} 1.296 + 1.297 +struct charsetMenuSortRecord { 1.298 + nsMenuEntry* item; 1.299 + uint8_t* key; 1.300 + uint32_t len; 1.301 + 1.302 +}; 1.303 + 1.304 +static int CompareMenuItems(const void* aArg1, const void* aArg2, void *data) 1.305 +{ 1.306 + int32_t res; 1.307 + nsICollation * collation = (nsICollation *) data; 1.308 + charsetMenuSortRecord *rec1 = (charsetMenuSortRecord *) aArg1; 1.309 + charsetMenuSortRecord *rec2 = (charsetMenuSortRecord *) aArg2; 1.310 + 1.311 + collation->CompareRawSortKey(rec1->key, rec1->len, rec2->key, rec2->len, &res); 1.312 + 1.313 + return res; 1.314 +} 1.315 + 1.316 +nsresult 1.317 +nsCharsetMenu::SetArrayFromEnumerator(nsIUTF8StringEnumerator* aEnumerator, 1.318 + nsTArray<nsCString>& aArray) 1.319 +{ 1.320 + nsresult rv; 1.321 + 1.322 + bool hasMore; 1.323 + rv = aEnumerator->HasMore(&hasMore); 1.324 + 1.325 + nsAutoCString value; 1.326 + while (NS_SUCCEEDED(rv) && hasMore) { 1.327 + rv = aEnumerator->GetNext(value); 1.328 + if (NS_SUCCEEDED(rv)) 1.329 + aArray.AppendElement(value); 1.330 + 1.331 + rv = aEnumerator->HasMore(&hasMore); 1.332 + } 1.333 + 1.334 + return rv; 1.335 +} 1.336 + 1.337 + 1.338 +class nsIgnoreCaseCStringComparator 1.339 +{ 1.340 + public: 1.341 + bool Equals(const nsACString& a, const nsACString& b) const 1.342 + { 1.343 + return nsCString(a).Equals(b, nsCaseInsensitiveCStringComparator()); 1.344 + } 1.345 + 1.346 + bool LessThan(const nsACString& a, const nsACString& b) const 1.347 + { 1.348 + return a < b; 1.349 + } 1.350 +}; 1.351 + 1.352 +//---------------------------------------------------------------------------- 1.353 +// Class nsCharsetMenuObserver 1.354 + 1.355 +class nsCharsetMenuObserver : public nsIObserver { 1.356 + 1.357 +public: 1.358 + NS_DECL_ISUPPORTS 1.359 + NS_DECL_NSIOBSERVER 1.360 + 1.361 + nsCharsetMenuObserver(nsCharsetMenu * menu) 1.362 + : mCharsetMenu(menu) 1.363 + { 1.364 + } 1.365 + 1.366 + virtual ~nsCharsetMenuObserver() {} 1.367 + 1.368 +private: 1.369 + nsCharsetMenu* mCharsetMenu; 1.370 +}; 1.371 + 1.372 +NS_IMPL_ISUPPORTS(nsCharsetMenuObserver, nsIObserver) 1.373 + 1.374 +NS_IMETHODIMP nsCharsetMenuObserver::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData) 1.375 +{ 1.376 + nsresult rv = NS_OK; 1.377 + 1.378 + //XUL event handler 1.379 + if (!nsCRT::strcmp(aTopic, "charsetmenu-selected")) { 1.380 + nsDependentString nodeName(someData); 1.381 + rv = mCharsetMenu->Init(); 1.382 + if (nodeName.EqualsLiteral("composer")) { 1.383 + rv = mCharsetMenu->InitComposerMenu(); 1.384 + } 1.385 + if (nodeName.EqualsLiteral("mailview")) { 1.386 + rv = mCharsetMenu->InitMailviewMenu(); 1.387 + } 1.388 + if (nodeName.EqualsLiteral("mailedit")) { 1.389 + rv = mCharsetMenu->InitMaileditMenu(); 1.390 + rv = mCharsetMenu->InitOthers(); 1.391 + } 1.392 + if (nodeName.EqualsLiteral("more-menu")) { 1.393 + rv = mCharsetMenu->InitSecondaryTiers(); 1.394 + rv = mCharsetMenu->InitAutodetMenu(); 1.395 + } 1.396 + if (nodeName.EqualsLiteral("other")) { 1.397 + rv = mCharsetMenu->InitOthers(); 1.398 + rv = mCharsetMenu->InitMaileditMenu(); 1.399 + } 1.400 + } 1.401 + 1.402 + //pref event handler 1.403 + if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { 1.404 + nsDependentString prefName(someData); 1.405 + 1.406 + if (prefName.EqualsLiteral(kBrowserStaticPrefKey)) { 1.407 + // refresh menus which share this pref 1.408 + rv = mCharsetMenu->RefreshMailviewMenu(); 1.409 + NS_ENSURE_SUCCESS(rv, rv); 1.410 + rv = mCharsetMenu->RefreshComposerMenu(); 1.411 + } 1.412 + else if (prefName.EqualsLiteral(kMaileditPrefKey)) { 1.413 + rv = mCharsetMenu->RefreshMaileditMenu(); 1.414 + } 1.415 + } 1.416 + 1.417 + return rv; 1.418 +} 1.419 + 1.420 +//---------------------------------------------------------------------------- 1.421 +// Class nsCharsetMenu [implementation] 1.422 + 1.423 +NS_IMPL_CYCLE_COLLECTION_CLASS(nsCharsetMenu) 1.424 + 1.425 +NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsCharsetMenu) 1.426 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCharsetMenu) 1.427 + cb.NoteXPCOMChild(nsCharsetMenu::mInner); 1.428 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.429 + 1.430 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCharsetMenu) 1.431 +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCharsetMenu) 1.432 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCharsetMenu) 1.433 + NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource) 1.434 + NS_INTERFACE_MAP_ENTRY(nsICurrentCharsetListener) 1.435 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRDFDataSource) 1.436 +NS_INTERFACE_MAP_END 1.437 + 1.438 +nsIRDFDataSource * nsCharsetMenu::mInner = nullptr; 1.439 +nsIRDFResource * nsCharsetMenu::kNC_BrowserAutodetMenuRoot = nullptr; 1.440 +nsIRDFResource * nsCharsetMenu::kNC_BrowserCharsetMenuRoot = nullptr; 1.441 +nsIRDFResource * nsCharsetMenu::kNC_BrowserMoreCharsetMenuRoot = nullptr; 1.442 +nsIRDFResource * nsCharsetMenu::kNC_BrowserMore1CharsetMenuRoot = nullptr; 1.443 +nsIRDFResource * nsCharsetMenu::kNC_BrowserMore2CharsetMenuRoot = nullptr; 1.444 +nsIRDFResource * nsCharsetMenu::kNC_BrowserMore3CharsetMenuRoot = nullptr; 1.445 +nsIRDFResource * nsCharsetMenu::kNC_BrowserMore4CharsetMenuRoot = nullptr; 1.446 +nsIRDFResource * nsCharsetMenu::kNC_BrowserMore5CharsetMenuRoot = nullptr; 1.447 +nsIRDFResource * nsCharsetMenu::kNC_MaileditCharsetMenuRoot = nullptr; 1.448 +nsIRDFResource * nsCharsetMenu::kNC_MailviewCharsetMenuRoot = nullptr; 1.449 +nsIRDFResource * nsCharsetMenu::kNC_ComposerCharsetMenuRoot = nullptr; 1.450 +nsIRDFResource * nsCharsetMenu::kNC_DecodersRoot = nullptr; 1.451 +nsIRDFResource * nsCharsetMenu::kNC_EncodersRoot = nullptr; 1.452 +nsIRDFResource * nsCharsetMenu::kNC_Name = nullptr; 1.453 +nsIRDFResource * nsCharsetMenu::kNC_CharsetDetector = nullptr; 1.454 +nsIRDFResource * nsCharsetMenu::kNC_BookmarkSeparator = nullptr; 1.455 +nsIRDFResource * nsCharsetMenu::kRDF_type = nullptr; 1.456 + 1.457 +nsCharsetMenu::nsCharsetMenu() 1.458 +: mInitialized(false), 1.459 + mMailviewMenuInitialized(false), 1.460 + mComposerMenuInitialized(false), 1.461 + mMaileditMenuInitialized(false), 1.462 + mSecondaryTiersInitialized(false), 1.463 + mAutoDetectInitialized(false), 1.464 + mOthersInitialized(false) 1.465 +{ 1.466 + nsresult res = NS_OK; 1.467 + 1.468 + //get charset manager 1.469 + mCCManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &res); 1.470 + 1.471 + //initialize skeleton RDF source 1.472 + mRDFService = do_GetService(kRDFServiceCID, &res); 1.473 + 1.474 + if (NS_SUCCEEDED(res)) { 1.475 + mRDFService->RegisterDataSource(this, false); 1.476 + 1.477 + CallCreateInstance(kRDFInMemoryDataSourceCID, &mInner); 1.478 + 1.479 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserCharsetMenuRoot), 1.480 + &kNC_BrowserCharsetMenuRoot); 1.481 + } 1.482 + 1.483 + //get pref service 1.484 + nsCOMPtr<nsIPrefService> PrefService = do_GetService(NS_PREFSERVICE_CONTRACTID, &res); 1.485 + if (NS_SUCCEEDED(res)) 1.486 + res = PrefService->GetBranch(nullptr, getter_AddRefs(mPrefs)); 1.487 + 1.488 + //register event listener 1.489 + mCharsetMenuObserver = new nsCharsetMenuObserver(this); 1.490 + 1.491 + if (mCharsetMenuObserver) { 1.492 + nsCOMPtr<nsIObserverService> observerService = 1.493 + do_GetService("@mozilla.org/observer-service;1", &res); 1.494 + 1.495 + if (NS_SUCCEEDED(res)) 1.496 + res = observerService->AddObserver(mCharsetMenuObserver, 1.497 + "charsetmenu-selected", 1.498 + false); 1.499 + } 1.500 + 1.501 + NS_ASSERTION(NS_SUCCEEDED(res), "Failed to initialize nsCharsetMenu"); 1.502 +} 1.503 + 1.504 +nsCharsetMenu::~nsCharsetMenu() 1.505 +{ 1.506 + Done(); 1.507 + 1.508 + FreeMenuItemArray(&mMailviewMenu); 1.509 + FreeMenuItemArray(&mComposerMenu); 1.510 + 1.511 + FreeResources(); 1.512 +} 1.513 + 1.514 +nsresult nsCharsetMenu::RefreshMailviewMenu() 1.515 +{ 1.516 + nsresult res = NS_OK; 1.517 + 1.518 + nsCOMPtr<nsIRDFContainer> container; 1.519 + res = NewRDFContainer(mInner, kNC_MailviewCharsetMenuRoot, getter_AddRefs(container)); 1.520 + if (NS_FAILED(res)) return res; 1.521 + 1.522 + // clean the menu 1.523 + res = ClearMenu(container, &mMailviewMenu); 1.524 + if (NS_FAILED(res)) return res; 1.525 + 1.526 + nsCOMPtr<nsIUTF8StringEnumerator> decoders; 1.527 + res = mCCManager->GetDecoderList(getter_AddRefs(decoders)); 1.528 + if (NS_FAILED(res)) return res; 1.529 + 1.530 + nsTArray<nsCString> decs; 1.531 + SetArrayFromEnumerator(decoders, decs); 1.532 + 1.533 + res = AddFromPrefsToMenu(&mMailviewMenu, container, kMailviewStaticPrefKey, 1.534 + decs, "charset."); 1.535 + NS_ASSERTION(NS_SUCCEEDED(res), "error initializing static charset menu from prefs"); 1.536 + 1.537 + // mark the end of the static area, the rest is cache 1.538 + mMailviewCacheStart = mMailviewMenu.Length(); 1.539 + 1.540 + res = InitCacheMenu(decs, kNC_MailviewCharsetMenuRoot, 1.541 + kMailviewCachePrefKey, &mMailviewMenu); 1.542 + NS_ASSERTION(NS_SUCCEEDED(res), "error initializing mailview cache charset menu"); 1.543 + 1.544 + return res; 1.545 +} 1.546 + 1.547 +nsresult nsCharsetMenu::RefreshMaileditMenu() 1.548 +{ 1.549 + nsresult res; 1.550 + 1.551 + nsCOMPtr<nsIRDFContainer> container; 1.552 + res = NewRDFContainer(mInner, kNC_MaileditCharsetMenuRoot, getter_AddRefs(container)); 1.553 + NS_ENSURE_SUCCESS(res, res); 1.554 + 1.555 + nsCOMPtr<nsISimpleEnumerator> enumerator; 1.556 + res = container->GetElements(getter_AddRefs(enumerator)); 1.557 + NS_ENSURE_SUCCESS(res, res); 1.558 + 1.559 + // clear the menu 1.560 + nsCOMPtr<nsISupports> supports; 1.561 + while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(supports)))) { 1.562 + nsCOMPtr<nsIRDFNode> node = do_QueryInterface(supports); 1.563 + 1.564 + res = mInner->Unassert(kNC_MaileditCharsetMenuRoot, kNC_Name, node); 1.565 + NS_ENSURE_SUCCESS(res, res); 1.566 + 1.567 + res = container->RemoveElement(node, false); 1.568 + NS_ENSURE_SUCCESS(res, res); 1.569 + } 1.570 + 1.571 + // get a list of available encoders 1.572 + nsCOMPtr<nsIUTF8StringEnumerator> encoders; 1.573 + res = mCCManager->GetEncoderList(getter_AddRefs(encoders)); 1.574 + NS_ENSURE_SUCCESS(res, res); 1.575 + 1.576 + nsTArray<nsCString> encs; 1.577 + SetArrayFromEnumerator(encoders, encs); 1.578 + 1.579 + // add menu items from pref 1.580 + res = AddFromPrefsToMenu(nullptr, container, kMaileditPrefKey, encs, nullptr); 1.581 + NS_ASSERTION(NS_SUCCEEDED(res), "error initializing mailedit charset menu from prefs"); 1.582 + 1.583 + return res; 1.584 +} 1.585 + 1.586 +nsresult nsCharsetMenu::RefreshComposerMenu() 1.587 +{ 1.588 + nsresult res = NS_OK; 1.589 + 1.590 + nsCOMPtr<nsIRDFContainer> container; 1.591 + res = NewRDFContainer(mInner, kNC_ComposerCharsetMenuRoot, getter_AddRefs(container)); 1.592 + if (NS_FAILED(res)) return res; 1.593 + 1.594 + // clean the menu 1.595 + res = ClearMenu(container, &mComposerMenu); 1.596 + if (NS_FAILED(res)) return res; 1.597 + 1.598 + nsCOMPtr<nsIUTF8StringEnumerator> decoders; 1.599 + res = mCCManager->GetDecoderList(getter_AddRefs(decoders)); 1.600 + if (NS_FAILED(res)) return res; 1.601 + 1.602 + nsTArray<nsCString> decs; 1.603 + SetArrayFromEnumerator(decoders, decs); 1.604 + 1.605 + res = AddFromPrefsToMenu(&mComposerMenu, container, kComposerStaticPrefKey, 1.606 + decs, "charset."); 1.607 + NS_ASSERTION(NS_SUCCEEDED(res), "error initializing static charset menu from prefs"); 1.608 + 1.609 + // mark the end of the static area, the rest is cache 1.610 + mComposerCacheStart = mComposerMenu.Length(); 1.611 + 1.612 + res = InitCacheMenu(decs, kNC_ComposerCharsetMenuRoot, 1.613 + kComposerCachePrefKey, &mComposerMenu); 1.614 + NS_ASSERTION(NS_SUCCEEDED(res), "error initializing composer cache charset menu"); 1.615 + 1.616 + return res; 1.617 +} 1.618 + 1.619 +nsresult nsCharsetMenu::Init() 1.620 +{ 1.621 + nsresult res = NS_OK; 1.622 + 1.623 + if (!mInitialized) { 1.624 + 1.625 + //enumerate decoders 1.626 + nsCOMPtr<nsIUTF8StringEnumerator> decoders; 1.627 + res = mCCManager->GetDecoderList(getter_AddRefs(decoders)); 1.628 + if (NS_FAILED(res)) return res; 1.629 + 1.630 + SetArrayFromEnumerator(decoders, mDecoderList); 1.631 + 1.632 + //initialize all remaining RDF template nodes 1.633 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserAutodetMenuRoot), 1.634 + &kNC_BrowserAutodetMenuRoot); 1.635 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMoreCharsetMenuRoot), 1.636 + &kNC_BrowserMoreCharsetMenuRoot); 1.637 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMore1CharsetMenuRoot), 1.638 + &kNC_BrowserMore1CharsetMenuRoot); 1.639 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMore2CharsetMenuRoot), 1.640 + &kNC_BrowserMore2CharsetMenuRoot); 1.641 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMore3CharsetMenuRoot), 1.642 + &kNC_BrowserMore3CharsetMenuRoot); 1.643 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMore4CharsetMenuRoot), 1.644 + &kNC_BrowserMore4CharsetMenuRoot); 1.645 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMore5CharsetMenuRoot), 1.646 + &kNC_BrowserMore5CharsetMenuRoot); 1.647 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_MaileditCharsetMenuRoot), 1.648 + &kNC_MaileditCharsetMenuRoot); 1.649 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_MailviewCharsetMenuRoot), 1.650 + &kNC_MailviewCharsetMenuRoot); 1.651 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_ComposerCharsetMenuRoot), 1.652 + &kNC_ComposerCharsetMenuRoot); 1.653 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_DecodersRoot), 1.654 + &kNC_DecodersRoot); 1.655 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_EncodersRoot), 1.656 + &kNC_EncodersRoot); 1.657 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_Name), 1.658 + &kNC_Name); 1.659 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_CharsetDetector), 1.660 + &kNC_CharsetDetector); 1.661 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BookmarkSeparator), 1.662 + &kNC_BookmarkSeparator); 1.663 + mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_type), &kRDF_type); 1.664 + 1.665 + nsIRDFContainerUtils * rdfUtil = nullptr; 1.666 + res = CallGetService(kRDFContainerUtilsCID, &rdfUtil); 1.667 + if (NS_FAILED(res)) goto done; 1.668 + 1.669 + res = rdfUtil->MakeSeq(mInner, kNC_BrowserAutodetMenuRoot, nullptr); 1.670 + if (NS_FAILED(res)) goto done; 1.671 + res = rdfUtil->MakeSeq(mInner, kNC_BrowserCharsetMenuRoot, nullptr); 1.672 + if (NS_FAILED(res)) goto done; 1.673 + res = rdfUtil->MakeSeq(mInner, kNC_BrowserMoreCharsetMenuRoot, nullptr); 1.674 + if (NS_FAILED(res)) goto done; 1.675 + res = rdfUtil->MakeSeq(mInner, kNC_BrowserMore1CharsetMenuRoot, nullptr); 1.676 + if (NS_FAILED(res)) goto done; 1.677 + res = rdfUtil->MakeSeq(mInner, kNC_BrowserMore2CharsetMenuRoot, nullptr); 1.678 + if (NS_FAILED(res)) goto done; 1.679 + res = rdfUtil->MakeSeq(mInner, kNC_BrowserMore3CharsetMenuRoot, nullptr); 1.680 + if (NS_FAILED(res)) goto done; 1.681 + res = rdfUtil->MakeSeq(mInner, kNC_BrowserMore4CharsetMenuRoot, nullptr); 1.682 + if (NS_FAILED(res)) goto done; 1.683 + res = rdfUtil->MakeSeq(mInner, kNC_BrowserMore5CharsetMenuRoot, nullptr); 1.684 + if (NS_FAILED(res)) goto done; 1.685 + res = rdfUtil->MakeSeq(mInner, kNC_MaileditCharsetMenuRoot, nullptr); 1.686 + if (NS_FAILED(res)) goto done; 1.687 + res = rdfUtil->MakeSeq(mInner, kNC_MailviewCharsetMenuRoot, nullptr); 1.688 + if (NS_FAILED(res)) goto done; 1.689 + res = rdfUtil->MakeSeq(mInner, kNC_ComposerCharsetMenuRoot, nullptr); 1.690 + if (NS_FAILED(res)) goto done; 1.691 + res = rdfUtil->MakeSeq(mInner, kNC_DecodersRoot, nullptr); 1.692 + if (NS_FAILED(res)) goto done; 1.693 + res = rdfUtil->MakeSeq(mInner, kNC_EncodersRoot, nullptr); 1.694 + if (NS_FAILED(res)) goto done; 1.695 + 1.696 + done: 1.697 + NS_IF_RELEASE(rdfUtil); 1.698 + if (NS_FAILED(res)) return res; 1.699 + } 1.700 + mInitialized = NS_SUCCEEDED(res); 1.701 + return res; 1.702 +} 1.703 + 1.704 +nsresult nsCharsetMenu::Done() 1.705 +{ 1.706 + nsresult res = NS_OK; 1.707 + res = mRDFService->UnregisterDataSource(this); 1.708 + 1.709 + NS_IF_RELEASE(kNC_BrowserAutodetMenuRoot); 1.710 + NS_IF_RELEASE(kNC_BrowserCharsetMenuRoot); 1.711 + NS_IF_RELEASE(kNC_BrowserMoreCharsetMenuRoot); 1.712 + NS_IF_RELEASE(kNC_BrowserMore1CharsetMenuRoot); 1.713 + NS_IF_RELEASE(kNC_BrowserMore2CharsetMenuRoot); 1.714 + NS_IF_RELEASE(kNC_BrowserMore3CharsetMenuRoot); 1.715 + NS_IF_RELEASE(kNC_BrowserMore4CharsetMenuRoot); 1.716 + NS_IF_RELEASE(kNC_BrowserMore5CharsetMenuRoot); 1.717 + NS_IF_RELEASE(kNC_MaileditCharsetMenuRoot); 1.718 + NS_IF_RELEASE(kNC_MailviewCharsetMenuRoot); 1.719 + NS_IF_RELEASE(kNC_ComposerCharsetMenuRoot); 1.720 + NS_IF_RELEASE(kNC_DecodersRoot); 1.721 + NS_IF_RELEASE(kNC_EncodersRoot); 1.722 + NS_IF_RELEASE(kNC_Name); 1.723 + NS_IF_RELEASE(kNC_CharsetDetector); 1.724 + NS_IF_RELEASE(kNC_BookmarkSeparator); 1.725 + NS_IF_RELEASE(kRDF_type); 1.726 + NS_IF_RELEASE(mInner); 1.727 + 1.728 + return res; 1.729 +} 1.730 + 1.731 +/** 1.732 + * Free the resources no longer needed by the component. 1.733 + */ 1.734 +nsresult nsCharsetMenu::FreeResources() 1.735 +{ 1.736 + nsresult res = NS_OK; 1.737 + 1.738 + if (mCharsetMenuObserver) { 1.739 + mPrefs->RemoveObserver(kBrowserStaticPrefKey, mCharsetMenuObserver); 1.740 + mPrefs->RemoveObserver(kMaileditPrefKey, mCharsetMenuObserver); 1.741 + /* nsIObserverService has to have released nsCharsetMenu already */ 1.742 + } 1.743 + 1.744 + mRDFService = nullptr; 1.745 + mCCManager = nullptr; 1.746 + mPrefs = nullptr; 1.747 + 1.748 + return res; 1.749 +} 1.750 + 1.751 +nsresult nsCharsetMenu::InitMaileditMenu() 1.752 +{ 1.753 + nsresult res = NS_OK; 1.754 + 1.755 + if (!mMaileditMenuInitialized) { 1.756 + nsCOMPtr<nsIRDFContainer> container; 1.757 + res = NewRDFContainer(mInner, kNC_MaileditCharsetMenuRoot, getter_AddRefs(container)); 1.758 + if (NS_FAILED(res)) return res; 1.759 + 1.760 + //enumerate encoders 1.761 + // this would bring in a whole bunch of 'font encoders' as well as genuine 1.762 + // charset encoders, but it's safe because we rely on prefs to filter 1.763 + // them out. Moreover, 'customize' menu lists only genuine charset 1.764 + // encoders further guarding against 'font encoders' sneaking in. 1.765 + nsCOMPtr<nsIUTF8StringEnumerator> encoders; 1.766 + res = mCCManager->GetEncoderList(getter_AddRefs(encoders)); 1.767 + if (NS_FAILED(res)) return res; 1.768 + 1.769 + nsTArray<nsCString> maileditEncoderList; 1.770 + SetArrayFromEnumerator(encoders, maileditEncoderList); 1.771 + 1.772 + res = AddFromPrefsToMenu(nullptr, container, kMaileditPrefKey, 1.773 + maileditEncoderList, nullptr); 1.774 + NS_ASSERTION(NS_SUCCEEDED(res), "error initializing mailedit charset menu from prefs"); 1.775 + 1.776 + // register prefs callback 1.777 + mPrefs->AddObserver(kMaileditPrefKey, mCharsetMenuObserver, false); 1.778 + } 1.779 + 1.780 + mMaileditMenuInitialized = NS_SUCCEEDED(res); 1.781 + 1.782 + return res; 1.783 +} 1.784 + 1.785 +nsresult nsCharsetMenu::InitMailviewMenu() 1.786 +{ 1.787 + nsresult res = NS_OK; 1.788 + 1.789 + if (!mMailviewMenuInitialized) { 1.790 + nsCOMPtr<nsIRDFContainer> container; 1.791 + res = NewRDFContainer(mInner, kNC_MailviewCharsetMenuRoot, getter_AddRefs(container)); 1.792 + if (NS_FAILED(res)) return res; 1.793 + 1.794 + nsTArray<nsCString> mailviewDecoderList(mDecoderList); 1.795 + 1.796 + res = InitStaticMenu(mailviewDecoderList, kNC_MailviewCharsetMenuRoot, 1.797 + kMailviewStaticPrefKey, &mMailviewMenu); 1.798 + NS_ASSERTION(NS_SUCCEEDED(res), "error initializing mailview static charset menu"); 1.799 + 1.800 + // mark the end of the static area, the rest is cache 1.801 + mMailviewCacheStart = mMailviewMenu.Length(); 1.802 + mPrefs->GetIntPref(kMailviewCacheSizePrefKey, &mMailviewCacheSize); 1.803 + 1.804 + // compute the position of the menu in the RDF container 1.805 + res = container->GetCount(&mMailviewMenuRDFPosition); 1.806 + if (NS_FAILED(res)) return res; 1.807 + // this "1" here is a correction necessary because the RDF container 1.808 + // elements are numbered from 1 (why god, WHY?!?!?!) 1.809 + mMailviewMenuRDFPosition -= mMailviewCacheStart - 1; 1.810 + 1.811 + res = InitCacheMenu(mailviewDecoderList, kNC_MailviewCharsetMenuRoot, 1.812 + kMailviewCachePrefKey, &mMailviewMenu); 1.813 + NS_ASSERTION(NS_SUCCEEDED(res), "error initializing mailview cache charset menu"); 1.814 + } 1.815 + 1.816 + mMailviewMenuInitialized = NS_SUCCEEDED(res); 1.817 + 1.818 + return res; 1.819 +} 1.820 + 1.821 +nsresult nsCharsetMenu::InitComposerMenu() 1.822 +{ 1.823 + nsresult res = NS_OK; 1.824 + 1.825 + if (!mComposerMenuInitialized) { 1.826 + nsCOMPtr<nsIRDFContainer> container; 1.827 + res = NewRDFContainer(mInner, kNC_ComposerCharsetMenuRoot, getter_AddRefs(container)); 1.828 + if (NS_FAILED(res)) return res; 1.829 + 1.830 + nsTArray<nsCString> composerDecoderList(mDecoderList); 1.831 + 1.832 + // even if we fail, the show must go on 1.833 + res = InitStaticMenu(composerDecoderList, kNC_ComposerCharsetMenuRoot, 1.834 + kComposerStaticPrefKey, &mComposerMenu); 1.835 + NS_ASSERTION(NS_SUCCEEDED(res), "error initializing composer static charset menu"); 1.836 + 1.837 + // mark the end of the static area, the rest is cache 1.838 + mComposerCacheStart = mComposerMenu.Length(); 1.839 + mPrefs->GetIntPref(kComposerCacheSizePrefKey, &mComposerCacheSize); 1.840 + 1.841 + // compute the position of the menu in the RDF container 1.842 + res = container->GetCount(&mComposerMenuRDFPosition); 1.843 + if (NS_FAILED(res)) return res; 1.844 + // this "1" here is a correction necessary because the RDF container 1.845 + // elements are numbered from 1 (why god, WHY?!?!?!) 1.846 + mComposerMenuRDFPosition -= mComposerCacheStart - 1; 1.847 + 1.848 + res = InitCacheMenu(composerDecoderList, kNC_ComposerCharsetMenuRoot, 1.849 + kComposerCachePrefKey, &mComposerMenu); 1.850 + NS_ASSERTION(NS_SUCCEEDED(res), "error initializing composer cache charset menu"); 1.851 + } 1.852 + 1.853 + mComposerMenuInitialized = NS_SUCCEEDED(res); 1.854 + 1.855 + return res; 1.856 +} 1.857 + 1.858 +nsresult nsCharsetMenu::InitOthers() 1.859 +{ 1.860 + nsresult res = NS_OK; 1.861 + 1.862 + if (!mOthersInitialized) { 1.863 + nsTArray<nsCString> othersDecoderList(mDecoderList); 1.864 + 1.865 + res = InitMoreMenu(othersDecoderList, kNC_DecodersRoot, ".notForBrowser"); 1.866 + if (NS_FAILED(res)) return res; 1.867 + 1.868 + // Using mDecoderList instead of GetEncoderList(), we can avoid having to 1.869 + // tag a whole bunch of 'font encoders' with '.notForOutgoing' in 1.870 + // charsetData.properties file. 1.871 + nsTArray<nsCString> othersEncoderList(mDecoderList); 1.872 + 1.873 + res = InitMoreMenu(othersEncoderList, kNC_EncodersRoot, ".notForOutgoing"); 1.874 + if (NS_FAILED(res)) return res; 1.875 + } 1.876 + 1.877 + mOthersInitialized = NS_SUCCEEDED(res); 1.878 + 1.879 + return res; 1.880 +} 1.881 + 1.882 +/** 1.883 + * Inits the secondary tiers of the charset menu. Because currently all the CS 1.884 + * menus are sharing the secondary tiers, one should call this method only 1.885 + * once for all of them. 1.886 + */ 1.887 +nsresult nsCharsetMenu::InitSecondaryTiers() 1.888 +{ 1.889 + nsresult res = NS_OK; 1.890 + 1.891 + if (!mSecondaryTiersInitialized) { 1.892 + nsTArray<nsCString> secondaryTiersDecoderList(mDecoderList); 1.893 + 1.894 + res = InitMoreSubmenus(secondaryTiersDecoderList); 1.895 + NS_ASSERTION(NS_SUCCEEDED(res), "err init browser charset more submenus"); 1.896 + 1.897 + res = InitMoreMenu(secondaryTiersDecoderList, kNC_BrowserMoreCharsetMenuRoot, ".notForBrowser"); 1.898 + NS_ASSERTION(NS_SUCCEEDED(res), "err init browser charset more menu"); 1.899 + } 1.900 + 1.901 + mSecondaryTiersInitialized = NS_SUCCEEDED(res); 1.902 + 1.903 + return res; 1.904 +} 1.905 + 1.906 +nsresult nsCharsetMenu::InitStaticMenu(nsTArray<nsCString>& aDecs, 1.907 + nsIRDFResource * aResource, 1.908 + const char * aKey, 1.909 + nsTArray<nsMenuEntry*> * aArray) 1.910 +{ 1.911 + nsresult res = NS_OK; 1.912 + nsCOMPtr<nsIRDFContainer> container; 1.913 + 1.914 + res = NewRDFContainer(mInner, aResource, getter_AddRefs(container)); 1.915 + if (NS_FAILED(res)) return res; 1.916 + 1.917 + // XXX work around bug that causes the submenus to be first instead of last 1.918 + res = AddSeparatorToContainer(container); 1.919 + NS_ASSERTION(NS_SUCCEEDED(res), "error adding separator to container"); 1.920 + 1.921 + res = AddFromPrefsToMenu(aArray, container, aKey, aDecs, "charset."); 1.922 + NS_ASSERTION(NS_SUCCEEDED(res), "error initializing static charset menu from prefs"); 1.923 + 1.924 + return res; 1.925 +} 1.926 + 1.927 +nsresult nsCharsetMenu::InitCacheMenu( 1.928 + nsTArray<nsCString>& aDecs, 1.929 + nsIRDFResource * aResource, 1.930 + const char * aKey, 1.931 + nsTArray<nsMenuEntry*> * aArray) 1.932 +{ 1.933 + nsresult res = NS_OK; 1.934 + nsCOMPtr<nsIRDFContainer> container; 1.935 + 1.936 + res = NewRDFContainer(mInner, aResource, getter_AddRefs(container)); 1.937 + if (NS_FAILED(res)) return res; 1.938 + 1.939 + res = AddFromNolocPrefsToMenu(aArray, container, aKey, aDecs, "charset."); 1.940 + NS_ASSERTION(NS_SUCCEEDED(res), "error initializing cache charset menu from prefs"); 1.941 + 1.942 + return res; 1.943 +} 1.944 + 1.945 +nsresult nsCharsetMenu::InitAutodetMenu() 1.946 +{ 1.947 + nsresult res = NS_OK; 1.948 + 1.949 + if (!mAutoDetectInitialized) { 1.950 + nsTArray<nsMenuEntry*> chardetArray; 1.951 + nsCOMPtr<nsIRDFContainer> container; 1.952 + nsTArray<nsCString> detectorArray; 1.953 + 1.954 + res = NewRDFContainer(mInner, kNC_BrowserAutodetMenuRoot, getter_AddRefs(container)); 1.955 + if (NS_FAILED(res)) return res; 1.956 + 1.957 + nsCOMPtr<nsIUTF8StringEnumerator> detectors; 1.958 + res = mCCManager->GetCharsetDetectorList(getter_AddRefs(detectors)); 1.959 + if (NS_FAILED(res)) goto done; 1.960 + 1.961 + res = SetArrayFromEnumerator(detectors, detectorArray); 1.962 + if (NS_FAILED(res)) goto done; 1.963 + 1.964 + res = AddCharsetArrayToItemArray(chardetArray, detectorArray); 1.965 + if (NS_FAILED(res)) goto done; 1.966 + 1.967 + // reorder the array 1.968 + res = ReorderMenuItemArray(&chardetArray); 1.969 + if (NS_FAILED(res)) goto done; 1.970 + 1.971 + res = AddMenuItemArrayToContainer(container, &chardetArray, 1.972 + kNC_CharsetDetector); 1.973 + if (NS_FAILED(res)) goto done; 1.974 + 1.975 + done: 1.976 + // free the elements in the nsTArray<nsMenuEntry*> 1.977 + FreeMenuItemArray(&chardetArray); 1.978 + } 1.979 + 1.980 + mAutoDetectInitialized = NS_SUCCEEDED(res); 1.981 + 1.982 + return res; 1.983 +} 1.984 + 1.985 +nsresult nsCharsetMenu::InitMoreMenu(nsTArray<nsCString>& aDecs, 1.986 + nsIRDFResource * aResource, 1.987 + const char * aFlag) 1.988 +{ 1.989 + nsresult res = NS_OK; 1.990 + nsCOMPtr<nsIRDFContainer> container; 1.991 + nsTArray<nsMenuEntry*> moreMenu; 1.992 + 1.993 + res = NewRDFContainer(mInner, aResource, getter_AddRefs(container)); 1.994 + if (NS_FAILED(res)) goto done; 1.995 + 1.996 + // remove charsets "not for browser" 1.997 + res = RemoveFlaggedCharsets(aDecs, NS_ConvertASCIItoUTF16(aFlag)); 1.998 + if (NS_FAILED(res)) goto done; 1.999 + 1.1000 + res = AddCharsetArrayToItemArray(moreMenu, aDecs); 1.1001 + if (NS_FAILED(res)) goto done; 1.1002 + 1.1003 + // reorder the array 1.1004 + res = ReorderMenuItemArray(&moreMenu); 1.1005 + if (NS_FAILED(res)) goto done; 1.1006 + 1.1007 + res = AddMenuItemArrayToContainer(container, &moreMenu, nullptr); 1.1008 + if (NS_FAILED(res)) goto done; 1.1009 + 1.1010 +done: 1.1011 + // free the elements in the nsTArray<nsMenuEntry*> 1.1012 + FreeMenuItemArray(&moreMenu); 1.1013 + 1.1014 + return res; 1.1015 +} 1.1016 + 1.1017 +// XXX please make this method more general; the cut&pasted code is laughable 1.1018 +nsresult nsCharsetMenu::InitMoreSubmenus(nsTArray<nsCString>& aDecs) 1.1019 +{ 1.1020 + nsresult res = NS_OK; 1.1021 + 1.1022 + nsCOMPtr<nsIRDFContainer> container1; 1.1023 + nsCOMPtr<nsIRDFContainer> container2; 1.1024 + nsCOMPtr<nsIRDFContainer> container3; 1.1025 + nsCOMPtr<nsIRDFContainer> container4; 1.1026 + nsCOMPtr<nsIRDFContainer> container5; 1.1027 + const char key1[] = "intl.charsetmenu.browser.more1"; 1.1028 + const char key2[] = "intl.charsetmenu.browser.more2"; 1.1029 + const char key3[] = "intl.charsetmenu.browser.more3"; 1.1030 + const char key4[] = "intl.charsetmenu.browser.more4"; 1.1031 + const char key5[] = "intl.charsetmenu.browser.more5"; 1.1032 + 1.1033 + res = NewRDFContainer(mInner, kNC_BrowserMore1CharsetMenuRoot, 1.1034 + getter_AddRefs(container1)); 1.1035 + if (NS_FAILED(res)) return res; 1.1036 + AddFromNolocPrefsToMenu(nullptr, container1, key1, aDecs, nullptr); 1.1037 + 1.1038 + res = NewRDFContainer(mInner, kNC_BrowserMore2CharsetMenuRoot, 1.1039 + getter_AddRefs(container2)); 1.1040 + if (NS_FAILED(res)) return res; 1.1041 + AddFromNolocPrefsToMenu(nullptr, container2, key2, aDecs, nullptr); 1.1042 + 1.1043 + res = NewRDFContainer(mInner, kNC_BrowserMore3CharsetMenuRoot, 1.1044 + getter_AddRefs(container3)); 1.1045 + if (NS_FAILED(res)) return res; 1.1046 + AddFromNolocPrefsToMenu(nullptr, container3, key3, aDecs, nullptr); 1.1047 + 1.1048 + res = NewRDFContainer(mInner, kNC_BrowserMore4CharsetMenuRoot, 1.1049 + getter_AddRefs(container4)); 1.1050 + if (NS_FAILED(res)) return res; 1.1051 + AddFromNolocPrefsToMenu(nullptr, container4, key4, aDecs, nullptr); 1.1052 + 1.1053 + res = NewRDFContainer(mInner, kNC_BrowserMore5CharsetMenuRoot, 1.1054 + getter_AddRefs(container5)); 1.1055 + if (NS_FAILED(res)) return res; 1.1056 + AddFromNolocPrefsToMenu(nullptr, container5, key5, aDecs, nullptr); 1.1057 + 1.1058 + return res; 1.1059 +} 1.1060 + 1.1061 +nsresult nsCharsetMenu::AddCharsetToItemArray(nsTArray<nsMenuEntry*> *aArray, 1.1062 + const nsAFlatCString& aCharset, 1.1063 + nsMenuEntry ** aResult, 1.1064 + int32_t aPlace) 1.1065 +{ 1.1066 + nsresult res = NS_OK; 1.1067 + nsMenuEntry * item = nullptr; 1.1068 + 1.1069 + if (aResult != nullptr) *aResult = nullptr; 1.1070 + 1.1071 + item = new nsMenuEntry(); 1.1072 + if (item == nullptr) { 1.1073 + res = NS_ERROR_OUT_OF_MEMORY; 1.1074 + goto done; 1.1075 + } 1.1076 + 1.1077 + item->mCharset = aCharset; 1.1078 + 1.1079 + if (NS_FAILED(mCCManager->GetCharsetTitle(aCharset.get(), item->mTitle))) { 1.1080 + item->mTitle.AssignWithConversion(aCharset.get()); 1.1081 + } 1.1082 + 1.1083 + if (aArray != nullptr) { 1.1084 + if (aPlace < 0) { 1.1085 + aArray->AppendElement(item); 1.1086 + } else { 1.1087 + aArray->InsertElementsAt(aPlace, 1, item); 1.1088 + } 1.1089 + } 1.1090 + 1.1091 + if (aResult != nullptr) *aResult = item; 1.1092 + 1.1093 + // if we have made another reference to "item", do not delete it 1.1094 + if ((aArray != nullptr) || (aResult != nullptr)) item = nullptr; 1.1095 + 1.1096 +done: 1.1097 + if (item != nullptr) delete item; 1.1098 + 1.1099 + return res; 1.1100 +} 1.1101 + 1.1102 +nsresult 1.1103 +nsCharsetMenu::AddCharsetArrayToItemArray(nsTArray<nsMenuEntry*>& aArray, 1.1104 + const nsTArray<nsCString>& aCharsets) 1.1105 +{ 1.1106 + uint32_t count = aCharsets.Length(); 1.1107 + 1.1108 + for (uint32_t i = 0; i < count; i++) { 1.1109 + 1.1110 + const nsCString& str = aCharsets[i]; 1.1111 + nsresult res = AddCharsetToItemArray(&aArray, str, nullptr, -1); 1.1112 + 1.1113 + if (NS_FAILED(res)) 1.1114 + return res; 1.1115 + } 1.1116 + 1.1117 + return NS_OK; 1.1118 +} 1.1119 + 1.1120 +// aPlace < -1 for Remove 1.1121 +// aPlace < 0 for Append 1.1122 +nsresult nsCharsetMenu::AddMenuItemToContainer( 1.1123 + nsIRDFContainer * aContainer, 1.1124 + nsMenuEntry * aItem, 1.1125 + nsIRDFResource * aType, 1.1126 + const char * aIDPrefix, 1.1127 + int32_t aPlace) 1.1128 +{ 1.1129 + nsresult res = NS_OK; 1.1130 + nsCOMPtr<nsIRDFResource> node; 1.1131 + 1.1132 + nsAutoCString id; 1.1133 + if (aIDPrefix != nullptr) id.Assign(aIDPrefix); 1.1134 + id.Append(aItem->mCharset); 1.1135 + 1.1136 + // Make up a unique ID and create the RDF NODE 1.1137 + res = mRDFService->GetResource(id, getter_AddRefs(node)); 1.1138 + if (NS_FAILED(res)) return res; 1.1139 + 1.1140 + const char16_t * title = aItem->mTitle.get(); 1.1141 + 1.1142 + // set node's title 1.1143 + nsCOMPtr<nsIRDFLiteral> titleLiteral; 1.1144 + res = mRDFService->GetLiteral(title, getter_AddRefs(titleLiteral)); 1.1145 + if (NS_FAILED(res)) return res; 1.1146 + 1.1147 + if (aPlace < -1) { 1.1148 + res = Unassert(node, kNC_Name, titleLiteral); 1.1149 + if (NS_FAILED(res)) return res; 1.1150 + } else { 1.1151 + res = Assert(node, kNC_Name, titleLiteral, true); 1.1152 + if (NS_FAILED(res)) return res; 1.1153 + } 1.1154 + 1.1155 + if (aType != nullptr) { 1.1156 + if (aPlace < -1) { 1.1157 + res = Unassert(node, kRDF_type, aType); 1.1158 + if (NS_FAILED(res)) return res; 1.1159 + } else { 1.1160 + res = Assert(node, kRDF_type, aType, true); 1.1161 + if (NS_FAILED(res)) return res; 1.1162 + } 1.1163 + } 1.1164 + 1.1165 + // Add the element to the container 1.1166 + if (aPlace < -1) { 1.1167 + res = aContainer->RemoveElement(node, true); 1.1168 + if (NS_FAILED(res)) return res; 1.1169 + } else if (aPlace < 0) { 1.1170 + res = aContainer->AppendElement(node); 1.1171 + if (NS_FAILED(res)) return res; 1.1172 + } else { 1.1173 + res = aContainer->InsertElementAt(node, aPlace, true); 1.1174 + if (NS_FAILED(res)) return res; 1.1175 + } 1.1176 + 1.1177 + return res; 1.1178 +} 1.1179 + 1.1180 +nsresult nsCharsetMenu::AddMenuItemArrayToContainer( 1.1181 + nsIRDFContainer * aContainer, 1.1182 + nsTArray<nsMenuEntry*> * aArray, 1.1183 + nsIRDFResource * aType) 1.1184 +{ 1.1185 + uint32_t count = aArray->Length(); 1.1186 + nsresult res = NS_OK; 1.1187 + 1.1188 + for (uint32_t i = 0; i < count; i++) { 1.1189 + nsMenuEntry * item = aArray->ElementAt(i); 1.1190 + if (item == nullptr) return NS_ERROR_UNEXPECTED; 1.1191 + 1.1192 + res = AddMenuItemToContainer(aContainer, item, aType, nullptr, -1); 1.1193 + if (NS_FAILED(res)) return res; 1.1194 + } 1.1195 + 1.1196 + return NS_OK; 1.1197 +} 1.1198 + 1.1199 +nsresult nsCharsetMenu::AddCharsetToContainer(nsTArray<nsMenuEntry*> *aArray, 1.1200 + nsIRDFContainer * aContainer, 1.1201 + const nsAFlatCString& aCharset, 1.1202 + const char * aIDPrefix, 1.1203 + int32_t aPlace, 1.1204 + int32_t aRDFPlace) 1.1205 +{ 1.1206 + nsresult res = NS_OK; 1.1207 + nsMenuEntry * item = nullptr; 1.1208 + 1.1209 + res = AddCharsetToItemArray(aArray, aCharset, &item, aPlace); 1.1210 + if (NS_FAILED(res)) goto done; 1.1211 + 1.1212 + res = AddMenuItemToContainer(aContainer, item, nullptr, aIDPrefix, 1.1213 + aPlace + aRDFPlace); 1.1214 + if (NS_FAILED(res)) goto done; 1.1215 + 1.1216 + // if we have made another reference to "item", do not delete it 1.1217 + if (aArray != nullptr) item = nullptr; 1.1218 + 1.1219 +done: 1.1220 + if (item != nullptr) delete item; 1.1221 + 1.1222 + return res; 1.1223 +} 1.1224 + 1.1225 +nsresult nsCharsetMenu::AddFromPrefsToMenu( 1.1226 + nsTArray<nsMenuEntry*> * aArray, 1.1227 + nsIRDFContainer * aContainer, 1.1228 + const char * aKey, 1.1229 + nsTArray<nsCString>& aDecs, 1.1230 + const char * aIDPrefix) 1.1231 +{ 1.1232 + nsresult res = NS_OK; 1.1233 + 1.1234 + nsCOMPtr<nsIPrefLocalizedString> pls; 1.1235 + res = mPrefs->GetComplexValue(aKey, NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(pls)); 1.1236 + if (NS_FAILED(res)) return res; 1.1237 + 1.1238 + if (pls) { 1.1239 + nsXPIDLString ucsval; 1.1240 + pls->ToString(getter_Copies(ucsval)); 1.1241 + NS_ConvertUTF16toUTF8 utf8val(ucsval); 1.1242 + if (ucsval) 1.1243 + res = AddFromStringToMenu(utf8val.BeginWriting(), aArray, 1.1244 + aContainer, aDecs, aIDPrefix); 1.1245 + } 1.1246 + 1.1247 + return res; 1.1248 +} 1.1249 + 1.1250 +nsresult 1.1251 +nsCharsetMenu::AddFromNolocPrefsToMenu(nsTArray<nsMenuEntry*> * aArray, 1.1252 + nsIRDFContainer * aContainer, 1.1253 + const char * aKey, 1.1254 + nsTArray<nsCString>& aDecs, 1.1255 + const char * aIDPrefix) 1.1256 +{ 1.1257 + nsresult res = NS_OK; 1.1258 + 1.1259 + char * value = nullptr; 1.1260 + res = mPrefs->GetCharPref(aKey, &value); 1.1261 + if (NS_FAILED(res)) return res; 1.1262 + 1.1263 + if (value != nullptr) { 1.1264 + res = AddFromStringToMenu(value, aArray, aContainer, aDecs, aIDPrefix); 1.1265 + nsMemory::Free(value); 1.1266 + } 1.1267 + 1.1268 + return res; 1.1269 +} 1.1270 + 1.1271 +nsresult nsCharsetMenu::AddFromStringToMenu( 1.1272 + char * aCharsetList, 1.1273 + nsTArray<nsMenuEntry*> * aArray, 1.1274 + nsIRDFContainer * aContainer, 1.1275 + nsTArray<nsCString>& aDecs, 1.1276 + const char * aIDPrefix) 1.1277 +{ 1.1278 + nsresult res = NS_OK; 1.1279 + char * p = aCharsetList; 1.1280 + char * q = p; 1.1281 + while (*p != 0) { 1.1282 + for (; (*q != ',') && (*q != ' ') && (*q != 0); q++) {;} 1.1283 + char temp = *q; 1.1284 + *q = 0; 1.1285 + 1.1286 + // if this charset is not on the accepted list of charsets, ignore it 1.1287 + int32_t index; 1.1288 + index = aDecs.IndexOf(nsAutoCString(p), 0, nsIgnoreCaseCStringComparator()); 1.1289 + if (index >= 0) { 1.1290 + 1.1291 + // else, add it to the menu 1.1292 + res = AddCharsetToContainer(aArray, aContainer, nsDependentCString(p), 1.1293 + aIDPrefix, -1, 0); 1.1294 + NS_ASSERTION(NS_SUCCEEDED(res), "cannot add charset to menu"); 1.1295 + if (NS_FAILED(res)) break; 1.1296 + 1.1297 + aDecs.RemoveElementAt(index); 1.1298 + } 1.1299 + 1.1300 + *q = temp; 1.1301 + for (; (*q == ',') || (*q == ' '); q++) {;} 1.1302 + p=q; 1.1303 + } 1.1304 + 1.1305 + return NS_OK; 1.1306 +} 1.1307 + 1.1308 +nsresult nsCharsetMenu::AddSeparatorToContainer(nsIRDFContainer * aContainer) 1.1309 +{ 1.1310 + nsAutoCString str; 1.1311 + str.AssignLiteral("----"); 1.1312 + 1.1313 + // hack to generate unique id's for separators 1.1314 + static int32_t u = 0; 1.1315 + u++; 1.1316 + str.AppendInt(u); 1.1317 + 1.1318 + nsMenuEntry item; 1.1319 + item.mCharset = str; 1.1320 + item.mTitle.AssignWithConversion(str.get()); 1.1321 + 1.1322 + return AddMenuItemToContainer(aContainer, &item, kNC_BookmarkSeparator, 1.1323 + nullptr, -1); 1.1324 +} 1.1325 + 1.1326 +nsresult 1.1327 +nsCharsetMenu::AddCharsetToCache(const nsAFlatCString& aCharset, 1.1328 + nsTArray<nsMenuEntry*> * aArray, 1.1329 + nsIRDFResource * aRDFResource, 1.1330 + uint32_t aCacheStart, 1.1331 + uint32_t aCacheSize, 1.1332 + int32_t aRDFPlace) 1.1333 +{ 1.1334 + int32_t i; 1.1335 + nsresult res = NS_OK; 1.1336 + 1.1337 + i = FindMenuItemInArray(aArray, aCharset, nullptr); 1.1338 + if (i >= 0) return res; 1.1339 + 1.1340 + nsCOMPtr<nsIRDFContainer> container; 1.1341 + res = NewRDFContainer(mInner, aRDFResource, getter_AddRefs(container)); 1.1342 + if (NS_FAILED(res)) return res; 1.1343 + 1.1344 + // if too many items, remove last one 1.1345 + if (aArray->Length() - aCacheStart >= aCacheSize){ 1.1346 + res = RemoveLastMenuItem(container, aArray); 1.1347 + if (NS_FAILED(res)) return res; 1.1348 + } 1.1349 + 1.1350 + res = AddCharsetToContainer(aArray, container, aCharset, "charset.", 1.1351 + aCacheStart, aRDFPlace); 1.1352 + 1.1353 + return res; 1.1354 +} 1.1355 + 1.1356 +nsresult nsCharsetMenu::WriteCacheToPrefs(nsTArray<nsMenuEntry*> * aArray, 1.1357 + int32_t aCacheStart, 1.1358 + const char * aKey) 1.1359 +{ 1.1360 + nsresult res = NS_OK; 1.1361 + 1.1362 + // create together the cache string 1.1363 + nsAutoCString cache; 1.1364 + nsAutoCString sep(NS_LITERAL_CSTRING(", ")); 1.1365 + uint32_t count = aArray->Length(); 1.1366 + 1.1367 + for (uint32_t i = aCacheStart; i < count; i++) { 1.1368 + nsMenuEntry * item = aArray->ElementAt(i); 1.1369 + if (item != nullptr) { 1.1370 + cache.Append(item->mCharset); 1.1371 + if (i < count - 1) { 1.1372 + cache.Append(sep); 1.1373 + } 1.1374 + } 1.1375 + } 1.1376 + 1.1377 + // write the pref 1.1378 + res = mPrefs->SetCharPref(aKey, cache.get()); 1.1379 + 1.1380 + return res; 1.1381 +} 1.1382 + 1.1383 +nsresult nsCharsetMenu::UpdateCachePrefs(const char * aCacheKey, 1.1384 + const char * aCacheSizeKey, 1.1385 + const char * aStaticKey, 1.1386 + const char16_t * aCharset) 1.1387 +{ 1.1388 + nsresult rv = NS_OK; 1.1389 + nsXPIDLCString cachePrefValue; 1.1390 + nsXPIDLCString staticPrefValue; 1.1391 + NS_LossyConvertUTF16toASCII currentCharset(aCharset); 1.1392 + int32_t cacheSize = 0; 1.1393 + 1.1394 + mPrefs->GetCharPref(aCacheKey, getter_Copies(cachePrefValue)); 1.1395 + mPrefs->GetCharPref(aStaticKey, getter_Copies(staticPrefValue)); 1.1396 + rv = mPrefs->GetIntPref(aCacheSizeKey, &cacheSize); 1.1397 + 1.1398 + if (NS_FAILED(rv) || cacheSize <= 0) 1.1399 + return NS_ERROR_UNEXPECTED; 1.1400 + 1.1401 + if ((cachePrefValue.Find(currentCharset) == kNotFound) && 1.1402 + (staticPrefValue.Find(currentCharset) == kNotFound)) { 1.1403 + 1.1404 + if (!cachePrefValue.IsEmpty()) 1.1405 + cachePrefValue.Insert(", ", 0); 1.1406 + 1.1407 + cachePrefValue.Insert(currentCharset, 0); 1.1408 + if (cacheSize < (int32_t) cachePrefValue.CountChar(',') + 1) 1.1409 + cachePrefValue.Truncate(cachePrefValue.RFindChar(',')); 1.1410 + 1.1411 + rv = mPrefs->SetCharPref(aCacheKey, cachePrefValue); 1.1412 + } 1.1413 + 1.1414 + return rv; 1.1415 +} 1.1416 + 1.1417 +nsresult nsCharsetMenu::ClearMenu(nsIRDFContainer * aContainer, 1.1418 + nsTArray<nsMenuEntry*> * aArray) 1.1419 +{ 1.1420 + nsresult res = NS_OK; 1.1421 + 1.1422 + // clean the RDF data source 1.1423 + uint32_t count = aArray->Length(); 1.1424 + for (uint32_t i = 0; i < count; i++) { 1.1425 + nsMenuEntry * item = aArray->ElementAt(i); 1.1426 + if (item != nullptr) { 1.1427 + res = AddMenuItemToContainer(aContainer, item, nullptr, "charset.", -2); 1.1428 + if (NS_FAILED(res)) return res; 1.1429 + } 1.1430 + } 1.1431 + 1.1432 + // clean the internal data structures 1.1433 + FreeMenuItemArray(aArray); 1.1434 + 1.1435 + return res; 1.1436 +} 1.1437 + 1.1438 +nsresult nsCharsetMenu::RemoveLastMenuItem(nsIRDFContainer * aContainer, 1.1439 + nsTArray<nsMenuEntry*> * aArray) 1.1440 +{ 1.1441 + nsresult res = NS_OK; 1.1442 + 1.1443 + int32_t last = aArray->Length() - 1; 1.1444 + if (last >= 0) { 1.1445 + nsMenuEntry * item = aArray->ElementAt(last); 1.1446 + if (item != nullptr) { 1.1447 + res = AddMenuItemToContainer(aContainer, item, nullptr, "charset.", -2); 1.1448 + if (NS_FAILED(res)) return res; 1.1449 + 1.1450 + aArray->RemoveElementAt(last); 1.1451 + } 1.1452 + } 1.1453 + 1.1454 + return res; 1.1455 +} 1.1456 + 1.1457 +nsresult nsCharsetMenu::RemoveFlaggedCharsets(nsTArray<nsCString>& aList, 1.1458 + const nsString& aProp) 1.1459 +{ 1.1460 + nsresult res = NS_OK; 1.1461 + uint32_t count; 1.1462 + 1.1463 + count = aList.Length(); 1.1464 + if (NS_FAILED(res)) return res; 1.1465 + 1.1466 + nsAutoString str; 1.1467 + for (uint32_t i = 0; i < count; i++) { 1.1468 + 1.1469 + res = mCCManager->GetCharsetData(aList[i].get(), aProp.get(), str); 1.1470 + if (NS_FAILED(res)) continue; 1.1471 + 1.1472 + aList.RemoveElementAt(i); 1.1473 + 1.1474 + i--; 1.1475 + count--; 1.1476 + } 1.1477 + 1.1478 + return NS_OK; 1.1479 +} 1.1480 + 1.1481 +nsresult nsCharsetMenu::NewRDFContainer(nsIRDFDataSource * aDataSource, 1.1482 + nsIRDFResource * aResource, 1.1483 + nsIRDFContainer ** aResult) 1.1484 +{ 1.1485 + nsresult res = CallCreateInstance(kRDFContainerCID, aResult); 1.1486 + if (NS_FAILED(res)) return res; 1.1487 + 1.1488 + res = (*aResult)->Init(aDataSource, aResource); 1.1489 + if (NS_FAILED(res)) NS_RELEASE(*aResult); 1.1490 + 1.1491 + return res; 1.1492 +} 1.1493 + 1.1494 +void nsCharsetMenu::FreeMenuItemArray(nsTArray<nsMenuEntry*> * aArray) 1.1495 +{ 1.1496 + uint32_t count = aArray->Length(); 1.1497 + for (uint32_t i = 0; i < count; i++) { 1.1498 + nsMenuEntry * item = aArray->ElementAt(i); 1.1499 + if (item != nullptr) { 1.1500 + delete item; 1.1501 + } 1.1502 + } 1.1503 + aArray->Clear(); 1.1504 +} 1.1505 + 1.1506 +int32_t nsCharsetMenu::FindMenuItemInArray(const nsTArray<nsMenuEntry*>* aArray, 1.1507 + const nsAFlatCString& aCharset, 1.1508 + nsMenuEntry ** aResult) 1.1509 +{ 1.1510 + uint32_t count = aArray->Length(); 1.1511 + 1.1512 + for (uint32_t i=0; i < count; i++) { 1.1513 + nsMenuEntry * item = aArray->ElementAt(i); 1.1514 + if (item->mCharset == aCharset) { 1.1515 + if (aResult != nullptr) *aResult = item; 1.1516 + return i; 1.1517 + } 1.1518 + } 1.1519 + 1.1520 + if (aResult != nullptr) *aResult = nullptr; 1.1521 + return -1; 1.1522 +} 1.1523 + 1.1524 +nsresult nsCharsetMenu::ReorderMenuItemArray(nsTArray<nsMenuEntry*> * aArray) 1.1525 +{ 1.1526 + nsresult res = NS_OK; 1.1527 + nsCOMPtr<nsICollation> collation; 1.1528 + uint32_t count = aArray->Length(); 1.1529 + uint32_t i; 1.1530 + 1.1531 + // we need to use a temporary array 1.1532 + charsetMenuSortRecord *array = new charsetMenuSortRecord [count]; 1.1533 + NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY); 1.1534 + for (i = 0; i < count; i++) 1.1535 + array[i].key = nullptr; 1.1536 + 1.1537 + res = GetCollation(getter_AddRefs(collation)); 1.1538 + if (NS_FAILED(res)) 1.1539 + goto done; 1.1540 + 1.1541 + for (i = 0; i < count && NS_SUCCEEDED(res); i++) { 1.1542 + array[i].item = aArray->ElementAt(i); 1.1543 + 1.1544 + res = collation->AllocateRawSortKey(nsICollation::kCollationCaseInSensitive, 1.1545 + (array[i].item)->mTitle, &array[i].key, &array[i].len); 1.1546 + } 1.1547 + 1.1548 + // reorder the array 1.1549 + if (NS_SUCCEEDED(res)) { 1.1550 + NS_QuickSort(array, count, sizeof(*array), CompareMenuItems, collation); 1.1551 + 1.1552 + // move the elements from the temporary array into the the real one 1.1553 + aArray->Clear(); 1.1554 + for (i = 0; i < count; i++) { 1.1555 + aArray->AppendElement(array[i].item); 1.1556 + } 1.1557 + } 1.1558 + 1.1559 +done: 1.1560 + for (i = 0; i < count; i++) { 1.1561 + PR_FREEIF(array[i].key); 1.1562 + } 1.1563 + delete [] array; 1.1564 + return res; 1.1565 +} 1.1566 + 1.1567 +nsresult nsCharsetMenu::GetCollation(nsICollation ** aCollation) 1.1568 +{ 1.1569 + nsresult res = NS_OK; 1.1570 + nsCOMPtr<nsILocale> locale = nullptr; 1.1571 + nsICollationFactory * collationFactory = nullptr; 1.1572 + 1.1573 + nsCOMPtr<nsILocaleService> localeServ = 1.1574 + do_GetService(NS_LOCALESERVICE_CONTRACTID, &res); 1.1575 + if (NS_FAILED(res)) return res; 1.1576 + 1.1577 + res = localeServ->GetApplicationLocale(getter_AddRefs(locale)); 1.1578 + if (NS_FAILED(res)) return res; 1.1579 + 1.1580 + res = CallCreateInstance(NS_COLLATIONFACTORY_CONTRACTID, &collationFactory); 1.1581 + if (NS_FAILED(res)) return res; 1.1582 + 1.1583 + res = collationFactory->CreateCollation(locale, aCollation); 1.1584 + NS_RELEASE(collationFactory); 1.1585 + return res; 1.1586 +} 1.1587 + 1.1588 +//---------------------------------------------------------------------------- 1.1589 +// Interface nsICurrentCharsetListener [implementation] 1.1590 + 1.1591 +NS_IMETHODIMP nsCharsetMenu::SetCurrentCharset(const char16_t * aCharset) 1.1592 +{ 1.1593 + return NS_OK; 1.1594 +} 1.1595 + 1.1596 +NS_IMETHODIMP nsCharsetMenu::SetCurrentMailCharset(const char16_t * aCharset) 1.1597 +{ 1.1598 + nsresult res = NS_OK; 1.1599 + 1.1600 + if (mMailviewMenuInitialized) { 1.1601 + res = AddCharsetToCache(NS_LossyConvertUTF16toASCII(aCharset), 1.1602 + &mMailviewMenu, kNC_MailviewCharsetMenuRoot, 1.1603 + mMailviewCacheStart, mMailviewCacheSize, 1.1604 + mMailviewMenuRDFPosition); 1.1605 + if (NS_FAILED(res)) return res; 1.1606 + 1.1607 + res = WriteCacheToPrefs(&mMailviewMenu, mMailviewCacheStart, 1.1608 + kMailviewCachePrefKey); 1.1609 + } else { 1.1610 + res = UpdateCachePrefs(kMailviewCachePrefKey, kMailviewCacheSizePrefKey, 1.1611 + kMailviewStaticPrefKey, aCharset); 1.1612 + } 1.1613 + return res; 1.1614 +} 1.1615 + 1.1616 +NS_IMETHODIMP nsCharsetMenu::SetCurrentComposerCharset(const char16_t * aCharset) 1.1617 +{ 1.1618 + nsresult res = NS_OK; 1.1619 + 1.1620 + if (mComposerMenuInitialized) { 1.1621 + 1.1622 + res = AddCharsetToCache(NS_LossyConvertUTF16toASCII(aCharset), 1.1623 + &mComposerMenu, kNC_ComposerCharsetMenuRoot, 1.1624 + mComposerCacheStart, mComposerCacheSize, 1.1625 + mComposerMenuRDFPosition); 1.1626 + if (NS_FAILED(res)) return res; 1.1627 + 1.1628 + res = WriteCacheToPrefs(&mComposerMenu, mComposerCacheStart, 1.1629 + kComposerCachePrefKey); 1.1630 + } else { 1.1631 + res = UpdateCachePrefs(kComposerCachePrefKey, kComposerCacheSizePrefKey, 1.1632 + kComposerStaticPrefKey, aCharset); 1.1633 + } 1.1634 + return res; 1.1635 +} 1.1636 + 1.1637 +//---------------------------------------------------------------------------- 1.1638 +// Interface nsIRDFDataSource [implementation] 1.1639 + 1.1640 +NS_IMETHODIMP nsCharsetMenu::GetURI(char ** uri) 1.1641 +{ 1.1642 + if (!uri) return NS_ERROR_NULL_POINTER; 1.1643 + 1.1644 + *uri = NS_strdup("rdf:charset-menu"); 1.1645 + if (!(*uri)) return NS_ERROR_OUT_OF_MEMORY; 1.1646 + 1.1647 + return NS_OK; 1.1648 +} 1.1649 + 1.1650 +NS_IMETHODIMP nsCharsetMenu::GetSource(nsIRDFResource* property, 1.1651 + nsIRDFNode* target, 1.1652 + bool tv, 1.1653 + nsIRDFResource** source) 1.1654 +{ 1.1655 + return mInner->GetSource(property, target, tv, source); 1.1656 +} 1.1657 + 1.1658 +NS_IMETHODIMP nsCharsetMenu::GetSources(nsIRDFResource* property, 1.1659 + nsIRDFNode* target, 1.1660 + bool tv, 1.1661 + nsISimpleEnumerator** sources) 1.1662 +{ 1.1663 + return mInner->GetSources(property, target, tv, sources); 1.1664 +} 1.1665 + 1.1666 +NS_IMETHODIMP nsCharsetMenu::GetTarget(nsIRDFResource* source, 1.1667 + nsIRDFResource* property, 1.1668 + bool tv, 1.1669 + nsIRDFNode** target) 1.1670 +{ 1.1671 + return mInner->GetTarget(source, property, tv, target); 1.1672 +} 1.1673 + 1.1674 +NS_IMETHODIMP nsCharsetMenu::GetTargets(nsIRDFResource* source, 1.1675 + nsIRDFResource* property, 1.1676 + bool tv, 1.1677 + nsISimpleEnumerator** targets) 1.1678 +{ 1.1679 + return mInner->GetTargets(source, property, tv, targets); 1.1680 +} 1.1681 + 1.1682 +NS_IMETHODIMP nsCharsetMenu::Assert(nsIRDFResource* aSource, 1.1683 + nsIRDFResource* aProperty, 1.1684 + nsIRDFNode* aTarget, 1.1685 + bool aTruthValue) 1.1686 +{ 1.1687 + // TODO: filter out asserts we don't care about 1.1688 + return mInner->Assert(aSource, aProperty, aTarget, aTruthValue); 1.1689 +} 1.1690 + 1.1691 +NS_IMETHODIMP nsCharsetMenu::Unassert(nsIRDFResource* aSource, 1.1692 + nsIRDFResource* aProperty, 1.1693 + nsIRDFNode* aTarget) 1.1694 +{ 1.1695 + // TODO: filter out unasserts we don't care about 1.1696 + return mInner->Unassert(aSource, aProperty, aTarget); 1.1697 +} 1.1698 + 1.1699 + 1.1700 +NS_IMETHODIMP nsCharsetMenu::Change(nsIRDFResource* aSource, 1.1701 + nsIRDFResource* aProperty, 1.1702 + nsIRDFNode* aOldTarget, 1.1703 + nsIRDFNode* aNewTarget) 1.1704 +{ 1.1705 + // TODO: filter out changes we don't care about 1.1706 + return mInner->Change(aSource, aProperty, aOldTarget, aNewTarget); 1.1707 +} 1.1708 + 1.1709 +NS_IMETHODIMP nsCharsetMenu::Move(nsIRDFResource* aOldSource, 1.1710 + nsIRDFResource* aNewSource, 1.1711 + nsIRDFResource* aProperty, 1.1712 + nsIRDFNode* aTarget) 1.1713 +{ 1.1714 + // TODO: filter out changes we don't care about 1.1715 + return mInner->Move(aOldSource, aNewSource, aProperty, aTarget); 1.1716 +} 1.1717 + 1.1718 + 1.1719 +NS_IMETHODIMP nsCharsetMenu::HasAssertion(nsIRDFResource* source, 1.1720 + nsIRDFResource* property, 1.1721 + nsIRDFNode* target, bool tv, 1.1722 + bool* hasAssertion) 1.1723 +{ 1.1724 + return mInner->HasAssertion(source, property, target, tv, hasAssertion); 1.1725 +} 1.1726 + 1.1727 +NS_IMETHODIMP nsCharsetMenu::AddObserver(nsIRDFObserver* n) 1.1728 +{ 1.1729 + return mInner->AddObserver(n); 1.1730 +} 1.1731 + 1.1732 +NS_IMETHODIMP nsCharsetMenu::RemoveObserver(nsIRDFObserver* n) 1.1733 +{ 1.1734 + return mInner->RemoveObserver(n); 1.1735 +} 1.1736 + 1.1737 +NS_IMETHODIMP 1.1738 +nsCharsetMenu::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result) 1.1739 +{ 1.1740 + return mInner->HasArcIn(aNode, aArc, result); 1.1741 +} 1.1742 + 1.1743 +NS_IMETHODIMP 1.1744 +nsCharsetMenu::HasArcOut(nsIRDFResource *source, nsIRDFResource *aArc, bool *result) 1.1745 +{ 1.1746 + return mInner->HasArcOut(source, aArc, result); 1.1747 +} 1.1748 + 1.1749 +NS_IMETHODIMP nsCharsetMenu::ArcLabelsIn(nsIRDFNode* node, 1.1750 + nsISimpleEnumerator** labels) 1.1751 +{ 1.1752 + return mInner->ArcLabelsIn(node, labels); 1.1753 +} 1.1754 + 1.1755 +NS_IMETHODIMP nsCharsetMenu::ArcLabelsOut(nsIRDFResource* source, 1.1756 + nsISimpleEnumerator** labels) 1.1757 +{ 1.1758 + return mInner->ArcLabelsOut(source, labels); 1.1759 +} 1.1760 + 1.1761 +NS_IMETHODIMP nsCharsetMenu::GetAllResources(nsISimpleEnumerator** aCursor) 1.1762 +{ 1.1763 + return mInner->GetAllResources(aCursor); 1.1764 +} 1.1765 + 1.1766 +NS_IMETHODIMP nsCharsetMenu::GetAllCmds( 1.1767 + nsIRDFResource* source, 1.1768 + nsISimpleEnumerator/*<nsIRDFResource>*/** commands) 1.1769 +{ 1.1770 + NS_NOTYETIMPLEMENTED("nsCharsetMenu::GetAllCmds"); 1.1771 + return NS_ERROR_NOT_IMPLEMENTED; 1.1772 +} 1.1773 + 1.1774 +NS_IMETHODIMP nsCharsetMenu::IsCommandEnabled( 1.1775 + nsISupportsArray/*<nsIRDFResource>*/* aSources, 1.1776 + nsIRDFResource* aCommand, 1.1777 + nsISupportsArray/*<nsIRDFResource>*/* aArguments, 1.1778 + bool* aResult) 1.1779 +{ 1.1780 + NS_NOTYETIMPLEMENTED("nsCharsetMenu::IsCommandEnabled"); 1.1781 + return NS_ERROR_NOT_IMPLEMENTED; 1.1782 +} 1.1783 + 1.1784 +NS_IMETHODIMP nsCharsetMenu::DoCommand(nsISupportsArray* aSources, 1.1785 + nsIRDFResource* aCommand, 1.1786 + nsISupportsArray* aArguments) 1.1787 +{ 1.1788 + NS_NOTYETIMPLEMENTED("nsCharsetMenu::DoCommand"); 1.1789 + return NS_ERROR_NOT_IMPLEMENTED; 1.1790 +} 1.1791 + 1.1792 +NS_IMETHODIMP nsCharsetMenu::BeginUpdateBatch() 1.1793 +{ 1.1794 + return mInner->BeginUpdateBatch(); 1.1795 +} 1.1796 + 1.1797 +NS_IMETHODIMP nsCharsetMenu::EndUpdateBatch() 1.1798 +{ 1.1799 + return mInner->EndUpdateBatch(); 1.1800 +}