diff --git a/src/calibre/ebooks/conversion/utils.py b/src/calibre/ebooks/conversion/utils.py index aabb1b8bc4..ad7f5f117d 100644 --- a/src/calibre/ebooks/conversion/utils.py +++ b/src/calibre/ebooks/conversion/utils.py @@ -137,17 +137,17 @@ class HeuristicProcessor(object): ] ITALICIZE_STYLE_PATS = [ - r'(?msu)(?<=\s)_(?P\S[^_]{0,40}?\S)?_(?=\s)', - r'(?msu)(?<=\s)/(?P\S[^/]{0,40}?\S)?/(?=\s)', - r'(?msu)(?<=\s)~~(?P\S[^~]{0,40}?\S)?~~(?=\s)', - r'(?msu)(?<=\s)\*(?P\S[^\*]{0,40}?\S)?\*(?=\s)', - r'(?msu)(?<=\s)~(?P\S[^~]{0,40}?\S)?~(?=\s)', - r'(?msu)(?<=\s)_/(?P\S[^/_]{0,40}?\S)?/_(?=\s)', - r'(?msu)(?<=\s)_\*(?P\S[^\*_]{0,40}?\S)?\*_(?=\s)', - r'(?msu)(?<=\s)\*/(?P\S[^/\*]{0,40}?\S)?/\*(?=\s)', - r'(?msu)(?<=\s)_\*/(?P\S[^\*_]{0,40}?\S)?/\*_(?=\s)', - r'(?msu)(?<=\s)/:(?P\S[^:/]{0,40}?\S)?:/(?=\s)', - r'(?msu)(?<=\s)\|:(?P\S[^:\|]{0,40}?\S)?:\|(?=\s)', + r'(?msu)(?<=\s)_(?P\S[^_]{0,40}?\S)?_(?=[\s\.,\!\?])', + r'(?msu)(?<=\s)/(?P\S[^/]{0,40}?\S)?/(?=[\s\.,\!\?])', + r'(?msu)(?<=\s)~~(?P\S[^~]{0,40}?\S)?~~(?=[\s\.,\!\?])', + r'(?msu)(?<=\s)\*(?P\S[^\*]{0,40}?\S)?\*(?=[\s\.,\!\?])', + r'(?msu)(?<=\s)~(?P\S[^~]{0,40}?\S)?~(?=[\s\.,\!\?])', + r'(?msu)(?<=\s)_/(?P\S[^/_]{0,40}?\S)?/_(?=[\s\.,\!\?])', + r'(?msu)(?<=\s)_\*(?P\S[^\*_]{0,40}?\S)?\*_(?=[\s\.,\!\?])', + r'(?msu)(?<=\s)\*/(?P\S[^/\*]{0,40}?\S)?/\*(?=[\s\.,\!\?])', + r'(?msu)(?<=\s)_\*/(?P\S[^\*_]{0,40}?\S)?/\*_(?=[\s\.,\!\?])', + r'(?msu)(?<=\s)/:(?P\S[^:/]{0,40}?\S)?:/(?=[\s\.,\!\?])', + r'(?msu)(?<=\s)\|:(?P\S[^:\|]{0,40}?\S)?:\|(?=[\s\.,\!\?])', ] for word in ITALICIZE_WORDS: diff --git a/src/calibre/gui2/convert/regex_builder.py b/src/calibre/gui2/convert/regex_builder.py index bdcbe3356d..bdd219d733 100644 --- a/src/calibre/gui2/convert/regex_builder.py +++ b/src/calibre/gui2/convert/regex_builder.py @@ -166,6 +166,8 @@ class RegexEdit(QWidget, Ui_Edit): def builder(self): bld = RegexBuilder(self.db, self.book_id, self.edit.text(), self) + if bld.cancelled: + return if bld.exec_() == bld.Accepted: self.edit.setText(bld.regex.text()) diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index 28b5e178ac..5df69442eb 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -13,7 +13,7 @@ from calibre.customize.ui import available_input_formats, available_output_forma device_plugins from calibre.devices.interface import DevicePlugin from calibre.devices.errors import UserFeedback, OpenFeedback -from calibre.gui2.dialogs.choose_format import ChooseFormatDialog +from calibre.gui2.dialogs.choose_format_device import ChooseFormatDeviceDialog from calibre.utils.ipc.job import BaseJob from calibre.devices.scanner import DeviceScanner from calibre.gui2 import config, error_dialog, Dispatcher, dynamic, \ @@ -826,8 +826,24 @@ class DeviceMixin(object): # {{{ fmt = None if specific: - d = ChooseFormatDialog(self, _('Choose format to send to device'), - self.device_manager.device.settings().format_map) + formats = [] + aval_out_formats = available_output_formats() + format_count = {} + for row in rows: + fmts = self.library_view.model().db.formats(row.row()) + if fmts: + for f in fmts.split(','): + f = f.lower() + if format_count.has_key(f): + format_count[f] += 1 + else: + format_count[f] = 1 + for f in self.device_manager.device.settings().format_map: + if f in format_count.keys(): + formats.append((f, _('%i of %i Books' % (format_count[f], len(rows))), True if f in aval_out_formats else False)) + elif f in aval_out_formats: + formats.append((f, _('0 of %i Books' % len(rows)), True)) + d = ChooseFormatDeviceDialog(self, _('Choose format to send to device'), formats) if d.exec_() != QDialog.Accepted: return if d.format(): diff --git a/src/calibre/gui2/dialogs/choose_format_device.py b/src/calibre/gui2/dialogs/choose_format_device.py new file mode 100644 index 0000000000..f5e0761e4f --- /dev/null +++ b/src/calibre/gui2/dialogs/choose_format_device.py @@ -0,0 +1,53 @@ +__license__ = 'GPL v3' +__copyright__ = '2011, John Schember ' + +from PyQt4.Qt import QDialog, QTreeWidgetItem, QIcon, SIGNAL + +from calibre.gui2 import file_icon_provider +from calibre.gui2.dialogs.choose_format_device_ui import Ui_ChooseFormatDeviceDialog + +class ChooseFormatDeviceDialog(QDialog, Ui_ChooseFormatDeviceDialog): + + def __init__(self, window, msg, formats): + ''' + formats is a list of tuples: [(format, exists, convertible)]. + format: Lower case format identifier. E.G. mobi + exists: String representing the number of books that + exist in the format. + convertible: True if the format is a convertible format. + formats should be ordered in the device's preferred format ordering. + ''' + QDialog.__init__(self, window) + Ui_ChooseFormatDeviceDialog.__init__(self) + self.setupUi(self) + self.connect(self.formats, SIGNAL('activated(QModelIndex)'), + self.activated_slot) + + self.msg.setText(msg) + for i, (format, exists, convertible) in enumerate(formats): + t_item = QTreeWidgetItem() + t_item.setIcon(0, file_icon_provider().icon_from_ext(format.lower())) + t_item.setText(0, format.upper()) + t_item.setText(1, exists) + if convertible: + t_item.setIcon(2, QIcon(I('ok.png'))) + self.formats.addTopLevelItem(t_item) + if i == 0: + self.formats.setCurrentItem(t_item) + t_item.setSelected(True) + self.formats.resizeColumnToContents(2) + self.formats.resizeColumnToContents(1) + self.formats.resizeColumnToContents(0) + self.formats.header().resizeSection(0, self.formats.header().sectionSize(0) * 2) + self._format = None + + def activated_slot(self, *args): + self.accept() + + def format(self): + return self._format + + def accept(self): + self._format = unicode(self.formats.currentItem().text(0)) + return QDialog.accept(self) + diff --git a/src/calibre/gui2/dialogs/choose_format_device.ui b/src/calibre/gui2/dialogs/choose_format_device.ui new file mode 100644 index 0000000000..a2a07e414a --- /dev/null +++ b/src/calibre/gui2/dialogs/choose_format_device.ui @@ -0,0 +1,111 @@ + + + ChooseFormatDeviceDialog + + + + 0 + 0 + 507 + 377 + + + + Choose Format + + + + :/images/mimetypes/unknown.png:/images/mimetypes/unknown.png + + + + + + + + + + + + + true + + + + 64 + 64 + + + + true + + + + Format + + + + + Existing + + + AlignLeft|AlignVCenter + + + + + Convertible + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + ChooseFormatDeviceDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ChooseFormatDeviceDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index b33c059c9b..6a74ccd6ea 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -16,7 +16,7 @@ from PyQt4.Qt import Qt, SIGNAL, QTimer, \ QPixmap, QMenu, QIcon, pyqtSignal, \ QDialog, \ QSystemTrayIcon, QApplication, QKeySequence, \ - QMessageBox, QHelpEvent + QMessageBox, QHelpEvent, QAction from calibre import prints from calibre.constants import __appname__, isosx @@ -198,6 +198,10 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ self.system_tray_icon.activated.connect( self.system_tray_icon_activated) + self.esc_action = QAction(self) + self.addAction(self.esc_action) + self.esc_action.setShortcut(QKeySequence(Qt.Key_Escape)) + self.esc_action.triggered.connect(self.esc) ####################### Start spare job server ######################## QTimer.singleShot(1000, self.add_spare_server) @@ -294,6 +298,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ 'the file: %s

The ' 'log will be displayed automatically.')%self.gui_debug, show=True) + def esc(self, *args): + self.search.clear() def start_content_server(self): from calibre.library.server.main import start_threaded_server @@ -305,7 +311,6 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ self.content_server.state_callback(True) self.test_server_timer = QTimer.singleShot(10000, self.test_server) - def resizeEvent(self, ev): MainWindow.resizeEvent(self, ev) self.search.setMaximumWidth(self.width()-150) diff --git a/src/calibre/manual/gui.rst b/src/calibre/manual/gui.rst index c84800116d..3718f830f3 100644 --- a/src/calibre/manual/gui.rst +++ b/src/calibre/manual/gui.rst @@ -478,6 +478,8 @@ Calibre has several keyboard shortcuts to save you time and mouse movement. Thes - Focus the search bar * - :kbd:`Shift+Ctrl+F` - Open the advanced search dialog + * - :kbd:`Esc` + - Clear the current search * - :kbd:`N or F3` - Find the next book that matches the current search (only works if the highlight checkbox next to the search bar is checked) * - :kbd:`Shift+N or Shift+F3`