Bug 492799 - nodeIsReadOnly should cache read-only item ids, r=mak77
authorDietrich Ayala <dietrich@mozilla.com>
Tue, 19 May 2009 01:06:50 +0200
changeset 28516 259b8094d8277254bebc4f41a5e184b0b8c0f22e
parent 28515 58346c44501fe155b5cc7194508fe261e2bc97bb
child 28517 95e15728ccae554eb1a21accef61105f5ff3f6ca
push id7104
push usermak77@bonardo.net
push dateMon, 18 May 2009 23:07:39 +0000
treeherdermozilla-central@652accbde683 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmak77
bugs492799
milestone1.9.2a1pre
Bug 492799 - nodeIsReadOnly should cache read-only item ids, r=mak77
toolkit/components/places/src/utils.js
--- a/toolkit/components/places/src/utils.js
+++ b/toolkit/components/places/src/utils.js
@@ -43,16 +43,19 @@ function LOG(str) {
   dump("*** " + str + "\n");
 }
 
 var EXPORTED_SYMBOLS = ["PlacesUtils"];
 
 var Ci = Components.interfaces;
 var Cc = Components.classes;
 var Cr = Components.results;
+var Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const EXCLUDE_FROM_BACKUP_ANNO = "places/excludeFromBackup";
 const POST_DATA_ANNO = "bookmarkProperties/POSTData";
 const READ_ONLY_ANNO = "placesInternal/READ_ONLY";
 const LMANNO_FEEDURI = "livemark/feedURI";
 const LMANNO_SITEURI = "livemark/siteURI";
 const LMANNO_EXPIRATION = "livemark/expiration";
 const LMANNO_LOADFAILED = "livemark/loadfailed";
@@ -252,28 +255,85 @@ var PlacesUtils = {
    *          A result node
    * @returns true if the node is a Query item, false otherwise
    */
   nodeIsQuery: function PU_nodeIsQuery(aNode) {
     return aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY;
   },
 
   /**
+   * Cache array of read-only item IDs.
+   *
+   * The first time this property is called:
+   * - the cache is filled with all ids with the RO annotation
+   * - an annotation observer is added
+   * - a shutdown observer is added
+   *
+   * When the annotation observer detects annotations added or
+   * removed that are the RO annotation name, it adds/removes
+   * the ids from the cache.
+   *
+   * At shutdown, the annotation and shutdown observers are removed.
+   */
+  get _readOnly() {
+    // add annotations observer
+    this.annotations.addObserver(this, false);
+
+    // observe shutdown, so we can remove the anno observer
+    const os = Cc["@mozilla.org/observer-service;1"].
+               getService(Ci.nsIObserverService);
+    os.addObserver(this, "xpcom-shutdown", false);
+
+    var readOnly = this.annotations.getItemsWithAnnotation(READ_ONLY_ANNO, {});
+    this.__defineGetter__("_readOnly", function() readOnly);
+    return this._readOnly;
+  },
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIAnnotationObserver,
+                                         Ci.nsIObserver]),
+
+  // nsIObserver
+  observe: function PU_observe(aSubject, aTopic, aData) {
+    if (aTopic == "xpcom-shutdown") {
+      this.annotations.removeObserver(this);
+      const os = Cc["@mozilla.org/observer-service;1"].
+                 getService(Ci.nsIObserverService);
+      os.removeObserver(this, "xpcom-shutdown");
+    }
+  },
+
+  // nsIAnnotationObserver
+  onItemAnnotationSet: function(aItemId, aAnnotationName) {
+    if (aAnnotationName == READ_ONLY_ANNO &&
+        this._readOnly.indexOf(aItemId) == -1)
+      this._readOnly.push(aItemId);
+  },
+  onItemAnnotationRemoved: function(aItemId, aAnnotationName) {
+    var index = this._readOnly.indexOf(aItemId);
+    if (aAnnotationName == READ_ONLY_ANNO && index > -1)
+      delete this._readOnly[index];
+  },
+  onPageAnnotationSet: function(aUri, aAnnotationName) {},
+  onPageAnnotationRemoved: function(aUri, aAnnotationName) {},
+
+  /**
    * Determines if a node is read only (children cannot be inserted, sometimes
    * they cannot be removed depending on the circumstance)
    * @param   aNode
    *          A result node
    * @returns true if the node is readonly, false otherwise
    */
   nodeIsReadOnly: function PU_nodeIsReadOnly(aNode) {
-    if (this.nodeIsFolder(aNode) || this.nodeIsDynamicContainer(aNode))
-      return this.bookmarks.getFolderReadonly(this.getConcreteItemId(aNode));
-    if (this.nodeIsQuery(aNode) &&
-        asQuery(aNode).queryOptions.resultType !=
-          Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_CONTENTS)
+    if (this.nodeIsFolder(aNode) || this.nodeIsDynamicContainer(aNode)) {
+      if (this._readOnly.indexOf(aNode.itemId) != -1)
+        return true;
+    }
+    else if (this.nodeIsQuery(aNode) &&
+             asQuery(aNode).queryOptions.resultType !=
+             Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_CONTENTS)
       return aNode.childrenReadOnly;
     return false;
   },
 
   /**
    * Determines whether or not a ResultNode is a host container.
    * @param   aNode
    *          A result node