Package for bionic
[public/library.git] / librarian
1 #!/usr/bin/env python3
2
3 import curses
4 import library.database as db
5 import library.interface.browser as browser
6 import library.interface.form as form
7 import library.interface.help_bar as helpBar
8 import library.interface.checkout as co
9 import library.interface.sendemails as sendemails
10
11 from  library import book_data
12
13 class SmallScreenException(Exception):
14     def __init__(self, *args, **kwargs):
15         Exception.__init__(self, *args, **kwargs)
16
17 stdscr=0
18 hb=0
19
20 menu_commands = [(' q','quit')]
21
22 def menutest(s, l):
23     global stdscr
24     global hb
25     stdscr=s
26     curses.use_default_colors() # colours will use terminal defaults
27     curses.curs_set(0)
28     (rows,cols)=stdscr.getmaxyx()
29     # set the default for the browser windows
30     browser.browserWindow._default_height = rows-10
31     browser.browserWindow._default_width = cols-10
32     bar = curses.newwin(1,cols-2,rows-1,1)
33     hb = helpBar.helpBar(bar)
34     hb.command=menu_commands
35     hb.refresh()
36     w = curses.newwin(15,40,(rows-10)//2, (cols-40)//2)
37
38     try:
39         menu(w, l)
40     except SystemExit: pass
41     except SmallScreenException:
42         text = """That's a small screen!
43 This librarian program won't work with a small screen.
44 Make your terminal window bigger and try again."""
45         form.error_form(text, stdscr, hb)
46         raise
47     except:
48         text = """An unexpected error occured.
49 Email the librarian (librarian@csclub.uwaterloo.ca)
50 with python's output after this program quits.
51 The program will now quit."""
52         form.error_form(text, stdscr, hb)
53         raise
54
55     curses.curs_set(1)
56
57 # item is a list of (string, callable) tuples
58 def menu(w, items):
59     w.keypad(1)
60     highlight=0
61     redrawMenu(w,items,highlight)
62
63     w.refresh()
64     ch=w.getch()
65     while (ch!=113 and ch!=27): # leave on q or ESC
66         if ch==curses.KEY_UP or ch==107 or ch==16:
67             if highlight!=0:
68                 w.chgat(highlight,0, 0)
69                 highlight -= 1
70                 while(items[highlight][0]==""):
71                     highlight -=1
72                 w.chgat(highlight,0, curses.A_REVERSE)
73         if ch==curses.KEY_DOWN or ch==106 or ch==14:
74             if highlight!=len(items)-1:
75                 w.chgat(highlight,0, 0)
76                 highlight += 1
77                 while(items[highlight][0]==""):
78                     highlight +=1
79                 w.chgat(highlight,0, curses.A_REVERSE)
80         if ch==curses.KEY_PPAGE:
81             w.chgat(highlight,0, 0)
82             highlight = 0
83             w.chgat(highlight,0, curses.A_REVERSE)
84         if ch==curses.KEY_NPAGE:
85             w.chgat(highlight,0, 0)
86             highlight = len(items)-1
87             w.chgat(highlight,0, curses.A_REVERSE)
88         if ch==114 or ch==10:
89             (s,f)=items[highlight]
90             f()
91             redrawMenu(w,items,highlight)
92         w.refresh()
93         ch = w.getch()
94
95 def redrawMenu(w,items,highlight):
96     i=0
97     for (mitem,fun) in items:
98         w.addstr(i,0, mitem)
99         i +=1
100     w.chgat(highlight, 0, curses.A_REVERSE)
101     w.refresh()
102     hb.commands=menu_commands
103     hb.refresh()
104
105
106 def addForm():
107     w=curses.newwin(1,1)
108     (my,mx)=stdscr.getmaxyx()
109     bf = form.BookForm(w,hb,width=mx-20)
110     (r,c)=w.getmaxyx()
111     try:
112         w.mvwin((my-r)//2,(mx-c)//2)
113     except curses.error as exc:
114         raise SmallScreenException("Terminal screen too small. Try again with a bigger terminal.") from exc
115     bf.lookup_isbn=book_data.openLibrary_isbn
116     bf.lookup_lccn=book_data.openLibrary_lccn
117     bf.caption='Add a Book'
118     bf.blabel = 'Add'
119     book = bf.event_loop()
120     bf.clear()
121     if len(book)!=0:
122         db.addBook(book)
123
124 def browseMenu():
125     w=curses.newwin(3,5)
126     b = browser.bookBrowser(w,hb)
127     (r,c) = w.getmaxyx()
128     (my,mx)=stdscr.getmaxyx()
129     try:
130         w.mvwin((my-r)//2 -2, (mx-c)//2)
131     except curses.error as exc:
132         raise SmallScreenException("Terminal screen too small. Try again with a bigger terminal.") from exc
133     b.refreshBooks()
134     b.eventLoop()
135     b.clear()
136
137 def trashMenu():
138     w=curses.newwin(3,5)
139     b = browser.trashBrowser(w,hb)
140     (r,c) = w.getmaxyx()
141     (my,mx)=stdscr.getmaxyx()
142     try:
143         w.mvwin((my-r)//2 -2, (mx-c)//2)
144     except curses.error as exc:
145         raise SmallScreenException("Terminal screen too small. Try again with a bigger terminal.") from exc
146     b.refreshBooks()
147     b.eventLoop()
148     b.clear()
149
150 def uncategorizedMenu():
151     w=curses.newwin(3,5)
152     b = browser.bookBrowser(w,hb)
153     (r,c) = w.getmaxyx()
154     (my,mx)=stdscr.getmaxyx()
155     try:
156         w.mvwin((my-r)//2 -2, (mx-c)//2)
157     except curses.error as exc:
158         raise SmallScreenException("Terminal screen too small. Try again with a bigger terminal.") from exc
159     b.refreshBooksUncategorized()
160     b.eventLoop()
161     b.clear()
162
163 def checkedout_menu():
164     w=curses.newwin(3,5)
165     b = browser.bookBrowser(w,hb)
166     (r,c) = w.getmaxyx()
167     (my,mx)=stdscr.getmaxyx()
168     try:
169         w.mvwin((my-r)//2 -2, (mx-c)//2)
170     except curses.error as exc:
171         raise SmallScreenException("Terminal screen too small. Try again with a bigger terminal.") from exc
172     b.refreshBooksCheckedout()
173     b.columnDefs = [("id",0,3),
174                     ("uwid",0,8),
175                     ("date",0,10),
176                     ("title",100,None)]
177     b.calcColWidths()
178     b.eventLoop()
179     b.clear()
180
181 def onshelf_menu():
182     w=curses.newwin(3,5)
183     b = browser.bookBrowser(w,hb)
184     (r,c) = w.getmaxyx()
185     (my,mx)=stdscr.getmaxyx()
186     try:
187         w.mvwin((my-r)//2 -2, (mx-c)//2)
188     except curses.error as exc:
189         raise SmallScreenException("Terminal screen too small. Try again with a bigger terminal.") from exc
190     b.refreshBooksOnshelf()
191     b.eventLoop()
192     b.clear()
193
194 def co_menu():
195     w=curses.newwin(1,1)
196     (my,mx)=stdscr.getmaxyx()
197     co.checkout_procedure(w,hb,my//2,mx//2,mx)
198
199 def return_menu():
200     w=curses.newwin(1,1)
201     (my,mx)=stdscr.getmaxyx()
202     co.return_procedure(w,hb,my//2,mx//2,mx)
203
204 def catMenu():
205     (my,mx)=stdscr.getmaxyx()
206     w=curses.newwin(3,5)
207     cat = browser.categoryBrowser(w,hb)
208     (r,c) = w.getmaxyx()
209     try:
210         w.mvwin((my-r)//2 -2, (mx-c)//2)
211     except curses.error as exc:
212         raise SmallScreenException("Terminal screen too small. Try again with a bigger terminal.") from exc
213     cat.refreshCategories()
214     cat.sortByColumn('category')
215     cat.eventLoop()
216     cat.clear()
217
218 def email_menu():
219     w=curses.newwin(1,1)
220     (my,mx)=stdscr.getmaxyx()
221     sendemails.sendemails_procedure(w,hb,my//2,mx//2,mx)
222
223
224 if __name__ == "__main__":
225     db.initializeDatabase()
226     m = [("Browse Library", browseMenu),
227          ("Add Book", addForm),
228          ("Categories", catMenu),
229          ("View Trash", trashMenu),
230          ("View Uncategorized Books", uncategorizedMenu),
231          ("",exit),
232          ("Check Out a Book", co_menu),
233          ("Return a Book", return_menu),
234          ("Send Overdue Email Reminders", email_menu),
235          ("",exit),
236          ("View Checked Out Books", checkedout_menu),
237          ("View On Shelf Books", onshelf_menu),
238          ("",exit),
239          ("Exit", exit)]
240     curses.wrapper(menutest, m)
241
242