Add a menu bar. By default the menu bar is hidden (except on OS X). You can add actions to it via Preferences->Toolbars.

This commit is contained in:
Kovid Goyal 2011-04-08 15:51:45 -06:00
parent 8a7877fb73
commit 86e17cc100
18 changed files with 146 additions and 36 deletions

View file

@ -23,6 +23,10 @@
# Setup gprefs {{{
gprefs = JSONConfig('gui')
gprefs.defaults['action-layout-menubar'] = ()
gprefs.defaults['action-layout-menubar-device'] = ()
gprefs.defaults['action-layout-toolbar'] = (
'Add Books', 'Edit Metadata', None, 'Convert Books', 'View', None,
'Choose Library', 'Donate', None, 'Fetch News', 'Save To Disk',

View file

@ -75,7 +75,7 @@ class InterfaceAction(QObject):
dont_remove_from = frozenset([])
all_locations = frozenset(['toolbar', 'toolbar-device', 'context-menu',
'context-menu-device', 'toolbar-child'])
'context-menu-device', 'toolbar-child', 'menubar', 'menubar-device'])
#: Type of action
#: 'current' means acts on the current view

View file

@ -12,7 +12,7 @@ class AddToLibraryAction(InterfaceAction):
name = 'Add To Library'
action_spec = (_('Add books to library'), 'add_book.png',
_('Add books to your calibre library from the connected device'), None)
dont_add_to = frozenset(['toolbar', 'context-menu', 'toolbar-child'])
dont_add_to = frozenset(['menubar', 'toolbar', 'context-menu', 'toolbar-child'])
action_type = 'current'
def genesis(self):

View file

@ -18,6 +18,7 @@ class FetchAnnotationsAction(InterfaceAction):
name = 'Fetch Annotations'
action_spec = (_('Fetch annotations (experimental)'), None, None, None)
dont_add_to = frozenset(['menubar', 'toolbar', 'context-menu', 'toolbar-child'])
action_type = 'current'
def genesis(self):

View file

@ -18,7 +18,7 @@ class GenerateCatalogAction(InterfaceAction):
name = 'Generate Catalog'
action_spec = (_('Create a catalog of the books in your calibre library'), None, None, None)
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device'])
def generate_catalog(self):
rows = self.gui.library_view.selectionModel().selectedRows()

View file

@ -80,7 +80,7 @@ class ChooseLibraryAction(InterfaceAction):
name = 'Choose Library'
action_spec = (_('%d books'), 'lt.png',
_('Choose calibre library to work with'), None)
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device'])
def genesis(self):
self.count_changed(0)
@ -210,7 +210,6 @@ def build_menus(self):
rename_actions, delete_actions, qs_actions,
self.action_choose)
def location_selected(self, loc):
enabled = loc == 'library'
self.qaction.setEnabled(enabled)

View file

@ -20,7 +20,7 @@ class ConvertAction(InterfaceAction):
name = 'Convert Books'
action_spec = (_('Convert books'), 'convert.png', None, _('C'))
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device'])
action_type = 'current'
def genesis(self):

View file

@ -24,7 +24,7 @@ class ShareConnMenu(QMenu): # {{{
config_email = pyqtSignal()
toggle_server = pyqtSignal()
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device'])
def __init__(self, parent=None):
QMenu.__init__(self, parent)
@ -121,8 +121,7 @@ class SendToDeviceAction(InterfaceAction):
name = 'Send To Device'
action_spec = (_('Send to device'), 'sync.png', None, _('D'))
dont_remove_from = frozenset(['toolbar-device'])
dont_add_to = frozenset(['toolbar', 'context-menu', 'toolbar-child'])
dont_add_to = frozenset(['menubar', 'toolbar', 'context-menu', 'toolbar-child'])
def genesis(self):
self.qaction.triggered.connect(self.do_sync)
@ -169,7 +168,7 @@ def content_server_state_changed(self, running):
def toggle_content_server(self):
if self.gui.content_server is None:
self.gui.start_content_server()
self.gui.start_content_server()
else:
self.gui.content_server.threaded_exit()
self.stopping_msg = info_dialog(self.gui, _('Stopping'),

View file

@ -12,7 +12,7 @@ class EditCollectionsAction(InterfaceAction):
name = 'Edit Collections'
action_spec = (_('Manage collections'), None,
_('Manage the collections on this device'), None)
dont_add_to = frozenset(['toolbar', 'context-menu', 'toolbar-child'])
dont_add_to = frozenset(['menubar', 'toolbar', 'context-menu', 'toolbar-child'])
action_type = 'current'
def genesis(self):

View file

@ -11,7 +11,7 @@ class NextMatchAction(InterfaceAction):
name = 'Move to next highlighted book'
action_spec = (_('Move to next match'), 'arrow-down.png',
_('Move to next highlighted match'), [_('N'), _('F3')])
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device'])
action_type = 'current'
def genesis(self):

View file

@ -13,7 +13,7 @@ class OpenFolderAction(InterfaceAction):
name = 'Open Folder'
action_spec = (_('Open containing folder'), 'document_open.png', None,
_('O'))
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device'])
action_type = 'current'
def genesis(self):

View file

@ -16,7 +16,6 @@ class PreferencesAction(InterfaceAction):
name = 'Preferences'
action_spec = (_('Preferences'), 'config.png', None, _('Ctrl+P'))
dont_remove_from = frozenset(['toolbar'])
def genesis(self):
pm = QMenu()

View file

@ -15,7 +15,7 @@ class ShowBookDetailsAction(InterfaceAction):
name = 'Show Book Details'
action_spec = (_('Show book details'), 'dialog_information.png', None,
_('I'))
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device'])
action_type = 'current'
def genesis(self):

View file

@ -15,7 +15,7 @@ class TweakEpubAction(InterfaceAction):
action_spec = (_('Tweak ePub'), 'trim.png',
_('Make small changes to ePub format books'),
_('T'))
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device'])
action_type = 'current'
def genesis(self):

View file

@ -8,11 +8,11 @@
from functools import partial
from PyQt4.Qt import (QIcon, Qt, QWidget, QToolBar, QSize,
pyqtSignal, QToolButton, QMenu,
pyqtSignal, QToolButton, QMenu, QMenuBar, QAction,
QObject, QVBoxLayout, QSizePolicy, QLabel, QHBoxLayout, QActionGroup)
from calibre.constants import __appname__
from calibre.constants import __appname__, isosx
from calibre.gui2.search_box import SearchBox2, SavedSearchBox
from calibre.gui2.throbber import ThrobbingButton
from calibre.gui2 import gprefs
@ -238,6 +238,80 @@ def __init__(self, parent):
self.l.addStretch(10)
# }}}
class MenuAction(QAction):
def __init__(self, clone, parent):
QAction.__init__(self, clone.text(), parent)
self.clone = clone
clone.changed.connect(self.clone_changed)
def clone_changed(self):
self.setText(self.clone.text())
class MenuBar(QMenuBar): # {{{
def __init__(self, location_manager, parent):
QMenuBar.__init__(self, parent)
self.gui = parent
self.setNativeMenuBar(True)
self.location_manager = location_manager
self.location_manager.locations_changed.connect(self.build_bar)
self.added_actions = []
self.donate_action = QAction(_('Donate'), self)
self.donate_menu = QMenu()
self.donate_menu.addAction(self.gui.donate_action)
self.donate_action.setMenu(self.donate_menu)
self.build_bar()
def build_bar(self, changed_action=None):
showing_device = self.location_manager.has_device
actions = '-device' if showing_device else ''
actions = gprefs['action-layout-menubar'+actions]
show_main = len(actions) > 0
self.setVisible(show_main)
for ac in self.added_actions:
m = ac.menu()
if m is not None:
m.setVisible(False)
self.clear()
self.added_actions = []
self.action_map = {}
for what in actions:
if what is None:
continue
elif what == 'Location Manager':
for ac in self.location_manager.available_actions:
ac = self.build_menu(ac)
self.addAction(ac)
self.added_actions.append(ac)
elif what == 'Donate':
self.addAction(self.donate_action)
elif what in self.gui.iactions:
action = self.gui.iactions[what]
ac = self.build_menu(action.qaction)
self.addAction(ac)
self.added_actions.append(ac)
def build_menu(self, action):
m = action.menu()
ac = MenuAction(action, self)
if m is None:
m = QMenu()
m.addAction(action)
ac.setMenu(m)
return ac
# }}}
class ToolBar(QToolBar): # {{{
def __init__(self, donate, location_manager, child_bar, parent):
@ -284,6 +358,8 @@ def build_bar(self):
mactions = gprefs['action-layout-toolbar'+mactions]
cactions = gprefs['action-layout-toolbar-child']
show_main = len(mactions) > 0
self.setVisible(show_main)
show_child = len(cactions) > 0
self.child_bar.setVisible(show_child)
@ -306,11 +382,16 @@ def build_bar(self):
bar.added_actions.append(ac)
bar.setup_tool_button(bar, ac, QToolButton.MenuButtonPopup)
elif what == 'Donate':
self.d_widget = QWidget()
self.d_widget.setLayout(QVBoxLayout())
self.d_widget.layout().addWidget(self.donate_button)
bar.addWidget(self.d_widget)
self.showing_donate = True
if isosx:
bar.addAction(self.gui.donate_action)
ch = self.setup_tool_button(bar, self.gui.donate_action)
ch.setText(_('Donate'))
else:
self.d_widget = QWidget()
self.d_widget.setLayout(QVBoxLayout())
self.d_widget.layout().addWidget(self.donate_button)
bar.addWidget(self.d_widget)
self.showing_donate = True
elif what in self.gui.iactions:
action = self.gui.iactions[what]
bar.addAction(action.qaction)
@ -325,17 +406,20 @@ def setup_tool_button(self, bar, ac, menu_mode=None):
ch.setAutoRaise(True)
if ac.menu() is not None and menu_mode is not None:
ch.setPopupMode(menu_mode)
return ch
def resizeEvent(self, ev):
QToolBar.resizeEvent(self, ev)
style = Qt.ToolButtonTextUnderIcon
p = gprefs['toolbar_text']
if p == 'never':
style = Qt.ToolButtonIconOnly
s = gprefs['toolbar_icon_size']
if s != 'off':
p = gprefs['toolbar_text']
if p == 'never':
style = Qt.ToolButtonIconOnly
if p == 'auto' and self.preferred_width > self.width()+35 and \
not gprefs['action-layout-toolbar-child']:
style = Qt.ToolButtonIconOnly
if p == 'auto' and self.preferred_width > self.width()+35 and \
not gprefs['action-layout-toolbar-child']:
style = Qt.ToolButtonIconOnly
self.setToolButtonStyle(style)
@ -421,6 +505,9 @@ def __init__(self, db):
self.location_manager, self.child_bar, self)
self.addToolBar(Qt.TopToolBarArea, self.tool_bar)
self.addToolBar(Qt.BottomToolBarArea, self.child_bar)
self.menu_bar = MenuBar(self.location_manager, self)
self.setMenuBar(self.menu_bar)
self.setUnifiedTitleAndToolBarOnMac(True)
l = self.centralwidget.layout()
l.addWidget(self.search_bar)

View file

@ -360,6 +360,7 @@ def closeEvent(self, *args):
self.gui.create_device_menu()
self.gui.set_device_menu_items_state(bool(self.gui.device_connected))
self.gui.tool_bar.build_bar()
self.gui.menu_bar.build_bar()
self.gui.build_context_menus()
self.gui.tool_bar.apply_settings()

View file

@ -34,9 +34,12 @@ def name_to_action(self, name, gui):
if name == 'Location Manager':
return FakeAction(name, None,
_('Switch between library and device views'),
dont_remove_from=set(['toolbar-device']))
dont_add_to=frozenset(['menubar', 'toolbar',
'toolbar-child', 'context-menu',
'context-menu-device']))
if name is None:
return FakeAction('--- '+_('Separator')+' ---', None)
return FakeAction('--- '+_('Separator')+' ---', None,
dont_add_to=frozenset(['menubar', 'menubar-device']))
try:
return gui.iactions[name]
except:
@ -89,7 +92,7 @@ def __init__(self, key, gui):
self._data = self.get_all_actions(current)
def get_all_actions(self, current):
all = list(self.gui.iactions.keys()) + ['Donate']
all = list(self.gui.iactions.keys()) + ['Donate', 'Location Manager']
all = [x for x in all if x not in current] + [None]
all = [self.name_to_action(x, self.gui) for x in all]
all = [x for x in all if self.key not in x.dont_add_to]
@ -208,12 +211,14 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
LOCATIONS = [
('toolbar', _('The main toolbar')),
('toolbar-child', _('The optional second toolbar')),
('toolbar-device', _('The main toolbar when a device is connected')),
('toolbar-child', _('The optional second toolbar')),
('menubar', _('The menubar')),
('menubar-device', _('The menubar when a device is connected')),
('context-menu', _('The context menu for the books in the '
'calibre library')),
('context-menu-device', _('The context menu for the books on '
'the device'))
'the device')),
]
def genesis(self, gui):
@ -284,6 +289,21 @@ def move(self, delta, *args):
self.changed_signal.emit()
def commit(self):
# Ensure preferences are showing in either the toolbar or
# the menubar.
pref_in_toolbar = lm_in_toolbar = False
cm = self.models['toolbar']
for x in cm[1]._data:
if x.name == 'Preferences':
pref_in_toolbar = True
if x.name == 'Location Manager':
lm_in_toolbar = True
if not pref_in_toolbar:
self.models['menubar'][1].add(['Preferences'])
if not lm_in_toolbar:
self.models['menubar-device'][1].add(['Location Manager'])
# Save data.
for am, cm in self.models.values():
cm.commit()
return False

View file

@ -153,6 +153,7 @@ def initialize(self, library_path, db, listener, actions, show_gui=True):
for ac in self.iactions.values():
ac.do_genesis()
self.donate_action = QAction(QIcon(I('donate.png')), _('&Donate to support calibre'), self)
MainWindowMixin.__init__(self, db)
# Jobs Button {{{
@ -186,8 +187,7 @@ def initialize(self, library_path, db, listener, actions, show_gui=True):
self.system_tray_menu = QMenu(self)
self.restore_action = self.system_tray_menu.addAction(
QIcon(I('page.png')), _('&Restore'))
self.donate_action = self.system_tray_menu.addAction(
QIcon(I('donate.png')), _('&Donate to support calibre'))
self.system_tray_menu.addAction(self.donate_action)
self.donate_button.setDefaultAction(self.donate_action)
self.donate_button.setStatusTip(self.donate_button.toolTip())
self.eject_action = self.system_tray_menu.addAction(