Merge from trunk

This commit is contained in:
Charles Haley 2010-10-18 19:40:53 +01:00
commit be78420241
10 changed files with 84 additions and 73 deletions

View File

@ -109,7 +109,7 @@ function toplevel_layout() {
var last = $(".toplevel li").last();
var title = $('.toplevel h3').first();
var bottom = last.position().top + last.height() - title.position().top;
$("#main").height(Math.max(200, bottom));
$("#main").height(Math.max(200, bottom+75));
}
function toplevel() {

View File

@ -53,6 +53,7 @@ div.navigation {
}
#listing td {
padding: 0.25em;
vertical-align: middle;
}
#listing td.thumbnail {
@ -73,6 +74,7 @@ div.navigation {
overflow: hidden;
text-align: center;
text-decoration: none;
vertical-align: middle;
}
#logo {

View File

@ -514,7 +514,7 @@ class FileDialog(QObject):
if f and os.path.exists(f):
self.selected_files.append(f)
else:
opts = QFileDialog.ShowDirsOnly if mode == QFileDialog.DirectoryOnly else QFileDialog.Option()
opts = QFileDialog.ShowDirsOnly if mode == QFileDialog.Directory else QFileDialog.Option()
f = unicode(QFileDialog.getExistingDirectory(parent, title, initial_dir, opts))
if os.path.exists(f):
self.selected_files.append(f)
@ -534,7 +534,7 @@ class FileDialog(QObject):
def choose_dir(window, name, title, default_dir='~'):
fd = FileDialog(title=title, filters=[], add_all_files_filter=False,
parent=window, name=name, mode=QFileDialog.DirectoryOnly,
parent=window, name=name, mode=QFileDialog.Directory,
default_dir=default_dir)
dir = fd.get_files()
if dir:

View File

@ -12,6 +12,7 @@ from PyQt4.Qt import QDialog, QVBoxLayout, QHBoxLayout, QTreeWidget, QLabel, \
from calibre.gui2.dialogs.confirm_delete import confirm
from calibre.library.check_library import CheckLibrary, CHECKS
from calibre.library.database2 import delete_file, delete_tree
from calibre import prints
class Item(QTreeWidgetItem):
pass
@ -126,14 +127,12 @@ class CheckLibraryDialog(QDialog):
self.text_results = '\n'.join(plaintext)
def item_changed(self, item, column):
print 'item_changed'
for it in self.all_items:
if it.checkState(1):
self.delete.setEnabled(True)
return
def delete_marked(self):
print 'delete marked'
if not confirm('<p>'+_('The marked files and folders will be '
'<b>permanently deleted</b>. Are you sure?')
+'</p>', 'check_library_editor_delete', self):
@ -153,7 +152,9 @@ class CheckLibraryDialog(QDialog):
else:
delete_file(p)
except:
print 'failed to delete', os.path.join(self.db.library_path ,unicode(it.text(1)))
prints('failed to delete',
os.path.join(self.db.library_path,
unicode(it.text(1))))
self.run_the_check()
def copy_to_clipboard(self):

View File

@ -365,6 +365,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{
except:
olddb = None
db = LibraryDatabase2(newloc)
if self.content_server is not None:
self.content_server.set_database(db)
self.library_path = newloc
self.book_on_device(None, reset=True)
db.set_book_on_device_func(self.book_on_device)

View File

@ -10,6 +10,7 @@ import logging
from logging.handlers import RotatingFileHandler
import cherrypy
from cherrypy.process.plugins import SimplePlugin
from calibre.constants import __appname__, __version__
from calibre.utils.date import fromtimestamp
@ -54,16 +55,43 @@ class DispatchController(object): # {{{
# }}}
class BonJour(SimplePlugin):
def __init__(self, engine, port=8080):
SimplePlugin.__init__(self, engine)
self.port = port
def start(self):
try:
publish_zeroconf('Books in calibre', '_stanza._tcp',
self.port, {'path':'/stanza'})
except:
import traceback
cherrypy.log.error('Failed to start BonJour:')
cherrypy.log.error(traceback.format_exc())
start.priority = 90
def stop(self):
try:
stop_zeroconf()
except:
import traceback
cherrypy.log.error('Failed to stop BonJour:')
cherrypy.log.error(traceback.format_exc())
stop.priority = 10
cherrypy.engine.bonjour = BonJour(cherrypy.engine)
class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache,
BrowseServer):
server_name = __appname__ + '/' + __version__
def __init__(self, db, opts, embedded=False, show_tracebacks=True):
self.db = db
for item in self.db:
item
break
self.opts = opts
self.embedded = embedded
self.state_callback = None
@ -71,7 +99,14 @@ class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache,
map(int, self.opts.max_cover.split('x'))
path = P('content_server')
self.build_time = fromtimestamp(os.stat(path).st_mtime)
self.default_cover = open(P('content_server/default_cover.jpg'), 'rb').read()
self.default_cover = open(P('content_server/default_cover.jpg'), 'rb').read()
cherrypy.engine.bonjour.port = opts.port
Cache.__init__(self)
self.set_database(db)
cherrypy.config.update({
'log.screen' : opts.develop,
'engine.autoreload_on' : opts.develop,
@ -97,18 +132,27 @@ class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache,
'tools.digest_auth.users' : {opts.username.strip():opts.password.strip()},
}
sr = getattr(opts, 'restriction', None)
sr = db.prefs.get('cs_restriction', '') if sr is None else sr
self.set_search_restriction(sr)
self.is_running = False
self.exception = None
self.setup_loggers()
cherrypy.engine.bonjour.subscribe()
def set_database(self, db):
self.db = db
sr = getattr(self.opts, 'restriction', None)
sr = db.prefs.get('cs_restriction', '') if sr is None else sr
self.set_search_restriction(sr)
def graceful(self):
cherrypy.engine.graceful()
def set_search_restriction(self, restriction):
if restriction:
self.search_restriction = 'search:"%s"'%restriction
else:
self.search_restriction = ''
self.reset_caches()
def setup_loggers(self):
access_file = log_access_file
@ -140,7 +184,6 @@ class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache,
root_conf['request.dispatch'] = d.dispatcher
self.config['/'] = root_conf
self.setup_loggers()
cherrypy.tree.mount(root=None, config=self.config)
try:
try:
@ -154,24 +197,14 @@ class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache,
cherrypy.engine.start()
self.is_running = True
try:
publish_zeroconf('Books in calibre', '_stanza._tcp',
self.opts.port, {'path':'/stanza'})
except:
import traceback
cherrypy.log.error('Failed to start BonJour:')
cherrypy.log.error(traceback.format_exc())
#if hasattr(cherrypy.engine, 'signal_handler'):
# cherrypy.engine.signal_handler.subscribe()
cherrypy.engine.block()
except Exception, e:
self.exception = e
finally:
self.is_running = False
try:
stop_zeroconf()
except:
import traceback
cherrypy.log.error('Failed to stop BonJour:')
cherrypy.log.error(traceback.format_exc())
try:
if callable(self.state_callback):
self.state_callback(self.is_running)

View File

@ -7,6 +7,7 @@ __docformat__ = 'restructuredtext en'
import operator, os, json
from binascii import hexlify, unhexlify
from urllib import quote
import cherrypy
@ -136,7 +137,7 @@ def get_category_items(category, items, db, datatype): # {{{
q = i.category
if not q:
q = category
href = '/browse/matches/%s/%s'%(q, id_)
href = '/browse/matches/%s/%s'%(quote(q), quote(id_))
return templ.format(xml(name), rating,
xml(desc), xml(href), rstring)
@ -329,7 +330,7 @@ class BrowseServer(object):
cats = [('<li title="{2} {0}"><img src="{src}" alt="{0}" />'
'<span class="label">{0}</span>'
'<span class="url">/browse/category/{1}</span></li>')
.format(xml(x, True), xml(y), xml(_('Browse books by')),
.format(xml(x, True), xml(quote(y)), xml(_('Browse books by')),
src='/browse/icon/'+z)
for x, y, z in cats]

View File

@ -10,7 +10,10 @@ from calibre.utils.ordered_dict import OrderedDict
class Cache(object):
def add_routes(self, c):
def __init__(self):
self.reset_caches()
def reset_caches(self):
self._category_cache = OrderedDict()
self._search_cache = OrderedDict()

View File

@ -5,7 +5,7 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import os, sys
import sys
from threading import Thread
from calibre.library.server import server_config as config
@ -38,50 +38,18 @@ def option_parser():
' in the GUI'))
return parser
def daemonize(stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
try:
pid = os.fork()
if pid > 0:
# exit first parent
sys.exit(0)
except OSError, e:
print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror)
sys.exit(1)
# decouple from parent environment
os.chdir("/")
os.setsid()
os.umask(0)
# do second fork
try:
pid = os.fork()
if pid > 0:
# exit from second parent
sys.exit(0)
except OSError, e:
print >>sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror)
sys.exit(1)
# Redirect standard file descriptors.
si = file(stdin, 'r')
so = file(stdout, 'a+')
se = file(stderr, 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
def main(args=sys.argv):
from calibre.library.database2 import LibraryDatabase2
parser = option_parser()
opts, args = parser.parse_args(args)
if opts.daemonize and not iswindows:
daemonize()
from cherrypy.process.plugins import Daemonizer
d = Daemonizer(cherrypy.engine)
d.subscribe()
if opts.pidfile is not None:
with open(opts.pidfile, 'wb') as f:
f.write(str(os.getpid()))
from cherrypy.process.plugins import PIDFile
PIDFile(cherrypy.engine, opts.pidfile).subscribe()
cherrypy.log.screen = True
from calibre.utils.config import prefs
if opts.with_library is None:

View File

@ -58,11 +58,12 @@ def publish(desc, type, port, properties=None, add_hostname=True):
'''
port = int(port)
server = start_server()
try:
hostname = socket.gethostname().partition('.')[0]
except:
hostname = 'Unknown'
if add_hostname:
try:
hostname = socket.gethostname().partition('.')[0]
except:
hostname = 'Unknown'
desc += ' (on %s)'%hostname
local_ip = get_external_ip()
type = type+'.local.'