예제 #1
0
파일: main.py 프로젝트: Chilipp/psyplot-gui
 def register_shortcut(self,
                       action,
                       shortcut,
                       context=Qt.ApplicationShortcut):
     """Register an action for a shortcut"""
     shortcuts = psy.safe_list(shortcut)
     for j, shortcut in enumerate(shortcuts):
         found = False
         for i, (s, a) in enumerate(self.current_shortcuts):
             if s == shortcut:
                 new_shortcuts = [
                     sc for sc in self.current_shortcuts[i][1].shortcuts()
                     if sc != s
                 ]
                 a.setShortcut(QKeySequence())
                 if new_shortcuts:
                     a.setShortcuts(new_shortcuts)
                 self.current_shortcuts[i][1] = action
                 found = True
                 break
         if not found:
             self.default_shortcuts.append([shortcut, action])
             self.current_shortcuts.append([shortcut, action])
     action.setShortcuts(shortcuts)
     action.setShortcutContext(context)
예제 #2
0
    def setup_shortcuts(self, main):
        """Setup the shortcuts when switched to the straditizer layout

        Parameters
        ----------
        main: psyplot_gui.main.MainWindow
            The psyplot mainwindow"""
        main.register_shortcut(self.save_straditizer_action, QKeySequence.Save)
        main.register_shortcut(self.save_straditizer_as_action,
                               QKeySequence.SaveAs)
        main.register_shortcut(self.close_straditizer_action,
                               QKeySequence.Close)
        main.register_shortcut(
            self.close_all_straditizer_action,
            QKeySequence('Ctrl+Shift+W', QKeySequence.NativeText))

        main.register_shortcut(self.export_final_action,
                               QKeySequence('Ctrl+E', QKeySequence.NativeText))
        main.register_shortcut(
            self.export_full_action,
            QKeySequence('Ctrl+Shift+E', QKeySequence.NativeText))
        main.register_shortcut(self.load_stradi_action,
                               [QKeySequence.Open, QKeySequence.New])
예제 #3
0
파일: main.py 프로젝트: Chilipp/psyplot-gui
    def __init__(self, show=True):
        """
        Parameters
        ----------
        show: bool
            If True, the created mainwindow is show
        """
        if sys.stdout is None:
            sys.stdout = StreamToLogger(self.logger)
        if sys.stderr is None:
            sys.stderr = StreamToLogger(self.logger)
        super(MainWindow, self).__init__()
        self.setWindowIcon(QIcon(get_icon('logo.png')))

        #: list of figures from the psyplot backend
        self.figures = []
        self.error_msg = PyErrorMessage(self)
        self.setDockOptions(QMainWindow.AnimatedDocks
                            | QMainWindow.AllowNestedDocks
                            | QMainWindow.AllowTabbedDocks)
        #: Inprocess console
        self.console = ConsoleWidget(self)
        self.project_actions = {}

        self.config_pages = []

        self.open_file_options = OrderedDict([
            ('new psyplot plot from dataset', self.open_external_files),
            ('new psyplot project', partial(self.open_external_files, [])),
        ])

        # ---------------------------------------------------------------------
        # ----------------------------- Menus ---------------------------------
        # ---------------------------------------------------------------------

        # ######################## File menu ##################################

        # --------------------------- New plot --------------------------------

        self.file_menu = QMenu('File', parent=self)
        self.new_plot_action = QAction('New plot', self)
        self.new_plot_action.setStatusTip(
            'Use an existing dataset (or open a new one) to create one or '
            'more plots')
        self.register_shortcut(self.new_plot_action, QKeySequence.New)
        self.new_plot_action.triggered.connect(lambda: self.new_plots(True))
        self.file_menu.addAction(self.new_plot_action)

        # --------------------------- Open project ----------------------------

        self.open_project_menu = QMenu('Open project', self)
        self.file_menu.addMenu(self.open_project_menu)

        self.open_mp_action = QAction('New main project', self)
        self.register_shortcut(self.open_mp_action, QKeySequence.Open)
        self.open_mp_action.setStatusTip('Open a new main project')
        self.open_mp_action.triggered.connect(self.open_mp)
        self.open_project_menu.addAction(self.open_mp_action)

        self.open_sp_action = QAction('Add to current', self)

        self.register_shortcut(
            self.open_sp_action,
            QKeySequence('Ctrl+Shift+O', QKeySequence.NativeText))
        self.open_sp_action.setStatusTip(
            'Load a project as a sub project and add it to the current main '
            'project')
        self.open_sp_action.triggered.connect(self.open_sp)
        self.open_project_menu.addAction(self.open_sp_action)

        # ---------------------- load preset menu -----------------------------

        self.load_preset_menu = QMenu('Load preset', parent=self)
        self.file_menu.addMenu(self.load_preset_menu)

        self.load_sp_preset_action = self.load_preset_menu.addAction(
            "For selection", self.load_sp_preset)
        self.load_sp_preset_action.setStatusTip(
            "Load a preset for the selected project")

        self.load_mp_preset_action = self.load_preset_menu.addAction(
            "For full project", self.load_mp_preset)
        self.load_sp_preset_action.setStatusTip(
            "Load a preset for the full project")

        # ----------------------- Save project --------------------------------

        self.save_project_menu = QMenu('Save', parent=self)
        self.file_menu.addMenu(self.save_project_menu)

        self.save_mp_action = QAction('Full psyplot project', self)
        self.save_mp_action.setStatusTip(
            'Save the entire project into a pickle file')
        self.register_shortcut(self.save_mp_action, QKeySequence.Save)
        self.save_mp_action.triggered.connect(self.save_mp)
        self.save_project_menu.addAction(self.save_mp_action)

        self.save_sp_action = QAction('Selected psyplot project', self)
        self.save_sp_action.setStatusTip(
            'Save the selected sub project into a pickle file')
        self.save_sp_action.triggered.connect(self.save_sp)
        self.save_project_menu.addAction(self.save_sp_action)

        # ------------------------ Save project as ----------------------------

        self.save_project_as_menu = QMenu('Save as', parent=self)
        self.file_menu.addMenu(self.save_project_as_menu)

        self.save_mp_as_action = QAction('Full psyplot project', self)
        self.save_mp_as_action.setStatusTip(
            'Save the entire project into a pickle file')
        self.register_shortcut(self.save_mp_as_action, QKeySequence.SaveAs)
        self.save_mp_as_action.triggered.connect(
            partial(self.save_mp, new_fname=True))
        self.save_project_as_menu.addAction(self.save_mp_as_action)

        self.save_sp_as_action = QAction('Selected psyplot project', self)
        self.save_sp_as_action.setStatusTip(
            'Save the selected sub project into a pickle file')
        self.save_sp_as_action.triggered.connect(
            partial(self.save_sp, new_fname=True))
        self.save_project_as_menu.addAction(self.save_sp_as_action)

        # ------------------------ Save preset --------------------------------

        self.save_preset_menu = QMenu('Save preset', parent=self)
        self.file_menu.addMenu(self.save_preset_menu)

        self.save_sp_preset_action = self.save_preset_menu.addAction(
            "Selection", self.save_sp_preset)
        self.save_sp_preset_action.setStatusTip(
            "Save the formatoptions of the selected project as a preset")

        self.save_mp_preset_action = self.save_preset_menu.addAction(
            "Full project", self.save_mp_preset)
        self.save_sp_preset_action.setStatusTip(
            "Save the formatoptions of the full project as a preset")

        # -------------------------- Pack project -----------------------------

        self.pack_project_menu = QMenu('Zip project files', parent=self)
        self.file_menu.addMenu(self.pack_project_menu)

        self.pack_mp_action = QAction('Full psyplot project', self)
        self.pack_mp_action.setStatusTip(
            'Pack all the data of the main project into one folder')
        self.pack_mp_action.triggered.connect(partial(self.save_mp, pack=True))
        self.pack_project_menu.addAction(self.pack_mp_action)

        self.pack_sp_action = QAction('Selected psyplot project', self)
        self.pack_sp_action.setStatusTip(
            'Pack all the data of the current sub project into one folder')
        self.pack_sp_action.triggered.connect(partial(self.save_sp, pack=True))
        self.pack_project_menu.addAction(self.pack_sp_action)

        # ------------------------ Export figures -----------------------------

        self.export_project_menu = QMenu('Export figures', parent=self)
        self.file_menu.addMenu(self.export_project_menu)

        self.export_mp_action = QAction('Full psyplot project', self)
        self.export_mp_action.setStatusTip(
            'Pack all the data of the main project into one folder')
        self.export_mp_action.triggered.connect(self.export_mp)
        self.register_shortcut(self.export_mp_action,
                               QKeySequence('Ctrl+E', QKeySequence.NativeText))
        self.export_project_menu.addAction(self.export_mp_action)

        self.export_sp_action = QAction('Selected psyplot project', self)
        self.export_sp_action.setStatusTip(
            'Pack all the data of the current sub project into one folder')
        self.register_shortcut(
            self.export_sp_action,
            QKeySequence('Ctrl+Shift+E', QKeySequence.NativeText))
        self.export_sp_action.triggered.connect(self.export_sp)
        self.export_project_menu.addAction(self.export_sp_action)

        # ------------------------ Close project ------------------------------

        self.file_menu.addSeparator()

        self.close_project_menu = QMenu('Close project', parent=self)
        self.file_menu.addMenu(self.close_project_menu)

        self.close_mp_action = QAction('Full psyplot project', self)
        self.register_shortcut(
            self.close_mp_action,
            QKeySequence('Ctrl+Shift+W', QKeySequence.NativeText))
        self.close_mp_action.setStatusTip(
            'Close the main project and delete all data and plots out of '
            'memory')
        self.close_mp_action.triggered.connect(
            lambda: psy.close(psy.gcp(True).num))
        self.close_project_menu.addAction(self.close_mp_action)

        self.close_sp_action = QAction('Selected psyplot project', self)
        self.close_sp_action.setStatusTip(
            'Close the selected arrays project and delete all data and plots '
            'out of memory')
        self.register_shortcut(self.close_sp_action, QKeySequence.Close)
        self.close_sp_action.triggered.connect(
            lambda: psy.gcp().close(True, True))
        self.close_project_menu.addAction(self.close_sp_action)

        # ----------------------------- Quit ----------------------------------

        if sys.platform != 'darwin':  # mac os makes this anyway
            self.quit_action = QAction('Quit', self)
            self.quit_action.triggered.connect(self.close)
            self.quit_action.triggered.connect(
                QtCore.QCoreApplication.instance().quit)
            self.register_shortcut(self.quit_action, QKeySequence.Quit)
            self.file_menu.addAction(self.quit_action)

        self.menuBar().addMenu(self.file_menu)

        # ######################## Console menu ###############################

        self.console_menu = QMenu('Console', self)
        self.console_menu.addActions(self.console.actions())
        self.menuBar().addMenu(self.console_menu)

        # ######################## Windows menu ###############################

        self.windows_menu = QMenu('Windows', self)
        self.menuBar().addMenu(self.windows_menu)

        # ############################ Help menu ##############################

        self.help_menu = QMenu('Help', parent=self)
        self.menuBar().addMenu(self.help_menu)

        # -------------------------- Preferences ------------------------------

        self.help_action = QAction('Preferences', self)
        self.help_action.triggered.connect(lambda: self.edit_preferences(True))
        self.register_shortcut(self.help_action, QKeySequence.Preferences)
        self.help_menu.addAction(self.help_action)

        # ---------------------------- About ----------------------------------

        self.about_action = QAction('About', self)
        self.about_action.triggered.connect(self.about)
        self.help_menu.addAction(self.about_action)

        # ---------------------------- Dependencies ---------------------------

        self.dependencies_action = QAction('Dependencies', self)
        self.dependencies_action.triggered.connect(
            lambda: self.show_dependencies(True))
        self.help_menu.addAction(self.dependencies_action)

        self.dockwidgets = []

        # ---------------------------------------------------------------------
        # -------------------------- Dock windows -----------------------------
        # ---------------------------------------------------------------------
        #: tab widget displaying the arrays in current main and sub project
        #: tree widget displaying the open datasets
        self.project_content = ProjectContentWidget(parent=self)
        self.ds_tree = DatasetTree(parent=self)
        #: tree widget displaying the open figures
        self.figures_tree = FiguresTree(parent=self)
        #: help explorer
        self.help_explorer = help_explorer = HelpExplorer(parent=self)
        if 'HTML help' in help_explorer.viewers and help_explorer.viewers[
                'HTML help'].sphinx_thread is not None:
            help_explorer.viewers[
                'HTML help'].sphinx_thread.html_ready.connect(
                    self.focus_on_console)
        #: the DataFrameEditor widgets
        self.dataframeeditors = []
        #: general formatoptions widget
        self.fmt_widget = FormatoptionWidget(parent=self,
                                             help_explorer=help_explorer,
                                             console=self.console)

        # load plugin widgets
        self.plugins = plugins = OrderedDict([
            ('console', self.console),
            ('project_content', self.project_content),
            ('ds_tree', self.ds_tree),
            ('figures_tree', self.figures_tree),
            ('help_explorer', self.help_explorer),
            ('fmt_widget', self.fmt_widget),
        ])
        self.default_plugins = list(plugins)
        for plugin_name, w_class in six.iteritems(rcParams.load_plugins()):
            plugins[plugin_name] = w_class(parent=self)

        self.add_mp_to_menu()
        psy.Project.oncpchange.connect(self.eventually_add_mp_to_menu)
        self.windows_menu.addSeparator()

        self.window_layouts_menu = QMenu('Window layouts', self)
        self.restore_layout_action = QAction('Restore default layout', self)
        self.restore_layout_action.triggered.connect(self.setup_default_layout)
        self.window_layouts_menu.addAction(self.restore_layout_action)
        self.windows_menu.addMenu(self.window_layouts_menu)

        self.panes_menu = QMenu('Panes', self)
        self.windows_menu.addMenu(self.panes_menu)

        self.dataframe_menu = QMenu('DataFrame editors', self)
        self.dataframe_menu.addAction(
            'New Editor',
            partial(self.new_data_frame_editor, None, 'DataFrame Editor'))
        self.dataframe_menu.addSeparator()
        self.windows_menu.addMenu(self.dataframe_menu)

        self.central_widgets_menu = menu = QMenu('Central widget', self)
        self.windows_menu.addMenu(menu)
        self.central_widgets_actions = group = QActionGroup(self)
        group.setExclusive(True)

        # ---------------------------------------------------------------------
        # -------------------------- connections ------------------------------
        # ---------------------------------------------------------------------

        self.console.help_explorer = help_explorer
        psyp.default_print_func = partial(help_explorer.show_rst,
                                          oname='formatoption_docs')
        psy.PlotterInterface._print_func = psyp.default_print_func
        self.setCentralWidget(self.console)

        # make sure that the plots are shown between the project content and
        # the help explorer widget
        self.setCorner(Qt.TopLeftCorner, Qt.LeftDockWidgetArea)
        self.setCorner(Qt.TopRightCorner, Qt.RightDockWidgetArea)

        # make sure that the formatoption widgets are shown between the
        # project content and the help explorer widget
        self.setCorner(Qt.BottomLeftCorner, Qt.LeftDockWidgetArea)
        self.setCorner(Qt.BottomRightCorner, Qt.RightDockWidgetArea)

        # ---------------------------------------------------------------------
        # ------------------------------ closure ------------------------------
        # ---------------------------------------------------------------------
        if show:
            self.help_explorer.show_intro(self.console.intro_msg)

        # ---------------------------------------------------------------------
        # ------------------------- open_files_server -------------------------
        # ---------------------------------------------------------------------
        self.callbacks = {
            'new_plot': self.open_external.emit,
            'change_cwd': self._change_cwd,
            'run_script': self.console.run_script.emit,
            'command': self.console.run_command.emit,
        }

        # Server to open external files on a single instance
        self.open_files_server = socket.socket(socket.AF_INET,
                                               socket.SOCK_STREAM,
                                               socket.IPPROTO_TCP)

        if rcParams['main.listen_to_port']:
            self._file_thread = Thread(target=self.start_open_files_server)
            self._file_thread.setDaemon(True)
            self._file_thread.start()

            self.open_external.connect(self._open_external_files)

        self.config_pages.extend([GuiRcParamsWidget, PsyRcParamsWidget])

        # display the statusBar
        statusbar = self.statusBar()
        self.figures_label = QLabel()
        statusbar.addWidget(self.figures_label)
        self.plugin_label = QLabel()
        statusbar.addWidget(self.plugin_label)

        self.default_widths = {}

        self.setup_default_layout()

        if show:
            self.showMaximized()

        # save the default widths after they have been shown
        for w in self.plugins.values():
            if w.dock is not None:
                self.default_widths[w] = w.dock.size().width()

        # hide plugin widgets that should be hidden at startup. Although this
        # has been executed by :meth:`setup_default_layout`, we have to execute
        # it again after the call of showMaximized
        for name, w in self.plugins.items():
            if name != self.central_widget_key:
                w.to_dock(self)
                if w.hidden:
                    w.hide_plugin()
            else:
                w.create_central_widget_action(self).setChecked(True)

        self._is_open = True
예제 #4
0
    def __init__(self, main, *args, **kwargs):
        """
        Parameters
        ----------
        help_explorer: psyplot_gui.help_explorer.HelpExplorer or None
            A widget that can be used to show the documentation of an object
        ``*args,**kwargs``
            Any other keyword argument for the
            :class:`qtconsole.rich_jupyter_widget.RichJupyterWidget`
        """
        self._closed = False
        kernel_manager = QtInProcessKernelManager()
        # on windows, sys.stdout may be None when using pythonw.exe. Therefore
        # we just us a StringIO for security
        orig_stdout = sys.stdout
        if sys.stdout is None:
            sys.stdout = StreamToLogger(logger)
        orig_stderr = sys.stderr
        if sys.stderr is None:
            sys.stderr = StreamToLogger(logger)
        kernel_manager.start_kernel(show_banner=False)
        if ipykernel.__version__ < '5.1.1':
            # monkey patch to fix
            # https://github.com/ipython/ipykernel/issues/370
            def _abort_queues(kernel):
                pass
            kernel_manager.kernel._abort_queues = _abort_queues
        sys.stdout = orig_stdout
        sys.stderr = orig_stderr
        kernel = kernel_manager.kernel
        kernel.gui = 'qt4' if not with_qt5 else 'qt'

        kernel_client = kernel_manager.client()
        if rcParams['console.start_channels']:
            kernel_client.start_channels()

        self.help_explorer = kwargs.pop('help_explorer', None)

        super(ConsoleWidget, self).__init__(*args, parent=main, **kwargs)

        self.intro_msg = dedents("""
        psyplot version: %s

        gui version: %s

        The console provides you the full access to the current project and
        plots.
        To make your life easier, the following modules have been imported

            - %s

        Furthermore, each time you change the selection or the content in the
        plot objects viewer, the `sp` (the selection) and `mp` (all arrays)
        variables in the console are adjusted. To disable this behaviour, set::

            >>> import psyplot_gui
            >>> psyplot_gui.rcParams['console.auto_set_mp'] = False
            >>> psyplot_gui.rcParams['console.auto_set_sp'] = False

        To inspect and object in the console and display it's documentation in
        the help explorer, type 'Ctrl + I' or a '?' after the object""") % (
                psyplot.__version__, psyplot_gui.__version__,
                '\n    - '.join('%s as %s' % t for t in modules2import))

        self.kernel_manager = kernel_manager
        self.kernel_client = kernel_client

        self.run_command_in_shell(
            '\n'.join('import %s as %s' % t for t in modules2import))
        self.exit_requested.connect(self._close_mainwindow)
        self.exit_requested.connect(QtCore.QCoreApplication.instance().quit)

        # we overwrite the short cut here because the 'Ctrl+S' shortcut is
        # reserved for mainwindows save action
        try:
            main.register_shortcut(
                self.export_action, QKeySequence(
                    'Ctrl+Alt+S', QKeySequence.NativeText))
        except AttributeError:
            pass

        psy.Project.oncpchange.connect(self.update_mp)
        psy.Project.oncpchange.connect(self.update_sp)

        self.run_script.connect(self._run_script_in_shell)
        self.run_command.connect(self._run_command_in_shell)

        # HACK: we set the IOloop for the InProcessKernel here manually without
        # starting it (not necessary because QApplication has a blocking
        # IOLoop). However, we need this because the ZMQInteractiveShell wants
        # to call
        #     loop = self.kernel.io_loop
        #     loop.call_later(0.1, loop.stop)``
        zmq_ioloop.install()
        self.kernel_manager.kernel.io_loop = ioloop.IOLoop.current()