Exemplo n.º 1
0
    def __init__(self, parent=None):
        super(ProjectsTab, self).__init__(parent)

        # Variables
        self.api = AnacondaAPI()
        self.current_project = None
        self.style_sheet = None
        self.projects = None

        # Widgets
        self.frame_list = FrameEnvironmentsList(self)
        self.frame_widget = FrameEnvironmentsPackages(self)
        self.frame_header_left = FrameTabHeader()
        self.frame_header_right = FrameTabHeader()
        self.button_create = ButtonToolNormal(text="Create")
        self.button_import = ButtonToolNormal(text="Import")
        self.button_remove = ButtonToolNormal(text="Remove")
        self.button_toggle_collapse = ButtonToggleCollapse()
        self.list = ListWidgetEnv()
        self.widget = ProjectsWidget()
        self.menu_list = QMenu()
        self.text_search = LineEditSearch()

        # Widgets setup
        self.frame_list.is_expanded = True
        self.list.setContextMenuPolicy(Qt.CustomContextMenu)
        self.text_search.setPlaceholderText("Search Projects")
        self.button_create.setObjectName("create")
        self.button_import.setObjectName("import")
        self.button_remove.setObjectName("remove")

        # Layouts
        layout_header_left = QVBoxLayout()
        layout_header_left.addWidget(self.text_search)
        self.frame_header_left.setLayout(layout_header_left)

        layout_buttons = QHBoxLayout()
        layout_buttons.addWidget(self.button_create)
        layout_buttons.addWidget(self.button_import)
        layout_buttons.addWidget(self.button_remove)

        layout_list_buttons = QVBoxLayout()
        layout_list_buttons.addWidget(self.frame_header_left)
        layout_list_buttons.addWidget(self.list)
        layout_list_buttons.addLayout(layout_buttons)
        self.frame_list.setLayout(layout_list_buttons)

        layout_widget = QHBoxLayout()
        layout_widget.addWidget(self.widget)
        self.frame_widget.setLayout(layout_widget)

        layout_main = QHBoxLayout()
        layout_main.addWidget(self.frame_list, 10)
        layout_main.addWidget(self.button_toggle_collapse, 1)
        layout_main.addWidget(self.frame_widget, 30)
        self.setLayout(layout_main)

        # Signals
        self.button_toggle_collapse.clicked.connect(self.expand_collapse)
        self.button_create.clicked.connect(self.sig_create_requested)
        self.button_import.clicked.connect(self.sig_import_requested)
        self.button_remove.clicked.connect(self.sig_remove_requested)

        self.list.sig_item_selected.connect(self._item_selected)
        self.text_search.textChanged.connect(self.filter_list)
        self.widget.sig_login_requested.connect(self.sig_login_requested)

        self.refresh()
Exemplo n.º 2
0
class ProjectsTab(WidgetBase):
    """Projects management tab."""
    # name, path, sender
    sig_item_selected = Signal(object, object, object)

    sig_create_requested = Signal()
    sig_import_requested = Signal()
    sig_remove_requested = Signal()
    sig_upload_requested = Signal()

    sig_login_requested = Signal()
    sig_ready = Signal()

    #    sig_apps_changed = Signal(str)
    #    sig_apps_updated = Signal()
    #    sig_project_updated = Signal()
    #    sig_status_updated = Signal(str, int, int, int)

    def __init__(self, parent=None):
        super(ProjectsTab, self).__init__(parent)

        # Variables
        self.api = AnacondaAPI()
        self.current_project = None
        self.style_sheet = None
        self.projects = None

        # Widgets
        self.frame_list = FrameEnvironmentsList(self)
        self.frame_widget = FrameEnvironmentsPackages(self)
        self.frame_header_left = FrameTabHeader()
        self.frame_header_right = FrameTabHeader()
        self.button_create = ButtonToolNormal(text="Create")
        self.button_import = ButtonToolNormal(text="Import")
        self.button_remove = ButtonToolNormal(text="Remove")
        self.button_toggle_collapse = ButtonToggleCollapse()
        self.list = ListWidgetEnv()
        self.widget = ProjectsWidget()
        self.menu_list = QMenu()
        self.text_search = LineEditSearch()

        # Widgets setup
        self.frame_list.is_expanded = True
        self.list.setContextMenuPolicy(Qt.CustomContextMenu)
        self.text_search.setPlaceholderText("Search Projects")
        self.button_create.setObjectName("create")
        self.button_import.setObjectName("import")
        self.button_remove.setObjectName("remove")

        # Layouts
        layout_header_left = QVBoxLayout()
        layout_header_left.addWidget(self.text_search)
        self.frame_header_left.setLayout(layout_header_left)

        layout_buttons = QHBoxLayout()
        layout_buttons.addWidget(self.button_create)
        layout_buttons.addWidget(self.button_import)
        layout_buttons.addWidget(self.button_remove)

        layout_list_buttons = QVBoxLayout()
        layout_list_buttons.addWidget(self.frame_header_left)
        layout_list_buttons.addWidget(self.list)
        layout_list_buttons.addLayout(layout_buttons)
        self.frame_list.setLayout(layout_list_buttons)

        layout_widget = QHBoxLayout()
        layout_widget.addWidget(self.widget)
        self.frame_widget.setLayout(layout_widget)

        layout_main = QHBoxLayout()
        layout_main.addWidget(self.frame_list, 10)
        layout_main.addWidget(self.button_toggle_collapse, 1)
        layout_main.addWidget(self.frame_widget, 30)
        self.setLayout(layout_main)

        # Signals
        self.button_toggle_collapse.clicked.connect(self.expand_collapse)
        self.button_create.clicked.connect(self.sig_create_requested)
        self.button_import.clicked.connect(self.sig_import_requested)
        self.button_remove.clicked.connect(self.sig_remove_requested)

        self.list.sig_item_selected.connect(self._item_selected)
        self.text_search.textChanged.connect(self.filter_list)
        self.widget.sig_login_requested.connect(self.sig_login_requested)

        self.refresh()

    # --- Setup methods
    # -------------------------------------------------------------------------

    def setup(self, projects):
        """Setup tab content and populates the list of projects."""
        self.set_projects(projects=projects)

    def set_projects(self, projects, current_project=None):
        """Populate the list of projects."""
        self.projects = projects
        if current_project is None:
            for (proj_path, proj_name) in projects.items():
                current_project = proj_path
                break

        self.list.clear()
        self.current_project = current_project
        selected_item_row = 0
        for i, (proj_path, proj_name) in enumerate(projects.items()):
            item = ListItemEnv(prefix=proj_path, name=proj_name)

            if proj_path == self.current_project:
                selected_item_row = i
            self.list.addItem(item)

        loading = False
        self.list.setCurrentRow(selected_item_row, loading=loading)
        self.set_project_widget(self.current_project)
        self.filter_list()

    def set_project_widget(self, project_path):
        """Set the project widget."""
        if project_path is None:
            # Disabled widget
            pass
        else:
            self.widget.load_project(project_path)
        self.refresh()
        self.sig_ready.emit()

    def before_delete(self):
        """Prerpare widget before delete."""
        self.widget.before_delete()

    def update_brand(self, brand):
        """Update service brand."""
        self.widget.update_brand(brand)

    # --- Common Helpers (# FIXME: factor out to common base widget)
    # -------------------------------------------------------------------------
    def _item_selected(self, item):
        """Callback to emit signal as user selects an item from the list."""
        prefix = item.prefix()
        self.current_project = prefix
        self.set_loading(prefix)
        self.sig_item_selected.emit(item.name, prefix, C.TAB_PROJECTS)

    def add_temporal_item(self, name):
        """Creates a temporal item on list while creation becomes effective."""
        item_names = [item.name for item in self.list.items()]
        item_names.append(name)
        index = list(sorted(item_names)).index(name) + 1
        item = ListItemEnv(name=name)
        self.list.insertItem(index, item)
        self.list.setCurrentRow(index)
        self.list.scrollToItem(item)
        item.set_loading(True)

    def expand_collapse(self):
        """Expand or collapse the list selector."""
        if self.frame_list.is_expanded:
            self.frame_list.hide()
            self.frame_list.is_expanded = False
        else:
            self.frame_list.show()
            self.frame_list.is_expanded = True

    def filter_list(self, text=None):
        """Filter items in list by name."""
        text = self.text_search.text().lower()
        for i in range(self.list.count()):
            item = self.list.item(i)
            item.setHidden(text not in item.name.lower())

            if not item.widget.isVisible():
                item.widget.repaint()

    def ordered_widgets(self, next_widget=None):
        """Return a list of the ordered widgets."""
        ordered_widgets = [self.text_search]
        ordered_widgets += self.list.ordered_widgets()
        ordered_widgets += [
            self.button_create, self.button_import, self.button_remove
        ]
        ordered_widgets += self.widget.ordered_widgets()
        return ordered_widgets

    def refresh(self):
        """Refresh the enabled/disabled status of the widget and subwidgets."""
        projects = self.projects
        active = bool(projects)
        if not active:
            self.widget.clear()
        self.widget.setVisible(active)
        self.button_remove.setEnabled(active)
        self.widget.setEnabled(active)

    def set_loading(self, prefix=None, value=True):
        """Set the item given by `prefix` to loading state."""
        for row, item in enumerate(self.list.items()):
            if item.prefix == prefix:
                item.set_loading(value)
                self.list.setCurrentRow(row)
                break

    def set_widgets_enabled(self, value):
        """Change the enabled status of widgets and subwidgets."""
        self.list.setEnabled(value)
        self.button_create.setEnabled(value)
        self.button_import.setEnabled(value)
        self.button_remove.setEnabled(value)
        self.widget_projects.set_widgets_enabled(value)
        if value:
            self.refresh()

    @staticmethod
    def update_status(action=None, message=None, value=0, max_value=0):
        """Update status bar."""
        # TODO:!

    def update_style_sheet(self, style_sheet=None):
        """Update custom CSS style sheet."""
        if style_sheet is None:
            self.style_sheet = load_style_sheet()
        else:
            self.style_sheet = style_sheet

        self.setStyleSheet(self.style_sheet)
Exemplo n.º 3
0
    def __init__(self, parent=None):
        super(EnvironmentsTab, self).__init__(parent)

        self.api = AnacondaAPI()
        self.last_env_prefix = None
        self.last_env_name = None
        self.previous_environments = None
        self.tracker = GATracker()
        self.metadata = {}

        active_channels = CONF.get('main',  'conda_active_channels', tuple())
        channels = CONF.get('main',  'conda_channels', tuple())
        conda_url = CONF.get('main',  'conda_url',
                             'https:/conda.anaconda.org')
        conda_api_url = CONF.get('main',  'anaconda_api_url',
                                 'https://api.anaconda.org')

        # Widgets
        self.button_clone = ButtonEnvironmentPrimary("Clone")
        self.button_create = ButtonEnvironmentPrimary("Create")
        self.button_remove = ButtonEnvironmentCancel("Remove")
        self.frame_environments = FrameEnvironments(self)
        self.frame_environments_list = FrameEnvironmentsList(self)
        self.frame_environments_list_buttons = FrameEnvironmentsListButtons(self)
        self.frame_environments_packages = FrameEnvironmentsPackages(self)
        self.list_environments = ListWidgetEnvironment()
        self.packages_widget = CondaPackagesWidget(
            self,
            setup=False,
            active_channels=active_channels,
            channels=channels,
            data_directory=CHANNELS_PATH,
            conda_api_url=conda_api_url,
            conda_url=conda_url)
        self.menu_list = QMenu()
        self.text_search = LineEditSearch()
        self.timer_environments = QTimer()

        # Widgets setup
        self.list_environments.setAttribute(Qt.WA_MacShowFocusRect, False)
        self.list_environments.setContextMenuPolicy(Qt.CustomContextMenu)
        self.packages_widget.textbox_search.setAttribute(
            Qt.WA_MacShowFocusRect, False)
        self.packages_widget.textbox_search.set_icon_visibility(False)
        self.text_search.setPlaceholderText("Search Environments")
        self.text_search.setAttribute(Qt.WA_MacShowFocusRect, False)
        self.timer_environments.setInterval(5000)

        # Layouts
        environments_layout = QVBoxLayout()
        environments_layout.addWidget(self.text_search)

        buttons_layout = QHBoxLayout()
        buttons_layout.addWidget(self.button_create)
        buttons_layout.addWidget(self.button_clone)
        buttons_layout.addWidget(self.button_remove)
        buttons_layout.setContentsMargins(0, 0, 0, 0)

        list_buttons_layout = QVBoxLayout()
        list_buttons_layout.addWidget(self.list_environments)
        list_buttons_layout.addLayout(buttons_layout)
        self.frame_environments_list_buttons.setLayout(list_buttons_layout)
        list_buttons_layout.setContentsMargins(0, 0, 0, 0)
        environments_layout.addWidget(self.frame_environments_list_buttons)

        self.frame_environments_list.setLayout(environments_layout)

        packages_layout = QHBoxLayout()
        packages_layout.addWidget(self.packages_widget)
        packages_layout.setContentsMargins(0, 0, 0, 0)
        self.frame_environments_packages.setLayout(packages_layout)

        main_layout = QHBoxLayout()
        main_layout.addWidget(self.frame_environments_list, 1)
        main_layout.addWidget(self.frame_environments_packages, 3)
        main_layout.setContentsMargins(0, 0, 0, 0)
        self.frame_environments.setLayout(main_layout)

        layout = QHBoxLayout()
        layout.addWidget(self.frame_environments)
        self.setLayout(layout)

        # Signals
        self.button_clone.clicked.connect(self.clone_environment)
        self.button_create.clicked.connect(self.create_environment)
        self.button_remove.clicked.connect(self.remove_environment)
        self.list_environments.sig_item_selected.connect(
            self.load_environment)
        self.packages_widget.sig_packages_ready.connect(self.refresh)
        self.packages_widget.sig_channels_updated.connect(self.update_channels)
#        self.packages_widget.sig_environment_cloned.connect(
#            self._environment_created)
#        self.packages_widget.sig_environment_created.connect(
#            self._environment_created)
#        self.packages_widget.sig_environment_removed.connect(
#            self._environment_removed)
        self.text_search.textChanged.connect(self.filter_environments)
        self.timer_environments.timeout.connect(self.refresh_environments)
        self.packages_widget.sig_process_cancelled.connect(
            lambda: self.update_visibility(True))
Exemplo n.º 4
0
class EnvironmentsTab(WidgetBase):
    """
    This tab holds the list of named and application environments in the local
    machine.

    Available options include, `create`, `clone` and `remove` and package
    management.
    """
    BLACKLIST = ['anaconda-navigator']  # Do not show in package manager.

    sig_status_updated = Signal(object, object, object, object)

    def __init__(self, parent=None):
        super(EnvironmentsTab, self).__init__(parent)

        self.api = AnacondaAPI()
        self.last_env_prefix = None
        self.last_env_name = None
        self.previous_environments = None
        self.tracker = GATracker()
        self.metadata = {}

        active_channels = CONF.get('main',  'conda_active_channels', tuple())
        channels = CONF.get('main',  'conda_channels', tuple())
        conda_url = CONF.get('main',  'conda_url',
                             'https:/conda.anaconda.org')
        conda_api_url = CONF.get('main',  'anaconda_api_url',
                                 'https://api.anaconda.org')

        # Widgets
        self.button_clone = ButtonEnvironmentPrimary("Clone")
        self.button_create = ButtonEnvironmentPrimary("Create")
        self.button_remove = ButtonEnvironmentCancel("Remove")
        self.frame_environments = FrameEnvironments(self)
        self.frame_environments_list = FrameEnvironmentsList(self)
        self.frame_environments_list_buttons = FrameEnvironmentsListButtons(self)
        self.frame_environments_packages = FrameEnvironmentsPackages(self)
        self.list_environments = ListWidgetEnvironment()
        self.packages_widget = CondaPackagesWidget(
            self,
            setup=False,
            active_channels=active_channels,
            channels=channels,
            data_directory=CHANNELS_PATH,
            conda_api_url=conda_api_url,
            conda_url=conda_url)
        self.menu_list = QMenu()
        self.text_search = LineEditSearch()
        self.timer_environments = QTimer()

        # Widgets setup
        self.list_environments.setAttribute(Qt.WA_MacShowFocusRect, False)
        self.list_environments.setContextMenuPolicy(Qt.CustomContextMenu)
        self.packages_widget.textbox_search.setAttribute(
            Qt.WA_MacShowFocusRect, False)
        self.packages_widget.textbox_search.set_icon_visibility(False)
        self.text_search.setPlaceholderText("Search Environments")
        self.text_search.setAttribute(Qt.WA_MacShowFocusRect, False)
        self.timer_environments.setInterval(5000)

        # Layouts
        environments_layout = QVBoxLayout()
        environments_layout.addWidget(self.text_search)

        buttons_layout = QHBoxLayout()
        buttons_layout.addWidget(self.button_create)
        buttons_layout.addWidget(self.button_clone)
        buttons_layout.addWidget(self.button_remove)
        buttons_layout.setContentsMargins(0, 0, 0, 0)

        list_buttons_layout = QVBoxLayout()
        list_buttons_layout.addWidget(self.list_environments)
        list_buttons_layout.addLayout(buttons_layout)
        self.frame_environments_list_buttons.setLayout(list_buttons_layout)
        list_buttons_layout.setContentsMargins(0, 0, 0, 0)
        environments_layout.addWidget(self.frame_environments_list_buttons)

        self.frame_environments_list.setLayout(environments_layout)

        packages_layout = QHBoxLayout()
        packages_layout.addWidget(self.packages_widget)
        packages_layout.setContentsMargins(0, 0, 0, 0)
        self.frame_environments_packages.setLayout(packages_layout)

        main_layout = QHBoxLayout()
        main_layout.addWidget(self.frame_environments_list, 1)
        main_layout.addWidget(self.frame_environments_packages, 3)
        main_layout.setContentsMargins(0, 0, 0, 0)
        self.frame_environments.setLayout(main_layout)

        layout = QHBoxLayout()
        layout.addWidget(self.frame_environments)
        self.setLayout(layout)

        # Signals
        self.button_clone.clicked.connect(self.clone_environment)
        self.button_create.clicked.connect(self.create_environment)
        self.button_remove.clicked.connect(self.remove_environment)
        self.list_environments.sig_item_selected.connect(
            self.load_environment)
        self.packages_widget.sig_packages_ready.connect(self.refresh)
        self.packages_widget.sig_channels_updated.connect(self.update_channels)
#        self.packages_widget.sig_environment_cloned.connect(
#            self._environment_created)
#        self.packages_widget.sig_environment_created.connect(
#            self._environment_created)
#        self.packages_widget.sig_environment_removed.connect(
#            self._environment_removed)
        self.text_search.textChanged.connect(self.filter_environments)
        self.timer_environments.timeout.connect(self.refresh_environments)
        self.packages_widget.sig_process_cancelled.connect(
            lambda: self.update_visibility(True))

    # --- Helpers
    # -------------------------------------------------------------------------
    def update_visibility(self, enabled=True):
        self.button_create.setDisabled(not enabled)
        self.button_remove.setDisabled(not enabled)
        self.button_clone.setDisabled(not enabled)
        self.list_environments.setDisabled(not enabled)
        update_pointer()

    def update_style_sheet(self, style_sheet=None):
        if style_sheet is None:
            style_sheet = load_style_sheet()

        self.setStyleSheet(style_sheet)
        self.menu_list.setStyleSheet(style_sheet)
        self.list_environments.setFrameStyle(QFrame.NoFrame)
        self.list_environments.setFrameShape(QFrame.NoFrame)
        self.packages_widget.table.setFrameStyle(QFrame.NoFrame)
        self.packages_widget.table.setFrameShape(QFrame.NoFrame)
        self.packages_widget.layout().setContentsMargins(0, 0, 0, 0)

        size = QSize(16, 16)

        palette = {
            'icon.action.not_installed': QIcon(images.CONDA_MANAGER_NOT_INSTALLED).pixmap(size),
            'icon.action.installed': QIcon(images.CONDA_MANAGER_INSTALLED).pixmap(size),
            'icon.action.remove': QIcon(images.CONDA_MANAGER_REMOVE).pixmap(size),
            'icon.action.add': QIcon(images.CONDA_MANAGER_ADD).pixmap(size),
            'icon.action.upgrade': QIcon(images.CONDA_MANAGER_UPGRADE).pixmap(size),
            'icon.action.downgrade': QIcon(images.CONDA_MANAGER_DOWNGRADE).pixmap(size),
            'icon.upgrade.arrow': QIcon(images.CONDA_MANAGER_UPGRADE_ARROW).pixmap(size),
            'background.remove': QColor(0, 0, 0, 0),
            'background.install': QColor(0, 0, 0, 0),
            'background.upgrade': QColor(0, 0, 0, 0),
            'background.downgrade': QColor(0, 0, 0, 0),
            'foreground.not.installed': QColor("#666"),
            'foreground.upgrade': QColor("#0071a0"),
            }

        self.packages_widget.update_style_sheet(
            style_sheet=style_sheet,
            extra_dialogs={'cancel_dialog': ClosePackageManagerDialog,
                           'apply_actions_dialog': ActionsDialog,
                           'message_box_error': MessageBoxError,
                           },
            palette=palette,
            )

    def get_environments(self):
        """
        Return an ordered dictionary of all existing named environments as
        keys and the prefix as items.

        The dictionary includes the root environment as the first entry.
        """
        environments = OrderedDict()
        environments_prefix = sorted(self.api.conda_get_envs())
        environments['root'] = self.api.ROOT_PREFIX

        for prefix in environments_prefix:
            name = os.path.basename(prefix)
            environments[name] = prefix

        return environments

    def refresh_environments(self):
        """
        Check every `timer_refresh_envs` amount of miliseconds for newly
        created environments and update the list if new ones are found.
        """
        environments = self.get_environments()
        if self.previous_environments is None:
            self.previous_environments = environments.copy()

        if self.previous_environments != environments:
            self.previous_environments = environments.copy()
            self.setup_tab()

    def open_environment_in(self, which):
        environment_prefix = self.list_environments.currentItem().prefix()
        environment_name = self.list_environments.currentItem().text()
        logger.debug("%s, %s", which, environment_prefix)

        if environment_name == 'root':
            environment_prefix = None

        if which == 'terminal':
            launch.console(environment_prefix)
        else:
            launch.py_in_console(environment_prefix, which)

    def set_last_active_prefix(self):
        current_item = self.list_environments.currentItem()
        if current_item:
            self.last_env_prefix = getattr(current_item, '_prefix')
        else:
            self.last_env_prefix = self.api.ROOT_PREFIX
        CONF.set('main', 'last_active_prefix', self.last_env_prefix)

    def setup_tab(self, metadata={}, load_environment=True):
        if metadata:
            self.metadata = metadata

        # show_apps = CONF.get('main', 'show_application_environments')
        envs = self.get_environments()
        self.timer_environments.start()
        self.menu_list.clear()
        menu_item = self.menu_list.addAction('Open Terminal')
        menu_item.triggered.connect(
            lambda: self.open_environment_in('terminal'))

        for word in ['Python', 'IPython', 'Jupyter Notebook']:
            menu_item = self.menu_list.addAction("Open with " + word)
            menu_item.triggered.connect(
                lambda x, w=word: self.open_environment_in(w.lower()))

        def select(value=None, position=None):
            current_item = self.list_environments.currentItem()
            prefix = current_item.prefix()

            if isinstance(position, bool) or position is None:
                width = current_item.button_options.width()
                position = QPoint(width, 0)

#            parent_position = self.list_environments.mapToGlobal(QPoint(0, 0))
            point = QPoint(0, 0)
            parent_position = current_item.button_options.mapToGlobal(point)
            self.menu_list.move(parent_position + position)
            self.menu_list.actions()[2].setEnabled(
                launch.check_prog('ipython', prefix))
            self.menu_list.actions()[3].setEnabled(
                launch.check_prog('notebook', prefix))
            self.menu_list.exec_()

        self.set_last_active_prefix()
        self.list_environments.clear()

#        if show_apps:
#            separator_item = ListItemSeparator('My environments:')
#            self.list_environments.addItem(separator_item)

        for env in envs:
            prefix = envs[env]
            item = ListItemEnvironment(env, prefix=prefix)
            item.button_options.clicked.connect(select)
            self.list_environments.addItem(item)

#        if show_apps:
#            application_envs = self.api.get_application_environments()
#            separator_item = ListItemSeparator('Application environments:')
#            self.list_environments.addItem(separator_item)
#            for app in application_envs:
#                env_prefix = application_envs[app]
#                item = ListItemEnvironment(name=app, prefix=env_prefix)
#                item.button_options.clicked.connect(select)
#                self.list_environments.addItem(item)

        if load_environment:
            self.load_environment()
        else:
            return

        # Adjust Tab Order
        self.setTabOrder(self.text_search,
                         self.list_environments._items[0].widget)
        for i in range(len(self.list_environments._items) - 1):
            self.setTabOrder(self.list_environments._items[i].widget,
                             self.list_environments._items[i+1].widget)
        self.setTabOrder(self.list_environments._items[-1].button_name,
                         self.button_create)
        self.setTabOrder(self.button_create, self.button_clone)
        self.setTabOrder(self.button_clone, self.button_remove)
        self.setTabOrder(self.button_remove,
                         self.packages_widget.combobox_filter)
        self.setTabOrder(self.packages_widget.combobox_filter,
                         self.packages_widget.button_channels)
        self.setTabOrder(self.packages_widget.button_channels,
                         self.packages_widget.button_update)
        self.setTabOrder(self.packages_widget.button_update,
                         self.packages_widget.textbox_search)
        self.setTabOrder(self.packages_widget.textbox_search,
                         self.packages_widget.table_first_row)
        self.setTabOrder(self.packages_widget.table_last_row,
                         self.packages_widget.button_apply)
        self.setTabOrder(self.packages_widget.button_apply,
                         self.packages_widget.button_clear)
        self.setTabOrder(self.packages_widget.button_clear,
                         self.packages_widget.button_cancel)

    def filter_environments(self):
        """
        Filter displayed environments by matching search text.
        """
        text = self.text_search.text().lower()

        for i in range(self.list_environments.count()):
            item = self.list_environments.item(i)
            item.setHidden(text not in item.text().lower())

            if not item.widget.isVisible():
                item.widget.repaint()

    def load_environment(self, item=None):
        self.update_visibility(False)
        if item is None:
            item = self.list_environments.currentItem()

        if item is None or not isinstance(item, ListItemEnvironment):
            prefix = self.api.ROOT_PREFIX
            index = 0
        elif item and isinstance(item, ListItemEnvironment):
            prefix = item.prefix()
        else:
            prefix = self.last_env_prefix if self.last_env_prefix else None

        index = [i for i, it in enumerate(self.list_environments._items)
                 if prefix in it.prefix()]
        index = index[0] if len(index) else 0

        self.list_environments.setCurrentRow(index)
        self.packages_widget.set_environment(prefix=prefix)
        self.packages_widget.setup(check_updates=False,
                                   blacklist=self.BLACKLIST,
                                   metadata=self.metadata)
        self.list_environments.setDisabled(True)
        self.update_visibility(False)
        self.set_last_active_prefix()
#        update_pointer(Qt.BusyCursor)

    def refresh(self):
        self.update_visibility(True)
        self.list_environments.setDisabled(False)
        item = self.list_environments.currentItem()

        try:
            item.set_loading(False)
        except RuntimeError:
            pass
            # C/C++ object not found

        is_root = item.text() == 'root'

        self.button_remove.setDisabled(is_root)
        self.button_clone.setDisabled(is_root)

    def update_channels(self, channels, active_channels):
        """
        Save updated channels to the CONF.
        """
        CONF.set('main', 'conda_active_channels', active_channels)
        CONF.set('main', 'conda_channels', channels)

    # --- Callbacks
    # -------------------------------------------------------------------------
    def _environment_created(self, worker, output, error):
        if error:
            logger.error(str(error))

        self.update_visibility(False)
        for row, environment in enumerate(self.get_environments()):
            if worker.name == environment:
                break

        self.last_env_prefix = self.api.conda_get_prefix_envname(environment)
        self.setup_tab(load_environment=False)
        self.list_environments.setCurrentRow(row)
        self.load_environment()
        self.refresh()
        self.update_visibility(True)
        update_pointer()

    def _environment_removed(self, worker, output, error):
        self.update_visibility(True)
        if error:
            logger.error(str(error))

        self.setup_tab()
        self.list_environments.setCurrentRow(0)

    # --- Public API
    # -------------------------------------------------------------------------
    def update_domains(self, anaconda_api_url, conda_url):
        self.packages_widget.update_domains(
            anaconda_api_url=anaconda_api_url,
            conda_url=conda_url,
            )

    def create_environment(self):
        """
        Create new basic environment with selectable python version.

        Actually makes new env on disc, in directory within the project
        whose name depends on the env name. New project state is saved.
        Should also sync to spec file.
        """
        dlg = CreateEnvironmentDialog(parent=self,
                                      environments=self.get_environments())
        self.tracker.track_page('/environments/create',
                                pagetitle='Create new environment dialog')

        if dlg.exec_():
            name = dlg.text_name.text().strip()
            pyver = dlg.combo_version.currentText()

            if name:
                logger.debug(str('{0}, {1}'.format(name, pyver)))

                self.update_visibility(False)
                update_pointer(Qt.BusyCursor)

                if pyver:
                    pkgs = ['python=' + pyver, 'jupyter']
                else:
                    pkgs = ['jupyter']

                channels = self.packages_widget._active_channels
                logger.debug(str((name, pkgs, channels)))
                self.update_visibility(False)
                worker = self.packages_widget.create_environment(name=name, 
                                                                 packages=pkgs)
#                worker = self.api.conda_create(name=name, pkgs=pkgs,
#                                               channels=channels)
                worker.name = name
                worker.sig_finished.connect(self._environment_created)
        self.tracker.track_page('/environments')

    def remove_environment(self):
        """
        Clone currently selected environment.
        """
        current_item = self.list_environments.currentItem()
        if current_item is not None:
            name = current_item.text()

            if name == 'root':
                return

            dlg = RemoveEnvironmentDialog(environment=name)
            self.tracker.track_page('/environments/remove',
                                    pagetitle='Remove environment dialog')
            if dlg.exec_():
                logger.debug(str(name))
                self.update_visibility(False)
                update_pointer(Qt.BusyCursor)
                worker = self.packages_widget.remove_environment(name=name)
#                worker = self.api.conda_remove(name=name, all_=True)
                worker.sig_finished.connect(self._environment_removed)
#                self.sig_status_updated.emit('Deleting environment '
#                                             '"{0}"'.format(name),
#                                             0, -1, -1)
            self.tracker.track_page('/environments')

    def clone_environment(self):
        """
        Clone currently selected environment.
        """
        current_item = self.list_environments.currentItem()
        if current_item is not None:
            current_name = current_item.text()
            dlg = CloneEnvironmentDialog(parent=self,
                                         environments=self.get_environments())
            self.tracker.track_page('/environments/clone',
                                    pagetitle='Clone environment dialog')

            if dlg.exec_():
                name = dlg.text_name.text().strip()

                if name and current_name:
                    logger.debug(str("{0}, {1}".format(current_name, name)))

                    self.update_visibility(False)
                    update_pointer(Qt.BusyCursor)
                    worker = self.packages_widget.clone_environment(clone=current_name,
                                                                    name=name)
#                    worker = self.api.conda_clone(current_name, name=name)
                    worker.name = name
                    worker.sig_finished.connect(self._environment_created)
            self.tracker.track_page('/environments')

    def import_environment(self):
        """
Exemplo n.º 5
0
    def __init__(self, parent=None):
        """Conda environments tab."""
        super(EnvironmentsTab, self).__init__(parent)

        # Variables
        self.api = AnacondaAPI()
        self.current_prefix = None
        self.style_sheet = None

        # Widgets
        self.frame_header_left = FrameTabHeader()
        self.frame_list = FrameEnvironmentsList(self)
        self.frame_widget = FrameEnvironmentsPackages(self)
        self.text_search = LineEditSearch()
        self.list = ListWidgetEnv()
        self.menu_list = QMenu()
        self.button_create = ButtonToolNormal(text="Create")
        self.button_clone = ButtonToolNormal(text="Clone")
        self.button_import = ButtonToolNormal(text="Import")
        self.button_remove = ButtonToolNormal(text="Remove")
        self.button_toggle_collapse = ButtonToggleCollapse()
        self.widget = CondaPackagesWidget(parent=self)

        # Widgets setup
        self.frame_list.is_expanded = True
        self.text_search.setPlaceholderText("Search Environments")
        self.list.setContextMenuPolicy(Qt.CustomContextMenu)
        self.button_create.setObjectName("create")  # Needed for QSS selectors
        self.button_clone.setObjectName("clone")
        self.button_import.setObjectName("import")
        self.button_remove.setObjectName("remove")
        self.widget.textbox_search.set_icon_visibility(False)

        # Layouts
        layout_header_left = QVBoxLayout()
        layout_header_left.addWidget(self.text_search)
        self.frame_header_left.setLayout(layout_header_left)

        layout_buttons = QHBoxLayout()
        layout_buttons.addWidget(self.button_create)
        layout_buttons.addWidget(self.button_clone)
        layout_buttons.addWidget(self.button_import)
        layout_buttons.addWidget(self.button_remove)

        layout_list_buttons = QVBoxLayout()
        layout_list_buttons.addWidget(self.frame_header_left)
        layout_list_buttons.addWidget(self.list)
        layout_list_buttons.addLayout(layout_buttons)
        self.frame_list.setLayout(layout_list_buttons)

        layout_widget = QHBoxLayout()
        layout_widget.addWidget(self.widget)
        self.frame_widget.setLayout(layout_widget)

        layout_main = QHBoxLayout()
        layout_main.addWidget(self.frame_list, 10)
        layout_main.addWidget(self.button_toggle_collapse, 1)
        layout_main.addWidget(self.frame_widget, 30)

        self.setLayout(layout_main)

        # Signals for buttons and boxes
        self.button_toggle_collapse.clicked.connect(self.expand_collapse)
        self.button_create.clicked.connect(self.sig_create_requested)
        self.button_clone.clicked.connect(self.sig_clone_requested)
        self.button_import.clicked.connect(self.sig_import_requested)
        self.button_remove.clicked.connect(self.sig_remove_requested)
        self.text_search.textChanged.connect(self.filter_list)

        # Signals for list
        self.list.sig_item_selected.connect(self._item_selected)

        # Signals for packages widget
        self.widget.sig_ready.connect(self.sig_ready)
        self.widget.sig_channels_requested.connect(self.sig_channels_requested)
        self.widget.sig_update_index_requested.connect(
            self.sig_update_index_requested)
        self.widget.sig_cancel_requested.connect(self.sig_cancel_requested)
        self.widget.sig_packages_action_requested.connect(
            self.sig_packages_action_requested)
Exemplo n.º 6
0
class EnvironmentsTab(WidgetBase):
    """Conda environments tab."""
    BLACKLIST = ['anaconda-navigator', '_license']  # Hide in package manager

    # --- Signals
    # -------------------------------------------------------------------------
    sig_ready = Signal()

    # name, prefix, sender
    sig_item_selected = Signal(object, object, object)

    # sender, func_after_dlg_accept, func_callback_on_finished
    sig_create_requested = Signal()
    sig_clone_requested = Signal()
    sig_import_requested = Signal()
    sig_remove_requested = Signal()

    # button_widget, sender_constant
    sig_channels_requested = Signal(object, object)

    # sender_constant
    sig_update_index_requested = Signal(object)
    sig_cancel_requested = Signal(object)

    # conda_packages_action_dict, pip_packages_action_dict
    sig_packages_action_requested = Signal(object, object)

    def __init__(self, parent=None):
        """Conda environments tab."""
        super(EnvironmentsTab, self).__init__(parent)

        # Variables
        self.api = AnacondaAPI()
        self.current_prefix = None
        self.style_sheet = None

        # Widgets
        self.frame_header_left = FrameTabHeader()
        self.frame_list = FrameEnvironmentsList(self)
        self.frame_widget = FrameEnvironmentsPackages(self)
        self.text_search = LineEditSearch()
        self.list = ListWidgetEnv()
        self.menu_list = QMenu()
        self.button_create = ButtonToolNormal(text="Create")
        self.button_clone = ButtonToolNormal(text="Clone")
        self.button_import = ButtonToolNormal(text="Import")
        self.button_remove = ButtonToolNormal(text="Remove")
        self.button_toggle_collapse = ButtonToggleCollapse()
        self.widget = CondaPackagesWidget(parent=self)

        # Widgets setup
        self.frame_list.is_expanded = True
        self.text_search.setPlaceholderText("Search Environments")
        self.list.setContextMenuPolicy(Qt.CustomContextMenu)
        self.button_create.setObjectName("create")  # Needed for QSS selectors
        self.button_clone.setObjectName("clone")
        self.button_import.setObjectName("import")
        self.button_remove.setObjectName("remove")
        self.widget.textbox_search.set_icon_visibility(False)

        # Layouts
        layout_header_left = QVBoxLayout()
        layout_header_left.addWidget(self.text_search)
        self.frame_header_left.setLayout(layout_header_left)

        layout_buttons = QHBoxLayout()
        layout_buttons.addWidget(self.button_create)
        layout_buttons.addWidget(self.button_clone)
        layout_buttons.addWidget(self.button_import)
        layout_buttons.addWidget(self.button_remove)

        layout_list_buttons = QVBoxLayout()
        layout_list_buttons.addWidget(self.frame_header_left)
        layout_list_buttons.addWidget(self.list)
        layout_list_buttons.addLayout(layout_buttons)
        self.frame_list.setLayout(layout_list_buttons)

        layout_widget = QHBoxLayout()
        layout_widget.addWidget(self.widget)
        self.frame_widget.setLayout(layout_widget)

        layout_main = QHBoxLayout()
        layout_main.addWidget(self.frame_list, 10)
        layout_main.addWidget(self.button_toggle_collapse, 1)
        layout_main.addWidget(self.frame_widget, 30)

        self.setLayout(layout_main)

        # Signals for buttons and boxes
        self.button_toggle_collapse.clicked.connect(self.expand_collapse)
        self.button_create.clicked.connect(self.sig_create_requested)
        self.button_clone.clicked.connect(self.sig_clone_requested)
        self.button_import.clicked.connect(self.sig_import_requested)
        self.button_remove.clicked.connect(self.sig_remove_requested)
        self.text_search.textChanged.connect(self.filter_list)

        # Signals for list
        self.list.sig_item_selected.connect(self._item_selected)

        # Signals for packages widget
        self.widget.sig_ready.connect(self.sig_ready)
        self.widget.sig_channels_requested.connect(self.sig_channels_requested)
        self.widget.sig_update_index_requested.connect(
            self.sig_update_index_requested)
        self.widget.sig_cancel_requested.connect(self.sig_cancel_requested)
        self.widget.sig_packages_action_requested.connect(
            self.sig_packages_action_requested)

    # --- Setup methods
    # -------------------------------------------------------------------------
    def setup(self, conda_data):
        """Setup tab content and populates the list of environments."""
        self.set_widgets_enabled(False)
        conda_processed_info = conda_data.get('processed_info')
        environments = conda_processed_info.get('__environments')
        packages = conda_data.get('packages')
        self.current_prefix = conda_processed_info.get('default_prefix')
        self.set_environments(environments)
        self.set_packages(packages)

    def set_environments(self, environments):
        """Populate the list of environments."""
        self.list.clear()
        selected_item_row = 0
        for i, (env_prefix, env_name) in enumerate(environments.items()):
            item = ListItemEnv(prefix=env_prefix, name=env_name)
            item.button_options.clicked.connect(self.show_environment_menu)
            if env_prefix == self.current_prefix:
                selected_item_row = i
            self.list.addItem(item)

        self.list.setCurrentRow(selected_item_row, loading=True)
        self.filter_list()

    def _set_packages(self, worker, output, error):
        """Set packages callback."""
        packages, model_data = output
        self.widget.setup(packages, model_data)
        self.set_widgets_enabled(True)
        self.set_loading(prefix=self.current_prefix, value=False)

    def set_packages(self, packages):
        """Set packages widget content."""
        worker = self.api.process_packages(packages,
                                           prefix=self.current_prefix,
                                           blacklist=self.BLACKLIST)
        worker.sig_chain_finished.connect(self._set_packages)

    def show_environment_menu(self, value=None, position=None):
        """Show the environment actions menu."""
        self.menu_list.clear()
        menu_item = self.menu_list.addAction('Open Terminal')
        menu_item.triggered.connect(
            lambda: self.open_environment_in('terminal'))

        for word in ['Python', 'IPython', 'Jupyter Notebook']:
            menu_item = self.menu_list.addAction("Open with " + word)
            menu_item.triggered.connect(
                lambda x, w=word: self.open_environment_in(w.lower()))

        current_item = self.list.currentItem()
        prefix = current_item.prefix

        if isinstance(position, bool) or position is None:
            width = current_item.button_options.width()
            position = QPoint(width, 0)

        point = QPoint(0, 0)
        parent_position = current_item.button_options.mapToGlobal(point)
        self.menu_list.move(parent_position + position)

        # Disabled actions depending on the environment installed packages
        actions = self.menu_list.actions()
        actions[2].setEnabled(launch.check_prog('ipython', prefix))
        actions[3].setEnabled(launch.check_prog('notebook', prefix))

        self.menu_list.exec_()

    def open_environment_in(self, which):
        """Open selected environment in console terminal."""
        prefix = self.list.currentItem().prefix
        logger.debug("%s, %s", which, prefix)

        if which == 'terminal':
            launch.console(prefix)
        else:
            launch.py_in_console(prefix, which)

    # --- Common Helpers (# FIXME: factor out to common base widget)
    # -------------------------------------------------------------------------
    def _item_selected(self, item):
        """Callback to emit signal as user selects an item from the list."""
        self.set_loading(prefix=item.prefix)
        self.sig_item_selected.emit(item.name, item.prefix, C.TAB_ENVIRONMENT)

    def add_temporal_item(self, name):
        """Creates a temporal item on list while creation becomes effective."""
        item_names = [item.name for item in self.list.items()]
        item_names.append(name)
        index = list(sorted(item_names)).index(name) + 1
        item = ListItemEnv(name=name)
        self.list.insertItem(index, item)
        self.list.setCurrentRow(index)
        self.list.scrollToItem(item)
        item.set_loading(True)

    def expand_collapse(self):
        """Expand or collapse the list selector."""
        if self.frame_list.is_expanded:
            self.frame_list.hide()
            self.frame_list.is_expanded = False
        else:
            self.frame_list.show()
            self.frame_list.is_expanded = True

    def filter_list(self, text=None):
        """Filter items in list by name."""
        text = self.text_search.text().lower()
        for i in range(self.list.count()):
            item = self.list.item(i)
            item.setHidden(text not in item.name.lower())

            if not item.widget.isVisible():
                item.widget.repaint()

    def ordered_widgets(self, next_widget=None):
        """Return a list of the ordered widgets."""
        if next_widget is not None:
            self.widget.table_last_row.add_focus_widget(next_widget)

        ordered_widgets = [
            self.text_search,
        ]
        ordered_widgets += self.list.ordered_widgets()
        ordered_widgets += [
            self.button_create,
            self.button_clone,
            self.button_import,
            self.button_remove,
            self.widget.combobox_filter,
            self.widget.button_channels,
            self.widget.button_update,
            self.widget.textbox_search,
            # self.widget.table_first_row,
            self.widget.table,
            self.widget.table_last_row,
            self.widget.button_apply,
            self.widget.button_clear,
            self.widget.button_cancel,
        ]
        return ordered_widgets

    def refresh(self):
        """Refresh the enabled/disabled status of the widget and subwidgets."""
        is_root = self.current_prefix == self.api.ROOT_PREFIX
        self.button_clone.setDisabled(is_root)
        self.button_remove.setDisabled(is_root)

    def set_loading(self, prefix=None, value=True):
        """Set the item given by `prefix` to loading state."""
        for row, item in enumerate(self.list.items()):
            if item.prefix == prefix:
                item.set_loading(value)
                self.list.setCurrentRow(row)
                break

    def set_widgets_enabled(self, value):
        """Change the enabled status of widgets and subwidgets."""
        self.list.setEnabled(value)
        self.button_create.setEnabled(value)
        self.button_clone.setEnabled(value)
        self.button_import.setEnabled(value)
        self.button_remove.setEnabled(value)
        self.widget.set_widgets_enabled(value)
        if value:
            self.refresh()

    def update_status(self, action='', message='', value=None, max_value=None):
        """Update widget status and progress bar."""
        self.widget.update_status(action=action,
                                  message=message,
                                  value=value,
                                  max_value=max_value)

    def update_style_sheet(self, style_sheet=None):
        """Update custom CSS stylesheet."""
        if style_sheet is None:
            self.style_sheet = load_style_sheet()
        else:
            self.style_sheet = style_sheet

        self.setStyleSheet(self.style_sheet)
        self.list.update_style_sheet(self.style_sheet)
        self.menu_list.setStyleSheet(self.style_sheet)