diff --git a/chrome/content/zotero/xpcom/collectionTreeView.js b/chrome/content/zotero/xpcom/collectionTreeView.js index 2dce05c29..c8826a7bc 100644 --- a/chrome/content/zotero/xpcom/collectionTreeView.js +++ b/chrome/content/zotero/xpcom/collectionTreeView.js @@ -74,76 +74,13 @@ Zotero.CollectionTreeView.prototype.setTree = function(treebox) this.refresh(); - // Select the last-viewed collection - var lastViewedFolder = Zotero.Prefs.get('lastViewedFolder'); - var matches = lastViewedFolder.match(/^(?:(C|S|G)([0-9]+)|L)$/); - var select = 0; - if (matches) { - if (matches[1] == 'C') { - if (this._collectionRowMap[matches[2]]) { - select = this._collectionRowMap[matches[2]]; - } - // Search recursively - else { - var path = []; - var failsafe = 10; // Only go up ten levels - var lastCol = matches[2]; - do { - failsafe--; - var col = Zotero.Collections.get(lastCol); - if (!col) { - var msg = "Last-viewed collection not found"; - Zotero.debug(msg); - path = []; - break; - } - var par = col.getParent(); - if (!par) { - var msg = "Parent collection not found in " - + "Zotero.CollectionTreeView.setTree()"; - Zotero.debug(msg, 1); - Components.utils.reportError(msg); - path = []; - break; - } - lastCol = par; - path.push(lastCol); - } - while (!this._collectionRowMap[lastCol] && failsafe > 0) - if (path.length) { - for (var i=path.length-1; i>=0; i--) { - var id = path[i]; - var row = this._collectionRowMap[id]; - if (!row) { - var msg = "Collection not found in tree in " - + "Zotero.CollectionTreeView.setTree()"; - Zotero.debug(msg, 1); - Components.utils.reportError(msg); - break; - } - if (!this.isContainerOpen(row)) { - this.toggleOpenState(row); - if (this._collectionRowMap[matches[2]]) { - select = this._collectionRowMap[matches[2]]; - break; - } - } - } - } - } - } - else if (matches[1] == 'S' && this._searchRowMap[matches[2]]) { - select = this._searchRowMap[matches[2]]; - } - else if (matches[1] == 'G' && this._groupRowMap[matches[2]]) { - select = this._groupRowMap[matches[2]]; - } - } - this.selection.currentColumn = this._treebox.columns.getFirstColumn(); - this.selection.select(select); + + var row = this.getLastViewedRow(); + this.selection.select(row); } + /* * Reload the rows from the data access methods * (doesn't call the tree.invalidate methods, etc.) @@ -165,6 +102,13 @@ Zotero.CollectionTreeView.prototype.refresh = function() this._dataItems = []; this.rowCount = 0; + try { + var unfiledLibraries = Zotero.Prefs.get('unfiledLibraries').split(','); + } + catch (e) { + unfiledLibraries = []; + } + var self = this; var library = { id: null, @@ -190,6 +134,18 @@ Zotero.CollectionTreeView.prototype.refresh = function() } } + // Unfiled items + if (unfiledLibraries.indexOf('0') != -1) { + var s = new Zotero.Search; + // Give virtual search an id so it can be reselected automatically + s.id = 86345330000; // 'UNFILED' + '000' + libraryID + s.name = Zotero.getString('pane.collections.unfiled'); + s.addCondition('libraryID', 'is', null); + s.addCondition('unfiled', 'true'); + self._showItem(new Zotero.ItemGroup('search', s), 1, newRows+1); + newRows++; + } + var deletedItems = Zotero.Items.getDeleted(); if (deletedItems || Zotero.Prefs.get("showTrashWhenEmpty")) { self._showItem(new Zotero.ItemGroup('trash', false), 1, newRows+1); @@ -236,6 +192,18 @@ Zotero.CollectionTreeView.prototype.refresh = function() newRows++; } } + + // Unfiled items + if (unfiledLibraries.indexOf(groups[i].libraryID + '') != -1) { + var s = new Zotero.Search; + s.id = parseInt('8634533000' + groups[i].libraryID); // 'UNFILED' + '000' + libraryID + s.libraryID = groups[i].libraryID; + s.name = Zotero.getString('pane.collections.unfiled'); + s.addCondition('libraryID', 'is', groups[i].libraryID); + s.addCondition('unfiled', 'true'); + self._showItem(new Zotero.ItemGroup('search', s), 2); + newRows++; + } } } }; @@ -270,8 +238,6 @@ Zotero.CollectionTreeView.prototype.refresh = function() } } }; - Zotero.debug('============='); - Zotero.debug(commonsExpand); this._showItem(new Zotero.ItemGroup('header', header), null, null, commonsExpand); if (commonsExpand) { header.expand(); @@ -781,6 +747,78 @@ Zotero.CollectionTreeView.prototype.selectLibrary = function (libraryID) { return false; } +/** + * Select the last-viewed source + */ +Zotero.CollectionTreeView.prototype.getLastViewedRow = function () { + var lastViewedFolder = Zotero.Prefs.get('lastViewedFolder'); + var matches = lastViewedFolder.match(/^(?:(C|S|G)([0-9]+)|L)$/); + var select = 0; + if (matches) { + if (matches[1] == 'C') { + if (this._collectionRowMap[matches[2]]) { + select = this._collectionRowMap[matches[2]]; + } + // Search recursively + else { + var path = []; + var failsafe = 10; // Only go up ten levels + var lastCol = matches[2]; + do { + failsafe--; + var col = Zotero.Collections.get(lastCol); + if (!col) { + var msg = "Last-viewed collection not found"; + Zotero.debug(msg); + path = []; + break; + } + var par = col.getParent(); + if (!par) { + var msg = "Parent collection not found in " + + "Zotero.CollectionTreeView.setTree()"; + Zotero.debug(msg, 1); + Components.utils.reportError(msg); + path = []; + break; + } + lastCol = par; + path.push(lastCol); + } + while (!this._collectionRowMap[lastCol] && failsafe > 0) + if (path.length) { + for (var i=path.length-1; i>=0; i--) { + var id = path[i]; + var row = this._collectionRowMap[id]; + if (!row) { + var msg = "Collection not found in tree in " + + "Zotero.CollectionTreeView.setTree()"; + Zotero.debug(msg, 1); + Components.utils.reportError(msg); + break; + } + if (!this.isContainerOpen(row)) { + this.toggleOpenState(row); + if (this._collectionRowMap[matches[2]]) { + select = this._collectionRowMap[matches[2]]; + break; + } + } + } + } + } + } + else if (matches[1] == 'S' && this._searchRowMap[matches[2]]) { + select = this._searchRowMap[matches[2]]; + } + else if (matches[1] == 'G' && this._groupRowMap[matches[2]]) { + select = this._groupRowMap[matches[2]]; + } + } + + return select; +} + /* * Delete the selection @@ -1790,6 +1828,7 @@ Zotero.ItemGroup.prototype.getChildItems = function() Zotero.debug(e, 2); throw (e); } + return Zotero.Items.get(ids); } @@ -1826,7 +1865,7 @@ Zotero.ItemGroup.prototype.getSearchObject = function() { s.addCondition('deleted', 'true'); } else if (this.isSearch()) { - s.id = this.ref.id; + var s = this.ref; } else { throw ('Invalid search mode in Zotero.ItemGroup.getSearchObject()'); diff --git a/chrome/content/zotero/xpcom/search.js b/chrome/content/zotero/xpcom/search.js index 177b4f987..8cf11642a 100644 --- a/chrome/content/zotero/xpcom/search.js +++ b/chrome/content/zotero/xpcom/search.js @@ -1015,6 +1015,11 @@ Zotero.Search.prototype._buildQuery = function(){ var includeChildren = this._conditions[i]['operator'] == 'true'; continue; + case 'unfiled': + this._conditions[i]['operator'] + var unfiled = this._conditions[i]['operator'] == 'true'; + continue; + // Search subfolders case 'recursive': var recursive = this._conditions[i]['operator']=='true'; @@ -1063,6 +1068,15 @@ Zotero.Search.prototype._buildQuery = function(){ + "WHERE sourceItemID IS NOT NULL))"; } + if (unfiled) { + sql += " AND (itemID NOT IN (SELECT itemID FROM collectionItems) " + // Exclude children + + "AND itemID NOT IN " + + "(SELECT itemID FROM itemAttachments WHERE sourceItemID IS NOT NULL " + + "UNION SELECT itemID FROM itemNotes WHERE sourceItemID IS NOT NULL)" + + ")"; + } + if (this._hasPrimaryConditions) { sql += " AND "; @@ -1753,6 +1767,14 @@ Zotero.SearchConditions = new function(){ } }, + { + name: 'unfiled', + operators: { + true: true, + false: true + } + }, + { name: 'includeParentsAndChildren', operators: { @@ -2071,7 +2093,6 @@ Zotero.SearchConditions = new function(){ special: true }, - { name: 'fulltextContent', operators: { diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js index fe713bc6b..55a171e4c 100644 --- a/chrome/content/zotero/zoteroPane.js +++ b/chrome/content/zotero/zoteroPane.js @@ -56,7 +56,6 @@ var ZoteroPane = new function() this.itemSelected = itemSelected; this.reindexItem = reindexItem; this.duplicateSelectedItem = duplicateSelectedItem; - this.deleteSelectedCollection = deleteSelectedCollection; this.editSelectedCollection = editSelectedCollection; this.copySelectedItemsToClipboard = copySelectedItemsToClipboard; this.clearQuicksearch = clearQuicksearch; @@ -714,6 +713,55 @@ var ZoteroPane = new function() window.openDialog('chrome://zotero/content/searchDialog.xul','','chrome,modal',io); } + this.setUnfiled = function (libraryID, show) { + try { + var ids = Zotero.Prefs.get('unfiledLibraries').split(','); + } + catch (e) { + var ids = []; + } + + if (!libraryID) { + libraryID = 0; + } + + var newids = []; + for each(var id in ids) { + id = parseInt(id); + if (isNaN(id)) { + continue; + } + // Remove current library if hiding + if (id == libraryID && !show) { + continue; + } + // Remove libraryIDs that no longer exist + if (id != 0 && !Zotero.Libraries.exists(id)) { + continue; + } + newids.push(id); + } + + // Add the current library if it's not already set + if (show && newids.indexOf(libraryID) == -1) { + newids.push(libraryID); + } + + newids.sort(); + + Zotero.Prefs.set('unfiledLibraries', newids.join()); + + if (show) { + // 'UNFILED' + '000' + libraryID + Zotero.Prefs.set('lastViewedFolder', 'S' + '8634533000' + libraryID); + } + + this.collectionsView.refresh(); + + // Select new row + var row = this.collectionsView.getLastViewedRow(); + this.collectionsView.selection.select(row); + } this.openLookupWindow = function () { if (!Zotero.stateCheck()) { @@ -1306,17 +1354,20 @@ var ZoteroPane = new function() } } - function deleteSelectedCollection() - { + this.deleteSelectedCollection = function () { + // Remove virtual Unfiled search + var row = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex); + if (row.isSearch() && (row.ref.id + "").match(/^8634533000/)) { // 'UNFILED000' + this.setUnfiled(row.ref.libraryID, false); + return; + } + if (!this.canEdit()) { this.displayCannotEditLibraryMessage(); return; } if (this.collectionsView.selection.count == 1) { - var row = - this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex); - if (row.isCollection()) { if (confirm(Zotero.getString('pane.collections.delete'))) @@ -1797,16 +1848,17 @@ var ZoteroPane = new function() newSavedSearch: 1, newSubcollection: 2, sep1: 3, - editSelectedCollection: 4, - removeCollection: 5, - sep2: 6, - exportCollection: 7, - createBibCollection: 8, - exportFile: 9, - loadReport: 10, - emptyTrash: 11, - createCommonsBucket: 12, - refreshCommonsBucket: 13 + showUnfiled: 4, + editSelectedCollection: 5, + removeCollection: 6, + sep2: 7, + exportCollection: 8, + createBibCollection: 9, + exportFile: 10, + loadReport: 11, + emptyTrash: 12, + createCommonsBucket: 13, + refreshCommonsBucket: 14 }; var itemGroup = this.collectionsView._getItemAtRow(this.collectionsView.selection.currentIndex); @@ -1846,14 +1898,27 @@ var ZoteroPane = new function() } // Saved Search else if (itemGroup.isSearch()) { - show = [ - m.editSelectedCollection, - m.removeCollection, - m.sep2, - m.exportCollection, - m.createBibCollection, - m.loadReport - ]; + // Unfiled items view + if ((itemGroup.ref.id + "").match(/^8634533000/)) { // 'UNFILED000' + show = [ + m.removeCollection + ]; + + menu.childNodes[m.removeCollection].setAttribute('label', Zotero.getString('general.remove')); + } + // Normal search view + else { + show = [ + m.editSelectedCollection, + m.removeCollection, + m.sep2, + m.exportCollection, + m.createBibCollection, + m.loadReport + ]; + + menu.childNodes[m.removeCollection].setAttribute('label', Zotero.getString('pane.collections.menu.remove.savedSearch')); + } var s = [m.exportCollection, m.createBibCollection, m.loadReport]; if (this.itemsView.rowCount>0) { @@ -1865,7 +1930,6 @@ var ZoteroPane = new function() // Adjust labels menu.childNodes[m.editSelectedCollection].setAttribute('label', Zotero.getString('pane.collections.menu.edit.savedSearch')); - menu.childNodes[m.removeCollection].setAttribute('label', Zotero.getString('pane.collections.menu.remove.savedSearch')); menu.childNodes[m.exportCollection].setAttribute('label', Zotero.getString('pane.collections.menu.export.savedSearch')); menu.childNodes[m.createBibCollection].setAttribute('label', Zotero.getString('pane.collections.menu.createBib.savedSearch')); menu.childNodes[m.loadReport].setAttribute('label', Zotero.getString('pane.collections.menu.generateReport.savedSearch')); @@ -1884,12 +1948,12 @@ var ZoteroPane = new function() } // Group else if (itemGroup.isGroup()) { - show = [m.newCollection, m.newSavedSearch]; + show = [m.newCollection, m.newSavedSearch, m.sep1, m.showUnfiled]; } // Library else { - show = [m.newCollection, m.newSavedSearch, m.sep1, m.exportFile]; + show = [m.newCollection, m.newSavedSearch, m.sep1, m.showUnfiled, m.sep2, m.exportFile]; } // Disable some actions if user doesn't have write access diff --git a/chrome/content/zotero/zoteroPane.xul b/chrome/content/zotero/zoteroPane.xul index 9fb37eccf..5dd8d9f60 100644 --- a/chrome/content/zotero/zoteroPane.xul +++ b/chrome/content/zotero/zoteroPane.xul @@ -216,6 +216,7 @@ + diff --git a/chrome/locale/en-US/zotero/searchbox.dtd b/chrome/locale/en-US/zotero/searchbox.dtd index 8f0843502..406f9be08 100644 --- a/chrome/locale/en-US/zotero/searchbox.dtd +++ b/chrome/locale/en-US/zotero/searchbox.dtd @@ -6,7 +6,7 @@ - + diff --git a/chrome/locale/en-US/zotero/zotero.dtd b/chrome/locale/en-US/zotero/zotero.dtd index 4b57c0d53..d5562076d 100644 --- a/chrome/locale/en-US/zotero/zotero.dtd +++ b/chrome/locale/en-US/zotero/zotero.dtd @@ -37,6 +37,8 @@ + + diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties index 0fa179c25..23934d134 100644 --- a/chrome/locale/en-US/zotero/zotero.properties +++ b/chrome/locale/en-US/zotero/zotero.properties @@ -33,6 +33,7 @@ general.create = Create general.seeForMoreInformation = See %S for more information. general.enable = Enable general.disable = Disable +general.remove = Remove general.operationInProgress = A Zotero operation is currently in progress. general.operationInProgress.waitUntilFinished = Please wait until it has finished. @@ -108,6 +109,7 @@ pane.collections.rename = Rename collection: pane.collections.library = My Library pane.collections.trash = Trash pane.collections.untitled = Untitled +pane.collections.unfiled = Unfiled Items pane.collections.menu.rename.collection = Rename Collection... pane.collections.menu.edit.savedSearch = Edit Saved Search