# USP Calendar/Reminder Plugin Version 1.0 ##Description:Calendar and Reminder Information import gtk import gtk.glade import sys import os import gobject import datetime import gconf import pango from execute import Execute from easygconf import SetGconf from easygconf import WriteGconf class pluginclass: """This is the main class for the plugin""" """It MUST be named pluginclass""" def __init__(self, USPWin): self.USPWin = USPWin #The Glade file for the plugin self.gladefile = os.path.join(os.path.dirname(__file__), "calrem.glade") #Read GLADE file self.wTree = gtk.glade.XML(self.gladefile,"window1") #These properties are NECESSARY to maintain consistency #throughout USP #Set 'window' property for the plugin (Must be the root widget) self.window = self.wTree.get_widget("window1") #Set 'heading' property for plugin self.heading = "Calendar/Reminders" #This should be the first item added to the window in glade self.content_holder = self.wTree.get_widget("eventbox1") self.cal=self.wTree.get_widget("calendar1") self.tasks=self.wTree.get_widget("TaskView") self.apps=self.wTree.get_widget("AppointView") #Specify plugin width self.width = 150 #Plugin icon self.icon = 'gnome-calendar.png' self.gconf_dir = '/apps/usp/plugins/calendar' self.client = gconf.client_get_default() self.client.add_dir('/apps/usp/plugins/calendar', gconf.CLIENT_PRELOAD_NONE) self.client.notify_add('/apps/usp/plugins/calendar/sticky',self.RegenPlugin) self.client.notify_add('/apps/usp/plugins/calendar/icon',self.RegenPlugin) self.client.notify_add('/apps/usp/plugins/calendar/heading_font_size',self.RegenPlugin) self.client.notify_add('/apps/usp/plugins/calendar/height',self.RegenPlugin) self.client.notify_add('/apps/usp/plugins/calendar/height_tasks',self.RegenPlugin) self.client.notify_add('/apps/usp/plugins/calendar/height_appoints',self.RegenPlugin) self.client.notify_add('/apps/usp/plugins/calendar/item_font_size',self.RegenPlugin) self.client.notify_add('/apps/usp/plugins/calendar/show_tasks_appoints',self.RegenPlugin) self.client.notify_add('/apps/usp/plugins/calendar/width',self.RegenPlugin) self.datetoday=datetime.datetime.today() #self.datetoday='20061009' """Test Date String for Debug/Testing""" #gobject.timeout_add(1000, self.DoTasks) #Connect event handlers dic = { "on_window1_destroy" : gtk.main_quit, "on_calendar1_day_selected_double_click" : self.runcal, "on_calendar1_day_selected" : self.setcal} self.wTree.signal_autoconnect(dic) self.GetGconfEntries() #Setup Viewers self.tstore=gtk.ListStore(str) self.tasks.set_model(self.tstore) self.trender = gtk.CellRendererText() self.trender.set_property('size',self.itemsize*1000) self.tcolumn = gtk.TreeViewColumn("Task",self.trender,text=0) self.tasks.append_column(self.tcolumn) self.astore=gtk.ListStore(str) self.apps.set_model(self.astore) self.arender = gtk.CellRendererText() self.arender.set_property('size',self.itemsize*1000) self.acolumn = gtk.TreeViewColumn("Task",self.arender,text=0) self.apps.append_column(self.acolumn) self.RegenPlugin() #items=["eventbox1","MainScrolledWindow","CalRemViewPort","vbox1","vbox2","vbox3","TaskLabel","AppointLabel","calendar1"] #i=0 #while i < len(items): # self.wTree.get_widget(items[i]).modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.customcolor)) # i+=1 return def RegenPlugin(self, *args, **kargs): self.GetGconfEntries() self.DoTasks() #gobject.timeout_add(1000, self.DoTasks) def GetGconfEntries(self): self.client = gconf.client_get_default() self.sticky = SetGconf( self.client, "bool", "/apps/usp/plugins/calendar/sticky", False ) self.minimized = SetGconf( self.client, "bool", "/apps/usp/plugins/calendar/minimized", False ) self.icon = SetGconf( self.client, "string", "/apps/usp/plugins/calendar/icon", "gnome-calendar.png" ) self.headingsize = SetGconf(self.client,'int','/apps/usp/plugins/calendar/heading_font_size',9) self.itemsize = SetGconf(self.client,'int','/apps/usp/plugins/calendar/item_font_size',8) self.h_apps = SetGconf(self.client,'int','/apps/usp/plugins/calendar/height_appoints', 56) if self.h_apps < 28: self.h_apps=28 self.h_tasks = SetGconf(self.client,'int','/apps/usp/plugins/calendar/height_tasks', 56) if self.h_tasks < 28: self.h_tasks=28 self.width= SetGconf(self.client,'int','/apps/usp/plugins/calendar/width', 220) if self.width < 220: self.width=220 self.height= SetGconf(self.client,'int','/apps/usp/plugins/calendar/height', 250) if self.height < 160: self.height=160 self.showtasksappoints= SetGconf(self.client,'bool','/apps/usp/plugins/calendar/show_tasks_appoints', False) def SetHidden( self, state ): if state == True: WriteGconf( self.client, "bool", "/apps/usp/plugins/calendar/minimized", True ) else: WriteGconf( self.client, "bool", "/apps/usp/plugins/calendar/minimized", False ) def runcal(self, widget): clicked_date=self.cal.get_date() # FOR SOME REASON MONTH IS ZERO OFFSET SO NEED TO ADD ONE TO MONTH ?????? evo_date=str(clicked_date[0])+str(clicked_date[1]+1).zfill(2)+str(clicked_date[2]).zfill(2) cmd=["evolution","calendar:///?startdate="+evo_date] pid = os.fork() if pid: os.chdir(os.path.expanduser("~")) os.spawnvp(os.P_NOWAIT,cmd[0], cmd) os._exit(0) self.USPWin.wTree.get_widget("window1").hide() # Reset Display to Today's Date self.cal.select_month(int(datetime.datetime.today().strftime("%m"))-1,int(datetime.datetime.today().strftime("%Y"))) self.cal.select_day(int(datetime.datetime.today().strftime("%d"))) def setcal(self, widget): clicked_date=self.cal.get_date() # FOR SOME REASON MONTH IS ZERO OFFSET SO NEED TO ADD ONE TO MONTH ?????? self.datetoday=datetime.datetime( clicked_date[0], clicked_date[1]+1, clicked_date[2] ) self.cal.clear_marks() self.DoTasks() def DoTasks(self, *args, **kargs): self.showtasksappoints = self.client.get_bool('/apps/usp/plugins/calendar/show_tasks_appoints') BoldDates = [] HStyle = pango.AttrList() attr = pango.AttrSize(self.headingsize*1000,0,-1) HStyle.insert(attr) LStyle = pango.AttrList() attr = pango.AttrSize(self.itemsize*1000,0,-1) LStyle.insert(attr) os.chdir(os.path.expanduser("~")) # Get Tasks File IN try: in_file=open(os.path.expanduser("~")+'/.evolution/tasks/local/system/tasks.ics','r') self.task_file=in_file.read() in_file.close() except: self.task_file="" # Get Appointments File IN #folder = os.path.expanduser("~")+'/.usp/plugins/' folder = os.path.expanduser("~")+'/.evolution/calendar/local/system/' pattern = "calendar.ics" filename = os.path.join(folder, pattern) self.app_file=[] try: in_file=open( filename, 'r' ) temp_in=in_file.readlines() in_file.close() self.app_file=temp_in except: self.app_file=[] # "Begin Parsing Tasks File....." taskview=[] start=self.task_file.find("BEGIN:VTODO") while start != -1: self.task_file=self.task_file[start:] self.task_file=self.task_file[self.task_file.find("SUMMARY:")+len("SUMMARY:"):] end=self.task_file.find("\n") sectionend=self.task_file.find("END:VTODO") if self.task_file[:sectionend].find("STATUS:COMPLETED")==-1: taskview.append(self.task_file[:end]) start=self.task_file.find("BEGIN:VTODO") # ".........End Parsing Tasks File." self.tstore.clear() # Add Tasks to List for reminds in taskview: self.tstore.append([reminds]) # "Begin Parsing Appointments File....." TotalAppoints = [] appsview = [] appdate = Summary = "" numlines = len(self.app_file) InEvent = False FreqArray = [] line = Interval = Numdays = Count = ByDayofMonth = 0 DayArray=["MO","TU","WE","TH","FR","SA","SU"] while line < numlines: Errored=False Test = self.app_file[line].strip( "\n" ) if Test.find( "BEGIN:VEVENT" ) != -1: FreqArray = [] ExcludeArray = [] Interval = Numdays = Count = ByDayofMonth = 0 appsview = [] InEvent = True if Test.find( "DTSTART;" ) != -1 and InEvent == True: # Have to check next line as Evolution randomly splits the line over two. NextLine = self.app_file[line+1] if NextLine.find( "TZID" ) != -1: Temp = NextLine.strip( "\n" ).strip( " " ).split(":") Test = Temp[1][0:8] appdate = Test[Test.find(":")+1:] elif Test.split(":")[1] == "": appdate = NextLine.strip()[0:8] else: appdate = Test.split(':')[1] appdateformat = self.datetoday.date try: appdateformat=datetime.date(int(appdate[0:4]),int(appdate[4:6]),int(appdate[6:8])) appsview.append(appdateformat) except: line += 1 InEvent = False if InEvent == True: EndLine=self.app_file[line+2] # Check old Nextline first if NextLine.find( "DTEND;" ) != -1: # Have to check next line as Evolution randomly splits the line over two. NextLine_2 = self.app_file[line+2] if NextLine.find( "TZID" ) != -1: Temp = NextLine.strip( "\n" ).strip( " " ).split(":") Test = Temp[1][0:8] appdate = Test[Test.find(":")+1:] elif Test.split(":")[1] == "": appdate = NextLine.strip()[0:8] else: appdate = Test.split(':')[1] appdateformat = self.datetoday.date try: appdateformat=datetime.date(int(appdate[0:4]),int(appdate[4:6]),int(appdate[6:8])) appsview.append(appdateformat) except: appsview.append("") pass elif EndLine.find( "DTEND;" ) != -1: #print EndLine # Have to check next line as Evolution randomly splits the line over two. NextLine_2 = self.app_file[line+3] if NextLine_2.find( "TZID" ) != -1: Temp = NextLine_2.strip( "\n" ).strip( " " ).split(":") Test = Temp[1][0:8] appdate = Test[Test.find(":")+1:] elif Test.split(":")[1] == "": appdate = NextLine_2.strip()[0:8] else: appdate = EndLine.split(':')[1] appdateformat = self.datetoday.date #print NextLine_2 try: appdateformat=datetime.date(int(appdate[0:4]),int(appdate[4:6]),int(appdate[6:8])) appsview.append(appdateformat) except: appsview.append("") pass else: appsview.append("") if InEvent == True: if Test.find( "EXDATE" ) != -1: exdate=Test.split(":")[1][0:8] try: Temp=datetime.date(int(exdate[0:4]),int(exdate[4:6]),int(exdate[6:8])) ExcludeArray.append(Temp) except: pass if Test.find( "RRULE" ) != -1: try: # Have to check next line as Evolution randomly splits the line over two. NextLine = self.app_file[line+1] if NextLine.find( "INTERVAL" ) != -1 or NextLine.find( "BYDAY" ) != -1 or NextLine.find( "BYMONTHDAY" ) != -1: Test = Test.strip( "\n" ) + NextLine.strip( "\n" ).strip( " " ) except: pass FreqArray=Test.split(":") FreqArray = FreqArray[1].split( ";" ) AddValuetoDays = False AddValuetoWeeks = False AddValuetoMonths = False AddValuetoYears = False if FreqArray[0] == 'FREQ=DAILY': AddValuetoDays = True Interval = int( FreqArray[2][9:].split( "\n" )[0] ) if FreqArray[0] == 'FREQ=WEEKLY': AddValuetoWeeks = True Interval = int( FreqArray[2][9:].split( "\n" )[0] )*7 if FreqArray[0] == 'FREQ=MONTHLY': AddValuetoMonths = True Interval = int( FreqArray[2][9:].split( "\n" )[0] ) try: ByDayofMonth = int( FreqArray[3][11:].split("\n")[0] ) except: ByDayofMonth = 0 pass if FreqArray[0] == 'FREQ=YEARLY': AddValuetoYears = True Count = int( FreqArray[1][6:].split("\n")[0] ) if Test.find( "SUMMARY:" ) != -1: SumStart = Test.find( "SUMMARY:" )+len( "SUMMARY:" ) SumStop = Test.find( "\n", SumStart ) Summary = Test[SumStart:] appsview.append(Summary) if Test.find( "END:VEVENT" ) != -1: appsview.append(FreqArray) appsview.append(ExcludeArray) TotalAppoints.append( appsview ) InEvent = False line += 1 clicked_date=self.cal.get_date() if self.USPWin.VERBOSE == True: print "\nTotalAppoints Array\n-------------------" DisplayAppoints = [] # Now work out Repeated Appointments for appoints in TotalAppoints: if self.USPWin.VERBOSE == True: print appoints if len( appoints[3] ) > 0: if appoints[3][0] == "FREQ=DAILY": Count = int( appoints[3][1][6:] ) Interval = int( appoints[3][2][9:] ) Ctr = 0 DisplayAppoints.append( [appdate, appoints[2]] ) while Ctr <= Count: advance=(Interval*Ctr) appdate=appoints[0]+datetime.timedelta( days = advance ) # Check if it's Excluded Excluded = False if len( appoints[4] ) > 0: try: appoints[4].index( appdate ) Excluded = True except: pass if Excluded == False: DisplayAppoints.append( [appdate, appoints[2]] ) Ctr+=1 if appoints[3][0] == "FREQ=WEEKLY": Count = int( appoints[3][1][6:] ) Interval = int( appoints[3][2][9:] ) * 7 ByDayofWeek = -1 if len( appoints[3] ) == 4: try: ByDayofWeek = DayArray.index( appoints[2][3][6:] ) except: pass Ctr = 0 DisplayAppoints.append( [appoints[0], appoints[2]] ) while Ctr < Count: if ByDayofWeek != -1: advance=(Interval*Ctr) + (ByDayofWeek+1) else: advance=(Interval*Ctr) appdate=appoints[0]+datetime.timedelta( days = advance ) # Check if it's Excluded Excluded = False if len( appoints[4] ) > 0: try: appoints[4].index( appdate ) Excluded = True except: pass if Excluded == False: DisplayAppoints.append( [appdate, appoints[2]] ) Ctr+=1 if appoints[3][0] == "FREQ=MONTHLY": Count = int( appoints[3][1][6:] ) Interval = int( appoints[3][2][9:] ) ByDayofMonth = -1 if len( appoints[3] ) == 4: try: ByDayofMonth = int( appoints[3][3][11:] ) except: pass Ctr = 0 DisplayAppoints.append( [appoints[0], appoints[2]] ) while Ctr < Count: appdate=self.addMonth( appoints[0], Interval*Ctr ) if ByDayofMonth != -1: appdate=appdate.replace(day=ByDayofMonth) # Check if it's Excluded Excluded = False if len( appoints[4] ) > 0: try: appoints[4].index( appdate ) Excluded = True except: pass if Excluded == False and appdate >= appoints[0]: DisplayAppoints.append( [appdate, appoints[2]] ) Ctr+=1 if appoints[3][0] == "FREQ=YEARLY": Count = int( appoints[3][1][6:] ) Interval = int( appoints[3][2][9:] ) Ctr = 1 DisplayAppoints.append( [appoints[0], appoints[2]] ) while Ctr < Count: appsyear = appoints[0].year + ( Interval*Ctr ) appdate = appoints[0].replace(year=appsyear) # Check if it's Excluded Excluded = False if len( appoints[4] ) > 0: try: appoints[4].index( appdate ) Excluded = True except: pass if Excluded == False and appdate >= appoints[0]: DisplayAppoints.append( [appdate, appoints[2]] ) Ctr+=1 else: done = False PostDate = appoints[0] Ctr = 1 while PostDate <= appoints[1]: DisplayAppoints.append( [PostDate, appoints[2]] ) PostDate = appoints[0]+datetime.timedelta( days = Ctr ) Ctr+=1 self.astore.clear() if self.USPWin.VERBOSE == True: print "\nDisplayAppoints Array\n---------------------" # Add Appointments to List for appoints in DisplayAppoints: if self.USPWin.VERBOSE == True: print appoints # Show Marked Dates in Bold if appoints[0].year == clicked_date[0] and (appoints[0].month-1) == clicked_date[1]: self.cal.mark_day(appoints[0].day) # FOR SOME REASON MONTH IS ZERO OFFSET SO NEED TO ADD ONE TO MONTH ?????? self.datetoday=datetime.datetime( clicked_date[0], clicked_date[1]+1, clicked_date[2] ) if appoints[0].year == self.datetoday.year and appoints[0].month == self.datetoday.month and appoints[0].day == self.datetoday.day: self.astore.append( [appoints[1]] ) # ".........End Parsing Appointments File." try: self.wTree.get_widget("CalRemViewPort").set_size_request(self.width,self.height) self.wTree.get_widget("scrolledwindow1").set_size_request(self.width,self.h_tasks) self.wTree.get_widget("scrolledwindow2").set_size_request(self.width,self.h_apps) except: pass self.wTree.get_widget("TaskLabel").set_attributes(HStyle) self.wTree.get_widget("AppointLabel").set_attributes(HStyle) if self.showtasksappoints != 0: #if len(taskview)==0: # self.wTree.get_widget("vbox2").hide() #else: self.wTree.get_widget("vbox2").show() #if len(appsview)==0: # self.wTree.get_widget("vbox3").hide() #else: self.wTree.get_widget("vbox3").show() else: self.wTree.get_widget("vbox2").hide() self.wTree.get_widget("vbox3").hide() return True def addMonth(self, date, n=1): OneDay = datetime.timedelta(days=1) # add n+1 months to date then subtract 1 day # to get eom, last day of target month q,r = divmod(date.month+n, 12) eom = datetime.date(date.year+q, r+1, 1) - OneDay if date.month != (date+OneDay).month or date.day >= eom.day: return eom return eom.replace(day=date.day) #---------------------------------------------------------------------------------------# # USPconfig Section Below #---------------------------------------------------------------------------------------# # This is the Config Class it must be called "cfgpluginclass' and the gtk.Window must be called 'config' class cfgpluginclass: def __init__(self): # The Gladefile for the plugins USPconfig Tab self.gladefile = os.path.join(os.path.dirname(__file__), "calrem.glade") # Read GLADE file self.wTree = gtk.glade.XML(self.gladefile,"config") # Set 'window' property for the plugin (Must be the root widget) self.window = self.wTree.get_widget("config") # Content Place Holder must be eventbox2 self.content_holder = self.wTree.get_widget("eventbox2") # Set Heading, this will be used for the tab label in USPconfig self.heading = "Cal/Rem" # GConf Stuff - This just makes sure a gconf path is there. self.gconf_dir = '/apps/usp/plugins/calendar' self.client = gconf.client_get_default() self.client.add_dir('/apps/usp/plugins/calendar', gconf.CLIENT_PRELOAD_NONE) # Setup the Functions of the Glade files spin controls or entry boxes for Value Changes # Tip: For spinbutton controls use the "_value_changed" event not the "_changed" event. dic = { "on_window2_destroy" : gtk.main_quit, "on_CalHSpin_changed" : self.height_spin, "on_CalWSpin_changed" : self.width_spin, "on_CalTasksHSpin_changed" : self.tasks_h_spin, "on_CalAppsHSpin_changed" : self.apps_h_spin, "on_CalHeadSizeSpin_changed" : self.head_spin, "on_CalItemSizeSpin_changed" : self.item_spin, "on_CalIconEntry_changed" : self.icon_changed, "on_CalShowChkBtn_toggled" : self.show_t_a, "on_StickyChkBtn_toggled" : self.sticky} self.wTree.signal_autoconnect(dic) # Read Values from GConf for USPconfig Tab and Set Default Values in GConf if they don't exist. self.wTree.get_widget("StickyChkBtn").set_active(SetGconf(self.client,'bool','/apps/usp/plugins/calendar/sticky',False)) self.wTree.get_widget("CalIconEntry").set_text(SetGconf( self.client, "string", '/apps/usp/plugins/calendar/icon', "gnome-calendar.png")) self.wTree.get_widget("CalHSpin").set_value(SetGconf(self.client,'int','/apps/usp/plugins/calendar/height',200)) self.wTree.get_widget("CalWSpin").set_value(SetGconf(self.client,'int','/apps/usp/plugins/calendar/width',250)) self.wTree.get_widget("CalTasksHSpin").set_value(SetGconf(self.client,'int','/apps/usp/plugins/calendar/height_tasks',80)) self.wTree.get_widget("CalAppsHSpin").set_value(SetGconf(self.client,'int','/apps/usp/plugins/calendar/height_appoints',80)) self.wTree.get_widget("CalHeadSizeSpin").set_value(SetGconf(self.client,'int','/apps/usp/plugins/calendar/heading_font_size',10)) self.wTree.get_widget("CalItemSizeSpin").set_value(SetGconf(self.client,'int','/apps/usp/plugins/calendar/item_font_size',8)) self.wTree.get_widget("CalShowChkBtn").set_active(SetGconf(self.client,'bool','/apps/usp/plugins/calendar/show_tasks_appoints',False)) # Functions for Changing Values when items checked or altered. def sticky(self, *args, **kargs): if self.wTree.get_widget("StickyChkBtn").get_active() == True: self.client.set_bool('/apps/usp/plugins/calendar/sticky',True) else: self.client.set_bool('/apps/usp/plugins/calendar/sticky',False) def icon_changed(self, *args, **kargs): self.client.set_string('/apps/usp/plugins/calendar/icon',self.wTree.get_widget("CalIconEntry").get_text()) def height_spin(self, *args, **kargs): self.client.set_int('/apps/usp/plugins/calendar/height',int(self.wTree.get_widget("CalHSpin").get_value())) def width_spin(self, *args, **kargs): self.client.set_int('/apps/usp/plugins/calendar/width',int(self.wTree.get_widget("CalWSpin").get_value())) def tasks_h_spin(self, *args, **kargs): self.client.set_int('/apps/usp/plugins/calendar/height_tasks',int(self.wTree.get_widget("CalTasksHSpin").get_value())) def apps_h_spin(self, *args, **kargs): self.client.set_int('/apps/usp/plugins/calendar/height_appoints',int(self.wTree.get_widget("CalAppsHSpin").get_value())) def head_spin(self, *args, **kargs): self.client.set_int('/apps/usp/plugins/calendar/heading_font_size',int(self.wTree.get_widget("CalHeadSizeSpin").get_value())) def item_spin(self, *args, **kargs): self.client.set_int('/apps/usp/plugins/calendar/item_font_size',int(self.wTree.get_widget("CalItemSizeSpin").get_value())) def show_t_a(self, *args, **kargs): if self.wTree.get_widget("CalShowChkBtn").get_active() == True: self.client.set_bool('/apps/usp/plugins/calendar/show_tasks_appoints',True) else: self.client.set_bool('/apps/usp/plugins/calendar/show_tasks_appoints',False)