]> err.no Git - scalable-opengroupware.org/blobdiff - UI/Scheduler/UIxAppointmentEditor.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1163 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / UI / Scheduler / UIxAppointmentEditor.m
index f8b1947392e72dbf896a6e279284531d0fa8c0f7..f4f041979508939748be44434a7fd7543f8e2bab 100644 (file)
-/*
-  Copyright (C) 2004-2005 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.
-*/
+/* UIxAppointmentEditor.m - this file is part of SOGo
+ *
+ * Copyright (C) 2007 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <math.h>
+
+#import <NGObjWeb/SoObject.h>
+#import <NGObjWeb/WORequest.h>
+#import <NGObjWeb/NSException+HTTP.h>
+#import <NGExtensions/NSCalendarDate+misc.h>
+
+#import <NGCards/iCalEvent.h>
+#import <NGCards/iCalPerson.h>
+
+#import <SoObjects/SOGo/SOGoUser.h>
+#import <SoObjects/SOGo/SOGoContentObject.h>
+#import <SoObjects/Appointments/SOGoAppointmentFolder.h>
+#import <SoObjects/Appointments/SOGoAppointmentObject.h>
+
+#import "UIxComponentEditor.h"
+#import "UIxAppointmentEditor.h"
 
-#import <NGCards/NSString+NGCards.h>
-#import <NGCards/NSCalendarDate+NGCards.h>
+@implementation UIxAppointmentEditor
 
-#import <SOGo/AgenorUserManager.h>
-#import <SOGo/NSCalendarDate+SOGo.h>
+- (id) init
+{
+  if ((self = [super init]))
+    {
+      aptStartDate = nil;
+      aptEndDate = nil;
+      item = nil;
+      event = nil;
+      isAllDay = NO;
+    }
 
-#import "common.h"
-#import <NGCards/NGCards.h>
-#import <NGExtensions/NGCalendarDateRange.h>
-#import <SOGoUI/SOGoDateFormatter.h>
-#import <Appointments/SOGoAppointmentFolder.h>
-#import <Appointments/SOGoAppointmentObject.h>
-#import "UIxComponent+Agenor.h"
+  return self;
+}
 
-#import "UIxAppointmentEditor.h"
+/* template values */
+- (iCalEvent *) event
+{
+  return event;
+}
 
-/* TODO: CLEAN UP */
+- (NSString *) saveURL
+{
+  return [NSString stringWithFormat: @"%@/saveAsAppointment",
+                   [[self clientObject] baseURL]];
+}
 
-@implementation UIxAppointmentEditor
+/* icalendar values */
+- (BOOL) isAllDay
+{
+  NSString *hm;
 
-+ (int)version {
-  return [super version] + 0 /* v2 */;
-}
+  hm = [self queryParameterForKey: @"hm"];
 
-+ (void)initialize {
-  NSAssert2([super version] == 2,
-            @"invalid superclass (%@) version %i !",
-            NSStringFromClass([self superclass]), [super version]);
+  return (isAllDay
+         || (hm && [hm isEqualToString: @"allday"]));
 }
 
-- (void) dealloc
+- (void) setIsAllDay: (BOOL) newIsAllDay
 {
-  [endDate release];
-  [super dealloc];
+  isAllDay = newIsAllDay;
 }
 
-/* accessors */
-
-- (void) setAptStartDate: (NSCalendarDate *)_date
+- (void) setAptStartDate: (NSCalendarDate *) newAptStartDate
 {
-  [self setStartDate: _date];
+  ASSIGN (aptStartDate, newAptStartDate);
 }
 
 - (NSCalendarDate *) aptStartDate
 {
-  return [self startDate];
+  return aptStartDate;
 }
 
-- (void) setAptEndDate: (NSCalendarDate *) _date
+- (void) setAptEndDate: (NSCalendarDate *) newAptEndDate
 {
-  ASSIGN(endDate, _date);
+  ASSIGN (aptEndDate, newAptEndDate);
 }
 
 - (NSCalendarDate *) aptEndDate
 {
-  return endDate;
+  return aptEndDate;
 }
 
-/* transparency */
-
-- (NSString *) transparency
+- (NSArray *) repeatList
 {
-  return @"OPAQUE";
+  static NSArray *repeatItems = nil;
+
+  if (!repeatItems)
+    {
+      repeatItems = [NSArray arrayWithObjects: @"DAILY",
+                             @"WEEKLY",
+                             @"BI-WEEKLY",
+                             @"EVERY WEEKDAY",
+                             @"MONTHLY",
+                             @"YEARLY",
+                             @"-",
+                             @"CUSTOM",
+                             nil];
+      [repeatItems retain];
+    }
+
+  return repeatItems;
 }
 
-/* iCal */
-
-- (NSString *)iCalStringTemplate {
-  static NSString *iCalStringTemplate = \
-    @"BEGIN:VCALENDAR\r\n"
-    @"METHOD:REQUEST\r\n"
-    @"PRODID://Inverse groupe conseil/SOGo 0.9\r\n"
-    @"VERSION:2.0\r\n"
-    @"BEGIN:VEVENT\r\n"
-    @"UID:%@\r\n"
-    @"CLASS:PUBLIC\r\n"
-    @"STATUS:CONFIRMED\r\n" /* confirmed by default */
-    @"DTSTAMP:%@Z\r\n"
-    @"DTSTART:%@Z\r\n"
-    @"DTEND:%@Z\r\n"
-    @"TRANSP:%@\r\n"
-    @"SEQUENCE:1\r\n"
-    @"PRIORITY:5\r\n"
-    @"%@"                   /* organizer */
-    @"%@"                   /* participants and resources */
-    @"END:VEVENT\r\n"
-    @"END:VCALENDAR";
-
-  NSTimeZone *utc;
-  NSCalendarDate *lStartDate, *lEndDate, *stamp;
-  NSString *template, *s;
-  unsigned minutes;
-
-  s = [self queryParameterForKey:@"dur"];
-  if ([s length] > 0)
-    minutes = [s intValue];
+- (NSString *) itemRepeatText
+{
+  NSString *text;
+
+  if ([item isEqualToString: @"-"])
+    text = item;
   else
-    minutes = 60;
-
-  utc = [NSTimeZone timeZoneWithName: @"GMT"];
-  lStartDate = [self newStartDate];
-  [lStartDate setTimeZone: utc];
-  lEndDate = [lStartDate dateByAddingYears: 0 months: 0 days: 0
-                         hours: 0 minutes: minutes seconds: 0];
-
-  stamp = [NSCalendarDate calendarDate];
-  [stamp setTimeZone: utc];
-
-  s          = [self iCalParticipantsAndResourcesStringFromQueryParameters];
-  template   = [NSString stringWithFormat:iCalStringTemplate,
-                         [[self clientObject] nameInContainer],
-                         [stamp iCalFormattedDateTimeString],
-                         [lStartDate iCalFormattedDateTimeString],
-                         [lEndDate iCalFormattedDateTimeString],
-                         [self transparency],
-                         [self iCalOrganizerString],
-                         s];
-  return template;
+    text = [self labelForKey: [NSString stringWithFormat: @"repeat_%@", item]];
+
+  return text;
 }
 
-/* new */
+- (void) setItem: (NSString *) newItem
+{
+  item = newItem;
+}
+
+- (NSString *) item
+{
+  return item;
+}
 
-- (id) newAction
+- (NSArray *) reminderList
 {
-  /*
-    This method creates a unique ID and redirects to the "edit" method on the
-    new ID.
-    It is actually a folder method and should be defined on the folder.
-    
-    Note: 'clientObject' is the SOGoAppointmentFolder!
-          Update: remember that there are group folders as well.
-  */
-  NSString *uri, *objectId, *method, *ps;
-
-  objectId = [NSClassFromString(@"SOGoAppointmentFolder")
-                              globallyUniqueObjectId];
-  if ([objectId length] == 0) {
-    return [NSException exceptionWithHTTPStatus:500 /* Internal Error */
-                       reason:@"could not create a unique ID"];
-  }
-
-  method = [NSString stringWithFormat:@"Calendar/%@/editAsAppointment", objectId];
-  method = [[self userFolderPath] stringByAppendingPathComponent:method];
-
-  /* check if participants have already been provided */
-  ps     = [self queryParameterForKey:@"ps"];
-//   if (ps) {
-//     [self setQueryParameter:ps forKey:@"ps"];
-//   }
- if (!ps
-     && [[self clientObject] respondsToSelector:@selector(calendarUIDs)]) {
-    AgenorUserManager *um;
-    NSArray *uids;
-    NSMutableArray *emails;
-    unsigned i, count;
-
-    /* add all current calendarUIDs as default participants */
-
-    um     = [AgenorUserManager sharedUserManager];
-    uids   = [[self clientObject] calendarUIDs];
-    count  = [uids count];
-    emails = [NSMutableArray arrayWithCapacity:count];
-    
-    for (i = 0; i < count; i++) {
-      NSString *email;
-      
-      email = [um getEmailForUID:[uids objectAtIndex:i]];
-      if (email)
-        [emails addObject:email];
+  static NSArray *reminderItems = nil;
+
+  if (!reminderItems)
+    {
+      reminderItems = [NSArray arrayWithObjects: @"5_MINUTES_BEFORE",
+                               @"10_MINUTES_BEFORE",
+                               @"15_MINUTES_BEFORE",
+                               @"30_MINUTES_BEFORE",
+                               @"45_MINUTES_BEFORE",
+                               @"-",
+                               @"1_HOUR_BEFORE",
+                               @"2_HOURS_BEFORE",
+                               @"5_HOURS_BEFORE",
+                               @"15_HOURS_BEFORE",
+                               @"-",
+                               @"1_DAY_BEFORE",
+                               @"2_DAYS_BEFORE",
+                               @"1_WEEK_BEFORE",
+                               @"-",
+                               @"CUSTOM",
+                               nil];
+      [reminderItems retain];
     }
-    ps = [emails componentsJoinedByString:@","];
-    [self setQueryParameter:ps forKey:@"ps"];
-  }
-  uri = [self completeHrefForMethod:method];
-  return [self redirectToLocation:uri];
+
+  return reminderItems;
 }
 
-/* save */
+// - (void) setReminder: (NSString *) reminder
+// {
+//   ASSIGN(reminder, _reminder);
+// }
 
-- (void) loadValuesFromAppointment: (iCalEvent *) appointment
-{
-  NSTimeZone *uTZ;
+// - (NSString *) reminder
+// {
+//   return reminder;
+// }
 
-  [self loadValuesFromComponent: appointment];
+- (NSString *) itemReminderText
+{
+  NSString *text;
 
-  uTZ = [[self clientObject] userTimeZone];
-  endDate = [appointment endDate];
-  if (!endDate)
-    endDate = [[self startDate] dateByAddingYears: 0 months: 0 days: 0
-                                hours: 1 minutes: 0 seconds: 0];
+  if ([item isEqualToString: @"-"])
+    text = item;
+  else
+    text = [self labelForKey: [NSString stringWithFormat: @"reminder_%@", item]];
 
-  [endDate setTimeZone: uTZ];
-  [endDate retain];
+  return text;
 }
 
-- (void) saveValuesIntoAppointment: (iCalEvent *) _appointment
+- (NSString *) repeat
 {
-  /* merge in form values */
-  NSArray *attendees, *lResources;
-  iCalRecurrenceRule *rrule;
-  
-  [_appointment setStartDate:[self aptStartDate]];
-  [_appointment setEndDate:[self aptEndDate]];
-
-  [_appointment setSummary: [self title]];
-  [_appointment setUrl: [self url]];
-  [_appointment setLocation: [self location]];
-  [_appointment setComment: [self comment]];
-  [_appointment setPriority:[self priority]];
-  [_appointment setAccessClass: [self privacy]];
-  [_appointment setStatus: [self status]];
-
-//   [_appointment setCategories: [[self categories] componentsJoinedByString: @","]];
-
-  [_appointment setTransparency: [self transparency]];
-
-#if 0
-  /*
-    Note: bad, bad, bad!
-    Organizer is no form value, thus we MUST NOT change it
-  */
-  [_appointment setOrganizer:organizer];
-#endif
-  attendees  = [self participants];
-  lResources = [self resources];
-  if ([lResources count] > 0) {
-    attendees = ([attendees count] > 0)
-      ? [attendees arrayByAddingObjectsFromArray: lResources]
-      : lResources;
-  }
-  [attendees makeObjectsPerformSelector: @selector (setTag:)
-             withObject: @"attendee"];
-  [_appointment setAttendees: attendees];
-
-  /* cycles */
-  [_appointment removeAllRecurrenceRules];
-  rrule = [self rrule];
-  if (rrule)
-    [_appointment addToRecurrenceRules: rrule];
+  return @"";
 }
 
-- (iCalEvent *) appointmentFromString: (NSString *) _iCalString
+- (void) setRepeat: (NSString *) newRepeat
 {
-  iCalCalendar *calendar;
-  iCalEvent *appointment;
-  SOGoAppointmentObject *clientObject;
-
-  clientObject = [self clientObject];
-  calendar = [iCalCalendar parseSingleFromSource: _iCalString];
-  appointment = [clientObject firstEventFromCalendar: calendar];
-
-  return appointment;
 }
 
-/* conflict management */
+- (NSString *) reminder
+{
+  return @"";
+}
 
-- (BOOL) containsConflict: (id) _apt
+- (void) setReminder: (NSString *) newReminder
 {
-  NSArray *attendees, *uids;
-  SOGoAppointmentFolder *groupCalendar;
-  NSArray *infos;
-  NSArray *ranges;
-  id folder;
-
-  [self logWithFormat:@"search from %@ to %@", 
-         [_apt startDate], [_apt endDate]];
-
-  folder    = [[self clientObject] container];
-  attendees = [_apt attendees];
-  uids      = [folder uidsFromICalPersons:attendees];
-  if ([uids count] == 0) {
-    [self logWithFormat:@"Note: no UIDs selected."];
-    return NO;
-  }
-
-  groupCalendar = [folder lookupGroupCalendarFolderForUIDs:uids
-                          inContext:[self context]];
-  [self debugWithFormat:@"group calendar: %@", groupCalendar];
-  
-  if (![groupCalendar respondsToSelector:@selector(fetchFreeBusyInfosFrom:to:)]) {
-    [self errorWithFormat:@"invalid folder to run freebusy query on!"];
-    return NO;
-  }
-
-  infos = [groupCalendar fetchFreeBusyInfosFrom:[_apt startDate]
-                         to:[_apt endDate]];
-  [self debugWithFormat:@"  process: %d events", [infos count]];
-
-  ranges = [infos arrayByCreatingDateRangesFromObjectsWithStartDateKey: @"startDate"
-                  andEndDateKey: @"endDate"];
-  ranges = [ranges arrayByCompactingContainedDateRanges];
-  [self debugWithFormat:@"  blocked ranges: %@", ranges];
-
-  return [ranges count] != 0 ? YES : NO;
 }
 
 /* actions */
-
-- (id) testAction
+- (NSCalendarDate *) newStartDate
 {
-  /* for testing only */
-  WORequest *req;
-  iCalEvent *apt;
-  NSString *content;
-
-  req = [[self context] request];
-  apt = [self appointmentFromString: [self iCalString]];
-  [self saveValuesIntoAppointment:apt];
-  content = [[apt parent] versitString];
-  [self logWithFormat:@"%s -- iCal:\n%@",
-    __PRETTY_FUNCTION__,
-    content];
+  NSCalendarDate *newStartDate, *now;
+  NSTimeZone *timeZone;
+  int hour;
+
+  newStartDate = [self selectedDate];
+  if ([[self queryParameterForKey: @"hm"] length] == 0)
+    {
+      now = [NSCalendarDate calendarDate];
+      timeZone = [[context activeUser] timeZone];
+      [now setTimeZone: timeZone];
+      if ([now isDateOnSameDay: newStartDate])
+        {
+          hour = [now hourOfDay];
+          if (hour < 8)
+            newStartDate = [now hour: 8 minute: 0];
+          else if (hour > 18)
+            newStartDate = [[now tomorrow] hour: 8 minute: 0];
+          else
+            newStartDate = now;
+        }
+      else
+        newStartDate = [newStartDate hour: 8 minute: 0];
+    }
 
-  return self;
+  return newStartDate;
 }
 
-- (id<WOActionResults>) defaultAction
+- (id <WOActionResults>) defaultAction
 {
-  NSString *ical;
-  
-  /* load iCalendar file */
-  
-  // TODO: can't we use [clientObject contentAsString]?
-//   ical = [[self clientObject] valueForKey:@"iCalString"];
-  ical = [[self clientObject] contentAsString];
-  if ([ical length] == 0) /* a new appointment */
-    ical = [self iCalStringTemplate];
-
-  [self setICalString:ical];
-  [self loadValuesFromAppointment: [self appointmentFromString: ical]];
-
-//   if (![self canEditComponent]) {
-//     /* TODO: we need proper ACLs */
-//     return [self redirectToLocation: [self completeURIForMethod: @"../view"]];
-//   }
+  NSCalendarDate *startDate, *endDate;
+  NSString *duration;
+  unsigned int minutes;
+
+  event = (iCalEvent *) [[self clientObject] component: NO];
+  if (event)
+    {
+      startDate = [event startDate];
+      isAllDay = [event isAllDay];
+      if (isAllDay)
+       endDate = [[event endDate] dateByAddingYears: 0 months: 0 days: -1];
+      else
+       endDate = [event endDate];
+    }
+  else
+    {
+      startDate = [self newStartDate];
+      duration = [self queryParameterForKey:@"dur"];
+      if ([duration length] > 0)
+       minutes = [duration intValue];
+      else
+       minutes = 60;
+      endDate
+       = [startDate dateByAddingYears: 0 months: 0 days: 0
+                    hours: 0 minutes: minutes seconds: 0];
+    }
+
+  ASSIGN (aptStartDate, startDate);
+  ASSIGN (aptEndDate, endDate);
+
+
+  /* here comes the code for initializing repeat, reminder and isAllDay... */
+
   return self;
 }
 
-- (id <WOActionResults>) saveAction
+- (id <WOActionResults>) newAction
 {
-  iCalEvent *apt;
-  iCalPerson *p;
+  NSString *objectId, *method, *uri;
   id <WOActionResults> result;
-  NSString *content;
-  NSException *ex;
-
-  if (![self isWriteableClientObject]) {
-    /* return 400 == Bad Request */
-    return [NSException exceptionWithHTTPStatus:400
-                        reason:@"method cannot be invoked on "
-                               @"the specified object"];
-  }
-  
-  apt = [self appointmentFromString: [self iCalString]];
-  if (apt == nil) {
-    NSString *s;
-    
-    s = [self labelForKey:@"Invalid iCal data!"];
-    [self setErrorText:s];
-    return self;
-  }
-  
-  [self saveValuesIntoAppointment:apt];
-  p = [apt findParticipantWithEmail:[self emailForUser]];
-  if (p) {
-    [p setParticipationStatus:iCalPersonPartStatAccepted];
-  }
-
-  if ([self checkForConflicts]) {
-    if ([self containsConflict:apt]) {
-      NSString *s;
-      
-      s = [self labelForKey:@"Conflicts found!"];
-      [self setErrorText:s];
-
-      return self;
+  Class clientKlazz;
+
+  clientKlazz = [[self clientObject] class];
+  objectId = [clientKlazz globallyUniqueObjectId];
+  if ([objectId length] > 0)
+    {
+      method = [NSString stringWithFormat:@"%@/Calendar/%@/editAsAppointment",
+                         [self userFolderPath], objectId];
+      uri = [self completeHrefForMethod: method];
+      result = [self redirectToLocation: uri];
     }
-  }
-  content = [[apt parent] versitString];
-//   [apt release]; apt = nil;
-  
-  if (content == nil) {
-    NSString *s;
-    
-    s = [self labelForKey:@"Could not create iCal data!"];
-    [self setErrorText:s];
-    return self;
-  }
-  
-  ex = [[self clientObject] saveContentString:content];
-  if (ex != nil) {
-    [self setErrorText:[ex reason]];
-    return self;
-  }
-  
-  if ([[[[self context] request] formValueForKey: @"nojs"] intValue])
-    result = [self redirectToLocation: [self applicationPath]];
   else
-    result = [self jsCloseWithRefreshMethod: @"refreshAppointmentsAndDisplay()"];
+    result = [NSException exceptionWithHTTPStatus: 500 /* Internal Error */
+                          reason: @"could not create a unique ID"];
 
   return result;
 }
 
-- (NSString *) saveUrl
+- (id <WOActionResults>) saveAction
 {
-  return [NSString stringWithFormat: @"%@/saveAsAppointment",
-                   [[self clientObject] baseURL]];
+  SOGoAppointmentObject *clientObject;
+  NSString *iCalString;
+
+  clientObject = [self clientObject];
+  iCalString = [[clientObject calendar: NO] versitString];
+  [clientObject saveContentString: iCalString];
+
+  return [self jsCloseWithRefreshMethod: @"refreshEventsAndDisplay()"];
 }
 
-- (id) acceptAction
+- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
+                           inContext: (WOContext*) context
 {
-  return [self acceptOrDeclineAction:YES];
+  NSString *actionName;
+
+  actionName = [[request requestHandlerPath] lastPathComponent];
+
+  return ([[self clientObject] isKindOfClass: [SOGoAppointmentObject class]]
+         && [actionName hasPrefix: @"save"]);
 }
 
-- (id) declineAction
+- (void) takeValuesFromRequest: (WORequest *) _rq
+                     inContext: (WOContext *) _ctx
 {
-  return [self acceptOrDeclineAction:NO];
+  SOGoAppointmentObject *clientObject;
+  int nbrDays;
+
+  clientObject = [self clientObject];
+  event = (iCalEvent *) [clientObject component: YES];
+
+  [super takeValuesFromRequest: _rq inContext: _ctx];
+
+  if (isAllDay)
+    {
+      nbrDays = ((float) abs ([aptEndDate timeIntervalSinceDate: aptStartDate])
+                / 86400) + 1;
+      [event setAllDayWithStartDate: aptStartDate
+            duration: nbrDays];
+    }
+  else
+    {
+      [event setStartDate: aptStartDate];
+      [event setEndDate: aptEndDate];
+    }
+  if ([clientObject isNew])
+    [event setTransparency: @"OPAQUE"];
 }
 
 // TODO: add tentatively
 
-- (id) acceptOrDeclineAction: (BOOL) _accept
+- (id) acceptOrDeclineAction: (BOOL) accept
+{
+  [[self clientObject] changeParticipationStatus: (accept
+                                                  ? @"ACCEPTED"
+                                                  : @"DECLINED")];
+
+  return self;
+}
+
+- (id) acceptAction
+{
+  return [self acceptOrDeclineAction: YES];
+}
+
+- (id) declineAction
 {
-  // TODO: this should live in the SoObjects
-  NSException *ex;
-
-  if ((ex = [self validateObjectForStatusChange]) != nil)
-    return ex;
-  
-  ex = [[self clientObject] changeParticipationStatus:
-                              _accept ? @"ACCEPTED" : @"DECLINED"
-                            inContext:[self context]];
-  if (ex != nil) return ex;
-
-  return self;  
-//   return [self redirectToLocation: [self completeURIForMethod: @"../view"]];
+  return [self acceptOrDeclineAction: NO];
 }
 
-@end /* UIxAppointmentEditor */
+@end