""" Calendar Toplevel Window """ # Copyright (C) 2004 Henning Jacobs # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # $Id: CalendarWindow.py 82 2004-07-11 13:01:44Z henning $ import sys import os import string from Tkinter import * import tkMessageBox import Pmw import debug import broadcaster import broker import time class CalendarWindow: from JournalListWidget import JournalListWidget from JournalEditWidget import JournalEditWidget def __init__(self, model, tkroot=None): if not tkroot: tkroot = Tk() tkroot.withdraw() self.tkroot = tkroot self.model = model # Handle to DateStart Mapping: self._journaldates = {} self.createWidgets() self.centerWindow() self.registerAtBroadcaster() self.onJournalsOpen() def registerAtBroadcaster(self): "Register our Callback Handlers" broadcaster.Register(self.onJournalsOpen, source='Journals', title='Opened') broadcaster.Register(self.onJournalsClose, source='Journals', title='Closed') broadcaster.Register(self.onJournalNew, source='Journal', title='Added') broadcaster.Register(self.onJournalDel, source='Journal', title='Deleted') broadcaster.Register(self.onJournalSave, source='Journal', title='Saved') # Broadcasted by JournalWindow: broadcaster.Register(self.onJournalOpen, source='Journal', title='Opened') def createWidgets(self): "create the top level window" top = self.top = Toplevel(self.tkroot, class_='CalendarWindow') top.protocol('WM_DELETE_WINDOW', self.close) top.title('Calendar') top.iconname('PyCoCuMa') try: os.chdir(os.path.dirname(sys.argv[0])) if sys.platform == "win32": top.iconbitmap("pycocuma.ico") else: top.iconbitmap("@pycocuma.xbm") top.iconmask("@pycocuma_mask.xbm") except: debug.echo("Could not set TopLevel window icon") top.withdraw() from CalendarWidget import CalendarWidget self.monthdisp = CalendarWidget(top, selectcommand=self._daySelect, dblclickcommand=self._dayDblClick) self.monthdisp.grid() def centerWindow(self, relx=0.5, rely=0.3): "Center the Main Window on Screen" widget = self.top master = self.tkroot widget.update_idletasks() # Actualize geometry information if master.winfo_ismapped(): m_width = master.winfo_width() m_height = master.winfo_height() m_x = master.winfo_rootx() m_y = master.winfo_rooty() else: m_width = master.winfo_screenwidth() m_height = master.winfo_screenheight() m_x = m_y = 0 w_width = widget.winfo_reqwidth() w_height = widget.winfo_reqheight() x = m_x + (m_width - w_width) * relx y = m_y + (m_height - w_height) * rely if x+w_width > master.winfo_screenwidth(): x = master.winfo_screenwidth() - w_width elif x < 0: x = 0 if y+w_height > master.winfo_screenheight(): y = master.winfo_screenheight() - w_height elif y < 0: y = 0 widget.geometry("+%d+%d" % (x, y)) widget.deiconify() # Become visible at the desired location def _daySelect(self, date, createnew=0): # This variable prevents a looping callback: self._indayselectcallback = 1 datadict = {'date':date} if createnew: datadict['createnew'] = createnew broadcaster.Broadcast('Calendar', 'Date Selected', data=datadict) self._indayselectcallback = 0 def _dayDblClick(self, date): self.top.event_generate('<>') if self.monthdisp.getmarks().has_key(date): self._daySelect(date, createnew=0) else: # Create New Journal Entry for a free day self._daySelect(date, createnew=1) def onJournalsOpen(self): "Callback, triggered on Broadcast" handles = self.model.ListJournalHandles() # take only the first 10 chars from dtstart, remainder could be time: dates = map(lambda x: x[:10], self.model.QueryJournalAttributes(handles, 'DateStart')) self._journaldates = dict(zip(handles, dates)) self.monthdisp.setmarks(dict(zip(dates,[None]*len(dates)))) def onJournalsClose(self): "Callback, triggered on Broadcast" self.monthdisp.setmarks({}) _indayselectcallback = 0 def onJournalOpen(self): "Callback, triggered on Broadcast by JournalWindow" if not self._indayselectcallback: # dtstart may include time, we take only the first 10 characters: year, month, day = tuple(map(int, broadcaster.CurrentData()['dtstart'][:10].split('-'))) self.monthdisp.setmonth(year, month) self.monthdisp.setday(day) def onJournalNew(self): "Callback, registered at Broadcaster" handle = broadcaster.CurrentData()['handle'] date = broadcaster.CurrentData()['dtstart'][:10] self._journaldates[handle] = date self.monthdisp.getmarks()[date] = 1 self.monthdisp.update() def onJournalDel(self): "Callback, registered at Broadcaster" handle = broadcaster.CurrentData()['handle'] date = self._journaldates[handle] del self._journaldates[handle] del self.monthdisp.getmarks()[date] self.monthdisp.update() def onJournalSave(self): "Callback, registered at Broadcaster" handle = broadcaster.CurrentData()['handle'] # Maybe the entry's date changed: # we take only the first 10 chars, because dtstart may include time: date = self.model.QueryJournalAttributes([handle], 'DateStart')[0][:10] # this mapping is for onDel only: olddate = self._journaldates[handle] if olddate != date: self._journaldates[handle] = date del self.monthdisp.getmarks()[olddate] self.monthdisp.getmarks()[date] = 1 self.monthdisp.update() def close(self, event=None): self.top.withdraw() def window(self): "Returns Tk's TopLevel Widget" return self.top def withdraw(self): "Withdraw: Forward to TopLevel Method" self.top.withdraw() def deiconify(self): "DeIconify: Forward to TopLevel Method" self.top.deiconify() def show(self): self.top.deiconify() self.top.lift() self.top.focus_set()