RE: Some changes

"Simon C" <[email protected]>
Newsgroups gmane.comp.mobile.bitpim.devel
Message-ID <005201c5b649$b6747340$6400a8c0@HOME>
> >4) Fix for outlook calender conflict exception(I sent you something
> >for this)
>
> It was a good attempt, but in this case I'd prefer to keep
> the separation between the data & the GUI modules.

I've attached a version that keep the two separate.
The error messages are collected in the outlook module and then returned to
the import dialog which then logs them and gives a warning message to the
user.

Simon
outlook.py (text/plain, 10.5 KB)
### BITPIM
###
### Copyright (C) 2004 Roger Binns <[email protected]>
###
### This program is free software; you can redistribute it and/or modify
### it under the terms of the BitPim license as detailed in the LICENSE file.
###
### $Id: outlook.py,v 1.13 2005/01/10 06:01:35 djpham Exp $

"Be at one with Outlook"

# Reject if not on Windows
import sys
if sys.platform!="win32":
   raise ImportError()

import common

# See this recipe on ASPN for how this code started
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/173216
# Chris Somerlot also gave some insights

import outlook_com

import pywintypes

# This is the complete list of field names available
##    Account
##    AssistantName
##    AssistantTelephoneNumber
##    BillingInformation
##    Body
##    Business2TelephoneNumber
##    BusinessAddress
##    BusinessAddressCity
##    BusinessAddressCountry
##    BusinessAddressPostOfficeBox
##    BusinessAddressPostalCode
##    BusinessAddressState
##    BusinessAddressStreet
##    BusinessFaxNumber
##    BusinessHomePage
##    BusinessTelephoneNumber
##    CallbackTelephoneNumber
##    CarTelephoneNumber
##    Categories
##    Children
##    Class
##    Companies
##    CompanyAndFullName
##    CompanyLastFirstNoSpace
##    CompanyLastFirstSpaceOnly
##    CompanyMainTelephoneNumber
##    CompanyName
##    ComputerNetworkName
##    ConversationIndex
##    ConversationTopic
##    CustomerID
##    Department
##    Email1Address
##    Email1AddressType
##    Email1DisplayName
##    Email1EntryID
##    Email2Address
##    Email2AddressType
##    Email2DisplayName
##    Email2EntryID
##    Email3Address
##    Email3AddressType
##    Email3DisplayName
##    Email3EntryID
##    EntryID
##    FTPSite
##    FileAs
##    FirstName
##    FullName
##    FullNameAndCompany
##    Gender
##    GovernmentIDNumber
##    Hobby
##    Home2TelephoneNumber
##    HomeAddress
##    HomeAddressCity
##    HomeAddressCountry
##    HomeAddressPostOfficeBox
##    HomeAddressPostalCode
##    HomeAddressState
##    HomeAddressStreet
##    HomeFaxNumber
##    HomeTelephoneNumber
##    ISDNNumber
##    Importance
##    Initials
##    InternetFreeBusyAddress
##    JobTitle
##    Journal
##    Language
##    LastFirstAndSuffix
##    LastFirstNoSpace
##    LastFirstNoSpaceCompany
##    LastFirstSpaceOnly
##    LastFirstSpaceOnlyCompany
##    LastName
##    LastNameAndFirstName
##    MailingAddress
##    MailingAddressCity
##    MailingAddressCountry
##    MailingAddressPostOfficeBox
##    MailingAddressPostalCode
##    MailingAddressState
##    MailingAddressStreet
##    ManagerName
##    MessageClass
##    MiddleName
##    Mileage
##    MobileTelephoneNumber
##    NetMeetingAlias
##    NetMeetingServer
##    NickName
##    NoAging
##    OfficeLocation
##    OrganizationalIDNumber
##    OtherAddress
##    OtherAddressCity
##    OtherAddressCountry
##    OtherAddressPostOfficeBox
##    OtherAddressPostalCode
##    OtherAddressState
##    OtherAddressStreet
##    OtherFaxNumber
##    OtherTelephoneNumber
##    OutlookInternalVersion
##    OutlookVersion
##    PagerNumber
##    PersonalHomePage
##    PrimaryTelephoneNumber
##    Profession
##    RadioTelephoneNumber
##    ReferredBy
##    Saved
##    SelectedMailingAddress
##    Sensitivity
##    Size
##    Spouse
##    Subject
##    Suffix
##    TTYTDDTelephoneNumber
##    TelexNumber
##    Title
##    UnRead
##    User1
##    User2
##    User3
##    User4
##    UserCertificate
##    WebPage
##    YomiCompanyName
##    YomiFirstName
##YomiLastName

def getcontacts(folder, keys=None):
    """Returns a list of dicts"""

    # There is a gross hack to only return email addresses if they are for SMTP

    res=[]
    for oc in range(folder.Items.Count):
        contact=folder.Items.Item(oc+1)
        if contact.Class == outlook_com.constants.olContact:
            record={}
            if keys is None:
                keys=[]
                for key in contact._prop_map_get_:
                    # work out if it is a property or a method (last field is None for properties)
                    if contact._prop_map_get_[key][-1] is None:
                        keys.append(key)
            for key in keys:
                v=getattr(contact, key)
                if v not in (None, "", "\x00\x00"):
                    if isinstance(v, pywintypes.TimeType): # convert from com time
                        try:
                            v=int(v)
                        except ValueError:
                            # illegal time value
                            continue
                    if key=="Categories":
                       # for some idiotic reason Outlook uses comma
                       # space seperators for this field despite using
                       # semi-colon elsewhere for the same field so we
                       # munge the data
                       v=";".join([x.strip() for x in v.split(",")])
                    if key.startswith("Email") and key.endswith("Address"):
                       keytype=key+"Type"
                       if keytype not in keys:
                          if getattr(contact, keytype)!="SMTP":
                             continue
                          
                    record[key]=v
            res.append(record)
    return res

def getitemdata(item, record, keys, client):
    for k, k_out, convertor_func in keys:
        v=getattr(item, k)
        if v is None or v=="\x00\x00":
            v=''
        if convertor_func is not None:
            # run through convertor func
            try:
                v=convertor_func(record, v, client)
            except:
                # failed conversion, skip this field
                raise
        # assign in dict if specified
        if k_out is not None:
            record[k_out]=v
    return record

def getdata(folder, keys=None, preset_dict={}, client=None, post_func=None):
    """Returns a list of dicts"""
    res=[]
    import_errors=""
    if not folder.Items.Count:
        # empty folder, just return
        return res
    # prefill keys if necessary
    if keys is None:
        keys=[]
        item=folder.Items.Item(1)
        for k in item._prop_map_get_:
            if item._prop_map_get_[k][-1] is None:
                keys.append((k, k, None))
    # go through the folder and read the data
    for i in range(folder.Items.Count):
        item=folder.Items.Item(i+1)
        record=preset_dict.copy()
        try: # this can fail if the calender has conflicts
            getitemdata(item, record, keys, client)
            if post_func is None or post_func(item, record, client):
                res.append(record)
        # synchronisation error in the outlook calender will cause exceptions, warn user
        except pythoncom.com_error, details:
            hr, msg, exc, arg_err = details
            if hr!=winerror.DISP_E_EXCEPTION:
                raise pythoncom.com_error, details
            # give the user a hint as to which entry is causing the problem
            import_errors+="\nCheck entry on %d-%d-%d starting at %02d:%02d. " % (record['start'])
            if exc[2]!=None and len(exc[2]): #display the error message from outlook
                import_errors+=exc[2]
    return res, import_errors

def getfolderfromid(id, default=False, default_type='contacts'):
    """Returns a folder object from the supplied id

    @param id: The id of the folder
    @param default: If true and the folder can't be found, then return the default"""
    onMAPI = getmapinamespace()
    try:
        folder=onMAPI.GetFolderFromID(id)
    except pywintypes.com_error,e:
        folder=None
        
    # ::TODO:: should be supplied default type (contacts, calendar etc)
    if default and not folder:
        if default_type=='calendar':
            default_folder=outlook_com.constants.olFolderCalendar
        else:
            # default to contacts, works as before
            default_folder=outlook_com.constants.olFolderContacts
        folder=onMAPI.GetDefaultFolder(default_folder)
    return folder

def getfoldername(folder):
    n=[]
    while folder:
        try:
            n=[folder.Name]+n
        except AttributeError:
            break # namespace object has no 'Name'
        folder=folder.Parent
    return " / ".join(n)

def getfolderid(folder):
    return str(folder.EntryID) # de-unicodify it

def pickfolder():
    return getmapinamespace().PickFolder()

_outlookappobject=None
def getoutlookapp():
    global _outlookappobject
    if _outlookappobject is None:
        _outlookappobject=outlook_com.Application()
    return _outlookappobject

_mapinamespaceobject=None
def getmapinamespace():
    global _mapinamespaceobject
    if _mapinamespaceobject is None:
        _mapinamespaceobject=getoutlookapp().GetNamespace("MAPI")
    return _mapinamespaceobject

def releaseoutlook():
    global _mapinamespaceobject
    global _outlookappobject
    _mapinamespaceobject=None
    _outlookappobject=None


if __name__=='__main__':
    oOutlookApp=outlook_com.Application()
    onMAPI = oOutlookApp.GetNamespace("MAPI")

    import guihelper # needed for common.strorunicode symbol

    res=onMAPI.PickFolder()
    print res

    contacts=getcontacts(res)
    keys={}
    for item in contacts:
        for k in item.keys():
            keys[k]=1
    keys=keys.keys()
    keys.sort()

    # Print out keys so they can be pasted in elsewhere
    for k in keys:
        print "   ('%s',  )," % (k,)

    import wx
    import wx.grid

    app=wx.PySimpleApp()
    import wx.lib.colourdb
    wx.lib.colourdb.updateColourDB()

    
    f=wx.Frame(None, -1, "Outlookinfo")
    g=wx.grid.Grid(f, -1)
    g.CreateGrid(len(contacts)+1,len(keys))
    g.SetColLabelSize(0)
    g.SetRowLabelSize(0)
    g.SetMargins(1,0)
    g.BeginBatch()
    attr=wx.grid.GridCellAttr()
    attr.SetBackgroundColour(wx.GREEN)
    attr.SetFont(wx.Font(10,wx.SWISS, wx.NORMAL, wx.BOLD))
    attr.SetReadOnly(True)
    for k in range(len(keys)):
        g.SetCellValue(0, k, keys[k])
    g.SetRowAttr(0,attr)
    # row attributes
    oddattr=wx.grid.GridCellAttr()
    oddattr.SetBackgroundColour("OLDLACE")
    oddattr.SetReadOnly(True)
    evenattr=wx.grid.GridCellAttr()
    evenattr.SetBackgroundColour("ALICE BLUE")
    evenattr.SetReadOnly(True)
    for row in range(len(contacts)):
        item=contacts[row]
        for col in range(len(keys)):
            key=keys[col]
            v=item.get(key, "")
            v=common.strorunicode(v)
            g.SetCellValue(row+1, col, v)
        g.SetRowAttr(row+1, (evenattr,oddattr)[row%2])

    g.AutoSizeColumns()
    g.AutoSizeRows()
    g.EndBatch()

    f.Show(True)
    app.MainLoop()
outlook.py.diff (application/octet-stream, 1.8 KB)
Index: outlook.py
===================================================================
RCS file: /cvsroot/bitpim/bitpim/native/outlook/outlook.py,v
retrieving revision 1.13
diff -u -r1.13 outlook.py
--- outlook.py	10 Jan 2005 06:01:35 -0000	1.13
+++ outlook.py	10 Sep 2005 20:43:05 -0000
@@ -219,6 +219,7 @@
 def getdata(folder, keys=None, preset_dict={}, client=None, post_func=None):
     """Returns a list of dicts"""
     res=[]
+    import_errors=""
     if not folder.Items.Count:
         # empty folder, just return
         return res
@@ -233,10 +234,20 @@
     for i in range(folder.Items.Count):
         item=folder.Items.Item(i+1)
         record=preset_dict.copy()
-        getitemdata(item, record, keys, client)
-        if post_func is None or post_func(item, record, client):
-            res.append(record)
-    return res
+        try: # this can fail if the calender has conflicts
+            getitemdata(item, record, keys, client)
+            if post_func is None or post_func(item, record, client):
+                res.append(record)
+        # synchronisation error in the outlook calender will cause exceptions, warn user
+        except pythoncom.com_error, details:
+            hr, msg, exc, arg_err = details
+            if hr!=winerror.DISP_E_EXCEPTION:
+                raise pythoncom.com_error, details
+            # give the user a hint as to which entry is causing the problem
+            import_errors+="\nCheck entry on %d-%d-%d starting at %02d:%02d. " % (record['start'])
+            if exc[2]!=None and len(exc[2]): #display the error message from outlook
+                import_errors+=exc[2]
+    return res, import_errors
 
 def getfolderfromid(id, default=False, default_type='contacts'):
     """Returns a folder object from the supplied id
outlook_calendar.py (text/plain, 17.8 KB)
### BITPIM
###
### Copyright (C) 2004 Joe Pham <[email protected]>
###
### This program is free software; you can redistribute it and/or modify
### it under the terms of the BitPim license as detailed in the LICENSE file.
###
### $Id: outlook_calendar.py,v 1.11 2005/06/22 00:07:43 djpham Exp $

"Deals with Outlook calendar import stuff"

# System modules
import datetime
import pywintypes
import sys
import time

# wxPython modules
import wx
import wx.calendar
import wx.lib.mixins.listctrl as listmix

# Others

# My modules
import bpcalendar
import common
import common_calendar
import guiwidgets
import helpids
import native.outlook

# common convertor functions
def to_bp_date(dict, v, oc):
    # convert a pyTime to (y, m, d, h, m)
    if not isinstance(v, pywintypes.TimeType):
        raise TypeError, 'illegal type'
    if v.year>common_calendar.no_end_date[0]:
        return common_calendar.no_end_date
    return (v.year, v.month, v.day, v.hour, v.minute)

def bp_repeat_str(dict, v):
    if v is None:
        return ''
    elif v==OutlookCalendarImportData.olRecursDaily:
        return 'Daily'
    elif v==OutlookCalendarImportData.olRecursWeekly:
        return 'Weekly'
    elif v==OutlookCalendarImportData.olRecursMonthly or \
         v==OutlookCalendarImportData.olRecursMonthNth:
        return 'Monthly'
    elif v==OutlookCalendarImportData.olRecursYearly:
        return 'Yearly'
    else:
        return '<Unknown Value>'

def convert_categories(dict, v, oc):
    return [x.strip() for x in v.split(",") if len(x)]

def set_recurrence(item, dict, oc):
    oc.update_display()
    if not dict['repeat']:
        # no reccurrence, ignore
        dict['repeat']=None
        return True
    # get the recurrence pattern and map it to BP Calendar
    return oc.process_repeat(item, dict)

#-------------------------------------------------------------------------------
class OutlookCalendarImportData:
    _calendar_keys=[
        # (Outlook field, BP Calendar field, convertor function)
        ('Subject', 'description', None),
        ('Location', 'location', None),
        ('Start', 'start', to_bp_date),
        ('End', 'end', to_bp_date),
        ('Categories', 'categories', convert_categories),
        ('IsRecurring', 'repeat', None),
        ('ReminderSet', 'alarm', None),
        ('ReminderMinutesBeforeStart', 'alarm_value', None),
        ('Importance', 'priority', None),
        ('Body', 'notes', None),
        ('AllDayEvent', 'allday', None)
        ]
    _recurrence_keys=[
        # (Outlook field, BP Calendar field, convertor function)
        ('NoEndDate', 'NoEndDate', None),
        ('PatternStartDate', 'PatternStartDate', to_bp_date),
        ('PatternEndDate', 'PatternEndDate', to_bp_date),
        ('Instance', 'Instance', None),
        ('DayOfWeekMask', 'DayOfWeekMask', None),
        ('Interval', 'Interval', None),
        ('Occurrences', 'Occurrences', None),
        ('RecurrenceType', 'RecurrenceType', None)
        ]
    _exception_keys=[
        # (Outlook field, BP Calendar field, convertor function)
        ('OriginalDate', 'exception_date', to_bp_date),
        ('Deleted', 'deleted', None)
        ]
    _default_filter={
        'start': None,
        'end': None,
        'categories': None,
        'rpt_events': False,
        'no_alarm': False
        }

    # Outlook constants
    olRecursDaily    = native.outlook.outlook_com.constants.olRecursDaily
    olRecursMonthNth = native.outlook.outlook_com.constants.olRecursMonthNth
    olRecursMonthly  = native.outlook.outlook_com.constants.olRecursMonthly
    olRecursWeekly   = native.outlook.outlook_com.constants.olRecursWeekly
    olRecursYearNth  = native.outlook.outlook_com.constants.olRecursYearNth
    olRecursYearly   = native.outlook.outlook_com.constants.olRecursYearly
    olImportanceHigh = native.outlook.outlook_com.constants.olImportanceHigh
    olImportanceLow  = native.outlook.outlook_com.constants.olImportanceLow
    olImportanceNormal = native.outlook.outlook_com.constants.olImportanceNormal

    def __init__(self, outlook):
        self._outlook=outlook
        self._data=[]
        self._single_data=[]
        self._folder=None
        self._filter=self._default_filter
        self._total_count=0
        self._current_count=0
        self._update_dlg=None
        self._exception_list=[]

    def _accept(self, entry):
        s_date=entry['start'][:3]
        e_date=entry['end'][:3]
        if entry.get('repeat', False):
            # repeat event, must not fall outside the range
            if self._filter['start'] is not None and \
               e_date<self._filter['start'][:3]:
                return False
            if self._filter['end'] is not None and \
               s_date>self._filter['end'][:3]:
                return False
        else:
            # non-repeat event, must fall within the range
            if self._filter['start'] is not None and \
               e_date<self._filter['start'][:3]:
                return False
            if self._filter['end'] is not None and \
               e_date>self._filter['end'][:3]:
                return False
        # check the catefory
        c=self._filter['categories']
        if c is None or not len(c):
            # no categories specified => all catefories allowed.
            return True
        if len([x for x in entry['categories'] if x in c]):
            return True
        return False

    def _populate_entry(self, e, ce):
        # populate an calendar entry with outlook data
        ce.description=e.get('description', None)
        ce.location=e.get('location', None)
        v=e.get('priority', None)
        if v is not None:
            if v==self.olImportanceNormal:
                ce.priority=ce.priority_normal
            elif v==self.olImportanceLow:
                ce.priority=ce.priority_low
            elif v==self.olImportanceHigh:
                ce.priority=ce.priority_high
        if not self._filter.get('no_alarm', False) and e.get('alarm', False):
            ce.alarm=e.get('alarm_value', 0)
        ce.allday=e.get('allday', False)
        ce.start=e['start']
        ce.end=e['end']
        ce.notes=e.get('notes', None)
        v=[]
        for k in e.get('categories', []):
            v.append({ 'category': k })
        ce.categories=v
        # look at repeat events
        if not e.get('repeat', False):
            # not a repeat event, just return
            return
        rp=bpcalendar.RepeatEntry()
        rt=e['repeat_type']
        r_interval=e.get('repeat_interval', 0)
        r_dow=e.get('repeat_dow', 0)
        if rt==self.olRecursDaily:
            rp.repeat_type=rp.daily
        elif rt==self.olRecursWeekly:
            if r_interval:
                # weekly event
                rp.repeat_type=rp.weekly
            else:
                # mon-fri event
                rp.repeat_type=rp.daily
        elif rt==self.olRecursMonthly or rt==self.olRecursMonthNth:
            rp.repeat_type=rp.monthly
        else:
            rp.repeat_type=rp.yearly
        if rp.repeat_type==rp.daily:
            rp.interval=r_interval
        elif rp.repeat_type==rp.weekly or rp.repeat_type==rp.monthly:
            rp.interval=r_interval
            rp.dow=r_dow
        # add the list of exceptions
        for k in e.get('exceptions', []):
            rp.add_suppressed(*k[:3])
        ce.repeat=rp

    def _generate_repeat_events(self, e):
        # generate multiple single events from this repeat event
        ce=bpcalendar.CalendarEntry()
        self._populate_entry(e, ce)
        l=[]
        new_e=e.copy()
        new_e['repeat']=False
        for k in ('repeat_type', 'repeat_interval', 'repeat_dow'):
            if new_e.has_key(k):
                del new_e[k]
        s_date=datetime.datetime(*self._filter['start'])
        e_date=datetime.datetime(*self._filter['end'])
        one_day=datetime.timedelta(1)
        this_date=s_date
        while this_date<=e_date:
            date_l=(this_date.year, this_date.month, this_date.day)
            if ce.is_active(*date_l):
                new_e['start']=date_l+new_e['start'][3:]
                new_e['end']=date_l+new_e['end'][3:]
                l.append(new_e.copy())
            this_date+=one_day
        return l
        
    def get(self):
        res={}
        single_rpt=self._filter.get('rpt_events', False)
        for k in self._data:
            if self._accept(k):
                if k.get('repeat', False) and single_rpt:
                    d=self._generate_repeat_events(k)
                else:
                    d=[k]
                for n in d:
                    ce=bpcalendar.CalendarEntry()
                    self._populate_entry(n, ce)
                    res[ce.id]=ce
        return res

    def get_display_data(self):
        cnt=0
        res={}
        single_rpt=self._filter.get('rpt_events', False)
        no_alarm=self._filter.get('no_alarm', False)
        for k in self._data:
            if self._accept(k):
                if k.get('repeat', False) and single_rpt:
                    d=self._generate_repeat_events(k)
                else:
                    d=[k.copy()]
                for n in d:
                    if no_alarm:
                        n['alarm']=False
                    res[cnt]=n
                    cnt+=1
        return res

    def get_category_list(self):
        l=[]
        for e in self._data:
            l+=[x for x in e.get('categories', []) if x not in l]
        return l
            
    def pick_folder(self):
        return self._outlook.pickfolder()

    def set_folder(self, f):
        if f is None:
            # default folder
            self._folder=self._outlook.getfolderfromid('', True, 'calendar')
        else:
            self._folder=f

    def set_filter(self, filter):
        self._filter=filter

    def get_filter(self):
        return self._filter

    def get_folder_name(self):
        if self._folder is None:
            return '<None>'
        return self._outlook.getfoldername(self._folder)

    def read(self, folder=None, update_dlg=None):
        # folder from which to read
        if folder is not None:
            self._folder=folder
        if self._folder is None:
            self._folder=self._outlook.getfolderfromid('', True, 'calendar')
        self._update_dlg=update_dlg
        self._total_count=self._folder.Items.Count
        self._current_count=0
        self._exception_list=[]
        self._data, import_warnings=self._outlook.getdata(self._folder,
                                    self._calendar_keys,
                                    {}, self,
                                    set_recurrence)
        # add in the exception list, .. or shoule we keep it separate ??
        self._data+=self._exception_list
        return import_warnings

    def _set_repeat_dates(self, dict, r):
        dict['start']=r['PatternStartDate'][:3]+dict['start'][3:]
        dict['end']=r['PatternEndDate'][:3]+dict['end'][3:]
        dict['repeat_type']=r['RecurrenceType']

    def _is_daily_or_weekly(self, dict, r):
        if r['RecurrenceType']==self.olRecursDaily or \
           r['RecurrenceType']==self.olRecursWeekly:
            self._set_repeat_dates(dict, r)
            dict['repeat_interval']=r['Interval']
            dict['repeat_dow']=r['DayOfWeekMask']
            return True
        return False

    def _is_monthly(self, dict, r):
        if r['RecurrenceType']==self.olRecursMonthly or \
           r['RecurrenceType']==self.olRecursMonthNth and \
           r['Interval']==1:
            self._set_repeat_dates(dict, r)
            if r['RecurrenceType']==self.olRecursMonthNth:
                dict['repeat_interval']=r['Instance']
                dict['repeat_dow']=r['DayOfWeekMask']
            return True
        return False

    def _is_yearly(self, dict, r):
        if r['RecurrenceType']==self.olRecursYearly and \
           r['Interval']==12:
            self._set_repeat_dates(dict, r)
            return True
        return False

    def _process_exceptions(self, dict, r):
        # check for and process exceptions for this event
        r_ex=r.Exceptions
        if not r_ex.Count:
            # no exception, bail
            return
        for i in range(1, r_ex.Count+1):
            ex=self._outlook.getitemdata(r_ex.Item(i), {},
                                          self._exception_keys, self)
            dict.setdefault('exceptions', []).append(ex['exception_date'])
            if not ex['deleted']:
                # if this instance has been changed, then need to get it
                appt=self._outlook.getitemdata(r_ex.Item(i).AppointmentItem,
                                                {}, self._calendar_keys, self)
                # by definition, this instance cannot be a repeat event
                appt['repeat']=False
                appt['end']=appt['start'][:3]+appt['end'][3:]
                # and add it to the exception list
                self._exception_list.append(appt)
                
    def process_repeat(self, item, dict):
        # get the recurrence info that we need.
        rec_pat=item.GetRecurrencePattern()
        r=self._outlook.getitemdata(rec_pat, {},
                                     self._recurrence_keys, self)
        if self._is_daily_or_weekly(dict, r) or \
           self._is_monthly(dict, r) or \
           self._is_yearly(dict, r):
            self._process_exceptions(dict, rec_pat)
            return True
        # invalide repeat type, turn this event into a regular event
        dict['repeat']=False
        dict['end']=dict['start'][:3]+dict['end'][3:]
        dict['notes']+=' [BITPIM: Unrecognized repeat event, repeat event discarded]'
        return True

    def update_display(self):
        # update the progress dialog if specified
        self._current_count += 1
        if self._update_dlg is not None:
            self._update_dlg.Update(100*self._current_count/self._total_count)
        
#-------------------------------------------------------------------------------
class OutlookImportCalDialog(common_calendar.PreviewDialog):
    _column_labels=[
        ('description', 'Description', 400, None),
        ('start', 'Start', 150, common_calendar.bp_date_str),
        ('end', 'End', 150, common_calendar.bp_date_str),
        ('repeat_type', 'Repeat', 80, bp_repeat_str),
        ('alarm', 'Alarm', 80, common_calendar.bp_alarm_str),
        ('categories', 'Category', 150, common_calendar.category_str)
        ]
    ID_ADD=wx.NewId()
    def __init__(self, parent, id, title):
        self._oc=OutlookCalendarImportData(native.outlook)
        self._oc.set_folder(None)
        common_calendar.PreviewDialog.__init__(self, parent, id, title,
                               self._column_labels,
                               self._oc.get_display_data(),
                               config_name='import/calendar/outlookdialog')
        
    def getcontrols(self, main_bs):
        hbs=wx.BoxSizer(wx.HORIZONTAL)
        # label
        hbs.Add(wx.StaticText(self, -1, "Outlook Calendar Folder:"), 0, wx.ALL|wx.ALIGN_CENTRE, 2)
        # where the folder name goes
        self.folderctrl=wx.TextCtrl(self, -1, "", style=wx.TE_READONLY)
        self.folderctrl.SetValue(self._oc.get_folder_name())
        hbs.Add(self.folderctrl, 1, wx.EXPAND|wx.ALL, 2)
        # browse button
        id_browse=wx.NewId()
        hbs.Add(wx.Button(self, id_browse, 'Browse ...'), 0, wx.EXPAND|wx.ALL, 2)
        main_bs.Add(hbs, 0, wx.EXPAND|wx.ALL, 5)
        main_bs.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
        wx.EVT_BUTTON(self, id_browse, self.OnBrowseFolder)

    def getpostcontrols(self, main_bs):
        main_bs.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
        hbs=wx.BoxSizer(wx.HORIZONTAL)
        id_import=wx.NewId()
        hbs.Add(wx.Button(self, id_import, 'Import'), 0, wx.ALIGN_CENTRE|wx.ALL, 5)
        hbs.Add(wx.Button(self, wx.ID_OK, 'Replace All'), 0, wx.ALIGN_CENTRE|wx.ALL, 5)
        hbs.Add(wx.Button(self, self.ID_ADD, 'Add'), 0, wx.ALIGN_CENTRE|wx.ALL, 5)
        hbs.Add(wx.Button(self, wx.ID_CANCEL, 'Cancel'), 0, wx.ALIGN_CENTRE|wx.ALL, 5)
        id_filter=wx.NewId()
        hbs.Add(wx.Button(self, id_filter, 'Filter'), 0, wx.ALIGN_CENTRE|wx.ALL, 5)
        hbs.Add(wx.Button(self, wx.ID_HELP, 'Help'), 0,  wx.ALIGN_CENTRE|wx.ALL, 5)
        main_bs.Add(hbs, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
        wx.EVT_BUTTON(self, id_import, self.OnImport)
        wx.EVT_BUTTON(self, id_filter, self.OnFilter)
        wx.EVT_BUTTON(self, self.ID_ADD, self.OnAdd)
        wx.EVT_BUTTON(self, wx.ID_HELP, lambda *_: wx.GetApp().displayhelpid(helpids.ID_DLG_CALENDAR_IMPORT))

    def OnImport(self, evt):
        wx.BeginBusyCursor()
        dlg=wx.ProgressDialog('Outlook Calendar Import',
                              'Importing Outlook Data, please wait ...\n(Please also watch out for the Outlook Permission Request dialog)',
                              parent=self)
        warnings=self._oc.read(None, dlg)
        if warnings!="":
            self.GetParent().log("Calender Import Errors: " +warnings)
            wx.MessageBox("Errors occured during calender Import, check BitPim log for details", "Import Warning")
        self.populate(self._oc.get_display_data())
        dlg.Destroy()
        wx.EndBusyCursor()

    def OnBrowseFolder(self, evt):
        f=self._oc.pick_folder()
        if f is None:
            return # user hit cancel
        self._oc.set_folder(f)
        self.folderctrl.SetValue(self._oc.get_folder_name())

    def OnFilter(self, evt):
        cat_list=self._oc.get_category_list()
        dlg=common_calendar.FilterDialog(self, -1, 'Filtering Parameters', cat_list)
        dlg.set(self._oc.get_filter())
        if dlg.ShowModal()==wx.ID_OK:
            self._oc.set_filter(dlg.get())
            self.populate(self._oc.get_display_data())

    def OnAdd(self, evt):
        self.EndModal(self.ID_ADD)

    def get(self):
        return self._oc.get()

    def get_categories(self):
        return self._oc.get_category_list()
outlook_calendar.py.diff (application/octet-stream, 1.6 KB)
Index: outlook_calendar.py
===================================================================
RCS file: /cvsroot/bitpim/bitpim/outlook_calendar.py,v
retrieving revision 1.11
diff -u -r1.11 outlook_calendar.py
--- outlook_calendar.py	22 Jun 2005 00:07:43 -0000	1.11
+++ outlook_calendar.py	10 Sep 2005 20:47:10 -0000
@@ -302,12 +302,13 @@
         self._total_count=self._folder.Items.Count
         self._current_count=0
         self._exception_list=[]
-        self._data=self._outlook.getdata(self._folder,
+        self._data, import_warnings=self._outlook.getdata(self._folder,
                                     self._calendar_keys,
                                     {}, self,
                                     set_recurrence)
         # add in the exception list, .. or shoule we keep it separate ??
         self._data+=self._exception_list
+        return import_warnings
 
     def _set_repeat_dates(self, dict, r):
         dict['start']=r['PatternStartDate'][:3]+dict['start'][3:]
@@ -439,7 +440,10 @@
         dlg=wx.ProgressDialog('Outlook Calendar Import',
                               'Importing Outlook Data, please wait ...\n(Please also watch out for the Outlook Permission Request dialog)',
                               parent=self)
-        self._oc.read(None, dlg)
+        warnings=self._oc.read(None, dlg)
+        if warnings!="":
+            self.GetParent().log("Calender Import Errors: " +warnings)
+            wx.MessageBox("Errors occured during calender Import, check BitPim log for details", "Import Warning")
         self.populate(self._oc.get_display_data())
         dlg.Destroy()
         wx.EndBusyCursor()
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.