Library GUI is coming, but awkwardsadface

pull/5/head
Nick Guenther 15 years ago
parent 9ac0c98ea6
commit 32004be45f
  1. 28
      ceo/library.py
  2. 193
      ceo/urwid/library.py

@ -11,6 +11,12 @@ import re
LIBRARY_DB = "./csc_library.db"
def format_maybe(v):
if v is None:
return "unknown"
else:
return str(v)
class Book:
def __init__(self, author, title, year):
"""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")
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)
class Signout:
@ -53,12 +66,12 @@ def reset():
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)
db[str(i)] = Book(author, title, year)
db.close()
def search(author=None, title=None, year=None):
def search(author=None, title=None, year=None, signedout=None):
"""search for a title
author and title are regular expressions
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?)
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
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:
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 type(year) == int:
year = [year]
#now assume year is a list
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()
return all

@ -4,11 +4,13 @@ from ceo.urwid import search
from ceo.urwid.widgets import *
from ceo.urwid.window import *
import ceo.library as lib
def library(data):
menu = make_menu([
("Checkout Book", checkout_book, None),
("Return Book", return_book, None),
("Search Books", search_books, None),
("List Books", search_books, None),
("Add Book", add_book, None),
("Remove Book", remove_book, None),
("Back", raise_back, None),
@ -16,16 +18,201 @@ def library(data):
push_window(menu, "Library")
def checkout_book(data):
"should only search signed in books"
pass
def return_book(data):
"should bring up a searchbox of all the guys first"
pass
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):
pass
push_wizard("Add Book", [AddBookPage])
def remove_book(data):
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)

Loading…
Cancel
Save