Skip to content

Commit aed4d25

Browse files
committed
added the possibility to change the centralWidget
1 parent 6242d2c commit aed4d25

5 files changed

Lines changed: 102 additions & 29 deletions

File tree

psyplot_gui/common.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import os.path as osp
88
from psyplot_gui.compat.qtcompat import (
99
QDockWidget, QRegExpValidator, QtCore, QErrorMessage, QDesktopWidget,
10-
QToolButton, QInputDialog, QIcon)
10+
QToolButton, QInputDialog, QIcon, QAction)
1111
import logging
1212

1313
if six.PY2:
@@ -39,6 +39,8 @@ class DockMixin(object):
3939
:attr:`title` attribute!
4040
"""
4141

42+
_set_central_action = _view_action = None
43+
4244
#: The position of the plugin
4345
dock_position = None
4446

@@ -83,7 +85,9 @@ def to_dock(self, main, title=None, position=None, docktype='pane', *args,
8385
self.dock = self.dock_cls(title, main)
8486
self.dock.setWidget(self)
8587
main.dockwidgets.append(self.dock)
86-
main.addDockWidget(position, self.dock, docktype, *args, **kwargs)
88+
self.create_central_widget_action(main)
89+
self.create_view_action(main, docktype)
90+
main.addDockWidget(position, self.dock, *args, **kwargs)
8791
config_page = self.config_page
8892
if config_page is not None:
8993
main.config_pages.append(config_page)
@@ -108,6 +112,27 @@ def show_status_message(self, msg):
108112
except AttributeError:
109113
pass
110114

115+
def create_central_widget_action(self, main):
116+
"""Setup the action to make this plugin the central widget"""
117+
if self._set_central_action is None:
118+
menu = main.central_widgets_menu
119+
group = main.central_widgets_actions
120+
self._set_central_action = action = QAction(self.title)
121+
action.setCheckable(True)
122+
action.triggered.connect(partial(main.set_central_widget, self))
123+
menu.addAction(action)
124+
group.addAction(action)
125+
return self._set_central_action
126+
127+
def create_view_action(self, main, docktype='pane'):
128+
if self._view_action is None:
129+
self._view_action = action = self.dock.toggleViewAction()
130+
if docktype == 'pane':
131+
main.panes_menu.addAction(action)
132+
elif docktype == 'df':
133+
main.dataframe_menu.addAction(action)
134+
return self._view_action
135+
111136

112137
class LoadFromConsoleButton(QToolButton):
113138
"""A toolbutton to load an object from the console"""

psyplot_gui/compat/qtcompat.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
QIntValidator, QErrorMessage, QInputDialog, QTabWidget,
2727
QDoubleValidator, QGraphicsScene, QGraphicsRectItem, QGraphicsView,
2828
QKeySequence, QStyleOptionViewItem, QDialog, QDialogButtonBox,
29-
QStackedWidget, QScrollArea, QTableView, QHeaderView)
29+
QStackedWidget, QScrollArea, QTableView, QHeaderView, QActionGroup)
3030
from PyQt4 import QtCore
3131
from PyQt4.QtCore import Qt
3232
from PyQt4.QtWebKit import QWebView as QWebEngineView
@@ -77,7 +77,7 @@ def setCurrentText(self, s):
7777
QGridLayout, QErrorMessage, QInputDialog, QTabWidget,
7878
QGraphicsScene, QGraphicsRectItem, QGraphicsView, QStyleOptionViewItem,
7979
QDialog, QDialogButtonBox, QStackedWidget, QScrollArea,
80-
QTableView, QHeaderView)
80+
QTableView, QHeaderView, QActionGroup)
8181
from PyQt5.QtGui import (
8282
QIcon, QKeyEvent, QStandardItem, QStandardItemModel, QTextCursor,
8383
QValidator, QRegExpValidator, QIntValidator, QDoubleValidator,

psyplot_gui/console.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import psyplot
2525
import psyplot_gui
2626
from psyplot_gui import rcParams
27+
from psyplot_gui.common import DockMixin
2728
import psyplot.project as psy
2829
from psyplot.docstring import dedents
2930

@@ -61,11 +62,15 @@ def keyPressEvent(self, event):
6162
QTextEdit.keyPressEvent(self, event)
6263

6364

64-
class ConsoleWidget(QtInProcessRichJupyterWidget):
65+
class ConsoleWidget(QtInProcessRichJupyterWidget, DockMixin):
6566
"""A console widget to access an inprocess shell"""
6667

6768
custom_control = IPythonControl
6869

70+
dock_position = Qt.RightDockWidgetArea
71+
72+
title = 'Console'
73+
6974
rc = rcParams.find_and_replace(
7075
'console.', pattern_base='console\.')
7176

psyplot_gui/main.py

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from psyplot_gui.compat.qtcompat import (
3232
QMainWindow, QApplication, Qt, QMenu, QAction, QDesktopWidget, QLabel,
3333
QFileDialog, QKeySequence, QtCore, with_qt5, QMessageBox, QIcon,
34-
QInputDialog)
34+
QInputDialog, QActionGroup)
3535
from psyplot_gui.content_widget import (
3636
ProjectContentWidget, DatasetTree, FiguresTree)
3737
from psyplot_gui.plot_creator import PlotCreator
@@ -108,6 +108,10 @@ class MainWindow(QMainWindow):
108108
#: The current keyboard shortcuts
109109
current_shortcuts = []
110110

111+
#: The key for the central widget for the main window in the
112+
#: :attr:`plugins` dictionary
113+
central_widget_key = 'console'
114+
111115
@property
112116
def logger(self):
113117
"""The logger of this instance"""
@@ -368,6 +372,7 @@ def __init__(self, show=True):
368372

369373
# load plugin widgets
370374
self.plugins = plugins = OrderedDict([
375+
('console', self.console),
371376
('project_content', self.project_content),
372377
('ds_tree', self.ds_tree),
373378
('figures_tree', self.figures_tree),
@@ -381,11 +386,13 @@ def __init__(self, show=True):
381386
self.add_mp_to_menu()
382387
psy.Project.oncpchange.connect(self.eventually_add_mp_to_menu)
383388
self.windows_menu.addSeparator()
389+
384390
self.window_layouts_menu = QMenu('Window layouts', self)
385391
self.restore_layout_action = QAction('Restore default layout', self)
386392
self.restore_layout_action.triggered.connect(self.setup_default_layout)
387393
self.window_layouts_menu.addAction(self.restore_layout_action)
388394
self.windows_menu.addMenu(self.window_layouts_menu)
395+
389396
self.panes_menu = QMenu('Panes', self)
390397
self.windows_menu.addMenu(self.panes_menu)
391398

@@ -396,6 +403,11 @@ def __init__(self, show=True):
396403
self.dataframe_menu.addSeparator()
397404
self.windows_menu.addMenu(self.dataframe_menu)
398405

406+
self.central_widgets_menu = menu = QMenu('Central widget', self)
407+
self.windows_menu.addMenu(menu)
408+
self.central_widgets_actions = group = QActionGroup(self)
409+
group.setExclusive(True)
410+
399411
# ---------------------------------------------------------------------
400412
# -------------------------- connections ------------------------------
401413
# ---------------------------------------------------------------------
@@ -461,15 +473,19 @@ def __init__(self, show=True):
461473

462474
# save the default widths after they have been shown
463475
for w in self.plugins.values():
464-
self.default_widths[w] = w.dock.size().width()
476+
if w.dock is not None:
477+
self.default_widths[w] = w.dock.size().width()
465478

466479
# hide plugin widgets that should be hidden at startup. Although this
467480
# has been executed by :meth:`setup_default_layout`, we have to execute
468481
# it again after the call of showMaximized
469-
for w in self.plugins.values():
470-
w.to_dock(self)
471-
if w.hidden:
472-
w.hide_plugin()
482+
for name, w in self.plugins.items():
483+
if name != self.central_widget_key:
484+
w.to_dock(self)
485+
if w.hidden:
486+
w.hide_plugin()
487+
else:
488+
w.create_central_widget_action(self).setChecked(True)
473489

474490
self._is_open = True
475491

@@ -514,17 +530,19 @@ def setup_default_layout(self):
514530

515531
modify_widths = bool(self.default_widths)
516532
for w in map(self.plugins.__getitem__, self.default_plugins):
517-
w.show_plugin()
533+
if w.dock is not None:
534+
w.show_plugin()
518535

519-
if modify_widths and with_qt5:
520-
self.resizeDocks([w.dock], [self.default_widths[w]],
521-
Qt.Horizontal)
536+
if modify_widths and with_qt5:
537+
self.resizeDocks([w.dock], [self.default_widths[w]],
538+
Qt.Horizontal)
522539

523540
# hide plugin widgets that should be hidden at startup
524-
for w in self.plugins.values():
525-
w.to_dock(self)
526-
if w.hidden:
527-
w.hide_plugin()
541+
for name, w in self.plugins.items():
542+
if name != self.central_widget_key:
543+
w.to_dock(self)
544+
if w.hidden:
545+
w.hide_plugin()
528546

529547
action2shortcut = defaultdict(list)
530548
for s, a in self.default_shortcuts:
@@ -533,6 +551,34 @@ def setup_default_layout(self):
533551
for a, s in action2shortcut.items():
534552
self.register_shortcut(a, s)
535553

554+
def set_central_widget(self, name):
555+
"""Set the central widget
556+
557+
Parameters
558+
----------
559+
name: str or QWidget
560+
The key or the plugin widget in the :attr:`plugins` dictionary"""
561+
current = self.centralWidget()
562+
if isinstance(name, six.string_types):
563+
new = self.plugins[name]
564+
else:
565+
new = name
566+
name = next(key for key, val in self.plugins.items() if val is new)
567+
if new is not current:
568+
self.removeDockWidget(new.dock)
569+
new.dock.close()
570+
self.panes_menu.removeAction(new._view_action)
571+
self.dataframe_menu.removeAction(new._view_action)
572+
new.dock = new._view_action = None
573+
self.central_widget_key = name
574+
current.to_dock(self)
575+
self.setCentralWidget(new)
576+
new._set_central_action.setChecked(True)
577+
current.show_plugin()
578+
current.to_dock(self)
579+
if current.hidden:
580+
current.hide_plugin()
581+
536582
def _save_project(self, p, new_fname=False, *args, **kwargs):
537583
if new_fname or 'project_file' not in p.attrs:
538584
fname = QFileDialog.getSaveFileName(
@@ -734,16 +780,6 @@ def eventually_add_mp_to_menu(self, p):
734780
if p.num not in self.project_actions:
735781
self.add_mp_to_menu()
736782

737-
def addDockWidget(self, area, dockwidget, docktype=None, *args, **kwargs):
738-
"""Reimplemented to add widgets to the windows menu"""
739-
ret = super(MainWindow, self).addDockWidget(area, dockwidget, *args,
740-
**kwargs)
741-
if docktype == 'pane':
742-
self.panes_menu.addAction(dockwidget.toggleViewAction())
743-
elif docktype == 'df':
744-
self.dataframe_menu.addAction(dockwidget.toggleViewAction())
745-
return ret
746-
747783
def start_open_files_server(self):
748784
"""This method listens to the open_files_port and opens the plot
749785
creator for new files

tests/test_main.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ def test_plugin(self):
2525
w.show_plugin()
2626
self.assertTrue(a.isChecked())
2727

28+
def test_central_widget(self):
29+
"""Test changing the central widget"""
30+
self.window.set_central_widget('help_explorer')
31+
self.assertIs(self.window.centralWidget(), self.window.help_explorer)
32+
self.window.set_central_widget(self.window.figures_tree)
33+
self.assertIs(self.window.centralWidget(), self.window.figures_tree)
34+
2835

2936
if __name__ == "__main__":
3037
unittest.main()

0 commit comments

Comments
 (0)