Library GUI is coming, but awkwardsadface

This commit is contained in:
Nick Guenther 2008-06-02 18:32:24 -04:00
parent 9ac0c98ea6
commit 32004be45f
2 changed files with 213 additions and 8 deletions

View File

@ -11,6 +11,12 @@ import re
LIBRARY_DB = "./csc_library.db" LIBRARY_DB = "./csc_library.db"
def format_maybe(v):
if v is None:
return "unknown"
else:
return str(v)
class Book: class Book:
def __init__(self, author, title, year): def __init__(self, author, title, year):
"""Any of these may be None to indicate 'unknown'.""" """Any of these may be None to indicate 'unknown'."""
@ -30,6 +36,13 @@ class Book:
raise Exception("Book was not signed out, no need to sign it in") raise Exception("Book was not signed out, no need to sign it in")
def __str__(self): def __str__(self):
author = self.author
book = "%s [%s]\nBy: %s" % (format_maybe(self.title), format_maybe(self.year), format_maybe(self.author))
if self.signout:
book += "\n Signed out by %s on %s" % (self.signout.name, time.ctime(self.signout.date))
return book
def __repr__(self):
return "Book(author=%r, title=%r, year=%r, signout=%r)" % (self.author, self.title, self.year, self.signout) return "Book(author=%r, title=%r, year=%r, signout=%r)" % (self.author, self.title, self.year, self.signout)
class Signout: class Signout:
@ -53,12 +66,12 @@ def reset():
def add(author, title, year): def add(author, title, year):
db = shelve.open(LIBRARY_DB,'w') #use w here (not c) to ensure a crash if the DB file got erased (is this a good idea?) db = shelve.open(LIBRARY_DB,'c') #use w here (not c) to ensure a crash if the DB file got erased (is this a good idea?)
i = len(db) i = len(db)
db[str(i)] = Book(author, title, year) db[str(i)] = Book(author, title, year)
db.close() db.close()
def search(author=None, title=None, year=None): def search(author=None, title=None, year=None, signedout=None):
"""search for a title """search for a title
author and title are regular expressions author and title are regular expressions
year is a single number or a list of numbers (so use range() to search the DB) year is a single number or a list of numbers (so use range() to search the DB)
@ -67,17 +80,22 @@ def search(author=None, title=None, year=None):
this is extraordinarily inefficient, but whatever (I don't think that without having an indexer run inthe background we can improve this any?) this is extraordinarily inefficient, but whatever (I don't think that without having an indexer run inthe background we can improve this any?)
returns: a list of Book objects returns: a list of Book objects
""" """
db = shelve.open(LIBRARY_DB, 'w', writeback=True) #open it for writing so that changes to books get saved db = shelve.open(LIBRARY_DB, 'c', writeback=True) #open it for writing so that changes to books get saved
all = db.values() #this should pull out the ID numbers somehow too.. bah all = db.values() #this should pull out the ID numbers somehow too.. bah
if author is not None: if author is not None:
all = [book for book in all if book.author and re.match(author, book.author)] #should factor this out all = [book for book in all if book.author and re.search(author, book.author)] #should factor this out
if title is not None: if title is not None:
all = [book for book in all if book.title and re.match(title, book.title)] #should factor this out all = [book for book in all if book.title and re.search(title, book.title)] #should factor this out
if year is not None: if year is not None:
if type(year) == int: if type(year) == int:
year = [year] year = [year]
#now assume year is a list #now assume year is a list
all = [book for book in all if book.year and book.year in year] all = [book for book in all if book.year and book.year in year]
if signedout is not None:
if signedout:
all = [book for book in all if book.signout is not None]
else:
all = [book for book in all if book.signout is None] #aaah copypaste
db.close() db.close()
return all return all

View File

@ -4,11 +4,13 @@ from ceo.urwid import search
from ceo.urwid.widgets import * from ceo.urwid.widgets import *
from ceo.urwid.window import * from ceo.urwid.window import *
import ceo.library as lib
def library(data): def library(data):
menu = make_menu([ menu = make_menu([
("Checkout Book", checkout_book, None), ("Checkout Book", checkout_book, None),
("Return Book", return_book, None), ("Return Book", return_book, None),
("Search Books", search_books, None), ("List Books", search_books, None),
("Add Book", add_book, None), ("Add Book", add_book, None),
("Remove Book", remove_book, None), ("Remove Book", remove_book, None),
("Back", raise_back, None), ("Back", raise_back, None),
@ -16,16 +18,201 @@ def library(data):
push_window(menu, "Library") push_window(menu, "Library")
def checkout_book(data): def checkout_book(data):
"should only search signed in books"
pass pass
def return_book(data): def return_book(data):
"should bring up a searchbox of all the guys first"
pass pass
def search_books(data): def search_books(data):
pass push_wizard("Search Books", [
SearchPage,
])
def view_book(book):
"this should develop into a full fledged useful panel for doing stuff with books. for now it's not."
push_window(BookPage(book), "Book detail")
def view_books(books):
#XXX should not use a hardcoded 20 in there, should grab the value from the width of the widget
widgets = []
for b in books:
widgets.append(urwid.AttrWrap(ButtonText(view_book, b, str(b)), None, 'selected'))
widgets.append(urwid.Divider())
push_window(urwid.ListBox(widgets))
def add_book(data): def add_book(data):
pass push_wizard("Add Book", [AddBookPage])
def remove_book(data): def remove_book(data):
pass pass
def parse_commaranges(s):
"""parse a string into a list of numbers"""
def numbers(section):
if "-" in section:
range_ = section.split("-")
assert len(range_) == 2
start = int(range_[0])
end = int(range_[1])
return range(start, end+1) #+1 to be inclusive of end
else:
return [int(section)]
l = []
for y in s.split(","):
l.append(numbers(y))
return l
class AddBookPage(WizardPanel):
def init_widgets(self):
self.author = SingleEdit("Author: ")
self.title = SingleEdit("Title: ")
self.year = SingleIntEdit("Year(s): ")
self.widgets = [
urwid.Text("Add Book"),
urwid.Divider(),
self.author,
self.title,
self.year,
]
def check(self):
author = self.author.get_edit_text()
if author == "":
author = None #null it so that searching ignores
title = self.title.get_edit_text()
if title == "":
title = None
try:
year = self.year.get_edit_text()
if year == "":
year = None
else:
year = int(year)
except:
self.focus_widget(self.year)
set_status("Invalid year")
return True
lib.add(author, title, year)
raise_back()
class SearchPage(WizardPanel):
def init_widgets(self):
self.author = SingleEdit("Author: ")
self.title = SingleEdit("Title: ")
self.year = SingleEdit("Year(s): ")
self.signedout = urwid.CheckBox("Checked Out: ")
self.widgets = [
urwid.Text("Search Library"),
urwid.Divider(),
self.author,
self.title,
self.year,
urwid.Divider(),
urwid.Text("Author/Title are regexes.\nYear is a comma-separated list or a hyphen-separated range")
]
def check(self):
author = self.author.get_edit_text()
if author == "":
author = None #null it so that searching ignores
title = self.title.get_edit_text()
if title == "":
title = None
try:
years = self.year.get_edit_text()
if years == "":
years = None
else:
#try to parse the year field
years = parse_commaranges( year )
except:
self.focus_widget(self.year)
set_status("Invalid year")
return True
signedout = self.signedout.get_state()
view_books(lib.search(author, title, years, signedout))
class CheckoutPage(urwid.WidgetWrap):
def __init__(self, book):
self.book = SingleEdit("Book: ") #this needs to be a widget that when you click on it, it takes you to the search_books pane, lets you pick a book, and then drops you back here
self.user = SingleEdit("Checkoutee: ")
self.widgets = [
urwid.Text("Checkout A Book"),
urwid.Divider(),
self.book,
self.user,
]
urwid.WidgetWrap.__init__(self, urwid.Pile(self.widgets))
class ConfirmDialog(urwid.WidgetWrap):
def __init__(self, msg):
raise NotImplementedError
def Confirm(msg):
#this should be in widgets.py
push_window(ConfirmDialog(msg))
class InputDialog(urwid.WidgetWrap):
def __init__(self, msg=None):
msg = urwid.Text(msg)
self.input = SingleEdit("")
ok = urwid.Button("OK", self.ok)
cancel = urwid.Button("Cancel", self.cancel)
buttons = urwid.Columns([ok, cancel])
display = urwid.Pile([msg, self.input, buttons])
urwid.WidgetWrap.__init__(self, display)
def ok():
self.result = self.input.get_edit_text()
raise Abort() #break out of the inner event loop
def cancel():
self.result = None
raise Abort()
def urwid_input(msg):
#this should be in widgets.py
dialog = InputDialog(msg)
push_window(dialog)
event_loop(urwid.main.ui) #HACK
return dialog.result
def do_checkout(book):
"this is temporary to fil lthe gap until we see what we reall need"
username = urwid_input("Username to check out to?")
if username is None:
set_status("Checkout cancelled")
else:
book.sign_out(username)
def do_delete(book):
if Confirm("Do you wish to delete %r?" % book):
lib.delete(book)
class BookPage(urwid.WidgetWrap):
def __init__(self, book):
self._book = book
self.author = SingleEdit("Author: ")
self.title = SingleEdit("Title: ")
self.year = SingleIntEdit("Year: ")
#now need a checkout widget to go down here..
#and "Delete"
if book.signout is None:
self.checkout = ButtonText(do_checkout, book, "Check Out")
else:
self.checkout = ButtonText(lambda book: book.sign_in(), book, "Check In")
#self.remove = ButtonText(do_delete, book, "Delete")
display = urwid.GridFlow([self.author, self.title, self.year,
#self.checkout,
#self.remove
], 15, 3, 1, 'left')
urwid.WidgetWrap.__init__(self, self.author)