Mercurial > snowl
changeset 355:e9d7087abad1
implement tree (list and collection) contextmenu foundation, change XXX Utils to DateUtils, some click handling fixes.
author | alta88 |
---|---|
date | Sun, 02 Nov 2008 10:20:12 -0700 |
parents | 3af68614eb52 |
children | 8d90feea857c |
files | content/collections.js content/collections.xul content/list-sidebar.js content/list.js content/list.xul content/message/message.js content/river.js content/stream.js locale/en-US/collections.dtd locale/en-US/list.dtd modules/collection.js modules/feed.js modules/message.js modules/service.js modules/source.js modules/twitter.js modules/utils.js |
diffstat | 17 files changed, 269 insertions(+), 104 deletions(-) [+] |
line wrap: on
line diff
--- a/content/collections.js Wed Oct 29 18:36:16 2008 -0600 +++ b/content/collections.js Sun Nov 02 10:20:12 2008 -0700 @@ -86,14 +86,7 @@ // Ensure collection selection maintained, if in List sidebar if (document.getElementById("snowlSidebar")) - this._tree.view.selection.select( - gMessageViewWindow.SnowlMessageView._listCollectionIndex); - - // Add a capturing click listener to the tree so we can find out if the user - // clicked on a row that is already selected (in which case we let them edit - // the collection name). - // FIXME: disable this for names that can't be changed. - this._tree.addEventListener("mousedown", function(aEvent) { CollectionsView.onClick(aEvent) }, true); + this._tree.view.selection.select(SnowlUtils.gListViewCollectionIndex); }, @@ -314,25 +307,21 @@ }, onSelect: function(aEvent) { - if (this._tree.currentIndex == -1) + if (this._tree.currentIndex == -1 || SnowlUtils.gRightMouseButtonDown) return; let collection = this._rows[this._tree.currentIndex]; - let index = this._tree.currentIndex; - gMessageViewWindow.SnowlMessageView.setCollection(collection, index); + SnowlUtils.gListViewCollectionIndex = this._tree.currentIndex; + gMessageViewWindow.SnowlMessageView.setCollection(collection); }, - onClick: function(aEvent) { -this._log.info("on click"); -//this._log.info(Log4Moz.enumerateProperties(aEvent).join("\n")); -//this._log.info(aEvent.target.nodeName); + onCollectionsTreeMouseDown: function(aEvent) { + SnowlUtils.onTreeMouseDown(aEvent, this._tree); + }, - let row = {}, col = {}, child = {}; - this._tree.treeBoxObject.getCellAt(aEvent.clientX, aEvent.clientY, row, col, child); - if (this._tree.view.selection.isSelected(row.value)) -this._log.info(row.value + " is selected"); -else -this._log.info(row.value + " is not selected"); + onTreeContextPopupHidden: function() { + if (!SnowlUtils.gSelectOnRtClick) + SnowlUtils.RestoreSelectionWithoutContentLoad(this._tree); }, unsubscribe: function() {
--- a/content/collections.xul Wed Oct 29 18:36:16 2008 -0600 +++ b/content/collections.xul Sun Nov 02 10:20:12 2008 -0700 @@ -45,13 +45,24 @@ <script type="application/x-javascript" src="chrome://snowl/content/collections.js"/> <vbox id="collectionsViewBox"> - <tree id="sourcesView" flex="1" context="sourcesContextMenu" editable="true" + + <!-- Collection context --> + <popup id="snowlCollectionContext" + onpopuphidden="CollectionsView.onTreeContextPopupHidden(event)"> + <menuitem id="snowlCollectionRefreshMenuitem" + label="&refreshAll.label;" + accesskey="&refreshAll.accesskey;" + oncommand="SnowlService.refreshAllSources();"/> + </popup> + + <tree id="sourcesView" flex="1" editable="true" onselect="CollectionsView.onSelect(event)"> <treecols> <treecol id="nameCol" label="&nameCol.label;" primary="true" flex="1"/> </treecols> - <treechildren flex="1"/> + <treechildren flex="1" context="snowlCollectionContext" + onmousedown="CollectionsView.onCollectionsTreeMouseDown(event)"/> </tree> <toolbar id="snowlToolbar"/>
--- a/content/list-sidebar.js Wed Oct 29 18:36:16 2008 -0600 +++ b/content/list-sidebar.js Sun Nov 02 10:20:12 2008 -0700 @@ -39,6 +39,9 @@ const Cr = Components.results; const Cu = Components.utils; +//modules that are Snowl-specific +Cu.import("resource://snowl/modules/utils.js"); + let gBrowserWindow = window.QueryInterface(Ci.nsIInterfaceRequestor). getInterface(Ci.nsIWebNavigation). QueryInterface(Ci.nsIDocShellTreeItem).
--- a/content/list.js Wed Oct 29 18:36:16 2008 -0600 +++ b/content/list.js Sun Nov 02 10:20:12 2008 -0700 @@ -108,10 +108,6 @@ return this._unreadButton = document.getElementById("snowlUnreadButton"); }, - // Always maintain selected collection within a session, only for List view - // XXX store on document for restore on restart?? - _listCollectionIndex: null, - // Maps XUL tree column IDs to collection properties. _columnProperties: { "snowlAuthorCol": "author", @@ -137,7 +133,7 @@ case "snowlSubjectCol": return this._collection.messages[aRow].subject; case "snowlTimestampCol": - return SnowlUtils._formatDate(this._collection.messages[aRow].timestamp); + return SnowlDateUtils._formatDate(this._collection.messages[aRow].timestamp); default: return null; } @@ -190,9 +186,8 @@ SnowlMessageView._snowlSidebar.hidden = (aEvent.newValue == "true"); }, false); - // Restore previous layout view + // Restore previous layout, if error or first time default to 'classic' view let layout = Snowl._mainWindow.getAttribute("snowllayout"); - // If error or first time default to 'classic' view let layoutIndex = Snowl.layoutName.indexOf(layout) < 0 ? this.kClassicLayout : Snowl.layoutName.indexOf(layout); this.layout(layoutIndex); @@ -295,9 +290,8 @@ this._rebuildView(); }, - setCollection: function(collection, index) { + setCollection: function(collection) { this._collection = collection; - this._listCollectionIndex = index; this._rebuildView(); }, @@ -410,7 +404,8 @@ }, onSelect: function(aEvent) { - if (this._tree.currentIndex == -1) +this._log.info("onSelect - start: event.target.id = "+aEvent.target.id); + if (this._tree.currentIndex == -1 || SnowlUtils.gRightMouseButtonDown) return; // When we support opening multiple links in the background, @@ -424,6 +419,7 @@ let url = "chrome://snowl/content/message/message.xul?id=" + message.id; window.loadURI(url, null, null, false); + SnowlUtils.gListViewListIndex = row; this._setRead(true); }, @@ -440,6 +436,8 @@ this._toggleRead(true); else if (aEvent.charCode == " ".charCodeAt(0)) this._onSpacePress(aEvent); + else if (aEvent.keyCode == "13") + this._openListMessage(aEvent); }, // Based on SpaceHit in mailWindowOverlay.js @@ -527,13 +525,15 @@ }, onClickColumnHeader: function(aEvent) { + // Only for left click, button = 0.. + if (aEvent.button != 0) + return; + let column = aEvent.target; let property = this._columnProperties[column.id]; let sortResource = this._tree.getAttribute("sortResource"); let sortDirection = this._tree.getAttribute("sortDirection"); - // FIXME: don't sort if the user right- or middle-clicked the header. - // Determine the sort order. If the user clicked on the header for // the current sort column, we sort in the reverse of the current order. // Otherwise we sort in ascending order. @@ -566,7 +566,21 @@ this._collection.sortProperties = [property]; this._collection.sortOrder = order; this._collection.sort(); - } + }, + + _openListMessage: function(event) { +alert("openlistmessage"); + }, + + onListTreeMouseDown: function(aEvent) { + SnowlUtils.onTreeMouseDown(aEvent, this._tree); + }, + + onTreeContextPopupHidden: function(aEvent) { + if (!SnowlUtils.gSelectOnRtClick) + SnowlUtils.RestoreSelectionWithoutContentLoad(this._tree); + }, + }; window.addEventListener("load", function() { SnowlMessageView.init() }, false);
--- a/content/list.xul Wed Oct 29 18:36:16 2008 -0600 +++ b/content/list.xul Sun Nov 02 10:20:12 2008 -0700 @@ -49,7 +49,21 @@ <window id="main-window" persist="screenX screenY width height sizemode snowllayout snowltabindex snowlcollectionindex" - snowllayout="classic"/> + snowllayout="classic"> + + <!-- Apparently Popup can not be child of mainPopupSet, otherwise popup hide + click is sent as select event. This effect is not bad but could not be + recreated in the collections sidebar tree context popup. Quirky xul here. --> + <popup id="snowlListContext" + onpopuphidden="SnowlMessageView.onTreeContextPopupHidden(event)"> + <menuitem id="snowlOpenListMessageMenuitem" + disabled="true" + label="&openListMessage.label;" + accesskey="&openListMessage.accesskey;" + oncommand="SnowlMessageView._openListMessage(event)"/> + </popup> + + </window> <hbox id="browser"> <hbox id="snowlSidebar" @@ -112,7 +126,8 @@ onclick="SnowlMessageView.onClickColumnHeader(event)"/> </treecols> - <treechildren flex="1"/> + <treechildren flex="1" context="snowlListContext" + onmousedown="SnowlMessageView.onListTreeMouseDown(event)"/> </tree> </vbox>
--- a/content/message/message.js Wed Oct 29 18:36:16 2008 -0600 +++ b/content/message/message.js Sun Nov 02 10:20:12 2008 -0700 @@ -87,13 +87,13 @@ document.getElementById("briefAuthor").value = message.author; document.getElementById("briefSubject").value = message.subject; document.getElementById("briefSubject").setAttribute("href", message.link); -document.getElementById("briefTimestamp").value = SnowlUtils._formatDate(message.timestamp); +document.getElementById("briefTimestamp").value = SnowlDateUtils._formatDate(message.timestamp); // Full headers document.getElementById("author").value = message.author; document.getElementById("subject").value = message.subject; document.documentElement.setAttribute("title", message.subject); -document.getElementById("timestamp").value = SnowlUtils._formatDate(message.timestamp); +document.getElementById("timestamp").value = SnowlDateUtils._formatDate(message.timestamp); document.getElementById("link").href = message.link; document.getElementById("link").value = message.link;
--- a/content/river.js Wed Oct 29 18:36:16 2008 -0600 +++ b/content/river.js Sun Nov 02 10:20:12 2008 -0700 @@ -123,13 +123,13 @@ switch (this._periodMenu.selectedItem.value) { case "today": - return SnowlUtils.jsToJulianDate(SnowlUtils.today); + return SnowlDateUtils.jsToJulianDate(SnowlDateUtils.today); case "yesterday": - return SnowlUtils.jsToJulianDate(SnowlUtils.yesterday); + return SnowlDateUtils.jsToJulianDate(SnowlDateUtils.yesterday); case "last7days": - return SnowlUtils.jsToJulianDate(SnowlUtils.sixDaysAgo.epoch); + return SnowlDateUtils.jsToJulianDate(SnowlDateUtils.sixDaysAgo.epoch); case "last4weeks": - return SnowlUtils.jsToJulianDate(SnowlUtils.twentySevenDaysAgo.epoch); + return SnowlDateUtils.jsToJulianDate(SnowlDateUtils.twentySevenDaysAgo.epoch); case "all": default: return 0; @@ -147,7 +147,7 @@ // messages received in the future from these categories, but since that // situation is exceptional, it's probably better to show those. case "yesterday": - return SnowlUtils.jsToJulianDate(SnowlUtils.today); + return SnowlDateUtils.jsToJulianDate(SnowlDateUtils.today); case "today": case "last7days": case "last4weeks": @@ -284,7 +284,7 @@ _setMidnightTimout: function() { let t = this; let now = new Date(); - let msUntilMidnight = SnowlUtils.tomorrow - now; + let msUntilMidnight = SnowlDateUtils.tomorrow - now; this._log.info("setting midnight timeout for " + new Date(now.getTime() + msUntilMidnight)); window.setTimeout(function() { t.onMidnight() }, msUntilMidnight); }, @@ -650,43 +650,43 @@ _groups: { today: [ { name: "The Future", epoch: Number.MAX_VALUE }, - { name: "Evening", epoch: SnowlUtils.evening(SnowlUtils.today) }, - { name: "Afternoon", epoch: SnowlUtils.afternoon(SnowlUtils.today) }, - { name: "Morning", epoch: SnowlUtils.morning(SnowlUtils.today) }, - { name: "Wee Hours", epoch: SnowlUtils.today }, + { name: "Evening", epoch: SnowlDateUtils.evening(SnowlDateUtils.today) }, + { name: "Afternoon", epoch: SnowlDateUtils.afternoon(SnowlDateUtils.today) }, + { name: "Morning", epoch: SnowlDateUtils.morning(SnowlDateUtils.today) }, + { name: "Wee Hours", epoch: SnowlDateUtils.today }, { name: "Older", epoch: 0 } ], yesterday: [ { name: "The Future", epoch: Number.MAX_VALUE }, - { name: "Evening", epoch: SnowlUtils.evening(SnowlUtils.yesterday) }, - { name: "Afternoon", epoch: SnowlUtils.afternoon(SnowlUtils.yesterday) }, - { name: "Morning", epoch: SnowlUtils.morning(SnowlUtils.yesterday) }, - { name: "Wee Hours", epoch: SnowlUtils.yesterday }, + { name: "Evening", epoch: SnowlDateUtils.evening(SnowlDateUtils.yesterday) }, + { name: "Afternoon", epoch: SnowlDateUtils.afternoon(SnowlDateUtils.yesterday) }, + { name: "Morning", epoch: SnowlDateUtils.morning(SnowlDateUtils.yesterday) }, + { name: "Wee Hours", epoch: SnowlDateUtils.yesterday }, { name: "Older", epoch: 0 } ], last7days: [ { name: "The Future", epoch: Number.MAX_VALUE }, - { name: "Today", epoch: SnowlUtils.today }, - { name: "Yesterday", epoch: SnowlUtils.yesterday }, - { name: SnowlUtils.twoDaysAgo.name, epoch: SnowlUtils.twoDaysAgo.epoch }, - { name: SnowlUtils.threeDaysAgo.name, epoch: SnowlUtils.threeDaysAgo.epoch }, - { name: SnowlUtils.fourDaysAgo.name, epoch: SnowlUtils.fourDaysAgo.epoch }, - { name: SnowlUtils.fiveDaysAgo.name, epoch: SnowlUtils.fiveDaysAgo.epoch }, - { name: SnowlUtils.sixDaysAgo.name, epoch: SnowlUtils.sixDaysAgo.epoch }, + { name: "Today", epoch: SnowlDateUtils.today }, + { name: "Yesterday", epoch: SnowlDateUtils.yesterday }, + { name: SnowlDateUtils.twoDaysAgo.name, epoch: SnowlDateUtils.twoDaysAgo.epoch }, + { name: SnowlDateUtils.threeDaysAgo.name, epoch: SnowlDateUtils.threeDaysAgo.epoch }, + { name: SnowlDateUtils.fourDaysAgo.name, epoch: SnowlDateUtils.fourDaysAgo.epoch }, + { name: SnowlDateUtils.fiveDaysAgo.name, epoch: SnowlDateUtils.fiveDaysAgo.epoch }, + { name: SnowlDateUtils.sixDaysAgo.name, epoch: SnowlDateUtils.sixDaysAgo.epoch }, { name: "Older", epoch: 0 } ], last4weeks: [ { name: "The Future", epoch: Number.MAX_VALUE }, - { name: "Week One", epoch: SnowlUtils.tomorrow - (SnowlUtils.msInDay * 7) }, - { name: "Week Two", epoch: SnowlUtils.tomorrow - (SnowlUtils.msInDay * 14) }, - { name: "Week Three", epoch: SnowlUtils.tomorrow - (SnowlUtils.msInDay * 21) }, - { name: "Week Four", epoch: SnowlUtils.tomorrow - (SnowlUtils.msInDay * 28) }, + { name: "Week One", epoch: SnowlDateUtils.tomorrow - (SnowlDateUtils.msInDay * 7) }, + { name: "Week Two", epoch: SnowlDateUtils.tomorrow - (SnowlDateUtils.msInDay * 14) }, + { name: "Week Three", epoch: SnowlDateUtils.tomorrow - (SnowlDateUtils.msInDay * 21) }, + { name: "Week Four", epoch: SnowlDateUtils.tomorrow - (SnowlDateUtils.msInDay * 28) }, { name: "Older", epoch: 0 } ], all: [ { name: "The Future", epoch: Number.MAX_VALUE }, - { name: "Today", epoch: SnowlUtils.today }, - { name: "Yesterday", epoch: SnowlUtils.yesterday }, + { name: "Today", epoch: SnowlDateUtils.today }, + { name: "Yesterday", epoch: SnowlDateUtils.yesterday }, { name: "Older", epoch: 0 } ] }, @@ -783,7 +783,7 @@ bylineBox.appendChild(this._document.createTextNode(message.source.name)); //// Timestamp - //let lastUpdated = SnowlUtils._formatDate(message.timestamp); + //let lastUpdated = SnowlDateUtils._formatDate(message.timestamp); //if (lastUpdated) { // let timestamp = this._document.createElementNS(HTML_NS, "span"); // timestamp.className = "timestamp";
--- a/content/stream.js Wed Oct 29 18:36:16 2008 -0600 +++ b/content/stream.js Sun Nov 02 10:20:12 2008 -0700 @@ -183,7 +183,7 @@ _setMidnightTimout: function() { let t = this; let now = new Date(); - let msUntilMidnight = SnowlUtils.tomorrow - now; + let msUntilMidnight = SnowlDateUtils.tomorrow - now; this._log.info("setting midnight timeout for " + new Date(now.getTime() + msUntilMidnight)); window.setTimeout(function() { t.onMidnight() }, msUntilMidnight); }, @@ -351,13 +351,13 @@ let groups = [ { name: "The Future", epoch: Number.MAX_VALUE }, - { name: "Today", epoch: SnowlUtils.today }, - { name: "Yesterday", epoch: SnowlUtils.yesterday }, - { name: SnowlUtils.twoDaysAgo.name, epoch: SnowlUtils.twoDaysAgo.epoch }, - { name: SnowlUtils.threeDaysAgo.name, epoch: SnowlUtils.threeDaysAgo.epoch }, - { name: SnowlUtils.fourDaysAgo.name, epoch: SnowlUtils.fourDaysAgo.epoch }, - { name: SnowlUtils.fiveDaysAgo.name, epoch: SnowlUtils.fiveDaysAgo.epoch }, - { name: SnowlUtils.sixDaysAgo.name, epoch: SnowlUtils.sixDaysAgo.epoch }, + { name: "Today", epoch: SnowlDateUtils.today }, + { name: "Yesterday", epoch: SnowlDateUtils.yesterday }, + { name: SnowlDateUtils.twoDaysAgo.name, epoch: SnowlDateUtils.twoDaysAgo.epoch }, + { name: SnowlDateUtils.threeDaysAgo.name, epoch: SnowlDateUtils.threeDaysAgo.epoch }, + { name: SnowlDateUtils.fourDaysAgo.name, epoch: SnowlDateUtils.fourDaysAgo.epoch }, + { name: SnowlDateUtils.fiveDaysAgo.name, epoch: SnowlDateUtils.fiveDaysAgo.epoch }, + { name: SnowlDateUtils.sixDaysAgo.name, epoch: SnowlDateUtils.sixDaysAgo.epoch }, { name: "Older", epoch: 0 } ]; @@ -445,7 +445,7 @@ // by time received. Instead, we're going to group by time period // received (this morning, yesterday, last week, etc.) to give users // useful chronographic info. - //let lastUpdated = SnowlUtils._formatDate(message.timestamp); + //let lastUpdated = SnowlDateUtils._formatDate(message.timestamp); //if (lastUpdated) { // let timestamp = this._document.createElementNS(XUL_NS, "description"); // timestamp.className = "timestamp";
--- a/locale/en-US/collections.dtd Wed Oct 29 18:36:16 2008 -0600 +++ b/locale/en-US/collections.dtd Sun Nov 02 10:20:12 2008 -0700 @@ -1,1 +1,5 @@ -<!ENTITY nameCol.label "Name"> +<!ENTITY nameCol.label "Name"> + +<!-- Collections contextmenu --> +<!ENTITY refreshAll.label "Refresh All"> +<!ENTITY refreshAll.accesskey "A">
--- a/locale/en-US/list.dtd Wed Oct 29 18:36:16 2008 -0600 +++ b/locale/en-US/list.dtd Sun Nov 02 10:20:12 2008 -0700 @@ -7,3 +7,6 @@ <!ENTITY authorCol.label "Author"> <!ENTITY subjectCol.label "Subject"> <!ENTITY timestampCol.label "Date"> + +<!ENTITY openListMessage.label "Open Message"> +<!ENTITY openListMessage.accesskey "O">
--- a/modules/collection.js Wed Oct 29 18:36:16 2008 -0600 +++ b/modules/collection.js Sun Nov 02 10:20:12 2008 -0700 @@ -254,10 +254,10 @@ statement.row.subject, statement.row.author, statement.row.link, - SnowlUtils.julianToJSDate(statement.row.timestamp), + SnowlDateUtils.julianToJSDate(statement.row.timestamp), (statement.row.read ? true : false), statement.row.authorIcon, - SnowlUtils.julianToJSDate(statement.row.received)); + SnowlDateUtils.julianToJSDate(statement.row.received)); this._messages.push(message); this._messageIndex[message.id] = message; }
--- a/modules/feed.js Wed Oct 29 18:36:16 2008 -0600 +++ b/modules/feed.js Sun Nov 02 10:20:12 2008 -0700 @@ -468,8 +468,8 @@ aExternalID, aSubject, aAuthorID, - SnowlUtils.jsToJulianDate(aTimestamp), - SnowlUtils.jsToJulianDate(aReceived), + SnowlDateUtils.jsToJulianDate(aTimestamp), + SnowlDateUtils.jsToJulianDate(aReceived), aLink ? aLink.spec : null); return messageID;
--- a/modules/message.js Wed Oct 29 18:36:16 2008 -0600 +++ b/modules/message.js Sun Nov 02 10:20:12 2008 -0700 @@ -86,10 +86,10 @@ statement.row.subject, statement.row.author, statement.row.link, - SnowlUtils.julianToJSDate(statement.row.timestamp), + SnowlDateUtils.julianToJSDate(statement.row.timestamp), (statement.row.read ? true : false), statement.row.authorIcon, - SnowlUtils.julianToJSDate(statement.row.received)); + SnowlDateUtils.julianToJSDate(statement.row.received)); } } finally {
--- a/modules/service.js Wed Oct 29 18:36:16 2008 -0600 +++ b/modules/service.js Sun Nov 02 10:20:12 2008 -0700 @@ -243,7 +243,7 @@ row.name, URI.get(row.machineURI), URI.get(row.humanURI), - SnowlUtils.julianToJSDate(row.lastRefreshed), + SnowlDateUtils.julianToJSDate(row.lastRefreshed), row.importance)); } }
--- a/modules/source.js Wed Oct 29 18:36:16 2008 -0600 +++ b/modules/source.js Sun Nov 02 10:20:12 2008 -0700 @@ -81,7 +81,7 @@ this._getStatement.row.name, URI.get(this._getStatement.row.machineURI), URI.get(this._getStatement.row.humanURI), - SnowlUtils.julianToJSDate(this._getStatement.row.lastRefreshed), + SnowlDateUtils.julianToJSDate(this._getStatement.row.lastRefreshed), this._getStatement.row.importance); } finally { @@ -134,7 +134,7 @@ let stmt = SnowlDatastore.createStatement("UPDATE sources " + "SET lastRefreshed = :lastRefreshed " + "WHERE id = :id"); - stmt.params.lastRefreshed = SnowlUtils.jsToJulianDate(this._lastRefreshed); + stmt.params.lastRefreshed = SnowlDateUtils.jsToJulianDate(this._lastRefreshed); stmt.params.id = this.id; stmt.execute(); },
--- a/modules/twitter.js Wed Oct 29 18:36:16 2008 -0600 +++ b/modules/twitter.js Sun Nov 02 10:20:12 2008 -0700 @@ -474,8 +474,8 @@ aExternalID, aSubject, aAuthorID, - SnowlUtils.jsToJulianDate(aTimestamp), - SnowlUtils.jsToJulianDate(aReceived), + SnowlDateUtils.jsToJulianDate(aTimestamp), + SnowlDateUtils.jsToJulianDate(aReceived), aLink ? aLink.spec : null); return messageID;
--- a/modules/utils.js Wed Oct 29 18:36:16 2008 -0600 +++ b/modules/utils.js Sun Nov 02 10:20:12 2008 -0700 @@ -34,16 +34,17 @@ * * ***** END LICENSE BLOCK ***** */ -const EXPORTED_SYMBOLS = ["SnowlUtils"]; +const EXPORTED_SYMBOLS = ["SnowlDateUtils", "SnowlUtils"]; const Cc = Components.classes; const Ci = Components.interfaces; const Cr = Components.results; const Cu = Components.utils; -// FIXME: rename this to reflect the fact that it's date-specific rather than -// being a generic set of utilities. -let SnowlUtils = { +//modules that are generic +Cu.import("resource://snowl/modules/log4moz.js"); + +let SnowlDateUtils = { get msInHour() 1000 * 60 * 60, get msInDay() this.msInHour * 24, @@ -132,32 +133,32 @@ }, twoDaysAgo: { - get epoch() { return new Date(SnowlUtils.today - (SnowlUtils.msInDay * 2)) }, - get name() { return SnowlUtils.days[this.epoch.getDay()] } + get epoch() { return new Date(SnowlDateUtils.today - (SnowlDateUtils.msInDay * 2)) }, + get name() { return SnowlDateUtils.days[this.epoch.getDay()] } }, threeDaysAgo: { - get epoch() { return new Date(SnowlUtils.today - (SnowlUtils.msInDay * 3)) }, - get name() { return SnowlUtils.days[this.epoch.getDay()] } + get epoch() { return new Date(SnowlDateUtils.today - (SnowlDateUtils.msInDay * 3)) }, + get name() { return SnowlDateUtils.days[this.epoch.getDay()] } }, fourDaysAgo: { - get epoch() { return new Date(SnowlUtils.today - (SnowlUtils.msInDay * 4)) }, - get name() { return SnowlUtils.days[this.epoch.getDay()] } + get epoch() { return new Date(SnowlDateUtils.today - (SnowlDateUtils.msInDay * 4)) }, + get name() { return SnowlDateUtils.days[this.epoch.getDay()] } }, fiveDaysAgo: { - get epoch() { return new Date(SnowlUtils.today - (SnowlUtils.msInDay * 5)) }, - get name() { return SnowlUtils.days[this.epoch.getDay()] } + get epoch() { return new Date(SnowlDateUtils.today - (SnowlDateUtils.msInDay * 5)) }, + get name() { return SnowlDateUtils.days[this.epoch.getDay()] } }, sixDaysAgo: { - get epoch() { return new Date(SnowlUtils.today - (SnowlUtils.msInDay * 6)) }, - get name() { return SnowlUtils.days[this.epoch.getDay()] } + get epoch() { return new Date(SnowlDateUtils.today - (SnowlDateUtils.msInDay * 6)) }, + get name() { return SnowlDateUtils.days[this.epoch.getDay()] } }, twentySevenDaysAgo: { - get epoch() { return new Date(SnowlUtils.today - (SnowlUtils.msInDay * 27)) }, + get epoch() { return new Date(SnowlDateUtils.today - (SnowlDateUtils.msInDay * 27)) }, get name() { return "Twenty Seven Days Ago" } }, @@ -237,6 +238,131 @@ date.getHours(), date.getMinutes(), date.getSeconds()); + }, +}; + +let SnowlUtils = { + get _log() { + let log = Log4Moz.Service.getLogger("Snowl.Utils"); + this.__defineGetter__("_log", function() { return log }); + return this._log; + }, + + // Always maintain selected listitem within a session + // XXX store on document for restore on restart?? + gListViewListIndex: null, + gListViewCollectionIndex: null, + + // From Tb: Detect right mouse click and change the highlight to the row + // where the click happened without loading the message headers in + // the Folder or Thread Pane. + gRightMouseButtonDown: false, + gSelectOnRtClick: false, + onTreeMouseDown: function(aEvent, tree) { + if (aEvent.button == 2 && !this.gSelectOnRtClick) { + this.gRightMouseButtonDown = true; + this.ChangeSelectionWithoutContentLoad(aEvent, aEvent.target.parentNode); + } + else { + // Add a capturing click listener to the tree so we can find out if the user + // clicked on a row that is already selected (in which case we let them edit + // the collection name). + // FIXME: disable this for names that can't be changed. + // this._tree.addEventListener("mousedown", function(aEvent) { + // CollectionsView.onClick(aEvent) }, true); + let row = {}, col = {}, child = {}; + tree.treeBoxObject.getCellAt(aEvent.clientX, aEvent.clientY, row, col, child); + if (tree.view.selection.isSelected(row.value)) +this._log.info("row: "+ row.value + " is selected"); + else { +this._log.info("row: "+ row.value + " is not selected"); + } + this.gRightMouseButtonDown = false; + } + }, + + // From Tb: Function to change the highlighted row to where the mouse was + // clicked without loading the contents of the selected row. + // It will also keep the outline/dotted line in the original row. + ChangeSelectionWithoutContentLoad: function(aEvent, tree) { +this._log.info("change selection right click: tree.id = "+tree.id); + let treeBoxObj = tree.treeBoxObject; + let treeSelection = treeBoxObj.view.selection; + + let row = treeBoxObj.getRowAt(aEvent.clientX, aEvent.clientY); + + // Make sure that row.value is valid so that it doesn't mess up + // the call to ensureRowIsVisible(). + if((row >= 0) && !treeSelection.isSelected(row)) { + let saveCurrentIndex = treeSelection.currentIndex; + treeSelection.selectEventsSuppressed = true; + treeSelection.select(row); + treeSelection.currentIndex = saveCurrentIndex; + treeBoxObj.ensureRowIsVisible(row); + // This causes onSelect to fire, not necessary here +// treeSelection.selectEventsSuppressed = false; + + // Keep track of which row in the tree is currently selected. + if(tree.id == "snowlView") + this.gListViewListIndex = row; + if(tree.id == "sourcesView") + this.gListViewCollectionIndex = row; + } + // This will not stop the onSelect event, need to test in the handler.. +// aEvent.stopPropagation(); + }, + + // From Tb: Function to change the highlighted row back to the row that + // is currently outline/dotted without loading the contents of either rows. + // This is triggered when the context menu for a given row is hidden/closed + // (onpopuphidden for the context <popup>). + RestoreSelectionWithoutContentLoad: function(tree) { + // If a delete or move command had been issued, then we should + // reset gRightMouseButtonDown and gListDeleteOrMoveOccurred + // and return (see bug 142065). + // TODO: once contextmenu has these options.. +// if(this.gListDeleteOrMoveOccurred) { +// this.gRightMouseButtonDown = false; +// this.gListDeleteOrMoveOccurred = false; +// return; +// } +this._log.info("restore selection onpopuphidden: tree.id = "+tree.id); + + let treeSelection = tree.view.selection; + + // Make sure that currentIndex is valid so that we don't try to restore + // a selection of an invalid row. + if((!treeSelection.isSelected(treeSelection.currentIndex)) && + (treeSelection.currentIndex >= 0)) { + treeSelection.selectEventsSuppressed = true; + treeSelection.select(treeSelection.currentIndex); + treeSelection.selectEventsSuppressed = false; + + // Keep track of which row in the tree is currently selected. + // This is currently only needed when deleting messages. + // TODO: once contextmenu has these options.. +// if(tree.id == "snowlView") +// this.gListViewListIndex = treeSelection.currentIndex; +// if(tree.id == "sourcesView") +// this.gListViewCollectionIndex = treeSelection.currentIndex; + } + else if(treeSelection.currentIndex < 0) + // Clear the selection in the case of when a folder has just been + // loaded where the message pane does not have a message loaded yet. + // When right-clicking a message in this case and dismissing the + // popup menu (by either executing a menu command or clicking + // somewhere else), the selection needs to be cleared. + // However, if the 'Delete Message' or 'Move To' menu item has been + // selected, DO NOT clear the selection, else it will prevent the + // tree view from refreshing. + treeSelection.clearSelection(); + + // Need to reset gRightMouseButtonDown to false here because + // TreeOnMouseDown() is only called on a mousedown, not on a key down. + // So resetting it here allows the loading of messages in the messagepane + // when navigating via the keyboard or the toolbar buttons *after* + // the context menu has been dismissed. + this.gRightMouseButtonDown = false; } };