Exemple #1
0
class ProgressView(QWidget):
    def __init__(self, parent=None) -> None:
        super(ProgressView, self).__init__(parent)

        self._progress_tree_view = QTreeView(self)
        self._progress_tree_view.setHeaderHidden(True)
        self._progress_tree_view.setItemsExpandable(False)
        self._progress_tree_view.setItemDelegate(ProgressDelegate(self))
        self._progress_tree_view.setRootIsDecorated(False)
        self._progress_tree_view.setFixedHeight(30)
        self._progress_tree_view.setVerticalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff)

        self._progress_bar = QProgressBar(self)
        self._progress_bar.setRange(0, 0)
        self._progress_bar.setFixedHeight(30)
        self._progress_bar.setVisible(False)

        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self._progress_tree_view)
        layout.addWidget(self._progress_bar)

        self.setLayout(layout)

        self.setFixedHeight(30)

    def setModel(self, model) -> None:
        self._progress_tree_view.setModel(model)

    @Slot(bool)
    def setIndeterminate(self, b: bool) -> None:
        if b:
            self._progress_bar.setVisible(True)
            self._progress_tree_view.setVisible(False)
        else:
            self._progress_bar.setVisible(False)
            self._progress_tree_view.setVisible(True)
Exemple #2
0
class HomeTab(WidgetBase):
    """Home applications tab."""
    # name, prefix, sender
    sig_item_selected = Signal(object, object, object)

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

    # application_name, command, prefix, leave_path_alone, sender
    sig_launch_action_requested = Signal(object, object, bool, object, object)

    # action, application_name, version, sender
    sig_conda_action_requested = Signal(object, object, object, object)

    # url
    sig_url_clicked = Signal(object)

    # TODO: Connect these signals to have more granularity
    # [{'name': package_name, 'version': version}...], sender
    sig_install_action_requested = Signal(object, object)
    sig_remove_action_requested = Signal(object, object)

    def __init__(self, parent=None):
        """Home applications tab."""
        super(HomeTab, self).__init__(parent)

        # Variables
        self._parent = parent
        self.api = AnacondaAPI()
        self.applications = None
        self.style_sheet = None
        self.app_timers = None
        self.current_prefix = None

        # Widgets
        self.list = ListWidgetApplication()
        self.button_channels = ButtonHomeChannels('Channels')
        self.button_refresh = ButtonHomeRefresh('Refresh')
        self.combo = ComboHomeEnvironment()
        self.frame_top = FrameTabHeader(self)
        self.frame_body = FrameTabContent(self)
        self.frame_bottom = FrameTabFooter(self)
        self.label_home = LabelHome('Applications on')
        self.label_status_action = QLabel('')
        self.label_status = QLabel('')
        self.progress_bar = QProgressBar()
        self.first_widget = self.combo

        # Widget setup
        self.setObjectName('Tab')
        self.progress_bar.setTextVisible(False)
        self.list.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)

        # Layout
        layout_top = QHBoxLayout()
        layout_top.addWidget(self.label_home)
        layout_top.addWidget(SpacerHorizontal())
        layout_top.addWidget(self.combo)
        layout_top.addWidget(SpacerHorizontal())
        layout_top.addWidget(self.button_channels)
        layout_top.addWidget(SpacerHorizontal())
        layout_top.addStretch()
        layout_top.addWidget(self.button_refresh)
        self.frame_top.setLayout(layout_top)

        layout_body = QVBoxLayout()
        layout_body.addWidget(self.list)
        self.frame_body.setLayout(layout_body)

        layout_bottom = QHBoxLayout()
        layout_bottom.addWidget(self.label_status_action)
        layout_bottom.addWidget(SpacerHorizontal())
        layout_bottom.addWidget(self.label_status)
        layout_bottom.addStretch()
        layout_bottom.addWidget(self.progress_bar)
        self.frame_bottom.setLayout(layout_bottom)

        layout = QVBoxLayout()
        layout.addWidget(self.frame_top)
        layout.addWidget(self.frame_body)
        layout.addWidget(self.frame_bottom)
        self.setLayout(layout)

        # Signals
        self.list.sig_conda_action_requested.connect(
            self.sig_conda_action_requested)
        self.list.sig_url_clicked.connect(self.sig_url_clicked)
        self.list.sig_launch_action_requested.connect(
            self.sig_launch_action_requested)
        self.button_channels.clicked.connect(self.show_channels)
        self.button_refresh.clicked.connect(self.refresh_cards)
        self.progress_bar.setVisible(False)

    # --- Setup methods
    # -------------------------------------------------------------------------
    def setup(self, conda_data):
        """Setup the tab content."""
        conda_processed_info = conda_data.get('processed_info')
        environments = conda_processed_info.get('__environments')
        applications = conda_data.get('applications')
        self.current_prefix = conda_processed_info.get('default_prefix')
        self.set_environments(environments)
        self.set_applications(applications)

    def set_environments(self, environments):
        """Setup the environments list."""
        # Disconnect to avoid triggering the signal when updating the content
        try:
            self.combo.currentIndexChanged.disconnect()
        except TypeError:
            pass

        self.combo.clear()
        for i, (env_prefix, env_name) in enumerate(environments.items()):
            self.combo.addItem(env_name, env_prefix)
            self.combo.setItemData(i, env_prefix, Qt.ToolTipRole)

        index = 0
        for i, (env_prefix, env_name) in enumerate(environments.items()):
            if self.current_prefix == env_prefix:
                index = i
                break

        self.combo.setCurrentIndex(index)
        self.combo.currentIndexChanged.connect(self._item_selected)

    def set_applications(self, applications):
        """Build the list of applications present in the current conda env."""
        apps = self.api.process_apps(applications, prefix=self.current_prefix)
        all_applications = []
        installed_applications = []
        not_installed_applications = []

        # Check if some installed applications are not on the apps dict
        # for example when the channel was removed.
        linked_apps = self.api.conda_linked_apps_info(self.current_prefix)
        missing_apps = [app for app in linked_apps if app not in apps]
        for app in missing_apps:
            apps[app] = linked_apps[app]

        for app_name in sorted(list(apps.keys())):
            app = apps[app_name]
            item = ListItemApplication(name=app['name'],
                                       description=app['description'],
                                       versions=app['versions'],
                                       command=app['command'],
                                       image_path=app['image_path'],
                                       prefix=self.current_prefix,
                                       needs_license=app.get(
                                           'needs_license', False))
            if item.installed:
                installed_applications.append(item)
            else:
                not_installed_applications.append(item)

        all_applications = installed_applications + not_installed_applications

        self.list.clear()
        for i in all_applications:
            self.list.addItem(i)
        self.list.update_style_sheet(self.style_sheet)

        self.set_widgets_enabled(True)
        self.update_status()

    # --- Other methods
    # -------------------------------------------------------------------------
    def current_environment(self):
        """Return the current selected environment."""
        env_name = self.combo.currentText()
        return self.api.conda_get_prefix_envname(env_name)

    def refresh_cards(self):
        """Refresh application widgets.

        List widget items sometimes are hidden on resize. This method tries
        to compensate for that refreshing and repainting on user demand.
        """
        self.list.update_style_sheet(self.style_sheet)
        self.list.repaint()
        for item in self.list.items():
            if not item.widget.isVisible():
                item.widget.repaint()

    def show_channels(self):
        """Emit signal requesting the channels dialog editor."""
        self.sig_channels_requested.emit(self.button_channels, C.TAB_HOME)

    def update_list(self, name=None, version=None):
        """Update applications list."""
        self.set_applications()
        self.label_status.setVisible(False)
        self.label_status_action.setVisible(False)
        self.progress_bar.setVisible(False)

    def update_versions(self, apps=None):
        """Update applications versions."""
        self.items = []

        for i in range(self.list.count()):
            item = self.list.item(i)
            self.items.append(item)
            if isinstance(item, ListItemApplication):
                name = item.name
                meta = apps.get(name)
                if meta:
                    versions = meta['versions']
                    version = self.api.get_dev_tool_version(item.path)
                    item.update_versions(version, versions)

    # --- Common Helpers (# FIXME: factor out to common base widget)
    # -------------------------------------------------------------------------
    def _item_selected(self, index):
        """Notify that the item in combo (environment) changed."""
        name = self.combo.itemText(index)
        prefix = self.combo.itemData(index)
        self.sig_item_selected.emit(name, prefix, C.TAB_HOME)

    @property
    def last_widget(self):
        """Return the last element of the list to be used in tab ordering."""
        if self.list.items():
            return self.list.items()[-1].widget

    def ordered_widgets(self, next_widget=None):
        """Return a list of the ordered widgets."""
        ordered_widgets = [
            self.combo,
            self.button_channels,
            self.button_refresh,
        ]
        ordered_widgets += self.list.ordered_widgets()

        return ordered_widgets

    def set_widgets_enabled(self, value):
        """Enable or disable widgets."""
        self.combo.setEnabled(value)
        self.button_channels.setEnabled(value)
        self.button_refresh.setEnabled(value)
        for item in self.list.items():
            item.button_install.setEnabled(value)
            item.button_options.setEnabled(value)

            if value:
                item.set_loading(not value)

    def update_items(self):
        """Update status of items in list."""
        if self.list:
            for item in self.list.items():
                item.update_status()

    def update_status(self, action='', message='', value=None, max_value=None):
        """Update the application action status."""

        # Elide if too big
        width = QApplication.desktop().availableGeometry().width()
        max_status_length = round(width * (2.0 / 3.0), 0)
        msg_percent = 0.70

        fm = self.label_status_action.fontMetrics()
        action = fm.elidedText(action, Qt.ElideRight,
                               round(max_status_length * msg_percent, 0))
        message = fm.elidedText(
            message, Qt.ElideRight,
            round(max_status_length * (1 - msg_percent), 0))
        self.label_status_action.setText(action)
        self.label_status.setText(message)

        if max_value is None and value is None:
            self.progress_bar.setVisible(False)
        else:
            self.progress_bar.setVisible(True)
            self.progress_bar.setMaximum(max_value)
            self.progress_bar.setValue(value)

    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.list.update_style_sheet(style_sheet=self.style_sheet)
        self.setStyleSheet(self.style_sheet)
Exemple #3
0
class MainWindow(QMainWindow):
    sig_logged_in = Signal()
    sig_logged_out = Signal()

    DOCS_URL = 'https://docs.continuum.io/anaconda/navigator'
    VIDEOS_URL = "http://content.continuum.io/api/videos"
    EVENTS_URL = "http://content.continuum.io/api/events"
    WEBINARS_URL = "http://content.continuum.io/api/webinars"

    def __init__(self, splash=None):
        super(MainWindow, self).__init__()
        self.tracker = None
        self.splash = splash

        # Anaconda API
        self.api = AnacondaAPI()
        self.busy = False
        self.logged = False
        self.username = ''
        self._login_text = 'Sign in to Anaconda Cloud'
        self.first_run = CONF.get('main', 'first_run')
        self.application_update_version = None

        # Widgets
        self.frame_header = FrameHeader(self)
        self.frame_body = FrameBody(self)
        self.label_logo = LabelHeaderLogo('ANACONDA NAVIGATOR')
        self.button_logged_text = ButtonLabelLogin('')
        self.button_logged_username = ButtonLinkLogin('')
        self.label_update_available = LabelHeaderUpdate('Update available!')
        self.button_update_available = ButtonHeaderUpdate('Update')
        self.button_login = ButtonLogin(self._login_text)
        self.central_widget = QWidget()
        self.statusbar = self.statusBar()
        self.progressbar = QProgressBar()

        self.stack = TabWidgetBody(self)
        self.home_tab = HomeTab(parent=self)
        self.environments_tab = EnvironmentsTab(parent=self)
        self.learning_tab = CommunityTab(
            parent=self,
            tags=['webinar', 'documentation', 'video', 'training'],
            content_urls=[self.VIDEOS_URL, self.WEBINARS_URL])
        self.community_tab = CommunityTab(parent=self,
                                          tags=['event', 'forum', 'social'],
                                          content_urls=[self.EVENTS_URL])

        #        self.projects_tab = ProjectsTab(parent=self)

        # Note: Icons are set in CSS
        self.stack.addTab(self.home_tab, text='Home')
        self.stack.addTab(self.environments_tab, text='Environments')
        self.stack.addTab(self.learning_tab, text='Learning')
        self.stack.addTab(self.community_tab, text='Community')
        #        self.stack.addTab(self.projects_tab, 'Projects')

        # Widget setup
        self.button_login.setDefault(True)
        self.label_logo.setPixmap(QPixmap(images.ANACONDA_NAVIGATOR_LOGO))
        self.setWindowTitle("Anaconda Navigator")
        self.statusbar.addPermanentWidget(self.progressbar)
        self.progressbar.setVisible(False)

        # Layout
        header_layout = QHBoxLayout()
        header_layout.addWidget(self.label_logo)
        header_layout.addSpacing(18)
        header_layout.addWidget(self.label_update_available, 0, Qt.AlignCenter)
        header_layout.addWidget(self.button_update_available, 0,
                                Qt.AlignCenter)
        header_layout.addStretch()
        header_layout.addWidget(self.button_logged_text, 0, Qt.AlignTrailing)
        header_layout.addWidget(self.button_logged_username, 0,
                                Qt.AlignTrailing)
        header_layout.addWidget(self.button_login, 0, Qt.AlignTrailing)
        header_layout.setContentsMargins(0, 0, 0, 0)
        self.frame_header.setLayout(header_layout)

        body_layout = QHBoxLayout()
        body_layout.addWidget(self.stack)
        body_layout.setContentsMargins(0, 0, 0, 0)
        self.frame_body.setLayout(body_layout)

        main_layout = QVBoxLayout()
        main_layout.addWidget(self.frame_header)
        main_layout.addWidget(self.frame_body)
        main_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.setSpacing(0)
        self.central_widget.setLayout(main_layout)
        self.setContentsMargins(0, 0, 0, 0)
        self.setCentralWidget(self.central_widget)

        # Signals
        self.button_login.clicked.connect(self.login)
        self.button_logged_username.clicked.connect(self.open_login_page)
        self.button_update_available.clicked.connect(self.update_application)
        self.stack.currentChanged.connect(self._track_tab)

        # This needs to be reworked!
        #        self.projects_tab.sig_apps_updated.connect(
        #            self.home_tab.set_applications)
        #        self.projects_tab.sig_apps_changed.connect(
        #            self.home_tab.set_applications)
        #        self.projects_tab.sig_project_updated.connect(
        #            self.home_tab.set_applications)
        #        self.projects_tab.sig_status_updated.connect(self.update_status_bar)

        # Setup
        self.api.set_data_directory(CHANNELS_PATH)
        self.update_style_sheet()

    # Helpers
    # -------------------------------------------------------------------------
    def _track_tab(self, index=None):
        """
        Tracks the active tab by index, or set `Home` when no index has been
        provided.
        """
        if index is None:
            index = self.stack.currentIndex()

        text = self.stack.currentText().lower()

        if self.tracker:
            page = '/{0}'.format(text)
            self.tracker.track_page(page)

    def _metadata_updated(self, worker, path, error):
        self.set_splash('Updating repodata...')
        if error:
            logger.error(str(error))

        if path and os.path.isfile(path):
            with open(path, 'r') as f:
                data = f.read()
        try:
            self._metadata = json.loads(data)
        except Exception:
            self._metadata = {}

        channels = CONF.get('main', 'conda_channels', default=tuple())
        if not channels:
            channels = self.api.conda_get_condarc_channels()
            CONF.set('main', 'conda_channels', channels)
            CONF.set('main', 'conda_active_channels', channels)

        self.api.update_repodata(channels=channels)
        self.api.sig_repodata_updated.connect(self._repodata_updated)

    def _repodata_updated(self, paths):
        self.set_splash('Loading repodata...')
        self.api.sig_repodata_updated.disconnect(self._repodata_updated)

        if self.first_run:
            self.set_splash('Initial configuration...')
            self.api.create_default_project()

        worker = self.api.client_load_repodata(paths, self._metadata)
        worker.sig_finished.connect(self.create_application_projects)

    # --- Public API
    # -------------------------------------------------------------------------
    def setup(self):
        """
        Perform initial setup and configuration.
        """
        self.set_splash('Updating metadata...')
        user = self.api.client_set_domain()
        self.update_login_status(user)
        self.setup_toolbars()
        self.set_application_icon()
        worker = self.api.update_metadata()
        worker.sig_finished.connect(self._metadata_updated)
        statusbar = self.statusBar()
        statusbar.setVisible(False)
        statusbar.setMaximumHeight(0)
        statusbar.hide()

    def create_application_projects(self, worker, output, error):
        if error:
            logger.error(str(error))
        packages, apps = output
        self.api.create_application_projects(
            apps,
            add_project=self.first_run,
        )

        self.post_setup(apps)
        self.check_for_updates(packages)

    def post_setup(self, apps):
        CONF.set('main', 'first_run', False)
        self.set_splash('Loading applications...')
        self.home_tab.setup_tab(apps)
        #        self.set_splash('Loading projects...')
        #        self.projects_tab.setup_tab()
        self.set_splash('Loading environments...')
        self.environments_tab.setup_tab(metadata=self._metadata)
        self.set_splash('Loading content...')
        self.community_tab.setup_tab()
        self.set_splash('Loading content...')
        self.learning_tab.setup_tab()
        self.update_style_sheet()

        self.showMaximized()
        self.post_visible_setup()

    def set_application_icon(self):
        """
        """
        app = QCoreApplication.instance()
        app_icon = QIcon()
        app_icon.addFile(images.ANACONDA_ICON_16_PATH, QSize(16, 16))
        app_icon.addFile(images.ANACONDA_ICON_24_PATH, QSize(24, 24))
        app_icon.addFile(images.ANACONDA_ICON_32_PATH, QSize(32, 32))
        app_icon.addFile(images.ANACONDA_ICON_48_PATH, QSize(48, 48))
        app_icon.addFile(images.ANACONDA_ICON_256_PATH, QSize(256, 256))
        app.setWindowIcon(app_icon)

    def setup_toolbars(self):
        menubar = self.menuBar()

        file_menu = menubar.addMenu('&File')
        file_menu.addAction(
            create_action(self,
                          "&Preferences",
                          triggered=self.show_preferences,
                          shortcut="Ctrl+P"))
        file_menu.addAction(
            create_action(self,
                          "&Quit",
                          triggered=self.close,
                          shortcut="Ctrl+Q"))

        helpmenu = menubar.addMenu('&Help')
        helpmenu.addAction(
            create_action(self,
                          "&Online Documentation",
                          triggered=lambda: self.open_url(self.DOCS_URL)))
        helpmenu.addAction(
            create_action(self,
                          "&Logs viewer",
                          triggered=self.show_log_viewer,
                          shortcut="F6"))
        helpmenu.addSeparator()
        helpmenu.addAction(
            create_action(self, "&About", triggered=self.show_about))

    def post_visible_setup(self):
        if self.splash:
            self.splash.hide()

        CONF.set('main', 'first_run', False)

        # Start the tracker only after post_visible_setup
        self.tracker = GATracker()
        self._track_tab(0)  # Start tracking home
        self.fix_tab_ordering()
        self.show_welcome_screen()

    def check_for_updates(self, packages=None):
        # Check if there is an update for navigator!
        version = self.api.conda_package_version(name='root',
                                                 pkg='anaconda-navigator')
        # Temporal mock test
        # mock_versions = [version, '1.1.0']
        # packages['anaconda-navigator'] = {'versions': mock_versions}
        self.button_update_available.setVisible(False)
        self.label_update_available.setVisible(False)

        text = ''
        if packages:
            package_data = packages.get('anaconda-navigator')
            if package_data:
                versions = package_data.get('versions')
                if versions and version != versions[-1]:
                    self.application_update_version = versions[-1]
                    self.label_update_available.setText(text)
                    self.label_update_available.setVisible(True)
                    self.button_update_available.setVisible(True)

    def fix_tab_ordering(self):
        return
        for tab in [self.community_tab, self.learning_tab]:
            self.setTabOrder(self.stack.tabbar.buttons[-1],
                             tab.filter_widgets[0])
            for i in range(len(tab.filter_widgets) - 1):
                self.setTabOrder(tab.filter_widgets[i],
                                 tab.filter_widgets[i + 1])
            self.setTabOrder(tab.filter_widgets[-1], tab.text_filter)
            self.setTabOrder(tab.text_filter.button_icon, tab.list)
            self.setTabOrder(tab.list, self.button_login)


#        self.button_login.setFocus()

        self.setTabOrder(self.stack.tabbar.buttons[-1],
                         self.environments_tab.text_search)

        self.environments_tab.packages_widget.table_last_row.add_focus_widget(
            self.button_login)
        self.setTabOrder(self.environments_tab.packages_widget.table_last_row,
                         self.button_login)

    def update_style_sheet(self):
        style_sheet = load_style_sheet()
        #        self.home_tab.update_style_sheet(style_sheet)
        self.environments_tab.update_style_sheet(style_sheet)
        #        self.community_tab.update_style_sheet(style_sheet)
        #        self.learning_tab.update_style_sheet(style_sheet)
        self.setStyleSheet(style_sheet)

    def set_splash(self, message):
        """
        Set splash message.
        """
        if self.splash:
            self.splash.show_message(message)
        QApplication.processEvents()

    # --- Login
    # -------------------------------------------------------------------------
    def update_login_status(self, user_data=None):
        """
        Update login button and information.
        """
        if user_data:
            self.username = user_data.get('login', '')
            self.logged = True

        if self.logged:
            username = self.username
            anaconda_api_url = CONF.get('main', 'anaconda_api_url')
            token = self.api.client_load_token(anaconda_api_url)
            self.button_logged_text.setText('Signed in as')
            self.button_logged_username.setText(username)
            url = "{0}/{1}".format(CONF.get('main', 'conda_url'), username)
            self.button_logged_username.setToolTip(url)
            self.button_login.setText('Sign out')
            self.environments_tab.packages_widget.set_token(token)
        else:
            self.button_logged_text.setText('')
            self.button_logged_username.setText('')
            self.button_login.setText(self._login_text)
        QApplication.restoreOverrideCursor()

    def login(self):
        """
        Open up login dialog or log out depending on logged status.
        """
        if self.logged:
            QApplication.setOverrideCursor(Qt.WaitCursor)
            self.api.client_logout()
            self.api.client_remove_token()
            self.logged = False
            self.sig_logged_out.emit()
            self.tracker.track_event('authenticate',
                                     'logout',
                                     label=self.username)
        else:
            dlg = AuthenticationDialog(self.api, parent=self)

            if self.tracker:
                self.tracker.track_page('/login', pagetitle='Login dialog')

            if dlg.exec_():
                self.api.client_store_token(dlg.token)
                self.username = dlg.username
                self.logged = True
                self.sig_logged_in.emit()

                if self.tracker:
                    self.tracker.track_event('authenticate',
                                             'login',
                                             label=self.username)
            self._track_tab()

        self.update_login_status()
        logger.debug(str((self.logged, self.username)))

    # --- Dialogs
    # -------------------------------------------------------------------------
    def show_preferences(self):
        """
        Display the preferences dialog and apply the needed actions.
        """
        dlg = PreferencesDialog(self)
        self.tracker.track_page('/preferences', pagetitle='Preferences dialog')
        set_domains = self.environments_tab.packages_widget.update_domains
        set_domains = self.environments_tab.packages_widget.update_domains

        dlg.sig_urls_updated.connect(set_domains)
        dlg.sig_urls_updated.connect(lambda au, cu: self.login())
        dlg.exec_()
        self._track_tab()

    def show_about(self):
        """
        Display the `About` dialog with information on the project.
        """
        dlg = AboutDialog(self)
        self.tracker.track_page('/about', pagetitle='About dialog')
        dlg.exec_()
        self._track_tab()

    def show_log_viewer(self):
        """
        Display the logs viewer to the user
        """
        dlg = LogViewerDialog()
        self.tracker.track_page('/logs', pagetitle='Log Viewer Dialog')
        dlg.exec_()
        self._track_tab()

    def show_welcome_screen(self):
        if getattr(self, 'showme', True) and CONF.get('main', 'show_startup',
                                                      True):
            from anaconda_navigator.widgets.splash import FirstSplash

            self.showme = False
            self.splash.hide()
            dlg = FirstSplash()
            dlg.raise_()
            dlg.exec_()

    # --- Update Navigator
    # -------------------------------------------------------------------------
    def _update_application(self, worker, output, error):
        self.button_update_available.setDisabled(False)
        if error:
            text = 'Anaconda Navigator Update error:'
            dlg = MessageBoxError(text=text,
                                  error=error,
                                  title='Application Update Error')
            self.tracker.track_page('/update/error',
                                    pagetitle='Update Application Error '
                                    'Message Box')
            dlg.exec_()
        else:
            text = ('Anaconda Navigator Updated succefully.\n\n'
                    'Please restart the application')
            dlg = MessageBoxInformation(text=text, title='Application Update')
            self.tracker.track_page('/update/successful',
                                    pagetitle='Application Update Succesful '
                                    'Message Box')
            dlg.exec_()
        self._track_tab()

    def update_application(self):
        version = self.application_update_version
        if version:
            dlg = DialogUpdateApplication(version=version)
            self.tracker.track_page('/update',
                                    pagetitle='Update Application Dialog')
            reply = dlg.exec_()
            if reply:
                self.tracker.track_event('application', 'updated', version)
                self.busy = True
                pkg = 'anaconda-navigator={}'.format(version)
                worker = self.api.conda_install(name='root', pkgs=[pkg])
                worker.sig_finished.connect(self._update_application)
                self.button_update_available.setDisabled(True)
            self._track_tab()

    def update_status_bar(self, message='', timeout=0, val=-1, max_val=-1):
        """ """
        statusbar = self.statusBar()
        if val != -1 and max_val != -1:
            self.progressbar.setVisible(True)
            self.progressbar.setValue(val)
            self.progressbar.setMaximum(max_val)
        else:
            self.progressbar.setVisible(False)

        if message:
            statusbar.showMessage(message, timeout)
        else:
            statusbar.clearMessage()
        statusbar.setVisible(False)
        statusbar.setMaximumHeight(0)
        statusbar.hide()

    # --- Url handling
    # -------------------------------------------------------------------------
    def open_url(self, url):
        qurl = QUrl(url)
        QDesktopServices.openUrl(qurl)
        self.tracker.track_event('help', 'documentation', url)

    def open_login_page(self):
        """
        """
        conda_url = CONF.get('main', 'conda_url')
        url = "{0}/{1}".format(conda_url, self.username)
        qurl = QUrl(url)
        QDesktopServices.openUrl(qurl)
        self.tracker.track_event('content', 'clicked', url)

    # --- Qt methods
    # -------------------------------------------------------------------------
    def closeEvent(self, event):
        """
        Catch close event.
        """
        # TODO: check if an update is not in progress or things might break!!
        #        if self.busy:
        show_dialog = not CONF.get('main', 'hide_quit_dialog')
        if show_dialog:
            if self.tracker:
                self.tracker.track_page('/quit', pagetitle='Quit dialog')
            dlg = QuitApplicationDialog()
            reply = dlg.exec_()

            if not reply:
                event.ignore()
                self._track_tab()

    def keyPressEvent(self, event):
        """
        Qt override.
        """
        #        if event.key() in [Qt.Key_F5]:
        #            self.update_style_sheet()
        super(MainWindow, self).keyPressEvent(event)

    def paintEvent(self, event):
        """
        Qt override.

        Draw lower left border of the main Stacked Widget.
        """
        super(MainWindow, self).paintEvent(event)
        tab = self.stack.tabbar
        tab_pos = self.mapTo(self, tab.pos())
        pane_pos = self.mapTo(self, self.stack.pos())

        stack_height = self.stack.height()
        menu_height = self.menuBar().height()
        header_height = 49  # From css
        padding = 20  # From css
        left = 1  # From css
        extra = 8  # Still wondering where this extra Y delta is
        deltay = menu_height + header_height + tab.height() + padding + extra
        x0 = tab_pos.x() + tab.width() + padding - left
        y0 = tab_pos.y() + deltay
        y1 = pane_pos.y() + stack_height + deltay - tab.height() - padding

        painter = QPainter(self)
        painter.setPen(QPen(QColor('#006f43'), 1, Qt.SolidLine, Qt.RoundCap))
        painter.drawLine(x0, y0, x0, y1)
class MainWindow(QMainWindow):
    def __init__(self, title):
        super().__init__()
        self.setWindowTitle(title)
        self.lib_path = ""
        self.final_title = ""
        analysis_icon = QIcon(os.path.join(icons_dir, "icon.png"))
        stack_icon = QIcon(os.path.join(icons_dir, "icon_stack.png"))
        self.analysis_button = QToolButton(self)
        self.analysis_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        self.analysis_button.setIcon(analysis_icon)
        # TODO use more general solution for text wrapping
        self.analysis_button.setText(SEGMENTATION_NAME.replace(" ", "\n"))
        self.analysis_button.setIconSize(QSize(100, 100))
        self.mask_button = QToolButton(self)
        self.mask_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        self.mask_button.setIcon(stack_icon)
        self.mask_button.setText(MASK_NAME.replace(" ", "\n"))
        self.mask_button.setIconSize(QSize(100, 100))
        self.analysis_button.clicked.connect(self.launch_analysis)
        self.mask_button.clicked.connect(self.launch_mask)
        self.progress = QProgressBar()
        self.progress.setHidden(True)
        layout = QGridLayout()
        layout.addWidget(self.progress, 0, 0, 1, 2)
        layout.addWidget(self.analysis_button, 1, 1)
        layout.addWidget(self.mask_button, 1, 0)
        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)
        self.setWindowIcon(analysis_icon)
        self.prepare = None
        self.wind = None

    def _launch_begin(self):
        self.progress.setVisible(True)
        self.progress.setRange(0, 0)
        self.analysis_button.setDisabled(True)
        self.mask_button.setDisabled(True)
        import_config()

    def launch_analysis(self):
        self._launch_begin()
        self.lib_path = "PartSeg.segmentation_analysis.main_window"
        self.final_title = "PartSeg Segmentation Analysis"
        self.prepare = Prepare(self.lib_path)
        self.prepare.finished.connect(self.launch)
        self.prepare.start()

    def launch_mask(self):
        self._launch_begin()
        self.lib_path = "PartSeg.segmentation_mask.main_window"
        self.final_title = "PartSeg Mask Segmentation"
        self.prepare = Prepare(self.lib_path)
        self.prepare.finished.connect(self.launch)
        self.prepare.start()

    def window_shown(self):
        self.close()

    def launch(self):
        if self.prepare.result is None:
            self.close()
            return
        if self.prepare.errors:
            errors_message = QMessageBox()
            errors_message.setText("There are errors during start")
            errors_message.setInformativeText(
                "During load saved state some of data could not be load properly\n"
                "The files has prepared backup copies in  state directory (Help > State directory)"
            )
            errors_message.setStandardButtons(QMessageBox.Ok)
            text = "\n".join(["File: " + x[0] + "\n" + str(x[1]) for x in self.prepare.errors])
            errors_message.setDetailedText(text)
            errors_message.exec()
        wind = self.prepare.result(title=self.final_title, signal_fun=self.window_shown)
        wind.show()
        self.wind = wind
Exemple #5
0
class MainWindow(QMainWindow):
    def __init__(self, title):
        super().__init__()
        self.setWindowTitle(title)
        self.lib_path = ""
        self.final_title = ""
        analysis_icon = QIcon(os.path.join(icons_dir, "icon.png"))
        stack_icon = QIcon(os.path.join(icons_dir, "icon_stack.png"))
        self.analysis_button = QToolButton(self)
        self.analysis_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        self.analysis_button.setIcon(analysis_icon)
        # TODO use more general solution for text wrapping
        self.analysis_button.setText(ANALYSIS_NAME.replace(" ", "\n"))
        self.analysis_button.setIconSize(QSize(100, 100))
        self.mask_button = QToolButton(self)
        self.mask_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        self.mask_button.setIcon(stack_icon)
        self.mask_button.setText(MASK_NAME.replace(" ", "\n"))
        self.mask_button.setIconSize(QSize(100, 100))
        self.analysis_button.clicked.connect(self.launch_analysis)
        self.mask_button.clicked.connect(self.launch_mask)
        self.progress = QProgressBar()
        self.progress.setHidden(True)
        layout = QGridLayout()
        layout.addWidget(self.progress, 0, 0, 1, 2)
        layout.addWidget(self.analysis_button, 1, 1)
        layout.addWidget(self.mask_button, 1, 0)
        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)
        self.setWindowIcon(analysis_icon)
        self.prepare = None
        self.wind = None
        self._update_theme()

    def _update_theme(self):
        napari_settings = napari_get_settings(state_store.save_folder)
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", FutureWarning)
            theme = get_theme(napari_settings.appearance.theme)
        # TODO understand qss overwrite mechanism
        self.setStyleSheet(napari_template(get_stylesheet(), **theme))

    def _launch_begin(self):
        self.progress.setVisible(True)
        self.progress.setRange(0, 0)
        self.analysis_button.setDisabled(True)
        self.mask_button.setDisabled(True)
        import_config()

    def launch_analysis(self):
        self._launch_begin()
        self._launch_analysis()
        self.prepare.start()

    def _launch_analysis(self):
        self.lib_path = "PartSeg._roi_analysis.main_window"
        self.final_title = f"{APP_NAME} {ANALYSIS_NAME}"
        self.prepare = Prepare(self.lib_path)
        self.prepare.finished.connect(self.launch)

    def launch_mask(self):
        self._launch_begin()
        self._launch_mask()
        self.prepare.start()

    def _launch_mask(self):
        self.lib_path = "PartSeg._roi_mask.main_window"
        self.final_title = f"{APP_NAME} {MASK_NAME}"
        self.prepare = Prepare(self.lib_path)
        self.prepare.finished.connect(self.launch)

    def window_shown(self):
        self.close()

    def launch(self):
        if self.prepare.result is None:
            self.close()
            return
        if self.prepare.errors:
            errors_message = QMessageBox()
            errors_message.setText("There are errors during start")
            errors_message.setInformativeText(
                "During load saved state some of data could not be load properly\n"
                "The files has prepared backup copies in  state directory (Help > State directory)"
            )
            errors_message.setStandardButtons(QMessageBox.Ok)
            text = "\n".join("File: " + x[0] + "\n" + str(x[1])
                             for x in self.prepare.errors)

            errors_message.setDetailedText(text)
            errors_message.exec_()
        wind = self.prepare.result(title=self.final_title,
                                   signal_fun=self.window_shown)
        wind.show()
        self.wind = wind
Exemple #6
0
class DialogChannels(DialogBase):
    """Dialog to add delete and select active conda package channels."""

    sig_channels_updated = Signal(object, object)  # added, removed
    sig_setup_ready = Signal()
    sig_check_ready = Signal()
    WIDTH = 550

    def __init__(self, parent=None):
        """Dialog to add delete and select active conda pacakge channels ."""
        super(DialogChannels, self).__init__(parent)
        self._parent = parent
        self._conda_url = 'https://conda.anaconda.org'
        self.api = AnacondaAPI()
        self.initial_sources = None
        self.config_sources = None
        self.style_sheet = None
        self._setup_ready = False
        self._conda_url_setup_ready = False

        # Widgets
        self.list = ListWidgetChannels(parent=self, api=self.api)
        self.label_info = LabelBase(
            'Manage channels you want Navigator to include.')
        self.label_status = LabelBase('Collecting sources...')
        self.progress_bar = QProgressBar(self)
        self.button_add = ButtonNormal('Add...')
        self.button_cancel = ButtonNormal('Cancel')
        self.button_ok = ButtonPrimary('Update channels')

        # Widget setup
        self.frame_title_bar.setVisible(False)
        self.list.setFrameStyle(QFrame.NoFrame)
        self.list.setFrameShape(QFrame.NoFrame)
        self.setWindowFlags(self.windowFlags() | Qt.Popup)
        self.setWindowOpacity(0.96)
        self.setMinimumHeight(300)
        self.setMinimumWidth(self.WIDTH)
        self.setModal(True)

        # Layout
        layout_button = QHBoxLayout()
        layout_button.addWidget(self.label_info)
        layout_button.addStretch()
        layout_button.addWidget(self.button_add)

        layout_ok = QHBoxLayout()
        layout_ok.addWidget(self.label_status)
        layout_ok.addWidget(SpacerHorizontal())
        layout_ok.addWidget(self.progress_bar)
        layout_ok.addWidget(SpacerHorizontal())
        layout_ok.addStretch()
        layout_ok.addWidget(self.button_cancel)
        layout_ok.addWidget(SpacerHorizontal())
        layout_ok.addWidget(self.button_ok)

        layout = QVBoxLayout()
        layout.addLayout(layout_button)
        layout.addWidget(SpacerVertical())
        layout.addWidget(self.list)
        layout.addWidget(SpacerVertical())
        layout.addWidget(SpacerVertical())
        layout.addLayout(layout_ok)
        self.setLayout(layout)

        # Signals
        self.button_add.clicked.connect(self.add_channel)
        self.button_ok.clicked.connect(self.update_channels)
        self.button_cancel.clicked.connect(self.reject)
        self.list.sig_status_updated.connect(self.update_status)
        self.list.sig_channel_added.connect(
            lambda v=None: self.set_tab_order())
        self.list.sig_channel_added.connect(
            lambda v=None: self.button_ok.setFocus())
        self.list.sig_channel_removed.connect(
            lambda v=None: self.set_tab_order())
        self.list.sig_channel_removed.connect(
            lambda v=None: self.button_ok.setFocus())
        self.list.sig_channel_checked.connect(self.sig_check_ready)
        self.list.sig_channel_status.connect(self.refresh)

        self.button_add.setDisabled(True)
        self.button_ok.setDisabled(True)
        self.button_cancel.setDisabled(True)
        self.update_status(action='Collecting sources...',
                           value=0,
                           max_value=0)

    @staticmethod
    def _group_sources_and_channels(sources):
        """
        Flatten sources and channels dictionary to list of tuples.

        [(source, channel), (source, channel)...]
        """
        grouped = []
        for source, channels in sources.items():
            for channel in channels:
                grouped.append((source, channel))
        return grouped

    def keyPressEvent(self, event):
        """Override Qt method."""
        key = event.key()
        if key in [Qt.Key_Escape]:
            if self.list.is_editing:
                self.refresh()
                self.list.is_editing = False
            else:
                self.reject()

    # --- Public API
    # -------------------------------------------------------------------------
    def update_style_sheet(self, style_sheet=None):
        """Update custom css style sheets."""
        if style_sheet is None:
            self.style_sheet = load_style_sheet()
        else:
            self.style_sheet = style_sheet

        self.setStyleSheet(self.style_sheet)
        self.setMinimumWidth(SASS_VARIABLES.WIDGET_CHANNEL_DIALOG_WIDTH)

        try:
            self.list.update_style_sheet(style_sheet)
        except Exception:
            pass

    def update_api(self, worker, api_info, error):
        """Update api info."""
        self._conda_url = api_info.get('conda_url',
                                       'https://conda.anaconda.org')
        self._conda_url_setup_ready = True

        if self._setup_ready:
            self.sig_setup_ready.emit()

    def setup(self, worker, conda_config_data, error):
        """Setup the channels widget."""
        self.config_sources = conda_config_data.get('config_sources')
        self.button_add.setDisabled(False)

        for source, data in self.config_sources.items():
            channels = data.get('channels', [])
            for channel in channels:
                item = ListWidgetItemChannel(channel=channel, location=source)
                item.set_editable(False)
                self.list.addItem(item)

        self.set_tab_order()
        self.button_add.setFocus()
        self.button_ok.setDefault(True)
        self.button_cancel.setEnabled(True)

        self.initial_sources = self.list.sources.copy()
        self.update_status()
        self._setup_ready = True

        if self._conda_url_setup_ready:
            self.sig_setup_ready.emit()

    def set_tab_order(self):
        """Fix the tab ordering in the list."""
        if self.list._items:
            self.setTabOrder(self.button_add,
                             self.list._items[0].button_remove)
            self.setTabOrder(self.list._items[-1].button_remove,
                             self.button_cancel)

        self.setTabOrder(self.button_cancel, self.button_ok)
        self.refresh()

    def add_channel(self):
        """Add new conda channel."""
        user_rc_path = self.api._conda_api.user_rc_path
        item = ListWidgetItemChannel(channel='', location=user_rc_path)
        self.list.addItem(item)
        self.refresh(False)

    def update_channels(self):
        """Update channels list and status."""
        sources = self.list.sources

        original = self._group_sources_and_channels(self.initial_sources)
        updated = self._group_sources_and_channels(sources)

        if sorted(original) != sorted(updated):
            self.sig_channels_updated.emit(*self.sources)
            self.accept()
        else:
            self.reject()

    def refresh(self, channel_status=True):
        """Update enable/disable status based on item count."""
        self.button_add.setEnabled(channel_status and bool(self.list.count))
        self.button_ok.setEnabled(channel_status)
        self.button_cancel.setEnabled(True)

        if self.list.count() == 0:
            self.button_add.setEnabled(True)
            self.button_ok.setEnabled(False)

    def update_status(self, action='', message='', value=None, max_value=None):
        """Update the status and progress bar of the widget."""
        visible = bool(action)
        self.label_status.setText(action)
        self.label_status.setVisible(visible)
        if value is not None and max_value is not None:
            self.progress_bar.setVisible(True)
            self.progress_bar.setRange(0, max_value)
            self.progress_bar.setValue(value)
        else:
            self.progress_bar.setVisible(False)

    @property
    def sources(self):
        """Return sources to add and remove from config."""
        original = self._group_sources_and_channels(self.initial_sources)
        updated = self._group_sources_and_channels(self.list.sources)

        original = set(original)
        updated = set(updated)

        add = updated - original
        remove = original - updated

        return add, remove
Exemple #7
0
class MainDialog(DialogBase):
    """Main dialog for the anaconda navgator updater."""
    # Signals
    sig_application_updated = Signal()
    sig_ready = Signal()

    # Class variables
    PACKAGE = 'anaconda-navigator'
    WIDTH = 450
    HEIGHT = 200

    def __init__(self, latest_version=None, prefix=None):
        """Main dialog for the anaconda navgator updater."""
        super(MainDialog, self).__init__()

        # Variables
        self.api = CondaAPI()
        self.prefix = prefix or os.environ.get('CONDA_PREFIX',
                                               self.api.ROOT_PREFIX)
        self.info = {}
        self.first_run = True
        self.setup_ready = False
        self.busy = False
        self.up_to_date = False
        self.error = False
        self.success = False
        self.status = ''
        self.current_version = None
        self.latest_version = latest_version
        self.style_sheet = load_style_sheet()
        self.timer = QTimer()
        self.timer_2 = QTimer()
        self._windows_appusermodelid = None

        # Widgets
        self.message_box = None  # For testing
        self.label_icon = QSvgWidget()
        self.label_message = LabelBase(
            "There's a new version of Anaconda Navigator available. "
            "We strongly recommend you to update.")

        self.label_status = LabelBase('')
        self.progress_bar = QProgressBar()
        self.button_cancel = ButtonNormal('Dismiss')
        self.button_update = ButtonPrimary('Update now')
        self.button_launch = ButtonPrimary('Launch Navigator')

        # Widgets setup
        if WIN:
            self._windows_appusermodelid = set_windows_appusermodelid()

        self.setMinimumSize(self.WIDTH, self.HEIGHT)
        self.label_message.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        self.label_message.setWordWrap(True)
        self.label_status.setWordWrap(True)
        self.button_update.setAutoDefault(True)
        self.button_launch.setAutoDefault(True)
        self.button_cancel.setFocusPolicy(Qt.NoFocus)
        self.timer.setInterval(1000)
        self.timer_2.setInterval(5000)
        self.progress_bar.setTextVisible(False)
        self.progress_bar.setStyleSheet(self.style_sheet)
        self.label_icon.load(images.ANACONDA_LOGO)
        self.label_icon.setMaximumSize(QSize(64, 64))
        self.label_icon.setMinimumSize(QSize(64, 64))
        self.setWindowTitle('Anaconda Navigator Updater')
        self.progress_bar.setMaximumWidth(self.WIDTH / 3)
        self.setMinimumWidth(self.WIDTH)
        self.setMaximumWidth(self.WIDTH)
        self.setMinimumHeight(self.HEIGHT)

        # Layouts
        layout_status = QHBoxLayout()
        layout_status.addWidget(self.label_status)
        layout_status.addWidget(SpacerHorizontal())
        layout_status.addWidget(self.progress_bar)

        layout_text = QVBoxLayout()
        layout_text.addWidget(self.label_message)
        layout_text.addStretch()
        layout_text.addWidget(SpacerVertical())
        layout_text.addLayout(layout_status)

        layout_icon = QVBoxLayout()
        layout_icon.addWidget(self.label_icon)
        layout_icon.addStretch()

        layout_top = QHBoxLayout()
        layout_top.addLayout(layout_icon)
        layout_top.addWidget(SpacerHorizontal())
        layout_top.addLayout(layout_text)

        layout_buttons = QHBoxLayout()
        layout_buttons.addStretch()
        layout_buttons.addWidget(self.button_cancel)
        layout_buttons.addWidget(SpacerHorizontal())
        layout_buttons.addWidget(self.button_update)
        layout_buttons.addWidget(self.button_launch)

        layout = QVBoxLayout()
        layout.addLayout(layout_top)
        layout.addWidget(SpacerVertical())
        layout.addWidget(SpacerVertical())
        layout.addStretch()
        layout.addLayout(layout_buttons)

        self.setLayout(layout)

        # Signals
        self.button_update.clicked.connect(self.install_update)
        self.button_cancel.clicked.connect(self.reject)
        self.button_launch.clicked.connect(self.launch)
        self.timer.timeout.connect(self.refresh)
        self.timer_2.timeout.connect(self.check_conditions)

        # Setup
        self.timer.start()
        self.timer_2.start()
        self.check_conditions()
        self.refresh()

    def check_conditions(self):
        """Check every 5 seconds installed packages in case codna was used."""
        packages = self.api.linked(prefix=self.prefix)
        package = [p for p in packages if self.PACKAGE in p]
        if package:
            n, v, b = self.api.split_canonical_name(package[0])
            self.current_version = v
        else:
            self.current_version = None

        if self.latest_version is None:
            worker_search = self.api.search(self.PACKAGE,
                                            platform=self.api.get_platform())
            worker_search.sig_finished.connect(self._search_callback)
        else:
            worker = self.api.info()
            worker.sig_finished.connect(self.setup)
            self.check_versions()

    def check_versions(self):
        """Check if navigator is up to date."""
        if self.latest_version and self.current_version:
            from distutils.version import LooseVersion
            cur_ver = LooseVersion(self.current_version)
            lat_ver = LooseVersion(self.latest_version)
            self.up_to_date = cur_ver >= lat_ver
        else:
            self.up_to_date = False

    def _search_callback(self, worker, output, error):
        """Setup the widget."""
        if isinstance(output, dict):
            packages = output.get(self.PACKAGE, [])
            versions = [package.get('version') for package in packages]
            unique_versions = []
            for version in versions:
                if version not in unique_versions:
                    unique_versions.append(version)
            if unique_versions:
                self.latest_version = unique_versions[-1]

        self.check_versions()
        worker = self.api.info()
        worker.sig_finished.connect(self.setup)

        self.refresh()

    def setup(self, worker, info, error):
        """Setup the widget."""
        self.info = info
        self.setup_ready = True
        self.sig_ready.emit()
        self.refresh()

        if self.button_update.isVisible():
            self.button_update.setFocus()

        if self.button_launch.isVisible():
            self.button_launch.setFocus()

    def update_style_sheet(self):
        """Update custom CSS style sheet."""
        self.style_sheet = load_style_sheet()
        self.setStyleSheet(self.style_sheet)

    def refresh(self):
        """Refresh enabled/disabled status of widgets."""
        current_version = 'Not installed'
        if self.current_version:
            current_version = self.current_version

        latest_version = '-'
        if self.latest_version:
            latest_version = self.latest_version

        main_message = (
            "Current version:    &nbsp;&nbsp;&nbsp;&nbsp;<i>{0}</i><br>"
            "Available version: &nbsp;&nbsp;<b>{1}</b><br>").format(
                current_version, latest_version)

        message = self.status
        running = self.check_running()
        self.button_launch.setVisible(False)

        if not self.setup_ready:
            self.button_update.setDisabled(True)
            self.progress_bar.setVisible(True)
            message = 'Updating index...'
            self.update_status(message)
        elif self.busy:
            self.button_update.setDisabled(True)
            self.progress_bar.setVisible(True)
        else:
            self.progress_bar.setVisible(False)

            if running:
                message = 'Please close Anaconda Navigator before updating.'
                self.button_update.setDisabled(running)
            elif not running:
                self.button_update.setDisabled(False)
                if self.success and self.current_version:
                    message = 'Anaconda Navigator was updated successfully.'
                    self.button_update.setVisible(False)
                    self.button_launch.setVisible(True)
                elif self.up_to_date:
                    message = 'Anaconda Navigator is already up to date.'
                    self.button_update.setVisible(False)
                    self.button_launch.setVisible(True)
                elif not self.error:
                    self.button_update.setVisible(True)
                    if self.current_version:
                        message = ('An update for Anaconda Navigator is now '
                                   'available.')
                        self.button_update.setText('Update now')
                    else:
                        message = (
                            'Anaconda Navigator is available for install.')
                        self.button_update.setText('Install now')

            if self.error:
                self.button_update.setDisabled(False)
                message = 'Cannot update Anaconda Navigator, <b>{0}</b>'
                message = message.format(self.error)

        self.label_status.setText(message)
        self.label_message.setText(main_message)

    def update_status(self, status='', value=-1, max_val=-1):
        """Update progress bar and message status."""
        if status:
            self.status = status
            self.label_status.setText(status)
            if value < 0 and max_val < 0:
                self.progress_bar.setRange(0, 0)
            else:
                self.progress_bar.setMinimum(0)
                self.progress_bar.setMaximum(max_val)
                self.progress_bar.setValue(value)

    def check_running(self):
        """Check if Anaconda Navigator is running."""
        # Create file lock
        lock = filelock.FileLock(NAVIGATOR_LOCKFILE)
        try:
            running = False
            with lock.acquire(timeout=0.01):
                pass
        except filelock.Timeout:
            running = True
        return running

    # --- Conda actions and helpers
    # -------------------------------------------------------------------------
    def partial_output_ready(self, worker, output, error):
        """Handle conda partial output ready."""
        self.busy = True
        # print(type(output))
        # print(output)

        # Get errors and data from ouput if it exists
        fetch = None
        if output and isinstance(output, dict):
            fetch = output.get('fetch')
            max_val = output.get('maxval', -1)
            value = output.get('progress', -1)

        if fetch:
            status = 'Fetching <b>{0}</b>...'.format(fetch)
            self.update_status(status=status, max_val=max_val, value=value)

    def output_ready(self, worker, output, error):
        """Handle conda output ready."""
        self.check_conditions()

        # Get errors and data from ouput if it exists
        error_text = output.get('error', '')
        exception_type = output.get('exception_type', '')
        exception_name = output.get('exception_name', '')
        success = output.get('success')
        actions = output.get('actions', {})
        # op_order = output.get('op_order', [])
        # action_check_fetch = actions.get('CHECK_FETCH', [])
        # action_rm_fetch = actions.get('RM_FETCHED', [])
        # action_fetch = actions.get('FETCH', [])
        # action_check_extract = actions.get('CHECK_EXTRACT', [])
        # action_rm_extract = actions.get('RM_EXTRACTED', [])
        # action_extract = actions.get('EXTRACT', [])
        # action_unlink = actions.get('UNLINK', [])
        action_link = actions.get('LINK', [])
        # action_symlink_conda = actions.get('SYMLINK_CONDA', [])

        self.busy = False

        # Get errors from json output
        if error_text or exception_type or exception_name or not success:
            self.error = exception_name
            self.success = False
            self.up_to_date = False
        elif success and action_link:
            self.sig_application_updated.emit()
            self.error = None
            self.success = True
            self.up_to_date = False
        elif success:
            self.success = False
            self.error = None
            self.up_to_date = True

        worker.lock.release()
        self.refresh()

    def install_update(self):
        """Install the specified version or latest version of navigator."""
        self.busy = True
        self.refresh()
        # conda_prefix = self.info.et('conda_prefix')
        # root_prefix = self.info.et('root_prefix')
        navigator_prefixes = [
            # os.path.join(self.api.ROOT_PREFIX, 'envs', '_navigator_'),
            # os.path.join(self.api.ROOT_PREFIX, 'envs', '_conda_'),
            self.prefix,
        ]
        for prefix in navigator_prefixes:
            if self.api.environment_exists(prefix=prefix):
                break

        if self.latest_version:
            pkgs = ['{0}=={1}'.format(self.PACKAGE, self.latest_version)]
        else:
            pkgs = [self.PACKAGE.format(self.latest_version)]

        # Lock Navigator
        lock = filelock.FileLock(NAVIGATOR_LOCKFILE)
        lock.acquire()
        worker = self.api.install(prefix=prefix, pkgs=pkgs)
        worker.lock = lock
        worker.sig_partial.connect(self.partial_output_ready)
        worker.sig_finished.connect(self.output_ready)
        self.refresh()

        if self.prefix == self.api.ROOT_PREFIX:
            name = 'root'
        else:
            name = os.path.basename(self.prefix)

        self.button_launch.setFocus()
        if self.current_version:
            msg = 'Updating package on <b>{0}</b>...'.format(name)
        else:
            msg = 'Installing package on <b>{0}</b>...'.format(name)
        self.update_status(msg)

    def launch(self):
        """Launch Anaconda Navigator."""
        leave_path_alone = True
        root_prefix = self.api.ROOT_PREFIX
        prefix = self.prefix
        command = ['anaconda-navigator']

        # Use the app bundle on OSX
        if MAC:
            command = ['open', os.path.join(prefix, 'Anaconda-Navigator.app')]

        launch_cmd(
            prefix,
            command,
            leave_path_alone,
            package_name='anaconda-navigator-app',
            root_prefix=root_prefix,
        )
        self.close()

    # --- Qt Overrides
    # -------------------------------------------------------------------------
    def reject(self):
        """Override Qt method."""
        if self.busy:
            msg_box = MessageBoxQuestion(title='Quit Navigator Updater?',
                                         text='Anaconda Navigator is being '
                                         'updated. <br><br>'
                                         'Are you sure you want to quit?')

            if msg_box.exec_():
                super(MainDialog, self).reject()
        else:
            super(MainDialog, self).reject()
Exemple #8
0
class PackagesDialog(DialogBase):
    """Package dependencies dialog."""

    sig_setup_ready = Signal()

    def __init__(
        self,
        parent=None,
        packages=None,
        pip_packages=None,
        remove_only=False,
        update_only=False,
    ):
        """About dialog."""
        super(PackagesDialog, self).__init__(parent=parent)

        # Variables
        self.api = AnacondaAPI()
        self.actions = None
        self.packages = packages or []
        self.pip_packages = pip_packages or []

        # Widgets
        self.stack = QStackedWidget()
        self.table = QTableWidget()
        self.text = QTextEdit()
        self.label_description = LabelBase()
        self.label_status = LabelBase()
        self.progress_bar = QProgressBar()
        self.button_ok = ButtonPrimary('Apply')
        self.button_cancel = ButtonNormal('Cancel')

        # Widget setup
        self.text.setReadOnly(True)
        self.stack.addWidget(self.table)
        self.stack.addWidget(self.text)
        if remove_only:
            text = 'The following packages will be removed:<br>'
        else:
            text = 'The following packages will be modified:<br>'
        self.label_description.setText(text)
        self.label_description.setWordWrap(True)
        self.label_description.setWordWrap(True)
        self.label_status.setWordWrap(True)
        self.table.horizontalScrollBar().setVisible(False)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setAlternatingRowColors(True)
        self.table.setSelectionMode(QAbstractItemView.NoSelection)
        self.table.setSortingEnabled(True)
        self._hheader = self.table.horizontalHeader()
        self._vheader = self.table.verticalHeader()
        self._hheader.setStretchLastSection(True)
        self._hheader.setDefaultAlignment(Qt.AlignLeft)
        self._hheader.setSectionResizeMode(self._hheader.Fixed)
        self._vheader.setSectionResizeMode(self._vheader.Fixed)
        self.button_ok.setMinimumWidth(70)
        self.button_ok.setDefault(True)
        self.base_minimum_width = 300 if remove_only else 420
        if remove_only:
            self.setWindowTitle("Remove Packages")
        elif update_only:
            self.setWindowTitle("Update Packages")
        else:
            self.setWindowTitle("Install Packages")

        self.setMinimumWidth(self.base_minimum_width)

        # Layouts
        layout_progress = QHBoxLayout()
        layout_progress.addWidget(self.label_status)
        layout_progress.addWidget(SpacerHorizontal())
        layout_progress.addWidget(self.progress_bar)

        layout_buttons = QHBoxLayout()
        layout_buttons.addStretch()
        layout_buttons.addWidget(self.button_cancel)
        layout_buttons.addWidget(SpacerHorizontal())
        layout_buttons.addWidget(self.button_ok)

        layout = QVBoxLayout()
        layout.addWidget(self.label_description)
        layout.addWidget(SpacerVertical())
        layout.addWidget(self.stack)
        layout.addWidget(SpacerVertical())
        layout.addLayout(layout_progress)
        layout.addWidget(SpacerVertical())
        layout.addWidget(SpacerVertical())
        layout.addLayout(layout_buttons)
        self.setLayout(layout)

        # Signals
        self.button_ok.clicked.connect(self.accept)
        self.button_cancel.clicked.connect(self.reject)
        self.button_ok.setDisabled(True)

        # Setup
        self.table.setDisabled(True)
        self.update_status('Solving package specifications',
                           value=0,
                           max_value=0)

    def setup(self, worker, output, error):
        """Setup the widget to include the list of dependencies."""
        if not isinstance(output, dict):
            output = {}

        packages = sorted(pkg.split('==')[0] for pkg in self.packages)
        success = output.get('success')
        error = output.get('error', '')
        exception_name = output.get('exception_name', '')
        actions = output.get('actions', [])
        prefix = worker.prefix

        if exception_name:
            message = exception_name
        else:
            # All requested packages already installed
            message = output.get('message', ' ')

        navi_deps_error = self.api.check_navigator_dependencies(
            actions, prefix)
        description = self.label_description.text()

        if error:
            description = 'No packages will be modified.'
            self.stack.setCurrentIndex(1)
            self.button_ok.setDisabled(True)
            if self.api.is_offline():
                error = ("Some of the functionality of Anaconda Navigator "
                         "will be limited in <b>offline mode</b>. <br><br>"
                         "Installation and upgrade actions will be subject to "
                         "the packages currently available on your package "
                         "cache.")
            self.text.setText(error)
        elif navi_deps_error:
            description = 'No packages will be modified.'
            error = ('Downgrading/removing these packages will modify '
                     'Anaconda Navigator dependencies.')
            self.text.setText(error)
            self.stack.setCurrentIndex(1)
            message = 'NavigatorDependenciesError'
            self.button_ok.setDisabled(True)
        elif success and actions:
            self.stack.setCurrentIndex(0)
            # Conda 4.3.x
            if isinstance(actions, list):
                actions_link = actions[0].get('LINK', [])
                actions_unlink = actions[0].get('UNLINK', [])
            # Conda 4.4.x
            else:
                actions_link = actions.get('LINK', [])
                actions_unlink = actions.get('UNLINK', [])

            deps = set()
            deps = deps.union({p['name'] for p in actions_link})
            deps = deps.union({p['name'] for p in actions_unlink})
            deps = deps - set(packages)
            deps = sorted(list(deps))

            count_total_packages = len(packages) + len(deps)
            plural_total = 's' if count_total_packages != 1 else ''
            plural_selected = 's' if len(packages) != 1 else ''

            self.table.setRowCount(count_total_packages)
            self.table.setColumnCount(4)
            if actions_link:
                description = '{0} package{1} will be installed'.format(
                    count_total_packages, plural_total)
                self.table.showColumn(2)
                self.table.showColumn(3)
            elif actions_unlink and not actions_link:
                self.table.hideColumn(2)
                self.table.hideColumn(3)
                self.table.setHorizontalHeaderLabels(
                    ['Name', 'Unlink', 'Link', 'Channel'])
                description = '{0} package{1} will be removed'.format(
                    count_total_packages, plural_total)

            for row, pkg in enumerate(packages + deps):
                link_item = [p for p in actions_link if p['name'] == pkg]
                if not link_item:
                    link_item = {
                        'version': '-'.center(len('link')),
                        'channel': '-'.center(len('channel')),
                    }
                else:
                    link_item = link_item[0]

                unlink_item = [p for p in actions_unlink if p['name'] == pkg]
                if not unlink_item:
                    unlink_item = {
                        'version': '-'.center(len('link')),
                    }
                else:
                    unlink_item = unlink_item[0]

                unlink_version = str(unlink_item['version'])
                link_version = str(link_item['version'])

                item_unlink_v = QTableWidgetItem(unlink_version)
                item_link_v = QTableWidgetItem(link_version)
                item_link_c = QTableWidgetItem(link_item['channel'])
                if pkg in packages:
                    item_name = QTableWidgetItem(pkg)
                else:
                    item_name = QTableWidgetItem('*' + pkg)

                items = [item_name, item_unlink_v, item_link_v, item_link_c]
                for column, item in enumerate(items):
                    item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
                    self.table.setItem(row, column, item)

            if deps:
                message = (
                    '<b>*</b> indicates the package is a dependency of a '
                    'selected package{0}<br>').format(plural_selected)

            self.button_ok.setEnabled(True)
            self.table.resizeColumnsToContents()
            unlink_width = self.table.columnWidth(1)
            if unlink_width < 60:
                self.table.setColumnWidth(1, 60)
            self.table.setHorizontalHeaderLabels(
                ['Name  ', 'Unlink  ', 'Link  ', 'Channel  '])

        self.table.setEnabled(True)
        self.update_status(message=message)
        self.label_description.setText(description)

        # Adjust size after data has populated the table
        self.table.resizeColumnsToContents()
        width = sum(
            self.table.columnWidth(i) for i in range(self.table.columnCount()))
        delta = (self.width() - self.table.width() +
                 self.table.verticalHeader().width() + 10)

        new_width = width + delta

        if new_width < self.base_minimum_width:
            new_width = self.base_minimum_width

        self.setMinimumWidth(new_width)
        self.setMaximumWidth(new_width)

        self.sig_setup_ready.emit()

    def update_status(self, message='', value=None, max_value=None):
        """Update status of packages dialog."""
        self.label_status.setText(message)

        if max_value is None and value is None:
            self.progress_bar.setVisible(False)
        else:
            self.progress_bar.setVisible(True)
            self.progress_bar.setMaximum(max_value)
            self.progress_bar.setValue(value)
class BatchProcessingView(View):
    btn_run_batch: QPushButton
    progress_bar: QProgressBar
    field_channel: QLineEdit
    field_workflow_config: FileInput
    field_input_dir: FileInput
    field_output_dir: FileInput

    def __init__(self, controller: IBatchProcessingController):
        super().__init__(template_class=MainTemplate)

        if controller is None:
            raise ValueError("controller")
        self._controller = controller
        self.setObjectName("batchProcessingView")

    def load(self, model=None):
        self._setup_ui()

    def _setup_ui(self):
        """
        Set up the UI for the BatchProcessingView
        """
        layout = QVBoxLayout()
        self.setLayout(layout)

        # Workflow config
        self.field_workflow_config = FileInput(
            mode=FileInputMode.FILE, filter="Json file (*.json)", placeholder_text="Load a JSON workflow file..."
        )
        self.field_workflow_config.file_selected.connect(self._form_field_changed)
        row1 = FormRow("1.  Load workflow:", self.field_workflow_config)

        # Channel index
        self.field_channel = QLineEdit("0")
        self.field_channel.setValidator(QIntValidator(bottom=0))
        self.field_channel.textChanged.connect(self._form_field_changed)
        row2 = FormRow("2.  Structure channel index:", self.field_channel)

        # Input dir
        self.field_input_dir = FileInput(mode=FileInputMode.DIRECTORY, placeholder_text="Select a directory...")
        self.field_input_dir.file_selected.connect(self._form_field_changed)
        row3 = FormRow("3.  Input directory:", self.field_input_dir)

        # Output dir
        self.field_output_dir = FileInput(mode=FileInputMode.DIRECTORY, placeholder_text="Select a directory...")
        self.field_output_dir.file_selected.connect(self._form_field_changed)
        row4 = FormRow("4.  Output directory:", self.field_output_dir)

        # Help
        label = QLabel()
        label.setText("Supported file formats: .tif, .tiff, .czi, .ome.tif, .ome.tiff")

        form = QWidget()
        form.setLayout(Form([row1, row2, row3, row4]))
        layout.addWidget(form)
        layout.addWidget(label)

        # Submit
        self.btn_run_batch = QPushButton("Run Batch")
        self.btn_run_batch.clicked.connect(self._btn_run_batch_clicked)
        self.update_button(enabled=False)
        layout.addWidget(self.btn_run_batch)

        # Progress bar
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 100)
        self.progress_bar.setValue(0)
        self.progress_bar.setTextVisible(True)
        self.progress_bar.setVisible(False)
        layout.addWidget(self.progress_bar)

    def update_button(self, enabled: bool):
        """
        Update state of process button
        Inputs:
            enabled: True to enable the button, false to disable it
        """
        self.btn_run_batch.setEnabled(enabled)

    def set_run_batch_in_progress(self):
        """
        Update page to reflect that a batch run is in progress
        """
        # TODO make a CancelButton widget to avoid repeating this connect / disconnect pattern
        self.btn_run_batch.setText("Cancel")
        self.btn_run_batch.clicked.disconnect()
        self.btn_run_batch.clicked.connect(self._btn_run_batch_cancel_clicked)
        self.progress_bar.setVisible(True)

    def reset_run_batch(self):
        """
        Reset page state to reflect that there is no batch run in progress
        """
        self.progress_bar.setValue(0)
        self.btn_run_batch.setText("Run Batch")
        self.btn_run_batch.clicked.disconnect()
        self.btn_run_batch.clicked.connect(self._btn_run_batch_clicked)
        self.progress_bar.setVisible(False)

    def set_progress(self, progress: int):
        """
        Update progress bar

        Inputs:
            progress (int): numerical value to set the progress bar to
        """
        self.progress_bar.setValue(progress)

    #####################################################################
    # Event handlers
    #####################################################################
    def _btn_run_batch_clicked(self):
        self._controller.run_batch()

    def _btn_run_batch_cancel_clicked(self):
        self.btn_run_batch.setText("Canceling...")
        self._controller.cancel_run_batch()

    def _form_field_changed(self, value):
        workflow_config = self.field_workflow_config.selected_file
        channel_index = int(self.field_channel.text()) if self.field_channel.text() else None
        input_dir = self.field_input_dir.selected_file
        output_dir = self.field_output_dir.selected_file

        self._controller.update_batch_parameters(workflow_config, channel_index, input_dir, output_dir)
Exemple #10
0
class AlgorithmOptions(QWidget):
    def __init__(self, settings: StackSettings, image_view: StackImageView):
        super().__init__()
        self.settings = settings
        self.view_name = image_view.name
        self.show_result = QEnumComboBox(
            enum_class=LabelEnum)  # QCheckBox("Show result")
        self._set_show_label_from_settings()
        self.opacity = QDoubleSpinBox()
        self.opacity.setRange(0, 1)
        self.opacity.setSingleStep(0.1)
        self._set_opacity_from_settings()
        self.only_borders = QCheckBox("Only borders")
        self._set_border_mode_from_settings()
        self.borders_thick = QSpinBox()
        self.borders_thick.setRange(1, 25)
        self.borders_thick.setSingleStep(1)
        self._set_border_thick_from_settings()
        self.execute_in_background_btn = QPushButton("Execute in background")
        self.execute_in_background_btn.setToolTip(
            "Run calculation in background. Put result in multiple files panel"
        )
        self.execute_btn = QPushButton("Execute")
        self.execute_btn.setStyleSheet("QPushButton{font-weight: bold;}")
        self.execute_all_btn = QPushButton("Execute all")
        self.execute_all_btn.setToolTip(
            "Execute in batch mode segmentation with current parameter. File list need to be specified in image tab."
        )
        self.execute_all_btn.setDisabled(True)
        self.save_parameters_btn = QPushButton("Save parameters")
        self.block_execute_all_btn = False
        self.algorithm_choose_widget = AlgorithmChoose(settings,
                                                       mask_algorithm_dict)
        self.algorithm_choose_widget.result.connect(self.execution_result_set)
        self.algorithm_choose_widget.finished.connect(self.execution_finished)
        self.algorithm_choose_widget.progress_signal.connect(
            self.progress_info)

        # self.stack_layout = QStackedLayout()
        self.keep_chosen_components_chk = QCheckBox("Save selected components")
        self.keep_chosen_components_chk.setToolTip(
            "Save chosen components when loading segmentation form file\n or from multiple file widget."
        )
        self.keep_chosen_components_chk.stateChanged.connect(
            self.set_keep_chosen_components)
        self.keep_chosen_components_chk.setChecked(
            settings.keep_chosen_components)
        self.show_parameters = QPushButton("Show parameters")
        self.show_parameters.setToolTip(
            "Show parameters of segmentation for each components")
        self.show_parameters_widget = SegmentationInfoDialog(
            self.settings, self.algorithm_choose_widget.change_algorithm)
        self.show_parameters.clicked.connect(self.show_parameters_widget.show)
        self.choose_components = ChosenComponents()
        self.choose_components.check_change_signal.connect(
            image_view.refresh_selected)
        self.choose_components.mouse_leave.connect(image_view.component_unmark)
        self.choose_components.mouse_enter.connect(image_view.component_mark)
        # WARNING works only with one channels algorithms
        # SynchronizeValues.add_synchronization("channels_chose", widgets_list)
        self.chosen_list = []
        self.progress_bar2 = QProgressBar()
        self.progress_bar2.setHidden(True)
        self.progress_bar = QProgressBar()
        self.progress_bar.setHidden(True)
        self.progress_info_lab = QLabel()
        self.progress_info_lab.setHidden(True)
        self.file_list = []
        self.batch_process = BatchProceed()
        self.batch_process.progress_signal.connect(self.progress_info)
        self.batch_process.error_signal.connect(self.execution_all_error)
        self.batch_process.execution_done.connect(self.execution_all_done)
        self.batch_process.range_signal.connect(self.progress_bar.setRange)
        self.is_batch_process = False

        self.setContentsMargins(0, 0, 0, 0)
        main_layout = QVBoxLayout()
        # main_layout.setSpacing(0)
        opt_layout = QHBoxLayout()
        opt_layout.setContentsMargins(0, 0, 0, 0)
        opt_layout.addWidget(self.show_result)
        opt_layout.addWidget(right_label("Opacity:"))
        opt_layout.addWidget(self.opacity)
        main_layout.addLayout(opt_layout)
        opt_layout2 = QHBoxLayout()
        opt_layout2.setContentsMargins(0, 0, 0, 0)
        opt_layout2.addWidget(self.only_borders)
        opt_layout2.addWidget(right_label("Border thick:"))
        opt_layout2.addWidget(self.borders_thick)
        main_layout.addLayout(opt_layout2)
        btn_layout = QGridLayout()
        btn_layout.setContentsMargins(0, 0, 0, 0)
        btn_layout.addWidget(self.execute_btn, 0, 0)
        btn_layout.addWidget(self.execute_in_background_btn, 0, 1)
        btn_layout.addWidget(self.execute_all_btn, 1, 0)
        btn_layout.addWidget(self.save_parameters_btn, 1, 1)
        main_layout.addLayout(btn_layout)
        main_layout.addWidget(self.progress_bar2)
        main_layout.addWidget(self.progress_bar)
        main_layout.addWidget(self.progress_info_lab)
        main_layout.addWidget(self.algorithm_choose_widget, 1)
        # main_layout.addWidget(self.algorithm_choose)
        # main_layout.addLayout(self.stack_layout, 1)
        main_layout.addWidget(self.choose_components)
        down_layout = QHBoxLayout()
        down_layout.addWidget(self.keep_chosen_components_chk)
        down_layout.addWidget(self.show_parameters)
        main_layout.addLayout(down_layout)
        main_layout.addStretch()
        main_layout.setContentsMargins(0, 0, 0, 0)
        # main_layout.setSpacing(0)
        self.setLayout(main_layout)

        # noinspection PyUnresolvedReferences
        self.execute_in_background_btn.clicked.connect(
            self.execute_in_background)
        self.execute_btn.clicked.connect(self.execute_action)
        self.execute_all_btn.clicked.connect(self.execute_all_action)
        self.save_parameters_btn.clicked.connect(self.save_parameters)
        # noinspection PyUnresolvedReferences
        self.opacity.valueChanged.connect(self._set_opacity)
        # noinspection PyUnresolvedReferences
        self.show_result.currentEnumChanged.connect(self._set_show_label)
        self.only_borders.stateChanged.connect(self._set_border_mode)
        # noinspection PyUnresolvedReferences
        self.borders_thick.valueChanged.connect(self._set_border_thick)
        image_view.component_clicked.connect(
            self.choose_components.other_component_choose)
        settings.chosen_components_widget = self.choose_components
        settings.components_change_list.connect(
            self.choose_components.new_choose)
        settings.image_changed.connect(
            self.choose_components.remove_components)
        settings.connect_to_profile(
            f"{self.view_name}.image_state.only_border",
            self._set_border_mode_from_settings)
        settings.connect_to_profile(
            f"{self.view_name}.image_state.border_thick",
            self._set_border_thick_from_settings)
        settings.connect_to_profile(f"{self.view_name}.image_state.opacity",
                                    self._set_opacity_from_settings)
        settings.connect_to_profile(f"{self.view_name}.image_state.show_label",
                                    self._set_show_label_from_settings)

    def _set_border_mode(self, value: bool):
        self.settings.set_in_profile(
            f"{self.view_name}.image_state.only_border", value)

    def _set_border_thick(self, value: int):
        self.settings.set_in_profile(
            f"{self.view_name}.image_state.border_thick", value)

    def _set_opacity(self, value: float):
        self.settings.set_in_profile(f"{self.view_name}.image_state.opacity",
                                     value)

    def _set_show_label(self, value: LabelEnum):
        self.settings.set_in_profile(
            f"{self.view_name}.image_state.show_label", value)

    def _set_border_mode_from_settings(self):
        self.only_borders.setChecked(
            self.settings.get_from_profile(
                f"{self.view_name}.image_state.only_border", True))

    def _set_border_thick_from_settings(self):
        self.borders_thick.setValue(
            self.settings.get_from_profile(
                f"{self.view_name}.image_state.border_thick", 1))

    def _set_opacity_from_settings(self):
        self.opacity.setValue(
            self.settings.get_from_profile(
                f"{self.view_name}.image_state.opacity", 1.0))

    def _set_show_label_from_settings(self):
        self.show_result.setCurrentEnum(
            self.settings.get_from_profile(
                f"{self.view_name}.image_state.show_label",
                LabelEnum.Show_results))

    @Slot(int)
    def set_keep_chosen_components(self, val):
        self.settings.set_keep_chosen_components(val)

    def save_parameters(self):
        dial = PSaveDialog(io_functions.save_parameters_dict,
                           system_widget=False,
                           settings=self.settings,
                           path=IO_SAVE_DIRECTORY)
        if not dial.exec_():
            return
        res = dial.get_result()
        res.save_class.save(res.save_destination,
                            self.algorithm_choose_widget.current_parameters())

    def file_list_change(self, val):
        self.file_list = val
        if len(self.file_list) > 0 and not self.block_execute_all_btn:
            self.execute_all_btn.setEnabled(True)
        else:
            self.execute_all_btn.setDisabled(True)

    def get_chosen_components(self):
        return sorted(self.choose_components.get_chosen())

    @property
    def segmentation(self):
        return self.settings.roi

    @segmentation.setter
    def segmentation(self, val):
        self.settings.roi = val

    def _image_changed(self):
        self.settings.roi = None
        self.choose_components.set_chose([], [])

    def _execute_in_background_init(self):
        if self.batch_process.isRunning():
            return
        self.progress_bar2.setVisible(True)
        self.progress_bar2.setRange(0, self.batch_process.queue.qsize())
        self.progress_bar2.setValue(self.batch_process.index)
        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(0)
        self.execute_btn.setDisabled(True)
        self.batch_process.start()

    def execute_in_background(self):
        # TODO check if components are properly passed
        widget = self.algorithm_choose_widget.current_widget()
        segmentation_profile = widget.get_segmentation_profile()
        task = BatchTask(self.settings.get_project_info(),
                         segmentation_profile, None)
        self.batch_process.add_task(task)
        self.progress_bar2.setRange(0, self.progress_bar2.maximum() + 1)
        self._execute_in_background_init()

    def execute_all_action(self):
        dial = PSaveDialog(
            SaveROI,
            settings=self.settings,
            system_widget=False,
            path="io.save_batch",
            file_mode=PSaveDialog.Directory,
        )
        if not dial.exec_():
            return
        folder_path = str(dial.selectedFiles()[0])

        widget = self.algorithm_choose_widget.current_widget()

        save_parameters = dial.values
        segmentation_profile = widget.get_segmentation_profile()
        for file_path in self.file_list:
            task = BatchTask(file_path, segmentation_profile,
                             (folder_path, save_parameters))
            self.batch_process.add_task(task)
        self.progress_bar2.setRange(
            0,
            self.progress_bar2.maximum() + len(self.file_list))
        self._execute_in_background_init()

    def execution_all_error(self, text):
        QMessageBox.warning(self, "Proceed error", text)

    def execution_all_done(self):
        if not self.batch_process.queue.empty():
            self._execute_in_background_init()
            return
        self.execute_btn.setEnabled(True)
        self.block_execute_all_btn = False
        if len(self.file_list) > 0:
            self.execute_all_btn.setEnabled(True)
        self.progress_bar.setHidden(True)
        self.progress_bar2.setHidden(True)
        self.progress_info_lab.setHidden(True)

    def execute_action(self):
        self.execute_btn.setDisabled(True)
        self.execute_all_btn.setDisabled(True)
        self.block_execute_all_btn = True
        self.is_batch_process = False
        self.progress_bar.setRange(0, 0)
        self.choose_components.setDisabled(True)
        chosen = sorted(self.choose_components.get_chosen())
        blank = get_mask(self.settings.roi, self.settings.mask, chosen)
        if blank is not None:
            # Problem with handling time data in algorithms
            # TODO Fix This
            blank = blank[0]
        self.progress_bar.setHidden(False)
        widget: AlgorithmSettingsWidget = self.algorithm_choose_widget.current_widget(
        )
        widget.set_mask(blank)
        self.progress_bar.setRange(0, widget.algorithm.get_steps_num())
        widget.execute()
        self.chosen_list = chosen

    def progress_info(self, text, num, file_name="", file_num=0):
        self.progress_info_lab.setVisible(True)
        if file_name != "":
            self.progress_info_lab.setText(file_name + "\n" + text)
        else:
            self.progress_info_lab.setText(text)
        self.progress_bar.setValue(num)
        self.progress_bar2.setValue(file_num)

    def execution_finished(self):
        self.execute_btn.setEnabled(True)
        self.block_execute_all_btn = False
        if len(self.file_list) > 0:
            self.execute_all_btn.setEnabled(True)
        self.progress_bar.setHidden(True)
        self.progress_info_lab.setHidden(True)
        self.choose_components.setDisabled(False)

    def execution_result_set(self, result):
        self.settings.set_segmentation_result(result)

    def showEvent(self, _):
        widget = self.algorithm_choose_widget.current_widget()
        widget.image_changed(self.settings.image)