2 # -*- coding: utf-8 -*-
4 # pylendar -- simple GTK calendar, with basic calendar features, that
5 # uses another application, like GNU Emacs org-mode, for
6 # agenda and project management.
7 # Copyright (C) 2009, 2010 Adrian C. <anrxc_sysphere_org>
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2 of the License, or
12 # (at your option) any later version.
15 # - http://www.pygtk.org/docs/pygtk/
20 from os
import path
, getenv
21 from subprocess
import call
22 from calendar
import month_name
23 # From 2.4 CALENDAR_WEEK_START_MONDAY is ignored and locales are used,
24 # which is broken, but if you still want it in your own language call:
26 locale
.setlocale(locale
.LC_ALL
, "en_US.utf-8")
31 # Name, Type, X, Y, Padding, Border, Timeout, Buttons
32 appprop
= ["Pylendar", gtk
.WINDOW_POPUP
, 1088, 14, 0, 5, 15000, True]
34 # Icon theme, icon size, icon category, icon name
35 appicon
= ["Tango", "16x16", "apps", "office-calendar.png"]
37 # Agenda and project management application, and options
38 appagen
= ["emacsclient", " --eval '(org-agenda-list)'"]
40 # Buttons and tooltips
42 1 : ["Agenda", "Open org-mode agenda in Emacs"],
43 2 : ["Close", "Close the calendar"],
44 3 : ["Praznici za", "Holidays in"]
47 # Local non-working holidays
49 1 : [["Nova Godina", 1],
50 ["Sveta tri kralja", 6]],
53 4 : [["Veliki petak", 2],
55 ["Uskrsni ponedjeljak", 5]],
56 5 : [["Praznik rada", 1]],
58 ["Dan antifašističke borbe", 22],
59 ["Dan državnosti", 25]],
61 8 : [["Dan domovinske zahvalnosti", 5],
62 ["Dan domovinske zahvalnosti", 6],
63 ["Velika Gospa", 15]],
65 10 : [["Dan neovisnosti", 8]],
66 11 : [["Svi sveti", 1]],
68 ["Sveti Stjepan", 26]]
73 DEF_POS_X
, DEF_POS_Y
, DEF_PAD
= appprop
[2], appprop
[3], appprop
[4]
75 def calendar_select_icon(self
):
76 icopath
= '/'.join(appicon
)
77 xdgdata
= getenv("XDG_DATA_DIRS").split(":")
78 xdgdata
.append(getenv("XDG_DATA_HOME"))
79 xdgdata
.append(getenv("HOME") + "/")
82 icopref
= i
.endswith("/") and ".icons/" or "/icons/"
83 if path
.isfile(i
+ icopref
+ icopath
):
84 pylendar_icon
= gtk
.gdk
.pixbuf_new_from_file(i
+ icopref
+ icopath
)
86 else: # Default to stock
87 pylendar_icon
= self
.window
.render_icon(gtk
.STOCK_EDIT
, gtk
.ICON_SIZE_DIALOG
)
90 def calendar_show_agenda(self
):
91 call(appagen
[0] + appagen
[1], shell
=True)
93 def calendar_month_changed(self
, widget
):
94 year
, month
, day
= self
.window
.get_date()
96 self
.window
.clear_marks()
98 tooltip
= "%s %s:" % (apptips
[3][0], month_name
[month
+1])
99 for key
, holiday
in list(nonworking
.items()):
100 if key
== month
+1 and holiday
:
102 self
.window
.mark_day(i
[1])
103 # Even out all dates for aligned table-like display
104 if len(str(i
[1])) < 2:
105 tableday
= "0%.0f" % i
[1]
108 tooltip
= "%s\n | %s.%s | %s" % (tooltip
, str(tableday
), str(key
), i
[0])
109 self
.window
.set_tooltip_text(tooltip
)
112 def __init__(self
, monthspec
=None):
114 # Create a new window
115 window
= gtk
.Window(appprop
[1])
116 # - floating when TOPLEVEL
117 window
.set_resizable(False)
118 # - window properties
119 window
.set_title(appprop
[0])
120 window
.set_border_width(appprop
[5])
122 # Connect the destroy event to a handler
123 window
.connect("destroy", lambda x
: gtk
.main_quit())
124 # Auto exit after timeout
125 timer
= gobject
.timeout_add(appprop
[6], lambda: gtk
.main_quit())
127 # The top part of the window: calendar box
128 vbox
= gtk
.VBox(False, self
.DEF_PAD
)
129 hbox
= gtk
.HBox(False, self
.DEF_PAD
)
130 hbbox
= gtk
.HButtonBox()
132 vbox
.pack_start(hbox
, True, True, self
.DEF_PAD
)
133 hbox
.pack_start(hbbox
, False, False, self
.DEF_PAD
)
134 hbbox
.set_layout(gtk
.BUTTONBOX_SPREAD
)
139 hbbox
.pack_start(frame
, False, True, self
.DEF_PAD
)
140 calendar
= gtk
.Calendar()
141 self
.window
= calendar
144 # GTK_CALENDAR_SHOW_HEADING = 1 << 0,
145 # GTK_CALENDAR_SHOW_DAY_NAMES = 1 << 1,
146 # GTK_CALENDAR_NO_MONTH_CHANGE = 1 << 2,
147 # GTK_CALENDAR_SHOW_WEEK_NUMBERS = 1 << 3,
148 # GTK_CALENDAR_WEEK_START_MONDAY = 1 << 4,
149 # GTK_CALENDAR_SHOW_DETAILS = 1 << 5
150 # As default, show heading, show days and allow date changes
151 #self.window.set_display_options(3 + (1<<5))
153 # Show a specific month if requested on startup
154 if monthspec
in range(1, 13):
155 # Clear day selection if not viewing current month
156 if monthspec
!= self
.window
.get_date()[1]+1:
157 self
.window
.select_day(0)
158 self
.window
.select_month(monthspec
-1, self
.window
.get_date()[0])
160 # Fake a month change on startup, to get marks right away
161 self
.calendar_month_changed(calendar
)
163 # Put the finished widget in the frame
167 calendar
.connect("month_changed", self
.calendar_month_changed
)
171 # The bottom part of the window: button box
172 bbox
= gtk
.HButtonBox ()
173 vbox
.pack_start(bbox
, False, False, 0)
174 bbox
.set_layout(gtk
.BUTTONBOX_SPREAD
)
176 # Button widget: Agenda
177 # - modify default label for STOCK_EDIT
178 gtk
.stock_add([(gtk
.STOCK_EDIT
, apptips
[1][0], 0, 0, "")])
179 button
= gtk
.Button(stock
=gtk
.STOCK_EDIT
)
180 button
.connect("clicked", lambda w
: self
.calendar_show_agenda())
182 button
.set_tooltip_text(apptips
[1][1])
184 # Button widget: Close
185 # - modify default label for STOCK_CANCEL
186 gtk
.stock_add([(gtk
.STOCK_CANCEL
, apptips
[2][0], 0, 0, "")])
187 button
= gtk
.Button(stock
=gtk
.STOCK_CANCEL
)
188 button
.connect("clicked", lambda w
: gtk
.main_quit())
190 # - this is the default button
191 button
.set_flags(gtk
.CAN_DEFAULT
)
192 button
.grab_default()
193 button
.set_tooltip_text(apptips
[2][1])
195 # Set application icon
196 gtk
.window_set_default_icon(self
.calendar_select_icon())
198 # Position the window
199 window
.move(self
.DEF_POS_X
, self
.DEF_POS_Y
)
210 if __name__
== "__main__":
215 PyLendar(int(argv
[1]))
217 raise SystemExit("Usage: %s [month (1-12)]" % path
.split(argv
[0])[1])