From e042cfc9a153baa91101f41aa52ff4cb1c6dee4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Sun, 26 Apr 2015 23:08:33 +0200 Subject: [PATCH 1/8] Add drag support for dockwidgets sharing same position --- spyderlib/plugins/__init__.py | 98 ++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 2 deletions(-) diff --git a/spyderlib/plugins/__init__.py b/spyderlib/plugins/__init__.py index 6b760b9bbe2..8e9376ec507 100644 --- a/spyderlib/plugins/__init__.py +++ b/spyderlib/plugins/__init__.py @@ -21,8 +21,10 @@ # Qt imports from spyderlib.qt import PYQT5 from spyderlib.qt.QtGui import (QDockWidget, QWidget, QShortcut, QCursor, - QKeySequence, QMainWindow, QApplication) -from spyderlib.qt.QtCore import Qt, Signal + QKeySequence, QMainWindow, QApplication, + QTabBar) +from spyderlib.qt.QtCore import Qt, Signal, QObject, QEvent + # Stdlib imports import sys @@ -121,6 +123,10 @@ class SpyderDockWidget(QDockWidget): def __init__(self, *args, **kwargs): super(SpyderDockWidget, self).__init__(*args, **kwargs) + self.visibilityChanged.connect(self.install_tab_event_filter) + self.title = args[0] + self.main = args[1] + self.bar = None if sys.platform == 'darwin': self.setStyleSheet(self.DARWIN_STYLE) @@ -131,6 +137,94 @@ def closeEvent(self, event): """ self.plugin_closed.emit() + def install_tab_event_filter(self, value): + bar = None + tabbars = self.main.findChildren(QTabBar) + for tabbar in tabbars: + for tab in range(tabbar.count()): + title = tabbar.tabText(tab) + if title == self.title: + bar = tabbar + break + if self.bar is None and bar is not None: + self.bar = bar + self.bar.setAcceptDrops(True) + + if getattr(self.bar, 'filter', None) is None: + self.bar.filter = TabFilter(self.bar, self.main) + self.bar.installEventFilter(self.bar.filter) + + +class TabFilter(QObject): + """ + """ + def __init__(self, tabbar, main): + QObject.__init__(self) + self.tabbar = tabbar + self.main = main + self.moving = False + + def eventFilter(self, obj, event): + event_type = event.type() + if event_type == QEvent.MouseButtonPress: + self.tab_pressed(event) + if event_type == QEvent.MouseMove: + self.tab_moved(event) + return True + if event_type == QEvent.MouseButtonRelease: + self.tab_released(event) + return True + return False + + def tab_released(self, event): + QApplication.restoreOverrideCursor() + self.moving = False + + def tab_pressed(self, event): + if event.button() == Qt.LeftButton: + start_tab = self.tabbar.tabAt(event.pos()) + self.start_widget = self.get_widget(start_tab) + self.widgets = self.get_widgets() + + def tab_moved(self, event): + # If the left button isn't pressed anymore then return + if not event.buttons() & Qt.LeftButton: + return + if not self.moving: + QApplication.setOverrideCursor(Qt.OpenHandCursor) + self.moving = True + pos = event.pos() + end_tab = self.tabbar.tabAt(pos) + self.end_widget = self.get_widget(end_tab) + + if self.start_widget is not self.end_widget and\ + self.end_widget is not None: + self.move_tab() + + def move_tab(self): + widgets = self.widgets + start = widgets.index(self.start_widget) + end = widgets.index(self.end_widget) + + widgets[start], widgets[end] = widgets[end], widgets[start] + + for i in range(len(self.widgets)-1): + self.main.tabify_plugins(widgets[i], widgets[i+1]) + self.widgets = self.get_widgets() + self.start_widget.dockwidget.raise_() + + def get_widget(self, index): + for widget in self.main.widgetlist: + if widget.get_plugin_title() == self.tabbar.tabText(index): + return widget + + def get_widgets(self): + widgets = [] + for index in range(self.tabbar.count()): + widget = self.get_widget(index) + widgets.append(widget) + return widgets + class SpyderPluginMixin(object): """ From 6c3774bfccbdd125a0be14df6b3bcfc84149741f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Mon, 27 Apr 2015 19:19:43 +0200 Subject: [PATCH 2/8] Add docstrings, minor code fixes --- spyderlib/plugins/__init__.py | 102 ++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 36 deletions(-) diff --git a/spyderlib/plugins/__init__.py b/spyderlib/plugins/__init__.py index 8e9376ec507..dfe11784fdd 100644 --- a/spyderlib/plugins/__init__.py +++ b/spyderlib/plugins/__init__.py @@ -123,12 +123,16 @@ class SpyderDockWidget(QDockWidget): def __init__(self, *args, **kwargs): super(SpyderDockWidget, self).__init__(*args, **kwargs) - self.visibilityChanged.connect(self.install_tab_event_filter) + if sys.platform == 'darwin': + self.setStyleSheet(self.DARWIN_STYLE) + + # Needed for the installation of the event filter self.title = args[0] self.main = args[1] self.bar = None - if sys.platform == 'darwin': - self.setStyleSheet(self.DARWIN_STYLE) + + # Update the QTabBar everytime dockwidget visibility changes + self.visibilityChanged.connect(self.install_tab_event_filter) def closeEvent(self, event): """ @@ -138,6 +142,10 @@ def closeEvent(self, event): self.plugin_closed.emit() def install_tab_event_filter(self, value): + """ + Install an event filter to capture mouse events in the tabs of a + QTabBar holding tabified dockwidgets. + """ bar = None tabbars = self.main.findChildren(QTabBar) for tabbar in tabbars: @@ -148,7 +156,7 @@ def install_tab_event_filter(self, value): break if self.bar is None and bar is not None: self.bar = bar - self.bar.setAcceptDrops(True) + #self.bar.setAcceptDrops(True) if getattr(self.bar, 'filter', None) is None: self.bar.filter = TabFilter(self.bar, self.main) @@ -157,17 +165,44 @@ def install_tab_event_filter(self, value): class TabFilter(QObject): """ + Filter event attached to each QTabBar that holds 2 or more dockwidgets in + charge of handling tab rearangement. + + This filter also holds the methods needed for the detection of a drag and + the movement of tabs. """ def __init__(self, tabbar, main): QObject.__init__(self) self.tabbar = tabbar self.main = main self.moving = False + self.start_tab = None + self.end_tab = None + + # Helper methods + def _get_widget(self, index): + """Get widget (Plugin) reference based on tab index.""" + for widget in self.main.widgetlist: + if widget.get_plugin_title() == self.tabbar.tabText(index): + return widget + + def _get_widgets(self): + """ + Get a list of all the widgets (Plugins) references in the QTabBar to + which this event filter was attached. + """ + widgets = [] + for index in range(self.tabbar.count()): + widget = self._get_widget(index) + widgets.append(widget) + return widgets def eventFilter(self, obj, event): + """Filter mouse press events.""" event_type = event.type() if event_type == QEvent.MouseButtonPress: self.tab_pressed(event) + return False if event_type == QEvent.MouseMove: self.tab_moved(event) return True @@ -176,54 +211,49 @@ def eventFilter(self, obj, event): return True return False - def tab_released(self, event): - QApplication.restoreOverrideCursor() - self.moving = False - def tab_pressed(self, event): + """Method called when a tab from a QTabBar has been pressed.""" if event.button() == Qt.LeftButton: - start_tab = self.tabbar.tabAt(event.pos()) - self.start_widget = self.get_widget(start_tab) - self.widgets = self.get_widgets() + self.start_tab = self.tabbar.tabAt(event.pos()) def tab_moved(self, event): + """ + Method called when a tab from a QTabBar has been moved. + """ # If the left button isn't pressed anymore then return if not event.buttons() & Qt.LeftButton: return if not self.moving: - QApplication.setOverrideCursor(Qt.OpenHandCursor) + QApplication.setOverrideCursor(Qt.ClosedHandCursor) self.moving = True + pos = event.pos() - end_tab = self.tabbar.tabAt(pos) - self.end_widget = self.get_widget(end_tab) + self.end_tab = self.tabbar.tabAt(pos) + if self.end_tab < 0: + self.end_tab = self.start_tab - if self.start_widget is not self.end_widget and\ - self.end_widget is not None: - self.move_tab() + if self.start_tab != self.end_tab: + self.move_tab(self.start_tab, self.end_tab) + self.start_tab = self.end_tab - def move_tab(self): - widgets = self.widgets - start = widgets.index(self.start_widget) - end = widgets.index(self.end_widget) + def tab_released(self, event): + """Method called when a tab from a QTabBar has been released.""" + QApplication.restoreOverrideCursor() + self.moving = False + def move_tab(self, start_tab, end_tab): + """Move a tab from a start to and end position .""" + widgets = self._get_widgets() + start_widget = self._get_widget(start_tab) + end_widget = self._get_widget(end_tab) + + start = widgets.index(start_widget) + end = widgets.index(end_widget) widgets[start], widgets[end] = widgets[end], widgets[start] - for i in range(len(self.widgets)-1): + for i in range(len(widgets)-1): self.main.tabify_plugins(widgets[i], widgets[i+1]) - self.widgets = self.get_widgets() - self.start_widget.dockwidget.raise_() - - def get_widget(self, index): - for widget in self.main.widgetlist: - if widget.get_plugin_title() == self.tabbar.tabText(index): - return widget - - def get_widgets(self): - widgets = [] - for index in range(self.tabbar.count()): - widget = self.get_widget(index) - widgets.append(widget) - return widgets + start_widget.dockwidget.raise_() class SpyderPluginMixin(object): From 0ad02d05fb5c2f060c30c3343bc51163cab38e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Mon, 27 Apr 2015 19:40:38 +0200 Subject: [PATCH 3/8] Fix behavior when moving pane to a new location --- spyderlib/plugins/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spyderlib/plugins/__init__.py b/spyderlib/plugins/__init__.py index dfe11784fdd..fec53f333cb 100644 --- a/spyderlib/plugins/__init__.py +++ b/spyderlib/plugins/__init__.py @@ -154,10 +154,8 @@ def install_tab_event_filter(self, value): if title == self.title: bar = tabbar break - if self.bar is None and bar is not None: + if bar is not None: self.bar = bar - #self.bar.setAcceptDrops(True) - if getattr(self.bar, 'filter', None) is None: self.bar.filter = TabFilter(self.bar, self.main) self.bar.installEventFilter(self.bar.filter) From 47f71219198d2d7174769ccf9d047fae0ab729d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Tue, 28 Apr 2015 00:14:22 +0200 Subject: [PATCH 4/8] Renamed variables for clarity, reorganized code --- spyderlib/plugins/__init__.py | 201 +++++++++++++++++----------------- 1 file changed, 100 insertions(+), 101 deletions(-) diff --git a/spyderlib/plugins/__init__.py b/spyderlib/plugins/__init__.py index fec53f333cb..a75bcac4509 100644 --- a/spyderlib/plugins/__init__.py +++ b/spyderlib/plugins/__init__.py @@ -57,6 +57,97 @@ def get_icon(self): return self.plugin.get_plugin_icon() +class TabFilter(QObject): + """ + Filter event attached to each QTabBar that holds 2 or more dockwidgets in + charge of handling tab rearangement. + + This filter also holds the methods needed for the detection of a drag and + the movement of tabs. + """ + def __init__(self, dock_tabbar, main): + QObject.__init__(self) + self.dock_tabbar = dock_tabbar + self.main = main + self.moving = False + self.start_tab = None + self.end_tab = None + + # Helper methods + def _get_plugin(self, index): + """Get plugin reference based on tab index.""" + for plugin in self.main.widgetlist: + if plugin.get_plugin_title() == self.dock_tabbar.tabText(index): + return plugin + + def _get_plugins(self): + """ + Get a list of all the plugins references in the QTabBar to which this + event filter was attached. + """ + plugins = [] + for index in range(self.dock_tabbar.count()): + plugin = self._get_plugin(index) + plugins.append(plugin) + return plugins + + def eventFilter(self, obj, event): + """Filter mouse press events.""" + event_type = event.type() + if event_type == QEvent.MouseButtonPress: + self.tab_pressed(event) + return False + if event_type == QEvent.MouseMove: + self.tab_moved(event) + return True + if event_type == QEvent.MouseButtonRelease: + self.tab_released(event) + return True + return False + + def tab_pressed(self, event): + """Method called when a tab from a QTabBar has been pressed.""" + if event.button() == Qt.LeftButton: + self.start_tab = self.dock_tabbar.tabAt(event.pos()) + + def tab_moved(self, event): + """Method called when a tab from a QTabBar has been moved.""" + # If the left button isn't pressed anymore then return + if not event.buttons() & Qt.LeftButton: + return + if not self.moving: + QApplication.setOverrideCursor(Qt.ClosedHandCursor) + self.moving = True + + pos = event.pos() + self.end_tab = self.dock_tabbar.tabAt(pos) + if self.end_tab < 0: + self.end_tab = self.start_tab + + if self.start_tab != self.end_tab: + self.move_tab(self.start_tab, self.end_tab) + self.start_tab = self.end_tab + + def tab_released(self, event): + """Method called when a tab from a QTabBar has been released.""" + QApplication.restoreOverrideCursor() + self.moving = False + + def move_tab(self, start_tab, end_tab): + """Move a tab from a start to and end position .""" + plugins = self._get_plugins() + start_plugin = self._get_plugin(start_tab) + end_plugin = self._get_plugin(end_tab) + + start = plugins.index(start_plugin) + end = plugins.index(end_plugin) + plugins[start], plugins[end] = plugins[end], plugins[start] + + for i in range(len(plugins)-1): + self.main.tabify_plugins(plugins[i], plugins[i+1]) + start_plugin.dockwidget.raise_() + + class SpyderDockWidget(QDockWidget): """Subclass to override needed methods""" DARWIN_STYLE = """ @@ -129,7 +220,7 @@ def __init__(self, *args, **kwargs): # Needed for the installation of the event filter self.title = args[0] self.main = args[1] - self.bar = None + self.dock_tabbar = None # Update the QTabBar everytime dockwidget visibility changes self.visibilityChanged.connect(self.install_tab_event_filter) @@ -146,112 +237,20 @@ def install_tab_event_filter(self, value): Install an event filter to capture mouse events in the tabs of a QTabBar holding tabified dockwidgets. """ - bar = None + dock_tabbar = None tabbars = self.main.findChildren(QTabBar) for tabbar in tabbars: for tab in range(tabbar.count()): title = tabbar.tabText(tab) if title == self.title: - bar = tabbar + dock_tabbar = tabbar break - if bar is not None: - self.bar = bar - if getattr(self.bar, 'filter', None) is None: - self.bar.filter = TabFilter(self.bar, self.main) - self.bar.installEventFilter(self.bar.filter) - - -class TabFilter(QObject): - """ - Filter event attached to each QTabBar that holds 2 or more dockwidgets in - charge of handling tab rearangement. - - This filter also holds the methods needed for the detection of a drag and - the movement of tabs. - """ - def __init__(self, tabbar, main): - QObject.__init__(self) - self.tabbar = tabbar - self.main = main - self.moving = False - self.start_tab = None - self.end_tab = None - - # Helper methods - def _get_widget(self, index): - """Get widget (Plugin) reference based on tab index.""" - for widget in self.main.widgetlist: - if widget.get_plugin_title() == self.tabbar.tabText(index): - return widget - - def _get_widgets(self): - """ - Get a list of all the widgets (Plugins) references in the QTabBar to - which this event filter was attached. - """ - widgets = [] - for index in range(self.tabbar.count()): - widget = self._get_widget(index) - widgets.append(widget) - return widgets - - def eventFilter(self, obj, event): - """Filter mouse press events.""" - event_type = event.type() - if event_type == QEvent.MouseButtonPress: - self.tab_pressed(event) - return False - if event_type == QEvent.MouseMove: - self.tab_moved(event) - return True - if event_type == QEvent.MouseButtonRelease: - self.tab_released(event) - return True - return False - - def tab_pressed(self, event): - """Method called when a tab from a QTabBar has been pressed.""" - if event.button() == Qt.LeftButton: - self.start_tab = self.tabbar.tabAt(event.pos()) - - def tab_moved(self, event): - """ - Method called when a tab from a QTabBar has been moved. - """ - # If the left button isn't pressed anymore then return - if not event.buttons() & Qt.LeftButton: - return - if not self.moving: - QApplication.setOverrideCursor(Qt.ClosedHandCursor) - self.moving = True - - pos = event.pos() - self.end_tab = self.tabbar.tabAt(pos) - if self.end_tab < 0: - self.end_tab = self.start_tab - - if self.start_tab != self.end_tab: - self.move_tab(self.start_tab, self.end_tab) - self.start_tab = self.end_tab - - def tab_released(self, event): - """Method called when a tab from a QTabBar has been released.""" - QApplication.restoreOverrideCursor() - self.moving = False - - def move_tab(self, start_tab, end_tab): - """Move a tab from a start to and end position .""" - widgets = self._get_widgets() - start_widget = self._get_widget(start_tab) - end_widget = self._get_widget(end_tab) - - start = widgets.index(start_widget) - end = widgets.index(end_widget) - widgets[start], widgets[end] = widgets[end], widgets[start] - - for i in range(len(widgets)-1): - self.main.tabify_plugins(widgets[i], widgets[i+1]) - start_widget.dockwidget.raise_() + if dock_tabbar is not None: + self.dock_tabbar = dock_tabbar + if getattr(self.dock_tabbar, 'filter', None) is None: + self.dock_tabbar.filter = TabFilter(self.dock_tabbar, + self.main) + self.dock_tabbar.installEventFilter(self.dock_tabbar.filter) class SpyderPluginMixin(object): From 0c2e1d60cda69fc20241791226af555a966bbc3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Tue, 28 Apr 2015 10:26:17 +0200 Subject: [PATCH 5/8] Minor code fixes --- spyderlib/plugins/__init__.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/spyderlib/plugins/__init__.py b/spyderlib/plugins/__init__.py index a75bcac4509..bc4b0c224c9 100644 --- a/spyderlib/plugins/__init__.py +++ b/spyderlib/plugins/__init__.py @@ -134,7 +134,7 @@ def tab_released(self, event): self.moving = False def move_tab(self, start_tab, end_tab): - """Move a tab from a start to and end position .""" + """Move a tab from a start to and end position.""" plugins = self._get_plugins() start_plugin = self._get_plugin(start_tab) end_plugin = self._get_plugin(end_tab) @@ -212,17 +212,19 @@ class SpyderDockWidget(QDockWidget): plugin_closed = Signal() - def __init__(self, *args, **kwargs): - super(SpyderDockWidget, self).__init__(*args, **kwargs) + def __init__(self, title, parent): + super(SpyderDockWidget, self).__init__(title, parent) if sys.platform == 'darwin': self.setStyleSheet(self.DARWIN_STYLE) # Needed for the installation of the event filter - self.title = args[0] - self.main = args[1] + self.title = title + self.main = parent self.dock_tabbar = None - # Update the QTabBar everytime dockwidget visibility changes + # To track dockwidget changes the filter is installed when dockwidget + # visibility changes. This installs the filter on startup and also + # on dockwidgets that are undocked and then docked to a new location. self.visibilityChanged.connect(self.install_tab_event_filter) def closeEvent(self, event): @@ -247,6 +249,7 @@ def install_tab_event_filter(self, value): break if dock_tabbar is not None: self.dock_tabbar = dock_tabbar + # Install filter only once per QTabBar if getattr(self.dock_tabbar, 'filter', None) is None: self.dock_tabbar.filter = TabFilter(self.dock_tabbar, self.main) From e5d6dde5ee7b7a0ee51e80e70390d41f9cca8466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Sun, 3 May 2015 16:34:40 +0200 Subject: [PATCH 6/8] Rename variables, add support for cursor fix --- spyderlib/plugins/__init__.py | 81 ++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 21 deletions(-) diff --git a/spyderlib/plugins/__init__.py b/spyderlib/plugins/__init__.py index bc4b0c224c9..f55acf9b793 100644 --- a/spyderlib/plugins/__init__.py +++ b/spyderlib/plugins/__init__.py @@ -23,7 +23,7 @@ from spyderlib.qt.QtGui import (QDockWidget, QWidget, QShortcut, QCursor, QKeySequence, QMainWindow, QApplication, QTabBar) -from spyderlib.qt.QtCore import Qt, Signal, QObject, QEvent +from spyderlib.qt.QtCore import Qt, Signal, QObject, QEvent, QPoint # Stdlib imports @@ -65,13 +65,15 @@ class TabFilter(QObject): This filter also holds the methods needed for the detection of a drag and the movement of tabs. """ + sig_tab_moved = Signal(int, int) + def __init__(self, dock_tabbar, main): QObject.__init__(self) self.dock_tabbar = dock_tabbar self.main = main self.moving = False - self.start_tab = None - self.end_tab = None + self.from_index = None + self.to_index = None # Helper methods def _get_plugin(self, index): @@ -91,6 +93,26 @@ def _get_plugins(self): plugins.append(plugin) return plugins + def _fix_cursor(self, from_index, to_index): + """Fix mouse cursor position to adjust for different tab sizes.""" + direction = abs(to_index - from_index)/(to_index - from_index) + tab_width = self.dock_tabbar.tabRect(to_index).width() + tab_x_min = self.dock_tabbar.tabRect(to_index).x() + tab_x_max = tab_x_min + tab_width + previous_width = self.dock_tabbar.tabRect(to_index - direction).width() + + delta = previous_width - tab_width + if delta > 0: + delta = delta * direction + else: + delta = 0 + cursor = QCursor() + pos = self.dock_tabbar.mapFromGlobal(cursor.pos()) + x, y = pos.x(), pos.y() + if x < tab_x_min or x > tab_x_max: + new_pos = self.dock_tabbar.mapToGlobal(QPoint(x + delta, y)) + cursor.setPos(new_pos) + def eventFilter(self, obj, event): """Filter mouse press events.""" event_type = event.type() @@ -107,45 +129,62 @@ def eventFilter(self, obj, event): def tab_pressed(self, event): """Method called when a tab from a QTabBar has been pressed.""" - if event.button() == Qt.LeftButton: - self.start_tab = self.dock_tabbar.tabAt(event.pos()) + self.from_index = self.dock_tabbar.tabAt(event.pos()) + + if event.button() == Qt.RightButton: + if self.from_index == -1: + self.show_nontab_menu() + else: + self.show_tab_menu() def tab_moved(self, event): """Method called when a tab from a QTabBar has been moved.""" # If the left button isn't pressed anymore then return if not event.buttons() & Qt.LeftButton: + self.to_index = None return - if not self.moving: + + self.to_index = self.dock_tabbar.tabAt(event.pos()) + + if not self.moving and self.from_index != -1 and self.to_index != -1: QApplication.setOverrideCursor(Qt.ClosedHandCursor) self.moving = True - pos = event.pos() - self.end_tab = self.dock_tabbar.tabAt(pos) - if self.end_tab < 0: - self.end_tab = self.start_tab + if self.to_index == -1: + self.to_index = self.from_index - if self.start_tab != self.end_tab: - self.move_tab(self.start_tab, self.end_tab) - self.start_tab = self.end_tab + from_index, to_index = self.from_index, self.to_index + if from_index != to_index and from_index != -1 and to_index != -1: + self.sig_tab_moved.emit(from_index, to_index) + self.move_tab(from_index, to_index) + self._fix_cursor(from_index, to_index) + self.from_index = to_index def tab_released(self, event): """Method called when a tab from a QTabBar has been released.""" QApplication.restoreOverrideCursor() self.moving = False - def move_tab(self, start_tab, end_tab): - """Move a tab from a start to and end position.""" + def move_tab(self, from_index, to_index): + """Move a tab from a given index to a given index position.""" plugins = self._get_plugins() - start_plugin = self._get_plugin(start_tab) - end_plugin = self._get_plugin(end_tab) + from_plugin = self._get_plugin(from_index) + to_plugin = self._get_plugin(to_index) + + from_idx = plugins.index(from_plugin) + to_idx = plugins.index(to_plugin) - start = plugins.index(start_plugin) - end = plugins.index(end_plugin) - plugins[start], plugins[end] = plugins[end], plugins[start] + plugins[from_idx], plugins[to_idx] = plugins[to_idx], plugins[from_idx] for i in range(len(plugins)-1): self.main.tabify_plugins(plugins[i], plugins[i+1]) - start_plugin.dockwidget.raise_() + from_plugin.dockwidget.raise_() + + def show_tab_menu(self): + """Show the context menu assigned to tabs.""" + + def show_nontab_menu(self): + """Show the context menu assigned to nontabs section.""" class SpyderDockWidget(QDockWidget): From bf7ba2f286074999a8a76e3f76cc7a1544c6bfed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Sun, 3 May 2015 17:57:02 +0200 Subject: [PATCH 7/8] Refactr code for clarity, minor fixes --- spyderlib/plugins/__init__.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/spyderlib/plugins/__init__.py b/spyderlib/plugins/__init__.py index f55acf9b793..10919018d0c 100644 --- a/spyderlib/plugins/__init__.py +++ b/spyderlib/plugins/__init__.py @@ -65,8 +65,6 @@ class TabFilter(QObject): This filter also holds the methods needed for the detection of a drag and the movement of tabs. """ - sig_tab_moved = Signal(int, int) - def __init__(self, dock_tabbar, main): QObject.__init__(self) self.dock_tabbar = dock_tabbar @@ -84,8 +82,8 @@ def _get_plugin(self, index): def _get_plugins(self): """ - Get a list of all the plugins references in the QTabBar to which this - event filter was attached. + Get a list of all plugin references in the QTabBar to which this + event filter is attached. """ plugins = [] for index in range(self.dock_tabbar.count()): @@ -95,7 +93,9 @@ def _get_plugins(self): def _fix_cursor(self, from_index, to_index): """Fix mouse cursor position to adjust for different tab sizes.""" + # The direction is +1 (moving to the right) or -1 (moving to the left) direction = abs(to_index - from_index)/(to_index - from_index) + tab_width = self.dock_tabbar.tabRect(to_index).width() tab_x_min = self.dock_tabbar.tabRect(to_index).x() tab_x_max = tab_x_min + tab_width @@ -114,7 +114,11 @@ def _fix_cursor(self, from_index, to_index): cursor.setPos(new_pos) def eventFilter(self, obj, event): - """Filter mouse press events.""" + """Filter mouse press events. + + Events that are captured and not propagated return True. Events that + are not captured and are propagated return False. + """ event_type = event.type() if event_type == QEvent.MouseButtonPress: self.tab_pressed(event) @@ -155,7 +159,6 @@ def tab_moved(self, event): from_index, to_index = self.from_index, self.to_index if from_index != to_index and from_index != -1 and to_index != -1: - self.sig_tab_moved.emit(from_index, to_index) self.move_tab(from_index, to_index) self._fix_cursor(from_index, to_index) self.from_index = to_index @@ -182,9 +185,11 @@ def move_tab(self, from_index, to_index): def show_tab_menu(self): """Show the context menu assigned to tabs.""" + pass def show_nontab_menu(self): """Show the context menu assigned to nontabs section.""" + pass class SpyderDockWidget(QDockWidget): From c22bc4827ea83ab2b7fbe1c5df3caa0d99097007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Sun, 3 May 2015 18:48:17 +0200 Subject: [PATCH 8/8] Add context menu to tab and nontab area --- spyderlib/plugins/__init__.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/spyderlib/plugins/__init__.py b/spyderlib/plugins/__init__.py index 10919018d0c..30a6e148455 100644 --- a/spyderlib/plugins/__init__.py +++ b/spyderlib/plugins/__init__.py @@ -137,9 +137,9 @@ def tab_pressed(self, event): if event.button() == Qt.RightButton: if self.from_index == -1: - self.show_nontab_menu() + self.show_nontab_menu(event) else: - self.show_tab_menu() + self.show_tab_menu(event) def tab_moved(self, event): """Method called when a tab from a QTabBar has been moved.""" @@ -183,13 +183,14 @@ def move_tab(self, from_index, to_index): self.main.tabify_plugins(plugins[i], plugins[i+1]) from_plugin.dockwidget.raise_() - def show_tab_menu(self): + def show_tab_menu(self, event): """Show the context menu assigned to tabs.""" - pass + self.show_nontab_menu(event) - def show_nontab_menu(self): + def show_nontab_menu(self, event): """Show the context menu assigned to nontabs section.""" - pass + menu = self.main.createPopupMenu() + menu.exec_(self.dock_tabbar.mapToGlobal(event.pos())) class SpyderDockWidget(QDockWidget):