diff options
Diffstat (limited to 'comm/suite/components/profile')
-rw-r--r-- | comm/suite/components/profile/content/profileSelection.js | 344 | ||||
-rw-r--r-- | comm/suite/components/profile/content/profileSelection.xul | 85 | ||||
-rw-r--r-- | comm/suite/components/profile/jar.mn | 8 | ||||
-rw-r--r-- | comm/suite/components/profile/moz.build | 13 | ||||
-rwxr-xr-x | comm/suite/components/profile/nsSuiteDirectoryProvider.cpp | 248 | ||||
-rw-r--r-- | comm/suite/components/profile/nsSuiteDirectoryProvider.h | 58 |
6 files changed, 756 insertions, 0 deletions
diff --git a/comm/suite/components/profile/content/profileSelection.js b/comm/suite/components/profile/content/profileSelection.js new file mode 100644 index 0000000000..6400d73359 --- /dev/null +++ b/comm/suite/components/profile/content/profileSelection.js @@ -0,0 +1,344 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); + +var gProfileBundle; +var gBrandBundle; +var gProfileService; +var gProfileManagerMode = "selection"; +var gDialogParams = window.arguments[0] + .QueryInterface(Ci.nsIDialogParamBlock); + +function StartUp() +{ + gProfileBundle = document.getElementById("bundle_profile"); + gBrandBundle = document.getElementById("bundle_brand"); + if (gDialogParams.objects) { + document.documentElement.getButton("accept").setAttribute("label", + document.documentElement.getAttribute("buttonlabelstart")); + document.documentElement.getButton("cancel").setAttribute("label", + document.documentElement.getAttribute("buttonlabelexit")); + document.getElementById('intro').textContent = + document.getElementById('intro').getAttribute("start"); + document.getElementById('offlineState').hidden = false; + gDialogParams.SetInt(0, 0); + } + + gProfileService = Cc["@mozilla.org/toolkit/profile-service;1"] + .getService(Ci.nsIToolkitProfileService); + var profileEnum = gProfileService.profiles; + var selectedProfile = null; + try { + selectedProfile = gProfileService.selectedProfile; + } + catch (ex) { + } + while (profileEnum.hasMoreElements()) { + AddItem(profileEnum.getNext().QueryInterface(Ci.nsIToolkitProfile), + selectedProfile); + } + + var autoSelect = document.getElementById("autoSelect"); + if (Services.prefs.getBoolPref("profile.manage_only_at_launch")) + autoSelect.hidden = true; + else + autoSelect.checked = gProfileService.startWithLastProfile; + + DoEnabling(); +} + +// function : <profileSelection.js>::AddItem(); +// purpose : utility function for adding items to a tree. +function AddItem(aProfile, aProfileToSelect) +{ + var tree = document.getElementById("profiles"); + var treeitem = document.createElement("treeitem"); + var treerow = document.createElement("treerow"); + var treecell = document.createElement("treecell"); + var treetip = document.getElementById("treetip"); + var profileDir = gProfileService.getProfileByName(aProfile.name).rootDir; + + treecell.setAttribute("label", aProfile.name); + treerow.appendChild(treecell); + treeitem.appendChild(treerow); + treeitem.setAttribute("tooltip", profileDir.path); + treetip.setAttribute("value", profileDir.path); + tree.lastChild.appendChild(treeitem); + treeitem.profile = aProfile; + if (aProfile == aProfileToSelect) { + var profileIndex = tree.view.getIndexOfItem(treeitem); + tree.view.selection.select(profileIndex); + tree.treeBoxObject.ensureRowIsVisible(profileIndex); + } +} + +// function : <profileSelection.js>::AcceptDialog(); +// purpose : sets the current profile to the selected profile (user choice: "Start Mozilla") +function AcceptDialog() +{ + var autoSelect = document.getElementById("autoSelect"); + if (!autoSelect.hidden) { + gProfileService.startWithLastProfile = autoSelect.checked; + gProfileService.flush(); + } + + var profileTree = document.getElementById("profiles"); + var selected = profileTree.view.getItemAtIndex(profileTree.currentIndex); + + if (!gDialogParams.objects) { + var profD = Services.dirsvc.get("ProfD", Ci.nsIFile); + var profLD = Services.dirsvc.get("ProfLD", Ci.nsIFile); + + if (selected.profile.rootDir.equals(profD) && + selected.profile.localDir.equals(profLD)) + return true; + } + + try { + var profileLock = selected.profile.lock({}); + gProfileService.selectedProfile = selected.profile; + gProfileService.defaultProfile = selected.profile; + gProfileService.flush(); + if (gDialogParams.objects) { + gDialogParams.objects.insertElementAt(profileLock, 0); + gProfileService.startOffline = document.getElementById("offlineState").checked; + gDialogParams.SetInt(0, 1); + gDialogParams.SetString(0, selected.profile.name); + return true; + } + profileLock.unlock(); + } catch (e) { + var brandName = gBrandBundle.getString("brandShortName"); + var message = gProfileBundle.getFormattedString("dirLocked", + [brandName, selected.profile.name]); + Services.prompt.alert(window, null, message); + return false; + } + + // Although switching profile works by performing a restart internally, + // the user is quitting the old profile, so make it look like a quit. + var cancelQuit = Cc["@mozilla.org/supports-PRBool;1"] + .createInstance(Ci.nsISupportsPRBool); + Services.obs.notifyObservers(cancelQuit, "quit-application-requested"); + + if (cancelQuit.data) { + return false; + } + + try { + var env = Cc["@mozilla.org/process/environment;1"] + .getService(Ci.nsIEnvironment); + env.set("XRE_PROFILE_NAME", selected.profile.name); + env.set("XRE_PROFILE_PATH", selected.profile.rootDir.path); + env.set("XRE_PROFILE_LOCAL_PATH", selected.profile.localDir.path); + var app = Services.startup; + app.quit(app.eAttemptQuit | app.eRestart); + return true; + } + catch (e) { + env.set("XRE_PROFILE_NAME", ""); + env.set("XRE_PROFILE_PATH", ""); + env.set("XRE_PROFILE_LOCAL_PATH", ""); + return false; + } +} + +// invoke the createProfile Wizard +function CreateProfileWizard() +{ + window.openDialog('chrome://mozapps/content/profile/createProfileWizard.xul', + '', 'centerscreen,chrome,modal,titlebar'); +} + +// update the display to show the additional profile +function CreateProfile(aProfile) +{ + gProfileService.flush(); + AddItem(aProfile, aProfile); +} + +// rename the selected profile +function RenameProfile() +{ + var profileTree = document.getElementById("profiles"); + var selected = profileTree.view.getItemAtIndex(profileTree.currentIndex); + var profileName = selected.profile.name; + var newName = {value: profileName}; + var dialogTitle = gProfileBundle.getString("renameProfileTitle"); + var msg = gProfileBundle.getFormattedString("renameProfilePrompt", [profileName]); + var ps = Services.prompt; + if (ps.prompt(window, dialogTitle, msg, newName, null, {value: 0}) && + newName.value != profileName) { + if (!/\S/.test(newName.value)) { + ps.alert(window, gProfileBundle.getString("profileNameInvalidTitle"), + gProfileBundle.getString("profileNameEmpty")); + return false; + } + + if (/([\\*:?<>|\/\"])/.test(newName.value)) { + ps.alert(window, gProfileBundle.getString("profileNameInvalidTitle"), + gProfileBundle.getFormattedString("invalidChar", [RegExp.$1])); + return false; + } + + try { + gProfileService.getProfileByName(newName.value); + ps.alert(window, gProfileBundle.getString("profileExistsTitle"), + gProfileBundle.getString("profileExists")); + return false; + } + catch (e) { + } + + selected.profile.name = newName.value; + gProfileService.flush(); + selected.firstChild.firstChild.setAttribute("label", newName.value); + } +} + +function ConfirmDelete() +{ + var profileTree = document.getElementById("profiles"); + var selected = profileTree.view.getItemAtIndex(profileTree.currentIndex); + if (!selected.profile.rootDir.exists()) { + DeleteProfile(false); + return; + } + + try { + var profileLock = selected.profile.lock({}); + var dialogTitle = gProfileBundle.getString("deleteTitle"); + var dialogText; + + var path = selected.profile.rootDir.path; + dialogText = gProfileBundle.getFormattedString("deleteProfile", [path]); + var ps = Services.prompt; + var buttonPressed = ps.confirmEx(window, dialogTitle, dialogText, + (ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_0) + + (ps.BUTTON_TITLE_CANCEL * ps.BUTTON_POS_1) + + (ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_2), + gProfileBundle.getString("dontDeleteFiles"), null, + gProfileBundle.getString("deleteFiles"), null, {value: 0}); + profileLock.unlock(); + if (buttonPressed != 1) + DeleteProfile(buttonPressed == 2); + } catch (e) { + var dialogTitle = gProfileBundle.getString("deleteTitle"); + var brandName = gBrandBundle.getString("brandShortName"); + var dialogText = gProfileBundle.getFormattedString("deleteLocked", + [brandName, selected.profile.name]); + ps.alert(window, dialogTitle, dialogText); + } +} + +// Delete the profile, with the delete flag set as per instruction above. +function DeleteProfile(aDeleteFiles) +{ + var profileTree = document.getElementById("profiles"); + var selected = profileTree.view.getItemAtIndex(profileTree.currentIndex); + var previous = profileTree.currentIndex && profileTree.currentIndex - 1; + + try { + selected.profile.remove(aDeleteFiles); + gProfileService.flush(); + selected.remove(); + + if (profileTree.view.rowCount != 0) { + profileTree.view.selection.select(previous); + profileTree.treeBoxObject.ensureRowIsVisible(previous); + } + + // set the button state + DoEnabling(); + } + catch (ex) { + dump("Exception during profile deletion.\n"); + } +} + +function SwitchProfileManagerMode() +{ + var captionLine; + var prattleIndex; + + if (gProfileManagerMode == "selection") { + prattleIndex = 1; + captionLine = gProfileBundle.getString("manageTitle"); + + document.getElementById("profiles").focus(); + + // hide the manage profiles button... + document.documentElement.getButton("extra2").hidden = true; + gProfileManagerMode = "manager"; + } + else { + prattleIndex = 0; + captionLine = gProfileBundle.getString("selectTitle"); + gProfileManagerMode = "selection"; + } + + // swap deck + document.getElementById("prattle").selectedIndex = prattleIndex; + + // change the title of the profile manager/selection window. + document.getElementById("header").setAttribute("description", captionLine); + document.title = captionLine; +} + +// do button enabling based on tree selection +function DoEnabling() +{ + var acceptButton = document.documentElement.getButton("accept"); + var deleteButton = document.getElementById("deleteButton"); + var renameButton = document.getElementById("renameButton"); + + var disabled = document.getElementById("profiles").view.selection.count == 0; + acceptButton.disabled = disabled; + deleteButton.disabled = disabled; + renameButton.disabled = disabled; +} + +// handle key event on tree +function HandleKeyEvent(aEvent) +{ + if (gProfileManagerMode != "manager") + return; + + switch (aEvent.keyCode) + { + case KeyEvent.DOM_VK_BACK_SPACE: + case KeyEvent.DOM_VK_DELETE: + if (!document.getElementById("deleteButton").disabled) + ConfirmDelete(); + break; + case KeyEvent.DOM_VK_F2: + if (!document.getElementById("renameButton").disabled) + RenameProfile(); + } +} + +function HandleClickEvent(aEvent) +{ + if (aEvent.button == 0 && aEvent.target.parentNode.view.selection.count != 0 && AcceptDialog()) { + window.close(); + return true; + } + + return false; +} + +function HandleToolTipEvent(aEvent) +{ + var treeTip = document.getElementById("treetip"); + var tree = document.getElementById("profiles"); + + var cell = tree.treeBoxObject.getCellAt(aEvent.clientX, aEvent.clientY); + if (cell.row < 0) + aEvent.preventDefault(); + else + treeTip.label = tree.view.getItemAtIndex(cell.row).tooltip; +} diff --git a/comm/suite/components/profile/content/profileSelection.xul b/comm/suite/components/profile/content/profileSelection.xul new file mode 100644 index 0000000000..dd62b4a7dd --- /dev/null +++ b/comm/suite/components/profile/content/profileSelection.xul @@ -0,0 +1,85 @@ +<?xml version="1.0"?> +<!-- -*- Mode: SGML; indent-tabs-mode: nil; -*- --> +<!-- + + This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + +<?xml-stylesheet href="chrome://communicator/skin/" type="text/css"?> +<?xml-stylesheet href="chrome://communicator/skin/profile/profile.css" type="text/css"?> + +<!DOCTYPE dialog [ +<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> +%brandDTD; +<!ENTITY % profileDTD SYSTEM "chrome://communicator/locale/profile/profileSelection.dtd"> +%profileDTD; +]> + +<dialog id="profileWindow" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + title="&windowTitle.label;" + windowtype="mozilla:profileSelection" + orient="vertical" + style="width: 42em;" + buttons="accept,cancel,extra2" + buttonlabelaccept="&select.label;" + buttonlabelstart="&start.label;" + buttonlabelexit="&exit.label;" + buttonlabelextra2="&manage.label;" + buttonaccesskeyextra2="&manage.accesskey;" + ondialogaccept="return AcceptDialog();" + ondialogextra2="SwitchProfileManagerMode();" + onload="StartUp();"> + + <stringbundle id="bundle_profile" + src="chrome://communicator/locale/profile/profileSelection.properties"/> + <stringbundle id="bundle_brand" + src="chrome://branding/locale/brand.properties"/> + + <script src="chrome://communicator/content/profile/profileSelection.js"/> + <script src="chrome://mozapps/content/profile/createProfileWizard.js"/> + + <dialogheader id="header" title="&profileManager.title;" description="&windowTitle.label;"/> + + <hbox class="wizard-box" flex="1"> + + <!-- instructions --> + <deck id="prattle"> + <description id="intro" start="&introStart.label;">&introSwitch.label;</description> + <vbox> + <description id="label">&profileManagerText.label;</description> + <separator/> + <hbox> + <vbox flex="1" id="managebuttons"> + <button id="newButton" label="&newButton.label;" accesskey="&newButton.accesskey;" oncommand="CreateProfileWizard();"/> + <button id="renameButton" label="&renameButton.label;" accesskey="&renameButton.accesskey;" oncommand="RenameProfile();"/> + <button id="deleteButton" label="&deleteButton.label;" accesskey="&deleteButton.accesskey;" oncommand="ConfirmDelete();"/> + </vbox> + <spacer flex="2"/> + </hbox> + </vbox> + </deck> + + <separator class="thin" orient="vertical"/> + + <vbox flex="1"> + <tooltip id="treetip" + onpopupshowing="HandleToolTipEvent(event);"> + </tooltip> + <tree id="profiles" flex="1" seltype="single" + hidecolumnpicker="true" + onselect="DoEnabling();" + onkeypress="HandleKeyEvent(event);"> + <treecols> + <treecol label="&availableProfiles.label;" flex="1" sortLocked="true"/> + </treecols> + <treechildren tooltip="treetip" + ondblclick="HandleClickEvent(event);"/> + </tree> + <checkbox id="offlineState" label="&offlineState.label;" accesskey="&offlineState.accesskey;" hidden="true"/> + <checkbox id="autoSelect" label="&autoSelect.label;" accesskey="&autoSelect.accesskey;"/> + </vbox> + </hbox> + +</dialog> diff --git a/comm/suite/components/profile/jar.mn b/comm/suite/components/profile/jar.mn new file mode 100644 index 0000000000..bf9706ba55 --- /dev/null +++ b/comm/suite/components/profile/jar.mn @@ -0,0 +1,8 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +comm.jar: +% override chrome://mozapps/content/profile/profileSelection.xul chrome://communicator/content/profile/profileSelection.xul + content/communicator/profile/profileSelection.js (content/profileSelection.js) + content/communicator/profile/profileSelection.xul (content/profileSelection.xul) diff --git a/comm/suite/components/profile/moz.build b/comm/suite/components/profile/moz.build new file mode 100644 index 0000000000..0f2d51ba64 --- /dev/null +++ b/comm/suite/components/profile/moz.build @@ -0,0 +1,13 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +SOURCES += [ + "nsSuiteDirectoryProvider.cpp", +] + +FINAL_LIBRARY = "suite" + +JAR_MANIFESTS += ["jar.mn"] diff --git a/comm/suite/components/profile/nsSuiteDirectoryProvider.cpp b/comm/suite/components/profile/nsSuiteDirectoryProvider.cpp new file mode 100755 index 0000000000..9d19615625 --- /dev/null +++ b/comm/suite/components/profile/nsSuiteDirectoryProvider.cpp @@ -0,0 +1,248 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsSuiteDirectoryProvider.h" +#include "nsAppDirectoryServiceDefs.h" +#include "nsCategoryManagerUtils.h" +#include "nsXULAppAPI.h" +#include "nsDirectoryServiceUtils.h" +#include "nsIPrefBranch.h" +#include "nsDirectoryServiceDefs.h" +#include "mozilla/intl/LocaleService.h" +#include "nsIPrefService.h" +#include "nsArrayEnumerator.h" +#include "nsEnumeratorUtils.h" + +using mozilla::intl::LocaleService; + +NS_IMPL_ISUPPORTS(nsSuiteDirectoryProvider, + nsIDirectoryServiceProvider, + nsIDirectoryServiceProvider2) + +NS_IMETHODIMP +nsSuiteDirectoryProvider::GetFile(const char *aKey, + bool *aPersist, + nsIFile* *aResult) +{ + // NOTE: This function can be reentrant through the NS_GetSpecialDirectory + // call, so be careful not to cause infinite recursion. + // i.e. the check for supported files must come first. + const char* leafName = nullptr; + + if (!strcmp(aKey, NS_APP_BOOKMARKS_50_FILE)) + leafName = "bookmarks.html"; + else if (!strcmp(aKey, NS_APP_USER_PANELS_50_FILE)) + leafName = "panels.rdf"; + else + return NS_ERROR_FAILURE; + + nsCOMPtr<nsIFile> parentDir; + nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, + getter_AddRefs(parentDir)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr<nsIFile> file; + rv = parentDir->Clone(getter_AddRefs(file)); + if (NS_FAILED(rv)) + return rv; + + nsDependentCString leafStr(leafName); + file->AppendNative(leafStr); + + bool exists; + if (NS_SUCCEEDED(file->Exists(&exists)) && !exists) + EnsureProfileFile(leafStr, parentDir, file); + + *aPersist = true; + NS_IF_ADDREF(*aResult = file); + + return NS_OK; +} + +NS_IMETHODIMP +nsSuiteDirectoryProvider::GetFiles(const char *aKey, + nsISimpleEnumerator* *aResult) +{ + nsresult rv; + nsCOMPtr<nsIProperties> dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + return rv; + + nsCOMArray<nsIFile> baseFiles; + AppendDistroSearchDirs(dirSvc, baseFiles); + + nsCOMPtr<nsISimpleEnumerator> baseEnum; + rv = NS_NewArrayEnumerator(getter_AddRefs(baseEnum), baseFiles); + if (NS_FAILED(rv)) + return rv; + + return NS_ERROR_FAILURE; +} + +void +nsSuiteDirectoryProvider::EnsureProfileFile(const nsACString& aLeafName, + nsIFile* aParentDir, + nsIFile* aTarget) +{ + nsCOMPtr<nsIFile> defaultsDir; + + NS_GetSpecialDirectory(NS_APP_DEFAULTS_50_DIR, + getter_AddRefs(defaultsDir)); + if (!defaultsDir) + return; + + nsresult rv = defaultsDir->AppendNative("profile"_ns); + NS_ENSURE_SUCCESS_VOID(rv); + + defaultsDir->AppendNative(aLeafName); + + defaultsDir->CopyToNative(aParentDir, aLeafName); +} + +NS_IMPL_ISUPPORTS(nsSuiteDirectoryProvider::AppendingEnumerator, + nsISimpleEnumerator) + +NS_IMETHODIMP +nsSuiteDirectoryProvider::AppendingEnumerator::HasMoreElements(bool *aResult) +{ + *aResult = mNext != nullptr; + return NS_OK; +} + +void +nsSuiteDirectoryProvider::AppendingEnumerator::GetNext() +{ + // Ignore all errors + + bool more; + while (NS_SUCCEEDED(mBase->HasMoreElements(&more)) && more) { + nsCOMPtr<nsISupports> nextSupports; + mBase->GetNext(getter_AddRefs(nextSupports)); + + mNext = do_QueryInterface(nextSupports); + if (!mNext) + continue; + + mNext->AppendNative(mLeafName); + + bool exists; + if (NS_SUCCEEDED(mNext->Exists(&exists)) && exists) + return; + } + + mNext = nullptr; +} + +NS_IMETHODIMP +nsSuiteDirectoryProvider::AppendingEnumerator::GetNext(nsISupports* *aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + + if (!mNext) { + *aResult = nullptr; + return NS_ERROR_FAILURE; + } + + NS_ADDREF(*aResult = mNext); + + GetNext(); + + return NS_OK; +} + +nsSuiteDirectoryProvider::AppendingEnumerator::AppendingEnumerator + (nsISimpleEnumerator* aBase, const char* const aLeafName) : + mBase(aBase), mLeafName(aLeafName) +{ + // Initialize mNext to begin. + GetNext(); +} + +// Appends the distribution-specific search engine directories to the +// array. The directory structure is as follows: + +// appdir/ +// \- distribution/ +// \- searchplugins/ +// |- common/ +// \- locale/ +// |- <locale 1>/ +// ... +// \- <locale N>/ + +// common engines are loaded for all locales. If there is no locale +// directory for the current locale, there is a pref: +// "distribution.searchplugins.defaultLocale" +// which specifies a default locale to use. + +void +nsSuiteDirectoryProvider::AppendDistroSearchDirs(nsIProperties* aDirSvc, + nsCOMArray<nsIFile> &array) +{ + nsCOMPtr<nsIFile> searchPlugins; + nsresult rv = aDirSvc->Get(NS_XPCOM_CURRENT_PROCESS_DIR, + NS_GET_IID(nsIFile), + getter_AddRefs(searchPlugins)); + if (NS_FAILED(rv)) + return; + searchPlugins->AppendNative("distribution"_ns); + searchPlugins->AppendNative("searchplugins"_ns); + + bool exists; + rv = searchPlugins->Exists(&exists); + if (NS_FAILED(rv) || !exists) + return; + + nsCOMPtr<nsIFile> commonPlugins; + rv = searchPlugins->Clone(getter_AddRefs(commonPlugins)); + if (NS_SUCCEEDED(rv)) { + commonPlugins->AppendNative("common"_ns); + rv = commonPlugins->Exists(&exists); + if (NS_SUCCEEDED(rv) && exists) + array.AppendObject(commonPlugins); + } + + nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); + if (prefs) { + nsCOMPtr<nsIFile> localePlugins; + rv = searchPlugins->Clone(getter_AddRefs(localePlugins)); + if (NS_FAILED(rv)) + return; + + localePlugins->AppendNative("locale"_ns); + + // we didn't append the locale dir - try the default one + nsCString defLocale; + rv = prefs->GetCharPref("distribution.searchplugins.defaultLocale", + defLocale); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr<nsIFile> defLocalePlugins; + rv = localePlugins->Clone(getter_AddRefs(defLocalePlugins)); + if (NS_SUCCEEDED(rv)) { + defLocalePlugins->AppendNative(defLocale); + rv = defLocalePlugins->Exists(&exists); + if (NS_SUCCEEDED(rv) && exists) { + array.AppendObject(defLocalePlugins); + return; // all done + } + } + } + + // we didn't have a defaultLocale, use the user agent locale + nsAutoCString locale; + LocaleService::GetInstance()->GetAppLocaleAsLangTag(locale); + + nsCOMPtr<nsIFile> curLocalePlugins; + rv = localePlugins->Clone(getter_AddRefs(curLocalePlugins)); + if (NS_SUCCEEDED(rv)) { + curLocalePlugins->AppendNative(locale); + rv = curLocalePlugins->Exists(&exists); + if (NS_SUCCEEDED(rv) && exists) { + array.AppendObject(curLocalePlugins); + return; // all done + } + } + } +} diff --git a/comm/suite/components/profile/nsSuiteDirectoryProvider.h b/comm/suite/components/profile/nsSuiteDirectoryProvider.h new file mode 100644 index 0000000000..6a06be3c30 --- /dev/null +++ b/comm/suite/components/profile/nsSuiteDirectoryProvider.h @@ -0,0 +1,58 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef SuiteDirectoryProvider_h__ +#define SuiteDirectoryProvider_h__ + +#include "nsCOMArray.h" +#include "nsIDirectoryService.h" +#include "nsIFile.h" +#include "nsISimpleEnumerator.h" +#include "nsString.h" +#include "nsCOMPtr.h" +#include "nsIProperties.h" +#include "mozilla/Attributes.h" +#include "nsSuiteCID.h" + +#define NS_APP_BOOKMARKS_50_FILE "BMarks" + +class nsSuiteDirectoryProvider final : public nsIDirectoryServiceProvider2 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIDIRECTORYSERVICEPROVIDER + NS_DECL_NSIDIRECTORYSERVICEPROVIDER2 + +private: + ~nsSuiteDirectoryProvider() {} + + void EnsureProfileFile(const nsACString& aLeafName, + nsIFile* aParentDir, nsIFile* aTarget); + + void AppendDistroSearchDirs(nsIProperties* aDirSvc, + nsCOMArray<nsIFile> &array); + + void AppendFileKey(const char *key, nsIProperties* aDirSvc, + nsCOMArray<nsIFile> &array); + + class AppendingEnumerator final : public nsISimpleEnumerator + { + public: + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + + AppendingEnumerator(nsISimpleEnumerator* aBase, + const char* const aLeafName); + + private: + ~AppendingEnumerator() {} + void GetNext(); + + nsCOMPtr<nsISimpleEnumerator> mBase; + nsDependentCString mLeafName; + nsCOMPtr<nsIFile> mNext; + }; +}; + +#endif |