implement 'busy' property and visuals for collections tree; fix inefficient 'mark all read' code.

This commit is contained in:
alta88 2009-07-05 09:04:45 -06:00
Родитель 8fa97ed3be
Коммит f1f696cd2a
6 изменённых файлов: 63 добавлений и 26 удалений

Просмотреть файл

@ -72,3 +72,14 @@
#sourcesViewTreeChildren::-moz-tree-image(hasNew) {
list-style-image: url("chrome://snowl/content/icons/asterisk_orange.png");
}
/* Collection loading/refreshing indicator */
#sourcesViewTreeChildren::-moz-tree-image(isBusy) {
/* XXX: argh, an animated image in the tree will cause a low level race condition
* which increases with number of rows with the image, after the image is no longer
* valid for a row property; no amount of view nulling etc etc could fix this.
* It seems the tree keeps invalidating itself once an anim image is loaded.
list-style-image: url("chrome://global/skin/icons/loading_16.png");
*/
list-style-image: url("chrome://snowl/content/icons/arrow_refresh_small.png");
}

Просмотреть файл

@ -195,7 +195,7 @@ let CollectionsView = {
Observers.add("snowl:source:added", this.onSourceAdded, this);
Observers.add("snowl:message:added", this.onMessageAdded, this);
Observers.add("snowl:source:removed", this.onSourceRemoved, this);
Observers.add("snowl:messages:changed", this.onMessagesComplete, this);
Observers.add("snowl:messages:completed", this.onMessagesCompleted, this);
Observers.add("itemchanged", this.onItemChanged, this);
if (this.gListOrRiver == "list")
Observers.add("snowl:author:removed", this.onSourceRemoved, this);
@ -206,7 +206,7 @@ let CollectionsView = {
Observers.remove("snowl:source:added", this.onSourceAdded, this);
Observers.remove("snowl:message:added", this.onMessageAdded, this);
Observers.remove("snowl:source:removed", this.onSourceRemoved, this);
Observers.remove("snowl:messages:changed", this.onMessagesComplete, this);
Observers.remove("snowl:messages:completed", this.onMessagesCompleted, this);
Observers.remove("itemchanged", this.onItemChanged, this);
if (this.gListOrRiver == "list")
Observers.remove("snowl:author:removed", this.onSourceRemoved, this);
@ -220,7 +220,7 @@ let CollectionsView = {
onSourceAdded: function(aPlaceID) {
//this._log.info("onSourceAdded: curIndex:curSelectedIndex = "+
// this._tree.currentIndex+" : "+this._tree.currentSelectedIndex);
// Newly subscribed source has been added to places, elect the inserted row.
// Newly subscribed source has been added to places, select the inserted row.
// The effect of selecting here is that onMessageAdded will trigger a view
// refresh for each message, so messages pop into the view as added.
this._tree.currentSelectedIndex = -1;
@ -244,12 +244,11 @@ let CollectionsView = {
}
},
onMessagesComplete: function(aSourceId) {
// Finished downloading all messages. Scroll the collection tree intelligently.
// SnowlUtils.scrollPlacement(this._tree, this._tree.currentIndex);
// Clear the collections stats cache and invalidate tree to rebuild.
SnowlService._collectionStatsByCollectionID = null;
onMessagesCompleted: function(aSourceId) {
// Source refresh completed, reset busy property.
if (SnowlService._sourcesByID[aSourceId])
SnowlService._sourcesByID[aSourceId].busy = false;
this._tree.treeBoxObject.invalidate();
},
@ -538,7 +537,7 @@ this._log.info("onClick: START itemIds - " +this.itemIds.toSource());
this._tree.view.nodeForTreeIndex(this._tree.currentSelectedIndex);
// Create places query object from tree item uri
let query = new SnowlQuery(selectedSource.uri);
if (query.queryGroupIDColumn != "sources.id")
if (!query.queryTypeSource)
return;
selectedSources.push(SnowlService.sourcesByID[query.queryID]);
@ -577,14 +576,14 @@ this._log.info("onClick: START itemIds - " +this.itemIds.toSource());
query += "authorID = " + authors.join(" OR authorID = ");
}
query = query ? " WHERE ( " + query + " AND" +
" (read = " + MESSAGE_UNREAD + " OR" +
" read = " + MESSAGE_NEW + ") )" : null;
query = query ? "( " + query + " ) AND " : null;
}
if (query != null) {
SnowlDatastore.dbConnection.executeSimpleSQL(
"UPDATE messages SET read = " + MESSAGE_READ + query);
"UPDATE messages SET read = " + MESSAGE_READ +
" WHERE " + query +
" (read = " + MESSAGE_UNREAD + " OR read = " + MESSAGE_NEW + ")");
gMessageViewWindow.SnowlMessageView.onFilter(this.Filters);
// Clear the collections stats cache and invalidate tree to rebuild.
@ -594,6 +593,7 @@ this._log.info("onClick: START itemIds - " +this.itemIds.toSource());
},
markCollectionNewState: function() {
//this._log.info("markCollectionNewState: START ");
// Mark all selected source/author collection messages as not new (unread)
// upon the collection being no longer selected. Note: shift-click on a
// collection will leave new state when unselected.
@ -1156,7 +1156,7 @@ PlacesTreeView.prototype.getCellProperties = SnowlTreeViewGetCellProperties;
function SnowlTreeViewGetCellProperties(aRow, aColumn, aProperties) {
this._getCellProperties(aRow, aColumn, aProperties);
let query, anno, propStr, propArr, prop, collID;
let query, anno, propStr, propArr, prop, collID, source;
let node = this._visibleElements[aRow].node;
query = new SnowlQuery(node.uri);
@ -1169,12 +1169,15 @@ function SnowlTreeViewGetCellProperties(aRow, aColumn, aProperties) {
(query.queryFolder == SnowlPlaces.collectionsSystemID ||
query.queryFolder == SnowlPlaces.collectionsSourcesID ||
query.queryFolder == SnowlPlaces.collectionsAuthorsID) ? "all" : null;
source = SnowlService._sourcesByID[query.queryID];
var nodeStats = SnowlService.getCollectionStatsByCollectionID()[collID];
if (nodeStats && nodeStats.u && !node.containerOpen)
aProperties.AppendElement(this._getAtomFor("hasUnread"));
if (nodeStats && nodeStats.n && !node.containerOpen)
aProperties.AppendElement(this._getAtomFor("hasNew"));
if (((source && source.busy) || (nodeStats && nodeStats.busy)) && !node.containerOpen)
aProperties.AppendElement(this._getAtomFor("isBusy"));
//if (nodeStats)
//SnowlPlaces._log.info("getCellProperties: itemId:title:stats - "+
@ -1232,10 +1235,16 @@ function SnowlTreeViewGetImageSrc(aRow, aColumn) {
// Custom handling for 'new' in collections.
let query = new SnowlQuery(node.uri);
let collID = query.queryTypeSource ? "s" + query.queryID :
query.queryTypeAuthor ? "a" + query.queryID : null;
query.queryTypeAuthor ? "a" + query.queryID :
(query.queryFolder == SnowlPlaces.collectionsSystemID ||
query.queryFolder == SnowlPlaces.collectionsSourcesID ||
query.queryFolder == SnowlPlaces.collectionsAuthorsID) ? "all" : null;
let nodeStats = SnowlService.getCollectionStatsByCollectionID()[collID];
if (nodeStats && nodeStats.n)
// Don't set icon, let css handle it for 'new'.
let source = SnowlService._sourcesByID[query.queryID];
if ((nodeStats && (nodeStats.n || nodeStats.busy)) || (source && source.busy))
// Don't set icon, let css handle it for 'new' or 'busy'. "all" collection
// (only) has a busy property so we can set an indicator on a closed container.
return "";
var icon = node.icon;
@ -1338,9 +1347,9 @@ PlacesUIUtils.getBestTitle =
nodeStats = SnowlService.getCollectionStatsByCollectionID()[collID];
if (nodeStats && collID == "all")
titleStats = " (New:" + nodeStats.n + "/Unread:" + nodeStats.u + "/Total:" + nodeStats.t + ")";
titleStats = " (New:" + nodeStats.n + " Unread:" + nodeStats.u + " Total:" + nodeStats.t + ")";
else if (nodeStats)
titleStats = " (" + nodeStats.n + "/" + nodeStats.u + "/" + nodeStats.t + ")";
titleStats = " (" + nodeStats.n + " " + nodeStats.u + " " + nodeStats.t + ")";
title = title + titleStats;
}

Двоичные данные
content/icons/asterisk_orange.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 760 B

Просмотреть файл

@ -865,7 +865,6 @@ let SnowlDatastore = {
},
_collectionStatsStatement: function(aType) {
// XXX: store MESSAGE_NEW on new msg instead of MESSAGE_UNREAD.
let typeID = aType == "*" ? "id" :
aType == "source" ? "sourceID" :
aType == "author" ? "authorID" : null;
@ -884,7 +883,7 @@ let SnowlDatastore = {
return statement;
},
collectionStatsByCollectionID: function(aType) {
collectionStatsByCollectionID: function() {
// Stats object for collections tree properties.
let statement, type, types = ["*", "source", "author"];
let collectionID, Total, Read, New, collectionStats = {};

Просмотреть файл

@ -275,6 +275,18 @@ let SnowlService = {
refreshAllSources: function(sources) {
let allSources = sources ? sources : this.sources;
// Set busy property, notify observer to invalidate tree.
for each (let source in allSources)
this._sourcesByID[source.id].busy = true;
if (allSources.length > 0) {
// Don't set busy on 'all' until we know when the last one is done so it
// can be unset.
// this._collectionStatsByCollectionID["all"].busy = true;
Observers.notify("snowl:messages:completed", "refresh");
}
// We specify the same refresh time when refreshing sources so that all
// new messages have the same received time, which makes messages sorted by
// received, then published times look better (more mixed together by
@ -346,7 +358,7 @@ let SnowlService = {
/**
* Return read, unread, new stats on author, source collections.
* *
*
* @returns {object} the t (total), u (unread), n (new) numbers for each
* source and author collection.
*/

Просмотреть файл

@ -49,6 +49,7 @@ Cu.import("resource://snowl/modules/URI.js");
Cu.import("resource://snowl/modules/constants.js");
Cu.import("resource://snowl/modules/datastore.js");
Cu.import("resource://snowl/modules/message.js");
Cu.import("resource://snowl/modules/service.js");
Cu.import("resource://snowl/modules/utils.js");
// FIXME: make strands.js into a module.
@ -191,6 +192,9 @@ SnowlSource.prototype = {
// How often to refresh sources, in milliseconds.
refreshInterval: 1000 * 60 * 30, // 30 minutes
// For adding isBusy property to collections tree.
busy: false,
id: null,
name: null,
@ -438,10 +442,12 @@ this._log.info("persist placeID:sources.id - " + this.placeID + " : " + this.id)
// Update the current flag.
this.updateCurrentMessages(currentMessageIDs);
// Notify list and collections views on completion of messages download, list
// also notified of each message addition.
if (messagesChanged)
Observers.notify("snowl:messages:changed", this.id);
// Invalidate stats cache on completion of refresh with new messages.
SnowlService._collectionStatsByCollectionID = null;
// Notify collections view on completion of refresh.
Observers.notify("snowl:messages:completed", this.id);
}),
unstore: function() {