Bug 393387 - week view is blank; r=mickey

This commit is contained in:
daniel.boelzle%sun.com 2007-09-14 12:08:49 +00:00
Родитель fe7c61eb45
Коммит 7869216e45
4 изменённых файлов: 257 добавлений и 72 удалений

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

@ -1091,17 +1091,24 @@
<parameter name="aEndDate"/>
<body><![CDATA[
if (this.mTimezone != aStartDate.timezone) {
aStartDate = aStartDate.getInTimezone(this.mTimezone);
aEndDate = aEndDate.getInTimezone(this.mTimezone);
aStartDate = aStartDate.getInTimezone(this.mTimezone);
aEndDate = aEndDate.getInTimezone(this.mTimezone);
}
var startDate = aStartDate.startOfWeek.clone();
var endDate = aEndDate.endOfWeek.clone();
startDate.day += this.mWeekStartOffset;
endDate.day += this.mWeekStartOffset;
this.mStartDate = aStartDate.startOfWeek;
this.mEndDate = aEndDate.endOfWeek;
this.mStartDate.day += this.mWeekStartOffset;
this.mEndDate.day += this.mWeekStartOffset;
this.refresh();
function compareDatetimes(one, two) {
return ((!one && !two) ||
(one && two && (one.compare(two) == 0)));
}
if (!compareDatetimes(this.mStartDate, startDate) ||
!compareDatetimes(this.mEndDate, endDate)) {
this.mStartDate = startDate;
this.mEndDate = endDate;
this.refresh();
}
]]></body>
</method>
@ -1159,15 +1166,21 @@
onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'monthgridrows');"/>
<field name="mRefreshQueue">[]</field>
<field name="mRefreshPending">false</field>
<field name="mRefreshPending">null</field>
<method name="popRefreshQueue">
<body><![CDATA[
if (this.mRefreshPending) {
if(this.mRefreshQueue.length > 0) {
this.relayout();
}
return;
var pendingRefresh = this.mRefreshPending;
if (pendingRefresh) {
if (pendingRefresh instanceof Components.interfaces.calIOperation) {
this.mRefreshPending = null;
pendingRefresh.cancel(null);
} else {
if(this.mRefreshQueue.length > 0) {
this.relayout();
}
return;
}
}
var refreshJob = this.mRefreshQueue.pop();
@ -1195,13 +1208,14 @@
else
filter |= this.mCalendar.ITEM_FILTER_TYPE_EVENT;
this.mRefreshPending = true;
this.mCalendar.getItems(filter,
0,
this.startDate,
this.queryEndDate,
this.mOperationListener);
this.mRefreshPending = this.mCalendar.getItems(filter,
0,
this.startDate,
this.queryEndDate,
this.mOperationListener);
if (!this.mRefreshPending) { // no support for calIOperation, fallback to bool
this.mRefreshPending = true;
}
]]></body>
</method>
@ -1498,7 +1512,7 @@
onOperationComplete: function(aCalendar, aStatus, aOperationType, aId, aDetail) {
// signal that the current operation finished.
this.calView.mRefreshPending = false;
this.calView.mRefreshPending = null;
// immediately start the next job on the queue.
this.calView.popRefreshQueue();

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

@ -2373,7 +2373,7 @@
function onOperationComplete(aCalendar, aStatus, aOperationType,
aId, aDetail) {
// signal that the current operation finished.
this.calView.mRefreshPending = false;
this.calView.mRefreshPending = null;
// immediately start the next job on the queue.
this.calView.popRefreshQueue();
@ -2554,29 +2554,36 @@
aStartDate = aEndDate = null;
if (this.mDisplayDaysOff) {
startDate.makeImmutable();
endDate.makeImmutable();
this.mDateList = null;
this.mStartDate = startDate;
this.mEndDate = endDate;
//
// For a true multiday view (e.g, 3 days advanced by one day
// at a time), a smarter refresh could reuse boxes, comparing
// the current date range and add/remove, instead of just
// replacing.
//
this.refresh();
} else { // workdays only
var dateList = new Array();
for (var d = startDate.clone(); d.compare(endDate) <= 0;) {
if (this.mDaysOffArray.indexOf(d.weekday) == -1) {
var workday = d.clone();
workday.makeImmutable();
dateList.push(workday);
function compareDatetimes(one, two) {
return ((!one && !two) ||
(one && two && (one.compare(two) == 0)));
}
d.day += 1;
}
this.setDateList(dateList.length, dateList);
if (!compareDatetimes(this.mStartDate, startDate) ||
!compareDatetimes(this.mEndDate, endDate)) {
startDate.makeImmutable();
endDate.makeImmutable();
this.mDateList = null;
this.mStartDate = startDate;
this.mEndDate = endDate;
//
// For a true multiday view (e.g, 3 days advanced by one day
// at a time), a smarter refresh could reuse boxes, comparing
// the current date range and add/remove, instead of just
// replacing.
//
this.refresh();
}
} else { // workdays only
var dateList = new Array();
for (var d = startDate.clone(); d.compare(endDate) <= 0;) {
if (this.mDaysOffArray.indexOf(d.weekday) == -1) {
var workday = d.clone();
workday.makeImmutable();
dateList.push(workday);
}
d.day += 1;
}
this.setDateList(dateList.length, dateList);
}
]]></body>
</method>
@ -2588,11 +2595,10 @@
this.mStartDate = null;
this.mEndDate = null;
if (aCount == 0) {
this.mDateList = null;
} else {
var dateList = null;
if (aCount > 0) {
aDates.sort (function(a, b) { return a.compare(b); });
this.mDateList = aDates.map(
dateList = aDates.map(
function dateMapper(d) {
if (d.isDate && !d.isMutable)
return d;
@ -2604,8 +2610,14 @@
}
);
}
this.refresh();
function compareDatetimes(one, two) {
return ((!one && !two) ||
(one && two && (one.compare(two) == 0)));
}
if (!compareArrays(this.mDateList, dateList, compareDatetimes)) {
this.mDateList = dateList;
this.refresh();
}
]]></body>
</method>
@ -2844,15 +2856,21 @@
</method>
<field name="mRefreshQueue">[]</field>
<field name="mRefreshPending">false</field>
<field name="mRefreshPending">null</field>
<method name="popRefreshQueue">
<body><![CDATA[
if (this.mRefreshPending) {
if(this.mRefreshQueue.length > 0) {
this.relayout();
}
return;
var pendingRefresh = this.mRefreshPending;
if (pendingRefresh) {
if (pendingRefresh instanceof Components.interfaces.calIOperation) {
this.mRefreshPending = null;
pendingRefresh.cancel(null);
} else {
if(this.mRefreshQueue.length > 0) {
this.relayout();
}
return;
}
}
var refreshJob = this.mRefreshQueue.pop();
@ -2885,13 +2903,14 @@
else
filter |= this.mCalendar.ITEM_FILTER_TYPE_EVENT;
this.mRefreshPending = true;
this.mCalendar.getItems(filter,
0,
this.startDate,
this.queryEndDate,
this.mOperationListener);
this.mRefreshPending = this.mCalendar.getItems(filter,
0,
this.startDate,
this.queryEndDate,
this.mOperationListener);
if (!this.mRefreshPending) { // no support for calIOperation, fallback to bool
this.mRefreshPending = true;
}
]]></body>
</method>

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

@ -543,6 +543,24 @@ function compareObjects(aObject, aOtherObject, aIID) {
return sip1.data == sip2.data;
}
/**
* Compare two arrays using the passed function.
*/
function compareArrays(aOne, aTwo, compareFunc) {
if (!aOne && !aTwo)
return true;
if (!aOne || !aTwo)
return false;
var len = aOne.length;
if (len != aTwo.length)
return false;
for (var i = 0; i < len; ++i) {
if (!compareFunc(aOne[i], aTwo[i]))
return false;
}
return true;
}
/**
* Many computations want to work only with date-times, not with dates. This
* method will return a proper datetime (set to midnight) for a date object. If
@ -1170,3 +1188,96 @@ function sendMailTo(aRecipient, aSubject, aBody) {
protoSvc.loadUrl(ioService.newURI(uriString, null, null));
}
}
var gOpGroupPrefix;
var gOpGroupId = 0;
/**
* This object implements calIOperation and could group multiple sub
* operations into one. You can pass a cancel function which is called once
* the operation group is cancelled.
* Users must call notifyCompleted() once all sub operations have been
* successful, else the operation group will stay pending.
* The reason for the latter is that providers currently should (but need
* not) implement (and return) calIOperation handles, thus there may be pending
* calendar operations (without handle).
*/
function calOperationGroup(cancelFunc) {
if (!gOpGroupPrefix) {
gOpGroupPrefix = (getUUID() + "-");
}
this.mCancelFunc = cancelFunc;
this.mId = (gOpGroupPrefix + gOpGroupId);
++gOpGroupId;
this.mSubOperations = [];
}
calOperationGroup.prototype = {
mCancelFunc: null,
mId: null,
mIsPending: true,
mStatus: Components.results.NS_OK,
mSubOperations: null,
add: function calOperationGroup_add(op) {
if (op) {
this.mSubOperations.push(op);
}
},
remove: function calOperationGroup_remove(op) {
if (op) {
function filterFunc(op_) {
return (op.id != op_.id);
}
this.mSubOperations = this.mSubOperations.filter(filterFunc);
}
},
get isEmpty() {
return (this.mSubOperations.length == 0);
},
notifyCompleted: function calOperationGroup_notifyCompleted(status) {
this.mIsPending = false;
if (status) {
this.mStatus = status;
}
},
// calIOperation:
get id() {
return this.mId;
},
get isPending() {
return this.mIsPending;
},
get status() {
return this.mStatus;
},
get success() {
return (!this.isPending && Components.results.isSuccessCode(this.status));
},
cancel: function calOperationGroup_cancel(status) {
if (this.isPending) {
if (!status) {
status = Components.interfaces.calIErrors.OPERATION_CANCELLED;
}
this.notifyCompleted(status);
var subOperations = this.mSubOperations;
this.mSubOperations = [];
function forEachFunc(op) {
op.cancel(null);
}
subOperations.forEach(forEachFunc);
if (this.mCancelFunc) {
var cancelFunc = this.mCancelFunc;
this.mCancelFunc = null;
cancelFunc();
}
}
}
};

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

@ -317,7 +317,9 @@ calCompositeCalendar.prototype = {
if (cal.canRefresh) {
cal.refresh();
}
} catch (e) { }
} catch (e) {
ASSERT(false, e);
}
}
} finally {
this.mObserverHelper.suppressOnLoad = false;
@ -336,7 +338,7 @@ calCompositeCalendar.prototype = {
throw Components.results.NS_ERROR_FAILURE;
}
aNewItem.calendar.modifyItem (aNewItem, aOldItem, aListener);
return aNewItem.calendar.modifyItem(aNewItem, aOldItem, aListener);
},
// void deleteItem( in string id, in calIOperationListener aListener );
@ -346,20 +348,25 @@ calCompositeCalendar.prototype = {
throw Components.results.NS_ERROR_FAILURE;
}
aItem.calendar.deleteItem (aItem, aListener);
return aItem.calendar.deleteItem(aItem, aListener);
},
// void addItem( in calIItemBase aItem, in calIOperationListener aListener );
addItem: function (aItem, aListener) {
this.mDefaultCalendar.addItem (aItem, aListener);
return this.mDefaultCalendar.addItem(aItem, aListener);
},
// void getItem( in string aId, in calIOperationListener aListener );
getItem: function (aId, aListener) {
var cmpListener = new calCompositeGetListenerHelper(this.mCalendars.length, aListener);
for each (cal in this.mCalendars) {
cal.getItem (aId, cmpListener);
try {
cmpListener.opGroup.add(cal.getItem(aId, cmpListener));
} catch (exc) {
ASSERT(false, exc);
}
}
return cmpListener.opGroup;
},
// void getItems( in unsigned long aItemFilter, in unsigned long aCount,
@ -378,8 +385,15 @@ calCompositeCalendar.prototype = {
var cmpListener = new calCompositeGetListenerHelper(this.mCalendars.length, aListener, aCount);
for (cal in this.mCalendars) {
this.mCalendars[cal].getItems (aItemFilter, aCount, aRangeStart, aRangeEnd, cmpListener);
try {
cmpListener.opGroup.add(
this.mCalendars[cal].getItems(
aItemFilter, aCount, aRangeStart, aRangeEnd, cmpListener));
} catch (exc) {
ASSERT(false, exc);
}
}
return cmpListener.opGroup;
},
startBatch: function ()
@ -403,11 +417,29 @@ function calCompositeGetListenerHelper(aNumQueries, aRealListener, aMaxItems) {
calCompositeGetListenerHelper.prototype = {
mNumQueries: 0,
mRealListener: null,
mOpGroup: null,
mReceivedCompletes: 0,
mFinished: false,
mMaxItems: 0,
mItemsReceived: 0,
get opGroup() {
if (!this.mOpGroup) {
var this_ = this;
function cancelFunc() { // operation group has been cancelled
var listener = this_.mRealListener;
this_.mRealListener = null;
if (listener) {
listener.onOperationComplete(
this_, Components.interfaces.calIErrors.OPERATION_CANCELLED,
calIOperationListener.GET, null, null);
}
}
this.mOpGroup = new calOperationGroup(cancelFunc);
}
return this.mOpGroup;
},
QueryInterface: function (aIID) {
if (!aIID.equals(Components.interfaces.nsISupports) &&
!aIID.equals(Components.interfaces.calIOperationListener))
@ -419,6 +451,10 @@ calCompositeGetListenerHelper.prototype = {
},
onOperationComplete: function (aCalendar, aStatus, aOperationType, aId, aDetail) {
if (!this.mRealListener) {
// has been cancelled, ignore any providers firing on this...
return;
}
if (this.mFinished) {
dump ("+++ calCompositeGetListenerHelper.onOperationComplete: called with mFinished == true!");
return;
@ -438,15 +474,20 @@ calCompositeGetListenerHelper.prototype = {
if (this.mReceivedCompletes == this.mNumQueries) {
// we're done here.
this.mRealListener.onOperationComplete (this,
aOperationType,
aStatus,
calIOperationListener.GET,
null,
null);
this.mFinished = true;
this.opGroup.notifyCompleted();
}
},
onGetResult: function (aCalendar, aStatus, aItemType, aDetail, aCount, aItems) {
if (!this.mRealListener) {
// has been cancelled, ignore any providers firing on this...
return;
}
if (this.mFinished) {
dump ("+++ calCompositeGetListenerHelper.onGetResult: called with mFinished == true!");
return;