2006-06-15 21:34:10 +02:00
|
|
|
/*
|
|
|
|
Copyright (C) 2004 SKYRIX Software AG
|
|
|
|
|
|
|
|
This file is part of OpenGroupware.org
|
|
|
|
|
|
|
|
OGo is free software; you can redistribute it and/or modify it under
|
|
|
|
the terms of the GNU Lesser General Public License as published by the
|
|
|
|
Free Software Foundation; either version 2, or (at your option) any
|
|
|
|
later version.
|
|
|
|
|
|
|
|
OGo is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
|
|
|
License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with OGo; see the file COPYING. If not, write to the
|
|
|
|
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <SOGoUI/UIxComponent.h>
|
|
|
|
|
|
|
|
@class NSMutableArray;
|
|
|
|
|
|
|
|
@interface UIxCalScheduleOverview : UIxComponent
|
|
|
|
{
|
|
|
|
NSMutableArray *userApts;
|
|
|
|
NSMutableArray *foreignApts;
|
|
|
|
id item;
|
|
|
|
NSMutableArray *partNames;
|
|
|
|
NSMutableArray *partStates;
|
|
|
|
NSString *userParticipationStatus;
|
|
|
|
unsigned participantIndex;
|
|
|
|
unsigned userIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSCalendarDate *)startDate;
|
|
|
|
- (NSCalendarDate *)endDate;
|
|
|
|
|
|
|
|
- (NSArray *)userAppointments;
|
|
|
|
- (NSArray *)foreignAppointments;
|
|
|
|
|
|
|
|
- (BOOL)hasUserAppointments;
|
|
|
|
- (BOOL)hasForeignAppointments;
|
|
|
|
- (BOOL)hasAnyAppointments;
|
|
|
|
|
|
|
|
- (void)fetchInfos;
|
|
|
|
|
|
|
|
- (NSString *)appointmentBaseURL;
|
|
|
|
|
|
|
|
- (unsigned)participantsCount;
|
|
|
|
- (unsigned)maxRenderedParticipantsCount;
|
|
|
|
- (unsigned)renderedParticipantsCount;
|
|
|
|
- (unsigned)truncatedParticipantsCount;
|
|
|
|
- (BOOL)didTruncateParticipants;
|
|
|
|
|
|
|
|
- (NSString *)getUserPartStateFromApt:(id)_apt;
|
|
|
|
|
|
|
|
- (BOOL)shouldIgnoreRejectedAppointments;
|
|
|
|
- (BOOL)shouldIgnoreAcceptedAppointments;
|
|
|
|
- (BOOL)shouldShowRejectedAndAcceptedAppointments;
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
#include <NGObjWeb/SoComponent.h>
|
|
|
|
#include "UIxComponent+Agenor.h"
|
|
|
|
#include "SoObjects/Appointments/SOGoAppointmentFolder.h"
|
|
|
|
#include "common.h"
|
|
|
|
|
|
|
|
@implementation UIxCalScheduleOverview
|
|
|
|
|
|
|
|
- (void)dealloc {
|
|
|
|
[self->userApts release];
|
|
|
|
[self->foreignApts release];
|
|
|
|
[self->item release];
|
|
|
|
[self->partNames release];
|
|
|
|
[self->partStates release];
|
|
|
|
[self->userParticipationStatus release];
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* accessors */
|
|
|
|
|
|
|
|
- (void)setItem:(id)_item {
|
|
|
|
NSString *ps, *email;
|
|
|
|
NSArray *partmails;
|
|
|
|
unsigned idx;
|
|
|
|
|
|
|
|
ASSIGN(self->item, _item);
|
|
|
|
|
|
|
|
[self->partNames release];
|
|
|
|
[self->partStates release];
|
|
|
|
ps = [self->item valueForKey:@"participants"];
|
|
|
|
self->partNames = [[ps componentsSeparatedByString:@"\n"] mutableCopy];
|
|
|
|
ps = [self->item valueForKey:@"partstates"];
|
|
|
|
self->partStates = [[ps componentsSeparatedByString:@"\n"] mutableCopy];
|
|
|
|
ps = [self->item valueForKey:@"partmails"];
|
|
|
|
partmails = [ps componentsSeparatedByString:@"\n"];
|
|
|
|
|
|
|
|
/* reorder partNames/partStates */
|
|
|
|
|
|
|
|
/* ensure organizer is first entry */
|
|
|
|
email = [self->item valueForKey:@"orgmail"];
|
|
|
|
if ([email isNotNull]) {
|
|
|
|
idx = [partmails indexOfObject:email];
|
|
|
|
if (idx != NSNotFound && idx != 0) {
|
|
|
|
id obj;
|
|
|
|
|
|
|
|
obj = [self->partNames objectAtIndex:idx];
|
|
|
|
[self->partNames insertObject:obj atIndex:0]; /* frontmost */
|
|
|
|
[self->partNames removeObjectAtIndex:idx + 1];
|
|
|
|
obj = [self->partStates objectAtIndex:idx];
|
|
|
|
[self->partStates insertObject:obj atIndex:0]; /* frontmost */
|
|
|
|
[self->partStates removeObjectAtIndex:idx + 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* user is either second, first or none at all */
|
|
|
|
[self->userParticipationStatus release];
|
|
|
|
email = [self emailForUser];
|
|
|
|
idx = [partmails indexOfObject:email];
|
|
|
|
if (idx != NSNotFound && idx != 0 && idx != 1) {
|
|
|
|
id obj;
|
|
|
|
|
|
|
|
self->userIndex = 1;
|
|
|
|
obj = [self->partNames objectAtIndex:idx];
|
|
|
|
[self->partNames insertObject:obj atIndex:self->userIndex]; /* second */
|
|
|
|
[self->partNames removeObjectAtIndex:idx + 1];
|
|
|
|
obj = [self->partStates objectAtIndex:idx];
|
|
|
|
[self->partStates insertObject:obj atIndex:self->userIndex]; /* second */
|
|
|
|
[self->partStates removeObjectAtIndex:idx + 1];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
self->userIndex = idx;
|
|
|
|
}
|
|
|
|
if (self->userIndex != NSNotFound)
|
|
|
|
self->userParticipationStatus =
|
|
|
|
[[self->partStates objectAtIndex:self->userIndex] retain];
|
|
|
|
else
|
|
|
|
self->userParticipationStatus = nil;
|
|
|
|
}
|
|
|
|
- (id)item {
|
|
|
|
return self->item;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setParticipantIndex:(unsigned)_participantIndex {
|
|
|
|
self->participantIndex = _participantIndex;
|
|
|
|
}
|
|
|
|
- (unsigned)participantIndex {
|
|
|
|
return self->participantIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (unsigned)userIndex {
|
|
|
|
return self->userIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isFirstParticipant {
|
|
|
|
return self->participantIndex == 0 ? YES : NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)hasUserAppointments {
|
|
|
|
// NOTE: this has been disabled for Agenor 0.8 on client's request
|
|
|
|
#if 1
|
|
|
|
return NO;
|
|
|
|
#else
|
|
|
|
return [[self userAppointments] count] > 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
- (BOOL)hasForeignAppointments {
|
|
|
|
return [[self foreignAppointments] count] > 0;
|
|
|
|
}
|
|
|
|
- (BOOL)hasAnyAppointments {
|
|
|
|
return ([self hasUserAppointments] ||
|
|
|
|
[self hasForeignAppointments]) ? YES : NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (unsigned)participantsCount {
|
|
|
|
return [self->partNames count];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)participant {
|
|
|
|
return [self->partNames objectAtIndex:self->participantIndex];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)participationStatus {
|
|
|
|
return [self->partStates objectAtIndex:self->participantIndex];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (unsigned)maxRenderedParticipantsCount {
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (unsigned)renderedParticipantsCount {
|
|
|
|
if ([self didTruncateParticipants])
|
|
|
|
return [self maxRenderedParticipantsCount];
|
|
|
|
return [self participantsCount];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (unsigned)truncatedParticipantsCount {
|
|
|
|
return [self participantsCount] - [self renderedParticipantsCount];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)didTruncateParticipants {
|
|
|
|
return [self participantsCount] >
|
|
|
|
([self maxRenderedParticipantsCount] + 1) ? YES : NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (unsigned)rowspan {
|
|
|
|
unsigned count;
|
|
|
|
|
|
|
|
count = [self renderedParticipantsCount];
|
|
|
|
if ([self didTruncateParticipants])
|
|
|
|
count += 1;
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)userParticipationStatus {
|
|
|
|
return self->userParticipationStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)shouldIgnoreRejectedAppointments {
|
|
|
|
return ![self shouldShowRejectedAndAcceptedAppointments];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)shouldIgnoreAcceptedAppointments {
|
|
|
|
return ![self shouldShowRejectedAndAcceptedAppointments];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)shouldShowRejectedAndAcceptedAppointments {
|
|
|
|
NSString *value;
|
|
|
|
|
|
|
|
value = [[[self context] request] formValueForKey:@"dr"];
|
|
|
|
if (!value) return NO;
|
|
|
|
return [value boolValue];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)toggleShowHideAptsQueryParameter {
|
|
|
|
BOOL shouldShow;
|
|
|
|
|
|
|
|
shouldShow = [self shouldShowRejectedAndAcceptedAppointments];
|
|
|
|
return shouldShow ? @"0" : @"1";
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)toggleShowHideAptsText {
|
|
|
|
if ([self shouldShowRejectedAndAcceptedAppointments])
|
|
|
|
return @"Hide already accepted and rejected appointments";
|
|
|
|
return @"Show already accepted and rejected appointments";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (NSString *)getUserPartStateFromApt:(id)_apt {
|
|
|
|
NSString *email;
|
|
|
|
NSArray *ps, *pms;
|
|
|
|
unsigned idx;
|
|
|
|
|
|
|
|
email = [self emailForUser];
|
|
|
|
pms = [[_apt valueForKey:@"partmails"]
|
|
|
|
componentsSeparatedByString:@"\n"];
|
|
|
|
idx = [pms indexOfObject:email];
|
|
|
|
if (idx == NSNotFound) return nil;
|
|
|
|
ps = [[_apt valueForKey:@"partstates"]
|
|
|
|
componentsSeparatedByString:@"\n"];
|
|
|
|
return [ps objectAtIndex:idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* fetching */
|
|
|
|
|
|
|
|
- (NSCalendarDate *)startDate {
|
|
|
|
return [[NSCalendarDate date] beginOfDay];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ZNeK: is a month ok? */
|
|
|
|
- (NSCalendarDate *)endDate {
|
|
|
|
NSCalendarDate *date;
|
|
|
|
|
|
|
|
date = [NSCalendarDate date];
|
|
|
|
date = [date dateByAddingYears:0 months:1 days:0
|
|
|
|
hours:0 minutes:0 seconds:0];
|
|
|
|
date = [date endOfDay];
|
|
|
|
return date;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *)userAppointments {
|
|
|
|
if (!self->userApts) {
|
|
|
|
[self fetchInfos];
|
|
|
|
}
|
|
|
|
return self->userApts;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *)foreignAppointments {
|
|
|
|
if (!self->foreignApts) {
|
|
|
|
[self fetchInfos];
|
|
|
|
}
|
|
|
|
return self->foreignApts;
|
|
|
|
}
|
|
|
|
|
2006-10-11 20:54:10 +02:00
|
|
|
- (void) fetchInfos {
|
2006-06-15 21:34:10 +02:00
|
|
|
static NSArray *orders = nil;
|
|
|
|
id aptFolder;
|
|
|
|
NSArray *apts;
|
|
|
|
NSString *userEmail;
|
|
|
|
unsigned i, count;
|
|
|
|
|
|
|
|
if (!orders) {
|
|
|
|
EOSortOrdering *so;
|
|
|
|
so = [EOSortOrdering sortOrderingWithKey:@"startDate"
|
|
|
|
selector:EOCompareAscending];
|
|
|
|
orders = [[NSArray alloc] initWithObjects:so, nil];
|
|
|
|
}
|
|
|
|
|
|
|
|
aptFolder = [self clientObject];
|
2006-10-11 20:54:10 +02:00
|
|
|
apts = [aptFolder fetchCoreInfosFrom: [self startDate]
|
|
|
|
to: [self endDate]
|
|
|
|
component: @"vevent"];
|
2006-06-15 21:34:10 +02:00
|
|
|
userEmail = [self emailForUser];
|
|
|
|
count = [apts count];
|
|
|
|
|
|
|
|
self->userApts = [[NSMutableArray alloc] initWithCapacity:count];
|
|
|
|
self->foreignApts = [[NSMutableArray alloc] initWithCapacity:count];
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
id apt;
|
|
|
|
NSString *orgEmail;
|
|
|
|
|
|
|
|
apt = [apts objectAtIndex:i];
|
|
|
|
orgEmail = [(NSDictionary *)apt objectForKey:@"orgmail"];
|
|
|
|
if (orgEmail && [orgEmail isEqualToString:userEmail]) {
|
|
|
|
[self->userApts addObject:apt];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BOOL shouldAdd = YES;
|
|
|
|
|
|
|
|
if ([self shouldIgnoreAcceptedAppointments] ||
|
|
|
|
[self shouldIgnoreRejectedAppointments])
|
|
|
|
{
|
|
|
|
NSString *userPartStat;
|
|
|
|
|
|
|
|
userPartStat = [self getUserPartStateFromApt:apt];
|
|
|
|
if (userPartStat) {
|
|
|
|
if ([self shouldIgnoreAcceptedAppointments] &&
|
|
|
|
[userPartStat isEqualToString:@"1"])
|
|
|
|
shouldAdd = NO;
|
|
|
|
else if ([self shouldIgnoreRejectedAppointments] &&
|
|
|
|
[userPartStat isEqualToString:@"2"])
|
|
|
|
shouldAdd = NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (shouldAdd)
|
|
|
|
[self->foreignApts addObject:apt];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[self->userApts sortUsingKeyOrderArray:orders];
|
|
|
|
[self->foreignApts sortUsingKeyOrderArray:orders];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* URLs */
|
|
|
|
|
|
|
|
- (NSString *)appointmentBaseURL {
|
|
|
|
id pkey;
|
|
|
|
|
|
|
|
if (![(pkey = [self->item valueForKey:@"uid"]) isNotNull])
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
return [[self clientObject] baseURLForAptWithUID:[pkey stringValue]
|
|
|
|
inContext:[self context]];
|
|
|
|
}
|
|
|
|
- (NSString *)appointmentViewURL {
|
|
|
|
return [[self appointmentBaseURL] stringByAppendingPathComponent:@"view"];
|
|
|
|
}
|
|
|
|
- (NSString *)acceptAppointmentURL {
|
|
|
|
return [[self appointmentBaseURL] stringByAppendingPathComponent:@"accept"];
|
|
|
|
}
|
|
|
|
- (NSString *)declineAppointmentURL {
|
|
|
|
return [[self appointmentBaseURL] stringByAppendingPathComponent:@"decline"];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* access protection */
|
|
|
|
|
|
|
|
- (BOOL)canAccess {
|
|
|
|
NSString *owner;
|
|
|
|
|
|
|
|
owner = [[self clientObject] ownerInContext:[self context]];
|
|
|
|
if (!owner)
|
|
|
|
return NO;
|
|
|
|
return [[[[self context] activeUser] login] isEqualToString:owner];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|