class WorkingDirectory(QToolBar, SpyderPluginMixin): """ Working directory changer widget """ CONF_SECTION = 'workingdir' CONFIGWIDGET_CLASS = WorkingDirectoryConfigPage LOG_PATH = get_conf_path(CONF_SECTION) sig_option_changed = Signal(str, object) set_previous_enabled = Signal(bool) set_next_enabled = Signal(bool) redirect_stdio = Signal(bool) set_explorer_cwd = Signal(str) refresh_findinfiles = Signal() set_current_console_wd = Signal(str) def __init__(self, parent, workdir=None, **kwds): if PYQT5: super(WorkingDirectory, self).__init__(parent, **kwds) else: QToolBar.__init__(self, parent) SpyderPluginMixin.__init__(self, parent) # Initialize plugin self.initialize_plugin() self.setWindowTitle(self.get_plugin_title()) # Toolbar title self.setObjectName( self.get_plugin_title()) # Used to save Window state # Previous dir action self.history = [] self.histindex = None self.previous_action = create_action(self, "previous", None, ima.icon('previous'), _('Back'), triggered=self.previous_directory) self.addAction(self.previous_action) # Next dir action self.history = [] self.histindex = None self.next_action = create_action(self, "next", None, ima.icon('next'), _('Next'), triggered=self.next_directory) self.addAction(self.next_action) # Enable/disable previous/next actions self.set_previous_enabled.connect(self.previous_action.setEnabled) self.set_next_enabled.connect(self.next_action.setEnabled) # Path combo box adjust = self.get_option('working_dir_adjusttocontents') self.pathedit = PathComboBox(self, adjust_to_contents=adjust) self.pathedit.setToolTip( _("This is the working directory for newly\n" "opened consoles (Python/IPython consoles and\n" "terminals), for the file explorer, for the\n" "find in files plugin and for new files\n" "created in the editor")) self.pathedit.open_dir.connect(self.chdir) self.pathedit.activated[str].connect(self.chdir) self.pathedit.setMaxCount(self.get_option('working_dir_history')) wdhistory = self.load_wdhistory(workdir) if workdir is None: if self.get_option('console/use_project_or_home_directory'): workdir = get_home_dir() else: workdir = self.get_option('console/fixed_directory', default='') if not osp.isdir(workdir): workdir = get_home_dir() self.chdir(workdir) self.pathedit.addItems(wdhistory) self.pathedit.selected_text = self.pathedit.currentText() self.refresh_plugin() self.addWidget(self.pathedit) # Browse action browse_action = create_action(self, "browse", None, ima.icon('DirOpenIcon'), _('Browse a working directory'), triggered=self.select_directory) self.addAction(browse_action) # Parent dir action parent_action = create_action(self, "parent", None, ima.icon('up'), _('Change to parent directory'), triggered=self.parent_directory) self.addAction(parent_action) #------ SpyderPluginWidget API --------------------------------------------- def get_plugin_title(self): """Return widget title""" return _('Current working directory') def get_plugin_icon(self): """Return widget icon""" return ima.icon('DirOpenIcon') def get_plugin_actions(self): """Setup actions""" return (None, None) def register_plugin(self): """Register plugin in Spyder's main window""" self.redirect_stdio.connect(self.main.redirect_internalshell_stdio) self.main.console.shell.refresh.connect(self.refresh_plugin) iconsize = 24 self.setIconSize(QSize(iconsize, iconsize)) self.main.addToolBar(self) def refresh_plugin(self): """Refresh widget""" curdir = getcwd_or_home() self.pathedit.add_text(curdir) self.save_wdhistory() self.set_previous_enabled.emit(self.histindex is not None and self.histindex > 0) self.set_next_enabled.emit(self.histindex is not None and \ self.histindex < len(self.history)-1) def apply_plugin_settings(self, options): """Apply configuration file's plugin settings""" pass def closing_plugin(self, cancelable=False): """Perform actions before parent main window is closed""" return True #------ Public API --------------------------------------------------------- def load_wdhistory(self, workdir=None): """Load history from a text file in user home directory""" if osp.isfile(self.LOG_PATH): wdhistory, _ = encoding.readlines(self.LOG_PATH) wdhistory = [name for name in wdhistory if os.path.isdir(name)] else: if workdir is None: workdir = get_home_dir() wdhistory = [workdir] return wdhistory def save_wdhistory(self): """Save history to a text file in user home directory""" text = [ to_text_string( self.pathedit.itemText(index) ) \ for index in range(self.pathedit.count()) ] encoding.writelines(text, self.LOG_PATH) @Slot() def select_directory(self): """Select directory""" self.redirect_stdio.emit(False) directory = getexistingdirectory(self.main, _("Select directory"), getcwd_or_home()) if directory: self.chdir(directory) self.redirect_stdio.emit(True) @Slot() def previous_directory(self): """Back to previous directory""" self.histindex -= 1 self.chdir(directory='', browsing_history=True) @Slot() def next_directory(self): """Return to next directory""" self.histindex += 1 self.chdir(directory='', browsing_history=True) @Slot() def parent_directory(self): """Change working directory to parent directory""" self.chdir(os.path.join(getcwd_or_home(), os.path.pardir)) @Slot(str) @Slot(str, bool) @Slot(str, bool, bool) @Slot(str, bool, bool, bool) def chdir(self, directory, browsing_history=False, refresh_explorer=True, refresh_console=True): """Set directory as working directory""" if directory: directory = osp.abspath(to_text_string(directory)) # Working directory history management if browsing_history: directory = self.history[self.histindex] elif directory in self.history: self.histindex = self.history.index(directory) else: if self.histindex is None: self.history = [] else: self.history = self.history[:self.histindex + 1] self.history.append(directory) self.histindex = len(self.history) - 1 # Changing working directory try: os.chdir(directory) if refresh_explorer: self.set_explorer_cwd.emit(directory) if refresh_console: self.set_current_console_wd.emit(directory) self.refresh_findinfiles.emit() except OSError: self.history.pop(self.histindex) self.refresh_plugin()
class WorkingDirectoryContainer(PluginMainContainer): """ """ DEFAULT_OPTIONS = { 'history': [], 'console/fixed_directory': '', 'console/use_cwd': True, 'console/use_project_or_home_directory': False, 'startup/fixed_directory': '', 'startup/use_fixed_directory': False, 'workdir': None, 'working_dir_adjusttocontents': False, 'working_dir_history': 20, } # Signals sig_current_directory_changed = Signal(str) """ This signal is emitted when the current directory has changed. Parameters ---------- new_working_directory: str The new new working directory path. """ def __init__(self, name, plugin, parent=None, options=DEFAULT_OPTIONS): super().__init__(name, plugin, parent=parent, options=options) # Variables self.history = self.get_option('history') self.histindex = None # Widgets title = _('Current working directory') self.toolbar = ApplicationToolBar(self, title) self.pathedit = PathComboBox( self, adjust_to_contents=self.get_option('working_dir_adjusttocontents'), ) # Widget Setup self.toolbar.setWindowTitle(title) self.toolbar.setObjectName(title) self.pathedit.setToolTip( _("This is the working directory for newly\n" "opened consoles (Python/IPython consoles and\n" "terminals), for the file explorer, for the\n" "find in files plugin and for new files\n" "created in the editor")) self.pathedit.setMaxCount(self.get_option('working_dir_history')) self.pathedit.selected_text = self.pathedit.currentText() # Signals self.pathedit.open_dir.connect(self.chdir) self.pathedit.activated[str].connect(self.chdir) # --- PluginWidget API # ------------------------------------------------------------------------ def setup(self, options=DEFAULT_OPTIONS): self.previous_action = self.create_action( WorkingDirectoryActions.Previous, text=_('Back'), tip=_('Back'), icon=self.create_icon('previous'), triggered=self.previous_directory, ) self.next_action = self.create_action( WorkingDirectoryActions.Next, text=_('Next'), tip=_('Next'), icon=self.create_icon('next'), triggered=self.next_directory, ) browse_action = self.create_action( WorkingDirectoryActions.Browse, text=_('Browse a working directory'), tip=_('Browse a working directory'), icon=self.create_icon('DirOpenIcon'), triggered=self.select_directory, ) parent_action = self.create_action( WorkingDirectoryActions.Parent, text=_('Change to parent directory'), tip=_('Change to parent directory'), icon=self.create_icon('up'), triggered=self.parent_directory, ) for item in [ self.previous_action, self.next_action, self.pathedit, browse_action, parent_action ]: self.add_item_to_toolbar( item, self.toolbar, section=WorkingDirectoryToolBarSections.Main, ) def update_actions(self): self.previous_action.setEnabled(self.histindex is not None and self.histindex > 0) self.next_action.setEnabled(self.histindex is not None and self.histindex < len(self.history) - 1) def on_option_update(self, option, value): if option == 'history': self.history = value # --- API # ------------------------------------------------------------------------ def get_workdir(self): """ Get the working directory from our config system or return the user home directory if none could be found. Returns ------- str: The current working directory. """ if self.get_option('startup/use_fixed_directory'): workdir = self.get_option('startup/fixed_directory') elif self.get_option('console/use_project_or_home_directory'): workdir = get_home_dir() else: workdir = self.get_option('console/fixed_directory') if not osp.isdir(workdir): workdir = get_home_dir() return workdir @Slot() def select_directory(self, directory=None): """ Select working directory. Parameters ---------- directory: str, optional The directory to change to. Notes ----- If directory is None, a get directorty dialog will be used. """ if directory is None: self.sig_redirect_stdio_requested.emit(False) directory = getexistingdirectory( self, _("Select directory"), getcwd_or_home(), ) self.sig_redirect_stdio_requested.emit(True) if directory: self.chdir(directory) @Slot() def previous_directory(self): """Select the previous directory.""" self.histindex -= 1 self.chdir(directory='', browsing_history=True) @Slot() def next_directory(self): """Select the next directory.""" self.histindex += 1 self.chdir(directory='', browsing_history=True) @Slot() def parent_directory(self): """Change working directory to parent one.""" self.chdir(osp.join(getcwd_or_home(), osp.pardir)) @Slot(str) @Slot(str, bool) @Slot(str, bool, bool) def chdir(self, directory, browsing_history=False, emit=True): """ Set `directory` as working directory. Parameters ---------- directory: str The new working directory. browsing_history: bool, optional Add the new `directory` to the browsing history. Default is False. emit: bool, optional Emit a signal when changing the working directory. Default is True. """ if directory: directory = osp.abspath(str(directory)) # Working directory history management if browsing_history: directory = self.history[self.histindex] elif directory in self.history: self.histindex = self.history.index(directory) else: if self.histindex is None: self.history = [] else: self.history = self.history[:self.histindex + 1] self.history.append(directory) self.histindex = len(self.history) - 1 # Changing working directory try: os.chdir(directory) self.pathedit.add_text(directory) self.update_actions() if emit: self.sig_current_directory_changed.emit(directory) except OSError: self.history.pop(self.histindex) def get_history(self): """ Get the current history list. Returns ------- list List of string paths. """ return [ str(self.pathedit.itemText(index)) for index in range(self.pathedit.count()) ] def set_history(self, history): """ Set the current history list. Parameters ---------- history: list List of string paths. """ self.change_option('history', history) if history: self.pathedit.addItems(history) if self.get_option('workdir') is None: workdir = self.get_workdir() else: workdir = self.get_option('workdir') self.chdir(workdir)
class WorkingDirectory(SpyderPluginWidget): """Working directory changer plugin.""" CONF_SECTION = 'workingdir' CONFIGWIDGET_CLASS = WorkingDirectoryConfigPage LOG_PATH = get_conf_path(CONF_SECTION) set_previous_enabled = Signal(bool) set_next_enabled = Signal(bool) redirect_stdio = Signal(bool) set_explorer_cwd = Signal(str) refresh_findinfiles = Signal() set_current_console_wd = Signal(str) def __init__(self, parent, workdir=None, **kwds): SpyderPluginWidget.__init__(self, parent) self.hide() self.toolbar = QToolBar(self) # Initialize plugin self.initialize_plugin() self.options_button.hide() self.toolbar.setWindowTitle(self.get_plugin_title()) # Used to save Window state self.toolbar.setObjectName(self.get_plugin_title()) # Previous dir action self.history = [] self.histindex = None self.previous_action = create_action(self, "previous", None, ima.icon('previous'), _('Back'), triggered=self.previous_directory) self.toolbar.addAction(self.previous_action) # Next dir action self.next_action = create_action(self, "next", None, ima.icon('next'), _('Next'), triggered=self.next_directory) self.toolbar.addAction(self.next_action) # Enable/disable previous/next actions self.set_previous_enabled.connect(self.previous_action.setEnabled) self.set_next_enabled.connect(self.next_action.setEnabled) # Path combo box adjust = self.get_option('working_dir_adjusttocontents') self.pathedit = PathComboBox(self, adjust_to_contents=adjust) self.pathedit.setToolTip(_("This is the working directory for newly\n" "opened consoles (Python/IPython consoles and\n" "terminals), for the file explorer, for the\n" "find in files plugin and for new files\n" "created in the editor")) self.pathedit.open_dir.connect(self.chdir) self.pathedit.activated[str].connect(self.chdir) self.pathedit.setMaxCount(self.get_option('working_dir_history')) wdhistory = self.load_wdhistory(workdir) if workdir is None: if self.get_option('console/use_project_or_home_directory'): workdir = get_home_dir() else: workdir = self.get_option('console/fixed_directory', default='') if not osp.isdir(workdir): workdir = get_home_dir() self.chdir(workdir) self.pathedit.addItems(wdhistory) self.pathedit.selected_text = self.pathedit.currentText() self.refresh_plugin() self.toolbar.addWidget(self.pathedit) # Browse action browse_action = create_action(self, "browse", None, ima.icon('DirOpenIcon'), _('Browse a working directory'), triggered=self.select_directory) self.toolbar.addAction(browse_action) # Parent dir action parent_action = create_action(self, "parent", None, ima.icon('up'), _('Change to parent directory'), triggered=self.parent_directory) self.toolbar.addAction(parent_action) #------ SpyderPluginWidget API --------------------------------------------- def get_plugin_title(self): """Return widget title""" return _('Current working directory') def get_plugin_icon(self): """Return widget icon""" return ima.icon('DirOpenIcon') def get_plugin_actions(self): """Setup actions""" return [None, None] def register_plugin(self): """Register plugin in Spyder's main window""" self.redirect_stdio.connect(self.main.redirect_internalshell_stdio) self.main.console.shell.refresh.connect(self.refresh_plugin) iconsize = 24 self.toolbar.setIconSize(QSize(iconsize, iconsize)) self.main.addToolBar(self.toolbar) def refresh_plugin(self): """Refresh widget""" curdir = getcwd_or_home() self.pathedit.add_text(curdir) self.save_wdhistory() self.set_previous_enabled.emit( self.histindex is not None and self.histindex > 0) self.set_next_enabled.emit(self.histindex is not None and \ self.histindex < len(self.history)-1) def apply_plugin_settings(self, options): """Apply configuration file's plugin settings""" pass def closing_plugin(self, cancelable=False): """Perform actions before parent main window is closed""" return True #------ Public API --------------------------------------------------------- def load_wdhistory(self, workdir=None): """Load history from a text file in user home directory""" if osp.isfile(self.LOG_PATH): wdhistory, _ = encoding.readlines(self.LOG_PATH) wdhistory = [name for name in wdhistory if os.path.isdir(name)] else: if workdir is None: workdir = get_home_dir() wdhistory = [ workdir ] return wdhistory def save_wdhistory(self): """Save history to a text file in user home directory""" text = [ to_text_string( self.pathedit.itemText(index) ) \ for index in range(self.pathedit.count()) ] try: encoding.writelines(text, self.LOG_PATH) except EnvironmentError: pass @Slot() def select_directory(self): """Select directory""" self.redirect_stdio.emit(False) directory = getexistingdirectory(self.main, _("Select directory"), getcwd_or_home()) if directory: self.chdir(directory) self.redirect_stdio.emit(True) @Slot() def previous_directory(self): """Back to previous directory""" self.histindex -= 1 self.chdir(directory='', browsing_history=True) @Slot() def next_directory(self): """Return to next directory""" self.histindex += 1 self.chdir(directory='', browsing_history=True) @Slot() def parent_directory(self): """Change working directory to parent directory""" self.chdir(os.path.join(getcwd_or_home(), os.path.pardir)) @Slot(str) @Slot(str, bool) @Slot(str, bool, bool) @Slot(str, bool, bool, bool) def chdir(self, directory, browsing_history=False, refresh_explorer=True, refresh_console=True): """Set directory as working directory""" if directory: directory = osp.abspath(to_text_string(directory)) # Working directory history management if browsing_history: directory = self.history[self.histindex] elif directory in self.history: self.histindex = self.history.index(directory) else: if self.histindex is None: self.history = [] else: self.history = self.history[:self.histindex+1] self.history.append(directory) self.histindex = len(self.history)-1 # Changing working directory try: os.chdir(directory) if refresh_explorer: self.set_explorer_cwd.emit(directory) if refresh_console: self.set_current_console_wd.emit(directory) self.refresh_findinfiles.emit() except OSError: self.history.pop(self.histindex) self.refresh_plugin()