Esempio n. 1
0
 def clear_all_memory_action(self):
     """
     Creates Question QMessageBox to check user wants to clear all memory
     when action is pressed from file menu
     """
     msg = QMessageBox(QMessageBox.Question,
                       "Clear All", "All workspaces and windows will be removed.\nAre you sure?")
     msg.addButton(QMessageBox.Ok)
     msg.addButton(QMessageBox.Cancel)
     msg.setWindowIcon(QIcon(':/images/MantidIcon.ico'))
     reply = msg.exec()
     if reply == QMessageBox.Ok:
         self.clear_all_memory()
Esempio n. 2
0
 def about(self):
     """
     Reset message box is based on aboutWindow object
     For some reason, I did not get time to fix that
     :return:
     """
     about_message_box = QMessageBox().window()
     about_message_box.about(
         self.pushButton,
         "Info",
         "Please restart guiscrcpy to reset the settings. "
         "guiscrcpy will now exit",
     )
     about_message_box.addButton("OK", about_message_box.hide)  # noqa:
     about_message_box.show()
Esempio n. 3
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
Esempio n. 4
0
    def _handle_error_msg(self, msg):
        """Handle error message with an error dialog."""
        error_message_dialog = QMessageBox(self._parent)
        error_message_dialog.setText(
            _("<b>An error ocurred while Kite was installing!</b><br><br>"
              "You can follow our manual install instructions to<br>"
              "integrate Kite with Spyder yourself."))
        error_message_dialog.setWindowTitle(_('Kite install error'))

        get_help_button = QPushButton(_('Contact Kite for help'))
        get_help_button.clicked.connect(
            lambda: QDesktopServices.openUrl(
                    QUrl('https://kite.com/contact/')))
        error_message_dialog.addButton(get_help_button, QMessageBox.ActionRole)
        error_message_dialog.exec_()
        self.accept()
Esempio n. 5
0
    def welcome_user(self):
        """
        On open, ask the user what they'd like to do (new config? load?)

        TODO: only show when we don't get a file cli argument to start.
        """
        welcome_box = QMessageBox()
        welcome_box.setIcon(QMessageBox.Question)
        welcome_box.setWindowTitle('Welcome')
        welcome_box.setText('Welcome to atef config!')
        welcome_box.setInformativeText('Please select a startup action')
        open_button = welcome_box.addButton(QMessageBox.Open)
        new_button = welcome_box.addButton('New', QMessageBox.AcceptRole)
        welcome_box.addButton(QMessageBox.Close)
        open_button.clicked.connect(self.open_file)
        new_button.clicked.connect(self.new_file)
        welcome_box.exec()
Esempio n. 6
0
 def reset(self):
     """
     Remove configuration files; Reset the mapper and guiscrcpy.json
     :return:
     """
     self.cfgmgr.reset_config()
     log("CONFIGURATION FILE REMOVED SUCCESSFULLY")
     log("RESTART")
     message_box = QMessageBox().window()
     message_box.about(
         self.pushButton,
         "Info",
         "Please restart guiscrcpy to reset the settings. "
         "guiscrcpy will now exit",
     )
     QMessageBox.ButtonRole()
     message_box.addButton("OK", self.quit_window)  # noqa:
     message_box.show()
Esempio n. 7
0
def __choose_by_mbox(viewer, choices, message):
    msgBox = QMessageBox(viewer.window.qt_viewer)
    msgBox.setText(message)
    msgBox.setIcon(QMessageBox.Question)
    buttons = []
    for choice in choices:
        button = msgBox.addButton(choice, QMessageBox.ActionRole)
        buttons.append(button)
    cancelled = msgBox.addButton(QMessageBox.Cancel)
    logger.info("messagebox selected")
    _ = msgBox.exec_()
    clicked_button = msgBox.clickedButton()

    if clicked_button == cancelled:
        return False
    try:
        return choices[buttons.index(clicked_button)]
    except ValueError:
        return None
Esempio n. 8
0
    def _save_and_run_dialog(self):

        mb = QMessageBox(self.main_window)
        mb.setWindowTitle(_(u'Unsaved changes'))
        mb.setText(
            u'You have unsaved changes. What do you want to do?'
        )
        mb.addButton(
            QPushButton(
                self.theme.qicon(u'os-run'),
                _(u'Save and run')
            ),
            QMessageBox.AcceptRole
        )
        mb.addButton(
            QPushButton(
                self.theme.qicon(u'os-run'),
                _(u'Save, run, and don\'t ask again')
            ),
            QMessageBox.AcceptRole
        )

        mb.addButton(
            QPushButton(
                self.theme.qicon(u'dialog-cancel'),
                _(u'Cancel')
            ),
            QMessageBox.AcceptRole
        )
        return mb.exec_()
Esempio n. 9
0
    def restart_debug(self):
        """Restart in debug mode."""
        box = QMessageBox(self)
        box.setWindowTitle(_("Question"))
        box.setIcon(QMessageBox.Question)
        box.setText(_("Which debug mode do you want Spyder to restart in?"))

        button_verbose = QPushButton(_('Verbose'))
        button_minimal = QPushButton(_('Minimal'))
        box.addButton(button_verbose, QMessageBox.AcceptRole)
        box.addButton(button_minimal, QMessageBox.AcceptRole)
        box.setStandardButtons(QMessageBox.Cancel)
        box.exec_()

        if box.clickedButton() == button_minimal:
            os.environ['SPYDER_DEBUG'] = '2'
        elif box.clickedButton() == button_verbose:
            os.environ['SPYDER_DEBUG'] = '3'
        else:
            return

        self.sig_restart_requested.emit()
Esempio n. 10
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()
Esempio n. 11
0
class ExportDialog(QDialog):
    def __init__(self, parent=None):
        QDialog.__init__(self, parent)
        self.ui = Ui_Dialog_Export()
        self.ui.setupUi(self)
        self._fig = None

        # setup file types
        for frmt in IMAGE_FORMATS:
            self.ui.comboBox_fileType.addItem("{0[1]} (.{0[0]})".format(frmt))

        self._file_name_changed()  # select the default format

        # setup directory and dir dialog
        self._dir_dialog = QFileDialog(self)
        # self._dir_dialog.setDirectory(os.path.expanduser("~"))
        self._dir_dialog.setFileMode(QFileDialog.DirectoryOnly)
        self._dir_dialog.setWindowTitle("Save to ...")
        self.ui.comboBox_directory.addItem(os.path.expanduser("~"))
        self.ui.pushButton_browse.clicked.connect(self._browse)

        self._dir_validator = DirectoryValidator()
        self.ui.comboBox_directory.lineEdit().setValidator(self._dir_validator)

        # file name
        self.ui.comboBox_fileName.currentIndexChanged.connect(
            self._file_name_changed)

        # file type
        self.ui.comboBox_fileType.currentIndexChanged.connect(
            self._file_type_changed)

        # cancel button
        self.ui.pushButton_cancel.clicked.connect(self._cancel_button_clicked)
        # export button
        self.ui.pushButton_export.clicked.connect(self._export_button_clicked)
        # preview button
        self.ui.pushButton_preview.clicked.connect(
            self._preview_button_clicked)

        # dpi
        self.ui.spinBox_dpi.valueChanged.connect(self._dpi_changed)
        # inches
        self.ui.doubleSpinBox_width_inches.valueChanged.connect(
            self._width_inches_changed)
        self.ui.doubleSpinBox_height_inches.valueChanged.connect(
            self._height_inches_changed)
        # pixels
        self.ui.spinBox_width_pixels.valueChanged.connect(
            self._width_pixels_changed)
        self.ui.spinBox_height_pixels.valueChanged.connect(
            self._height_pixels_changed)

        # message box for when the file already exist
        self._msg_box = QMessageBox(self)
        self._msg_box.setWindowTitle("Export...")
        self._msg_box_button_overwrite = self._msg_box.addButton(
            self.tr("Overwrite"), QMessageBox.AcceptRole)
        self._msg_box_button_save_as = self._msg_box.addButton(
            self.tr("Save As"), QMessageBox.ActionRole)
        self._msg_box_button_cancel = self._msg_box.addButton(
            QMessageBox.Cancel)
        self._msg_box.setDefaultButton(self._msg_box_button_save_as)

    _orientation = ['portrait', 'landscape']

    _no_alpha_channel_formats = ('jpg', 'jpeg')  # ("png", "gif", "psd")

    def _dpi_changed(self, dpi):
        self.ui.doubleSpinBox_height_inches.blockSignals(True)
        self.ui.doubleSpinBox_width_inches.blockSignals(True)
        self.ui.spinBox_height_pixels.setValue(
            self.ui.doubleSpinBox_height_inches.value() * dpi)
        self.ui.spinBox_width_pixels.setValue(
            self.ui.doubleSpinBox_width_inches.value() * dpi)
        self.ui.doubleSpinBox_height_inches.blockSignals(False)
        self.ui.doubleSpinBox_width_inches.blockSignals(False)

    def _width_pixels_changed(self, width):
        self.ui.doubleSpinBox_width_inches.blockSignals(True)
        new_width_inches = width / float(self.ui.spinBox_dpi.value())
        self.ui.doubleSpinBox_width_inches.setValue(new_width_inches)
        self.ui.doubleSpinBox_width_inches.blockSignals(False)

    def _height_pixels_changed(self, height):
        self.ui.doubleSpinBox_height_inches.blockSignals(True)
        new_height_inches = height / float(self.ui.spinBox_dpi.value())
        self.ui.doubleSpinBox_height_inches.setValue(new_height_inches)
        self.ui.doubleSpinBox_height_inches.blockSignals(False)

    def _width_inches_changed(self, width):
        self.ui.spinBox_width_pixels.blockSignals(True)
        self.ui.spinBox_width_pixels.setValue(width *
                                              self.ui.spinBox_dpi.value())
        self.ui.spinBox_width_pixels.blockSignals(False)

    def _height_inches_changed(self, height):
        self.ui.spinBox_height_pixels.blockSignals(True)
        self.ui.spinBox_height_pixels.setValue(height *
                                               self.ui.spinBox_dpi.value())
        self.ui.spinBox_height_pixels.blockSignals(False)

    def _cancel_button_clicked(self, b):
        self.reject()

    def _export_button_clicked(self, b):
        self.accept()

    def _preview_button_clicked(self):
        if self._fig:
            # set figures
            self._fig.set_size_inches(self.get_size_inches_width(),
                                      self.get_size_inches_height())
            params = self.get_savefig_params()
            self._fig.set_dpi(params['dpi'])
            self._fig.set_tight_layout(True if params['bbox_inches'] ==
                                       'tight' else False)

            canvas = FigureCanvas(self._fig)
            canvas.show()

            # dialog
            preview_dialog = PreviewDialog(self, self._fig)
            preview_dialog.exec_()

    def _file_type_changed(self, *args, **kwargs):
        index = self.ui.comboBox_fileType.currentIndex()
        ext, _ = IMAGE_FORMATS[index]
        filename = str(self.ui.comboBox_fileName.currentText())
        filename, _ = os.path.splitext(filename)

        if ext in self._no_alpha_channel_formats:  # enable transparent if the format supports
            self.ui.checkBox_transparent.setEnabled(False)
        else:
            self.ui.checkBox_transparent.setEnabled(True)

        # update file name
        filename = "%s.%s" % (filename, ext)
        index = self.ui.comboBox_fileName.findText(filename)
        if index == -1:
            self.ui.comboBox_fileName.addItem(filename)
        self.ui.comboBox_fileName.setCurrentIndex(
            index if index >= 0 else self.ui.comboBox_fileName.
            findText(filename))

    def _file_name_changed(self, *args, **kwargs):
        filename = str(self.ui.comboBox_fileName.currentText())
        filename, extension = os.path.splitext(filename)
        extension = extension[1:]  # get ride of .
        # check if the extension is supported
        index = [
            i for i, (ext, dsc) in enumerate(IMAGE_FORMATS) if ext == extension
        ]
        if index:
            self.ui.comboBox_fileType.setCurrentIndex(index[0])
        elif extension:
            # no extension
            pass
        else:
            # extension not supported:
            pass

    def _browse(self, *args, **kwargs):
        if self._dir_dialog.exec_() == QDialog.Accepted:
            dirs = self._dir_dialog.selectedFiles(
            )  # behave differently in pyqt4 and pyqt5
            directory = str(dirs[0] if dirs else self._dir_dialog.directory().
                            absolutePath())  # this makes the behave the same
            # update directory
            index = self.ui.comboBox_directory.findText(directory)
            if index == -1:
                self.ui.comboBox_directory.addItem(directory)
            self.ui.comboBox_directory.setCurrentIndex(
                index if index >= 0 else self.ui.comboBox_directory.
                findText(directory))

    def export_to_file(self, fig):
        self._fig = fig
        respawn = True
        while respawn:
            respawn = False
            self.ui.spinBox_dpi.setValue(fig.get_dpi())
            self.ui.doubleSpinBox_width_inches.setValue(fig.get_figwidth())
            self.ui.doubleSpinBox_height_inches.setValue(fig.get_figheight())
            response = self.exec_()
            if response == QDialog.Accepted:
                # saving files
                fname = self.get_save_file_name()

                if os.path.exists(fname):
                    new_name = generate_unique_file_name(fname)
                    self._show_file_exist_message(fname, new_name)
                    if self._msg_box.clickedButton(
                    ) == self._msg_box_button_cancel:
                        respawn = True
                        continue
                    elif self._msg_box.clickedButton(
                    ) == self._msg_box_button_save_as:
                        fname = new_name  # save_as
                    else:
                        pass  # use the original name to overwrite

                params = self.get_savefig_params()
                # change size
                fig.set_size_inches(self.get_size_inches_width(),
                                    self.get_size_inches_height())
                try:
                    fig.savefig(fname, **params)
                except IOError as err:
                    if 'RGBA' in err.message:
                        # if the problem is RGBA as the alpha channel is not supported in the selected format
                        # save to png then save as
                        basename = os.path.basename(fname)
                        tmp_dir = tempfile.gettempdir()
                        filename, ext = os.path.splitext(basename)
                        png_file = filename + ".png"
                        final_format = params['format']
                        params['format'] = 'png'
                        new_fname = os.path.join(tmp_dir, png_file)
                        fig.savefig(new_fname, **params)
                        with Image.open(new_fname) as im:
                            rgb_im = im.convert('RGB')
                            # make sure the fname is ended with the right extension
                            fname, _ = os.path.splitext(fname)
                            fname += "." + final_format
                            rgb_im.save(fname)
                    else:
                        raise err

                if self.ui.checkBox_open_after_export.isChecked():
                    # open with the system default application, this should work on all platforms
                    webbrowser.open(fname)
                return fname
                # elif response == QtGu

    def get_size_inches_width(self):
        return self.ui.doubleSpinBox_width_inches.value()

    def get_size_inches_height(self):
        return self.ui.doubleSpinBox_height_inches.value()

    def _show_file_exist_message(self, fname, new_name):
        self._msg_box.setText(
            "<p>File \"{0}\" already exists. Do you want to overwrite the existing, or save to \"{1}\" instead?<\p>"
            .format(fname, new_name))
        self._msg_box.exec_()

    def get_save_file_name(self):
        name = os.path.join(str(self.ui.comboBox_directory.currentText()),
                            str(self.ui.comboBox_fileName.currentText()))
        return os.path.normpath(name)

    def get_savefig_params(self):
        params = {
            'dpi': self.ui.spinBox_dpi.value(),
            'orientation': self.get_orientation(),
            'format': self.get_file_format()[0],
            'transparent': self.get_transparent(),
            'bbox_inches': self.get_bbox_inches()
        }
        return params

    def get_transparent(self):
        return self.ui.checkBox_transparent.isEnabled(
        ) and self.ui.checkBox_transparent.isChecked()

    def get_file_format(self):
        return IMAGE_FORMATS[self.ui.comboBox_fileType.currentIndex()]

    def get_bbox_inches(self):
        return 'tight' if self.ui.checkBox_tightBbox.isChecked() else None

    def get_orientation(self):
        return self._orientation[self.ui.comboBox_orientation.currentIndex()]

    def keyPressEvent(self, event):
        """Capture and ignore all key press events.

        This is used so that return key event does not trigger any button
        from the dialog. We need to allow the return key to be used in filters
        in the widget."""
        if event.key() == QtCore.Qt.Key_Escape:
            # call reject if Escape is pressed.
            self.reject()
        pass
Esempio n. 12
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()