Backed out changeset 5a2ea27885f0 (bug 1850738) for causing build bustages on gfxUser...
[gecko.git] / toolkit / content / aboutProfiles.js
blob15c0419a11fee377f17dd766938943024723aab0
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 "use strict";
7 const { XPCOMUtils } = ChromeUtils.importESModule(
8   "resource://gre/modules/XPCOMUtils.sys.mjs"
9 );
11 XPCOMUtils.defineLazyServiceGetter(
12   this,
13   "ProfileService",
14   "@mozilla.org/toolkit/profile-service;1",
15   "nsIToolkitProfileService"
18 async function flush() {
19   try {
20     ProfileService.flush();
21     rebuildProfileList();
22   } catch (e) {
23     let [title, msg, button] = await document.l10n.formatValues([
24       { id: "profiles-flush-fail-title" },
25       {
26         id:
27           e.result == Cr.NS_ERROR_DATABASE_CHANGED
28             ? "profiles-flush-conflict"
29             : "profiles-flush-failed",
30       },
31       { id: "profiles-flush-restart-button" },
32     ]);
34     const PS = Ci.nsIPromptService;
35     let result = Services.prompt.confirmEx(
36       window,
37       title,
38       msg,
39       PS.BUTTON_POS_0 * PS.BUTTON_TITLE_CANCEL +
40         PS.BUTTON_POS_1 * PS.BUTTON_TITLE_IS_STRING,
41       null,
42       button,
43       null,
44       null,
45       {}
46     );
47     if (result == 1) {
48       restart(false);
49     }
50   }
53 function rebuildProfileList() {
54   let parent = document.getElementById("profiles");
55   while (parent.firstChild) {
56     parent.firstChild.remove();
57   }
59   let defaultProfile;
60   try {
61     defaultProfile = ProfileService.defaultProfile;
62   } catch (e) {}
64   let currentProfile = ProfileService.currentProfile;
66   for (let profile of ProfileService.profiles) {
67     let isCurrentProfile = profile == currentProfile;
68     let isInUse = isCurrentProfile;
69     if (!isInUse) {
70       try {
71         let lock = profile.lock({});
72         lock.unlock();
73       } catch (e) {
74         if (
75           e.result != Cr.NS_ERROR_FILE_NOT_DIRECTORY &&
76           e.result != Cr.NS_ERROR_FILE_NOT_FOUND
77         ) {
78           isInUse = true;
79         }
80       }
81     }
82     display({
83       profile,
84       isDefault: profile == defaultProfile,
85       isCurrentProfile,
86       isInUse,
87     });
88   }
91 function display(profileData) {
92   let parent = document.getElementById("profiles");
94   let div = document.createElement("div");
95   parent.appendChild(div);
97   let name = document.createElement("h2");
99   div.appendChild(name);
100   document.l10n.setAttributes(name, "profiles-name", {
101     name: profileData.profile.name,
102   });
104   if (profileData.isCurrentProfile) {
105     let currentProfile = document.createElement("h3");
106     document.l10n.setAttributes(currentProfile, "profiles-current-profile");
107     div.appendChild(currentProfile);
108   } else if (profileData.isInUse) {
109     let currentProfile = document.createElement("h3");
110     document.l10n.setAttributes(currentProfile, "profiles-in-use-profile");
111     div.appendChild(currentProfile);
112   }
114   let table = document.createElement("table");
115   div.appendChild(table);
117   let tbody = document.createElement("tbody");
118   table.appendChild(tbody);
120   function createItem(title, value, dir = false) {
121     let tr = document.createElement("tr");
122     tbody.appendChild(tr);
124     let th = document.createElement("th");
125     th.setAttribute("class", "column");
126     document.l10n.setAttributes(th, title);
127     tr.appendChild(th);
129     let td = document.createElement("td");
130     tr.appendChild(td);
132     if (dir) {
133       td.appendChild(document.createTextNode(value.path));
135       if (value.exists()) {
136         let button = document.createElement("button");
137         button.setAttribute("class", "opendir");
138         document.l10n.setAttributes(button, "profiles-opendir");
140         td.appendChild(button);
142         button.addEventListener("click", function (e) {
143           value.reveal();
144         });
145       }
146     } else {
147       document.l10n.setAttributes(td, value);
148     }
149   }
151   createItem(
152     "profiles-is-default",
153     profileData.isDefault ? "profiles-yes" : "profiles-no"
154   );
156   createItem("profiles-rootdir", profileData.profile.rootDir, true);
158   if (profileData.profile.localDir.path != profileData.profile.rootDir.path) {
159     createItem("profiles-localdir", profileData.profile.localDir, true);
160   }
162   let renameButton = document.createElement("button");
163   document.l10n.setAttributes(renameButton, "profiles-rename");
164   renameButton.onclick = function () {
165     renameProfile(profileData.profile);
166   };
167   div.appendChild(renameButton);
169   if (!profileData.isInUse) {
170     let removeButton = document.createElement("button");
171     document.l10n.setAttributes(removeButton, "profiles-remove");
172     removeButton.onclick = function () {
173       removeProfile(profileData.profile);
174     };
176     div.appendChild(removeButton);
177   }
179   if (!profileData.isDefault) {
180     let defaultButton = document.createElement("button");
181     document.l10n.setAttributes(defaultButton, "profiles-set-as-default");
182     defaultButton.onclick = function () {
183       defaultProfile(profileData.profile);
184     };
185     div.appendChild(defaultButton);
186   }
188   if (!profileData.isInUse) {
189     let runButton = document.createElement("button");
190     document.l10n.setAttributes(runButton, "profiles-launch-profile");
191     runButton.onclick = function () {
192       openProfile(profileData.profile);
193     };
194     div.appendChild(runButton);
195   }
197   let sep = document.createElement("hr");
198   div.appendChild(sep);
201 // This is called from the createProfileWizard.xhtml dialog.
202 function CreateProfile(profile) {
203   // The wizard created a profile, just make it the default.
204   defaultProfile(profile);
207 function createProfileWizard() {
208   // This should be rewritten in HTML eventually.
209   window.browsingContext.topChromeWindow.openDialog(
210     "chrome://mozapps/content/profile/createProfileWizard.xhtml",
211     "",
212     "centerscreen,chrome,modal,titlebar",
213     ProfileService,
214     { CreateProfile }
215   );
218 async function renameProfile(profile) {
219   let newName = { value: profile.name };
220   let [title, msg] = await document.l10n.formatValues([
221     { id: "profiles-rename-profile-title" },
222     { id: "profiles-rename-profile", args: { name: profile.name } },
223   ]);
225   if (Services.prompt.prompt(window, title, msg, newName, null, { value: 0 })) {
226     newName = newName.value;
228     if (newName == profile.name) {
229       return;
230     }
232     try {
233       profile.name = newName;
234     } catch (e) {
235       let [title, msg] = await document.l10n.formatValues([
236         { id: "profiles-invalid-profile-name-title" },
237         { id: "profiles-invalid-profile-name", args: { name: newName } },
238       ]);
240       Services.prompt.alert(window, title, msg);
241       return;
242     }
244     flush();
245   }
248 async function removeProfile(profile) {
249   let deleteFiles = false;
251   if (profile.rootDir.exists()) {
252     let [title, msg, dontDeleteStr, deleteStr] =
253       await document.l10n.formatValues([
254         { id: "profiles-delete-profile-title" },
255         {
256           id: "profiles-delete-profile-confirm",
257           args: { dir: profile.rootDir.path },
258         },
259         { id: "profiles-dont-delete-files" },
260         { id: "profiles-delete-files" },
261       ]);
262     let buttonPressed = Services.prompt.confirmEx(
263       window,
264       title,
265       msg,
266       Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0 +
267         Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1 +
268         Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_2,
269       dontDeleteStr,
270       null,
271       deleteStr,
272       null,
273       { value: 0 }
274     );
275     if (buttonPressed == 1) {
276       return;
277     }
279     if (buttonPressed == 2) {
280       deleteFiles = true;
281     }
282   }
284   // If we are deleting the default profile we must choose a different one.
285   let isDefault = false;
286   try {
287     isDefault = ProfileService.defaultProfile == profile;
288   } catch (e) {}
290   if (isDefault) {
291     for (let p of ProfileService.profiles) {
292       if (profile == p) {
293         continue;
294       }
296       if (isDefault) {
297         try {
298           ProfileService.defaultProfile = p;
299         } catch (e) {
300           // This can happen on dev-edition if a non-default profile is in use.
301           // In such a case the next time that dev-edition is started it will
302           // find no default profile and just create a new one.
303         }
304       }
306       break;
307     }
308   }
310   try {
311     profile.removeInBackground(deleteFiles);
312   } catch (e) {
313     let [title, msg] = await document.l10n.formatValues([
314       { id: "profiles-delete-profile-failed-title" },
315       { id: "profiles-delete-profile-failed-message" },
316     ]);
318     Services.prompt.alert(window, title, msg);
319     return;
320   }
322   flush();
325 async function defaultProfile(profile) {
326   try {
327     ProfileService.defaultProfile = profile;
328     flush();
329   } catch (e) {
330     // This can happen on dev-edition.
331     let [title, msg] = await document.l10n.formatValues([
332       { id: "profiles-cannot-set-as-default-title" },
333       { id: "profiles-cannot-set-as-default-message" },
334     ]);
336     Services.prompt.alert(window, title, msg);
337   }
340 function openProfile(profile) {
341   Services.startup.createInstanceWithProfile(profile);
344 function restart(safeMode) {
345   let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(
346     Ci.nsISupportsPRBool
347   );
348   Services.obs.notifyObservers(
349     cancelQuit,
350     "quit-application-requested",
351     "restart"
352   );
354   if (cancelQuit.data) {
355     return;
356   }
358   let flags = Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart;
360   if (safeMode) {
361     Services.startup.restartInSafeMode(flags);
362   } else {
363     Services.startup.quit(flags);
364   }
367 window.addEventListener(
368   "DOMContentLoaded",
369   function () {
370     let createButton = document.getElementById("create-button");
371     createButton.addEventListener("click", createProfileWizard);
373     let restartSafeModeButton = document.getElementById(
374       "restart-in-safe-mode-button"
375     );
376     if (!Services.policies || Services.policies.isAllowed("safeMode")) {
377       restartSafeModeButton.addEventListener("click", () => {
378         restart(true);
379       });
380     } else {
381       restartSafeModeButton.setAttribute("disabled", "true");
382     }
384     let restartNormalModeButton = document.getElementById("restart-button");
385     restartNormalModeButton.addEventListener("click", () => {
386       restart(false);
387     });
389     if (ProfileService.isListOutdated) {
390       document.getElementById("owned").hidden = true;
391     } else {
392       document.getElementById("conflict").hidden = true;
393       rebuildProfileList();
394     }
395   },
396   { once: true }