4 from form import BookForm,CategoryForm
11 commands = [(' /', 'search'), (' n', 'find next'), (' N', 'find previous'),
12 ('F6', 'Sort Column'), (' q', 'quit')]
14 # column definitions are in (label, weight, specified width) triples
15 columnDefs = [('something',1,None)]
21 def __init__(self,window,helpbar, height=50, width=80):
24 self.w.resize(height,width)
26 self.commands = self.cs+self.commands
28 def sortByColumn(self, col):
29 self.entries.sort(key=lambda k: k.get(col,"")) # key=dict.get(col))
30 self.selected = list(map(lambda x: False, self.selected))
33 def updateGeometry(self):
34 (self.my,self.mx)=self.w.getmaxyx()
35 self.pageSize = self.my-4
38 def calcColWidths(self):
40 available_space = self.mx - len(self.columnDefs) -2
42 for label,weight,value in self.columnDefs:
44 available_space -= value
48 for label,weight,value in self.columnDefs:
50 cols.append((label,value))
52 cols.append((label,available_space*weight//total_weights))
56 self.hb.commands = self.commands
60 for r in range(0,self.pageSize):
69 def centreChild(self,child):
70 (y,x) = self.w.getbegyx()
71 (r,c) = child.getmaxyx()
72 child.mvwin( y+(self.my-r)//2,x+(self.mx-c)//2)
75 def displayHeader(self):
77 for header,width in self.columns:
78 self.w.addnstr(1,cursor,header+" "*width,width)
79 self.w.addstr(2,cursor,"-"*width)
82 def displayRow(self,row):
83 if self.topline+row < len(self.entries):
84 entry = self.entries[self.topline+row]
86 self.w.addnstr(row+3, 1, " "*self.mx,self.mx-2)
87 if self.selected[self.topline+row]:
88 self.w.addstr(row+3, 1, "*")
90 self.w.addstr(row+3, 1, " ")
91 for k,width in self.columns:
92 if k.lower() in entry:
93 self.w.addnstr(row+3, cursor,
94 str(entry[k.lower()])+" "*width, width)
97 self.w.addstr(row+3,1," "*(self.mx-2))
100 row = self.hl-self.topline+3
101 if row > 1 and row < self.my:
102 self.w.chgat(row,1,self.mx-2,curses.A_REVERSE)
104 def unHighlight(self):
105 row = self.hl-self.topline+3
106 if row > 1 and row < self.my:
107 self.w.chgat(row,1,self.mx-2,curses.A_NORMAL)
109 def mvHighlight(self,delta):
112 new = min(new,len(self.entries)-1)
117 def scroll(self,delta):
119 self.topline += delta
120 self.topline = min(self.topline,len(self.entries)-1)
121 self.topline = max(self.topline,0)
124 def search(self, string):
125 case_sensitive = not(string.islower())
126 #sys.stderr.write(str(case_sensitive)+'\n')
129 for e in self.entries:
130 for k,v in e.items():
131 # we or with found to make sure it is never "unfound"
133 found = str(v).find(string) != -1 or found
135 found = str(v).lower().find(string) != -1 or found
140 self.last_search = string
141 self.search_index = i
142 self.case_sensitive = case_sensitive
145 self.search_index = -1
148 def _find_again(self, direction=1):
149 """Find the next match in the entries
151 direction = 1 means look ahead
152 direction = -1 means look back
154 if self.last_search == "" or self.search_index == -1:
158 last = len(self.entries) -1
159 elif direction == -1:
161 for i in range(self.hl+direction, last, direction):
162 for k,v in self.entries[i].items():
163 if self.case_sensitive:
164 found = str(v).find(self.last_search) != -1 or found
166 found = str(v).lower().find(self.last_search) != -1 or found
170 self.search_index = i
180 while ch != 27 and ch != 113:
181 ch = self.handleInput(ch)
188 def handleInput(self,ch):
189 if ch == curses.KEY_UP or ch == 107 or ch == 16:
190 if self.hl == self.topline:
191 self.scroll(-self.pageSize//2-1)
193 elif ch == curses.KEY_DOWN or ch == 106 or ch == 14:
194 if self.hl == self.topline+self.pageSize-1:
195 self.scroll(+self.pageSize//2+1)
197 elif ch == curses.KEY_PPAGE:
198 self.scroll(-self.pageSize)
199 self.mvHighlight(-self.pageSize)
200 elif ch == curses.KEY_NPAGE:
201 self.scroll(+self.pageSize)
202 self.mvHighlight(+self.pageSize)
203 elif ch == curses.KEY_HOME:
204 self.scroll(-len(self.entries))
205 self.mvHighlight(-len(self.entries))
206 elif ch == curses.KEY_END:
207 self.scroll(len(self.entries))
208 self.mvHighlight(len(self.entries))
209 elif ch == 47: # forward slash
210 string = self.hb.getSearch()
211 hl = self.search(string)
215 self.mvHighlight(delta)
217 self.hb.display(string+' not found')
219 hl = self._find_again(+1)
223 self.mvHighlight(delta)
225 self.hb.display(self.last_search+' not found')
227 hl = self._find_again(-1)
231 self.mvHighlight(delta)
233 self.hb.display(self.last_search+' not found')
234 elif ch == 270: # F6 Sorts
235 w = curses.newwin(1,1)
236 cl = columnSelector(w,self.hb,40,20)
240 self.sortByColumn(col)
244 if len(self.selected)>0:
245 self.selected[self.hl] = not self.selected[self.hl]
246 self.displayRow(self.hl-self.topline)
251 class trashBrowser(browserWindow):
252 columnDefs = [('ID',0,3),
257 cs = [(' r', 'restore selected'), (' d', 'delete selected')]
259 # redefinable functions
260 def viewSelection(self,book):
263 bf = BookForm(w, self.hb, book, width=self.mx-10)
265 bf.caption='Viewing Book '+str(bookid)
270 def restoreSelected(self):
272 for sel,book in zip(self.selected, self.entries):
275 db.restoreBooks(books)
277 def delSelected(self):
279 for sel,book in zip(self.selected, self.entries):
282 db.deleteBooks(books)
284 def refreshBooks(self):
285 self.entries = db.getRemovedBooks()
286 self.selected = list(map(lambda x:False, self.entries))
288 def handleInput(self,ch):
289 browserWindow.handleInput(self,ch)
291 book = self.entries[self.hl]
292 self.viewSelection(book)
294 if ch==114: #restore books
296 for s in self.selected[0:self.hl-1]:
299 self.restoreSelected()
303 self.mvHighlight(-count)
304 if ch==100: # delete books
306 for s in self.selected[0:self.hl-1]:
313 self.mvHighlight(-count)
316 class bookBrowser(browserWindow):
317 columnDefs = [('ID',0,3),
322 cs = [(' u', 'update'), (' d', 'delete selected')]
324 # redefinable functions
325 def updateSelection(self,book):
329 bf = BookForm(w,self.hb,book, width=self.mx-20)
331 bf.caption='Update Book '+str(bookid)
333 newbook = bf.event_loop()
335 db.updateBook(newbook,bookid)
338 def viewSelection(self,book):
341 bf = BookForm(w,self.hb,book, width=self.mx-20)
343 bf.caption='Viewing Book '+str(bookid)
348 def categorizeSelection(self,book):
349 w = curses.newwin(1,1)
350 cs = categorySelector(w,self.hb,40,40)
353 cs.refreshCategories()
357 def delSelected(self):
359 for sel,book in zip(self.selected, self.entries):
362 db.removeBooks(books)
364 def refreshBooks(self):
365 self.entries = db.getBooks()
366 self.selected = list(map(lambda x:False, self.entries))
368 def refreshBooksInCategory(self,cat):
369 self.entries = db.getBooksByCategory(cat)
370 self.selected = list(map(lambda x:False, self.entries))
372 def handleInput(self,ch):
373 browserWindow.handleInput(self,ch)
374 if ch == 117: #update on 'u'
375 book = self.entries[self.hl]
376 self.updateSelection(book)
377 self.entries[self.hl]=db.getBookByID(book['id'])
380 book = self.entries[self.hl]
381 self.viewSelection(book)
384 book = self.entries[self.hl]
385 self.categorizeSelection(book)
389 for s in self.selected[0:self.hl-1]:
396 self.mvHighlight(-count)
399 class categoryBrowser(browserWindow):
400 columnDefs = [('Category',100,None)]
401 cs = [(' a', 'add category'), (' d', 'delete selected')]
404 def refreshCategories(self):
405 self.entries = db.getCategories()
406 self.sortByColumn('category')
407 self.selected = list(map(lambda x:False, self.entries))
409 def addCategory(self):
410 w = curses.newwin(1,1,10,10)
411 cf = CategoryForm(w,self.hb)
413 cats = cf.event_loop()
418 def viewCategory(self):
419 w = curses.newwin(20,80,20,20)
420 b = bookBrowser(w,self.hb)
422 b.refreshBooksInCategory(self.entries[self.hl])
426 def delSelected(self):
428 for sel,cat in zip(self.selected, self.entries):
430 categories.append(cat)
431 db.deleteCategories(categories)
433 def handleInput(self,ch):
434 browserWindow.handleInput(self,ch)
437 self.refreshCategories()
444 for s in self.selected[0:self.hl-1]:
448 self.refreshCategories()
451 self.mvHighlight(-count)
454 class categorySelector(browserWindow):
455 columnDefs = [('Category',100,None)]
456 cs = [(' a', 'add category'), (' c', 'commit')]
461 def refreshCategories(self):
462 self.entries = db.getCategories()
463 self.sortByColumn('category')
464 self.refreshSelected()
466 def refreshSelected(self):
467 self.original = list(map(lambda x:False, self.entries))
468 cats = db.getBookCategories(self.book)
470 cats.sort(key=lambda k: k.get('category')) # key=dict.get(col))
473 for cat in self.entries:
476 if cat['id']==cats[i]['cat_id']:
477 self.original[j] = True;
480 self.selected = self.original[:]
483 def addCategory(self):
484 w = curses.newwin(1,1,10,10)
485 cf = CategoryForm(w,self.hb)
487 cats = cf.event_loop()
492 def updateCategories(self):
493 # first removed the deselected ones
496 for old, new, category in zip(self.original, self.selected,
499 uncats.append(category)
501 cats.append(category)
502 db.uncategorizeBook(self.book, uncats)
503 # add the newly selected categories
504 db.categorizeBook(self.book, cats)
507 def handleInput(self,ch):
508 browserWindow.handleInput(self,ch)
511 self.refreshCategories()
514 self.updateCategories()
519 class columnSelector(browserWindow):
520 columnDefs = [('Column',100,None)]
522 {'column': 'id'}, {'column': 'isbn'}, {'column': 'lccn'},
523 {'column': 'title'}, {'column': 'subtitle'}, {'column': 'authors'},
524 {'column': 'edition'}, {'column': 'publisher'},
525 {'column': 'publish year'}, {'column': 'publish month'},
526 {'column': 'publish location'}, {'column': 'pages'},
527 {'column': 'pagination'}, {'column': 'weight'},
528 {'column': 'last updated'},
531 def __init__(self,window,helpbar,height=40,width=20):
532 self.selected = [False,False,False,False,False,False,False,
533 False,False,False,False,False,False,False,False]
534 browserWindow.__init__(self,window,helpbar,height,width)
542 while ch != 27 and ch != 113:
543 ch = self.handleInput(ch)
545 col = self.entries[self.hl]
551 def handleInput(self,ch):
552 browserWindow.handleInput(self,ch)