mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Workaround for broken handling of menus on OSX in Qt 5
This commit is contained in:
parent
500b05da83
commit
8ea1a6c6cb
@ -359,6 +359,9 @@ class ChooseLibraryAction(InterfaceAction):
|
||||
self.gui.location_manager.set_switch_actions(quick_actions,
|
||||
rename_actions, delete_actions, qs_actions,
|
||||
self.action_choose)
|
||||
# Allow the cloned actions in the OS X global menubar to update
|
||||
for a in (self.qaction, self.menuless_qaction):
|
||||
a.changed.emit()
|
||||
|
||||
def location_selected(self, loc):
|
||||
enabled = loc == 'library'
|
||||
|
@ -7,10 +7,11 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
import sip
|
||||
from PyQt5.Qt import (Qt, QAction, QMenu, QMenuBar, QObject,
|
||||
QToolBar, QToolButton, QSize)
|
||||
QToolBar, QToolButton, QSize, pyqtSignal, QTimer)
|
||||
|
||||
from calibre.constants import isosx
|
||||
from calibre.gui2.throbber import create_donate_widget
|
||||
from calibre.gui2 import gprefs
|
||||
|
||||
@ -204,61 +205,203 @@ class MenuAction(QAction): # {{{
|
||||
self.setText(self.clone.text())
|
||||
# }}}
|
||||
|
||||
class MenuBar(QMenuBar): # {{{
|
||||
# MenuBar {{{
|
||||
|
||||
def __init__(self, location_manager, parent):
|
||||
QMenuBar.__init__(self, parent)
|
||||
self.gui = parent
|
||||
self.setNativeMenuBar(True)
|
||||
if isosx:
|
||||
# On OS X we need special handling for the application global menu bar and
|
||||
# the context menus, since Qt does not handle dynamic menus or menus in
|
||||
# which the same action occurs in more than one place.
|
||||
|
||||
self.location_manager = location_manager
|
||||
self.added_actions = []
|
||||
class CloneAction(QAction):
|
||||
|
||||
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)
|
||||
text_changed = pyqtSignal()
|
||||
visibility_changed = pyqtSignal()
|
||||
|
||||
def update_lm_actions(self):
|
||||
for ac in self.added_actions:
|
||||
clone = getattr(ac, 'clone', None)
|
||||
if clone is not None and clone in self.location_manager.all_actions:
|
||||
ac.setVisible(clone in self.location_manager.available_actions)
|
||||
def __init__(self, clone, parent, is_top_level=False, clone_shortcuts=True):
|
||||
QAction.__init__(self, clone.text(), parent)
|
||||
self.is_top_level = is_top_level
|
||||
self.clone_shortcuts = clone_shortcuts
|
||||
self.clone = clone
|
||||
clone.changed.connect(self.clone_changed)
|
||||
self.clone_changed()
|
||||
self.triggered.connect(self.do_trigger)
|
||||
|
||||
def init_bar(self, actions):
|
||||
for ac in self.added_actions:
|
||||
m = ac.menu()
|
||||
if m is not None:
|
||||
m.setVisible(False)
|
||||
def clone_changed(self):
|
||||
otext = self.text()
|
||||
self.setText(self.clone.text())
|
||||
if otext != self.text:
|
||||
self.text_changed.emit()
|
||||
ov = self.isVisible()
|
||||
self.setVisible(self.clone.isVisible())
|
||||
if ov != self.isVisible():
|
||||
self.visibility_changed.emit()
|
||||
self.setEnabled(self.clone.isEnabled())
|
||||
self.setCheckable(self.clone.isCheckable())
|
||||
self.setChecked(self.clone.isChecked())
|
||||
self.setIcon(self.clone.icon())
|
||||
if self.clone_shortcuts:
|
||||
self.setShortcuts(self.clone.shortcuts())
|
||||
if self.clone.menu() is None:
|
||||
if not self.is_top_level:
|
||||
self.setMenu(None)
|
||||
else:
|
||||
m = QMenu(self.text(), self.parent())
|
||||
for ac in QMenu.actions(self.clone.menu()):
|
||||
if ac.isSeparator():
|
||||
m.addSeparator()
|
||||
else:
|
||||
m.addAction(CloneAction(ac, self.parent(), clone_shortcuts=self.clone_shortcuts))
|
||||
self.setMenu(m)
|
||||
|
||||
self.clear()
|
||||
self.added_actions = []
|
||||
def do_trigger(self, checked=False):
|
||||
if not sip.isdeleted(self.clone):
|
||||
self.clone.trigger()
|
||||
|
||||
for what in actions:
|
||||
def populate_menu(m, items, iactions):
|
||||
for what in items:
|
||||
if what is None:
|
||||
continue
|
||||
elif what == 'Location Manager':
|
||||
for ac in self.location_manager.all_actions:
|
||||
ac = self.build_menu(ac)
|
||||
m.addSeparator()
|
||||
elif what in iactions:
|
||||
m.addAction(CloneAction(iactions[what].qaction, m))
|
||||
|
||||
class MenuBar(QObject):
|
||||
|
||||
@property
|
||||
def native_menubar(self):
|
||||
return self.gui.native_menubar
|
||||
|
||||
def __init__(self, location_manager, parent):
|
||||
QObject.__init__(self, parent)
|
||||
self.gui = parent
|
||||
|
||||
self.location_manager = location_manager
|
||||
self.added_actions = []
|
||||
self.last_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.refresh_timer = t = QTimer(self)
|
||||
t.setInterval(200), t.setSingleShot(True), t.timeout.connect(self.refresh_bar)
|
||||
|
||||
def init_bar(self, actions):
|
||||
self.last_actions = actions
|
||||
for ac in self.added_actions:
|
||||
m = ac.menu()
|
||||
if m is not None:
|
||||
m.setVisible(False)
|
||||
|
||||
mb = self.native_menubar
|
||||
for ac in self.added_actions:
|
||||
mb.removeAction(ac)
|
||||
if ac is not self.donate_action:
|
||||
ac.setMenu(None)
|
||||
ac.deleteLater()
|
||||
self.added_actions = []
|
||||
|
||||
for what in actions:
|
||||
if what is None:
|
||||
continue
|
||||
elif what == 'Location Manager':
|
||||
for ac in self.location_manager.available_actions:
|
||||
self.build_menu(ac, ac.isVisible())
|
||||
elif what == 'Donate':
|
||||
mb.addAction(self.donate_action)
|
||||
elif what in self.gui.iactions:
|
||||
action = self.gui.iactions[what]
|
||||
self.build_menu(action.qaction)
|
||||
|
||||
def build_menu(self, ac, visible=True):
|
||||
ans = CloneAction(ac, self.native_menubar, is_top_level=True)
|
||||
ans.setVisible(visible)
|
||||
if ans.menu() is None:
|
||||
m = QMenu()
|
||||
m.addAction(CloneAction(ac, self.native_menubar))
|
||||
ans.setMenu(m)
|
||||
# Qt (as of 5.3.0) does not update global menubar entries
|
||||
# correctly, so we have to rebuild the global menubar.
|
||||
# Without this the Choose Library action shows the text
|
||||
# 'Untitled' and the Location Manager items do not work.
|
||||
ans.text_changed.connect(self.refresh_timer.start)
|
||||
ans.visibility_changed.connect(self.refresh_timer.start)
|
||||
self.native_menubar.addAction(ans)
|
||||
self.added_actions.append(ans)
|
||||
return ans
|
||||
|
||||
def setVisible(self, yes):
|
||||
pass # no-op on OS X since menu bar is always visible
|
||||
|
||||
def update_lm_actions(self):
|
||||
pass # no-op as this is taken care of by init_bar()
|
||||
|
||||
def refresh_bar(self):
|
||||
self.init_bar(self.last_actions)
|
||||
|
||||
else:
|
||||
|
||||
def populate_menu(m, items, iactions):
|
||||
for what in items:
|
||||
if what is None:
|
||||
m.addSeparator()
|
||||
elif what in iactions:
|
||||
m.addAction(iactions[what].qaction)
|
||||
|
||||
class MenuBar(QMenuBar):
|
||||
|
||||
def __init__(self, location_manager, parent):
|
||||
QMenuBar.__init__(self, parent)
|
||||
parent.setMenuBar(self)
|
||||
self.gui = parent
|
||||
|
||||
self.location_manager = location_manager
|
||||
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)
|
||||
|
||||
def init_bar(self, actions):
|
||||
for ac in self.added_actions:
|
||||
m = ac.menu()
|
||||
if m is not None:
|
||||
m.setVisible(False)
|
||||
|
||||
self.clear()
|
||||
self.added_actions = []
|
||||
|
||||
for what in actions:
|
||||
if what is None:
|
||||
continue
|
||||
elif what == 'Location Manager':
|
||||
for ac in self.location_manager.all_actions:
|
||||
ac = self.build_menu(ac)
|
||||
self.addAction(ac)
|
||||
self.added_actions.append(ac)
|
||||
ac.setVisible(False)
|
||||
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)
|
||||
ac.setVisible(False)
|
||||
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
|
||||
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
|
||||
|
||||
def update_lm_actions(self):
|
||||
for ac in self.added_actions:
|
||||
clone = getattr(ac, 'clone', None)
|
||||
if clone is not None and clone in self.location_manager.all_actions:
|
||||
ac.setVisible(clone in self.location_manager.available_actions)
|
||||
|
||||
# }}}
|
||||
|
||||
@ -275,7 +418,6 @@ class BarsManager(QObject):
|
||||
self.child_bars = tuple(bars[2:])
|
||||
|
||||
self.menu_bar = MenuBar(self.location_manager, self.parent())
|
||||
self.parent().setMenuBar(self.menu_bar)
|
||||
|
||||
self.apply_settings()
|
||||
self.init_bars()
|
||||
|
@ -70,16 +70,11 @@ class LibraryViewMixin(object): # {{{
|
||||
self.library_view.model().set_highlight_only(config['highlight_search_matches'])
|
||||
|
||||
def build_context_menus(self):
|
||||
from calibre.gui2.bars import populate_menu
|
||||
lm = QMenu(self)
|
||||
def populate_menu(m, items):
|
||||
for what in items:
|
||||
if what is None:
|
||||
m.addSeparator()
|
||||
elif what in self.iactions:
|
||||
m.addAction(self.iactions[what].qaction)
|
||||
populate_menu(lm, gprefs['action-layout-context-menu'])
|
||||
populate_menu(lm, gprefs['action-layout-context-menu'], self.iactions)
|
||||
dm = QMenu(self)
|
||||
populate_menu(dm, gprefs['action-layout-context-menu-device'])
|
||||
populate_menu(dm, gprefs['action-layout-context-menu-device'], self.iactions)
|
||||
ec = self.iactions['Edit Collections'].qaction
|
||||
self.library_view.set_context_menu(lm, ec)
|
||||
for v in (self.memory_view, self.card_a_view, self.card_b_view):
|
||||
@ -88,7 +83,7 @@ class LibraryViewMixin(object): # {{{
|
||||
if self.cover_flow is not None:
|
||||
cm = QMenu(self.cover_flow)
|
||||
populate_menu(cm,
|
||||
gprefs['action-layout-context-menu-cover-browser'])
|
||||
gprefs['action-layout-context-menu-cover-browser'], self.iactions)
|
||||
self.cover_flow.set_context_menu(cm)
|
||||
|
||||
def search_done(self, view, ok):
|
||||
|
@ -43,10 +43,10 @@ class GarbageCollector(QObject):
|
||||
self.threshold = gc.get_threshold()
|
||||
gc.disable()
|
||||
self.timer.start(self.INTERVAL)
|
||||
#gc.set_debug(gc.DEBUG_SAVEALL)
|
||||
# gc.set_debug(gc.DEBUG_SAVEALL)
|
||||
|
||||
def check(self):
|
||||
#return self.debug_cycles()
|
||||
# return self.debug_cycles()
|
||||
l0, l1, l2 = gc.get_count()
|
||||
if self.debug:
|
||||
print ('gc_check called:', l0, l1, l2)
|
||||
@ -97,6 +97,10 @@ class MainWindow(QMainWindow):
|
||||
quit_action.setMenuRole(QAction.QuitRole)
|
||||
return preferences_action, quit_action
|
||||
|
||||
@property
|
||||
def native_menubar(self):
|
||||
return self.___menu_bar
|
||||
|
||||
def __init__(self, opts, parent=None, disable_automatic_gc=False):
|
||||
QMainWindow.__init__(self, parent)
|
||||
if disable_automatic_gc:
|
||||
|
Loading…
x
Reference in New Issue
Block a user