Skip to content

Commit 215f0ef

Browse files
committed
moving nagme into github -- first commit in new repo
Signed-off-by: Santosh S <[email protected]>
0 parents  commit 215f0ef

File tree

3 files changed

+563
-0
lines changed

3 files changed

+563
-0
lines changed

nagme.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from nagme_gui import tui
2+
3+
if __name__ == "__main__":
4+
t = tui()
5+
t.main()

nagme_gui.py

+367
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
#
2+
# GUI for the timer implementation
3+
#
4+
# Copyright (C) 2011 Santosh Sivaraj <[email protected]>
5+
#
6+
# This program is free software; you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation; either version 2 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with this program; if not, write to the Free Software
18+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19+
# 02110-1301, USA
20+
#
21+
22+
# List of Todo items:
23+
# TODO Update the timer list when a new timer is added when there was none
24+
# TODO system tray notification when timer has expired
25+
# TODO Play sound when timer expires
26+
# TODO There is a timing issue in label update and expiry (see 153,154 in timer_timer)
27+
# TODO Remove timer thread and implement as a schedulable time event, so we don't loop and waste cycles
28+
29+
from nagme_timer import Timer
30+
from collections import deque
31+
import pygtk
32+
pygtk.require('2.0')
33+
import gtk, gobject
34+
import time
35+
from datetime import datetime
36+
import os
37+
if os.name == 'nt':
38+
import winsound, sys
39+
40+
class MessageDialog_nb(gtk.MessageDialog):
41+
42+
def __init__(self, parent=None, typ=gtk.MESSAGE_INFO,
43+
buttons=gtk.BUTTONS_NONE, message_format=None):
44+
super(MessageDialog_nb, self).__init__(parent,
45+
gtk.DIALOG_DESTROY_WITH_PARENT|gtk.DIALOG_MODAL,
46+
typ, buttons,
47+
message_format)
48+
49+
def dialog_response_cb(self, response_id, param):
50+
self.destroy()
51+
52+
def run_nb(self):
53+
if not self.modal:
54+
self.set_modal(True)
55+
self.connect('response', self.dialog_response_cb)
56+
self.show()
57+
58+
class tui(Timer):
59+
notify_event = ("added", "expired", "deleted")
60+
TIMER_ADDED = 0
61+
TIMER_EXPIRED = 1
62+
TIMER_DELETED = 2
63+
64+
def stop(self):
65+
return super(tui, self).stop()
66+
67+
def delete_event(self, widget, event, data=None):
68+
if self.confirm_close:
69+
dialog = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL,
70+
gtk.MESSAGE_INFO, gtk.BUTTONS_YES_NO,
71+
"Sure you wanna quit??? Click \'No\' to keep nagging you.")
72+
dialog.set_title("Exit timer?")
73+
74+
response = dialog.run()
75+
dialog.destroy()
76+
if response == gtk.RESPONSE_YES:
77+
return False
78+
return True
79+
80+
return False
81+
82+
def destroy(self, widget, data=None):
83+
self.stop()
84+
gtk.main_quit()
85+
86+
def notify(self, event, timer_text, title=None):
87+
d = {'text':timer_text, 'title':title if title else self.notify_event[event],
88+
'type':self.notify_event[event]}
89+
self.notify_list.append(d)
90+
91+
def get_values(self, widget, data=None):
92+
txt = self.textentry.get_text()
93+
94+
if self.relative_time:
95+
self.add_timer_rel(self.hourspin.get_value_as_int(),
96+
self.minspin.get_value_as_int(),
97+
txt)
98+
else:
99+
self.add_timer(self.hourspin.get_value_as_int(),
100+
self.minspin.get_value_as_int(), txt)
101+
102+
self.reset_values(widget, data)
103+
self.update_timer_list()
104+
105+
def reset_values(self, widget, data=None):
106+
self.textentry.set_text("")
107+
108+
if self.relative_time:
109+
self.hourspin.spin(gtk.SPIN_HOME)
110+
self.minspin.spin(gtk.SPIN_HOME)
111+
else:
112+
t = time.localtime(time.time())
113+
self.hourspin.set_value(t[3])
114+
self.minspin.set_value(t[4])
115+
116+
def toggle_window_hide(self):
117+
if self.mainwin_hidden:
118+
self.window.show()
119+
self.window.deiconify()
120+
else: self.window.hide()
121+
122+
self.mainwin_hidden = not self.mainwin_hidden
123+
self.statusicon.set_visible(self.mainwin_hidden)
124+
125+
def status_clicked(self, status):
126+
self.toggle_window_hide()
127+
#self.statusicon.set_tooltip("the window is visible")
128+
129+
def timer_timer(self, pobj):
130+
while len(self.notify_list):
131+
i = self.notify_list.popleft()
132+
text = "<big><b>" + i['title'].capitalize() + "</b></big>\n\n<tt>" + i['text'] + "</tt>"
133+
134+
if self.expander.get_expanded():
135+
if not self.next_timer:
136+
self.expander.set_expanded(False)
137+
else:
138+
self.update_timer_list()
139+
140+
if i['type'] == "expired":
141+
self.update_timer_list()
142+
md = MessageDialog_nb(self.window, gtk.MESSAGE_INFO,
143+
gtk.BUTTONS_OK, None)
144+
md.set_markup(text)
145+
#self.statusicon.set_tooltip(i['text'])
146+
md.run_nb()
147+
if os.name == 'nt':
148+
winsound.PlaySound("*", winsound.SND_ALIAS)
149+
150+
self.statusbar.push(0, i['title'] + " " + i['text'])
151+
152+
# Countdown
153+
if not self.mainwin_hidden:
154+
if self.next_timer:
155+
t = datetime.fromtimestamp(self.next_timer) - datetime.now()
156+
text = "<i>Next:</i> <b><tt>" + self.get_timer_text(self.next_timer) + "</tt></b> <i>in</i>\n<big>" + str(t).split(".")[0] + "</big>"
157+
else:
158+
text = "<b>Nothing to remind</b>"
159+
160+
self.timer_counter.set_markup(text)
161+
162+
return True
163+
164+
def win_state_cb(self, widget, event):
165+
if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED:
166+
if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED:
167+
self.toggle_window_hide()
168+
169+
def relative_time_cb(self, tb):
170+
self.relative_time = not tb.get_active()
171+
172+
txt = self.textentry.get_text()
173+
self.reset_values(None, None)
174+
# Put back whatever text was there, reset_values resets all fields
175+
self.textentry.set_text(txt)
176+
177+
def confirm_close_cb(self, tb):
178+
self.confirm_close = tb.get_active()
179+
180+
def update_timer_list(self):
181+
if self.expander.get_expanded() and self.next_timer:
182+
self.liststore.clear()
183+
tl = self.get_timerlist()
184+
if tl:
185+
for t in tl:
186+
self.liststore.append(t)
187+
188+
def update_expander(self, expander):
189+
if not self.next_timer:
190+
label = gtk.Label("You haven't added anything")
191+
expander.add(label)
192+
label.show()
193+
return;
194+
195+
box = gtk.VBox(False, 0)
196+
self.liststore = gtk.ListStore(str, str)
197+
self.treeview = gtk.TreeView(self.liststore)
198+
# For timer text
199+
textcell = gtk.CellRendererText()
200+
self.textcol = gtk.TreeViewColumn("What?", textcell, text=0)
201+
self.textcol.set_property('resizable', True)
202+
# For time (in absolute values only)
203+
timecell = gtk.CellRendererText()
204+
self.timecol = gtk.TreeViewColumn("When?", timecell, text=1)
205+
self.timecol.set_property('resizable', True)
206+
self.treeview.append_column(self.textcol)
207+
self.treeview.append_column(self.timecol)
208+
box.pack_start(self.treeview, True, True, 0)
209+
self.treeview.show()
210+
211+
buttonDel = gtk.Button(label=None, stock=gtk.STOCK_DELETE)
212+
buttonDel.connect("clicked", self.del_timer, None)
213+
buttonDel.show()
214+
# label.set_size_request(200, 100)
215+
box.pack_start(buttonDel, False, True, 0)
216+
expander.add(box)
217+
box.show()
218+
219+
def del_timer(self, widget, data=None):
220+
selection = self.treeview.get_selection()
221+
model, iter = selection.get_selected()
222+
223+
if iter:
224+
i = selection.get_selected_rows()[1][0][0]
225+
model.remove(iter)
226+
tl = self.del_timer_at_index(i)
227+
self.notify(self.TIMER_DELETED, tl[1], "Deleted")
228+
229+
return
230+
231+
def expanded(self, expander, parameter):
232+
if expander.get_expanded():
233+
self.update_expander(expander)
234+
self.update_timer_list()
235+
else:
236+
if expander.child:
237+
expander.remove(expander.child)
238+
# expander.get_parent().resize(200, 1)
239+
240+
def create_window(self):
241+
# GTK initialisation
242+
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
243+
window.connect("delete_event", self.delete_event)
244+
window.connect("destroy", self.destroy)
245+
window.connect("window-state-event", self.win_state_cb)
246+
window.set_border_width(10)
247+
window.set_title("NagMe")
248+
window.set_resizable(False)
249+
250+
self.statusicon = gtk.status_icon_new_from_stock(gtk.STOCK_GOTO_TOP)
251+
self.statusicon.connect('activate', self.status_clicked)
252+
self.statusicon.set_visible(self.mainwin_hidden)
253+
254+
vbox = gtk.VBox(False, 5)
255+
256+
self.statusbar = gtk.Statusbar()
257+
vbox.pack_end(self.statusbar, False, True, 0)
258+
259+
# I need to say something
260+
label = gtk.Label("Don't forget things, just tell me, I will nag you!!\n"
261+
"What you want to be reminded of?")
262+
vbox.pack_start(label, True, True, 0)
263+
264+
self.textentry = gtk.Entry(max = 0)
265+
vbox.pack_start(self.textentry, True, True, 0)
266+
267+
self.ptimer = gobject.timeout_add(200, self.timer_timer, self)
268+
269+
hbox1 = gtk.HBox(True, 5)
270+
hbox2 = gtk.HBox(True, 5)
271+
hbox3 = gtk.HBox(True, 5)
272+
hbox0 = gtk.HBox(True, 5)
273+
vbox.pack_start(hbox1, True, True, 0)
274+
vbox.pack_start(hbox2, True, True, 0)
275+
vbox.pack_start(hbox3, True, True, 0)
276+
window.add(vbox)
277+
278+
label = gtk.Label("Hour :")
279+
label.set_alignment(0, 0.5)
280+
hbox1.pack_start(label, False, True, 0)
281+
adj = gtk.Adjustment(0, 0.0, 23.0, 1.0, 5.0, 0.0)
282+
self.hourspin = gtk.SpinButton(adj, 0, 0)
283+
self.hourspin.set_wrap(True)
284+
hbox1.pack_start(self.hourspin, False, True, 0)
285+
286+
label = gtk.Label("Minute :")
287+
label.set_alignment(0, 0.5)
288+
hbox1.pack_start(label, False, True, 0)
289+
adj = gtk.Adjustment(0, 0.0, 59.0, 1.0, 5.0, 0.0)
290+
self.minspin = gtk.SpinButton(adj, 0, 0)
291+
self.minspin.set_wrap(True)
292+
hbox1.pack_start(self.minspin, False, True, 0)
293+
294+
# Add a button for OK
295+
buttonOK = gtk.Button(label=None, stock=gtk.STOCK_ADD)
296+
buttonOK.connect("clicked", self.get_values, None)
297+
hbox2.pack_start(buttonOK, True, True, 0)
298+
add_tt = gtk.Tooltips()
299+
add_tt.set_tip(buttonOK, "Add timer", tip_private=None) # Tool tip
300+
301+
# Add a button for clearing
302+
buttonClear = gtk.Button(label=None, stock=gtk.STOCK_CLEAR)
303+
buttonClear.connect_object("clicked", self.reset_values, None)
304+
hbox2.pack_start(buttonClear, True, True, 0)
305+
clear_tt = gtk.Tooltips()
306+
clear_tt.set_tip(buttonClear, "Clear Form", tip_private=None)
307+
308+
# Close confirmation
309+
confirm_close_toggle = gtk.CheckButton("_Confirm Close?")
310+
confirm_close_toggle.connect("toggled", self.confirm_close_cb)
311+
confirm_close_toggle.set_active(self.confirm_close)
312+
hbox3.pack_start(confirm_close_toggle, True, True, 0)
313+
314+
# Relative or absolute timing?
315+
relative_time_toggle = gtk.CheckButton("_Absolute timing?")
316+
relative_time_toggle.connect("toggled", self.relative_time_cb)
317+
hbox3.pack_start(relative_time_toggle, True, True, 0)
318+
319+
# Make a display to list timers
320+
label_exp = gtk.Label("Timers")
321+
self.expander = gtk.Expander(None)
322+
self.expander.set_label_widget(label_exp)
323+
self.expander.connect("notify::expanded", self.expanded)
324+
vbox.pack_end(self.expander, True, True, 0)
325+
list_tt = gtk.Tooltips()
326+
list_tt.set_tip(self.expander, "Show all timers", tip_private=None)
327+
328+
self.timer_counter = gtk.Label("Nothing to remind")
329+
self.timer_counter.set_justify(gtk.JUSTIFY_CENTER)
330+
vbox.pack_start(self.timer_counter, True, True, 0)
331+
332+
return window
333+
334+
def __init__(self):
335+
self.notify_list = deque([])
336+
self.mainwin_hidden = False
337+
self.relative_time = True
338+
self.confirm_close = True
339+
340+
self.window = self.create_window()
341+
super(tui, self).__init__(self)
342+
self.window.show_all()
343+
self.start()
344+
345+
def main(self):
346+
gtk.main()
347+
#self.test_timer()
348+
349+
def test_timer(self):
350+
print "Nagme test start"
351+
self.add_timer_rel(5, 30, "Five hours from now")
352+
self.add_timer_rel(1, 0, "One hour from now")
353+
self.add_timer_rel(1, 0, "Another timer at one")
354+
self.add_timer_rel(23, 0, "New timer at 23 hours from now")
355+
self.add_timer_rel(12, 30, "Timer at 13 hours from now")
356+
self.add_timer_rel(2, 1, "A little later")
357+
self.add_timer_rel(0, 0, None)
358+
self.add_timer_rel(0, 0, "Now Now")
359+
self.add_timer_rel(0, 1, "1 min from now")
360+
self.list_timers()
361+
print "peek_next: " + str(self.peek_next())
362+
print "at_index: " + str(self.at_index(2))
363+
print "at_index: " + str(self.at_index(9))
364+
print "pop_next: " + str(test.pop_next())
365+
self.list_timers()
366+
self.print_times()
367+
print "Test complete"

0 commit comments

Comments
 (0)