class AlgorithmProgressWidget(QWidget): """ Widget consisting of a progress bar and a button. """ def __init__(self, parent=None): super(AlgorithmProgressWidget, self).__init__(parent) self.progress_bar = None self.details_button = QPushButton('Details') self.details_button.clicked.connect(self.show_dialog) self.layout = QHBoxLayout() self.layout.addStretch() self.layout.addWidget(self.details_button) self.setLayout(self.layout) self.presenter = AlgorithmProgressPresenter(self) def show_progress_bar(self): if self.progress_bar is None: self.progress_bar = QProgressBar() self.progress_bar.setAlignment(Qt.AlignHCenter) self.layout.insertWidget(0, self.progress_bar) self.layout.removeItem(self.layout.takeAt(1)) def hide_progress_bar(self): if self.progress_bar is not None: self.layout.insertStretch(0) self.layout.removeWidget(self.progress_bar) self.progress_bar.close() self.progress_bar = None def show_dialog(self): dialog = AlgorithmMonitorDialog(self, self.presenter.model) dialog.show()
def __init__(self, parent=None): """ init abort or notification ui. Displays while smoothing freezes the application. Allows abort button to be added if needed. """ super(AbortWindow, self).__init__(parent) self.setModal(False) self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint) self.parent = parent self.label_a_1 = QLabel("Executing smoothing algorithm.") self.label_a_2 = QLabel("This may take several minutes.") self.abort_button = QPushButton("Abort") self.abort_button.clicked.connect(self.abort) self.pb = QProgressBar(self) self.pb_counter = 0 self.abort_flag = False self.info_box = None # vbl is short for Vertical Box Layout vbl = QVBoxLayout() vbl.addWidget(self.label_a_1) vbl.addWidget(self.label_a_2) vbl.addWidget(self.pb) vbl.addWidget(self.abort_button) self.setLayout(vbl) self.show()
def update(self, data): """ Update the gui elements. :param data: Data in format of AlgorithmProgressModel.get_running_algorithm_data() """ self.tree.clear() for alg_data in data: name, id, properties = alg_data item = QTreeWidgetItem([name]) self.tree.addTopLevelItem(item) progress_bar = QProgressBar() progress_bar.setAlignment(Qt.AlignHCenter) self.presenter.add_progress_bar(id, progress_bar) cancel_button = CancelButton(self.presenter, id) self.tree.setItemWidget(item, 1, progress_bar) self.tree.setItemWidget(item, 2, cancel_button) for prop in properties: item.addChild(QTreeWidgetItem(prop))
def __init__(self, parent=None): QWidget.__init__(self, parent) self.home_url = None self.webview = WebView(self) self.webview.loadFinished.connect(self.load_finished) self.webview.titleChanged.connect(self.setWindowTitle) self.webview.urlChanged.connect(self.url_changed) home_button = create_toolbutton(self, icon=ima.icon('home'), tip=_("Home"), triggered=self.go_home) zoom_out_button = action2button(self.webview.zoom_out_action) zoom_in_button = action2button(self.webview.zoom_in_action) pageact2btn = lambda prop: action2button(self.webview.pageAction(prop), parent=self.webview) refresh_button = pageact2btn(QWebEnginePage.Reload) stop_button = pageact2btn(QWebEnginePage.Stop) previous_button = pageact2btn(QWebEnginePage.Back) next_button = pageact2btn(QWebEnginePage.Forward) stop_button.setEnabled(False) self.webview.loadStarted.connect(lambda: stop_button.setEnabled(True)) self.webview.loadFinished.connect(lambda: stop_button.setEnabled(False)) progressbar = QProgressBar(self) progressbar.setTextVisible(False) progressbar.hide() self.webview.loadStarted.connect(progressbar.show) self.webview.loadProgress.connect(progressbar.setValue) self.webview.loadFinished.connect(lambda _state: progressbar.hide()) label = QLabel(self.get_label()) self.url_combo = UrlComboBox(self) self.url_combo.valid.connect(self.url_combo_activated) if not WEBENGINE: self.webview.iconChanged.connect(self.icon_changed) self.find_widget = FindReplace(self) self.find_widget.set_editor(self.webview) self.find_widget.hide() find_button = create_toolbutton(self, icon=ima.icon('find'), tip=_("Find text"), toggled=self.toggle_find_widget) self.find_widget.visibility_changed.connect(find_button.setChecked) hlayout = QHBoxLayout() for widget in (previous_button, next_button, home_button, find_button, label, self.url_combo, zoom_out_button, zoom_in_button, refresh_button, progressbar, stop_button): hlayout.addWidget(widget) layout = QVBoxLayout() layout.addLayout(hlayout) layout.addWidget(self.webview) layout.addWidget(self.find_widget) self.setLayout(layout)
def show_progress_bar(self): if self.progress_bar is None: self.progress_bar = QProgressBar() self.progress_bar.setAlignment(Qt.AlignHCenter) self.layout.insertWidget(0, self.progress_bar) self.layout.removeItem(self.layout.takeAt(1))
class AbortWindow(QDialog): """ Displays busy message and provides abort button. The class serves SmoothCube, WorkerThread and SelectSmoothing. """ def __init__(self, parent=None): """ init abort or notification ui. Displays while smoothing freezes the application. Allows abort button to be added if needed. """ super(AbortWindow, self).__init__(parent) self.setModal(False) self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint) self.parent = parent self.label_a_1 = QLabel("Executing smoothing algorithm.") self.label_a_2 = QLabel("This may take several minutes.") self.abort_button = QPushButton("Abort") self.abort_button.clicked.connect(self.abort) self.pb = QProgressBar(self) self.pb_counter = 0 self.abort_flag = False self.info_box = None # vbl is short for Vertical Box Layout vbl = QVBoxLayout() vbl.addWidget(self.label_a_1) vbl.addWidget(self.label_a_2) vbl.addWidget(self.pb) vbl.addWidget(self.abort_button) self.setLayout(vbl) self.show() def init_pb(self, start, end): """ Init the progress bar :param start: Start Value :param end: End Value """ self.pb.setRange(start, end) self.pb_counter = start def update_pb(self): """ This function is called in the worker thread to update the progress bar and checks if the local class variable abort_flag is active. If the abort button is clicked, the main thread will set abort_flag to True. The next time the worker thread calls this function, a custom exception is raised terminating the calculation. The exception is handled by the WorkerThread class. :raises: AbortException: terminating smoothing calculation """ if self.abort_flag: raise AbortException("Abort Calculation") self.pb_counter += 1 self.pb.setValue(self.pb_counter) QApplication.processEvents() def abort(self): """Abort calculation""" self.abort_flag = True self.parent.clean_up() def show_error_message(self, message, title, parent=None): self.info_box = QMessageBox(parent=parent) self.info_box.setIcon(QMessageBox.Information) self.info_box.setText(message) self.info_box.setWindowTitle(title) self.info_box.setStandardButtons(QMessageBox.Ok) self.info_box.show() def smoothing_done(self, component_id=None): """Notify user success""" self.hide() if component_id is None: message = "The result has been added as a" \ " new component of the input Data." \ " The new component can be accessed" \ " in the viewer drop-downs." else: message = "The result has been added as" \ " \"{0}\" and can be selected" \ " in the viewer drop-down menu.".format(component_id) self.show_error_message(message, "Success", self) self.clean_up() def print_error(self, exception): """Print error message""" if "signal only works in main thread" in str(exception): message = "Smoothing Failed!\n\n" + "Please update your SpectralCube package" else: message = "Smoothing Failed!\n\n" + str(exception) self.show_error_message(message, "Error", self) self.clean_up() def clean_up(self): self.parent.clean_up() def keyPressEvent(self, e): if e.key() == Qt.Key_Escape: self.abort()
def __init__(self, parent=None, options_button=None, handle_links=True): QWidget.__init__(self, parent) self.home_url = None self.webview = WebView(self, handle_links=handle_links) self.webview.setup() self.webview.loadFinished.connect(self.load_finished) self.webview.titleChanged.connect(self.setWindowTitle) self.webview.urlChanged.connect(self.url_changed) home_button = create_toolbutton(self, icon=ima.icon('home'), tip=_("Home"), triggered=self.go_home) zoom_out_button = action2button(self.webview.zoom_out_action) zoom_in_button = action2button(self.webview.zoom_in_action) def pageact2btn(prop, icon=None): return action2button(self.webview.pageAction(prop), parent=self.webview, icon=icon) refresh_button = pageact2btn(QWebEnginePage.Reload, icon=ima.icon('refresh')) stop_button = pageact2btn(QWebEnginePage.Stop, icon=ima.icon('stop')) previous_button = pageact2btn(QWebEnginePage.Back, icon=ima.icon('previous')) next_button = pageact2btn(QWebEnginePage.Forward, icon=ima.icon('next')) stop_button.setEnabled(False) self.webview.loadStarted.connect(lambda: stop_button.setEnabled(True)) self.webview.loadFinished.connect( lambda: stop_button.setEnabled(False)) progressbar = QProgressBar(self) progressbar.setTextVisible(False) progressbar.hide() self.webview.loadStarted.connect(progressbar.show) self.webview.loadProgress.connect(progressbar.setValue) self.webview.loadFinished.connect(lambda _state: progressbar.hide()) label = QLabel(self.get_label()) self.url_combo = UrlComboBox(self) self.url_combo.valid.connect(self.url_combo_activated) if not WEBENGINE: self.webview.iconChanged.connect(self.icon_changed) self.find_widget = FindReplace(self) self.find_widget.set_editor(self.webview) self.find_widget.hide() find_button = create_toolbutton(self, icon=ima.icon('find'), tip=_("Find text"), toggled=self.toggle_find_widget) self.find_widget.visibility_changed.connect(find_button.setChecked) hlayout = QHBoxLayout() for widget in (previous_button, next_button, home_button, find_button, label, self.url_combo, zoom_out_button, zoom_in_button, refresh_button, progressbar, stop_button): hlayout.addWidget(widget) if options_button: hlayout.addWidget(options_button) layout = create_plugin_layout(hlayout) layout.addWidget(self.webview) layout.addWidget(self.find_widget) self.setLayout(layout)
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() # 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 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()
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() # 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 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: <i>{0}</i><br>" "Available version: <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(output) # Get errors and data from ouput if it exists 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()