We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
AttributeError in dockwidgets tabbar
## Description

### What steps will reproduce the problem?

<!--- You can use Markdown here --->

i dont know, im beginner in this program, so im watching a tutorial

### Traceback
```python-traceback
  File "/Users/luismireles/opt/anaconda3/envs/K37/lib/python3.7/site-packages/spyder/widgets/dock.py", line 43, in eventFilter
    self.tab_pressed(event)
  File "/Users/luismireles/opt/anaconda3/envs/K37/lib/python3.7/site-packages/spyder/widgets/dock.py", line 52, in tab_pressed
    if event.button() == Qt.RightButton:
AttributeError: 'QContextMenuEvent' object has no attribute 'button'
```

## Versions

* Spyder version: 4.0.0 
* Python version: 3.7.0
* Qt version: 5.9.6
* PyQt5 version: 5.9.2
* Operating System: Darwin 19.2.0

### Dependencies

```
cloudpickle >=0.5.0          :  1.2.2 (OK)
pygments >=2.0               :  2.5.2 (OK)
qtconsole >=4.6.0            :  4.6.0 (OK)
nbconvert >=4.0              :  5.6.1 (OK)
sphinx >=0.6.6               :  2.3.0 (OK)
pylint >=0.25                :  2.4.4 (OK)
psutil >=0.3                 :  5.6.7 (OK)
qtawesome >=0.5.7            :  0.6.0 (OK)
qtpy >=1.5.0                 :  1.9.0 (OK)
pickleshare >=0.4            :  0.7.5 (OK)
zmq >=17                     :  18.1.0 (OK)
chardet >=2.0.0              :  3.0.4 (OK)
numpydoc >=0.6.0             :  0.9.1 (OK)
spyder_kernels >=1.8.1;<2.0.0:  1.8.1 (OK)
qdarkstyle >=2.7             :  2.7 (OK)
atomicwrites >=1.2.0         :  1.3.0 (OK)
diff_match_patch >=20181111  :  20181111 (OK)
intervaltree                 :  None (OK)
watchdog                     :  None (OK)
keyring                      :  None (OK)
pexpect >=4.4.0              :  4.7.0 (OK)
pympler                      :  None (OK)
sympy >=0.7.3                :  None (NOK)
cython >=0.21                :  0.29.14 (OK)
IPython >=4.0                :  7.10.2 (OK)
matplotlib >=2.0.0           :  3.1.1 (OK)
pandas >=0.13.1              :  0.25.3 (OK)
numpy >=1.7                  :  1.17.4 (OK)
scipy >=0.17.0               :  1.3.1 (OK)
pyls >=0.31.2;<0.32.0        :  0.31.2 (OK)
applaunchservices >=0.1.7    :  0.2.1 (OK)
rtree >=0.8.3                :  0.8.3 (OK)
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `spyder/widgets/dock.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright © Spyder Project Contributors
4 # Licensed under the terms of the MIT License
5 # (see spyder/__init__.py for details)
6 
7 """
8 Dock widgets for plugins
9 """
10 
11 from qtpy.QtCore import QEvent, QObject, Qt, QSize, Signal
12 from qtpy.QtWidgets import (QApplication, QDockWidget, QHBoxLayout,
13                             QSizePolicy, QStyle, QTabBar, QToolButton,
14                             QWidget)
15 
16 from spyder.config.gui import is_dark_interface
17 from spyder.utils import icon_manager as ima
18 
19 
20 # =============================================================================
21 # Tab filter
22 # =============================================================================
23 class TabFilter(QObject):
24     """Filter event attached to each DockWidget QTabBar."""
25     def __init__(self, dock_tabbar, main):
26         QObject.__init__(self)
27         self.dock_tabbar = dock_tabbar
28         self.main = main
29         self.from_index = None
30 
31         # Center dockwidget tabs to differentiate them from plugin tabs.
32         # See spyder-ide/spyder#9763
33         self.dock_tabbar.setStyleSheet("QTabBar {alignment: center;}")
34 
35     def eventFilter(self, obj, event):
36         """Filter mouse press events.
37 
38         Events that are captured and not propagated return True. Events that
39         are not captured and are propagated return False.
40         """
41         event_type = event.type()
42         if event_type == QEvent.MouseButtonPress:
43             self.tab_pressed(event)
44             return False
45         return False
46 
47     def tab_pressed(self, event):
48         """Method called when a tab from a QTabBar has been pressed."""
49         self.from_index = self.dock_tabbar.tabAt(event.pos())
50         self.dock_tabbar.setCurrentIndex(self.from_index)
51 
52         if event.button() == Qt.RightButton:
53             if self.from_index == -1:
54                 self.show_nontab_menu(event)
55             else:
56                 self.show_tab_menu(event)
57 
58     def show_tab_menu(self, event):
59         """Show the context menu assigned to tabs."""
60         self.show_nontab_menu(event)
61 
62     def show_nontab_menu(self, event):
63         """Show the context menu assigned to nontabs section."""
64         menu = self.main.createPopupMenu()
65         menu.exec_(self.dock_tabbar.mapToGlobal(event.pos()))
66 
67 
68 # =============================================================================
69 # Title bar
70 # =============================================================================
71 class DragButton(QToolButton):
72     """
73     Drag button for the title bar.
74 
75     This button pass all its mouse events to its parent.
76     """
77 
78     def __init__(self, parent, button_size):
79         super(QToolButton, self).__init__(parent)
80         self.parent = parent
81 
82         # Style
83         self.setMaximumSize(button_size)
84         self.setAutoRaise(True)
85         self.setIcon(ima.icon('drag-horizontal'))
86         if is_dark_interface():
87             self.setStyleSheet(
88                 "QToolButton {"
89                 "border-radius: 0px;"
90                 "border: 0px;"
91                 "background-color: #32414B;}")
92         else:
93             self.setStyleSheet("QToolButton {border: 0px;}")
94 
95     def mouseReleaseEvent(self, event):
96         self.parent.mouseReleaseEvent(event)
97 
98     def mousePressEvent(self, event):
99         self.parent.mousePressEvent(event)
100 
101     def mouseMoveEvent(self, event):
102         self.parent.mouseMoveEvent(event)
103 
104 
105 class CloseButton(QToolButton):
106     """Close button for the title bar."""
107 
108     def __init__(self, parent, button_size):
109         super(QToolButton, self).__init__(parent)
110 
111         # Style
112         self.setMaximumSize(button_size)
113         self.setAutoRaise(True)
114         self.setCursor(Qt.ArrowCursor)
115         if is_dark_interface():
116             self.setStyleSheet(
117                 "QToolButton {"
118                 "border-radius: 0px;"
119                 "border: 0px;"
120                 "image: url(:/qss_icons/rc/close.png);"
121                 "background-color: #32414B;}"
122                 "QToolButton:hover {"
123                 "image: url(:/qss_icons/rc/close-hover.png);}")
124         else:
125             self.setIcon(QApplication.style().standardIcon(
126                 QStyle.SP_DockWidgetCloseButton))
127 
128 
129 class DockTitleBar(QWidget):
130     """
131     Custom title bar for our dock widgets.
132 
133     Inspired from
134     https://stackoverflow.com/a/40894225/438386
135     """
136 
137     def __init__(self, parent):
138         super(DockTitleBar, self).__init__(parent)
139 
140         icon_size = QApplication.style().standardIcon(
141             QStyle.SP_TitleBarNormalButton).actualSize(QSize(100, 100))
142         button_size = icon_size + QSize(8, 8)
143 
144         left_spacer = QWidget(self)
145         left_spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
146         if is_dark_interface():
147             left_spacer.setStyleSheet("background-color: #32414B")
148 
149         drag_button = DragButton(self, button_size)
150 
151         right_spacer = QWidget(self)
152         right_spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
153         if is_dark_interface():
154             right_spacer.setStyleSheet("background-color: #32414B")
155 
156         close_button = CloseButton(self, button_size)
157         close_button.clicked.connect(parent.sig_plugin_closed.emit)
158 
159         hlayout = QHBoxLayout(self)
160         hlayout.setSpacing(0)
161         hlayout.setContentsMargins(0, 0, 0, 0)
162         hlayout.addWidget(left_spacer)
163         hlayout.addWidget(drag_button)
164         hlayout.addWidget(right_spacer)
165         hlayout.addWidget(close_button)
166 
167         # To signal that dock widgets can be dragged from here
168         self.setCursor(Qt.SizeAllCursor)
169 
170     def mouseReleaseEvent(self, event):
171         self.setCursor(Qt.SizeAllCursor)
172         QWidget.mouseReleaseEvent(self, event)
173 
174     def mousePressEvent(self, event):
175         self.setCursor(Qt.ClosedHandCursor)
176         QWidget.mousePressEvent(self, event)
177 
178     def mouseMoveEvent(self, event):
179         QWidget.mouseMoveEvent(self, event)
180         self.setCursor(Qt.SizeAllCursor)
181 
182 
183 class SpyderDockWidget(QDockWidget):
184     """Subclass to override needed methods"""
185     sig_plugin_closed = Signal()
186 
187     def __init__(self, title, parent):
188         super(SpyderDockWidget, self).__init__(title, parent)
189 
190         # Set our custom title bar
191         self.titlebar = DockTitleBar(self)
192         self.set_title_bar()
193 
194         # Needed for the installation of the event filter
195         self.title = title
196         self.main = parent
197         self.dock_tabbar = None
198 
199         # To track dockwidget changes the filter is installed when dockwidget
200         # visibility changes. This installs the filter on startup and also
201         # on dockwidgets that are undocked and then docked to a new location.
202         self.visibilityChanged.connect(self.install_tab_event_filter)
203 
204     def closeEvent(self, event):
205         """
206         Reimplement Qt method to send a signal on close so that "Panes" main
207         window menu can be updated correctly
208         """
209         self.sig_plugin_closed.emit()
210 
211     def install_tab_event_filter(self, value):
212         """
213         Install an event filter to capture mouse events in the tabs of a
214         QTabBar holding tabified dockwidgets.
215         """
216         dock_tabbar = None
217         tabbars = self.main.findChildren(QTabBar)
218         for tabbar in tabbars:
219             for tab in range(tabbar.count()):
220                 title = tabbar.tabText(tab)
221                 if title == self.title:
222                     dock_tabbar = tabbar
223                     break
224 
225         if dock_tabbar is not None:
226             self.dock_tabbar = dock_tabbar
227             # Install filter only once per QTabBar
228             if getattr(self.dock_tabbar, 'filter', None) is None:
229                 self.dock_tabbar.filter = TabFilter(self.dock_tabbar,
230                                                     self.main)
231                 self.dock_tabbar.installEventFilter(self.dock_tabbar.filter)
232 
233     def set_title_bar(self):
234         """Set custom title bar."""
235         self.setTitleBarWidget(self.titlebar)
236
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/spyder/widgets/dock.py b/spyder/widgets/dock.py
--- a/spyder/widgets/dock.py
+++ b/spyder/widgets/dock.py
@@ -49,11 +49,17 @@
         self.from_index = self.dock_tabbar.tabAt(event.pos())
         self.dock_tabbar.setCurrentIndex(self.from_index)
 
-        if event.button() == Qt.RightButton:
-            if self.from_index == -1:
-                self.show_nontab_menu(event)
-            else:
-                self.show_tab_menu(event)
+        try:
+            if event.button() == Qt.RightButton:
+                if self.from_index == -1:
+                    self.show_nontab_menu(event)
+                else:
+                    self.show_tab_menu(event)
+        except AttributeError:
+            # Needed to avoid an error when generating the
+            # context menu on top of the tab.
+            # See spyder-ide/spyder#11226
+            pass
 
     def show_tab_menu(self, event):
         """Show the context menu assigned to tabs."""

{"golden_diff": "diff --git a/spyder/widgets/dock.py b/spyder/widgets/dock.py\n--- a/spyder/widgets/dock.py\n+++ b/spyder/widgets/dock.py\n@@ -49,11 +49,17 @@\n         self.from_index = self.dock_tabbar.tabAt(event.pos())\n         self.dock_tabbar.setCurrentIndex(self.from_index)\n \n-        if event.button() == Qt.RightButton:\n-            if self.from_index == -1:\n-                self.show_nontab_menu(event)\n-            else:\n-                self.show_tab_menu(event)\n+        try:\n+            if event.button() == Qt.RightButton:\n+                if self.from_index == -1:\n+                    self.show_nontab_menu(event)\n+                else:\n+                    self.show_tab_menu(event)\n+        except AttributeError:\n+            # Needed to avoid an error when generating the\n+            # context menu on top of the tab.\n+            # See spyder-ide/spyder#11226\n+            pass\n \n     def show_tab_menu(self, event):\n         \"\"\"Show the context menu assigned to tabs.\"\"\"\n", "issue": "AttributeError in dockwidgets tabbar\n## Description\n\n### What steps will reproduce the problem?\n\n<!--- You can use Markdown here --->\n\ni dont know, im beginner in this program, so im watching a tutorial\n\n### Traceback\n```python-traceback\n  File \"/Users/luismireles/opt/anaconda3/envs/K37/lib/python3.7/site-packages/spyder/widgets/dock.py\", line 43, in eventFilter\n    self.tab_pressed(event)\n  File \"/Users/luismireles/opt/anaconda3/envs/K37/lib/python3.7/site-packages/spyder/widgets/dock.py\", line 52, in tab_pressed\n    if event.button() == Qt.RightButton:\nAttributeError: 'QContextMenuEvent' object has no attribute 'button'\n```\n\n## Versions\n\n* Spyder version: 4.0.0 \n* Python version: 3.7.0\n* Qt version: 5.9.6\n* PyQt5 version: 5.9.2\n* Operating System: Darwin 19.2.0\n\n### Dependencies\n\n```\ncloudpickle >=0.5.0          :  1.2.2 (OK)\npygments >=2.0               :  2.5.2 (OK)\nqtconsole >=4.6.0            :  4.6.0 (OK)\nnbconvert >=4.0              :  5.6.1 (OK)\nsphinx >=0.6.6               :  2.3.0 (OK)\npylint >=0.25                :  2.4.4 (OK)\npsutil >=0.3                 :  5.6.7 (OK)\nqtawesome >=0.5.7            :  0.6.0 (OK)\nqtpy >=1.5.0                 :  1.9.0 (OK)\npickleshare >=0.4            :  0.7.5 (OK)\nzmq >=17                     :  18.1.0 (OK)\nchardet >=2.0.0              :  3.0.4 (OK)\nnumpydoc >=0.6.0             :  0.9.1 (OK)\nspyder_kernels >=1.8.1;<2.0.0:  1.8.1 (OK)\nqdarkstyle >=2.7             :  2.7 (OK)\natomicwrites >=1.2.0         :  1.3.0 (OK)\ndiff_match_patch >=20181111  :  20181111 (OK)\nintervaltree                 :  None (OK)\nwatchdog                     :  None (OK)\nkeyring                      :  None (OK)\npexpect >=4.4.0              :  4.7.0 (OK)\npympler                      :  None (OK)\nsympy >=0.7.3                :  None (NOK)\ncython >=0.21                :  0.29.14 (OK)\nIPython >=4.0                :  7.10.2 (OK)\nmatplotlib >=2.0.0           :  3.1.1 (OK)\npandas >=0.13.1              :  0.25.3 (OK)\nnumpy >=1.7                  :  1.17.4 (OK)\nscipy >=0.17.0               :  1.3.1 (OK)\npyls >=0.31.2;<0.32.0        :  0.31.2 (OK)\napplaunchservices >=0.1.7    :  0.2.1 (OK)\nrtree >=0.8.3                :  0.8.3 (OK)\n```\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright \u00a9 Spyder Project Contributors\n# Licensed under the terms of the MIT License\n# (see spyder/__init__.py for details)\n\n\"\"\"\nDock widgets for plugins\n\"\"\"\n\nfrom qtpy.QtCore import QEvent, QObject, Qt, QSize, Signal\nfrom qtpy.QtWidgets import (QApplication, QDockWidget, QHBoxLayout,\n                            QSizePolicy, QStyle, QTabBar, QToolButton,\n                            QWidget)\n\nfrom spyder.config.gui import is_dark_interface\nfrom spyder.utils import icon_manager as ima\n\n\n# =============================================================================\n# Tab filter\n# =============================================================================\nclass TabFilter(QObject):\n    \"\"\"Filter event attached to each DockWidget QTabBar.\"\"\"\n    def __init__(self, dock_tabbar, main):\n        QObject.__init__(self)\n        self.dock_tabbar = dock_tabbar\n        self.main = main\n        self.from_index = None\n\n        # Center dockwidget tabs to differentiate them from plugin tabs.\n        # See spyder-ide/spyder#9763\n        self.dock_tabbar.setStyleSheet(\"QTabBar {alignment: center;}\")\n\n    def eventFilter(self, obj, event):\n        \"\"\"Filter mouse press events.\n\n        Events that are captured and not propagated return True. Events that\n        are not captured and are propagated return False.\n        \"\"\"\n        event_type = event.type()\n        if event_type == QEvent.MouseButtonPress:\n            self.tab_pressed(event)\n            return False\n        return False\n\n    def tab_pressed(self, event):\n        \"\"\"Method called when a tab from a QTabBar has been pressed.\"\"\"\n        self.from_index = self.dock_tabbar.tabAt(event.pos())\n        self.dock_tabbar.setCurrentIndex(self.from_index)\n\n        if event.button() == Qt.RightButton:\n            if self.from_index == -1:\n                self.show_nontab_menu(event)\n            else:\n                self.show_tab_menu(event)\n\n    def show_tab_menu(self, event):\n        \"\"\"Show the context menu assigned to tabs.\"\"\"\n        self.show_nontab_menu(event)\n\n    def show_nontab_menu(self, event):\n        \"\"\"Show the context menu assigned to nontabs section.\"\"\"\n        menu = self.main.createPopupMenu()\n        menu.exec_(self.dock_tabbar.mapToGlobal(event.pos()))\n\n\n# =============================================================================\n# Title bar\n# =============================================================================\nclass DragButton(QToolButton):\n    \"\"\"\n    Drag button for the title bar.\n\n    This button pass all its mouse events to its parent.\n    \"\"\"\n\n    def __init__(self, parent, button_size):\n        super(QToolButton, self).__init__(parent)\n        self.parent = parent\n\n        # Style\n        self.setMaximumSize(button_size)\n        self.setAutoRaise(True)\n        self.setIcon(ima.icon('drag-horizontal'))\n        if is_dark_interface():\n            self.setStyleSheet(\n                \"QToolButton {\"\n                \"border-radius: 0px;\"\n                \"border: 0px;\"\n                \"background-color: #32414B;}\")\n        else:\n            self.setStyleSheet(\"QToolButton {border: 0px;}\")\n\n    def mouseReleaseEvent(self, event):\n        self.parent.mouseReleaseEvent(event)\n\n    def mousePressEvent(self, event):\n        self.parent.mousePressEvent(event)\n\n    def mouseMoveEvent(self, event):\n        self.parent.mouseMoveEvent(event)\n\n\nclass CloseButton(QToolButton):\n    \"\"\"Close button for the title bar.\"\"\"\n\n    def __init__(self, parent, button_size):\n        super(QToolButton, self).__init__(parent)\n\n        # Style\n        self.setMaximumSize(button_size)\n        self.setAutoRaise(True)\n        self.setCursor(Qt.ArrowCursor)\n        if is_dark_interface():\n            self.setStyleSheet(\n                \"QToolButton {\"\n                \"border-radius: 0px;\"\n                \"border: 0px;\"\n                \"image: url(:/qss_icons/rc/close.png);\"\n                \"background-color: #32414B;}\"\n                \"QToolButton:hover {\"\n                \"image: url(:/qss_icons/rc/close-hover.png);}\")\n        else:\n            self.setIcon(QApplication.style().standardIcon(\n                QStyle.SP_DockWidgetCloseButton))\n\n\nclass DockTitleBar(QWidget):\n    \"\"\"\n    Custom title bar for our dock widgets.\n\n    Inspired from\n    https://stackoverflow.com/a/40894225/438386\n    \"\"\"\n\n    def __init__(self, parent):\n        super(DockTitleBar, self).__init__(parent)\n\n        icon_size = QApplication.style().standardIcon(\n            QStyle.SP_TitleBarNormalButton).actualSize(QSize(100, 100))\n        button_size = icon_size + QSize(8, 8)\n\n        left_spacer = QWidget(self)\n        left_spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)\n        if is_dark_interface():\n            left_spacer.setStyleSheet(\"background-color: #32414B\")\n\n        drag_button = DragButton(self, button_size)\n\n        right_spacer = QWidget(self)\n        right_spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)\n        if is_dark_interface():\n            right_spacer.setStyleSheet(\"background-color: #32414B\")\n\n        close_button = CloseButton(self, button_size)\n        close_button.clicked.connect(parent.sig_plugin_closed.emit)\n\n        hlayout = QHBoxLayout(self)\n        hlayout.setSpacing(0)\n        hlayout.setContentsMargins(0, 0, 0, 0)\n        hlayout.addWidget(left_spacer)\n        hlayout.addWidget(drag_button)\n        hlayout.addWidget(right_spacer)\n        hlayout.addWidget(close_button)\n\n        # To signal that dock widgets can be dragged from here\n        self.setCursor(Qt.SizeAllCursor)\n\n    def mouseReleaseEvent(self, event):\n        self.setCursor(Qt.SizeAllCursor)\n        QWidget.mouseReleaseEvent(self, event)\n\n    def mousePressEvent(self, event):\n        self.setCursor(Qt.ClosedHandCursor)\n        QWidget.mousePressEvent(self, event)\n\n    def mouseMoveEvent(self, event):\n        QWidget.mouseMoveEvent(self, event)\n        self.setCursor(Qt.SizeAllCursor)\n\n\nclass SpyderDockWidget(QDockWidget):\n    \"\"\"Subclass to override needed methods\"\"\"\n    sig_plugin_closed = Signal()\n\n    def __init__(self, title, parent):\n        super(SpyderDockWidget, self).__init__(title, parent)\n\n        # Set our custom title bar\n        self.titlebar = DockTitleBar(self)\n        self.set_title_bar()\n\n        # Needed for the installation of the event filter\n        self.title = title\n        self.main = parent\n        self.dock_tabbar = None\n\n        # To track dockwidget changes the filter is installed when dockwidget\n        # visibility changes. This installs the filter on startup and also\n        # on dockwidgets that are undocked and then docked to a new location.\n        self.visibilityChanged.connect(self.install_tab_event_filter)\n\n    def closeEvent(self, event):\n        \"\"\"\n        Reimplement Qt method to send a signal on close so that \"Panes\" main\n        window menu can be updated correctly\n        \"\"\"\n        self.sig_plugin_closed.emit()\n\n    def install_tab_event_filter(self, value):\n        \"\"\"\n        Install an event filter to capture mouse events in the tabs of a\n        QTabBar holding tabified dockwidgets.\n        \"\"\"\n        dock_tabbar = None\n        tabbars = self.main.findChildren(QTabBar)\n        for tabbar in tabbars:\n            for tab in range(tabbar.count()):\n                title = tabbar.tabText(tab)\n                if title == self.title:\n                    dock_tabbar = tabbar\n                    break\n\n        if dock_tabbar is not None:\n            self.dock_tabbar = dock_tabbar\n            # Install filter only once per QTabBar\n            if getattr(self.dock_tabbar, 'filter', None) is None:\n                self.dock_tabbar.filter = TabFilter(self.dock_tabbar,\n                                                    self.main)\n                self.dock_tabbar.installEventFilter(self.dock_tabbar.filter)\n\n    def set_title_bar(self):\n        \"\"\"Set custom title bar.\"\"\"\n        self.setTitleBarWidget(self.titlebar)\n", "path": "spyder/widgets/dock.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright \u00a9 Spyder Project Contributors\n# Licensed under the terms of the MIT License\n# (see spyder/__init__.py for details)\n\n\"\"\"\nDock widgets for plugins\n\"\"\"\n\nfrom qtpy.QtCore import QEvent, QObject, Qt, QSize, Signal\nfrom qtpy.QtWidgets import (QApplication, QDockWidget, QHBoxLayout,\n                            QSizePolicy, QStyle, QTabBar, QToolButton,\n                            QWidget)\n\nfrom spyder.config.gui import is_dark_interface\nfrom spyder.utils import icon_manager as ima\n\n\n# =============================================================================\n# Tab filter\n# =============================================================================\nclass TabFilter(QObject):\n    \"\"\"Filter event attached to each DockWidget QTabBar.\"\"\"\n    def __init__(self, dock_tabbar, main):\n        QObject.__init__(self)\n        self.dock_tabbar = dock_tabbar\n        self.main = main\n        self.from_index = None\n\n        # Center dockwidget tabs to differentiate them from plugin tabs.\n        # See spyder-ide/spyder#9763\n        self.dock_tabbar.setStyleSheet(\"QTabBar {alignment: center;}\")\n\n    def eventFilter(self, obj, event):\n        \"\"\"Filter mouse press events.\n\n        Events that are captured and not propagated return True. Events that\n        are not captured and are propagated return False.\n        \"\"\"\n        event_type = event.type()\n        if event_type == QEvent.MouseButtonPress:\n            self.tab_pressed(event)\n            return False\n        return False\n\n    def tab_pressed(self, event):\n        \"\"\"Method called when a tab from a QTabBar has been pressed.\"\"\"\n        self.from_index = self.dock_tabbar.tabAt(event.pos())\n        self.dock_tabbar.setCurrentIndex(self.from_index)\n\n        try:\n            if event.button() == Qt.RightButton:\n                if self.from_index == -1:\n                    self.show_nontab_menu(event)\n                else:\n                    self.show_tab_menu(event)\n        except AttributeError:\n            # Needed to avoid an error when generating the\n            # context menu on top of the tab.\n            # See spyder-ide/spyder#11226\n            pass\n\n    def show_tab_menu(self, event):\n        \"\"\"Show the context menu assigned to tabs.\"\"\"\n        self.show_nontab_menu(event)\n\n    def show_nontab_menu(self, event):\n        \"\"\"Show the context menu assigned to nontabs section.\"\"\"\n        menu = self.main.createPopupMenu()\n        menu.exec_(self.dock_tabbar.mapToGlobal(event.pos()))\n\n\n# =============================================================================\n# Title bar\n# =============================================================================\nclass DragButton(QToolButton):\n    \"\"\"\n    Drag button for the title bar.\n\n    This button pass all its mouse events to its parent.\n    \"\"\"\n\n    def __init__(self, parent, button_size):\n        super(QToolButton, self).__init__(parent)\n        self.parent = parent\n\n        # Style\n        self.setMaximumSize(button_size)\n        self.setAutoRaise(True)\n        self.setIcon(ima.icon('drag-horizontal'))\n        if is_dark_interface():\n            self.setStyleSheet(\n                \"QToolButton {\"\n                \"border-radius: 0px;\"\n                \"border: 0px;\"\n                \"background-color: #32414B;}\")\n        else:\n            self.setStyleSheet(\"QToolButton {border: 0px;}\")\n\n    def mouseReleaseEvent(self, event):\n        self.parent.mouseReleaseEvent(event)\n\n    def mousePressEvent(self, event):\n        self.parent.mousePressEvent(event)\n\n    def mouseMoveEvent(self, event):\n        self.parent.mouseMoveEvent(event)\n\n\nclass CloseButton(QToolButton):\n    \"\"\"Close button for the title bar.\"\"\"\n\n    def __init__(self, parent, button_size):\n        super(QToolButton, self).__init__(parent)\n\n        # Style\n        self.setMaximumSize(button_size)\n        self.setAutoRaise(True)\n        self.setCursor(Qt.ArrowCursor)\n        if is_dark_interface():\n            self.setStyleSheet(\n                \"QToolButton {\"\n                \"border-radius: 0px;\"\n                \"border: 0px;\"\n                \"image: url(:/qss_icons/rc/close.png);\"\n                \"background-color: #32414B;}\"\n                \"QToolButton:hover {\"\n                \"image: url(:/qss_icons/rc/close-hover.png);}\")\n        else:\n            self.setIcon(QApplication.style().standardIcon(\n                QStyle.SP_DockWidgetCloseButton))\n\n\nclass DockTitleBar(QWidget):\n    \"\"\"\n    Custom title bar for our dock widgets.\n\n    Inspired from\n    https://stackoverflow.com/a/40894225/438386\n    \"\"\"\n\n    def __init__(self, parent):\n        super(DockTitleBar, self).__init__(parent)\n\n        icon_size = QApplication.style().standardIcon(\n            QStyle.SP_TitleBarNormalButton).actualSize(QSize(100, 100))\n        button_size = icon_size + QSize(8, 8)\n\n        left_spacer = QWidget(self)\n        left_spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)\n        if is_dark_interface():\n            left_spacer.setStyleSheet(\"background-color: #32414B\")\n\n        drag_button = DragButton(self, button_size)\n\n        right_spacer = QWidget(self)\n        right_spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)\n        if is_dark_interface():\n            right_spacer.setStyleSheet(\"background-color: #32414B\")\n\n        close_button = CloseButton(self, button_size)\n        close_button.clicked.connect(parent.sig_plugin_closed.emit)\n\n        hlayout = QHBoxLayout(self)\n        hlayout.setSpacing(0)\n        hlayout.setContentsMargins(0, 0, 0, 0)\n        hlayout.addWidget(left_spacer)\n        hlayout.addWidget(drag_button)\n        hlayout.addWidget(right_spacer)\n        hlayout.addWidget(close_button)\n\n        # To signal that dock widgets can be dragged from here\n        self.setCursor(Qt.SizeAllCursor)\n\n    def mouseReleaseEvent(self, event):\n        self.setCursor(Qt.SizeAllCursor)\n        QWidget.mouseReleaseEvent(self, event)\n\n    def mousePressEvent(self, event):\n        self.setCursor(Qt.ClosedHandCursor)\n        QWidget.mousePressEvent(self, event)\n\n    def mouseMoveEvent(self, event):\n        QWidget.mouseMoveEvent(self, event)\n        self.setCursor(Qt.SizeAllCursor)\n\n\nclass SpyderDockWidget(QDockWidget):\n    \"\"\"Subclass to override needed methods\"\"\"\n    sig_plugin_closed = Signal()\n\n    def __init__(self, title, parent):\n        super(SpyderDockWidget, self).__init__(title, parent)\n\n        # Set our custom title bar\n        self.titlebar = DockTitleBar(self)\n        self.set_title_bar()\n\n        # Needed for the installation of the event filter\n        self.title = title\n        self.main = parent\n        self.dock_tabbar = None\n\n        # To track dockwidget changes the filter is installed when dockwidget\n        # visibility changes. This installs the filter on startup and also\n        # on dockwidgets that are undocked and then docked to a new location.\n        self.visibilityChanged.connect(self.install_tab_event_filter)\n\n    def closeEvent(self, event):\n        \"\"\"\n        Reimplement Qt method to send a signal on close so that \"Panes\" main\n        window menu can be updated correctly\n        \"\"\"\n        self.sig_plugin_closed.emit()\n\n    def install_tab_event_filter(self, value):\n        \"\"\"\n        Install an event filter to capture mouse events in the tabs of a\n        QTabBar holding tabified dockwidgets.\n        \"\"\"\n        dock_tabbar = None\n        tabbars = self.main.findChildren(QTabBar)\n        for tabbar in tabbars:\n            for tab in range(tabbar.count()):\n                title = tabbar.tabText(tab)\n                if title == self.title:\n                    dock_tabbar = tabbar\n                    break\n\n        if dock_tabbar is not None:\n            self.dock_tabbar = dock_tabbar\n            # Install filter only once per QTabBar\n            if getattr(self.dock_tabbar, 'filter', None) is None:\n                self.dock_tabbar.filter = TabFilter(self.dock_tabbar,\n                                                    self.main)\n                self.dock_tabbar.installEventFilter(self.dock_tabbar.filter)\n\n    def set_title_bar(self):\n        \"\"\"Set custom title bar.\"\"\"\n        self.setTitleBarWidget(self.titlebar)\n", "path": "spyder/widgets/dock.py"}]}