commit 675fde2f1a894a7e824e19002a4febc439353250
parent 86c66115608330aedda34f2a950139ac2a33211c
Author: Dan Stillman <dstillman@zotero.org>
Date: Mon, 5 Aug 2013 16:31:23 -0400
Use async I/O for attachment (blue dot) column file check in Fx23+
Diffstat:
2 files changed, 114 insertions(+), 27 deletions(-)
diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js
@@ -2951,12 +2951,48 @@ Zotero.Item.prototype.getFilename = function () {
*
* This is updated only initially and on subsequent getFile() calls.
*/
-Zotero.Item.prototype.__defineGetter__('fileExists', function () {
- if (this._fileExists === null) {
+Zotero.Item.prototype.fileExists = function (cachedOnly) {
+ if (!cachedOnly && this._fileExists === null) {
this.getFile();
}
return this._fileExists;
-});
+};
+
+
+/**
+ * Asynchronous cached check for file existence, used for items view
+ *
+ * This is updated only initially and on subsequent getFile() calls.
+ */
+Zotero.Item.prototype.fileExistsAsync = function () {
+ var self = this;
+ return Q.fcall(function () {
+ if (self._fileExists !== null) {
+ return self._fileExists;
+ }
+
+ if (Zotero.platformMajorVersion < 23) {
+ return self.fileExists();
+ }
+
+ if (!self.isAttachment()) {
+ throw new Error("Zotero.Item.fileExistsAsync() can only be called on attachment items");
+ }
+
+ if (self.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_URL) {
+ throw new Error("Zotero.Item.fileExistsAsync() cannot be called on link attachments");
+ }
+
+ var nsIFile = self.getFile(null, true);
+ Components.utils.import("resource://gre/modules/osfile.jsm");
+ return Q(OS.File.exists(nsIFile.path))
+ .then(function(exists) {
+ self._updateAttachmentStates(exists);
+ return exists;
+ });
+ });
+};
+
/*
@@ -3611,16 +3647,46 @@ Zotero.Item.prototype.getBestAttachment = function() {
*
* @return {Integer} 0 (none), 1 (present), -1 (missing)
*/
-Zotero.Item.prototype.getBestAttachmentState = function () {
- if (this._bestAttachmentState !== null) {
+Zotero.Item.prototype.getBestAttachmentState = function (cachedOnly) {
+ if (cachedOnly || this._bestAttachmentState !== null) {
return this._bestAttachmentState;
}
var itemID = this.getBestAttachment();
- this._bestAttachmentState = itemID ? (Zotero.Items.get(itemID).fileExists ? 1 : -1) : 0;
+ this._bestAttachmentState = itemID
+ ? (Zotero.Items.get(itemID).fileExists() ? 1 : -1)
+ : 0;
return this._bestAttachmentState;
}
+/**
+ * Return cached state of best attachment for use in items view
+ *
+ * @return {Promise:Integer} Promise with 0 (none), 1 (present), -1 (missing)
+ */
+Zotero.Item.prototype.getBestAttachmentStateAsync = function () {
+ var self = this;
+ return Q.fcall(function() {
+ if (self._bestAttachmentState !== null) {
+ return self._bestAttachmentState;
+ }
+ var itemID = self.getBestAttachment();
+ if (itemID) {
+ return Zotero.Items.get(itemID).fileExistsAsync()
+ .then(function (exists) {
+ self._bestAttachmentState = exists ? 1 : -1;
+ });
+ }
+ else {
+ self._bestAttachmentState = 0;
+ }
+ })
+ .then(function () {
+ return self._bestAttachmentState;
+ });
+}
+
+
Zotero.Item.prototype.updateBestAttachmentState = function () {
this._bestAttachmentState = null;
}
diff --git a/chrome/content/zotero/xpcom/itemTreeView.js b/chrome/content/zotero/xpcom/itemTreeView.js
@@ -598,7 +598,8 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
// Clear item type icons
var items = Zotero.Items.get(ids);
for (let i=0; i<items.length; i++) {
- delete this._itemImages[items[i].id];
+ let id = items[i].id;
+ delete this._itemImages[id];
}
this.refresh();
@@ -612,7 +613,7 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
var items = Zotero.Items.get(ids);
for each(var item in items) {
- var id = item.id;
+ let id = item.id;
// Make sure row map is up to date
// if we made changes in a previous loop
@@ -691,8 +692,9 @@ Zotero.ItemTreeView.prototype.notify = function(action, type, ids, extraData)
var isTrash = itemGroup.isTrash();
var items = Zotero.Items.get(ids);
for each(var item in items) {
+ let id = item.id;
// Clear item type icon
- delete this._itemImages[item.id];
+ delete this._itemImages[id];
// If not viewing trash and all items were deleted, ignore modify
if (allDeleted && !isTrash && !item.deleted) {
@@ -1062,34 +1064,53 @@ Zotero.ItemTreeView.prototype.getImageSrc = function(row, col)
if (this._itemGroup.isTrash()) return false;
var treerow = this._getItemAtRow(row);
+ var item = treerow.ref;
if ((!this.isContainer(row) || !this.isContainerOpen(row))
- && Zotero.Sync.Storage.getItemDownloadImageNumber(treerow.ref)) {
+ && Zotero.Sync.Storage.getItemDownloadImageNumber(item)) {
return '';
}
+ var itemID = item.id;
+
if (treerow.level === 0) {
- if (treerow.ref.isRegularItem()) {
- switch (treerow.ref.getBestAttachmentState()) {
- case 1:
- return "chrome://zotero/skin/bullet_blue.png";
-
- case -1:
- return "chrome://zotero/skin/bullet_blue_empty.png";
-
- default:
- return "";
+ if (item.isRegularItem()) {
+ let state = item.getBestAttachmentState(true);
+ if (state !== null) {
+ switch (state) {
+ case 1:
+ return "chrome://zotero/skin/bullet_blue.png";
+
+ case -1:
+ return "chrome://zotero/skin/bullet_blue_empty.png";
+
+ default:
+ return "";
+ }
}
+
+ item.getBestAttachmentStateAsync()
+ // Refresh cell when promise is fulfilled
+ .then(function (state) {
+ this._treebox.invalidateCell(row, col);
+ }.bind(this))
+ .done();
}
}
- if (treerow.ref.isFileAttachment()) {
- if (treerow.ref.fileExists) {
- return "chrome://zotero/skin/bullet_blue.png";
- }
- else {
- return "chrome://zotero/skin/bullet_blue_empty.png";
+ if (item.isFileAttachment()) {
+ let exists = item.fileExists(true);
+ if (exists !== null) {
+ return exists
+ ? "chrome://zotero/skin/bullet_blue.png"
+ : "chrome://zotero/skin/bullet_blue_empty.png";
}
+
+ item.fileExistsAsync()
+ // Refresh cell when promise is fulfilled
+ .then(function (exists) {
+ this._treebox.invalidateCell(row, col);
+ }.bind(this));
}
}
}
@@ -1354,7 +1375,7 @@ Zotero.ItemTreeView.prototype.sort = function(itemID)
case 'hasAttachment':
getField = function (row) {
if (row.ref.isAttachment()) {
- var state = row.ref.fileExists ? 1 : -1;
+ var state = row.ref.fileExists() ? 1 : -1;
}
else if (row.ref.isRegularItem()) {
var state = row.ref.getBestAttachmentState();