~m-buck/+junk/gtk-desktop-info

« back to all changes in this revision

Viewing changes to plugin_googlecalendar.py

  • Committer: Mark Buck (Kaivalagi)
  • Date: 2009-06-19 17:13:00 UTC
  • Revision ID: m_buck@hotmail.com-20090619171300-5cbhr90xwg62z27y
Added --backgroundblend and --backgroundcolour options for visual seperation of output from wallpaper if required, Fixed song length output in the rhythmbox plugin when songs are an hour long or more, Added copy option to right click, enabling the copying of html content to the clipboard for testing, Moved common functions into a plugin_common module

Show diffs side-by-side

added added

removed removed

Lines of Context:
9
9
# Created: 23/11/2008
10
10
 
11
11
from datetime import datetime, date, timedelta
12
 
from htmlentitydefs import name2codepoint, codepoint2name
13
12
from optparse import OptionParser
 
13
from plugin_common import getHTMLText, getSpaces, getTypedValue, getWrappedText, removeLineByString
14
14
from xml.dom import minidom
15
 
import socket
 
15
import codecs
 
16
import fileinput
 
17
import gdata.calendar
16
18
import gdata.calendar.service
17
 
import gdata.calendar
18
 
import sys
19
19
import locale
 
20
import logging
 
21
import os
20
22
import re
21
 
import textwrap
22
 
import urllib
23
 
import codecs
24
 
import os
25
23
import shutil
 
24
import socket
 
25
import sys
26
26
import traceback
27
 
import logging
28
 
import fileinput
 
27
import urllib
 
28
 
29
29
 
30
30
app_name = "gtk-desktop-info"
31
31
app_path = os.path.dirname(os.path.abspath(__file__))
32
32
module_name = __file__.replace(os.path.dirname (__file__) + "/", "").replace(".pyc","").replace(".py", "")
33
33
 
34
34
class CalendarData:
35
 
    
 
35
 
36
36
    def __init__(self, title):
37
37
        self.title = title
38
38
 
39
39
class CalendarEventData:
40
 
    
 
40
 
41
41
    def __init__(self, title, starttime, endtime, location, description, who=None):
42
42
        self.title = title
43
43
        self.starttime = starttime
48
48
 
49
49
    def __cmp__(self, other):
50
50
        return cmp(self.starttime, other.starttime)
51
 
    
 
51
 
52
52
    def __str__(self):
53
53
        return str(self.starttime)
54
54
 
68
68
    TIMEFORMAT = None
69
69
    DATEFORMAT = None
70
70
    CONNECTION_TIMEOUT = 30
71
 
    
 
71
 
72
72
class Output:
73
 
    
 
73
 
74
74
    dateformat=""
75
75
    timeformat=""
76
76
    options = None
86
86
    ACCESS_CONTRIBUTOR = 'contributor'
87
87
    ACCESS_READ        = 'read'
88
88
    ACCESS_FREEBUSY    = 'freebusy'
89
 
    
 
89
 
90
90
    ################ CONSTANTS ################################################
91
91
    MAX_WIDTH = 100
92
 
        
 
92
 
93
93
    ################ GOOGLE CALENDAR FUNCTIONS ################################
94
94
    def __init__(self, options):
95
95
 
97
97
            self.options = options
98
98
            self.logger = logging.getLogger(app_name+"."+module_name)
99
99
            self.loadConfigData()
100
 
            
 
100
 
101
101
            self.logger.info("Initialising google calendar connection...")
102
 
            
 
102
 
103
103
            socket.setdefaulttimeout(self.config.CONNECTION_TIMEOUT)
104
104
 
105
105
            self.cal_client = gdata.calendar.service.CalendarService()
107
107
            self.cal_client.password = self.config.PASSWORD
108
108
            self.cal_client.source = app_name
109
109
            self.cal_client.ProgrammaticLogin()
110
 
    
 
110
 
111
111
            # load the format for date and time to use
112
112
            self.getDatetimeFormat(self.config.DATEFORMAT, self.config.TIMEFORMAT)
113
113
 
114
114
            # prepare calendar list to use for event retrieval
115
115
            self.getCalendarList()
116
 
            
 
116
 
117
117
        except Exception,e:
118
118
            self.logger.error("GoogleCalendarEngine Initialisation:Unexpected error:" + e.__str__())
119
 
            
 
119
 
120
120
    def loadConfigData(self):
121
 
        try:         
 
121
        try:
122
122
 
123
123
            self.config = GoogleCalendarConfig()
124
 
            
 
124
 
125
125
            if self.options.config != None:
126
126
                # load the config based on options passed in from the main app
127
127
                configfilepath = self.options.config
128
128
            else:
129
129
                # load plugin config from home directory of the user
130
130
                configfilepath = os.path.join(os.path.expanduser('~'), ".config/"+app_name+"/"+module_name+".config")
131
 
                            
 
131
 
132
132
            if os.path.exists(configfilepath):
133
 
                
 
133
 
134
134
                self.logger.info("Loading config settings from \"%s\""%configfilepath)
135
 
                
 
135
 
136
136
                for line in fileinput.input(os.path.expanduser(configfilepath)):
137
137
                    line = line.strip()
138
138
                    if len(line) > 0 and line[0:1] != "#": # ignore commented lines or empty ones
139
 
    
 
139
 
140
140
                        name = line.split("=")[0].strip().upper() # config setting name on the left of =
141
141
                        value = line.split("=")[1].split("#")[0].strip() # config value on the right of = (minus any trailing comments)
142
 
                       
 
142
 
143
143
                        if len(value) > 0:
144
144
                            if name == "HEADERTEMPLATE":
145
 
                                self.config.TEMPLATE = self.getTypedValue(value, "string")
 
145
                                self.config.TEMPLATE = getTypedValue(value, "string")
146
146
                            elif name == "TEMPLATE":
147
 
                                self.config.TEMPLATE = self.getTypedValue(value, "string")
 
147
                                self.config.TEMPLATE = getTypedValue(value, "string")
148
148
                            elif name == "USERNAME":
149
 
                                self.config.USERNAME = self.getTypedValue(value, "string")
 
149
                                self.config.USERNAME = getTypedValue(value, "string")
150
150
                            elif name == "PASSWORD":
151
 
                                self.config.PASSWORD = self.getTypedValue(value, "string")
 
151
                                self.config.PASSWORD = getTypedValue(value, "string")
152
152
                            elif name == "REQUESTCALENDARS":
153
 
                                self.config.REQUESTCALENDARS = self.getTypedValue(value, "string")
 
153
                                self.config.REQUESTCALENDARS = getTypedValue(value, "string")
154
154
                            elif name == "DAYSAHEAD":
155
 
                                self.config.DAYSAHEAD = self.getTypedValue(value, "integer")
 
155
                                self.config.DAYSAHEAD = getTypedValue(value, "integer")
156
156
                            elif name == "STARTDATE":
157
 
                                self.config.STARTDATE = self.getTypedValue(value, "string")
 
157
                                self.config.STARTDATE = getTypedValue(value, "string")
158
158
                            elif name == "ENDDATE":
159
 
                                self.config.ENDDATE = self.getTypedValue(value, "string")
 
159
                                self.config.ENDDATE = getTypedValue(value, "string")
160
160
                            elif name == "ALLEVENTS":
161
 
                                self.config.ALLEVENTS = self.getTypedValue(value, "boolean")
 
161
                                self.config.ALLEVENTS = getTypedValue(value, "boolean")
162
162
                            elif name == "WORDSEARCH":
163
 
                                self.config.WORDSEARCH = self.getTypedValue(value, "string")
 
163
                                self.config.WORDSEARCH = getTypedValue(value, "string")
164
164
                            elif name == "LIMIT":
165
 
                                self.config.LIMIT = self.getTypedValue(value, "integer")
 
165
                                self.config.LIMIT = getTypedValue(value, "integer")
166
166
                            elif name == "NOWHO":
167
 
                                self.config.NOWHO = self.getTypedValue(value, "boolean")
 
167
                                self.config.NOWHO = getTypedValue(value, "boolean")
168
168
                            elif name == "TIMEFORMAT":
169
 
                                self.config.TIMEFORMAT = self.getTypedValue(value, "string")
 
169
                                self.config.TIMEFORMAT = getTypedValue(value, "string")
170
170
                            elif name == "DATEFORMAT":
171
 
                                self.config.DATEFORMAT = self.getTypedValue(value, "string")
 
171
                                self.config.DATEFORMAT = getTypedValue(value, "string")
172
172
                            elif name == "CONNECTION_TIMEOUT":
173
 
                                self.config.CONNECTION_TIMEOUT = self.getTypedValue(value, "integer")                                                             
 
173
                                self.config.CONNECTION_TIMEOUT = getTypedValue(value, "integer")
174
174
                            else:
175
175
                                self.logger.error("Unknown option in config file: " + name)
176
176
            else:
177
177
                self.logger.info("Config data file %s not found, using defaults and setting up config file for next time" % configfilepath)
178
 
                
 
178
 
179
179
                userconfigpath = os.path.join(os.path.expanduser('~'), ".config/"+app_name+"/")
180
180
                configsource = os.path.join(app_path, "config/"+module_name+".config")
181
 
                
 
181
 
182
182
                if os.path.exists(userconfigpath) == False:
183
183
                    os.makedirs(userconfigpath)
184
184
 
185
185
                shutil.copy(configsource, configfilepath)
186
 
                
 
186
 
187
187
        except Exception, e:
188
188
            self.logger.error(e.__str__()+"\n"+traceback.format_exc())
189
189
 
190
 
    def getTypedValue(self, value, expectedtype):
191
 
        
192
 
        try:
193
 
            if len(value.strip(" ")) == 0:
194
 
                return None
195
 
            
196
 
            elif value.lower() == "true":
197
 
                if expectedtype == "boolean":
198
 
                    return True
199
 
                else:
200
 
                    self.logger.error("Expected type was '%s', but the value '%s' was given"%(expectedtype, value))
201
 
                    
202
 
            elif value.lower() == "false":
203
 
                if expectedtype == "boolean":
204
 
                    return False
205
 
                else:
206
 
                    self.logger.error("Expected type was '%s', but the value '%s' was given"%(expectedtype, value))
207
 
                    
208
 
            elif self.isNumeric(value) == True:
209
 
                if expectedtype == "integer":
210
 
                    return int(value)
211
 
                else:
212
 
                    self.logger.error("Expected type was '%s', but the value '%s' was given"%(expectedtype, value))
213
 
                    
214
 
            else:
215
 
                return value
216
 
 
217
 
        except (TypeError, ValueError):
218
 
            self.logger.error("Cannot convert '%s' to expected type of '%s'"%(value,expectedtype))
219
 
            return value
220
 
                
221
190
    def getCalendarList(self):
222
 
        
 
191
 
223
192
        self.logger.info("Preparing google calendar list...")
224
 
        
 
193
 
225
194
        # prepare calendar list to retrieve
226
195
        if self.config.REQUESTCALENDARS != None:
227
196
            self.requestedCalendars = self.config.REQUESTCALENDARS.split(",")
228
 
        
 
197
 
229
198
        # get the list of calendars from google
230
199
        calendars = self.cal_client.GetAllCalendarsFeed()
231
200
 
242
211
 
243
212
        # clear the list
244
213
        self.requiredCalendars = []
245
 
        
 
214
 
246
215
        for cal in calendars.entry:
247
216
 
248
217
            cal.gcalcli_altLink = cal.GetAlternateLink().href
250
219
            cal.username    = urllib.unquote(match.group(1))
251
220
            cal.visibility  = urllib.unquote(match.group(2))
252
221
            cal.projection  = urllib.unquote(match.group(3))
253
 
            
 
222
 
254
223
            if len(self.requestedCalendars):
255
 
                
 
224
 
256
225
                # get the calendar name, updating it if an override is found
257
226
                calendarName = cal.title.text
258
227
                doc = minidom.parseString(str(cal))
259
228
                overrideName = doc.getElementsByTagNameNS(u'http://schemas.google.com/gCal/2005', 'overridename')
260
229
                if len(overrideName) > 0:
261
230
                    calendarName = overrideName[0].getAttribute("value")
262
 
                                
 
231
 
263
232
                for rc in self.requestedCalendars:
264
233
                    if rc.lower() == calendarName.lower():
265
234
                        self.requiredCalendars.append(cal)
266
235
            else:
267
 
                self.requiredCalendars.append(cal)    
268
 
            
 
236
                self.requiredCalendars.append(cal)
 
237
 
269
238
 
270
239
    def getOwnedCalendars(self):
271
240
 
272
241
        try:
273
242
 
274
243
            self.logger.info("Fetching owned calendars...")
275
 
            
 
244
 
276
245
            feed = self.cal_client.GetOwnCalendarsFeed()
277
 
        
 
246
 
278
247
            calendarDataList = []
279
 
        
 
248
 
280
249
            for mycalendar in zip(xrange(len(feed.entry)), feed.entry):
281
250
                calendarData = CalendarData(mycalendar.title.text)
282
251
                calendarDataList.append(calendarData)
283
 
    
 
252
 
284
253
            return calendarDataList
285
254
 
286
255
        except Exception,e:
287
256
            self.logger.error(e.__str__()+"\n"+traceback.format_exc())
288
257
            return []
289
 
        
 
258
 
290
259
    def getAllEvents(self):
291
260
 
292
261
        try:
293
 
    
 
262
 
294
263
            self.logger.info("Fetching all event data...")
295
 
              
 
264
 
296
265
            calendarDataEventList = []
297
266
 
298
267
            for cal in self.requiredCalendars:
303
272
                    for j, when in zip(xrange(len(event.when)), event.when):
304
273
                        for k, where in zip(xrange(len(event.where)), event.where):
305
274
                            # if the event's end time is after now then add it!
306
 
                            if self.getDateFromWhen(when.end_time) > now:                        
 
275
                            if self.getDateFromWhen(when.end_time) > now:
307
276
                                whoList = []
308
277
                                for l, who in zip(xrange(len(event.who)), event.who):
309
278
                                    whoList.append(who.email)
310
279
                                if len(whoList) == 0:
311
 
                                    whoList = None                        
 
280
                                    whoList = None
312
281
                                calendarDataEvent = CalendarEventData(event.title.text, when.start_time, when.end_time, where.value_string, event.content.text, whoList)
313
282
                                calendarDataEventList.append(calendarDataEvent)
314
 
                        
 
283
 
315
284
            return calendarDataEventList
316
285
 
317
286
        except Exception,e:
318
287
            self.logger.error(e.__str__()+"\n"+traceback.format_exc())
319
288
            return []
320
 
        
 
289
 
321
290
    def getTextQueryEvents(self, text_query='Project'):
322
291
 
323
292
        try:
324
293
 
325
294
            self.logger.info("Fetching text queried event data using text query of \"%s\"..."%text_query)
326
 
            
 
295
 
327
296
            calendarDataEventList = []
328
297
 
329
298
            for cal in self.requiredCalendars:
330
 
                 
 
299
 
331
300
                query = gdata.calendar.service.CalendarEventQuery(cal.username, cal.visibility, cal.projection, text_query)
332
301
                query.orderby = 'starttime'
333
 
                query.singleevents = 'true'        
 
302
                query.singleevents = 'true'
334
303
                feed = self.cal_client.CalendarQuery(query)
335
304
                now = datetime.now()
336
305
                for i, event in zip(xrange(len(feed.entry)), feed.entry):
337
306
                    for j, when in zip(xrange(len(event.when)), event.when):
338
307
                        for k, where in zip(xrange(len(event.where)), event.where):
339
308
                            # if the event's end time is after now then add it!
340
 
                            if self.getDateFromWhen(when.end_time) > now:                        
 
309
                            if self.getDateFromWhen(when.end_time) > now:
341
310
                                whoList = []
342
311
                                for l, who in zip(xrange(len(event.who)), event.who):
343
312
                                    whoList.append(who.email)
345
314
                                    whoList = None
346
315
                                calendarDataEvent = CalendarEventData(event.title.text, when.start_time, when.end_time, where.value_string, event.content.text, whoList)
347
316
                                calendarDataEventList.append(calendarDataEvent)
348
 
    
 
317
 
349
318
            return calendarDataEventList
350
319
 
351
320
        except Exception,e:
352
321
            self.logger.error(e.__str__()+"\n"+traceback.format_exc())
353
322
            return []
354
 
        
 
323
 
355
324
    def getDateRangedEvents(self, start_date='2007-01-01', end_date='2020-01-01'):
356
325
 
357
326
        try:
358
327
 
359
328
            self.logger.info("Fetching date ranged event data for dates between %s and %s..."%(start_date,end_date))
360
 
            
 
329
 
361
330
            calendarDataEventList = []
362
331
 
363
332
            for cal in self.requiredCalendars:
364
 
                 
 
333
 
365
334
                query = gdata.calendar.service.CalendarEventQuery(cal.username, cal.visibility, cal.projection)
366
335
                query.start_min = start_date
367
336
                query.start_max = end_date
368
337
                query.orderby = 'starttime'
369
 
                query.singleevents = 'true'        
 
338
                query.singleevents = 'true'
370
339
                feed = self.cal_client.CalendarQuery(query)
371
340
                for i, event in zip(xrange(len(feed.entry)), feed.entry):
372
341
                    for j, when in zip(xrange(len(event.when)), event.when):
375
344
                            for l, who in zip(xrange(len(event.who)), event.who):
376
345
                                whoList.append(who.email)
377
346
                            if len(whoList) == 0:
378
 
                                whoList = None                    
 
347
                                whoList = None
379
348
                            calendarDataEvent = CalendarEventData(event.title.text, when.start_time, when.end_time, where.value_string, event.content.text, whoList)
380
349
                            calendarDataEventList.append(calendarDataEvent)
381
 
    
 
350
 
382
351
            return calendarDataEventList
383
352
 
384
353
        except Exception,e:
385
354
            self.logger.error(e.__str__()+"\n"+traceback.format_exc())
386
355
            return []
387
 
        
 
356
 
388
357
    def getFutureEvents(self, days_ahead=7):
389
358
 
390
359
        try:
391
360
 
392
361
            self.logger.info("Fetching future event data, for the next %s days..."%days_ahead)
393
 
                    
 
362
 
394
363
            calendarDataEventList = []
395
364
 
396
365
            for cal in self.requiredCalendars:
397
 
                 
 
366
 
398
367
                query = gdata.calendar.service.CalendarEventQuery(cal.username, cal.visibility, cal.projection)
399
368
                query.start_min = str(date.today())
400
369
                query.start_max = str(date.today()+timedelta(days=days_ahead))
406
375
                    for j, when in zip(xrange(len(event.when)), event.when):
407
376
                        for k, where in zip(xrange(len(event.where)), event.where):
408
377
                            # if the event's end time is after now then add it!
409
 
                            if self.getDateFromWhen(when.end_time) > now:                        
 
378
                            if self.getDateFromWhen(when.end_time) > now:
410
379
                                whoList = []
411
380
                                for l, who in zip(xrange(len(event.who)), event.who):
412
381
                                    whoList.append(who.email)
413
382
                                if len(whoList) == 0:
414
 
                                    whoList = None                        
 
383
                                    whoList = None
415
384
                                calendarDataEvent = CalendarEventData(event.title.text, when.start_time, when.end_time, where.value_string, event.content.text, whoList)
416
385
                                calendarDataEventList.append(calendarDataEvent)
417
 
    
 
386
 
418
387
            return calendarDataEventList
419
388
 
420
389
        except Exception,e:
421
390
            self.logger.error(e.__str__()+"\n"+traceback.format_exc())
422
391
            return []
423
 
            
 
392
 
424
393
    def getOutputFromTemplate(self, template, title, starttime, endtime, location, description, who):
425
 
        
 
394
 
426
395
        try:
427
 
            
 
396
 
428
397
            output = template
429
 
    
 
398
 
430
399
            if title == None or title.strip() == "":
431
 
                output = self.removeLineByString(output,"[title]")
 
400
                output = removeLineByString(output,"[title]")
432
401
            else:
433
402
                output = output.replace("[title]",title)
434
 
                
 
403
 
435
404
            if location == None or location.strip() == "":
436
 
                output = self.removeLineByString(output,"[location]")
 
405
                output = removeLineByString(output,"[location]")
437
406
            else:
438
407
                output = output.replace("[location]",location)
439
 
                
 
408
 
440
409
            if description == None or description.strip() == "":
441
 
                output = self.removeLineByString(output,"[description]")
 
410
                output = removeLineByString(output,"[description]")
442
411
            else:
443
412
                output = output.replace("[description]",description)
444
 
                
 
413
 
445
414
            if who == None or who.strip() == "":
446
 
                output = self.removeLineByString(output,"[who]")
 
415
                output = removeLineByString(output,"[who]")
447
416
            else:
448
417
                #output = output.replace("[who]",";".join(who))
449
418
                output = output.replace("[who]",who)
450
 
            
 
419
 
451
420
            output = output.replace("[starttime]",starttime)
452
421
            output = output.replace("[endtime]",endtime)
453
 
            
 
422
 
454
423
            # get rid of any excess crlf's and add just one
455
424
            #output = output.rstrip(" \n")
456
425
            #output = output + "\n"
457
 
            
458
 
            return output.encode("utf-8")
459
 
        
 
426
 
 
427
            return output #output.encode("utf-8")
 
428
 
460
429
        except Exception,e:
461
430
            self.logger.error(e.__str__()+"\n"+traceback.format_exc())
462
431
            return ""
463
432
 
464
433
    def getDatetimeFormat(self,dateformat=None,timeformat=None):
465
 
        
 
434
 
466
435
        try:
467
 
            
 
436
 
468
437
            # get locale defaults for output
469
438
            locale.setlocale(locale.LC_ALL,'')
470
 
    
 
439
 
471
440
            # format date based on format setting
472
441
            if dateformat == None:
473
442
                self.dateformat = "%a "+locale.nl_langinfo(locale.D_FMT)
484
453
 
485
454
        except Exception,e:
486
455
            self.logger.error(e.__str__()+"\n"+traceback.format_exc())
487
 
                
 
456
 
488
457
    def getDateFromWhen(self,when, stringformat=False):
489
458
 
490
459
        try:
491
 
            
 
460
 
492
461
            # is this a datetime or just date field
493
462
            if len(when) > 10:
494
463
                dateandtime = True
495
464
            else:
496
465
                dateandtime = False
497
 
            
 
466
 
498
467
            # convert to datetime field
499
468
            if dateandtime == True:
500
 
                whendatetime = datetime.strptime(when[0:19], "%Y-%m-%dT%H:%M:%S")             
 
469
                whendatetime = datetime.strptime(when[0:19], "%Y-%m-%dT%H:%M:%S")
501
470
            else:
502
471
                whendatetime = datetime.strptime(when[0:10], "%Y-%m-%d")
503
 
    
 
472
 
504
473
            # if string formatting required, format to a string using locale
505
474
            if stringformat == True:
506
475
                if dateandtime == True:
513
482
                        whendatetime = whendatetime.strftime(locale.nl_langinfo(locale.D_FMT))
514
483
                    else:
515
484
                        whendatetime = whendatetime.strftime(self.dateformat)
516
 
            
 
485
 
517
486
                # remove excess space between date and time if necessary
518
487
                whendatetime = whendatetime.replace("  "," ")
519
 
            
 
488
 
520
489
            return whendatetime
521
 
        
 
490
 
522
491
        except Exception,e:
523
 
            self.logger.error(e.__str__()+"\n"+traceback.format_exc())        
 
492
            self.logger.error(e.__str__()+"\n"+traceback.format_exc())
524
493
 
525
494
    def getOutput(self):
526
 
        
 
495
 
527
496
        try:
528
 
            
 
497
 
529
498
            ################ GOOGLE CALENDAR DATA RETRIEVAL #########################
530
 
            
 
499
 
531
500
            # determine the required query and run it
532
501
            if self.config.WORDSEARCH != None:
533
502
                calendarEventDataList = self.getTextQueryEvents(self.config.WORDSEARCH)
540
509
                calendarEventDataList = self.getAllEvents()
541
510
            else:
542
511
                calendarEventDataList = self.getFutureEvents(self.config.DAYSAHEAD)
543
 
              
 
512
 
544
513
            ################ PREPARE FOR OUTPUT ##############################
545
514
 
546
515
            self.logger.info("Processing output...")
557
526
            else:
558
527
                headertemplatefilepath = app_path+"/templates/googlecalendarheader.template"
559
528
                self.logger.info("Using default header template")
560
 
                
 
529
 
561
530
            # load the file
562
531
            try:
563
532
                inputfile = codecs.open(os.path.expanduser(headertemplatefilepath), encoding='utf-8')
567
536
                headertemplate = inputfile.read()
568
537
            finally:
569
538
                inputfile.close()
570
 
                                    
 
539
 
571
540
            if self.options.template != None:
572
541
                templatefilepath = self.options.template
573
542
                self.logger.info("Using custom template file '%s'"%templatefilepath)
577
546
            else:
578
547
                templatefilepath = app_path+"/templates/googlecalendar.template"
579
548
                self.logger.info("Using default template")
580
 
                 
 
549
 
581
550
            # load the file
582
551
            try:
583
552
                inputfile = codecs.open(os.path.expanduser(templatefilepath), encoding='utf-8')
587
556
                template = inputfile.read()
588
557
            finally:
589
558
                inputfile.close()
590
 
            
 
559
 
591
560
            ################ PROCESS OUTPUT #########################################
592
561
            calendarEventCount = 0
593
562
            calendarEventDataList.sort()
594
 
        
 
563
 
595
564
            if len(calendarEventDataList) > 0:
596
 
                
 
565
 
597
566
                output = headertemplate
598
 
                
 
567
 
599
568
                # walk through the calendar events
600
569
                for calendarEventData in calendarEventDataList:
601
 
                    
 
570
 
602
571
                    # keep a tally of events output, if past the limit then exit
603
572
                    if self.config.LIMIT <> 0:
604
573
                        calendarEventCount = calendarEventCount+1
605
574
                        if calendarEventCount > self.config.LIMIT:
606
575
                            break
607
 
                
 
576
 
608
577
                    # collect calendar event data and format as we go
609
578
                    title = calendarEventData.title
610
579
                    starttime = self.getDateFromWhen(calendarEventData.starttime, True)
611
580
                    endtime = self.getDateFromWhen(calendarEventData.endtime, True)
612
 
                    
 
581
 
613
582
                    location = calendarEventData.location
614
583
                    if location <> None:
615
 
                        #location = self.getWrappedText(location, self.MAX_WIDTH, indent)
 
584
                        #location = getWrappedText(location, self.MAX_WIDTH, indent)
616
585
                        if len(location) > self.MAX_WIDTH:
617
586
                            location = location[0:self.MAX_WIDTH].replace("\n","")+"..."
618
 
        
 
587
 
619
588
                    description = calendarEventData.description
620
589
                    if description <> None:
621
 
                        #description = self.getWrappedText(description, self.MAX_WIDTH, indent)
 
590
                        #description = getWrappedText(description, self.MAX_WIDTH, indent)
622
591
                        if len(description) > self.MAX_WIDTH:
623
592
                            description = description[0:self.MAX_WIDTH].replace("\n","")+"..."
624
 
        
 
593
 
625
594
                    who = calendarEventData.who
626
595
                    if who != None:
627
596
                        if self.config.NOWHO == True:
632
601
                            if len(who) > self.MAX_WIDTH:
633
602
                                who = who[0:self.MAX_WIDTH]+"..."
634
603
                                #who = ";".join(who).replace(";",", ")
635
 
                                #who = self.getWrappedText(who, self.MAX_WIDTH, indent)
 
604
                                #who = getWrappedText(who, self.MAX_WIDTH, indent)
636
605
 
637
606
                    # ready text for html output
638
 
                    title = self.getHTMLText(title)
639
 
                    location = self.getHTMLText(location)
640
 
                    description = self.getHTMLText(description)
641
 
                    who = self.getHTMLText(who)
642
 
                
 
607
                    title = getHTMLText(title)
 
608
                    location = getHTMLText(location)
 
609
                    description = getHTMLText(description)
 
610
                    who = getHTMLText(who)
 
611
 
643
612
                    # output event data using the template
644
613
                    output = output + self.getOutputFromTemplate(template, title, starttime, endtime, location, description, who)
645
614
 
646
 
                return output.encode("utf-8")
647
 
        
 
615
                return output #.encode("utf-8")
 
616
 
648
617
            else:
649
618
                output = headertemplate
650
619
                output = output + "<p>No Events...<p>"
651
620
                return output.encode("utf-8")
652
 
                        
 
621
 
653
622
        except Exception,e:
654
623
            self.logger.error(e.__str__()+"\n"+traceback.format_exc())
655
624
 
656
 
    def removeLineByString(self,lines,string):
657
 
        
658
 
        # define list from multiple lines, to allow remove function
659
 
        lineslist = lines.split("\n")
660
 
        lineslistchanged = False
661
 
        
662
 
        for line in lineslist:
663
 
            if line.find(string) <> -1:
664
 
                lineslist.remove(line)
665
 
                lineslistchanged = True
666
 
                break
667
 
            
668
 
        if lineslistchanged == True:
669
 
            # rebuild lines string from updated list
670
 
            lines = "\n".join(lineslist)
671
 
            
672
 
        return lines
673
 
    
674
 
    def getSpaces(self,spaces):
675
 
        string = ""
676
 
        for i in range(0, spaces+1):
677
 
            string = string + " "
678
 
        return string
679
 
 
680
 
    def getWrappedText(self,text,width=40,indent=""):
681
 
        wrappedtext=""
682
 
        for line in textwrap.wrap(text,width=(width-len(indent)),expand_tabs=False,replace_whitespace=False):
683
 
            wrappedtext = wrappedtext + "\n" + indent + line
684
 
        return wrappedtext
685
 
 
686
 
    def getHTMLText(self,text):
687
 
        try:
688
 
            htmlentities = []               
689
 
            for char in text: #html:
690
 
                if ord(char) < 128:
691
 
                    htmlentities.append(char)
692
 
                else:
693
 
                    htmlentities.append('&%s;' % codepoint2name[ord(char)])
694
 
            html = "".join(htmlentities)
695
 
            
696
 
            html = html.replace("\n","<br>\n") # switch out new line for html breaks
697
 
            return html            
698
 
        except:
699
 
            return text
700
 
 
701
 
    def getCleanText(self,html):
702
 
        try:
703
 
            text = str(html)
704
 
            text = text.replace("\n","") # remove new lines from html
705
 
            text = text.replace("&apos;","'") # workaround for shitty xml codes not compliant with html
706
 
            text = text.replace("<br>","\n") # switch out html breaks for new line
707
 
            text = re.sub('<(.|\n)+?>','',text) # remove any html tags
708
 
            text =  re.sub('&(%s);' % '|'.join(name2codepoint), lambda m: chr(name2codepoint[m.group(1)]), text)
709
 
            return text            
710
 
        except:
711
 
            return html
712
 
    
713
 
    def isNumeric(self, string):
714
 
        try:
715
 
            dummy = float(string)
716
 
            return True
717
 
        except:
718
 
            return False
719
 
        
720
625
def getHTML(options):
721
626
    output = Output(options)
722
627
    html = output.getOutput()
725
630
 
726
631
# to enable testing in isolation
727
632
if __name__ == "__main__":
728
 
    
 
633
 
729
634
    parser = OptionParser()
730
 
    parser.add_option("--noheader", dest="noheader", default=False, action="store_true", help=u"Turn off header output. This will override any header template setting to be nothing")        
 
635
    parser.add_option("--noheader", dest="noheader", default=False, action="store_true", help=u"Turn off header output. This will override any header template setting to be nothing")
731
636
    parser.add_option("--headertemplate", dest="headertemplate", type="string", metavar="FILE", help=u"Override the header template for the plugin, default or config based template ignored.")
732
637
    parser.add_option("--template", dest="template", type="string", metavar="FILE", help=u"Override the template for the plugin, default or config based template ignored.")
733
638
    parser.add_option("--verbose", dest="verbose", default=False, action="store_true", help=u"Outputs verbose info to the terminal")
734
639
    parser.add_option("--version", dest="version", default=False, action="store_true", help=u"Displays the version of the script.")
735
 
    parser.add_option("--logfile", dest="logfile", type="string", metavar="FILE", help=u"If a filepath is set, the script logs to the filepath.")                
736
 
    
 
640
    parser.add_option("--logfile", dest="logfile", type="string", metavar="FILE", help=u"If a filepath is set, the script logs to the filepath.")
 
641
 
737
642
    (options, args) = parser.parse_args()
738
 
        
 
643
 
739
644
    output = Output(options)
740
645
    html = output.getOutput()
741
646
    del output