preferences.js
Go to the documentation of this file.
1 /* preferences.js
2  * This will be loaded into the main window, and manage all preference-
3  * related tasks.
4  */
5 // Make a namespace.
6 if (typeof playlistfolders == 'undefined') {
7  var playlistfolders = {};
8 };
9 
10 /* Preference controller
11  * Controller for all preference-related stuff.
12  */
13 playlistfolders.preferences={
14  // Playlist Folder's preference branch
15  _prefs: null,
16  /* The JSON object stored in a preference
17  * Structure:
18  * {
19  * version: <string>, // version for migrating issues. See _migrateIfNeeded
20  * folders: [<folder>], // see createFolder for folder structure
21  * }
22  */
23  _root: null,
24 
25  // Startup code for the preference controller
26  onLoad: function(e){
27  playlistfolders.central.logEvent("preferences", "Perference controller " +
28  "initialisation started.", 5);
29  try {
30  // Get the preferences
31  var prefs = Components.classes["@mozilla.org/preferences-service;1"].
32  getService(Components.interfaces.nsIPrefService);
33  this._prefs = prefs.getBranch("extensions.playlistfolders.");
34  // Get JSON
35  try {
36  this._root = JSON.parse(this._prefs.getCharPref("JSON"));
37  } catch (e) {
38  this._root = {};
39  playlistfolders.central.logEvent("preferences",
40  "extensions.playlistfolders.JSON " +
41  "is invalid. Fallback to default " +
42  "value.", 2,
43  "chrome://playlistfolders/content/" +
44  "preferences.js",
45  e.lineNumber);
46  }
47  // Perform migration if needed
48  this._migrateIfNeeded();
49  // We're done.
50  playlistfolders.central.logEvent("preferences",
51  "Preference controller started.", 4);
52  } catch (e) {
53  playlistfolders.central.logEvent("preferences",
54  "Startup of Preference controller " +
55  "failed:\n\n" + e, 1, "chrome://" +
56  "playlistfolders/content/" +
57  "preferences.js", e.lineNumber);
58  }
59  },
60  // Shutdown code for the preference controller
61  onUnload: function(e){
62  playlistfolders.central.logEvent("preferences", "Preference controller " +
63  "shutdown started.", 5);
64  // Save JSON
65  this._saveCurrent();
66  // We're done!
67  playlistfolders.central.logEvent("preferences",
68  "Preference controller stopped.", 4);
69  },
70 
71  // Migrates JSON preferences (_root), if needed
72  _migrateIfNeeded: function(){
73  /* Playlist Folders JSON Migration Structure
74  * For each AddOn version with new/changed entrys in JSON there is a
75  * JSON version string (1.0.0.0 -> "1.0.0.0"). But not every Version
76  * needs a separate JSON version (so in 1.0.0.0b2 the current JSON
77  * version might be "1.0.0.0b1"). Final versions will have a non-beta
78  * version, so 1.0.0.0 can't get "1.0.0.0b1", although nothing changed.
79  * The migration will be performed in steps, if there are more than one
80  * JSON version between the saved preference and the installed release.
81  * Alpha and Beta Versions might have a own JSON version WITHOUT migration
82  * code needed (so there might be no migration from 1.0.0.0a1 to 1.0.0.0b1)
83  * There will be migration code for public beta releases in following
84  * releases with the same version number, but taken out in next releases.
85  */
86  // Migration from fresh install
87  if (!this._root.version){
88  playlistfolders.central.logEvent("preferences", "Migration from fresh " +
89  "install", 4);
90  this._root.version = "1.0.0.0";
91  this._root.folders = [];
92  var root = this.createFolder("");
93  root.GUID = "{root}";
94  }
95  // Don't kill alpha tester's JSON
96  if (this._root.version == "0.0.0.0a")
97  this._root.version = "1.0.0.0";
98  // If we weren't able to migrate, log a fatal error message and reset
99  // everything.
100  if (this._root.version != "1.0.0.0"){
101  playlistfolders.central.logEvent("preferences", "There is no rule to " +
102  "migrate from JSON version " +
103  this._root.version + ". Fallback to " +
104  "empty JSON root.", 2, "chrome://" +
105  "playlistfolders/content/" +
106  "preferences.js");
107  this._root = {};
108  this._migrateIfNeeded();
109  }
110  },
111 
112  // Saves current JSON (_root) to preferences
113  _saveCurrent: function(){
114  try {
115  playlistfolders.central.logEvent("preferences",
116  "Save JSON preferences", 5);
117  this._prefs.setCharPref("JSON", JSON.stringify(this._root));
118  } catch (e){
119  playlistfolders.central.logEvent("preferences",
120  "Saving of JSON preferences failed:" +
121  "\n\n" + e, 1, "chrome://" +
122  "playlistfolders/content/" +
123  "preferences.js", e.lineNumber);
124  }
125  },
126 
127  /* Generate a new Folder
128  * name (string): the name of the folder
129  */
130  createFolder: function(name){
131  // generate a folder with the given name and the default values
132  var result = {
133  name: name, // The folder's name; MUST get changed via renameFolder ONLY!
134  GUID: Components.classes["@mozilla.org/uuid-generator;1"].
135  getService(Components.interfaces.nsIUUIDGenerator).generateUUID().
136  toString(), // A unique ID for referencing purposes
137  content: [], // GUIDs of subfolders and playlists in this folder; MUST
138  // get changed via move functions ONLY!
139  closed: false, // True if the Folder's node was closed on last shutdown
140  };
141  // append and return the folder
142  playlistfolders.central.logEvent("preferences",
143  "Create Folder "+result.GUID, 5);
144  try {
145  this._root.folders.push(result);
146  if (name != "")
147  this.getFolderByGUID("{root}").content.push(result.GUID);
148  this._saveCurrent(); // save current state to prevent loss of data
149  return result;
150  } catch (e){
151  playlistfolders.central.logEvent("preferences",
152  "Adding of folder failed:\n\n" + e, 1,
153  "chrome://playlistfolders/content/" +
154  "preferences.js", e.lineNumber);
155  }
156  return null;
157  },
158 
159  /* Rename the given Folder
160  * folder (folder): the folder to rename
161  * name (string): the new name
162  */
163  renameFolder: function(folder, name){
164  playlistfolders.central.logEvent("preferences", "Rename folder " +
165  folder.GUID, 5);
166  try {
167  folder.name = name;
168  } catch (e){
169  playlistfolders.central.logEvent("preferences",
170  "Renaming folder failed:\n\n" + e, 1,
171  "chrome://playlistfolders/content/" +
172  "preferences.js", e.lineNumber);
173  }
174  this._saveCurrent(); // save current state to prevent loss of data
175  },
176 
177  /* Moves a folder and all sub-folders into another folder
178  * folder (folder): the folder to move
179  * targetF (folder): the target folder, or null for root folder
180  * before (string, optional): insert before this (guid)
181  */
182  moveFolder: function(folder, targetF, before){
183  playlistfolders.central.logEvent("preferences", "Move folder " +
184  folder.GUID, 5);
185  try {
186  var target = targetF;
187  if (!target)
188  target = this.getFolderByGUID("{root}");
189  // Search for current parent folder, and unlink it there
190  for each (var f in this._root.folders)
191  for (var i = 0; i < f.content.length; i++)
192  if (f.content[i] == folder.GUID)
193  f.content.splice(i,1);
194  // Register new sub-folder at target
195  var sort = false;
196  if (before)
197  for each (var guid in target.content)
198  if (guid == before)
199  sort = true;
200  if (sort) {
201  var tmp = [];
202  for each (var f in target.content){
203  if (f == before)
204  tmp.push(folder.GUID);
205  tmp.push(f);
206  }
207  target.content = tmp;
208  } else {
209  target.content.push(folder.GUID);
210  }
211  } catch (e){
212  playlistfolders.central.logEvent("preferences",
213  "Moving folder failed:\n\n" + e, 1,
214  "chrome://playlistfolders/content/" +
215  "preferences.js", e.lineNumber);
216  }
217  this._saveCurrent(); // save current state to prevent loss of data
218  },
219 
220  /* Moves a playlist into another folder
221  * pguid (string): the playlist's guid
222  * targetF (folder): the target folder or null for root folder
223  * before (string, optional): insert before this playlist (guid)
224  */
225  movePlaylist: function(pguid, targetF, before){
226  playlistfolders.central.logEvent("preferences", "Move playlist " +
227  pguid, 5);
228  try {
229  var target = targetF;
230  if (!target)
231  target = this.getFolderByGUID("{root}");
232  // Search for current parent folder, and unlink it there
233  for each (var f in this._root.folders)
234  for (var i = 0; i < f.content.length; i++)
235  if (f.content[i] == pguid)
236  f.content.splice(i,1);
237  // Register new sub-playlist at target
238  var sort = false;
239  if (before)
240  for each (var guid in target.content)
241  if (guid == before)
242  sort = true;
243  if (sort) {
244  var tmp = [];
245  for each (var p in target.content){
246  if (p == before)
247  tmp.push(pguid);
248  tmp.push(p);
249  }
250  target.content = tmp;
251  } else {
252  target.content.push(pguid);
253  }
254  } catch (e){
255  playlistfolders.central.logEvent("preferences",
256  "Moving playlist failed:\n\n" + e, 1,
257  "chrome://playlistfolders/content/" +
258  "preferences.js", e.lineNumber);
259  }
260  this._saveCurrent(); // save current state to prevent loss of data
261  },
262 
263  /* Removes the given Folder from the folder list, return true if succeed
264  * folder (folder): the folder to remove
265  * recursive (boolean): weather this should work even if there are subfolders
266  * or playlists (true) or not (false)
267  */
268  removeFolder: function(folder, recursive){
269  try {
270  playlistfolders.central.logEvent("preferences",
271  "Remove Folder " + folder.GUID, 5);
272  // Check if we need recursive deletion
273  if (folder.content.length){
274  if (!recursive){
275  playlistfolders.central.logEvent("preferences",
276  "Removing of folder failed:\n\n" +
277  folder.GUID + " is not empty" +
278  " folder", 1, "chrome://" +
279  "playlistfolders/content/" +
280  "preferences.js");
281  return;
282  }
283  var succeed = true;
284  for each (var GUID in folder.content){
285  if (this.isFolder(GUID)){
286  if (!this.removeFolder(this.getFolderByGUID(GUID), true))
287  succeed = false;
288  } else if (this.isPlaylist(GUID)){
289  if (!playlistfolders.central.removePlaylist(GUID))
290  succeed = false;
291  }
292  }
293  if (!succeed){
294  playlistfolders.central.logEvent("preferences",
295  "Removing of folder failed:\n\n" +
296  folder.GUID + " has content " +
297  "that can't get deleted", 1,
298  "chrome://playlistfolders/" +
299  "content/preferences.js");
300  return;
301  }
302  }
303  // Delete this folder
304  var deleted = false;
305  for (var i = 0; i < this._root.folders.length; i++){
306  if (this._root.folders[i] == folder){
307  this._root.folders.splice(i,1);
308  deleted = true;
309  }
310  }
311  // Delete references to this folder, if any
312  for each (var f in this._root.folders)
313  for (var i = 0; i < f.content.length; i++)
314  if (f.content[i] == folder.GUID)
315  f.content.splice(i,1);
316 
317  if (!deleted)
318  playlistfolders.central.logEvent("preferences",
319  "Removing of folder failed:\n\n" +
320  folder.GUID + " is no registered" +
321  " folder", 3, "chrome://" +
322  "playlistfolders/content/" +
323  "preferences.js");
324  else
325  return true;
326  } catch (e){
327  playlistfolders.central.logEvent("preferences",
328  "Removing of folder failed:\n\n" + e, 1,
329  "chrome://playlistfolders/content/" +
330  "preferences.js", e.lineNumber);
331  }
332  this._saveCurrent(); // save current state to prevent loss of data
333  },
334 
335  /* Remove the given Playlist from list WITHOUT deleting it
336  * playlist (string): guid of the playlist to remove
337  * folder (string): guid of parent folder of playlist
338  */
339  removePlaylist: function(playlist, folder){
340  try {
341  var plists = playlistfolders.preferences.getFolderByGUID(folder).content;
342  var deleted = false;
343  for (var i in plists)
344  if (plists[i] == playlist){
345  plists.splice(i,1);
346  deleted = true;
347  }
348  if (!deleted)
349  playlistfolders.central.logEvent("preferences", "Playlist to remove " +
350  "not found in parent folder.", 2,
351  "chrome://playlistfolders/content/" +
352  "preferences.js");
353  else
354  playlistfolders.central.logEvent("preferences", "Playlist " +
355  playlist + " removed in folder " +
356  folder + ".", 5);
357  } catch (e){
358  playlistfolders.central.logEvent("preferences",
359  "Removing of playlist failed:\n\n" + e,
360  1, "chrome://playlistfolders/content/" +
361  "preferences.js", e.lineNumber);
362  }
363  this._saveCurrent(); // save current state to prevent loss of data
364  },
365 
366  // Returns the array of all folders
367  getFolders: function(){
368  try {
369  return this._root.folders;
370  } catch (e){
371  playlistfolders.central.logEvent("preferences",
372  "Getting Folder list failed:\n\n" + e,
373  1, "chrome://playlistfolders/content/" +
374  "preferences.js",
375  e.lineNumber);
376  }
377  return null;
378  },
379 
380  /* Returns the folder with the given GUID
381  * guid (string): the GUID of the requested folder
382  */
383  getFolderByGUID: function(guid){
384  try {
385  for each (var f in this._root.folders){
386  if (f.GUID == guid)
387  return f;
388  }
389  playlistfolders.central.logEvent("preferences",
390  "Getting folder " + guid + " failed:" +
391  "\n\n" + guid + " is no registered " +
392  "folder", 1, "chrome://" +
393  "playlistfolders/content/" +
394  "preferences.js");
395  } catch (e){
396  playlistfolders.central.logEvent("preferences",
397  "Getting folder " + guid + " failed:" +
398  "\n\n" + e, 1, "chrome://" +
399  "playlistfolders/content/" +
400  "preferences.js", e.lineNumber);
401  }
402  return null;
403  },
404 
405  /* Return true, if given GUID belongs to a folder
406  * guid (string): guid to check
407  */
408  isFolder: function(guid){
409  // All GUIDs wrapped in {} are folders, currently
410  return guid[0] == "{";
411  },
412 
413  /* Return true, if given GUID belongs to a playlist
414  * guid (string): guid to check
415  */
416  isPlaylist: function(guid){
417  // All GUIDS not wrapped in {} are playlists, currently
418  return guid[0] != "{";
419  },
420 
421  // Return false if we should ask the user before deleting folders
422  isDeleteBypass: function(){
423  return this._prefs.getBoolPref("bypassdeletewarning");
424  },
425 
426  // Set the "do not ask me again" flag
427  doDeleteBypass: function(){
428  this._prefs.setBoolPref("bypassdeletewarning", true);
429  },
430 
431  /* Get the internal event logging level for Playlist Folders, return values:
432  * 0: do not log anything
433  * 1: log only fatal errors
434  * 2: log all errors (default)
435  * 3: log all errors and warnings
436  * 4: log all errors, warnings and essential debug messages
437  * 5: log everything
438  */
439  getEvtLogLevel: function(){
440  /* We can't use _prefs here because this function might be called before
441  * onLoad, hence we might want to log things before the preferences are up.
442  */
443  return Components.classes["@mozilla.org/preferences-service;1"].
444  getService(Components.interfaces.nsIPrefService).
445  getBranch("extensions.playlistfolders.").getIntPref("debugLevel");
446  },
447 };
getService(Ci.sbIFaceplateManager)
Lastfm onLoad
Definition: mini.js:36
return null
Definition: FeedWriter.js:1143
var prefs
Definition: FeedWriter.js:1169
Sanitizer _prefs
Definition: sanitize.js:435
var JSON
function onUnload()
onUnload - called when the cover preview window unloads.
Definition: coverPreview.js:36
_getSelectedPageStyle s i