class CloneDialog(EnvironmentActionsDialog): """Clone environment dialog.""" def __init__(self, parent=None, clone_from_name=None): """Clone environment dialog.""" super(CloneDialog, self).__init__(parent=parent) # Widgets self.label_name = LabelBase("Name:") self.text_name = LineEditEnvironment() self.label_location = LabelBase("Location:") self.label_prefix = LabelBase() self.button_ok = ButtonPrimary('Clone') self.button_cancel = ButtonNormal('Cancel') # Widget setup self.align_labels([self.label_name, self.label_location]) self.setMinimumWidth(self.BASE_DIALOG_WIDTH) self.setWindowTitle("Clone from environment: " + clone_from_name) self.text_name.setPlaceholderText("New environment name") self.label_prefix.setObjectName('environment-location') # Layouts grid = QGridLayout() grid.addWidget(self.label_name, 2, 0) grid.addWidget(SpacerHorizontal(), 2, 1) grid.addWidget(self.text_name, 2, 2) grid.addWidget(SpacerVertical(), 3, 0) grid.addWidget(self.label_location, 4, 0) grid.addWidget(self.label_prefix, 4, 2) 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.addLayout(grid) layout.addWidget(SpacerVertical()) layout.addWidget(SpacerVertical()) layout.addLayout(layout_buttons) self.setLayout(layout) # Signals self.text_name.textChanged.connect(self.refresh) self.button_ok.clicked.connect(self.accept) self.button_cancel.clicked.connect(self.reject) # Setup self.text_name.setFocus() self.refresh() def refresh(self, text=''): """Update status of buttons based on combobox selection.""" name = self.name self.update_location() if self.environments: self.button_ok.setDisabled(not self.is_valid_env_name(name))
def __init__(self, *args, **kwargs): """About dialog.""" super(PasswordDialog, self).__init__(*args, **kwargs) self.wm = WorkerManager() # Widgets self.label_text = LabelBase( 'VSCode will be installed through your system <br> package ' 'manager.<br><br>' 'This action requires elevated privileges. Please <br>provide a ' 'password to forward to sudo') self.lineedit = PasswordEdit() self.label_info = LabelBase() self.button_cancel = ButtonNormal('Cancel') self.button_ok = ButtonPrimary('Ok') self.worker = None self._valid = False self._timer = QTimer() self._timer.setInterval(3000) self._timer.timeout.connect(self.check) # Widgets setup self.button_ok.setMinimumWidth(70) self.button_ok.setDefault(True) self.setWindowTitle("Privilege Elevation Required") self.lineedit.setEchoMode(LineEditBase.Password) # Layouts layout_content = QVBoxLayout() layout_content.addWidget(self.label_text) layout_content.addWidget(SpacerVertical()) layout_content.addWidget(self.lineedit, 0, Qt.AlignBottom) layout_content.addWidget(SpacerVertical()) layout_content.addWidget(self.label_info, 0, Qt.AlignTop) layout_content.addWidget(SpacerVertical()) layout_buttons = QHBoxLayout() layout_buttons.addStretch() layout_buttons.addWidget(self.button_cancel) layout_buttons.addWidget(SpacerHorizontal()) layout_buttons.addWidget(self.button_ok) layout_main = QVBoxLayout() layout_main.addLayout(layout_content) layout_main.addWidget(SpacerVertical()) layout_main.addWidget(SpacerVertical()) layout_main.addLayout(layout_buttons) self.setLayout(layout_main) # Signals self.button_ok.clicked.connect(self.accept2) self.button_cancel.clicked.connect(self.reject2) self.lineedit.textChanged.connect(self.refresh) # Setup self.lineedit.setFocus() self.refresh()
def __init__(self, parent=None, clone_from_name=None): """Clone environment dialog.""" super(CloneDialog, self).__init__(parent=parent) # Widgets self.label_name = LabelBase("Name:") self.text_name = LineEditBase() self.label_location = LabelBase("Location:") self.label_prefix = LabelBase() self.button_ok = ButtonPrimary('Clone') self.button_cancel = ButtonNormal('Cancel') # Widget setup self.align_labels([self.label_name, self.label_location]) self.setMinimumWidth(self.BASE_DIALOG_WIDTH) self.setWindowTitle("Clone from environment: " + clone_from_name) self.text_name.setPlaceholderText("New environment name") self.text_name.setValidator(self.get_regex_validator()) self.label_prefix.setObjectName('environment-location') # Layouts grid = QGridLayout() grid.addWidget(self.label_name, 2, 0) grid.addWidget(SpacerHorizontal(), 2, 1) grid.addWidget(self.text_name, 2, 2) grid.addWidget(SpacerVertical(), 3, 0) grid.addWidget(self.label_location, 4, 0) grid.addWidget(self.label_prefix, 4, 2) 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.addLayout(grid) layout.addWidget(SpacerVertical()) layout.addWidget(SpacerVertical()) layout.addLayout(layout_buttons) self.setLayout(layout) # Signals self.text_name.textChanged.connect(self.refresh) self.button_ok.clicked.connect(self.accept) self.button_cancel.clicked.connect(self.reject) # Setup self.text_name.setFocus() self.refresh()
def __init__(self, package): """List item representing a running application.""" super(ListItemRunningApp, self).__init__() self.widget = FrameRunningApps() self.package = package self.label = LabelBase(package) self.checkbox = CheckBoxBase() layout_frame = QHBoxLayout() layout_frame.addWidget(self.checkbox) layout_frame.addWidget(self.label) layout_frame.addStretch() self.widget.setLayout(layout_frame) self.setSizeHint(self.widget_size())
def __init__(self, parent=None, name=None, prefix=None): """Remove existing environment `name` dialog.""" super(RemoveDialog, self).__init__(parent=parent) # Widgets self.label_text = LabelBase('Do you want to remove the environment?') self.label_name = LabelBase('Name:') self.label_name_value = LabelBase(name) self.label_location = LabelBase('Location:') self.label_prefix = LabelBase(prefix) self.button_cancel = ButtonNormal('Cancel') self.button_ok = ButtonDanger('Remove') # Setup self.align_labels([self.label_name, self.label_location]) self.label_prefix.setObjectName('environment-location') self.setWindowTitle('Remove environment') self.setMinimumWidth(380) self.label_name.setMinimumWidth(60) self.label_location.setMinimumWidth(60) # Layouts layout_name = QHBoxLayout() layout_name.addWidget(self.label_name) layout_name.addWidget(SpacerHorizontal()) layout_name.addWidget(self.label_name_value) layout_name.addStretch() layout_location = QHBoxLayout() layout_location.addWidget(self.label_location) layout_location.addWidget(SpacerHorizontal()) layout_location.addWidget(self.label_prefix) layout_location.addStretch() 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.addLayout(layout_name) layout.addWidget(SpacerVertical()) layout.addLayout(layout_location) 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) # Setup self.update_location() self.button_ok.setDisabled(False)
class ListItemRunningApp(QListWidgetItem): """List item representing a running application.""" def __init__(self, package): """List item representing a running application.""" super(ListItemRunningApp, self).__init__() self.widget = FrameRunningApps() self.package = package self.label = LabelBase(package) self.checkbox = CheckBoxBase() layout_frame = QHBoxLayout() layout_frame.addWidget(self.checkbox) layout_frame.addWidget(self.label) layout_frame.addStretch() self.widget.setLayout(layout_frame) self.setSizeHint(self.widget_size()) def set_checked(self, value): """Set the check state for the checkbox in the list item.""" self.checkbox.setChecked(value) def checked(self): """Return True if checked otherwise return False.""" return self.checkbox.isChecked() @staticmethod def set_loading(item): """Override.""" item def text(self): """Qt override.""" return self.label.text() @staticmethod def set_selected(item): """Override.""" item @staticmethod def widget_size(): """Return the size defined in the SASS file.""" return QSize(SASS_VARIABLES.WIDGET_RUNNING_APPS_TOTAL_WIDTH, SASS_VARIABLES.WIDGET_RUNNING_APPS_TOTAL_HEIGHT)
def __init__(self, tooltip, parent=None): """Dialog a custom tool tip.""" super(CustomToolTip, self).__init__(parent=parent) self._parent = parent self._tooltip = tooltip self.style_sheet = None # Widgets self._label_tip = LabelBase(tooltip) # Widget setup self.frame_title_bar.setVisible(False) self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) self.setWindowOpacity(0.96) self.setModal(False) # Layout layout = QHBoxLayout() layout.addWidget(self._label_tip) self.setLayout(layout)
def __init__(self, title='', text='', value=None, value_type=None): """Base message box dialog.""" super(InputDialog, self).__init__() # Widgets self.label = LabelBase(text) self.text = LineEditBase() self.button_ok = ButtonPrimary('Ok') self.button_cancel = ButtonNormal('Cancel') # Widget setup self.setWindowTitle(to_text_string(title)) if value: self.text.setText(str(value)) # Layouts layout = QVBoxLayout() layout_text = QHBoxLayout() layout_text.addWidget(self.label) layout_text.addWidget(SpacerHorizontal()) layout_text.addWidget(self.text) layout_buttons = QHBoxLayout() layout_buttons.addStretch() layout_buttons.addWidget(self.button_cancel) layout_buttons.addWidget(SpacerHorizontal()) layout_buttons.addWidget(self.button_ok) layout.addLayout(layout_text) 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)
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)
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
def __init__(self, parent=None): """License Manager main dialog.""" super(LicenseManagerDialog, self).__init__(parent=parent) self.api = AnacondaAPI() # Widgets self.message_box = None # For testing self.button_add = ButtonPrimary('Add license') self.button_ok = ButtonNormal('Close') self.button_remove = ButtonNormal('Remove license') self.button_contact = ButtonLink('Please contact us.') self.label_info = LabelBase('Manage your Continuum Analytics ' 'license keys.') self.label_contact = LabelBase('Got a problem with your license? ') self.proxy_model = QSortFilterProxyModel(parent=self) self.model = LicenseModel(parent=self) self.table = LicenseTableView(parent=self) self.delegate = BackgroundDelegate(self.table) # Widget setup self.proxy_model.setSourceModel(self.model) self.table.setItemDelegate(self.delegate) self.table.setModel(self.proxy_model) self.setWindowTitle('License Manager') # Layouts layout_buttons = QHBoxLayout() layout_buttons.addWidget(self.label_info) layout_buttons.addWidget(SpacerHorizontal()) layout_buttons.addStretch() layout_buttons.addWidget(self.button_add) layout_buttons.addWidget(SpacerHorizontal()) layout_buttons.addWidget(self.button_remove) layout_buttons_bottom = QHBoxLayout() layout_buttons_bottom.addWidget(self.label_contact) layout_buttons_bottom.addWidget(self.button_contact) layout_buttons_bottom.addStretch() layout_buttons_bottom.addWidget(self.button_ok) layout = QVBoxLayout() layout.addLayout(layout_buttons) layout.addWidget(SpacerVertical()) layout.addWidget(self.table) layout.addWidget(SpacerVertical()) layout.addWidget(SpacerVertical()) layout.addLayout(layout_buttons_bottom) self.setLayout(layout) # Signals self.button_add.clicked.connect(lambda: self.add_license()) self.button_remove.clicked.connect(self.remove_license) self.button_ok.clicked.connect(self.accept) self.button_contact.clicked.connect( lambda v=None: self.sig_url_clicked.emit(self.CONTACT_LINK, 'License Manager')) self.table.sig_dropped.connect(self.handle_drop) # Setup self.button_add.setFocus() self.load_licenses()
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)
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 CreateDialog(EnvironmentActionsDialog): """Create new environment dialog.""" MRO = 'mro' R = 'r' PYTHON_VERSIONS = [u'2.7', u'3.5', u'3.6', u'3.7'] MRO_MAC_MIN_VERSION = (10, 11) def __init__(self, parent=None, api=None): """Create new environment dialog.""" super(CreateDialog, self).__init__(parent=parent, api=api) # Widgets self.label_name = LabelBase("Name:") self.label_location = LabelBase("Location:") self.label_prefix = LabelBase('') self.text_name = LineEditBase() self.label_version = LabelBase("Python version") self.label_packages = LabelBase("Packages:") self.combo_version = ComboBoxBase() self.check_python = CheckBoxBase("Python") self.check_r = CheckBoxBase('R') self.combo_r_type = ComboBoxBase() self.button_ok = ButtonPrimary('Create') self.button_cancel = ButtonNormal('Cancel') # Widgets setup self.align_labels( [self.label_name, self.label_location, self.label_packages] ) self.text_name.setPlaceholderText("New environment name") self.setMinimumWidth(self.BASE_DIALOG_WIDTH) self.setWindowTitle("Create new environment") self.text_name.setValidator(self.get_regex_validator()) self.label_prefix.setObjectName('environment-location') self.combo_version.setObjectName('package-version') self.combo_r_type.setObjectName('r-type') # Supported set of python versions self.combo_version.setDisabled(True) r_types = [self.R] self.combo_r_type.clear() self.combo_r_type.addItems(r_types) self.combo_r_type.setCurrentIndex(0) self.combo_r_type.setEnabled(len(r_types) != 1) # Layouts layout_packages = QGridLayout() layout_packages.addWidget(self.check_python, 0, 0) layout_packages.addWidget(SpacerHorizontal(), 0, 1) layout_packages.addWidget(self.combo_version, 0, 2) layout_packages.addWidget(SpacerVertical(), 1, 0) layout_packages.addWidget(self.check_r, 2, 0) layout_packages.addWidget(SpacerHorizontal(), 2, 1) layout_packages.addWidget(self.combo_r_type, 2, 2) grid = QGridLayout() grid.addWidget(self.label_name, 0, 0, 1, 1) grid.addWidget(SpacerHorizontal(), 0, 1, 1, 1) grid.addWidget(self.text_name, 0, 2, 1, 4) grid.addWidget(SpacerVertical(), 1, 0, 1, 1) grid.addWidget(self.label_location, 2, 0, 1, 1) grid.addWidget(SpacerHorizontal(), 2, 1, 1, 1) grid.addWidget(self.label_prefix, 2, 2, 1, 4) grid.addWidget(SpacerVertical(), 3, 0, 1, 1) grid.addWidget(self.label_packages, 4, 0, 1, 1) grid.addWidget(SpacerHorizontal(), 4, 1, 1, 1) grid.addLayout(layout_packages, 4, 2, 3, 1) layout_buttons = QHBoxLayout() layout_buttons.addStretch() layout_buttons.addWidget(self.button_cancel) layout_buttons.addWidget(SpacerHorizontal()) layout_buttons.addWidget(self.button_ok) main_layout = QVBoxLayout() main_layout.addLayout(grid) main_layout.addWidget(SpacerVertical()) main_layout.addWidget(SpacerVertical()) main_layout.addLayout(layout_buttons) self.setLayout(main_layout) # Signals self.button_ok.clicked.connect(self.accept) self.button_cancel.clicked.connect(self.reject) self.text_name.textChanged.connect(self.refresh) self.check_python.stateChanged.connect(self.refresh) self.check_r.stateChanged.connect(self.refresh) self.sig_setup_ready.connect(self.update_mro) self.sig_setup_ready.connect(self.update_pyversions) # Setup self.text_name.setFocus() self.check_python.setChecked(True) self.check_r.setChecked(False) self.refresh() def update_pyversions(self): """""" python_pks = self._packages.get('python', {}) python_versions = python_pks.get('versions', []) pyvers = set(['.'.join(v.split('.')[:2]) for v in python_versions]) final_pyvers = [] for pyver in self.PYTHON_VERSIONS: if pyver in pyvers: final_pyvers.append(pyver) versions = self.PYTHON_VERSIONS now = "{}.{}".format(sys.version_info.major, sys.version_info.minor) if now not in final_pyvers: # Guard against non-standard version, or the coming 3.7 final_pyvers.append(now) final_pyvers.sort() final_pyvers = list(reversed(final_pyvers)) self.combo_version.addItems(final_pyvers) self.combo_version.setCurrentIndex(versions.index(now)) self.combo_version.setEnabled(True) def update_mro(self): """""" # Operating systems with MRO support r_types = [self.R] if self.api: is_mro_available = self.api._conda_api.is_package_available( 'mro-base', channels=self.channels, ) if is_mro_available and BITS_64: if ((MAC and MAC_VERSION_INFO > self.MRO_MAC_MIN_VERSION) or WIN or LINUX): r_types = [self.MRO, self.R] self.combo_r_type.clear() self.combo_r_type.addItems(r_types) self.combo_r_type.setCurrentIndex(0) self.combo_r_type.setEnabled(len(r_types) != 1) def refresh(self, text=''): """Update status of buttons based on data.""" name = self.name self.update_location() if self.environments: check = self.install_python or self.install_r if check and self.is_valid_env_name(name): self.button_ok.setDisabled(False) else: self.button_ok.setDisabled(True) self.combo_version.setEnabled(self.install_python) self.combo_r_type.setEnabled(self.install_r) @property def python_version(self): """Return the python version if python was selected for install.""" version = None if self.install_python: version = self.combo_version.currentText() return version @property def install_python(self): """Return if python was selected for install.""" return bool(self.check_python.checkState()) @property def install_r(self): """Return if r was selected for install.""" return bool(self.check_r.checkState()) @property def r_type(self): """Return if r was selected for install.""" return bool(self.combo_r_type.currentText())
class ProjectsWidget(WidgetBase): """Main projects widget.""" sig_saved = Signal() sig_login_requested = Signal() def __init__(self, *args, **kwargs): super(ProjectsWidget, self).__init__(*args, **kwargs) self.api = AnacondaAPI() self.timer = None self.timer_content_changed = QTimer() self.project_path = None self.original_content = None self.config = CONF self.timer = None # Widgets self.frame_projects_header = FrameProjectDetailsHeader() self.frame_projects_footer = FrameProjectDetailsFooter() self.button_upload = ButtonPrimary('Upload to Anaconda Cloud') self.button_cancel = ButtonDanger('Cancel') self.label_project_location = LabelProjectLocation( '<b>Project location</b>') self.label_status_message = LabelBase('') self.text_project_location = TextProjectLocation() self.tab_details = QTabWidget() self.file_explorer = ExplorerWidget() self.editor = ProjectEditor(parent=self) # Wigets setup tabbar = self.tab_details.tabBar() tabbar.setFocusPolicy(Qt.StrongFocus) self.tab_details.addTab(self.file_explorer, 'Files') self.tab_details.addTab(self.editor, 'Edit') self.timer_content_changed.setInterval(2000) self.timer_content_changed.timeout.connect(self.check_content_change) self.timer_content_changed.start() # Layouts layout_upload = QHBoxLayout() layout_upload.addWidget(SpacerHorizontal()) layout_upload.addWidget(SpacerHorizontal()) layout_upload.addWidget(self.label_status_message) layout_upload.addStretch() layout_upload.addWidget(self.button_cancel) layout_upload.addWidget(SpacerHorizontal()) layout_upload.addWidget(self.button_upload) layout_upload.addWidget(SpacerHorizontal()) layout_upload.addWidget(SpacerHorizontal()) layout_footer = QVBoxLayout() layout_footer.addWidget(SpacerVertical()) layout_footer.addWidget(self.tab_details) layout_footer.addLayout(layout_upload) layout_footer.addWidget(SpacerVertical()) layout_footer.addWidget(SpacerVertical()) self.frame_projects_footer.setLayout(layout_footer) layout = QVBoxLayout() layout.addWidget(self.frame_projects_footer) self.setLayout(layout) # Signals self.editor.sig_dirty_state.connect(self.set_dirty) self.editor.sig_saved.connect(self.save) self.button_upload.clicked.connect(self.upload) self.button_cancel.clicked.connect(self.cancel) self.file_explorer.sig_add_to_project.connect(self.add_to_project) self.button_cancel.setVisible(False) self.file_explorer.set_current_folder(HOME_PATH) def add_to_project(self, fname): """Add selected file to project.""" file_path = os.path.join( self.project_path, os.path.basename(fname), ) try: shutil.copyfile(fname, file_path) except Exception: pass def check_content_change(self): """Check if content of anaconda-project changed outside.""" if self.project_path: project_config_path = os.path.join(self.project_path, 'anaconda-project.yml') if os.path.isfile(project_config_path): current_content = self.editor.text() with open(project_config_path, 'r') as f: data = f.read() if (current_content != data and data != self.original_content): self.load_project(self.project_path) def set_dirty(self, state): """Set dirty state editor tab.""" text = 'Edit*' if state else 'Edit' self.tab_details.setTabText(1, text) def before_delete(self): """Before deleting a folder, ensure it is not the same as the cwd.""" self.file_explorer.set_current_folder(HOME_PATH) def clear(self): """Reset view for proect details.""" self.text_project_location.setText('') self.editor.set_text('') def cancel(self): """Cancel ongoing project process.""" # TODO: when running project. Cancel ongoing process! self.button_cancel.setVisible(False) self.button_upload.setEnabled(True) def _upload(self, worker, output, error): """Upload callback.""" error = error if error else '' errors = [] if output is not None: errors = output.errors # print(output.status_description) # print(output.logs) # print(errors) if error or errors: if errors: error_msg = error or '\n'.join(errors) elif error: error_msg = 'Upload failed!' self.update_status(error_msg) else: self.update_status('Project <b>{0}</b> upload successful'.format( worker.name)) self.timer = QTimer() self.timer.setSingleShot(True) self.timer.setInterval(10000) self.timer.timeout.connect(lambda: self.update_status('')) self.timer.start() self.button_upload.setEnabled(True) self.button_cancel.setVisible(False) def update_status(self, message): """Update Status Bar message.""" self.label_status_message.setText(message) def upload(self): """Upload project to Anaconda Cloud.""" # Check if is logged in? if not self.api.is_logged_in(): self.update_status('You need to log in to Anaconda Cloud') self.sig_login_requested.emit() self.update_status('') return project = self.api.project_load(self.project_path) name = project.name or os.path.basename(self.project_path) # Check if saved? if self.editor.is_dirty(): self.update_status('Saving project <b>{0}</b>'.format( project.name)) self.editor.save() project = self.api.project_load(self.project_path) if not project.problems: username, token = self.api.get_username_token() self.button_cancel.setVisible(True) worker = self.api.project_upload( project, username=username, token=token, ) worker.sig_finished.connect(self._upload) worker.name = project.name self.button_upload.setEnabled(False) msg = 'Uploading project <b>{0}</b> to Anaconda Cloud.'.format( project.name) self.update_status(msg) else: self.update_status( 'Problems must be fixed before uploading <b>{0}</b>' ''.format(name)) def save(self): """Save current edited project.""" project_config_path = os.path.join(self.project_path, 'anaconda-project.yml') data = self.editor.text() if os.path.isfile(project_config_path): with open(project_config_path, 'w') as f: data = f.write(data) self.load_project(self.project_path, overwrite=False) self.sig_saved.emit() def load_project(self, project_path, overwrite=True): """Load a conda project located at path.""" self.project_path = project_path project = self.api.project_load(project_path) self.project = project self.text_project_location.setText(project_path) self.file_explorer.set_current_folder(project_path) project_config_path = os.path.join(project_path, 'anaconda-project.yml') data = '' if os.path.isfile(project_config_path): with open(project_config_path, 'r') as f: data = f.read() self.original_content = data if overwrite: self.editor.set_text(data) self.set_dirty(False) self.file_explorer.set_home(project_path) self.update_error_status(project) self.update_status('') def ordered_widgets(self): """Return a list of the ordered widgets.""" tabbar = self.tab_details.tabBar() ordered_widgets = [tabbar] ordered_widgets += self.file_explorer.ordered_widgets() ordered_widgets += self.editor.ordered_widgets() ordered_widgets += [self.button_upload] return ordered_widgets def update_error_status(self, project): """Update problems and suggestions.""" if project: problems = project.problems suggestions = project.suggestions if problems or suggestions: icon = QIcon(WARNING_ICON) self.tab_details.setTabIcon(1, icon) else: self.tab_details.setTabIcon(1, QIcon()) self.editor.set_info(problems, suggestions)
def __init__(self, parent=None, api=None): """Create new environment dialog.""" super(CreateDialog, self).__init__(parent=parent, api=api) # Widgets self.label_name = LabelBase("Name:") self.label_location = LabelBase("Location:") self.label_prefix = LabelBase('') self.text_name = LineEditBase() self.label_version = LabelBase("Python version") self.label_packages = LabelBase("Packages:") self.combo_version = ComboBoxBase() self.check_python = CheckBoxBase("Python") self.check_r = CheckBoxBase('R') self.combo_r_type = ComboBoxBase() self.button_ok = ButtonPrimary('Create') self.button_cancel = ButtonNormal('Cancel') # Widgets setup self.align_labels( [self.label_name, self.label_location, self.label_packages] ) self.text_name.setPlaceholderText("New environment name") self.setMinimumWidth(self.BASE_DIALOG_WIDTH) self.setWindowTitle("Create new environment") self.text_name.setValidator(self.get_regex_validator()) self.label_prefix.setObjectName('environment-location') self.combo_version.setObjectName('package-version') self.combo_r_type.setObjectName('r-type') # Supported set of python versions self.combo_version.setDisabled(True) r_types = [self.R] self.combo_r_type.clear() self.combo_r_type.addItems(r_types) self.combo_r_type.setCurrentIndex(0) self.combo_r_type.setEnabled(len(r_types) != 1) # Layouts layout_packages = QGridLayout() layout_packages.addWidget(self.check_python, 0, 0) layout_packages.addWidget(SpacerHorizontal(), 0, 1) layout_packages.addWidget(self.combo_version, 0, 2) layout_packages.addWidget(SpacerVertical(), 1, 0) layout_packages.addWidget(self.check_r, 2, 0) layout_packages.addWidget(SpacerHorizontal(), 2, 1) layout_packages.addWidget(self.combo_r_type, 2, 2) grid = QGridLayout() grid.addWidget(self.label_name, 0, 0, 1, 1) grid.addWidget(SpacerHorizontal(), 0, 1, 1, 1) grid.addWidget(self.text_name, 0, 2, 1, 4) grid.addWidget(SpacerVertical(), 1, 0, 1, 1) grid.addWidget(self.label_location, 2, 0, 1, 1) grid.addWidget(SpacerHorizontal(), 2, 1, 1, 1) grid.addWidget(self.label_prefix, 2, 2, 1, 4) grid.addWidget(SpacerVertical(), 3, 0, 1, 1) grid.addWidget(self.label_packages, 4, 0, 1, 1) grid.addWidget(SpacerHorizontal(), 4, 1, 1, 1) grid.addLayout(layout_packages, 4, 2, 3, 1) layout_buttons = QHBoxLayout() layout_buttons.addStretch() layout_buttons.addWidget(self.button_cancel) layout_buttons.addWidget(SpacerHorizontal()) layout_buttons.addWidget(self.button_ok) main_layout = QVBoxLayout() main_layout.addLayout(grid) main_layout.addWidget(SpacerVertical()) main_layout.addWidget(SpacerVertical()) main_layout.addLayout(layout_buttons) self.setLayout(main_layout) # Signals self.button_ok.clicked.connect(self.accept) self.button_cancel.clicked.connect(self.reject) self.text_name.textChanged.connect(self.refresh) self.check_python.stateChanged.connect(self.refresh) self.check_r.stateChanged.connect(self.refresh) self.sig_setup_ready.connect(self.update_mro) self.sig_setup_ready.connect(self.update_pyversions) # Setup self.text_name.setFocus() self.check_python.setChecked(True) self.check_r.setChecked(False) self.refresh()
def __init__(self, parent=None): """Import environment from environment specification dialog.""" super(ImportDialog, self).__init__(parent=parent) self.environments = None self.env_dirs = None self.selected_file_filter = None # Widgets self.label_name = LabelBase("Name:") self.label_location = LabelBase("Location:") self.label_path = LabelBase("Specification File") self.text_name = LineEditBase() self.label_prefix = LabelBase("") self.text_path = LineEditBase() self.button_path = ButtonNormal("") self.button_cancel = ButtonNormal('Cancel') self.button_ok = ButtonPrimary('Import') # Widgets setup self.align_labels( [self.label_name, self.label_location, self.label_path]) self.label_prefix.setObjectName('environment-location') self.button_path.setObjectName('import') self.button_ok.setDefault(True) self.text_path.setPlaceholderText("File to import from") self.text_name.setPlaceholderText("New environment name") self.setMinimumWidth(self.BASE_DIALOG_WIDTH) self.setWindowTitle("Import new environment") self.text_name.setValidator(self.get_regex_validator()) # Layouts layout_infile = QHBoxLayout() layout_infile.addWidget(self.text_path) layout_infile.addWidget(SpacerHorizontal()) layout_infile.addWidget(self.button_path) layout_grid = QGridLayout() layout_grid.addWidget(self.label_name, 0, 0) layout_grid.addWidget(SpacerHorizontal(), 0, 1) layout_grid.addWidget(self.text_name, 0, 2) layout_grid.addWidget(SpacerVertical(), 1, 0) layout_grid.addWidget(self.label_location, 2, 0) layout_grid.addWidget(SpacerHorizontal(), 2, 1) layout_grid.addWidget(self.label_prefix, 2, 2) layout_grid.addWidget(SpacerVertical(), 3, 0) layout_grid.addWidget(self.label_path, 4, 0) layout_grid.addWidget(SpacerHorizontal(), 4, 1) layout_grid.addLayout(layout_infile, 4, 2) 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.addLayout(layout_grid) 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_path.clicked.connect(self.choose) self.text_path.textChanged.connect(self.refresh) self.text_name.textChanged.connect(self.refresh) # Setup self.text_name.setFocus() self.refresh()
class ImportDialog(EnvironmentActionsDialog): """Import environment from environment specification dialog.""" CONDA_ENV_FILES = 'Conda environment files (*.yaml *.yml)' CONDA_SPEC_FILES = 'Conda explicit specification files (*.txt)' PIP_REQUIREMENT_FILES = 'Pip requirement files (*.txt)' def __init__(self, parent=None): """Import environment from environment specification dialog.""" super(ImportDialog, self).__init__(parent=parent) self.environments = None self.env_dirs = None self.selected_file_filter = None # Widgets self.label_name = LabelBase("Name:") self.label_location = LabelBase("Location:") self.label_path = LabelBase("Specification File") self.text_name = LineEditBase() self.label_prefix = LabelBase("") self.text_path = LineEditBase() self.button_path = ButtonNormal("") self.button_cancel = ButtonNormal('Cancel') self.button_ok = ButtonPrimary('Import') # Widgets setup self.align_labels( [self.label_name, self.label_location, self.label_path]) self.label_prefix.setObjectName('environment-location') self.button_path.setObjectName('import') self.button_ok.setDefault(True) self.text_path.setPlaceholderText("File to import from") self.text_name.setPlaceholderText("New environment name") self.setMinimumWidth(self.BASE_DIALOG_WIDTH) self.setWindowTitle("Import new environment") self.text_name.setValidator(self.get_regex_validator()) # Layouts layout_infile = QHBoxLayout() layout_infile.addWidget(self.text_path) layout_infile.addWidget(SpacerHorizontal()) layout_infile.addWidget(self.button_path) layout_grid = QGridLayout() layout_grid.addWidget(self.label_name, 0, 0) layout_grid.addWidget(SpacerHorizontal(), 0, 1) layout_grid.addWidget(self.text_name, 0, 2) layout_grid.addWidget(SpacerVertical(), 1, 0) layout_grid.addWidget(self.label_location, 2, 0) layout_grid.addWidget(SpacerHorizontal(), 2, 1) layout_grid.addWidget(self.label_prefix, 2, 2) layout_grid.addWidget(SpacerVertical(), 3, 0) layout_grid.addWidget(self.label_path, 4, 0) layout_grid.addWidget(SpacerHorizontal(), 4, 1) layout_grid.addLayout(layout_infile, 4, 2) 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.addLayout(layout_grid) 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_path.clicked.connect(self.choose) self.text_path.textChanged.connect(self.refresh) self.text_name.textChanged.connect(self.refresh) # Setup self.text_name.setFocus() self.refresh() def choose(self): """Display file dialog to select environment specification.""" path, selected_filter = getopenfilename( caption="Import Environment", basedir=os.path.expanduser('~'), parent=None, filters="{0};;{1};;{2}".format(self.CONDA_ENV_FILES, self.CONDA_SPEC_FILES, self.PIP_REQUIREMENT_FILES)) if path: name = self.name self.selected_file_filter = selected_filter self.text_path.setText(path) self.refresh(path) # Try to get the name key of the file if an environment.yaml file if selected_filter == self.CONDA_ENV_FILES: try: with open(path, 'r') as f: raw = f.read() data = yaml.load(raw) name = data.get('name', name) except Exception: pass self.text_name.setText(name) def refresh(self, text=''): """Update the status of buttons based data entered.""" name = self.name path = self.path self.update_location() if (name and path and os.path.exists(self.path) and self.is_valid_env_name(name)): self.button_ok.setDisabled(False) self.button_ok.setDefault(True) else: self.button_ok.setDisabled(True) self.button_cancel.setDefault(True) @property def path(self): """Return the content of the selected path if it exists.""" path = None if os.path.isfile(self.text_path.text()): path = self.text_path.text() return path
def __init__(self, parent=None): """Create new environment dialog.""" super(CreateDialog, self).__init__(parent=parent) # Widgets self.label_name = LabelBase("Name:") self.label_location = LabelBase("Location:") self.label_prefix = LabelBase('') self.text_name = LineEditBase() self.label_version = LabelBase("Python version") self.label_packages = LabelBase("Packages:") self.combo_version = ComboBoxBase() self.check_python = CheckBoxBase("Python") self.check_r = CheckBoxBase('R') self.button_ok = ButtonPrimary('Create') self.button_cancel = ButtonNormal('Cancel') # Widgets setup self.align_labels( [self.label_name, self.label_location, self.label_packages]) self.text_name.setPlaceholderText("New environment name") self.setMinimumWidth(self.BASE_DIALOG_WIDTH) self.setWindowTitle("Create new environment") self.text_name.setValidator(self.get_regex_validator()) self.label_prefix.setObjectName('environment-location') self.combo_version.setObjectName('package-version') # Supported set of python versions versions = self.PYTHON_VERSIONS now = "{}.{}".format(sys.version_info.major, sys.version_info.minor) if now not in versions: # Guard against non-standard version, or the coming 3.6 versions.append(now) versions.sort() versions = list(reversed(versions)) self.combo_version.addItems(versions) self.combo_version.setCurrentIndex(versions.index(now)) # Layouts layout_python = QHBoxLayout() layout_python.addWidget(self.check_python) layout_python.addWidget(self.combo_version) layout_python.addStretch() layout_r = QHBoxLayout() layout_r.addWidget(self.check_r) grid = QGridLayout() grid.addWidget(self.label_name, 0, 0) grid.addWidget(SpacerHorizontal(), 0, 1) grid.addWidget(self.text_name, 0, 2) grid.addWidget(SpacerVertical(), 1, 0) grid.addWidget(self.label_location, 2, 0) grid.addWidget(SpacerHorizontal(), 2, 1) grid.addWidget(self.label_prefix, 2, 2) grid.addWidget(SpacerVertical(), 3, 0) grid.addWidget(self.label_packages, 4, 0) grid.addLayout(layout_python, 4, 2) grid.addWidget(SpacerVertical(), 5, 0) grid.addLayout(layout_r, 6, 2) layout_buttons = QHBoxLayout() layout_buttons.addStretch() layout_buttons.addWidget(self.button_cancel) layout_buttons.addWidget(SpacerHorizontal()) layout_buttons.addWidget(self.button_ok) main_layout = QVBoxLayout() main_layout.addLayout(grid) main_layout.addWidget(SpacerVertical()) main_layout.addWidget(SpacerVertical()) main_layout.addLayout(layout_buttons) self.setLayout(main_layout) # Signals self.button_ok.clicked.connect(self.accept) self.button_cancel.clicked.connect(self.reject) self.text_name.textChanged.connect(self.refresh) self.check_python.stateChanged.connect(self.refresh) self.check_r.stateChanged.connect(self.refresh) # Setup self.text_name.setFocus() self.check_python.setChecked(True) self.check_r.setChecked(False) self.refresh()
def __init__(self, *args, **kwargs): super(ProjectsWidget, self).__init__(*args, **kwargs) self.api = AnacondaAPI() self.timer = None self.timer_content_changed = QTimer() self.project_path = None self.original_content = None self.config = CONF self.timer = None # Widgets self.frame_projects_header = FrameProjectDetailsHeader() self.frame_projects_footer = FrameProjectDetailsFooter() self.button_upload = ButtonPrimary('Upload to Anaconda Cloud') self.button_cancel = ButtonDanger('Cancel') self.label_project_location = LabelProjectLocation( '<b>Project location</b>') self.label_status_message = LabelBase('') self.text_project_location = TextProjectLocation() self.tab_details = QTabWidget() self.file_explorer = ExplorerWidget() self.editor = ProjectEditor(parent=self) # Wigets setup tabbar = self.tab_details.tabBar() tabbar.setFocusPolicy(Qt.StrongFocus) self.tab_details.addTab(self.file_explorer, 'Files') self.tab_details.addTab(self.editor, 'Edit') self.timer_content_changed.setInterval(2000) self.timer_content_changed.timeout.connect(self.check_content_change) self.timer_content_changed.start() # Layouts layout_upload = QHBoxLayout() layout_upload.addWidget(SpacerHorizontal()) layout_upload.addWidget(SpacerHorizontal()) layout_upload.addWidget(self.label_status_message) layout_upload.addStretch() layout_upload.addWidget(self.button_cancel) layout_upload.addWidget(SpacerHorizontal()) layout_upload.addWidget(self.button_upload) layout_upload.addWidget(SpacerHorizontal()) layout_upload.addWidget(SpacerHorizontal()) layout_footer = QVBoxLayout() layout_footer.addWidget(SpacerVertical()) layout_footer.addWidget(self.tab_details) layout_footer.addLayout(layout_upload) layout_footer.addWidget(SpacerVertical()) layout_footer.addWidget(SpacerVertical()) self.frame_projects_footer.setLayout(layout_footer) layout = QVBoxLayout() layout.addWidget(self.frame_projects_footer) self.setLayout(layout) # Signals self.editor.sig_dirty_state.connect(self.set_dirty) self.editor.sig_saved.connect(self.save) self.button_upload.clicked.connect(self.upload) self.button_cancel.clicked.connect(self.cancel) self.file_explorer.sig_add_to_project.connect(self.add_to_project) self.button_cancel.setVisible(False) self.file_explorer.set_current_folder(HOME_PATH)
class ConflictDialog(EnvironmentActionsDialog): """Create new environment dialog if navigator conflicts with deps.""" def __init__(self, parent=None, package=None, extra_message='', current_prefix=None): """Create new environment dialog if navigator conflicts with deps.""" super(ConflictDialog, self).__init__(parent=parent) parts = package.split('=') self.package = parts[0] if '=' in package else package self.package_version = parts[-1] if '=' in package else '' self.current_prefix = current_prefix base_message = ('<b>{0}</b> cannot be installed on this ' 'environment.').format(package) base_message = extra_message or base_message # Widgets self.label_info = LabelBase( base_message + '<br><br>' 'Do you want to install the package in an existing ' 'environment or <br>create a new environment?' ''.format(package)) self.label_name = LabelBase('Name:') self.label_prefix = LabelBase(' ' * 100) self.label_location = LabelBase('Location:') self.combo_name = ComboBoxBase() self.button_ok = ButtonPrimary('Create') self.button_cancel = ButtonNormal('Cancel') # Widgets setup self.align_labels([self.label_name, self.label_location]) self.combo_name.setEditable(True) self.combo_name.setCompleter(None) self.combo_name.setValidator(self.get_regex_validator()) self.setMinimumWidth(self.BASE_DIALOG_WIDTH) self.setWindowTitle("Create new environment for '{}'".format(package)) self.label_prefix.setObjectName('environment-location') self.combo_name.setObjectName('environment-selection') # Layouts grid_layout = QGridLayout() grid_layout.addWidget(self.label_name, 0, 0) grid_layout.addWidget(SpacerHorizontal(), 0, 1) grid_layout.addWidget(self.combo_name, 0, 2) grid_layout.addWidget(SpacerVertical(), 1, 0) grid_layout.addWidget(self.label_location, 2, 0) grid_layout.addWidget(SpacerHorizontal(), 2, 1) grid_layout.addWidget(self.label_prefix, 2, 2) layout_buttons = QHBoxLayout() layout_buttons.addStretch() layout_buttons.addWidget(self.button_cancel) layout_buttons.addWidget(SpacerHorizontal()) layout_buttons.addWidget(self.button_ok) main_layout = QVBoxLayout() main_layout.addWidget(self.label_info) main_layout.addWidget(SpacerVertical()) main_layout.addWidget(SpacerVertical()) main_layout.addLayout(grid_layout) main_layout.addWidget(SpacerVertical()) main_layout.addWidget(SpacerVertical()) main_layout.addLayout(layout_buttons) self.setLayout(main_layout) # Signals self.button_ok.clicked.connect(self.accept) self.button_cancel.clicked.connect(self.reject) self.combo_name.setCurrentText(self.package) self.combo_name.currentTextChanged.connect(self.refresh) self.button_ok.setDisabled(True) def new_env_name(self): """Generate a unique environment name.""" pkg_name_version = self.package + '-' + self.package_version if self.environments: if self.package not in self.environments.values(): env_name = self.package elif pkg_name_version not in self.environments.values(): env_name = pkg_name_version else: for i in range(1, 1000): new_pkg_name = pkg_name_version + '_' + str(i) if new_pkg_name not in self.environments.values(): env_name = new_pkg_name break else: env_name = self.package return env_name def setup(self, worker, info, error): """Setup the dialog conda information as a result of a worker.""" super(ConflictDialog, self).setup(worker, info, error) self.combo_name.blockSignals(True) self.combo_name.clear() new_env_name = self.new_env_name() for i, (env_prefix, env_name) in enumerate(self.environments.items()): # Do not include the env where the conflict was found! if self.current_prefix != env_prefix: self.combo_name.addItem(env_name, env_prefix) self.combo_name.setCurrentText(new_env_name) self.combo_name.setItemData(i, env_prefix, Qt.ToolTipRole) self.combo_name.setCurrentText(new_env_name) self.combo_name.blockSignals(False) self.refresh() def refresh(self): """Refresh state of buttons based on content.""" self.update_location() if self.environments: self.button_ok.setEnabled(bool(self.name)) @property def name(self): """Return the name of the environment.""" return self.combo_name.currentText()
def __init__(self, parent=None, package=None, extra_message='', current_prefix=None): """Create new environment dialog if navigator conflicts with deps.""" super(ConflictDialog, self).__init__(parent=parent) parts = package.split('=') self.package = parts[0] if '=' in package else package self.package_version = parts[-1] if '=' in package else '' self.current_prefix = current_prefix base_message = ('<b>{0}</b> cannot be installed on this ' 'environment.').format(package) base_message = extra_message or base_message # Widgets self.label_info = LabelBase( base_message + '<br><br>' 'Do you want to install the package in an existing ' 'environment or <br>create a new environment?' ''.format(package)) self.label_name = LabelBase('Name:') self.label_prefix = LabelBase(' ' * 100) self.label_location = LabelBase('Location:') self.combo_name = ComboBoxBase() self.button_ok = ButtonPrimary('Create') self.button_cancel = ButtonNormal('Cancel') # Widgets setup self.align_labels([self.label_name, self.label_location]) self.combo_name.setEditable(True) self.combo_name.setCompleter(None) self.combo_name.setValidator(self.get_regex_validator()) self.setMinimumWidth(self.BASE_DIALOG_WIDTH) self.setWindowTitle("Create new environment for '{}'".format(package)) self.label_prefix.setObjectName('environment-location') self.combo_name.setObjectName('environment-selection') # Layouts grid_layout = QGridLayout() grid_layout.addWidget(self.label_name, 0, 0) grid_layout.addWidget(SpacerHorizontal(), 0, 1) grid_layout.addWidget(self.combo_name, 0, 2) grid_layout.addWidget(SpacerVertical(), 1, 0) grid_layout.addWidget(self.label_location, 2, 0) grid_layout.addWidget(SpacerHorizontal(), 2, 1) grid_layout.addWidget(self.label_prefix, 2, 2) layout_buttons = QHBoxLayout() layout_buttons.addStretch() layout_buttons.addWidget(self.button_cancel) layout_buttons.addWidget(SpacerHorizontal()) layout_buttons.addWidget(self.button_ok) main_layout = QVBoxLayout() main_layout.addWidget(self.label_info) main_layout.addWidget(SpacerVertical()) main_layout.addWidget(SpacerVertical()) main_layout.addLayout(grid_layout) main_layout.addWidget(SpacerVertical()) main_layout.addWidget(SpacerVertical()) main_layout.addLayout(layout_buttons) self.setLayout(main_layout) # Signals self.button_ok.clicked.connect(self.accept) self.button_cancel.clicked.connect(self.reject) self.combo_name.setCurrentText(self.package) self.combo_name.currentTextChanged.connect(self.refresh) self.button_ok.setDisabled(True)
class PasswordDialog(DialogBase): """Password dialog.""" def __init__(self, *args, **kwargs): """About dialog.""" super(PasswordDialog, self).__init__(*args, **kwargs) self.wm = WorkerManager() # Widgets self.label_text = LabelBase( 'VSCode will be installed through your system <br> package ' 'manager.<br><br>' 'This action requires elevated privileges. Please <br>provide a ' 'password to forward to sudo') self.lineedit = PasswordEdit() self.label_info = LabelBase() self.button_cancel = ButtonNormal('Cancel') self.button_ok = ButtonPrimary('Ok') self.worker = None self._valid = False self._timer = QTimer() self._timer.setInterval(3000) self._timer.timeout.connect(self.check) # Widgets setup self.button_ok.setMinimumWidth(70) self.button_ok.setDefault(True) self.setWindowTitle("Privilege Elevation Required") self.lineedit.setEchoMode(LineEditBase.Password) # Layouts layout_content = QVBoxLayout() layout_content.addWidget(self.label_text) layout_content.addWidget(SpacerVertical()) layout_content.addWidget(self.lineedit, 0, Qt.AlignBottom) layout_content.addWidget(SpacerVertical()) layout_content.addWidget(self.label_info, 0, Qt.AlignTop) layout_content.addWidget(SpacerVertical()) layout_buttons = QHBoxLayout() layout_buttons.addStretch() layout_buttons.addWidget(self.button_cancel) layout_buttons.addWidget(SpacerHorizontal()) layout_buttons.addWidget(self.button_ok) layout_main = QVBoxLayout() layout_main.addLayout(layout_content) layout_main.addWidget(SpacerVertical()) layout_main.addWidget(SpacerVertical()) layout_main.addLayout(layout_buttons) self.setLayout(layout_main) # Signals self.button_ok.clicked.connect(self.accept2) self.button_cancel.clicked.connect(self.reject2) self.lineedit.textChanged.connect(self.refresh) # Setup self.lineedit.setFocus() self.refresh() def refresh(self): """Refresh state of buttons.""" self.button_ok.setEnabled(bool(self.password)) def _output(self, worker, output, error): """Callback.""" self._valid = True def check(self): """Check password.""" if self.worker._started and self._valid: self.lineedit.setEnabled(False) self.label_info.setText('') self.accept() elif self.worker._started: self._timer.stop() self.lineedit.setEnabled(True) self.button_ok.setEnabled(True) self.lineedit.setFocus() self.lineedit.selectAll() self.label_info.setText('<i>Invalid password</i>') def reject2(self): """Handle reject.""" if self.worker is not None: self.worker.terminate() self.reject() def accept2(self): """Handle accept.""" stdin = to_binary_string(self.password + '\n') if self.worker is not None: self.worker.terminate() self.worker = self.wm.create_process_worker(['sudo', '-kS', 'ls']) self.worker.sig_partial.connect(self._output) self.worker.sig_finished.connect(self._output) self._valid = False self._timer.start() self.worker.start() self.worker.write(stdin) self.lineedit.setEnabled(False) self.button_ok.setEnabled(False) @property def password(self): """Return password.""" return self.lineedit.text()