mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Split Send to device into two actions
This commit is contained in:
parent
f7d5dbaf5f
commit
e41fe501dd
5123
resources/images/connect_share.svg
Normal file
5123
resources/images/connect_share.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 214 KiB |
@ -395,8 +395,6 @@ class DeviceAction(QAction): # {{{
|
||||
class DeviceMenu(QMenu): # {{{
|
||||
|
||||
fetch_annotations = pyqtSignal()
|
||||
connect_to_folder = pyqtSignal()
|
||||
connect_to_itunes = pyqtSignal()
|
||||
disconnect_mounted_device = pyqtSignal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
@ -408,26 +406,6 @@ class DeviceMenu(QMenu): # {{{
|
||||
self.set_default_menu = QMenu(_('Set default send to device action'))
|
||||
self.set_default_menu.setIcon(QIcon(I('config.svg')))
|
||||
|
||||
opts = email_config().parse()
|
||||
default_account = None
|
||||
if opts.accounts:
|
||||
self.email_to_menu = self.addMenu(_('Email to')+'...')
|
||||
keys = sorted(opts.accounts.keys())
|
||||
for account in keys:
|
||||
formats, auto, default = opts.accounts[account]
|
||||
dest = 'mail:'+account+';'+formats
|
||||
if default:
|
||||
default_account = (dest, False, False, I('mail.svg'),
|
||||
_('Email to')+' '+account)
|
||||
action1 = DeviceAction(dest, False, False, I('mail.svg'),
|
||||
_('Email to')+' '+account)
|
||||
action2 = DeviceAction(dest, True, False, I('mail.svg'),
|
||||
_('Email to')+' '+account+ _(' and delete from library'))
|
||||
map(self.email_to_menu.addAction, (action1, action2))
|
||||
map(self._memory.append, (action1, action2))
|
||||
self.email_to_menu.addSeparator()
|
||||
action1.a_s.connect(self.action_triggered)
|
||||
action2.a_s.connect(self.action_triggered)
|
||||
|
||||
basic_actions = [
|
||||
('main:', False, False, I('reader.svg'),
|
||||
@ -457,13 +435,6 @@ class DeviceMenu(QMenu): # {{{
|
||||
]
|
||||
|
||||
|
||||
if default_account is not None:
|
||||
for x in (basic_actions, delete_actions):
|
||||
ac = list(default_account)
|
||||
if x is delete_actions:
|
||||
ac[1] = True
|
||||
x.insert(1, tuple(ac))
|
||||
|
||||
for menu in (self, self.set_default_menu):
|
||||
for actions, desc in (
|
||||
(basic_actions, ''),
|
||||
@ -502,21 +473,7 @@ class DeviceMenu(QMenu): # {{{
|
||||
config['default_send_to_device_action'] = repr(action)
|
||||
|
||||
self.group.triggered.connect(self.change_default_action)
|
||||
if opts.accounts:
|
||||
self.addSeparator()
|
||||
self.addMenu(self.email_to_menu)
|
||||
|
||||
self.addSeparator()
|
||||
mitem = self.addAction(QIcon(I('document_open.svg')), _('Connect to folder'))
|
||||
mitem.setEnabled(True)
|
||||
mitem.triggered.connect(lambda x : self.connect_to_folder.emit())
|
||||
self.connect_to_folder_action = mitem
|
||||
|
||||
mitem = self.addAction(QIcon(I('devices/itunes.png')),
|
||||
_('Connect to iTunes'))
|
||||
mitem.setEnabled(True)
|
||||
mitem.triggered.connect(lambda x : self.connect_to_itunes.emit())
|
||||
self.connect_to_itunes_action = mitem
|
||||
|
||||
mitem = self.addAction(QIcon(I('eject.svg')), _('Eject device'))
|
||||
mitem.setEnabled(False)
|
||||
@ -638,6 +595,8 @@ class DeviceMixin(object): # {{{
|
||||
self.device_error_dialog = error_dialog(self, _('Error'),
|
||||
_('Error communicating with device'), ' ')
|
||||
self.device_error_dialog.setModal(Qt.NonModal)
|
||||
self.share_conn_menu.connect_to_folder.connect(self.connect_to_folder)
|
||||
self.share_conn_menu.connect_to_itunes.connect(self.connect_to_itunes)
|
||||
self.emailer = Emailer()
|
||||
self.emailer.start()
|
||||
self.device_manager = DeviceManager(Dispatcher(self.device_detected),
|
||||
@ -675,21 +634,20 @@ class DeviceMixin(object): # {{{
|
||||
|
||||
def create_device_menu(self):
|
||||
self._sync_menu = DeviceMenu(self)
|
||||
self.share_conn_menu.build_email_entries(self._sync_menu)
|
||||
self.action_sync.setMenu(self._sync_menu)
|
||||
self.connect(self._sync_menu,
|
||||
SIGNAL('sync(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
|
||||
self.dispatch_sync_event)
|
||||
self._sync_menu.fetch_annotations.connect(self.fetch_annotations)
|
||||
self._sync_menu.connect_to_folder.connect(self.connect_to_folder)
|
||||
self._sync_menu.connect_to_itunes.connect(self.connect_to_itunes)
|
||||
self._sync_menu.disconnect_mounted_device.connect(self.disconnect_mounted_device)
|
||||
if self.device_connected:
|
||||
self._sync_menu.connect_to_folder_action.setEnabled(False)
|
||||
self._sync_menu.connect_to_itunes_action.setEnabled(False)
|
||||
self.share_conn_menu.connect_to_folder_action.setEnabled(False)
|
||||
self.share_conn_menu.connect_to_itunes_action.setEnabled(False)
|
||||
self._sync_menu.disconnect_mounted_device_action.setEnabled(True)
|
||||
else:
|
||||
self._sync_menu.connect_to_folder_action.setEnabled(True)
|
||||
self._sync_menu.connect_to_itunes_action.setEnabled(True)
|
||||
self.share_conn_menu.connect_to_folder_action.setEnabled(True)
|
||||
self.share_conn_menu.connect_to_itunes_action.setEnabled(True)
|
||||
self._sync_menu.disconnect_mounted_device_action.setEnabled(False)
|
||||
|
||||
def device_job_exception(self, job):
|
||||
@ -726,16 +684,16 @@ class DeviceMixin(object): # {{{
|
||||
|
||||
def set_device_menu_items_state(self, connected):
|
||||
if connected:
|
||||
self._sync_menu.connect_to_folder_action.setEnabled(False)
|
||||
self._sync_menu.connect_to_itunes_action.setEnabled(False)
|
||||
self.share_conn_menu.connect_to_folder_action.setEnabled(False)
|
||||
self.share_conn_menu.connect_to_itunes_action.setEnabled(False)
|
||||
self._sync_menu.disconnect_mounted_device_action.setEnabled(True)
|
||||
self._sync_menu.enable_device_actions(True,
|
||||
self.device_manager.device.card_prefix(),
|
||||
self.device_manager.device)
|
||||
self.eject_action.setEnabled(True)
|
||||
else:
|
||||
self._sync_menu.connect_to_folder_action.setEnabled(True)
|
||||
self._sync_menu.connect_to_itunes_action.setEnabled(True)
|
||||
self.share_conn_menu.connect_to_folder_action.setEnabled(True)
|
||||
self.share_conn_menu.connect_to_itunes_action.setEnabled(True)
|
||||
self._sync_menu.disconnect_mounted_device_action.setEnabled(False)
|
||||
self._sync_menu.enable_device_actions(False)
|
||||
self.eject_action.setEnabled(False)
|
||||
@ -983,6 +941,8 @@ class DeviceMixin(object): # {{{
|
||||
else:
|
||||
self.status_bar.show_message(_('Sent by email:') + ', '.join(good),
|
||||
5000)
|
||||
if remove:
|
||||
self.library_view.model().delete_books_by_id(remove)
|
||||
|
||||
def cover_to_thumbnail(self, data):
|
||||
p = QPixmap()
|
||||
|
@ -195,22 +195,32 @@ class PluginModel(QAbstractItemModel):
|
||||
|
||||
class CategoryModel(QStringListModel):
|
||||
|
||||
CATEGORIES = [
|
||||
('general', _('General'), 'dialog_information.svg'),
|
||||
('interface', _('Interface'), 'lookfeel.svg'),
|
||||
('conversion', _('Conversion'), 'convert.svg'),
|
||||
('email', _('Email\nDelivery'), 'mail.svg'),
|
||||
('add/save', _('Add/Save'), 'save.svg'),
|
||||
('advanced', _('Advanced'), 'view.svg'),
|
||||
('server', _('Content\nServer'), 'network-server.svg'),
|
||||
('plugins', _('Plugins'), 'plugins.svg'),
|
||||
]
|
||||
|
||||
def __init__(self, *args):
|
||||
QStringListModel.__init__(self, *args)
|
||||
self.setStringList([_('General'), _('Interface'), _('Conversion'),
|
||||
_('Email\nDelivery'), _('Add/Save'),
|
||||
_('Advanced'), _('Content\nServer'), _('Plugins')])
|
||||
self.icons = list(map(QVariant, map(QIcon,
|
||||
[I('dialog_information.svg'), I('lookfeel.svg'),
|
||||
I('convert.svg'),
|
||||
I('mail.svg'), I('save.svg'), I('view.svg'),
|
||||
I('network-server.svg'), I('plugins.svg')])))
|
||||
self.setStringList([x[1] for x in self.CATEGORIES])
|
||||
|
||||
def data(self, index, role):
|
||||
if role == Qt.DecorationRole:
|
||||
return self.icons[index.row()]
|
||||
return QVariant(QIcon(I(self.CATEGORIES[index.row()][2])))
|
||||
return QStringListModel.data(self, index, role)
|
||||
|
||||
def index_for_name(self, name):
|
||||
for i, x in enumerate(self.CATEGORIES):
|
||||
if x[0] == name:
|
||||
return self.index(i)
|
||||
return self.index(0)
|
||||
|
||||
class EmailAccounts(QAbstractTableModel):
|
||||
|
||||
def __init__(self, accounts):
|
||||
@ -332,7 +342,8 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
|
||||
def category_current_changed(self, n, p):
|
||||
self.stackedWidget.setCurrentIndex(n.row())
|
||||
|
||||
def __init__(self, parent, library_view, server=None):
|
||||
def __init__(self, parent, library_view, server=None,
|
||||
initial_category='general'):
|
||||
ResizableDialog.__init__(self, parent)
|
||||
self._category_model = CategoryModel()
|
||||
|
||||
@ -461,7 +472,6 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
|
||||
self.button_osx_symlinks.setVisible(isosx)
|
||||
self.separate_cover_flow.setChecked(config['separate_cover_flow'])
|
||||
self.setup_email_page()
|
||||
self.category_view.setCurrentIndex(self.category_view.model().index(0))
|
||||
self.delete_news.setEnabled(bool(self.sync_news.isChecked()))
|
||||
self.connect(self.sync_news, SIGNAL('toggled(bool)'),
|
||||
self.delete_news.setEnabled)
|
||||
@ -489,6 +499,8 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
|
||||
self.opt_disable_animations.setChecked(config['disable_animations'])
|
||||
self.opt_show_donate_button.setChecked(config['show_donate_button'])
|
||||
|
||||
self.category_view.setCurrentIndex(self.category_view.model().index_for_name(initial_category))
|
||||
|
||||
def check_port_value(self, *args):
|
||||
port = self.port.value()
|
||||
if port < 1025:
|
||||
@ -942,6 +954,5 @@ if __name__ == '__main__':
|
||||
from PyQt4.Qt import QApplication
|
||||
app = QApplication([])
|
||||
d=ConfigDialog(None, LibraryDatabase2('/tmp'))
|
||||
d.category_view.setCurrentIndex(d.category_view.model().index(0))
|
||||
d.show()
|
||||
app.exec_()
|
||||
|
@ -59,6 +59,7 @@ class LibraryViewMixin(object): # {{{
|
||||
self.action_open_containing_folder,
|
||||
self.action_show_book_details,
|
||||
self.action_del,
|
||||
self.action_conn_share,
|
||||
add_to_library = None,
|
||||
edit_device_collections=None,
|
||||
similar_menu=similar_menu)
|
||||
@ -67,21 +68,24 @@ class LibraryViewMixin(object): # {{{
|
||||
edit_device_collections = (_('Manage collections'),
|
||||
partial(self.edit_device_collections, oncard=None))
|
||||
self.memory_view.set_context_menu(None, None, None,
|
||||
self.action_view, self.action_save, None, None, self.action_del,
|
||||
self.action_view, self.action_save, None, None,
|
||||
self.action_del, None,
|
||||
add_to_library=add_to_library,
|
||||
edit_device_collections=edit_device_collections)
|
||||
|
||||
edit_device_collections = (_('Manage collections'),
|
||||
partial(self.edit_device_collections, oncard='carda'))
|
||||
self.card_a_view.set_context_menu(None, None, None,
|
||||
self.action_view, self.action_save, None, None, self.action_del,
|
||||
self.action_view, self.action_save, None, None,
|
||||
self.action_del, None,
|
||||
add_to_library=add_to_library,
|
||||
edit_device_collections=edit_device_collections)
|
||||
|
||||
edit_device_collections = (_('Manage collections'),
|
||||
partial(self.edit_device_collections, oncard='cardb'))
|
||||
self.card_b_view.set_context_menu(None, None, None,
|
||||
self.action_view, self.action_save, None, None, self.action_del,
|
||||
self.action_view, self.action_save, None, None,
|
||||
self.action_del, None,
|
||||
add_to_library=add_to_library,
|
||||
edit_device_collections=edit_device_collections)
|
||||
|
||||
|
@ -22,6 +22,7 @@ from calibre import human_readable
|
||||
from calibre.utils.config import prefs
|
||||
from calibre.ebooks import BOOK_EXTENSIONS
|
||||
from calibre.gui2.dialogs.scheduler import Scheduler
|
||||
from calibre.utils.smtp import config as email_config
|
||||
|
||||
ICON_SIZE = 48
|
||||
|
||||
@ -262,7 +263,9 @@ class ToolBar(QToolBar): # {{{
|
||||
ch.setCursor(Qt.PointingHandCursor)
|
||||
ch.setAutoRaise(True)
|
||||
if ac.menu() is not None:
|
||||
ch.setPopupMode(ch.MenuButtonPopup)
|
||||
name = getattr(ac, 'action_name', None)
|
||||
ch.setPopupMode(ch.InstantPopup if name == 'conn_share'
|
||||
else ch.MenuButtonPopup)
|
||||
|
||||
for x in actions:
|
||||
self.addAction(x)
|
||||
@ -306,6 +309,60 @@ class ToolBar(QToolBar): # {{{
|
||||
class Action(QAction):
|
||||
pass
|
||||
|
||||
class ShareConnMenu(QMenu):
|
||||
|
||||
connect_to_folder = pyqtSignal()
|
||||
connect_to_itunes = pyqtSignal()
|
||||
config_email = pyqtSignal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QMenu.__init__(self, parent)
|
||||
mitem = self.addAction(QIcon(I('devices/folder.svg')), _('Connect to folder'))
|
||||
mitem.setEnabled(True)
|
||||
mitem.triggered.connect(lambda x : self.connect_to_folder.emit())
|
||||
self.connect_to_folder_action = mitem
|
||||
|
||||
mitem = self.addAction(QIcon(I('devices/itunes.png')),
|
||||
_('Connect to iTunes'))
|
||||
mitem.setEnabled(True)
|
||||
mitem.triggered.connect(lambda x : self.connect_to_itunes.emit())
|
||||
self.connect_to_itunes_action = mitem
|
||||
self.addSeparator()
|
||||
self.email_actions = []
|
||||
|
||||
def build_email_entries(self, sync_menu):
|
||||
from calibre.gui2.device import DeviceAction
|
||||
for ac in self.email_actions:
|
||||
self.removeAction(ac)
|
||||
self.email_actions = []
|
||||
opts = email_config().parse()
|
||||
if opts.accounts:
|
||||
self.email_to_menu = QMenu(_('Email to')+'...', self)
|
||||
keys = sorted(opts.accounts.keys())
|
||||
for account in keys:
|
||||
formats, auto, default = opts.accounts[account]
|
||||
dest = 'mail:'+account+';'+formats
|
||||
action1 = DeviceAction(dest, False, False, I('mail.svg'),
|
||||
_('Email to')+' '+account)
|
||||
action2 = DeviceAction(dest, True, False, I('mail.svg'),
|
||||
_('Email to')+' '+account+ _(' and delete from library'))
|
||||
map(self.email_to_menu.addAction, (action1, action2))
|
||||
if default:
|
||||
map(self.addAction, (action1, action2))
|
||||
map(self.email_actions.append, (action1, action2))
|
||||
self.email_to_menu.addSeparator()
|
||||
action1.a_s.connect(sync_menu.action_triggered)
|
||||
action2.a_s.connect(sync_menu.action_triggered)
|
||||
ac = self.addMenu(self.email_to_menu)
|
||||
self.email_actions.append(ac)
|
||||
else:
|
||||
ac = self.addAction(_('Setup email based sharing of books'))
|
||||
self.email_actions.append(ac)
|
||||
ac.triggered.connect(self.setup_email)
|
||||
|
||||
def setup_email(self, *args):
|
||||
self.config_email.emit()
|
||||
|
||||
class MainWindowMixin(object):
|
||||
|
||||
def __init__(self, db):
|
||||
@ -341,7 +398,6 @@ class MainWindowMixin(object):
|
||||
self.scheduler.start_recipe_fetch.connect(
|
||||
self.download_scheduled_recipe, type=Qt.QueuedConnection)
|
||||
|
||||
|
||||
def read_toolbar_settings(self):
|
||||
pass
|
||||
|
||||
@ -372,18 +428,19 @@ class MainWindowMixin(object):
|
||||
setattr(self, 'action_'+name, action)
|
||||
all_actions.append(action)
|
||||
|
||||
ac(0, 7, 0, 'add', _('Add books'), 'add_book.svg', _('A'))
|
||||
ac(0, 0, 0, 'add', _('Add books'), 'add_book.svg', _('A'))
|
||||
ac(1, 1, 0, 'edit', _('Edit metadata'), 'edit_input.svg', _('E'))
|
||||
ac(2, 2, 3, 'convert', _('Convert books'), 'convert.svg', _('C'))
|
||||
ac(3, 3, 0, 'view', _('View'), 'view.svg', _('V'))
|
||||
ac(4, 4, 3, 'choose_library', _('%d books')%0, 'lt.png',
|
||||
ac(-1, 4, 0, 'sync', _('Send to device'), 'sync.svg')
|
||||
ac(5, 5, 3, 'choose_library', _('%d books')%0, 'lt.png',
|
||||
tooltip=_('Choose calibre library to work with'))
|
||||
ac(5, 5, 3, 'news', _('Fetch news'), 'news.svg', _('F'))
|
||||
ac(6, 6, 0, 'save', _('Save to disk'), 'save.svg', _('S'))
|
||||
ac(7, 0, 0, 'sync', _('Send to device'), 'sync.svg')
|
||||
ac(8, 8, 3, 'del', _('Remove books'), 'trash.svg', _('Del'))
|
||||
ac(9, 9, 3, 'help', _('Help'), 'help.svg', _('F1'), _("Browse the calibre User Manual"))
|
||||
ac(10, 10, 0, 'preferences', _('Preferences'), 'config.svg', _('Ctrl+P'))
|
||||
ac(6, 6, 3, 'news', _('Fetch news'), 'news.svg', _('F'))
|
||||
ac(7, 7, 0, 'save', _('Save to disk'), 'save.svg', _('S'))
|
||||
ac(8, 8, 0, 'conn_share', _('Connect/share'), 'connect_share.svg')
|
||||
ac(9, 9, 3, 'del', _('Remove books'), 'trash.svg', _('Del'))
|
||||
ac(10, 10, 3, 'help', _('Help'), 'help.svg', _('F1'), _("Browse the calibre User Manual"))
|
||||
ac(11, 11, 0, 'preferences', _('Preferences'), 'config.svg', _('Ctrl+P'))
|
||||
|
||||
ac(-1, -1, 0, 'merge', _('Merge book records'), 'merge_books.svg', _('M'))
|
||||
ac(-1, -1, 0, 'open_containing_folder', _('Open containing folder'),
|
||||
@ -402,6 +459,10 @@ class MainWindowMixin(object):
|
||||
self.action_news.setMenu(self.scheduler.news_menu)
|
||||
self.action_news.triggered.connect(
|
||||
self.scheduler.show_dialog)
|
||||
self.share_conn_menu = ShareConnMenu(self)
|
||||
self.share_conn_menu.config_email.connect(partial(self.do_config,
|
||||
initial_category='email'))
|
||||
self.action_conn_share.setMenu(self.share_conn_menu)
|
||||
|
||||
self.action_help.triggered.connect(self.show_help)
|
||||
md = QMenu()
|
||||
@ -528,6 +589,7 @@ class MainWindowMixin(object):
|
||||
for x in (self.preferences_action, self.action_preferences):
|
||||
x.triggered.connect(self.do_config)
|
||||
|
||||
|
||||
return all_actions
|
||||
# }}}
|
||||
|
||||
|
@ -390,7 +390,7 @@ class BooksView(QTableView): # {{{
|
||||
|
||||
# Context Menu {{{
|
||||
def set_context_menu(self, edit_metadata, send_to_device, convert, view,
|
||||
save, open_folder, book_details, delete,
|
||||
save, open_folder, book_details, delete, conn_share,
|
||||
similar_menu=None, add_to_library=None,
|
||||
edit_device_collections=None):
|
||||
self.setContextMenuPolicy(Qt.DefaultContextMenu)
|
||||
@ -401,6 +401,8 @@ class BooksView(QTableView): # {{{
|
||||
self.context_menu.addAction(send_to_device)
|
||||
if convert is not None:
|
||||
self.context_menu.addAction(convert)
|
||||
if conn_share is not None:
|
||||
self.context_menu.addAction(conn_share)
|
||||
self.context_menu.addAction(view)
|
||||
self.context_menu.addAction(save)
|
||||
if open_folder is not None:
|
||||
|
@ -351,7 +351,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{
|
||||
return self.memory_view.model().db, self.card_a_view.model().db, self.card_b_view.model().db
|
||||
|
||||
|
||||
def do_config(self, *args):
|
||||
def do_config(self, checked=False, initial_category='general'):
|
||||
if self.job_manager.has_jobs():
|
||||
d = error_dialog(self, _('Cannot configure'),
|
||||
_('Cannot configure while there are running jobs.'))
|
||||
@ -363,7 +363,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{
|
||||
d.exec_()
|
||||
return
|
||||
d = ConfigDialog(self, self.library_view,
|
||||
server=self.content_server)
|
||||
server=self.content_server, initial_category=initial_category)
|
||||
|
||||
d.exec_()
|
||||
self.content_server = d.server
|
||||
|
Loading…
x
Reference in New Issue
Block a user