Merge from trunk

This commit is contained in:
Charles Haley 2010-10-03 09:34:57 +01:00
commit e2038a71dd
18 changed files with 257 additions and 51 deletions

View File

@ -29,6 +29,10 @@ class WashingtonPost(BasicNewsRecipe):
('Technology', 'http://www.washingtonpost.com/wp-dyn/rss/technology/index.xml'), ('Technology', 'http://www.washingtonpost.com/wp-dyn/rss/technology/index.xml'),
('Health', 'http://www.washingtonpost.com/wp-dyn/rss/health/index.xml'), ('Health', 'http://www.washingtonpost.com/wp-dyn/rss/health/index.xml'),
('Education', 'http://www.washingtonpost.com/wp-dyn/rss/education/index.xml'), ('Education', 'http://www.washingtonpost.com/wp-dyn/rss/education/index.xml'),
('Style',
'http://www.washingtonpost.com/wp-dyn/rss/print/style/index.xml'),
('Sports',
'http://feeds.washingtonpost.com/wp-dyn/rss/linkset/2010/08/19/LI2010081904067_xml'),
('Editorials', 'http://www.washingtonpost.com/wp-dyn/rss/linkset/2005/05/30/LI2005053000331.xml'), ('Editorials', 'http://www.washingtonpost.com/wp-dyn/rss/linkset/2005/05/30/LI2005053000331.xml'),
] ]

View File

@ -455,6 +455,24 @@ def prepare_string_for_xml(raw, attribute=False):
def isbytestring(obj): def isbytestring(obj):
return isinstance(obj, (str, bytes)) return isinstance(obj, (str, bytes))
def force_unicode(obj, enc=preferred_encoding):
if isbytestring(obj):
try:
obj = obj.decode(enc)
except:
try:
obj = obj.decode(filesystem_encoding if enc ==
preferred_encoding else preferred_encoding)
except:
try:
obj = obj.decode('utf-8')
except:
obj = repr(obj)
if isbytestring(obj):
obj = obj.decode('utf-8')
return obj
def human_readable(size): def human_readable(size):
""" Convert a size in bytes into a human readable form """ """ Convert a size in bytes into a human readable form """
divisor, suffix = 1, "B" divisor, suffix = 1, "B"

View File

@ -707,7 +707,7 @@ OptionRecommendation(name='timestamp',
if mi.cover.startswith('http:') or mi.cover.startswith('https:'): if mi.cover.startswith('http:') or mi.cover.startswith('https:'):
mi.cover = self.download_cover(mi.cover) mi.cover = self.download_cover(mi.cover)
ext = mi.cover.rpartition('.')[-1].lower().strip() ext = mi.cover.rpartition('.')[-1].lower().strip()
if ext not in ('png', 'jpg', 'jpeg'): if ext not in ('png', 'jpg', 'jpeg', 'gif'):
ext = 'jpg' ext = 'jpg'
mi.cover_data = (ext, open(mi.cover, 'rb').read()) mi.cover_data = (ext, open(mi.cover, 'rb').read())
mi.cover = None mi.cover = None

View File

@ -654,8 +654,6 @@ class Metadata(object):
if predicate(x): if predicate(x):
l.remove(x) l.remove(x)
def __getitem__(self, key): def __getitem__(self, key):
return self.items[key] return self.items[key]

View File

@ -132,17 +132,23 @@ class OEBReader(object):
if not mi.language: if not mi.language:
mi.language = get_lang().replace('_', '-') mi.language = get_lang().replace('_', '-')
self.oeb.metadata.add('language', mi.language) self.oeb.metadata.add('language', mi.language)
if not mi.title:
mi.title = self.oeb.translate(__('Unknown'))
if not mi.authors:
mi.authors = [self.oeb.translate(__('Unknown'))]
if not mi.book_producer: if not mi.book_producer:
mi.book_producer = '%(a)s (%(v)s) [http://%(a)s.kovidgoyal.net]'%\ mi.book_producer = '%(a)s (%(v)s) [http://%(a)s-ebook.com]'%\
dict(a=__appname__, v=__version__) dict(a=__appname__, v=__version__)
meta_info_to_oeb_metadata(mi, self.oeb.metadata, self.logger) meta_info_to_oeb_metadata(mi, self.oeb.metadata, self.logger)
self.oeb.metadata.add('identifier', str(uuid.uuid4()), id='uuid_id', m = self.oeb.metadata
scheme='uuid') m.add('identifier', str(uuid.uuid4()), id='uuid_id', scheme='uuid')
self.oeb.uid = self.oeb.metadata.identifier[-1] self.oeb.uid = self.oeb.metadata.identifier[-1]
if not m.title:
m.add('title', self.oeb.translate(__('Unknown')))
has_aut = False
for x in m.creator:
if getattr(x, 'role', '').lower() in ('', 'aut'):
has_aut = True
break
if not has_aut:
m.add('creator', self.oeb.translate(__('Unknown')), role='aut')
def _manifest_prune_invalid(self): def _manifest_prune_invalid(self):
''' '''

View File

@ -3,6 +3,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
""" The GUI """ """ The GUI """
import os, sys, Queue, threading import os, sys, Queue, threading
from threading import RLock from threading import RLock
from urllib import unquote
from PyQt4.Qt import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, \ from PyQt4.Qt import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, \
QByteArray, QTranslator, QCoreApplication, QThread, \ QByteArray, QTranslator, QCoreApplication, QThread, \
@ -505,6 +506,11 @@ class FileDialog(QObject):
fs = QFileDialog.getOpenFileNames(parent, title, initial_dir, ftext, "") fs = QFileDialog.getOpenFileNames(parent, title, initial_dir, ftext, "")
for f in fs: for f in fs:
f = unicode(f) f = unicode(f)
if not f: continue
if not os.path.exists(f):
# QFileDialog for some reason quotes spaces
# on linux if there is more than one space in a row
f = unquote(f)
if f and os.path.exists(f): if f and os.path.exists(f):
self.selected_files.append(f) self.selected_files.append(f)
else: else:

View File

@ -234,13 +234,14 @@ class AddAction(InterfaceAction):
self.gui.set_books_in_library(booklists=[model.db], reset=True) self.gui.set_books_in_library(booklists=[model.db], reset=True)
self.gui.refresh_ondevice() self.gui.refresh_ondevice()
def add_books_from_device(self, view): def add_books_from_device(self, view, paths=None):
if paths is None:
rows = view.selectionModel().selectedRows() rows = view.selectionModel().selectedRows()
if not rows or len(rows) == 0: if not rows or len(rows) == 0:
d = error_dialog(self.gui, _('Add to library'), _('No book selected')) d = error_dialog(self.gui, _('Add to library'), _('No book selected'))
d.exec_() d.exec_()
return return
paths = [p for p in view._model.paths(rows) if p is not None] paths = [p for p in view.model().paths(rows) if p is not None]
ve = self.gui.device_manager.device.VIRTUAL_BOOK_EXTENSIONS ve = self.gui.device_manager.device.VIRTUAL_BOOK_EXTENSIONS
def ext(x): def ext(x):
ans = os.path.splitext(x)[1] ans = os.path.splitext(x)[1]
@ -261,7 +262,7 @@ class AddAction(InterfaceAction):
return return
from calibre.gui2.add import Adder from calibre.gui2.add import Adder
self.__adder_func = partial(self._add_from_device_adder, on_card=None, self.__adder_func = partial(self._add_from_device_adder, on_card=None,
model=view._model) model=view.model())
self._adder = Adder(self.gui, self.gui.library_view.model().db, self._adder = Adder(self.gui, self.gui.library_view.model().db,
self.Dispatcher(self.__adder_func), spare_server=self.gui.spare_server) self.Dispatcher(self.__adder_func), spare_server=self.gui.spare_server)
self._adder.add(paths) self._adder.add(paths)

View File

@ -21,7 +21,10 @@ from calibre.gui2.convert import Widget
def create_opf_file(db, book_id): def create_opf_file(db, book_id):
mi = db.get_metadata(book_id, index_is_id=True) mi = db.get_metadata(book_id, index_is_id=True)
mi.application_id = uuid.uuid4() mi.application_id = uuid.uuid4()
old_cover = mi.cover
mi.cover = None
raw = metadata_to_opf(mi) raw = metadata_to_opf(mi)
mi.cover = old_cover
opf_file = PersistentTemporaryFile('.opf') opf_file = PersistentTemporaryFile('.opf')
opf_file.write(raw) opf_file.write(raw)
opf_file.close() opf_file.close()

View File

@ -23,7 +23,7 @@ from calibre.gui2 import config, error_dialog, Dispatcher, dynamic, \
warning_dialog, \ warning_dialog, \
question_dialog, info_dialog, choose_dir question_dialog, info_dialog, choose_dir
from calibre.ebooks.metadata import authors_to_string from calibre.ebooks.metadata import authors_to_string
from calibre import preferred_encoding, prints from calibre import preferred_encoding, prints, force_unicode
from calibre.utils.filenames import ascii_filename from calibre.utils.filenames import ascii_filename
from calibre.devices.errors import FreeSpaceError from calibre.devices.errors import FreeSpaceError
from calibre.utils.smtp import compose_mail, sendmail, extract_email_address, \ from calibre.utils.smtp import compose_mail, sendmail, extract_email_address, \
@ -964,12 +964,12 @@ class DeviceMixin(object): # {{{
for jobname, exception, tb in results: for jobname, exception, tb in results:
title = jobname.partition(':')[-1] title = jobname.partition(':')[-1]
if exception is not None: if exception is not None:
errors.append([title, exception, tb]) errors.append(list(map(force_unicode, [title, exception, tb])))
else: else:
good.append(title) good.append(title)
if errors: if errors:
errors = '\n'.join([ errors = u'\n'.join([
'%s\n\n%s\n%s\n' % u'%s\n\n%s\n%s\n' %
(title, e, tb) for \ (title, e, tb) for \
title, e, tb in errors title, e, tb in errors
]) ])

View File

@ -375,7 +375,7 @@ p, li { white-space: pre-wrap; }
<item> <item>
<widget class="QLabel" name="label_8"> <widget class="QLabel" name="label_8">
<property name="text"> <property name="text">
<string>For help with writing advanced news recipes, please visit &lt;a href=&quot;http://__appname__.kovidgoyal.net/user_manual/news.html&quot;&gt;User Recipes&lt;/a&gt;</string> <string>For help with writing advanced news recipes, please visit &lt;a href=&quot;http://__appname__-ebook.com/user_manual/news.html&quot;&gt;User Recipes&lt;/a&gt;</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>

View File

@ -56,6 +56,7 @@ class LocationManager(QObject): # {{{
self._mem.append(a) self._mem.append(a)
else: else:
ac.setToolTip(tooltip) ac.setToolTip(tooltip)
ac.calibre_name = name
return ac return ac
@ -112,7 +113,6 @@ class LocationManager(QObject): # {{{
ac.setWhatsThis(t) ac.setWhatsThis(t)
ac.setStatusTip(t) ac.setStatusTip(t)
@property @property
def has_device(self): def has_device(self):
return max(self.free) > -1 return max(self.free) > -1
@ -228,6 +228,7 @@ class ToolBar(QToolBar): # {{{
self.added_actions = [] self.added_actions = []
self.build_bar() self.build_bar()
self.preferred_width = self.sizeHint().width() self.preferred_width = self.sizeHint().width()
self.setAcceptDrops(True)
def apply_settings(self): def apply_settings(self):
sz = gprefs['toolbar_icon_size'] sz = gprefs['toolbar_icon_size']
@ -317,6 +318,59 @@ class ToolBar(QToolBar): # {{{
def database_changed(self, db): def database_changed(self, db):
pass pass
#support drag&drop from/to library from/to reader/card
def dragEnterEvent(self, event):
md = event.mimeData()
if md.hasFormat("application/calibre+from_library") or \
md.hasFormat("application/calibre+from_device"):
event.setDropAction(Qt.CopyAction)
event.accept()
else:
event.ignore()
def dragMoveEvent(self, event):
allowed = False
md = event.mimeData()
#Drop is only allowed in the location manager widget's different from the selected one
for ac in self.location_manager.available_actions:
w = self.widgetForAction(ac)
if w is not None:
if ( md.hasFormat("application/calibre+from_library") or \
md.hasFormat("application/calibre+from_device") ) and \
w.geometry().contains(event.pos()) and \
isinstance(w, QToolButton) and not w.isChecked():
allowed = True
break
if allowed:
event.acceptProposedAction()
else:
event.ignore()
def dropEvent(self, event):
data = event.mimeData()
mime = 'application/calibre+from_library'
if data.hasFormat(mime):
ids = list(map(int, str(data.data(mime)).split()))
tgt = None
for ac in self.location_manager.available_actions:
w = self.widgetForAction(ac)
if w is not None and w.geometry().contains(event.pos()):
tgt = ac.calibre_name
if tgt is not None:
if tgt == 'main':
tgt = None
self.gui.sync_to_device(tgt, False, send_ids=ids)
event.accept()
mime = 'application/calibre+from_device'
if data.hasFormat(mime):
paths = [unicode(u.toLocalFile()) for u in data.urls()]
if paths:
self.gui.iactions['Add Books'].add_books_from_device(
self.gui.current_view(), paths=paths)
event.accept()
# }}} # }}}
class MainWindowMixin(object): # {{{ class MainWindowMixin(object): # {{{

View File

@ -1081,12 +1081,11 @@ class DeviceBooksModel(BooksModel): # {{{
self.db = db self.db = db
self.map = list(range(0, len(db))) self.map = list(range(0, len(db)))
def current_changed(self, current, previous): def cover(self, row):
data = {} item = self.db[self.map[row]]
item = self.db[self.map[current.row()]]
cdata = item.thumbnail cdata = item.thumbnail
if cdata is not None:
img = QImage() img = QImage()
if cdata is not None:
if hasattr(cdata, 'image_path'): if hasattr(cdata, 'image_path'):
img.load(cdata.image_path) img.load(cdata.image_path)
elif cdata: elif cdata:
@ -1096,7 +1095,14 @@ class DeviceBooksModel(BooksModel): # {{{
img.loadFromData(cdata) img.loadFromData(cdata)
if img.isNull(): if img.isNull():
img = self.default_image img = self.default_image
data['cover'] = img return img
def current_changed(self, current, previous):
data = {}
item = self.db[self.map[current.row()]]
cover = self.cover(current.row())
if cover is not self.default_image:
data['cover'] = cover
type = _('Unknown') type = _('Unknown')
ext = os.path.splitext(item.path)[1] ext = os.path.splitext(item.path)[1]
if ext: if ext:

View File

@ -9,7 +9,8 @@ import os
from functools import partial from functools import partial
from PyQt4.Qt import QTableView, Qt, QAbstractItemView, QMenu, pyqtSignal, \ from PyQt4.Qt import QTableView, Qt, QAbstractItemView, QMenu, pyqtSignal, \
QModelIndex, QIcon, QItemSelection QModelIndex, QIcon, QItemSelection, QMimeData, QDrag, QApplication, \
QPoint, QPixmap, QUrl, QImage, QPainter, QColor, QRect
from calibre.gui2.library.delegates import RatingDelegate, PubDateDelegate, \ from calibre.gui2.library.delegates import RatingDelegate, PubDateDelegate, \
TextDelegate, DateDelegate, TagsDelegate, CcTextDelegate, \ TextDelegate, DateDelegate, TagsDelegate, CcTextDelegate, \
@ -18,7 +19,8 @@ from calibre.gui2.library.models import BooksModel, DeviceBooksModel
from calibre.utils.config import tweaks, prefs from calibre.utils.config import tweaks, prefs
from calibre.gui2 import error_dialog, gprefs from calibre.gui2 import error_dialog, gprefs
from calibre.gui2.library import DEFAULT_SORT from calibre.gui2.library import DEFAULT_SORT
from calibre.constants import filesystem_encoding
from calibre import force_unicode
class BooksView(QTableView): # {{{ class BooksView(QTableView): # {{{
@ -31,6 +33,7 @@ class BooksView(QTableView): # {{{
self.setDragEnabled(True) self.setDragEnabled(True)
self.setDragDropOverwriteMode(False) self.setDragDropOverwriteMode(False)
self.setDragDropMode(self.DragDrop) self.setDragDropMode(self.DragDrop)
self.drag_start_pos = None
self.setAlternatingRowColors(True) self.setAlternatingRowColors(True)
self.setSelectionBehavior(self.SelectRows) self.setSelectionBehavior(self.SelectRows)
self.setShowGrid(False) self.setShowGrid(False)
@ -426,6 +429,69 @@ class BooksView(QTableView): # {{{
urls = [unicode(u.toLocalFile()) for u in event.mimeData().urls()] urls = [unicode(u.toLocalFile()) for u in event.mimeData().urls()]
return [u for u in urls if os.path.splitext(u)[1] and os.access(u, os.R_OK)] return [u for u in urls if os.path.splitext(u)[1] and os.access(u, os.R_OK)]
def drag_icon(self, cover, multiple):
cover = cover.scaledToHeight(120, Qt.SmoothTransformation)
if multiple:
base_width = cover.width()
base_height = cover.height()
base = QImage(base_width+21, base_height+21,
QImage.Format_ARGB32_Premultiplied)
base.fill(QColor(255, 255, 255, 0).rgba())
p = QPainter(base)
rect = QRect(20, 0, base_width, base_height)
p.fillRect(rect, QColor('white'))
p.drawRect(rect)
rect.moveLeft(10)
rect.moveTop(10)
p.fillRect(rect, QColor('white'))
p.drawRect(rect)
rect.moveLeft(0)
rect.moveTop(20)
p.fillRect(rect, QColor('white'))
p.save()
p.setCompositionMode(p.CompositionMode_SourceAtop)
p.drawImage(rect.topLeft(), cover)
p.restore()
p.drawRect(rect)
p.end()
cover = base
return QPixmap.fromImage(cover)
def drag_data(self):
m = self.model()
db = m.db
rows = self.selectionModel().selectedRows()
selected = map(m.id, rows)
ids = ' '.join(map(str, selected))
md = QMimeData()
md.setData('application/calibre+from_library', ids)
md.setUrls([QUrl.fromLocalFile(db.abspath(i, index_is_id=True))
for i in selected])
drag = QDrag(self)
drag.setMimeData(md)
cover = self.drag_icon(m.cover(self.currentIndex().row()),
len(selected) > 1)
drag.setHotSpot(QPoint(cover.width()//3, cover.height()//3))
drag.setPixmap(cover)
return drag
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.drag_start_pos = event.pos()
return QTableView.mousePressEvent(self, event)
def mouseMoveEvent(self, event):
if not (event.buttons() & Qt.LeftButton) or self.drag_start_pos is None:
return
if (event.pos() - self.drag_start_pos).manhattanLength() \
< QApplication.startDragDistance():
return
index = self.indexAt(event.pos())
if not index.isValid():
return
drag = self.drag_data()
drag.exec_(Qt.CopyAction)
def dragEnterEvent(self, event): def dragEnterEvent(self, event):
if int(event.possibleActions() & Qt.CopyAction) + \ if int(event.possibleActions() & Qt.CopyAction) + \
int(event.possibleActions() & Qt.MoveAction) == 0: int(event.possibleActions() & Qt.MoveAction) == 0:
@ -547,6 +613,21 @@ class DeviceBooksView(BooksView): # {{{
self.setDragDropMode(self.NoDragDrop) self.setDragDropMode(self.NoDragDrop)
self.setAcceptDrops(False) self.setAcceptDrops(False)
def drag_data(self):
m = self.model()
rows = self.selectionModel().selectedRows()
paths = [force_unicode(p, enc=filesystem_encoding) for p in m.paths(rows) if p]
md = QMimeData()
md.setData('application/calibre+from_device', 'dummy')
md.setUrls([QUrl.fromLocalFile(p) for p in paths])
drag = QDrag(self)
drag.setMimeData(md)
cover = self.drag_icon(m.cover(self.currentIndex().row()), len(paths) >
1)
drag.setHotSpot(QPoint(cover.width()//3, cover.height()//3))
drag.setPixmap(cover)
return drag
def contextMenuEvent(self, event): def contextMenuEvent(self, event):
edit_collections = callable(getattr(self._model.db, 'supports_collections', None)) and \ edit_collections = callable(getattr(self._model.db, 'supports_collections', None)) and \
self._model.db.supports_collections() and \ self._model.db.supports_collections() and \

View File

@ -302,7 +302,7 @@ def do_add_empty(db, title, authors, isbn):
if isbn: if isbn:
mi.isbn = isbn mi.isbn = isbn
db.import_book(mi, []) db.import_book(mi, [])
write_dirtied() write_dirtied(db)
send_message() send_message()
def command_add(args, dbpath): def command_add(args, dbpath):
@ -456,7 +456,7 @@ def do_set_metadata(db, id, stream):
db.set_metadata(id, mi) db.set_metadata(id, mi)
db.clean() db.clean()
do_show_metadata(db, id, False) do_show_metadata(db, id, False)
write_dirtied() write_dirtied(db)
send_message() send_message()
def set_metadata_option_parser(): def set_metadata_option_parser():

View File

@ -19,7 +19,7 @@ from calibre.ebooks.metadata.meta import set_metadata
from calibre.constants import preferred_encoding, filesystem_encoding from calibre.constants import preferred_encoding, filesystem_encoding
from calibre.ebooks.metadata import fmt_sidx from calibre.ebooks.metadata import fmt_sidx
from calibre.ebooks.metadata import title_sort from calibre.ebooks.metadata import title_sort
from calibre import strftime from calibre import strftime, prints
plugboard_any_device_value = 'any device' plugboard_any_device_value = 'any device'
plugboard_any_format_value = 'any format' plugboard_any_format_value = 'any format'

View File

@ -18,7 +18,7 @@ Editing the metadata of one book at a time
Click the book you want to edit and then click the :guilabel:`Edit metadata` button or press the ``E`` key. A dialog opens that allows you to edit all aspects of the metadata. It has various features to make editing faster and more efficient. A list of the commonly used tips: Click the book you want to edit and then click the :guilabel:`Edit metadata` button or press the ``E`` key. A dialog opens that allows you to edit all aspects of the metadata. It has various features to make editing faster and more efficient. A list of the commonly used tips:
* You can click the button in between title and authors to swap them automatically. Or * You can click the button in between title and authors to swap them automatically.
* You can click the button next to author sort to automatically to have |app| automatically fill it from the author name. * You can click the button next to author sort to automatically to have |app| automatically fill it from the author name.
* You can click the button next to tags to use the Tag Editor to manage the tags associated with the book. * You can click the button next to tags to use the Tag Editor to manage the tags associated with the book.
* The ISBN box will have a red background if you enter an invalid ISBN. It will be green for valid ISBNs * The ISBN box will have a red background if you enter an invalid ISBN. It will be green for valid ISBNs

View File

@ -6,7 +6,7 @@ __docformat__ = 'restructuredtext en'
Perform various initialization tasks. Perform various initialization tasks.
''' '''
import locale, sys, os import locale, sys, os, re
# Default translation is NOOP # Default translation is NOOP
import __builtin__ import __builtin__
@ -114,6 +114,34 @@ if not _run_once:
r, w, a, rb, wb, ab, r+, w+, a+, r+b, w+b, a+b r, w, a, rb, wb, ab, r+, w+, a+, r+b, w+b, a+b
''' '''
if iswindows: if iswindows:
class fwrapper(object):
def __init__(self, name, fobject):
object.__setattr__(self, 'fobject', fobject)
object.__setattr__(self, 'name', name)
def __getattribute__(self, attr):
if attr == 'name':
return object.__getattribute__(self, attr)
fobject = object.__getattribute__(self, 'fobject')
return getattr(fobject, attr)
def __setattr__(self, attr, val):
fobject = object.__getattribute__(self, 'fobject')
return setattr(fobject, attr, val)
def __repr__(self):
fobject = object.__getattribute__(self, 'fobject')
name = object.__getattribute__(self, 'name')
return re.sub(r'''['"]<fdopen>['"]''', repr(name),
repr(fobject))
def __str__(self):
return repr(self)
def __unicode__(self):
return repr(self).decode('utf-8')
m = mode[0] m = mode[0]
random = len(mode) > 1 and mode[1] == '+' random = len(mode) > 1 and mode[1] == '+'
binary = mode[-1] == 'b' binary = mode[-1] == 'b'
@ -139,6 +167,7 @@ if not _run_once:
flags |= os.O_NOINHERIT flags |= os.O_NOINHERIT
fd = os.open(name, flags) fd = os.open(name, flags)
ans = os.fdopen(fd, mode, bufsize) ans = os.fdopen(fd, mode, bufsize)
ans = fwrapper(name, ans)
else: else:
import fcntl import fcntl
try: try:

View File

@ -5,8 +5,8 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: calibre 0.7.21\n" "Project-Id-Version: calibre 0.7.21\n"
"POT-Creation-Date: 2010-10-01 14:42+MDT\n" "POT-Creation-Date: 2010-10-02 11:26+MDT\n"
"PO-Revision-Date: 2010-10-01 14:42+MDT\n" "PO-Revision-Date: 2010-10-02 11:26+MDT\n"
"Last-Translator: Automatically generated\n" "Last-Translator: Automatically generated\n"
"Language-Team: LANGUAGE\n" "Language-Team: LANGUAGE\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -10057,7 +10057,7 @@ msgid ""
" files in each directory of the calibre library. This is\n" " files in each directory of the calibre library. This is\n"
" useful if your metadata.db file has been corrupted.\n" " useful if your metadata.db file has been corrupted.\n"
"\n" "\n"
" WARNING: This completely regenrates your datbase. You will\n" " WARNING: This completely regenerates your datbase. You will\n"
" lose stored per-book conversion settings and custom recipes.\n" " lose stored per-book conversion settings and custom recipes.\n"
" " " "
msgstr "" msgstr ""