示例#1
0
    def create_error_dlg(self,
                         message,
                         info=None,
                         detail=None,
                         ignore_buttons=True):
        dlg = QMessageBox()
        dlg.setText(message)

        if info:
            dlg.setInformativeText(info)

        if detail:
            dlg.setDetailedText(detail)

        dlg.setWindowTitle(self.name + self.tr(" - Error"))
        dlg.setIcon(QMessageBox.Critical)

        if ignore_buttons:
            dlg.setStandardButtons(QMessageBox.Abort | QMessageBox.Ignore)
            dlg.btn_ignoreall = dlg.addButton(self.tr("Ignore A&ll"),
                                              QMessageBox.ActionRole)
            dlg.setDefaultButton(QMessageBox.Ignore)
        else:
            dlg.setDefaultButton(QMessageBox.NoButton)

        return dlg
示例#2
0
def raise_to_operator(exc, execute=True):
    """
    Utility function to show a Python Exception in QMessageBox

    The type and representation of the Exception are shown in a pop-up
    QMessageBox. The entire traceback is available via a drop-down detailed
    text box in the QMessageBox

    Parameters
    ----------
    exc: Exception

    execute: bool, optional
        Whether to execute the QMessageBox
    """
    # Assemble QMessageBox with Exception details
    err_msg = QMessageBox()
    err_msg.setText(f'{exc.__class__.__name__}: {exc}')
    err_msg.setWindowTitle(type(exc).__name__)
    err_msg.setIcon(QMessageBox.Critical)
    # Format traceback as detailed text
    with io.StringIO() as handle:
        traceback.print_tb(exc.__traceback__, file=handle)
        handle.seek(0)
        err_msg.setDetailedText(handle.read())
    if execute:
        # Execute
        err_msg.exec_()
    return err_msg
示例#3
0
    def delete_patches(self):
        if self.mainwin.selection.hasSelection():
            rows = sorted(
                [r.row() for r in self.mainwin.selection.selectedRows()])
            patches = tuple(self.patches.get_row(r).displayname for r in rows)
            msg_box = QMessageBox()

            if len(rows) == 1:
                msg_box.setText(
                    self.tr("Delete patch '{}'?").format(patches[0]))
            else:
                msg_box.setText(
                    self.tr("Delete {} patches?").format(len(rows)))
                msg_box.setDetailedText('\n'.join(patches))

            msg_box.setInformativeText(
                self.tr("Patches can only be restored by re-importing them."))
            msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
            msg_box.setDefaultButton(QMessageBox.Cancel)
            msg_box.setIcon(QMessageBox.Warning)

            if msg_box.exec_() == QMessageBox.Yes:
                with self.session.begin():
                    for n, row in enumerate(rows):
                        self.patches.removeRows(row - n)
示例#4
0
    def load_files(self):
        dial = MultipleLoadDialog(self.load_register,
                                  self.settings.get_path_history())
        dial.setDirectory(
            self.settings.get("io.multiple_open_directory", str(Path.home())))
        dial.selectNameFilter(
            self.settings.get("io.multiple_open_filter",
                              next(iter(self.load_register.keys()))))
        self.error_list = []
        if dial.exec_():
            result = dial.get_result()
            load_dir = os.path.dirname(result.load_location[0])
            self.settings.set("io.multiple_open_directory", load_dir)
            self.settings.add_path_history(load_dir)
            self.settings.set("io.multiple_open_filter",
                              result.selected_filter)

            dial_fun = ExecuteFunctionDialog(
                self.execute_load_files, [result],
                exception_hook=load_data_exception_hook)
            dial_fun.exec_()
            if self.error_list:
                errors_message = QMessageBox()
                errors_message.setText("There are errors during load files")
                errors_message.setInformativeText(
                    "During load files cannot found some of files on disc")
                errors_message.setStandardButtons(QMessageBox.Ok)
                text = "\n".join("File: " + x[0] + "\n" + str(x[1])
                                 for x in self.error_list)
                errors_message.setDetailedText(text)
                errors_message.exec_()
示例#5
0
 def show_failure_msg(self, msg, info, details):
     self.viz_tab.set_message(msg)
     msgBox = QMessageBox()
     msgBox.setIcon(QMessageBox.Critical)
     msgBox.setText(msg)
     msgBox.setInformativeText(info)
     msgBox.setDetailedText(details)
     msgBox.exec()
示例#6
0
 def _plotting_error(self, msg, trace):
     msg_box = QMessageBox(self)
     msg_box.setIcon(QMessageBox.Critical)
     msg_box.setText('Plotting Error')
     msg_box.setInformativeText(msg)
     msg_box.setDetailedText(trace)
     msg_box.setStandardButtons(QMessageBox.Close)
     msg_box.exec_()
示例#7
0
    def __init__(
        self,
        config_folder: Union[str, Path, None] = None,
        title="PartSeg",
        settings: Optional[BaseSettings] = None,
        load_dict: Optional[Register] = None,
        signal_fun=None,
    ):
        if settings is None:
            if config_folder is None:
                raise ValueError("wrong config folder")
            if not os.path.exists(config_folder):
                import_config()
            settings: BaseSettings = self.get_setting_class()(config_folder)
            errors = settings.load()
            if errors:
                errors_message = QMessageBox()
                errors_message.setText("There are errors during start")
                errors_message.setInformativeText(
                    "During load saved state some of data could not be load properly\n"
                    "The files has prepared backup copies in "
                    " state directory (Help > State directory)")
                errors_message.setStandardButtons(QMessageBox.Ok)
                text = "\n".join("File: " + x[0] + "\n" + str(x[1])
                                 for x in errors)
                errors_message.setDetailedText(text)
                errors_message.exec_()

        super().__init__()
        if signal_fun is not None:
            self.show_signal.connect(signal_fun)
        self.settings = settings
        self._load_dict = load_dict
        self.viewer_list: List[Viewer] = []
        self.files_num = 1
        self.setAcceptDrops(True)
        self.setWindowTitle(title)
        self.title_base = title
        app = QApplication.instance()
        if app is not None:
            app.setStyleSheet(settings.style_sheet)
        self.settings.theme_changed.connect(self.change_theme)
        self.channel_info = ""
        self.multiple_files = None
        self.settings.request_load_files.connect(self.read_drop)
        self.recent_file_menu = QMenu("Open recent")
        self._refresh_recent()
        self.settings.connect_(FILE_HISTORY, self._refresh_recent)
        self.settings.napari_settings.appearance.events.theme.connect(
            self.change_theme)
        self.settings.set_parent(self)
        self.console = None
        self.console_dock = QDockWidget("console", self)
        self.console_dock.setAllowedAreas(Qt.LeftDockWidgetArea
                                          | Qt.BottomDockWidgetArea)
        # self.console_dock.setWidget(self.console)
        self.console_dock.hide()
        self.addDockWidget(Qt.BottomDockWidgetArea, self.console_dock)
示例#8
0
 def display_message_box(self, title, message, details):
     msg = QMessageBox(self)
     msg.setIcon(QMessageBox.Warning)
     msg.setText(message)
     msg.setWindowTitle(title)
     msg.setDetailedText(details)
     msg.setStandardButtons(QMessageBox.Ok)
     msg.setDefaultButton(QMessageBox.Ok)
     msg.setEscapeButton(QMessageBox.Ok)
     msg.exec_()
示例#9
0
 def display_message_box(self, title, message, details):
     msg = QMessageBox(self)
     msg.setIcon(QMessageBox.Warning)
     msg.setText(message)
     msg.setWindowTitle(title)
     msg.setDetailedText(details)
     msg.setStandardButtons(QMessageBox.Ok)
     msg.setDefaultButton(QMessageBox.Ok)
     msg.setEscapeButton(QMessageBox.Ok)
     msg.exec_()
示例#10
0
    def errorPopup(self, title, msg, details=None):
        """
        Display an error popup to inform the user.

        Args:
            title (str): popup title
            msg (str): popup message
            details (str): facultative detailed text
        """
        w = QMessageBox(QMessageBox.Critical, title, msg, QMessageBox.Ok, self)
        if details:
            w.setDetailedText(details)
        w.exec()
示例#11
0
    def _check_rows(self, rows, only_one=False):
        """Checks how many items are in ``rows`` and alerts user if not right.

        Checks the number of indices in ``rows``, alerts the user with a
        popup box if there are no items in ``rows``. Alternatively if the kwarg
        ``only_one`` is ``True`` also alerts users that too many rows are
        selected. Returns ``True`` if the right number(s) of items are in
        ``rows`` otherwise it returns ``False``.

        Parameters
        ----------
        rows : [row indices]
            A list of row indices to be checked.
        only_one : Bool, optional
            A boolean that indicates if more than one row is allowed, default
            is ``False``.
        Returns
        -------
        Ok : Bool
            A boolean to indicate if the number of items in row is Ok.

        """
        Ok = True

        if not rows:  # if no cell is selected
            Ok = False
            warning = QMessageBox()
            warning.setIcon(QMessageBox.Information)
            warning.setWindowTitle('Row(s) must be selected')
            warning.setText('Action not performed as no row is selected')
            warning.setDetailedText('This warning generally occurs '
                                    'because no row is selected, select a row'
                                    ' and try again')
            warning.setStandardButtons(QMessageBox.Ok)
            warning.exec_()

        elif len(rows) > 1 and only_one:
            Ok = False
            warning = QMessageBox()
            warning.setIcon(QMessageBox.Information)
            warning.setWindowTitle('More than one row is selected')
            warning.setText('Action not performed as more than one row is '
                            'selected')
            warning.setDetailedText('This warning generally occurs '
                                    'because there are more than one row '
                                    'selected, unselect some rows and try '
                                    'again')
            warning.setStandardButtons(QMessageBox.Ok)
            warning.exec_()

        return Ok
示例#12
0
    def __createMsgBox(self, title, message, details):
        msg_box = QMessageBox(self.parent())
        msg_box.setText(title)
        msg_box.setInformativeText(message)

        if len(details) > 0:
            msg_box.setDetailedText(details)

        horizontal_spacer = QSpacerItem(
            500, 0, QSizePolicy.MinimumExpanding, QSizePolicy.Expanding
        )
        layout = msg_box.layout()
        layout.addItem(horizontal_spacer, layout.rowCount(), 0, 1, layout.columnCount())

        return msg_box
示例#13
0
def exception(parent, ex, buttons=QMessageBox.Ok,
              defaultButton=QMessageBox.NoButton):
    title = type(ex).__name__
    message = str(ex)
    tb = StringIO()
    if hasattr(ex, '__traceback__'):
        exc_traceback = ex.__traceback__
    else:
        exc_traceback = sys.exc_info()[2]
    traceback.print_tb(exc_traceback, file=tb)

    msgbox = QMessageBox(QMessageBox.Critical, title, message, buttons, parent)
    msgbox.setDefaultButton(defaultButton)
    msgbox.setDetailedText(tb.getvalue())
    msgbox.exec_()
示例#14
0
    def _on_simulation_done(self, failed, failed_msg):
        self.processing_animation.hide()
        self.kill_button.setHidden(True)
        self.done_button.setHidden(False)
        self.restart_button.setVisible(
            self._run_model.has_failed_realizations())
        self.restart_button.setEnabled(self._run_model.support_restart)
        self._total_progress_bar.setValue(100)
        self._total_progress_label.setText(
            _TOTAL_PROGRESS_TEMPLATE.format(
                total_progress=100, phase_name=self._run_model.getPhaseName()))

        if failed:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Simulations failed!".center(100))
            msg.setDetailedText(failed_msg)
            msg.exec_()
示例#15
0
 def launch(self):
     if self.prepare.result is None:
         self.close()
         return
     if self.prepare.errors:
         errors_message = QMessageBox()
         errors_message.setText("There are errors during start")
         errors_message.setInformativeText(
             "During load saved state some of data could not be load properly\n"
             "The files has prepared backup copies in  state directory (Help > State directory)"
         )
         errors_message.setStandardButtons(QMessageBox.Ok)
         text = "\n".join(["File: " + x[0] + "\n" + str(x[1]) for x in self.prepare.errors])
         errors_message.setDetailedText(text)
         errors_message.exec()
     wind = self.prepare.result(title=self.final_title, signal_fun=self.window_shown)
     wind.show()
     self.wind = wind
示例#16
0
def exceptions(parent, exs, buttons=QMessageBox.Ok,
              defaultButton=QMessageBox.NoButton):
    title = 'Exception(s)'
    message = '\n'.join(map(str, exs))

    tracebacks = []
    for ex in exs:
        tb = StringIO()
        if not hasattr(ex, '__traceback__'):
            continue
        exc_traceback = ex.__traceback__
        traceback.print_tb(exc_traceback, file=tb)
        tracebacks.append(tb.getvalue())

    msgbox = QMessageBox(QMessageBox.Critical, title, message, buttons, parent)
    msgbox.setDefaultButton(defaultButton)
    msgbox.setDetailedText('\n'.join(tracebacks))
    msgbox.exec_()
示例#17
0
    def _export_shape_file(self, *args, **kwargs):
        # show files
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Information)
        msg.setText("You are about to create shape files.")
        msg.setInformativeText(
            "Please select an output directory after click \"OK\"\n"
            "For the list of .edi files (stations) included in the creation, please click \"Show Details\""
        )
        msg.setWindowTitle("Note")
        msg.setDetailedText("\n".join([
            "{station} ({fn})".format(
                station=station, fn=self._file_handler.station2ref(station))
            for station in self._station_viewer.selected_stations
        ]))
        msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)

        if msg.exec_() == QMessageBox.Ok:
            dialog = QFileDialog(self)
            dir_name = None
            dialog.setWindowTitle("Selecting Output Directory ...")
            dialog.setFileMode(QFileDialog.DirectoryOnly)
            while dir_name is None:
                if dialog.exec_() == QDialog.Accepted:
                    dir_name = dialog.selectedFiles()[0]
                    dir_name = str(dir_name)
                    if not os.path.isdir(dir_name):
                        QMessageBox.information(
                            self, "NOTE",
                            "Please select a directory to save the created shape files."
                        )
                        dir_name = None  # will read again
                else:
                    break
            if dir_name is not None:
                collect = EdiCollection(mt_objs=[
                    self._file_handler.get_MT_obj(
                        self._file_handler.station2ref(station))
                    for station in self._station_viewer.selected_stations
                ])
                collect.create_mt_station_gdf(dir_name)
                QMessageBox.information(self, "Creation Completed",
                                        "Output written to %s" % dir_name)
                webbrowser.open(dir_name)
示例#18
0
    def __init__(
        self,
        config_folder: Optional[str] = None,
        title="PartSeg",
        settings: Optional[BaseSettings] = None,
        signal_fun=None,
    ):
        if settings is None:
            if config_folder is None:
                raise ValueError("wrong config folder")
            settings: BaseSettings = self.get_setting_class()(config_folder)
            if not os.path.exists(config_folder):
                import_config()
            errors = settings.load()
            if errors:
                errors_message = QMessageBox()
                errors_message.setText("There are errors during start")
                errors_message.setInformativeText(
                    "During load saved state some of data could not be load properly\n"
                    "The files has prepared backup copies in "
                    " state directory (Help > State directory)")
                errors_message.setStandardButtons(QMessageBox.Ok)
                text = "\n".join(
                    ["File: " + x[0] + "\n" + str(x[1]) for x in errors])
                errors_message.setDetailedText(text)
                errors_message.exec()

        super().__init__()
        if signal_fun is not None:
            self.show_signal.connect(signal_fun)
        self.settings = settings
        self.viewer_list: List[Viewer] = []
        self.files_num = 1
        self.setAcceptDrops(True)
        self.setWindowTitle(title)
        self.title_base = title
        app = QApplication.instance()
        if app is not None:
            app.setStyleSheet(settings.style_sheet)
        self.settings.theme_changed.connect(self.change_theme)
        self.channel_info = ""
示例#19
0
def pop_message(parent, message, detailed_message=None, message_type='error'):
    """ pop up a message with specified message type such as error, warning, info...
    :param parent:
    :param message:
    :param detailed_message: detailed message optionally shown to user
    :param message_type: str as ['error', 'warning', 'info'] but NOT case sensitive
    :return:
    """
    message_type = message_type.lower()
    if message_type not in ['error', 'warning', 'info']:
        raise TypeError(
            'Message type {0} is not supported.'.format(message_type))

    # check types
    checkdatatypes.check_string_variable('(Main) message to show', message)
    if detailed_message is not None:
        checkdatatypes.check_string_variable('(Detailed) message to show',
                                             detailed_message)

    # create a QMessageBox
    msg_box = QMessageBox()

    # set information type
    if message_type == 'info':
        msg_box.setIcon(QMessageBox.Information)
    elif message_type == 'error':
        msg_box.setIcon(QMessageBox.Critical)
    elif message_type == 'warning':
        msg_box.setIcon(QMessageBox.Warning)

    # set text
    msg_box.setText(message)
    if detailed_message is not None:
        msg_box.setDetailedText(detailed_message)  # another button
    msg_box.setWindowTitle('PyRS Message')

    # box
    msg_box.setStandardButtons(QMessageBox.Ok)

    ret_val = msg_box.exec_()
    print('Message box return value: {}'.format(ret_val))
示例#20
0
 def __on_ws_message(self, msg):
     '''
     Handles messages from the device.
     :param msg: the message.
     '''
     if msg.startswith('mso '):
         logger.debug(f"Processing mso {msg}")
         self.__on_mso(json.loads(msg[4:]))
     elif msg.startswith('msoupdate '):
         logger.debug(f"Processing msoupdate {msg}")
         self.__on_msoupdate(json.loads(msg[10:]))
     else:
         logger.warning(f"Unknown message {msg}")
         msg_box = QMessageBox(QMessageBox.Critical, 'Unknown Message',
                               f"Received unexpected message from {self.ipAddress.text()}")
         msg_box.setDetailedText(f"<code>{msg}</code>")
         msg_box.setTextFormat(Qt.RichText)
         msg_box.exec()
         if self.__spinner is not None:
             stop_spinner(self.__spinner, self.syncStatus)
             self.__spinner = None
             self.syncStatus.setIcon(qta.icon('fa5s.times', color='red'))
示例#21
0
    def load_files(self):
        def exception_hook(exception):
            from qtpy.QtCore import QMetaObject

            instance = QApplication.instance()
            if isinstance(exception, MemoryError):
                instance.warning = "Open error", f"Not enough memory to read this image: {exception}"
                QMetaObject.invokeMethod(instance, "show_warning", Qt.QueuedConnection)
            elif isinstance(exception, IOError):
                instance.warning = "Open error", f"Some problem with reading from disc: {exception}"
                QMetaObject.invokeMethod(instance, "show_warning", Qt.QueuedConnection)
            elif isinstance(exception, KeyError):
                instance.warning = "Open error", f"Some problem project file: {exception}"
                QMetaObject.invokeMethod(instance, "show_warning", Qt.QueuedConnection)
                print(exception, file=sys.stderr)
            else:
                raise exception

        dial = MultipleLoadDialog(self.load_register, self.settings.get_path_history())
        dial.setDirectory(self.settings.get("io.multiple_open_directory", str(Path.home())))
        dial.selectNameFilter(self.settings.get("io.multiple_open_filter", next(iter(self.load_register.keys()))))
        self.error_list = []
        if dial.exec():
            result = dial.get_result()
            load_dir = os.path.dirname(result.load_location[0])
            self.settings.set("io.multiple_open_directory", load_dir)
            self.settings.add_path_history(load_dir)
            self.settings.set("io.multiple_open_filter", result.selected_filter)

            dial_fun = ExecuteFunctionDialog(self.execute_load_files, [result], exception_hook=exception_hook)
            dial_fun.exec()
            if self.error_list:
                errors_message = QMessageBox()
                errors_message.setText("There are errors during load files")
                errors_message.setInformativeText("During load files cannot found some of files on disc")
                errors_message.setStandardButtons(QMessageBox.Ok)
                text = "\n".join(["File: " + x[0] + "\n" + str(x[1]) for x in self.error_list])
                errors_message.setDetailedText(text)
                errors_message.exec()
示例#22
0
class Console(SpyderPluginWidget):
    """
    Console widget
    """
    CONF_SECTION = 'internal_console'
    focus_changed = Signal()
    redirect_stdio = Signal(bool)
    edit_goto = Signal(str, int, str)

    def __init__(self,
                 parent=None,
                 namespace=None,
                 commands=[],
                 message=None,
                 exitfunc=None,
                 profile=False,
                 multithreaded=False):
        SpyderPluginWidget.__init__(self, parent)

        debug_print("    ..internal console: initializing")
        self.dialog_manager = DialogManager()

        # Shell
        light_background = self.get_option('light_background')
        self.shell = InternalShell(parent,
                                   namespace,
                                   commands,
                                   message,
                                   self.get_option('max_line_count'),
                                   self.get_plugin_font(),
                                   exitfunc,
                                   profile,
                                   multithreaded,
                                   light_background=light_background)
        self.shell.status.connect(lambda msg: self.show_message.emit(msg, 0))
        self.shell.go_to_error.connect(self.go_to_error)
        self.shell.focus_changed.connect(lambda: self.focus_changed.emit())

        # Redirecting some signals:
        self.shell.redirect_stdio.connect(
            lambda state: self.redirect_stdio.emit(state))

        # Initialize plugin
        self.initialize_plugin()

        # Find/replace widget
        self.find_widget = FindReplace(self)
        self.find_widget.set_editor(self.shell)
        self.find_widget.hide()
        self.register_widget_shortcuts(self.find_widget)

        # Main layout
        btn_layout = QHBoxLayout()
        btn_layout.setAlignment(Qt.AlignLeft)
        btn_layout.addStretch()
        btn_layout.addWidget(self.options_button, Qt.AlignRight)
        layout = create_plugin_layout(btn_layout)
        layout.addWidget(self.shell)
        layout.addWidget(self.find_widget)
        self.setLayout(layout)

        # Parameters
        self.shell.toggle_wrap_mode(self.get_option('wrap'))

        # Accepting drops
        self.setAcceptDrops(True)

        # Traceback MessageBox
        self.msgbox_traceback = None
        self.error_traceback = ""

    #------ Private API --------------------------------------------------------
    def set_historylog(self, historylog):
        """Bind historylog instance to this console
        Not used anymore since v2.0"""
        historylog.add_history(self.shell.history_filename)
        self.shell.append_to_history.connect(historylog.append_to_history)

    def set_help(self, help_plugin):
        """Bind help instance to this console"""
        self.shell.help = help_plugin

    #------ SpyderPluginWidget API ---------------------------------------------
    def get_plugin_title(self):
        """Return widget title"""
        return _('Internal console')

    def get_focus_widget(self):
        """
        Return the widget to give focus to when
        this plugin's dockwidget is raised on top-level
        """
        return self.shell

    def update_font(self):
        """Update font from Preferences"""
        font = self.get_plugin_font()
        self.shell.set_font(font)

    def closing_plugin(self, cancelable=False):
        """Perform actions before parent main window is closed"""
        self.dialog_manager.close_all()
        self.shell.exit_interpreter()
        return True

    def refresh_plugin(self):
        pass

    def get_plugin_actions(self):
        """Return a list of actions related to plugin"""
        quit_action = create_action(self,
                                    _("&Quit"),
                                    icon=ima.icon('exit'),
                                    tip=_("Quit"),
                                    triggered=self.quit)
        self.register_shortcut(quit_action, "_", "Quit", "Ctrl+Q")
        run_action = create_action(self,
                                   _("&Run..."),
                                   None,
                                   ima.icon('run_small'),
                                   _("Run a Python script"),
                                   triggered=self.run_script)
        environ_action = create_action(
            self,
            _("Environment variables..."),
            icon=ima.icon('environ'),
            tip=_("Show and edit environment variables"
                  " (for current session)"),
            triggered=self.show_env)
        syspath_action = create_action(self,
                                       _("Show sys.path contents..."),
                                       icon=ima.icon('syspath'),
                                       tip=_("Show (read-only) sys.path"),
                                       triggered=self.show_syspath)
        buffer_action = create_action(self,
                                      _("Buffer..."),
                                      None,
                                      tip=_("Set maximum line count"),
                                      triggered=self.change_max_line_count)
        exteditor_action = create_action(
            self,
            _("External editor path..."),
            None,
            None,
            _("Set external editor executable path"),
            triggered=self.change_exteditor)
        wrap_action = create_action(self,
                                    _("Wrap lines"),
                                    toggled=self.toggle_wrap_mode)
        wrap_action.setChecked(self.get_option('wrap'))
        calltips_action = create_action(self,
                                        _("Display balloon tips"),
                                        toggled=self.toggle_calltips)
        calltips_action.setChecked(self.get_option('calltips'))
        codecompletion_action = create_action(
            self,
            _("Automatic code completion"),
            toggled=self.toggle_codecompletion)
        codecompletion_action.setChecked(
            self.get_option('codecompletion/auto'))
        codecompenter_action = create_action(
            self,
            _("Enter key selects completion"),
            toggled=self.toggle_codecompletion_enter)
        codecompenter_action.setChecked(
            self.get_option('codecompletion/enter_key'))

        option_menu = QMenu(_('Internal console settings'), self)
        option_menu.setIcon(ima.icon('tooloptions'))
        add_actions(
            option_menu,
            (buffer_action, wrap_action, calltips_action,
             codecompletion_action, codecompenter_action, exteditor_action))

        plugin_actions = [
            None, run_action, environ_action, syspath_action, option_menu,
            MENU_SEPARATOR, quit_action, self.undock_action
        ]

        return plugin_actions

    def register_plugin(self):
        """Register plugin in Spyder's main window"""
        self.focus_changed.connect(self.main.plugin_focus_changed)
        self.main.add_dockwidget(self)
        # Connecting the following signal once the dockwidget has been created:
        self.shell.exception_occurred.connect(self.exception_occurred)

    def exception_occurred(self, text, is_traceback):
        """Exception ocurred in the internal console.
        Show a QMessageBox or the internal console to warn the user"""
        # Skip errors without traceback
        if not is_traceback and self.msgbox_traceback is None:
            return

        if CONF.get('main', 'show_internal_console_if_traceback', False):
            self.dockwidget.show()
            self.dockwidget.raise_()
        else:
            if self.msgbox_traceback is None:
                self.msgbox_traceback = QMessageBox(
                    QMessageBox.Critical,
                    _('Error'),
                    _("<b>Spyder has encountered a problem.</b><br>"
                      "Sorry for the inconvenience."
                      "<br><br>"
                      "You can automatically submit this error to our Github "
                      "issues tracker.<br><br>"
                      "<i>Note:</i> You need a Github account for that."),
                    QMessageBox.Ok,
                    parent=self)

                self.submit_btn = self.msgbox_traceback.addButton(
                    _('Submit to Github'), QMessageBox.YesRole)
                self.submit_btn.pressed.connect(self.press_submit_btn)

                self.msgbox_traceback.setWindowModality(Qt.NonModal)
                self.error_traceback = ""
                self.msgbox_traceback.show()
                self.msgbox_traceback.finished.connect(self.close_msg)
                self.msgbox_traceback.setDetailedText(' ')

                # open show details (iterate over all buttons and click it)
                for button in self.msgbox_traceback.buttons():
                    if (self.msgbox_traceback.buttonRole(button) ==
                            QMessageBox.ActionRole):
                        button.click()
                        break

            self.error_traceback += text
            self.msgbox_traceback.setDetailedText(self.error_traceback)

    def close_msg(self):
        self.msgbox_traceback = None

    def press_submit_btn(self):
        self.main.report_issue(self.error_traceback)
        self.msgbox_traceback = None

    #------ Public API ---------------------------------------------------------
    @Slot()
    def quit(self):
        """Quit mainwindow"""
        self.main.close()

    @Slot()
    def show_env(self):
        """Show environment variables"""
        self.dialog_manager.show(EnvDialog())

    @Slot()
    def show_syspath(self):
        """Show sys.path"""
        editor = CollectionsEditor()
        editor.setup(sys.path,
                     title="sys.path",
                     readonly=True,
                     width=600,
                     icon=ima.icon('syspath'))
        self.dialog_manager.show(editor)

    @Slot()
    def run_script(self,
                   filename=None,
                   silent=False,
                   set_focus=False,
                   args=None):
        """Run a Python script"""
        if filename is None:
            self.shell.interpreter.restore_stds()
            filename, _selfilter = getopenfilename(
                self, _("Run Python script"), getcwd_or_home(),
                _("Python scripts") + " (*.py ; *.pyw ; *.ipy)")
            self.shell.interpreter.redirect_stds()
            if filename:
                os.chdir(osp.dirname(filename))
                filename = osp.basename(filename)
            else:
                return
        debug_print(args)
        filename = osp.abspath(filename)
        rbs = remove_backslashes
        command = "runfile('%s', args='%s')" % (rbs(filename), rbs(args))
        if set_focus:
            self.shell.setFocus()
        if self.dockwidget and not self.ismaximized:
            self.dockwidget.setVisible(True)
            self.dockwidget.raise_()
        self.shell.write(command + '\n')
        self.shell.run_command(command)

    def go_to_error(self, text):
        """Go to error if relevant"""
        match = get_error_match(to_text_string(text))
        if match:
            fname, lnb = match.groups()
            self.edit_script(fname, int(lnb))

    def edit_script(self, filename=None, goto=-1):
        """Edit script"""
        # Called from InternalShell
        if not hasattr(self, 'main') \
           or not hasattr(self.main, 'editor'):
            self.shell.external_editor(filename, goto)
            return
        if filename is not None:
            self.edit_goto.emit(osp.abspath(filename), goto, '')

    def execute_lines(self, lines):
        """Execute lines and give focus to shell"""
        self.shell.execute_lines(to_text_string(lines))
        self.shell.setFocus()

    @Slot()
    def change_max_line_count(self):
        "Change maximum line count" ""
        mlc, valid = QInputDialog.getInt(self, _('Buffer'),
                                         _('Maximum line count'),
                                         self.get_option('max_line_count'), 0,
                                         1000000)
        if valid:
            self.shell.setMaximumBlockCount(mlc)
            self.set_option('max_line_count', mlc)

    @Slot()
    def change_exteditor(self):
        """Change external editor path"""
        path, valid = QInputDialog.getText(
            self, _('External editor'), _('External editor executable path:'),
            QLineEdit.Normal, self.get_option('external_editor/path'))
        if valid:
            self.set_option('external_editor/path', to_text_string(path))

    @Slot(bool)
    def toggle_wrap_mode(self, checked):
        """Toggle wrap mode"""
        self.shell.toggle_wrap_mode(checked)
        self.set_option('wrap', checked)

    @Slot(bool)
    def toggle_calltips(self, checked):
        """Toggle calltips"""
        self.shell.set_calltips(checked)
        self.set_option('calltips', checked)

    @Slot(bool)
    def toggle_codecompletion(self, checked):
        """Toggle automatic code completion"""
        self.shell.set_codecompletion_auto(checked)
        self.set_option('codecompletion/auto', checked)

    @Slot(bool)
    def toggle_codecompletion_enter(self, checked):
        """Toggle Enter key for code completion"""
        self.shell.set_codecompletion_enter(checked)
        self.set_option('codecompletion/enter_key', checked)

    #----Drag and drop
    def dragEnterEvent(self, event):
        """Reimplement Qt method
        Inform Qt about the types of data that the widget accepts"""
        source = event.mimeData()
        if source.hasUrls():
            if mimedata2url(source):
                event.acceptProposedAction()
            else:
                event.ignore()
        elif source.hasText():
            event.acceptProposedAction()

    def dropEvent(self, event):
        """Reimplement Qt method
        Unpack dropped data and handle it"""
        source = event.mimeData()
        if source.hasUrls():
            pathlist = mimedata2url(source)
            self.shell.drop_pathlist(pathlist)
        elif source.hasText():
            lines = to_text_string(source.text())
            self.shell.set_cursor_position('eof')
            self.shell.execute_lines(lines)
        event.acceptProposedAction()
示例#23
0
class Console(SpyderPluginWidget):
    """
    Console widget
    """
    CONF_SECTION = 'internal_console'
    focus_changed = Signal()
    redirect_stdio = Signal(bool)
    edit_goto = Signal(str, int, str)
    
    def __init__(self, parent=None, namespace=None, commands=[], message=None,
                 exitfunc=None, profile=False, multithreaded=False):
        SpyderPluginWidget.__init__(self, parent)

        debug_print("    ..internal console: initializing")
        self.dialog_manager = DialogManager()

        # Shell
        light_background = self.get_option('light_background')
        self.shell = InternalShell(parent, namespace, commands, message,
                                   self.get_option('max_line_count'),
                                   self.get_plugin_font(), exitfunc, profile,
                                   multithreaded,
                                   light_background=light_background)
        self.shell.status.connect(lambda msg: self.show_message.emit(msg, 0))
        self.shell.go_to_error.connect(self.go_to_error)
        self.shell.focus_changed.connect(lambda: self.focus_changed.emit())

        # Redirecting some signals:
        self.shell.redirect_stdio.connect(lambda state:
                                          self.redirect_stdio.emit(state))
        
        # Initialize plugin
        self.initialize_plugin()

        # Find/replace widget
        self.find_widget = FindReplace(self)
        self.find_widget.set_editor(self.shell)
        self.find_widget.hide()
        self.register_widget_shortcuts(self.find_widget)

        # Main layout
        layout = QVBoxLayout()
        layout.addWidget(self.shell)
        layout.addWidget(self.find_widget)
        self.setLayout(layout)
        
        # Parameters
        self.shell.toggle_wrap_mode(self.get_option('wrap'))
            
        # Accepting drops
        self.setAcceptDrops(True)

        # Traceback MessageBox
        self.msgbox_traceback= None
        self.error_traceback = ""

    #------ Private API --------------------------------------------------------
    def set_historylog(self, historylog):
        """Bind historylog instance to this console
        Not used anymore since v2.0"""
        historylog.add_history(self.shell.history_filename)
        self.shell.append_to_history.connect(historylog.append_to_history)

    def set_help(self, help_plugin):
        """Bind help instance to this console"""
        self.shell.help = help_plugin

    #------ SpyderPluginWidget API ---------------------------------------------
    def get_plugin_title(self):
        """Return widget title"""
        return _('Internal console')
    
    def get_focus_widget(self):
        """
        Return the widget to give focus to when
        this plugin's dockwidget is raised on top-level
        """
        return self.shell

    def update_font(self):
        """Update font from Preferences"""
        font = self.get_plugin_font()
        self.shell.set_font(font)

    def closing_plugin(self, cancelable=False):
        """Perform actions before parent main window is closed"""
        self.dialog_manager.close_all()
        self.shell.exit_interpreter()
        return True
        
    def refresh_plugin(self):
        pass
    
    def get_plugin_actions(self):
        """Return a list of actions related to plugin"""
        quit_action = create_action(self, _("&Quit"),
                                    icon=ima.icon('exit'), 
                                    tip=_("Quit"),
                                    triggered=self.quit)
        self.register_shortcut(quit_action, "_", "Quit", "Ctrl+Q")
        run_action = create_action(self, _("&Run..."), None,
                            ima.icon('run_small'),
                            _("Run a Python script"),
                            triggered=self.run_script)
        environ_action = create_action(self,
                            _("Environment variables..."),
                            icon=ima.icon('environ'),
                            tip=_("Show and edit environment variables"
                                        " (for current session)"),
                            triggered=self.show_env)
        syspath_action = create_action(self,
                            _("Show sys.path contents..."),
                            icon=ima.icon('syspath'),
                            tip=_("Show (read-only) sys.path"),
                            triggered=self.show_syspath)
        buffer_action = create_action(self,
                            _("Buffer..."), None,
                            tip=_("Set maximum line count"),
                            triggered=self.change_max_line_count)
        exteditor_action = create_action(self,
                            _("External editor path..."), None, None,
                            _("Set external editor executable path"),
                            triggered=self.change_exteditor)
        wrap_action = create_action(self,
                            _("Wrap lines"),
                            toggled=self.toggle_wrap_mode)
        wrap_action.setChecked(self.get_option('wrap'))
        calltips_action = create_action(self, _("Display balloon tips"),
            toggled=self.toggle_calltips)
        calltips_action.setChecked(self.get_option('calltips'))
        codecompletion_action = create_action(self,
                                          _("Automatic code completion"),
                                          toggled=self.toggle_codecompletion)
        codecompletion_action.setChecked(self.get_option('codecompletion/auto'))
        codecompenter_action = create_action(self,
                                    _("Enter key selects completion"),
                                    toggled=self.toggle_codecompletion_enter)
        codecompenter_action.setChecked(self.get_option(
                                                    'codecompletion/enter_key'))
        
        option_menu = QMenu(_('Internal console settings'), self)
        option_menu.setIcon(ima.icon('tooloptions'))
        add_actions(option_menu, (buffer_action, wrap_action,
                                  calltips_action, codecompletion_action,
                                  codecompenter_action, exteditor_action))
                    
        plugin_actions = [None, run_action, environ_action, syspath_action,
                          option_menu, None, quit_action]
        
        # Add actions to context menu
        add_actions(self.shell.menu, plugin_actions)
        
        return plugin_actions
    
    def register_plugin(self):
        """Register plugin in Spyder's main window"""
        self.focus_changed.connect(self.main.plugin_focus_changed)
        self.main.add_dockwidget(self)
        # Connecting the following signal once the dockwidget has been created:
        self.shell.exception_occurred.connect(self.exception_occurred)
    
    def exception_occurred(self, text, is_traceback):
        """Exception ocurred in the internal console.
        Show a QMessageBox or the internal console to warn the user"""
        # Skip errors without traceback
        if not is_traceback and self.msgbox_traceback is None:
            return

        if CONF.get('main', 'show_internal_console_if_traceback', False):
            self.dockwidget.show()
            self.dockwidget.raise_()
        else:
            if self.msgbox_traceback is None:
                self.msgbox_traceback = QMessageBox(
                    QMessageBox.Critical,
                    _('Error'),
                    _("<b>Spyder has encountered a problem.</b><br>"
                      "Sorry for the inconvenience."
                      "<br><br>"
                      "You can automatically submit this error to our Github "
                      "issues tracker.<br><br>"
                      "<i>Note:</i> You need a Github account for that."),
                    QMessageBox.Ok,
                    parent=self)

                self.submit_btn = self.msgbox_traceback.addButton(
                        _('Submit to Github'), QMessageBox.YesRole)
                self.submit_btn.pressed.connect(self.press_submit_btn)

                self.msgbox_traceback.setWindowModality(Qt.NonModal)
                self.error_traceback = ""
                self.msgbox_traceback.show()
                self.msgbox_traceback.finished.connect(self.close_msg)
                self.msgbox_traceback.setDetailedText(' ')

                # open show details (iterate over all buttons and click it)
                for button in self.msgbox_traceback.buttons():
                    if (self.msgbox_traceback.buttonRole(button)
                       == QMessageBox.ActionRole):
                        button.click()
                        break

            self.error_traceback += text
            self.msgbox_traceback.setDetailedText(self.error_traceback)

    def close_msg(self):
        self.msgbox_traceback = None

    def press_submit_btn(self):
        self.main.report_issue(self.error_traceback)
        self.msgbox_traceback = None

    #------ Public API ---------------------------------------------------------
    @Slot()
    def quit(self):
        """Quit mainwindow"""
        self.main.close()
    
    @Slot()
    def show_env(self):
        """Show environment variables"""
        self.dialog_manager.show(EnvDialog())
    
    @Slot()
    def show_syspath(self):
        """Show sys.path"""
        editor = CollectionsEditor()
        editor.setup(sys.path, title="sys.path", readonly=True,
                     width=600, icon=ima.icon('syspath'))
        self.dialog_manager.show(editor)
    
    @Slot()
    def run_script(self, filename=None, silent=False, set_focus=False,
                   args=None):
        """Run a Python script"""
        if filename is None:
            self.shell.interpreter.restore_stds()
            filename, _selfilter = getopenfilename(self, _("Run Python script"),
                   getcwd(), _("Python scripts")+" (*.py ; *.pyw ; *.ipy)")
            self.shell.interpreter.redirect_stds()
            if filename:
                os.chdir( osp.dirname(filename) )
                filename = osp.basename(filename)
            else:
                return
        debug_print(args)
        filename = osp.abspath(filename)
        rbs = remove_backslashes
        command = "runfile('%s', args='%s')" % (rbs(filename), rbs(args))
        if set_focus:
            self.shell.setFocus()
        if self.dockwidget and not self.ismaximized:
            self.dockwidget.setVisible(True)
            self.dockwidget.raise_()
        self.shell.write(command+'\n')
        self.shell.run_command(command)

            
    def go_to_error(self, text):
        """Go to error if relevant"""
        match = get_error_match(to_text_string(text))
        if match:
            fname, lnb = match.groups()
            self.edit_script(fname, int(lnb))
            
    def edit_script(self, filename=None, goto=-1):
        """Edit script"""
        # Called from InternalShell
        if not hasattr(self, 'main') \
           or not hasattr(self.main, 'editor'):
            self.shell.external_editor(filename, goto)
            return
        if filename is not None:
            self.edit_goto.emit(osp.abspath(filename), goto, '')
        
    def execute_lines(self, lines):
        """Execute lines and give focus to shell"""
        self.shell.execute_lines(to_text_string(lines))
        self.shell.setFocus()

    @Slot()
    def change_max_line_count(self):
        "Change maximum line count"""
        mlc, valid = QInputDialog.getInt(self, _('Buffer'),
                                           _('Maximum line count'),
                                           self.get_option('max_line_count'),
                                           0, 1000000)
        if valid:
            self.shell.setMaximumBlockCount(mlc)
            self.set_option('max_line_count', mlc)

    @Slot()
    def change_exteditor(self):
        """Change external editor path"""
        path, valid = QInputDialog.getText(self, _('External editor'),
                          _('External editor executable path:'),
                          QLineEdit.Normal,
                          self.get_option('external_editor/path'))
        if valid:
            self.set_option('external_editor/path', to_text_string(path))
    
    @Slot(bool)
    def toggle_wrap_mode(self, checked):
        """Toggle wrap mode"""
        self.shell.toggle_wrap_mode(checked)
        self.set_option('wrap', checked)
    
    @Slot(bool)
    def toggle_calltips(self, checked):
        """Toggle calltips"""
        self.shell.set_calltips(checked)
        self.set_option('calltips', checked)
    
    @Slot(bool)
    def toggle_codecompletion(self, checked):
        """Toggle automatic code completion"""
        self.shell.set_codecompletion_auto(checked)
        self.set_option('codecompletion/auto', checked)
    
    @Slot(bool)
    def toggle_codecompletion_enter(self, checked):
        """Toggle Enter key for code completion"""
        self.shell.set_codecompletion_enter(checked)
        self.set_option('codecompletion/enter_key', checked)
                
    #----Drag and drop                    
    def dragEnterEvent(self, event):
        """Reimplement Qt method
        Inform Qt about the types of data that the widget accepts"""
        source = event.mimeData()
        if source.hasUrls():
            if mimedata2url(source):
                event.acceptProposedAction()
            else:
                event.ignore()
        elif source.hasText():
            event.acceptProposedAction()
            
    def dropEvent(self, event):
        """Reimplement Qt method
        Unpack dropped data and handle it"""
        source = event.mimeData()
        if source.hasUrls():
            pathlist = mimedata2url(source)
            self.shell.drop_pathlist(pathlist)
        elif source.hasText():
            lines = to_text_string(source.text())
            self.shell.set_cursor_position('eof')
            self.shell.execute_lines(lines)
        event.acceptProposedAction()