www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

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:
Mchrome/content/zotero/xpcom/data/item.js | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Mchrome/content/zotero/xpcom/itemTreeView.js | 63++++++++++++++++++++++++++++++++++++++++++---------------------
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();