Merge from trunk

This commit is contained in:
Charles Haley 2010-10-11 18:31:39 +01:00
commit ce9b91ef27
10 changed files with 65 additions and 25 deletions

View File

@ -105,7 +105,6 @@ function init_sort_combobox() {
// }}} // }}}
function init() { function init() {
$("#container").corner("30px"); $("#container").corner("30px");
$("#header").corner("30px"); $("#header").corner("30px");

View File

@ -13,7 +13,8 @@ from calibre.devices.errors import UserFeedback
from calibre.devices.usbms.deviceconfig import DeviceConfig from calibre.devices.usbms.deviceconfig import DeviceConfig
from calibre.devices.interface import DevicePlugin from calibre.devices.interface import DevicePlugin
from calibre.ebooks.BeautifulSoup import BeautifulSoup from calibre.ebooks.BeautifulSoup import BeautifulSoup
from calibre.ebooks.metadata import authors_to_string, MetaInformation from calibre.ebooks.metadata import authors_to_string, MetaInformation, \
title_sort
from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.metadata.book.base import Metadata
from calibre.ebooks.metadata.epub import set_metadata from calibre.ebooks.metadata.epub import set_metadata
from calibre.library.server.utils import strftime from calibre.library.server.utils import strftime
@ -96,6 +97,9 @@ class ITUNES(DriverBase):
OPEN_FEEDBACK_MESSAGE = _( OPEN_FEEDBACK_MESSAGE = _(
'Apple device detected, launching iTunes, please wait ...') 'Apple device detected, launching iTunes, please wait ...')
BACKLOADING_ERROR_MESSAGE = _(
"Cannot copy books directly from iDevice. "
"Drag from iTunes Library to desktop, then add to calibre's Library window.")
# Product IDs: # Product IDs:
# 0x1291 iPod Touch # 0x1291 iPod Touch
@ -3128,6 +3132,9 @@ class Book(Metadata):
See ebooks.metadata.book.base See ebooks.metadata.book.base
''' '''
def __init__(self,title,author): def __init__(self,title,author):
Metadata.__init__(self, title, authors=[author]) Metadata.__init__(self, title, authors=[author])
@property
def title_sorter(self):
return title_sort(self.title)

View File

@ -39,9 +39,9 @@ class DevicePlugin(Plugin):
#: Whether the metadata on books can be set via the GUI. #: Whether the metadata on books can be set via the GUI.
CAN_SET_METADATA = ['title', 'authors', 'collections'] CAN_SET_METADATA = ['title', 'authors', 'collections']
# Set this to True if the books on the device are files that the GUI can # Set this to None if the books on the device are files that the GUI can
# access in order to add the books from the device to the library # access in order to add the books from the device to the library
SUPPORTS_BACKLOADING = False BACKLOADING_ERROR_MESSAGE = _('Cannot get files from this device')
#: Path separator for paths to books on device #: Path separator for paths to books on device
path_sep = os.sep path_sep = os.sep

View File

@ -6,6 +6,7 @@ __docformat__ = 'restructuredtext en'
import os, re, time, sys import os, re, time, sys
from calibre.ebooks.metadata import title_sort
from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.metadata.book.base import Metadata
from calibre.devices.mime import mime_type_ext from calibre.devices.mime import mime_type_ext
from calibre.devices.interface import BookList as _BookList from calibre.devices.interface import BookList as _BookList
@ -54,7 +55,7 @@ class Book(Metadata):
def title_sorter(self): def title_sorter(self):
doc = '''String to sort the title. If absent, title is returned''' doc = '''String to sort the title. If absent, title is returned'''
def fget(self): def fget(self):
return re.sub('^\s*A\s+|^\s*The\s+|^\s*An\s+', '', self.title).rstrip() return title_sort(self.title)
return property(doc=doc, fget=fget) return property(doc=doc, fget=fget)
@dynamic_property @dynamic_property

View File

@ -96,7 +96,7 @@ class Device(DeviceConfig, DevicePlugin):
# USB disk-based devices can see the book files on the device, so can # USB disk-based devices can see the book files on the device, so can
# copy these back to the library # copy these back to the library
SUPPORTS_BACKLOADING = True BACKLOADING_ERROR_MESSAGE = None
def reset(self, key='-1', log_packets=False, report_progress=None, def reset(self, key='-1', log_packets=False, report_progress=None,
detected_device=None): detected_device=None):

View File

@ -235,6 +235,10 @@ class AddAction(InterfaceAction):
self.gui.refresh_ondevice() self.gui.refresh_ondevice()
def add_books_from_device(self, view, paths=None): def add_books_from_device(self, view, paths=None):
backloading_err = self.gui.device_manager.device.BACKLOADING_ERROR_MESSAGE
if backloading_err is not None:
return error_dialog(self.gui, _('Add to library'), backloading_err,
show=True)
if paths is 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:

View File

@ -19,12 +19,7 @@ class AddToLibraryAction(InterfaceAction):
self.qaction.triggered.connect(self.add_books_to_library) self.qaction.triggered.connect(self.add_books_to_library)
def location_selected(self, loc): def location_selected(self, loc):
enabled = False enabled = loc != 'library'
if loc != 'library':
if self.gui.device_manager.is_device_connected:
device = self.gui.device_manager.connected_device
if device is not None:
enabled = getattr(device, 'SUPPORTS_BACKLOADING', False)
self.qaction.setEnabled(enabled) self.qaction.setEnabled(enabled)
def add_books_to_library(self, *args): def add_books_to_library(self, *args):

View File

@ -794,13 +794,16 @@ class DeviceMixin(object): # {{{
mainlist, cardalist, cardblist = job.result mainlist, cardalist, cardblist = job.result
self.memory_view.set_database(mainlist) self.memory_view.set_database(mainlist)
self.memory_view.set_editable(self.device_manager.device.CAN_SET_METADATA, self.memory_view.set_editable(self.device_manager.device.CAN_SET_METADATA,
self.device_manager.device.SUPPORTS_BACKLOADING) self.device_manager.device.BACKLOADING_ERROR_MESSAGE
is None)
self.card_a_view.set_database(cardalist) self.card_a_view.set_database(cardalist)
self.card_a_view.set_editable(self.device_manager.device.CAN_SET_METADATA, self.card_a_view.set_editable(self.device_manager.device.CAN_SET_METADATA,
self.device_manager.device.SUPPORTS_BACKLOADING) self.device_manager.device.BACKLOADING_ERROR_MESSAGE
is None)
self.card_b_view.set_database(cardblist) self.card_b_view.set_database(cardblist)
self.card_b_view.set_editable(self.device_manager.device.CAN_SET_METADATA, self.card_b_view.set_editable(self.device_manager.device.CAN_SET_METADATA,
self.device_manager.device.SUPPORTS_BACKLOADING) self.device_manager.device.BACKLOADING_ERROR_MESSAGE
is None)
self.sync_news() self.sync_news()
self.sync_catalogs() self.sync_catalogs()
self.refresh_ondevice() self.refresh_ondevice()

View File

@ -263,7 +263,7 @@
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>20</width> <width>20</width>
<height>00</height> <height>0</height>
</size> </size>
</property> </property>
</spacer> </spacer>
@ -357,13 +357,13 @@ from the value in the box</string>
</item> </item>
<item row="12" column="0" colspan="2"> <item row="12" column="0" colspan="2">
<widget class="QCheckBox" name="change_title_to_title_case"> <widget class="QCheckBox" name="change_title_to_title_case">
<property name="text">
<string>Change title to title case</string>
</property>
<property name="toolTip"> <property name="toolTip">
<string>Force the title to be in title case. If both this and swap authors are checked, <string>Force the title to be in title case. If both this and swap authors are checked,
title and author are swapped before the title case is set</string> title and author are swapped before the title case is set</string>
</property> </property>
<property name="text">
<string>Change title to title case</string>
</property>
</widget> </widget>
</item> </item>
<item row="10" column="0" colspan="2"> <item row="10" column="0" colspan="2">
@ -486,15 +486,15 @@ Future conversion of these books will use the default settings.</string>
</item> </item>
<item row="4" column="1"> <item row="4" column="1">
<widget class="HistoryLineEdit" name="search_for"> <widget class="HistoryLineEdit" name="search_for">
<property name="toolTip">
<string>Enter the what you are looking for, either plain text or a regular expression, depending on the mode</string>
</property>
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>100</horstretch> <horstretch>100</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="toolTip">
<string>Enter the what you are looking for, either plain text or a regular expression, depending on the mode</string>
</property>
</widget> </widget>
</item> </item>
<item row="4" column="2"> <item row="4" column="2">
@ -656,6 +656,14 @@ nothing should be put between the original text and the inserted text</string>
<bool>true</bool> <bool>true</bool>
</property> </property>
<widget class="QWidget" name="gridLayoutWidget_2"> <widget class="QWidget" name="gridLayoutWidget_2">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>122</width>
<height>34</height>
</rect>
</property>
<layout class="QGridLayout" name="testgrid"> <layout class="QGridLayout" name="testgrid">
<item row="8" column="0"> <item row="8" column="0">
<widget class="QLabel" name="label_31"> <widget class="QLabel" name="label_31">
@ -733,14 +741,33 @@ nothing should be put between the original text and the inserted text</string>
<tabstop>author_sort</tabstop> <tabstop>author_sort</tabstop>
<tabstop>rating</tabstop> <tabstop>rating</tabstop>
<tabstop>publisher</tabstop> <tabstop>publisher</tabstop>
<tabstop>tag_editor_button</tabstop>
<tabstop>tags</tabstop> <tabstop>tags</tabstop>
<tabstop>tag_editor_button</tabstop>
<tabstop>remove_tags</tabstop> <tabstop>remove_tags</tabstop>
<tabstop>remove_all_tags</tabstop>
<tabstop>series</tabstop> <tabstop>series</tabstop>
<tabstop>clear_series</tabstop>
<tabstop>autonumber_series</tabstop> <tabstop>autonumber_series</tabstop>
<tabstop>series_numbering_restarts</tabstop>
<tabstop>series_start_number</tabstop>
<tabstop>remove_format</tabstop> <tabstop>remove_format</tabstop>
<tabstop>remove_conversion_settings</tabstop>
<tabstop>swap_title_and_author</tabstop> <tabstop>swap_title_and_author</tabstop>
<tabstop>change_title_to_title_case</tabstop>
<tabstop>button_box</tabstop> <tabstop>button_box</tabstop>
<tabstop>central_widget</tabstop>
<tabstop>search_field</tabstop>
<tabstop>search_mode</tabstop>
<tabstop>search_for</tabstop>
<tabstop>case_sensitive</tabstop>
<tabstop>replace_with</tabstop>
<tabstop>replace_func</tabstop>
<tabstop>destination_field</tabstop>
<tabstop>replace_mode</tabstop>
<tabstop>comma_separated</tabstop>
<tabstop>scrollArea11</tabstop>
<tabstop>test_text</tabstop>
<tabstop>test_result</tabstop>
</tabstops> </tabstops>
<resources> <resources>
<include location="../../../../resources/images.qrc"/> <include location="../../../../resources/images.qrc"/>

View File

@ -11,6 +11,7 @@ This module implements a simple commandline SMTP client that supports:
import sys, traceback, os import sys, traceback, os
from email import encoders from email import encoders
from calibre import isbytestring
def create_mail(from_, to, subject, text=None, attachment_data=None, def create_mail(from_, to, subject, text=None, attachment_data=None,
attachment_type=None, attachment_name=None): attachment_type=None, attachment_name=None):
@ -26,7 +27,10 @@ def create_mail(from_, to, subject, text=None, attachment_data=None,
if text is not None: if text is not None:
from email.mime.text import MIMEText from email.mime.text import MIMEText
if isbytestring(text):
msg = MIMEText(text) msg = MIMEText(text)
else:
msg = MIMEText(text, 'plain', 'utf-8')
outer.attach(msg) outer.attach(msg)
if attachment_data is not None: if attachment_data is not None: