Пример #1
0
    def onExportIcalendarEvent(self, event):
        # triggered from "File | Import/Export" Menu

        wildcard = "iCalendar files|*.ics|All files (*.*)|*.*"
        dlg = wx.FileDialog(wx.GetApp().mainFrame, "Choose filename to export to",
                              "", "export.ics", wildcard,
                              wx.SAVE | wx.OVERWRITE_PROMPT)
        if dlg.ShowModal() == wx.ID_OK:
            (dir, filename) = os.path.split(dlg.GetPath())
            dlg.Destroy()
        else:
            dlg.Destroy()
            self.setStatusMessage("Export aborted")
            return

        self.setStatusMessage ("Exporting to %s" % filename)
        try:
            share = Sharing.OneTimeFileSystemShare(dir, filename,
                            ICalendar.ICalendarFormat, view=self.itsView)
            collection = ItemCollection(view=self.itsView)
            for event in Calendar.CalendarEvent.iterItems(self.itsView):
                collection.add(event)
            share.contents = collection
            share.put()
            self.setStatusMessage("Export completed")
        except:
            trace = "".join(traceback.format_exception (*sys.exc_info()))
            logger.info("Failed exportFile:\n%s" % trace)
            self.setStatusMessage("Export failed")
Пример #2
0
    def onExportIcalendarEvent(self, event):
        # triggered from "File | Import/Export" Menu

        wildcard = "iCalendar files|*.ics|All files (*.*)|*.*"
        dlg = wx.FileDialog(
            wx.GetApp().mainFrame,
            "Choose filename to export to",
            "",
            "export.ics",
            wildcard,
            wx.SAVE | wx.OVERWRITE_PROMPT,
        )
        if dlg.ShowModal() == wx.ID_OK:
            (dir, filename) = os.path.split(dlg.GetPath())
            dlg.Destroy()
        else:
            dlg.Destroy()
            self.setStatusMessage("Export aborted")
            return

        self.setStatusMessage("Exporting to %s" % filename)
        try:
            share = Sharing.OneTimeFileSystemShare(dir, filename, ICalendar.ICalendarFormat, view=self.itsView)
            collection = ItemCollection(view=self.itsView)
            for event in Calendar.CalendarEvent.iterItems(self.itsView):
                collection.add(event)
            share.contents = collection
            share.put()
            self.setStatusMessage("Export completed")
        except:
            trace = "".join(traceback.format_exception(*sys.exc_info()))
            logger.info("Failed exportFile:\n%s" % trace)
            self.setStatusMessage("Export failed")
Пример #3
0
    def writeICalendarUnicodeBug3338(self):
        event = Calendar.CalendarEvent(view = self.repo.view)
        event.displayName = u"unicode \u0633\u0644\u0627\u0645"
        event.startTime = datetime.datetime(2010, 1, 1, 10)
        event.endTime = datetime.datetime(2010, 1, 1, 11)

        coll = ItemCollection(name="testcollection", 
                                             parent=self.sandbox)
        coll.add(event)
        filename = "unicode_export.ics"

        conduit = Sharing.FileSystemConduit(name="conduit", sharePath=".",
                            shareName=filename, view=self.repo.view)
        format = ICalendar.ICalendarFormat(name="format", view=self.repo.view)
        self.share = Sharing.Share(name="share",contents=coll, conduit=conduit,
                                    format=format, view=self.repo.view)
        if self.share.exists():
            self.share.destroy()
        self.share.create()
        self.share.put()
        cal=vobject.readComponents(file(filename, 'rb')).next()
        self.assertEqual(cal.vevent[0].summary[0].value, event.displayName)
        self.share.destroy()
Пример #4
0
    def importProcess(self, text, extension=None, item=None):
        # the item parameter is so that a share item can be passed in for us
        # to populate.

        # An ICalendar file doesn't have any 'share' info, just the collection
        # of events, etc.  Therefore, we want to actually populate the share's
        # 'contents':

        view = self.itsView
        filters = self.share.filterAttributes

        newItemParent = self.findPath("//userdata")
        eventKind = self.itsView.findPath(self._calendarEventPath)
        taskKind = self.itsView.findPath(self._taskPath)
        textKind = self.itsView.findPath(self._lobPath)

        if self.fileStyle() == self.STYLE_SINGLE:
            if item is None:
                item = ItemCollection(view=view)
            elif isinstance(item, Sharing.Share):
                if item.contents is None:
                    item.contents = ItemCollection(view=view)
                item = item.contents

            if not isinstance(item, ItemCollection):
                print "Only a share or an item collection can be passed in"
                #@@@MOR Raise something

        input = StringIO.StringIO(text)
        calendar = vobject.readComponents(input, validate=True).next()

        if self.fileStyle() == self.STYLE_SINGLE:
            try:
                calName = calendar.contents[u'x-wr-calname'][0].value
            except:
                calName = "Imported Calendar"
            item.displayName = calName

        countNew = 0
        countUpdated = 0

        eventlist = getattr(calendar, 'vevent', [])
        todolist = getattr(calendar, 'vtodo', [])

        # this is just a quick hack to get VTODO working, FIXME write
        # more readable table driven code to process VEVENTs and VTODOs
        for event in itertools.chain(eventlist, todolist):
            vtype = event.name
            if vtype == u'VEVENT':
                logger.debug("got VEVENT")
                pickKind = eventKind
            elif vtype == u'VTODO':
                logger.debug("got VTODO")
                pickKind = taskKind

            try:
                displayName = event.summary[0].value
            except AttributeError:
                displayName = ""

            try:
                description = event.description[0].value
            except AttributeError:
                description = None

            try:
                location = event.location[0].value
            except AttributeError:
                location = None

            try:
                status = event.status[0].value.lower()
                if status in ('confirmed', 'tentative'):
                    pass
                elif status == 'cancelled':  #Chandler doesn't have CANCELLED
                    status = 'fyi'
                else:
                    status = 'confirmed'
            except AttributeError:
                status = 'confirmed'

            try:
                # FIXME assumes DURATION, not DATE-TIME
                reminderDelta = event.valarm[0].trigger[0].value
            except AttributeError:
                reminderDelta = None

            # RFC2445 allows VEVENTs without DTSTART, but it's hard to guess
            # what that would mean, so we won't catch an exception if there's no
            # dtstart.
            dtstart = event.dtstart[0].value

            try:
                duration = event.duration[0].value
            except AttributeError:
                # note that duration = dtend - dtstart isn't strictly correct
                # throughout a recurrence set, 1 hour differences might happen
                # around DST, but we'll ignore that corner case for now
                try:
                    duration = event.dtend[0].value - dtstart
                # FIXME no end time or duration, Calendar UI doesn't seem to
                # like events with no duration, so for now we'll set a dummy
                # duration of 1 hour
                except AttributeError:
                    # FIXME Nesting try/excepts is ugly.  Also, we're assuming
                    # DATE-TIMEs, not DATEs.
                    try:
                        duration = event.due[0].value - dtstart
                    except AttributeError:
                        if vtype == u'VEVENT':
                            duration = datetime.timedelta(hours=1)
                        elif vtype == u'VTODO':
                            duration = None

            isDate = type(dtstart) == date
            if isDate:
                dtstart = datetime.datetime.combine(dtstart, time(0))
                if duration:  # convert to Chandler's notion of all day duration
                    duration -= datetime.timedelta(days=1)

            # ignore timezones and recurrence till tzinfo -> PyICU is written
            # give the repository a naive datetime, no timezone
            dtstart = Recurrence.stripTZ(dtstart)

            # See if we have a corresponding item already
            recurrenceID = None
            uidMatchItem = self.findUID(event.uid[0].value)
            if uidMatchItem is not None:
                logger.debug("matched UID")
                try:
                    recurrenceID = event.contents['recurrence-id'][0].value
                    if type(recurrenceID) == date:
                        recurrenceID = datetime.datetime.combine(
                            recurrenceID, time(0))
                    else:
                        recurrenceID = Recurrence.stripTZ(recurrenceID)
                except:
                    pass
                if recurrenceID:
                    eventItem = uidMatchItem.getRecurrenceID(recurrenceID)
                    if eventItem == None:
                        raise Exception, "RECURRENCE-ID didn't match rule. " + \
                                         "RECURRENCE-ID = %s" % recurrenceID
                else:
                    eventItem = uidMatchItem
                    countUpdated += 1
            else:
                eventItem = pickKind.newItem(None, newItemParent)
                countNew += 1
                eventItem.icalUID = event.uid[0].value

            # vobject isn't meshing well with dateutil when dtstart isDate;
            # dtstart is converted to a datetime for dateutil, but rdate
            # isn't.  To make dateutil happy, convert rdates which are dates to
            # datetimes until vobject is fixed.
            for i, rdate in enumerate(event.rdate):
                if type(rdate) == date:
                    event.rdate[i] = datetime.datetime.combine(rdate, time(0))
                else:
                    event.rdate[i] = Recurrence.stripTZ(event.rdate[i])

                # get rid of RDATES that match dtstart, created by vobject to
                # deal with unusual RRULEs correctly
                if event.rdate[i] == dtstart:
                    del event.rdate[i]

            logger.debug("eventItem is %s" % str(eventItem))

            #Default to NOT any time
            eventItem.anyTime = False

            eventItem.displayName = displayName
            if isDate:
                eventItem.allDay = True
            eventItem.startTime = dtstart
            if vtype == u'VEVENT':
                eventItem.endTime = dtstart + duration
            elif vtype == u'VTODO':
                if duration is not None:
                    eventItem.dueDate = dtstart + duration

            if not filters or "transparency" not in filters:
                eventItem.transparency = status

            # I think Item.description describes a Kind, not userdata, so
            # I'm using DESCRIPTION <-> body
            if description is not None:
                eventItem.body = textKind.makeValue(description)

            if location:
                eventItem.location = Calendar.Location.getLocation(
                    view, location)

            if not filters or "reminderTime" not in filters:
                if reminderDelta is not None:
                    eventItem.reminderTime = dtstart + reminderDelta

            if len(event.rdate) > 0 or len(event.rrule) > 0:
                eventItem.setRuleFromDateUtil(event.rruleset)
            elif recurrenceID is None:  # delete any existing rule
                eventItem.removeRecurrence()

            logger.debug("Imported %s %s" %
                         (eventItem.displayName, eventItem.startTime))

            if self.fileStyle() == self.STYLE_SINGLE:
                item.add(eventItem)
            else:
                return eventItem

        logger.info("...iCalendar import of %d new items, %d updated" % \
         (countNew, countUpdated))

        return item
Пример #5
0
    def importProcess(self, text, extension=None, item=None):
        # the item parameter is so that a share item can be passed in for us
        # to populate.

        # An ICalendar file doesn't have any 'share' info, just the collection
        # of events, etc.  Therefore, we want to actually populate the share's
        # 'contents':

        view = self.itsView
        filters = self.share.filterAttributes

        newItemParent = self.findPath("//userdata")
        eventKind = self.itsView.findPath(self._calendarEventPath)
        taskKind  = self.itsView.findPath(self._taskPath)
        textKind  = self.itsView.findPath(self._lobPath)

        if self.fileStyle() == self.STYLE_SINGLE:
            if item is None:
                item = ItemCollection(view=view)
            elif isinstance(item, Sharing.Share):
                if item.contents is None:
                    item.contents = ItemCollection(view=view)
                item = item.contents

            if not isinstance(item, ItemCollection):
                print "Only a share or an item collection can be passed in"
                #@@@MOR Raise something

        input = StringIO.StringIO(text)
        calendar = vobject.readComponents(input, validate=True).next()

        if self.fileStyle() == self.STYLE_SINGLE:
            try:
                calName = calendar.contents[u'x-wr-calname'][0].value
            except:
                calName = "Imported Calendar"
            item.displayName = calName

        countNew = 0
        countUpdated = 0
        
        eventlist = getattr(calendar, 'vevent', [])
        todolist  = getattr(calendar, 'vtodo', [])
        
        # this is just a quick hack to get VTODO working, FIXME write
        # more readable table driven code to process VEVENTs and VTODOs
        for event in itertools.chain(eventlist, todolist):
            vtype = event.name
            if vtype == u'VEVENT':
                logger.debug("got VEVENT")
                pickKind = eventKind
            elif vtype == u'VTODO':
                logger.debug("got VTODO")
                pickKind = taskKind

            try:
                displayName = event.summary[0].value
            except AttributeError:
                displayName = ""

            try:
                description = event.description[0].value
            except AttributeError:
                description = None
                
            try:
                location = event.location[0].value
            except AttributeError:
                location = None            

            try:
                status = event.status[0].value.lower()
                if status in ('confirmed', 'tentative'):
                    pass
                elif status == 'cancelled': #Chandler doesn't have CANCELLED
                    status = 'fyi'
                else:
                    status = 'confirmed'
            except AttributeError:
                status = 'confirmed'

            try:
                # FIXME assumes DURATION, not DATE-TIME
                reminderDelta = event.valarm[0].trigger[0].value
            except AttributeError:
                reminderDelta = None

            # RFC2445 allows VEVENTs without DTSTART, but it's hard to guess
            # what that would mean, so we won't catch an exception if there's no
            # dtstart.
            dtstart  = event.dtstart[0].value 
            
            try:
                duration = event.duration[0].value
            except AttributeError:
                # note that duration = dtend - dtstart isn't strictly correct
                # throughout a recurrence set, 1 hour differences might happen
                # around DST, but we'll ignore that corner case for now
                try:
                    duration = event.dtend[0].value - dtstart
                # FIXME no end time or duration, Calendar UI doesn't seem to
                # like events with no duration, so for now we'll set a dummy
                # duration of 1 hour
                except AttributeError:
                    # FIXME Nesting try/excepts is ugly.  Also, we're assuming
                    # DATE-TIMEs, not DATEs.
                    try:
                        duration = event.due[0].value - dtstart
                    except AttributeError:
                        if vtype == u'VEVENT':
                            duration = datetime.timedelta(hours=1)
                        elif vtype == u'VTODO':
                            duration = None
                            
            isDate = type(dtstart) == date
            if isDate:
                dtstart = datetime.datetime.combine(dtstart, time(0))
                if duration: # convert to Chandler's notion of all day duration
                    duration -= datetime.timedelta(days=1)
                    
            # ignore timezones and recurrence till tzinfo -> PyICU is written
            # give the repository a naive datetime, no timezone
            dtstart = Recurrence.stripTZ(dtstart)
            
            # See if we have a corresponding item already
            recurrenceID = None
            uidMatchItem = self.findUID(event.uid[0].value)
            if uidMatchItem is not None:
                logger.debug("matched UID")
                try:
                    recurrenceID = event.contents['recurrence-id'][0].value
                    if type(recurrenceID) == date:
                        recurrenceID = datetime.datetime.combine(recurrenceID,
                                                                 time(0))
                    else:
                        recurrenceID = Recurrence.stripTZ(recurrenceID)
                except:
                    pass
                if recurrenceID:
                    eventItem = uidMatchItem.getRecurrenceID(recurrenceID)
                    if eventItem == None:
                        raise Exception, "RECURRENCE-ID didn't match rule. " + \
                                         "RECURRENCE-ID = %s" % recurrenceID
                else:
                    eventItem = uidMatchItem
                    countUpdated += 1
            else:
                eventItem = pickKind.newItem(None, newItemParent)
                countNew += 1
                eventItem.icalUID = event.uid[0].value
            

            # vobject isn't meshing well with dateutil when dtstart isDate;
            # dtstart is converted to a datetime for dateutil, but rdate
            # isn't.  To make dateutil happy, convert rdates which are dates to
            # datetimes until vobject is fixed.
            for i, rdate in enumerate(event.rdate):
                if type(rdate) == date:
                    event.rdate[i] = datetime.datetime.combine(rdate, time(0))
                else:
                    event.rdate[i] = Recurrence.stripTZ(event.rdate[i])
                    
                # get rid of RDATES that match dtstart, created by vobject to
                # deal with unusual RRULEs correctly
                if event.rdate[i] == dtstart:
                    del event.rdate[i]
                
            logger.debug("eventItem is %s" % str(eventItem))
            
            #Default to NOT any time
            eventItem.anyTime = False
            
            eventItem.displayName = displayName
            if isDate:
                eventItem.allDay = True
            eventItem.startTime   = dtstart
            if vtype == u'VEVENT':
                eventItem.endTime = dtstart + duration
            elif vtype == u'VTODO':
                if duration is not None:
                    eventItem.dueDate = dtstart + duration
            
            if not filters or "transparency" not in filters:
                eventItem.transparency = status
            
            # I think Item.description describes a Kind, not userdata, so
            # I'm using DESCRIPTION <-> body  
            if description is not None:
                eventItem.body = textKind.makeValue(description)
            
            if location:
                eventItem.location = Calendar.Location.getLocation(view,
                                                                   location)
            
            if not filters or "reminderTime" not in filters:
                if reminderDelta is not None:
                    eventItem.reminderTime = dtstart + reminderDelta

            if len(event.rdate) > 0 or len(event.rrule) > 0:
                eventItem.setRuleFromDateUtil(event.rruleset)
            elif recurrenceID is None: # delete any existing rule
                eventItem.removeRecurrence()

            logger.debug("Imported %s %s" % (eventItem.displayName,
             eventItem.startTime))

            if self.fileStyle() == self.STYLE_SINGLE:
                item.add(eventItem)
            else:
                return eventItem
                 
        logger.info("...iCalendar import of %d new items, %d updated" % \
         (countNew, countUpdated))

        return item