class ConfigWidget(QWidget): def __init__(self): QWidget.__init__(self) self.layout = QVBoxLayout() self.setLayout(self.layout) self.l = QHBoxLayout() self.layout.addLayout(self.l) self.l = QHBoxLayout() self.layout.addLayout(self.l) self.label = QLabel('epub tag') self.l.addWidget(self.label) self.tags = QLineEdit(self) self.tags.setText(prefs['tags']) self.l.addWidget(self.tags) self.label.setBuddy(self.tags) self.l = QHBoxLayout() self.layout.addLayout(self.l) self.label = QLabel('search result limit:') self.l.addWidget(self.label) self.search_result_count = QLineEdit(self) self.search_result_count.setValidator( QIntValidator(self.search_result_count)) self.search_result_count.setText(prefs['search_result_count']) self.l.addWidget(self.search_result_count) self.label.setBuddy(self.search_result_count) def save_settings(self): prefs['tags'] = self.tags.text() prefs['search_result_count'] = self.search_result_count.text()
class ConfigWidget(QWidget): def __init__(self): QWidget.__init__(self) self.l = QVBoxLayout() self.setLayout(self.l) self.label = QLabel("Voice") self.l.addWidget(self.label) self.voiceOptions = QComboBox() self.l.addWidget(self.voiceOptions) self.rateLabel = QLabel("Rate (-10 to 10)") self.l.addWidget(self.rateLabel) self.rateEdit = QLineEdit() self.rateEdit.setValidator(QIntValidator(-10, 10)) self.rateEdit.setText(str(prefs['rate'])) self.l.addWidget(self.rateEdit) self.volumeLabel = QLabel("Volume (0 to 100)") self.volumeEdit = QLineEdit() self.volumeEdit.setValidator(QIntValidator(0, 100)) self.volumeEdit.setText(str(prefs['volume'])) self.l.addWidget(self.volumeLabel) self.l.addWidget(self.volumeEdit) import win32com.client self.spVoice = win32com.client.Dispatch("SAPI.SpVoice") voices = self.spVoice.GetVoices("", "") for i in range(voices.Count): self.voiceOptions.addItem(voices.Item(i).GetDescription()) if voices.Item(i).GetDescription() == prefs['voice']: self.voiceOptions.setCurrentIndex(i) self.pauseHotKey = HotkeyWidget(prefs, "pause", "Enable Pause/Play hotkey") self.l.addWidget(self.pauseHotKey) self.stopHotKey = HotkeyWidget(prefs, "stop", "Enable Stop hotkey") self.l.addWidget(self.stopHotKey) self.selectHotKey = HotkeyWidget(prefs, "select", "Enable Select Mode hotkey") self.l.addWidget(self.selectHotKey) def save_settings(self): from calibre_plugins.tts_ebook_viewer.hotkeys import keycodes prefs['voice'] = unicode(self.voiceOptions.currentText()) prefs['rate'] = int(self.rateEdit.text()) prefs['volume'] = int(self.volumeEdit.text()) self.pauseHotKey.save_settings(prefs) self.stopHotKey.save_settings(prefs) self.selectHotKey.save_settings(prefs)
class CountSelectorWidget(QWidget): def __init__(self, parent, minimum, maximum, initial=0): QWidget.__init__(self, parent) self._slider = QScrollBar(Qt.Horizontal, self) self._slider.setMinimum(minimum) self._slider.setMaximum(maximum) self._slider.setSingleStep(1) # self._slider.setTickInterval(1) self._linedit = QLineEdit(self) self._linedit.setValidator(QIntValidator(minimum, maximum, self)) self._linedit.setMinimumWidth(20) self._layout = QHBoxLayout(self) self._layout.setContentsMargins(0, 0, 0, 0) self._layout.addWidget(self._slider, 4) self._layout.addWidget(self._linedit, 1) self._slider.valueChanged.connect(self._update_value) self._linedit.textChanged.connect(self._update_value) self._update_value(initial) valueChanged = pyqtSignal(int) def _update_value(self, value): value = int(value) if value else 0 self.value = value self.valueChanged.emit(value) @property def value(self): return self._slider.value() @value.setter def value(self, value): if self._slider.value() != value: self._slider.setValue(value) self._linedit.setText(str(value))
class ConditionEditor(QWidget): # {{{ ACTION_MAP = { 'bool' : ( (_('is true'), 'is true',), (_('is false'), 'is false'), (_('is undefined'), 'is undefined') ), 'ondevice' : ( (_('is true'), 'is set',), (_('is false'), 'is not set'), ), 'identifiers' : ( (_('has id'), 'has id'), (_('does not have id'), 'does not have id'), ), 'int' : ( (_('is equal to'), 'eq'), (_('is less than'), 'lt'), (_('is greater than'), 'gt') ), 'datetime' : ( (_('is equal to'), 'eq'), (_('is less than'), 'lt'), (_('is greater than'), 'gt'), (_('is set'), 'is set'), (_('is not set'), 'is not set'), (_('is more days ago than'), 'older count days'), (_('is fewer days ago than'), 'count_days'), (_('is more days from now than'), 'newer future days'), (_('is fewer days from now than'), 'older future days') ), 'multiple' : ( (_('has'), 'has'), (_('does not have'), 'does not have'), (_('has pattern'), 'has pattern'), (_('does not have pattern'), 'does not have pattern'), (_('is set'), 'is set'), (_('is not set'), 'is not set'), ), 'single' : ( (_('is'), 'is'), (_('is not'), 'is not'), (_('contains'), 'contains'), (_('does not contain'), 'does not contain'), (_('matches pattern'), 'matches pattern'), (_('does not match pattern'), 'does not match pattern'), (_('is set'), 'is set'), (_('is not set'), 'is not set'), ), } for x in ('float', 'rating'): ACTION_MAP[x] = ACTION_MAP['int'] def __init__(self, fm, parent=None): QWidget.__init__(self, parent) self.fm = fm self.action_map = self.ACTION_MAP self.l = l = QGridLayout(self) self.setLayout(l) texts = _('If the ___ column ___ values') try: one, two, three = texts.split('___') except: one, two, three = 'If the ', ' column ', ' value ' self.l1 = l1 = QLabel(one) l.addWidget(l1, 0, 0) self.column_box = QComboBox(self) l.addWidget(self.column_box, 0, 1) self.l2 = l2 = QLabel(two) l.addWidget(l2, 0, 2) self.action_box = QComboBox(self) l.addWidget(self.action_box, 0, 3) self.l3 = l3 = QLabel(three) l.addWidget(l3, 0, 4) self.value_box = QLineEdit(self) l.addWidget(self.value_box, 0, 5) self.column_box.addItem('', '') for key in sorted( conditionable_columns(fm), key=lambda key: sort_key(fm[key]['name'])): self.column_box.addItem(fm[key]['name'], key) self.column_box.setCurrentIndex(0) self.column_box.currentIndexChanged.connect(self.init_action_box) self.action_box.currentIndexChanged.connect(self.init_value_box) for b in (self.column_box, self.action_box): b.setSizeAdjustPolicy(b.AdjustToMinimumContentsLengthWithIcon) b.setMinimumContentsLength(20) @dynamic_property def current_col(self): def fget(self): idx = self.column_box.currentIndex() return unicode_type(self.column_box.itemData(idx) or '') def fset(self, val): for idx in range(self.column_box.count()): c = unicode_type(self.column_box.itemData(idx) or '') if c == val: self.column_box.setCurrentIndex(idx) return raise ValueError('Column %r not found'%val) return property(fget=fget, fset=fset) @dynamic_property def current_action(self): def fget(self): idx = self.action_box.currentIndex() return unicode_type(self.action_box.itemData(idx) or '') def fset(self, val): for idx in range(self.action_box.count()): c = unicode_type(self.action_box.itemData(idx) or '') if c == val: self.action_box.setCurrentIndex(idx) return raise ValueError('Action %r not valid for current column'%val) return property(fget=fget, fset=fset) @property def current_val(self): ans = unicode_type(self.value_box.text()).strip() if self.current_col == 'languages': rmap = {lower(v):k for k, v in lang_map().iteritems()} ans = rmap.get(lower(ans), ans) return ans @dynamic_property def condition(self): def fget(self): c, a, v = (self.current_col, self.current_action, self.current_val) if not c or not a: return None return (c, a, v) def fset(self, condition): c, a, v = condition if not v: v = '' v = v.strip() self.current_col = c self.current_action = a self.value_box.setText(v) return property(fget=fget, fset=fset) def init_action_box(self): self.action_box.blockSignals(True) self.action_box.clear() self.action_box.addItem('', '') col = self.current_col if col: m = self.fm[col] dt = m['datatype'] if dt in self.action_map: actions = self.action_map[dt] else: if col == 'ondevice': k = 'ondevice' elif col == 'identifiers': k = 'identifiers' else: k = 'multiple' if m['is_multiple'] else 'single' actions = self.action_map[k] for text, key in actions: self.action_box.addItem(text, key) self.action_box.setCurrentIndex(0) self.action_box.blockSignals(False) self.init_value_box() def init_value_box(self): self.value_box.setEnabled(True) self.value_box.setText('') self.value_box.setInputMask('') self.value_box.setValidator(None) col = self.current_col if not col: return action = self.current_action if not action: return m = self.fm[col] dt = m['datatype'] tt = '' if col == 'identifiers': tt = _('Enter either an identifier type or an ' 'identifier type and value of the form identifier:value') elif col == 'languages': tt = _('Enter a 3 letter ISO language code, like fra for French' ' or deu for German or eng for English. You can also use' ' the full language name, in which case calibre will try to' ' automatically convert it to the language code.') elif dt in ('int', 'float', 'rating'): tt = _('Enter a number') v = QIntValidator if dt == 'int' else QDoubleValidator self.value_box.setValidator(v(self.value_box)) elif dt == 'datetime': if action == 'count_days': self.value_box.setValidator(QIntValidator(self.value_box)) tt = _('Enter the maximum days old the item can be. Zero is today. ' 'Dates in the future always match') elif action == 'older count days': self.value_box.setValidator(QIntValidator(self.value_box)) tt = _('Enter the minimum days old the item can be. Zero is today. ' 'Dates in the future never match') elif action == 'older future days': self.value_box.setValidator(QIntValidator(self.value_box)) tt = _('Enter the maximum days in the future the item can be. ' 'Zero is today. Dates in the past always match') elif action == 'newer future days': self.value_box.setValidator(QIntValidator(self.value_box)) tt = _('Enter the minimum days in the future the item can be. ' 'Zero is today. Dates in the past never match') else: self.value_box.setInputMask('9999-99-99') tt = _('Enter a date in the format YYYY-MM-DD') else: tt = _('Enter a string.') if 'pattern' in action: tt = _('Enter a regular expression') elif m.get('is_multiple', False): tt += '\n' + _('You can match multiple values by separating' ' them with %s')%m['is_multiple']['ui_to_list'] self.value_box.setToolTip(tt) if action in ('is set', 'is not set', 'is true', 'is false', 'is undefined'): self.value_box.setEnabled(False)
class ConditionEditor(QWidget): # {{{ ACTION_MAP = { 'bool' : ( (_('is true'), 'is true',), (_('is false'), 'is false'), (_('is undefined'), 'is undefined') ), 'ondevice' : ( (_('is true'), 'is set',), (_('is false'), 'is not set'), ), 'identifiers' : ( (_('has id'), 'has id'), (_('does not have id'), 'does not have id'), ), 'int' : ( (_('is equal to'), 'eq'), (_('is less than'), 'lt'), (_('is greater than'), 'gt') ), 'datetime' : ( (_('is equal to'), 'eq'), (_('is less than'), 'lt'), (_('is greater than'), 'gt'), (_('is set'), 'is set'), (_('is not set'), 'is not set'), (_('is more days ago than'), 'older count days'), (_('is fewer days ago than'), 'count_days'), (_('is more days from now than'), 'newer future days'), (_('is fewer days from now than'), 'older future days') ), 'multiple' : ( (_('has'), 'has'), (_('does not have'), 'does not have'), (_('has pattern'), 'has pattern'), (_('does not have pattern'), 'does not have pattern'), (_('is set'), 'is set'), (_('is not set'), 'is not set'), ), 'single' : ( (_('is'), 'is'), (_('is not'), 'is not'), (_('matches pattern'), 'matches pattern'), (_('does not match pattern'), 'does not match pattern'), (_('is set'), 'is set'), (_('is not set'), 'is not set'), ), } for x in ('float', 'rating'): ACTION_MAP[x] = ACTION_MAP['int'] def __init__(self, fm, parent=None): QWidget.__init__(self, parent) self.fm = fm self.action_map = self.ACTION_MAP self.l = l = QGridLayout(self) self.setLayout(l) texts = _('If the ___ column ___ values') try: one, two, three = texts.split('___') except: one, two, three = 'If the ', ' column ', ' value ' self.l1 = l1 = QLabel(one) l.addWidget(l1, 0, 0) self.column_box = QComboBox(self) l.addWidget(self.column_box, 0, 1) self.l2 = l2 = QLabel(two) l.addWidget(l2, 0, 2) self.action_box = QComboBox(self) l.addWidget(self.action_box, 0, 3) self.l3 = l3 = QLabel(three) l.addWidget(l3, 0, 4) self.value_box = QLineEdit(self) l.addWidget(self.value_box, 0, 5) self.column_box.addItem('', '') for key in sorted( conditionable_columns(fm), key=lambda(key): sort_key(fm[key]['name'])): self.column_box.addItem(fm[key]['name'], key) self.column_box.setCurrentIndex(0) self.column_box.currentIndexChanged.connect(self.init_action_box) self.action_box.currentIndexChanged.connect(self.init_value_box) for b in (self.column_box, self.action_box): b.setSizeAdjustPolicy(b.AdjustToMinimumContentsLengthWithIcon) b.setMinimumContentsLength(20) @dynamic_property def current_col(self): def fget(self): idx = self.column_box.currentIndex() return unicode(self.column_box.itemData(idx) or '') def fset(self, val): for idx in range(self.column_box.count()): c = unicode(self.column_box.itemData(idx) or '') if c == val: self.column_box.setCurrentIndex(idx) return raise ValueError('Column %r not found'%val) return property(fget=fget, fset=fset) @dynamic_property def current_action(self): def fget(self): idx = self.action_box.currentIndex() return unicode(self.action_box.itemData(idx) or '') def fset(self, val): for idx in range(self.action_box.count()): c = unicode(self.action_box.itemData(idx) or '') if c == val: self.action_box.setCurrentIndex(idx) return raise ValueError('Action %r not valid for current column'%val) return property(fget=fget, fset=fset) @property def current_val(self): ans = unicode(self.value_box.text()).strip() if self.current_col == 'languages': rmap = {lower(v):k for k, v in lang_map().iteritems()} ans = rmap.get(lower(ans), ans) return ans @dynamic_property def condition(self): def fget(self): c, a, v = (self.current_col, self.current_action, self.current_val) if not c or not a: return None return (c, a, v) def fset(self, condition): c, a, v = condition if not v: v = '' v = v.strip() self.current_col = c self.current_action = a self.value_box.setText(v) return property(fget=fget, fset=fset) def init_action_box(self): self.action_box.blockSignals(True) self.action_box.clear() self.action_box.addItem('', '') col = self.current_col if col: m = self.fm[col] dt = m['datatype'] if dt in self.action_map: actions = self.action_map[dt] else: if col == 'ondevice': k = 'ondevice' elif col == 'identifiers': k = 'identifiers' else: k = 'multiple' if m['is_multiple'] else 'single' actions = self.action_map[k] for text, key in actions: self.action_box.addItem(text, key) self.action_box.setCurrentIndex(0) self.action_box.blockSignals(False) self.init_value_box() def init_value_box(self): self.value_box.setEnabled(True) self.value_box.setText('') self.value_box.setInputMask('') self.value_box.setValidator(None) col = self.current_col if not col: return action = self.current_action if not action: return m = self.fm[col] dt = m['datatype'] tt = '' if col == 'identifiers': tt = _('Enter either an identifier type or an ' 'identifier type and value of the form identifier:value') elif col == 'languages': tt = _('Enter a 3 letter ISO language code, like fra for French' ' or deu for German or eng for English. You can also use' ' the full language name, in which case calibre will try to' ' automatically convert it to the language code.') elif dt in ('int', 'float', 'rating'): tt = _('Enter a number') v = QIntValidator if dt == 'int' else QDoubleValidator self.value_box.setValidator(v(self.value_box)) elif dt == 'datetime': if action == 'count_days': self.value_box.setValidator(QIntValidator(self.value_box)) tt = _('Enter the maximum days old the item can be. Zero is today. ' 'Dates in the future always match') elif action == 'older count days': self.value_box.setValidator(QIntValidator(self.value_box)) tt = _('Enter the minimum days old the item can be. Zero is today. ' 'Dates in the future never match') elif action == 'older future days': self.value_box.setValidator(QIntValidator(self.value_box)) tt = _('Enter the maximum days in the future the item can be. ' 'Zero is today. Dates in the past always match') elif action == 'newer future days': self.value_box.setValidator(QIntValidator(self.value_box)) tt = _('Enter the minimum days in the future the item can be. ' 'Zero is today. Dates in the past never match') else: self.value_box.setInputMask('9999-99-99') tt = _('Enter a date in the format YYYY-MM-DD') else: tt = _('Enter a string.') if 'pattern' in action: tt = _('Enter a regular expression') elif m.get('is_multiple', False): tt += '\n' + _('You can match multiple values by separating' ' them with %s')%m['is_multiple']['ui_to_list'] self.value_box.setToolTip(tt) if action in ('is set', 'is not set', 'is true', 'is false', 'is undefined'): self.value_box.setEnabled(False)
class OperationsPanel(QScrollArea): def __init__(self): super().__init__() self.app_state = AppState() self.setWidgetResizable(True) self.initUI() def initUI(self): self.container = QToolBox() self.setWidget(self.container) self.b_save_edit = QPushButton("Save current edit") self.b_save_edit.clicked.connect(self._applySaveEdit) self.container.addItem(OptionBox([self.b_save_edit]), "Save") self.tf_importance_point_count = QLineEdit() self.tf_importance_point_count.setPlaceholderText( "Number of Points to Sample") self.tf_importance_point_count.setValidator( QIntValidator(1, 1000000, self)) self.b_importance_apply = QPushButton("Apply Sampling") self.b_importance_apply.clicked.connect( self._applyFaceImportanceSampling) self.container.addItem( OptionBox( [self.tf_importance_point_count, self.b_importance_apply]), "Importance Sampling (Mesh)") self.tf_poisson_point_count = QLineEdit() self.tf_poisson_point_count.setPlaceholderText( "Number of Points to Sample") self.tf_poisson_point_count.setValidator( QIntValidator(1, 1000000, self)) self.tf_poisson_radius = QLineEdit() self.tf_poisson_radius.setPlaceholderText( "Radius of the poisson disks") self.tf_poisson_radius.setValidator(QDoubleValidator( 0.0, 2.0, 5, self)) self.b_poisson_apply = QPushButton("Apply Sampling") self.b_poisson_apply.clicked.connect(self._applyPoissonDiskSampling) self.container.addItem( OptionBox([ self.tf_poisson_point_count, self.tf_poisson_radius, self.b_poisson_apply ]), "Poisson Sampling (Mesh)") self.tf_montecarlo_point_count = QLineEdit() self.tf_montecarlo_point_count.setPlaceholderText( "Number of Points to Sample") self.tf_montecarlo_point_count.setValidator( QIntValidator(1, 1000000, self)) self.b_montecarlo_apply = QPushButton("Apply Sampling") self.b_montecarlo_apply.clicked.connect(self._applyMontecarloSampling) self.container.addItem( OptionBox( [self.tf_montecarlo_point_count, self.b_montecarlo_apply]), "Montecarlo Sampling (Mesh)") self.tf_centroid_count = QLineEdit() self.tf_centroid_count.setPlaceholderText("Centroid Count") self.tf_centroid_count.setValidator(QIntValidator(1, 1000000, self)) self.b_show_centroids = QPushButton("Apply FPS") self.b_show_centroids.clicked.connect(self._applyFPS) self.container.addItem( OptionBox([self.tf_centroid_count, self.b_show_centroids]), "FPS Sampling (Point)") self.tf_show_pp2_centroids = QLineEdit() self.tf_show_pp2_centroids.setPlaceholderText("Number of Centroids") self.tf_show_pp2_centroids.setValidator(QIntValidator( 1, 1000000, self)) self.tf_show_pp2_centroids_with_ball = QLineEdit() self.tf_show_pp2_centroids_with_ball.setPlaceholderText( "Number of Centroids with plotted radius") self.tf_show_pp2_centroids_with_ball.setValidator( QIntValidator(1, 1000000, self)) self.tf_show_pp2_radius = QLineEdit() self.tf_show_pp2_radius.setPlaceholderText( "Radius of the neighbour area") self.tf_show_pp2_radius.setValidator( QDoubleValidator(0.0, 2.0, 5, self)) self.b_show_pp2_step = QPushButton("Apply Sampling") self.b_show_pp2_step.clicked.connect(self._show_pp2_step) self.container.addItem( OptionBox([ self.tf_show_pp2_centroids, self.tf_show_pp2_centroids_with_ball, self.tf_show_pp2_radius, self.b_show_pp2_step ]), "Show PointNet2 sampling") #Event Handlers def _applyFPS(self, event): item = self.app_state.current_item if (item is None or item.data is None): return if (item.type != item.TypePointCloud): self.app_state.showError( 'This operation can only be applyed to a Point Clouds.') return if (len(self.tf_centroid_count.text()) <= 0): return count = int(self.tf_centroid_count.text()) rateo = count / item.data.pos.size(0) if (rateo >= 1): self.app_state.showError( 'The number of point to select with FPS({}) have to be less than the total number of points({}).' .format(count, item.data.pos.size(0))) return item.data.pos = item.data.pos.double() idx = FPS(item.data.pos, torch.zeros(item.data.pos.size(0)).long(), rateo) new_item = Item(name='{}-FPS'.format(item.name), data=Data(pos=item.data.pos[idx]), type=Item.TypePointCloud) self.app_state.setNewItem(new_item) def _applyPoissonDiskSampling(self, event): item = self.app_state.current_item if (item is None or item.data is None): return if (item.type != item.TypeMesh): self.app_state.showError( 'This operation can only be applyed to be a Mesh object.') return if (len(self.tf_poisson_point_count.text()) <= 0 or len(self.tf_poisson_radius.text()) <= 0): return count = int(self.tf_poisson_point_count.text()) radio = float(self.tf_poisson_radius.text()) item.data.pos = item.data.pos.float() new_data = PoissonDiskSampling(count, radio)(item.data) new_item = Item(name='{}-Poisson'.format(item.name), data=new_data, type=Item.TypePointCloud) self.app_state.setNewItem(new_item) def _applyMontecarloSampling(self, event): item = self.app_state.current_item if (item is None or item.data is None): return if (item.type != item.TypeMesh): self.app_state.showError( 'This operation can only be applyed to be a Mesh object.') return if (len(self.tf_montecarlo_point_count.text()) <= 0): return count = int(self.tf_montecarlo_point_count.text()) item.data.pos = item.data.pos.float() new_data = MontecarloSampling(count)(item.data) new_item = Item(name='{}-Montecarlo'.format(item.name), data=new_data, type=Item.TypePointCloud) self.app_state.setNewItem(new_item) def _applyFaceImportanceSampling(self, event): item = self.app_state.current_item if (item is None or item.data is None): return if (item.type != item.TypeMesh): self.app_state.showError( 'This operation can only be applyed to be a Mesh object.') return if (len(self.tf_importance_point_count.text()) <= 0): return count = int(self.tf_importance_point_count.text()) item.data.pos = item.data.pos.float() new_data = SamplePoints(count)(item.data) new_item = Item(name='{}-ImportanceSamped'.format(item.name), data=new_data, type=Item.TypePointCloud) self.app_state.setNewItem(new_item) def _show_pp2_step(self, event): item = self.app_state.current_item if (item is None or item.data is None): return if (item.type != item.TypePointCloud): self.app_state.showError( 'This operation can only be applyed to a Point Clouds.') return if (len(self.tf_show_pp2_centroids.text()) <= 0 or len(self.tf_show_pp2_centroids_with_ball.text()) <= 0): return count = int(self.tf_show_pp2_centroids.text()) rateo = count / item.data.pos.size(0) if (rateo >= 1): self.app_state.showError( 'The number of point to select with FPS({}) have to be less than the total number of points({}).' .format(count, item.data.pos.size(0))) return with_ball = int(self.tf_show_pp2_centroids_with_ball.text()) if (with_ball > count): self.app_state.showError( 'The number of point for which plot the radius({}), have to be less than the sampled ammount({}).' .format(with_ball, count)) return item.data.pos = item.data.pos.double() idx = FPS(item.data.pos, torch.zeros(item.data.pos.size(0)).long(), rateo) radius = 0.0 if len(self.tf_show_pp2_radius.text()) <=0 \ else float(self.tf_show_pp2_radius.text()) render = CenterAndRadious(item.data.pos.size(0), centroids_idx=idx, centroid_to_draw=with_ball, radius=radius) self.app_state.setNewItem(item, render) def _applySaveEdit(self, event): sourceItem = self.app_state.current_item item = Item(data=sourceItem.data, name=sourceItem.name, type=sourceItem.type) self.app_state.addItem(item)
def request_octo_init_settings(self, wizard, method): vbox = QVBoxLayout() next_enabled = True label = QLabel(_("Enter a label to name your device:")) name = QLineEdit() hl = QHBoxLayout() hl.addWidget(label) hl.addWidget(name) hl.addStretch(1) vbox.addLayout(hl) def clean_text(widget): text = widget.toPlainText().strip() return ' '.join(text.split()) if method in [TIM_NEW, TIM_RECOVER]: gb = QGroupBox() hbox1 = QHBoxLayout() gb.setLayout(hbox1) vbox.addWidget(gb) gb.setTitle(_("Select your seed length:")) bg_numwords = QButtonGroup() for i, count in enumerate([12, 18, 24]): rb = QRadioButton(gb) rb.setText(_("%d words") % count) bg_numwords.addButton(rb) bg_numwords.setId(rb, i) hbox1.addWidget(rb) rb.setChecked(True) cb_pin = QCheckBox(_('Enable PIN protection')) cb_pin.setChecked(True) else: text = QTextEdit() text.setMaximumHeight(60) if method == TIM_MNEMONIC: msg = _("Enter your BIP39 mnemonic:") else: msg = _("Enter the master private key beginning with xprv:") def set_enabled(): from electrum.keystore import is_xprv wizard.next_button.setEnabled(is_xprv(clean_text(text))) text.textChanged.connect(set_enabled) next_enabled = False vbox.addWidget(QLabel(msg)) vbox.addWidget(text) pin = QLineEdit() pin.setValidator(QRegExpValidator(QRegExp('[1-9]{0,9}'))) pin.setMaximumWidth(100) hbox_pin = QHBoxLayout() hbox_pin.addWidget(QLabel(_("Enter your PIN (digits 1-9):"))) hbox_pin.addWidget(pin) hbox_pin.addStretch(1) if method in [TIM_NEW, TIM_RECOVER]: vbox.addWidget(WWLabel(RECOMMEND_PIN)) vbox.addWidget(cb_pin) else: vbox.addLayout(hbox_pin) passphrase_msg = WWLabel(PASSPHRASE_HELP_SHORT) passphrase_warning = WWLabel(PASSPHRASE_NOT_PIN) passphrase_warning.setStyleSheet("color: red") cb_phrase = QCheckBox(_('Enable passphrases')) cb_phrase.setChecked(False) vbox.addWidget(passphrase_msg) vbox.addWidget(passphrase_warning) vbox.addWidget(cb_phrase) # ask for recovery type (random word order OR matrix) if method == TIM_RECOVER: gb_rectype = QGroupBox() hbox_rectype = QHBoxLayout() gb_rectype.setLayout(hbox_rectype) vbox.addWidget(gb_rectype) gb_rectype.setTitle(_("Select recovery type:")) bg_rectype = QButtonGroup() rb1 = QRadioButton(gb_rectype) rb1.setText(_('Scrambled words')) bg_rectype.addButton(rb1) bg_rectype.setId(rb1, RECOVERY_TYPE_SCRAMBLED_WORDS) hbox_rectype.addWidget(rb1) rb1.setChecked(True) rb2 = QRadioButton(gb_rectype) rb2.setText(_('Matrix')) bg_rectype.addButton(rb2) bg_rectype.setId(rb2, RECOVERY_TYPE_MATRIX) hbox_rectype.addWidget(rb2) else: bg_rectype = None wizard.exec_layout(vbox, next_enabled=next_enabled) if method in [TIM_NEW, TIM_RECOVER]: item = bg_numwords.checkedId() pin = cb_pin.isChecked() recovery_type = bg_rectype.checkedId() if bg_rectype else None else: item = ' '.join(str(clean_text(text)).split()) pin = str(pin.text()) recovery_type = None return (item, name.text(), pin, cb_phrase.isChecked(), recovery_type)
class ParameterPanel(EditionWidget, WidgetController): """Edition Panel implementation.""" def __init__(self, astergui, parent=None): """ Create panel. Arguments: astergui (AsterGui): AsterGui instance. parent (Optional[QWidget]): Parent widget. """ super(ParameterPanel, self).__init__(parent=parent, name=translate("ParameterPanel", "Edit command"), astergui=astergui) self.setPixmap(load_pixmap("as_pic_edit_command.png")) self._files_model = astergui.study().dataFilesModel() self._unit_model = None self._command = None self.title = ParameterTitle(self) self.title.installEventFilter(self) self._name = QLineEdit(self) self.views = QStackedWidget(self) v_layout = QVBoxLayout(self) v_layout.setContentsMargins(0, 0, 0, 0) v_layout.setSpacing(5) v_layout.addWidget(self.title) v_layout.addWidget(HLine(self)) n_layout = QHBoxLayout() v_layout.addLayout(n_layout) n_layout.addWidget(QLabel(translate("ParameterPanel", "Name"), self)) n_layout.addWidget(self._name) # force to be a valid identifier + length <= 8 self._name.setValidator(QRegExpValidator(QRegExp(r"[a-zA-Z]\w{1,7}"))) # create toolbar tbar = QToolBar(self) tbar.setToolButtonStyle(Qt.ToolButtonIconOnly) # - Edit comment edit_comment = QAction(translate("AsterStudy", "Edit &Comment"), self) edit_comment.setToolTip(translate("AsterStudy", "Edit comment")) edit_comment.setStatusTip( translate("AsterStudy", "Edit comment for the " "selected object")) edit_comment.setIcon(load_icon("as_pic_edit_comment.png")) connect(edit_comment.triggered, self._editComment) tbar.addAction(edit_comment) # - Switch on/off business-translations title = translate("AsterStudy", "Use Business-Oriented Translations") self.use_translations = QAction(title, self) title = translate("AsterStudy", "Use business-oriented translations") self.use_translations.setToolTip(title) self.use_translations.setStatusTip(title) self.use_translations.setIcon(load_icon("as_pic_use_translations.png")) self.use_translations.setCheckable(True) if behavior().forced_native_names: force = behavior().force_native_names self.use_translations.setDisabled(True) is_on = not force else: is_on = behavior().use_business_translations Options.use_translations = is_on self.use_translations.setChecked(is_on) connect(self.use_translations.toggled, self.updateTranslations) tbar.addAction(self.use_translations) # - Hide unused hide_unused = astergui.action(ActionType.HideUnused) connect(hide_unused.toggled, self._unusedVisibility) tbar.addAction(hide_unused) # - What's this whats_this = QWhatsThis.createAction(tbar) whats_this.setToolTip(translate("AsterStudy", "What's this?")) whats_this.setStatusTip( translate("AsterStudy", "Show element's description")) whats_this.setIcon(load_icon("as_pic_whats_this.png")) tbar.addAction(whats_this) # - Link to doc tbar.addAction(astergui.action(ActionType.LinkToDoc)) n_layout.addWidget(tbar) v_layout.addWidget(self.views) self._updateState() def unitModel(self): """ Method that get unit model. Returns: UnitModel: Unit model. """ return self._unit_model def command(self): """ Get command being edited. Returns: Command: Command being edited. """ return self._command def setCommand(self, command): """ Set command to edit. Arguments: command (Command): Command to edit. """ self.clear() self._command = command if self._command is None: self._name.setText("") else: self._name.setText(self._command.name) self._unit_model = UnitModel(command.stage) pview = self._createParameterView(ParameterPath(self._command), '') pview.view().setItemValue(command.storage) hide_unused = self.astergui().action(ActionType.HideUnused) pview.setUnusedVisibile(not hide_unused.isChecked()) self.views.setCurrentWidget(pview) self._updateState() def currentPath(self): """ Get currently edited parameter path. Returns: str: currently edited parameter path. """ path = "" wid = self.currentParameterView() if wid is not None: path = wid.path() return path def isCurrentCommand(self): """ Get true if the currently edited view contains command. Returns: bool: Current edited command flag """ curpath = self.currentPath() return ParameterPath(self.command()).isEqual(curpath) def currentParameterView(self): """ Get current parameter view. Returns: ParameterView: current view. """ return self.views.currentWidget() def clear(self): """Remove all parameter views.""" while self.views.count() > 0: wid = self.views.widget(0) if wid is not None: self.views.removeWidget(wid) wid.deleteLater() def store(self): """ Save data from all parameter views. """ cmd = self.command() if cmd is not None: with auto_dupl_on(self.astergui().study().activeCase): cmd.rename(self._name.text()) wid = self._viewByPath(ParameterPath(cmd)) if wid is not None: cmd.init(wid.view().itemValue()) def requiredButtons(self): """ Return the combination of standard button flags required for this widget. Returns: int: button flags for buttons required for this widget (combination of QDialogButtonBox.StandardButton flags). """ if self.isCurrentCommand(): return QDialogButtonBox.Ok | QDialogButtonBox.Apply | \ QDialogButtonBox.Close else: return QDialogButtonBox.Ok | QDialogButtonBox.Cancel | \ QDialogButtonBox.Abort def isButtonEnabled(self, button): """ Return True if a particular button is enabled. Arguments: button (QDialogButtonBox.StandardButton): button flag. Returns: True: that means that all buttons should be enabled. """ return True def perform(self, button): """ Perform action on button click. Redefined method from the base class. Arguments: button (QDialogButtonBox.StandardButton): clicked button flag. """ if button == QDialogButtonBox.Ok: self.performOk() elif button == QDialogButtonBox.Apply: self.performApply() elif button == QDialogButtonBox.Abort: self.performAbort() elif button == QDialogButtonBox.Close or \ button == QDialogButtonBox.Cancel: self.performClose() def performOk(self): """Called when `Ok` button is clicked in Edition panel.""" self.performChanges(True) def performApply(self): """Called when `Apply` button is clicked in Edition panel.""" self.performChanges(False) def performAbort(self): """Called when `Abort` button is clicked in Edition panel.""" pref_mgr = self.astergui().preferencesMgr() msg = translate( "ParameterPanel", "Command edition will be aborted and " "all made changes will be lost. " "Do you want to continue?") noshow = "parampanel_abort" ask = MessageBox.question(self.astergui().mainWindow(), translate("ParameterPanel", "Abort"), msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes, noshow=noshow, prefmgr=pref_mgr) if ask == QMessageBox.Yes: self.close() self.astergui().study().revert() def performClose(self): """Called when `Cancel` button is clicked in Edition panel.""" has_modif = self._hasModifications() if has_modif: pref_mgr = self.astergui().preferencesMgr() msg = translate( "ParameterPanel", "There are some unsaved modifications will be " "lost. Do you want to continue?") noshow = "parampanel_close" ask = MessageBox.question(self.astergui().mainWindow(), translate("ParameterPanel", "Close"), msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes, noshow=noshow, prefmgr=pref_mgr) has_modif = ask != QMessageBox.Yes if not has_modif: self.performDissmis(True) def performChanges(self, close=True): """ Validate and store the command into data model. """ wid = self.currentParameterView() if wid is not None: view = wid.view() if view.validate(): cur_path = self.currentPath() if self.isCurrentCommand(): self.store() self._files_model.update() if self.astergui() is not None: opname = translate("ParameterPanel", "Edit command") self.astergui().study().commit(opname) self.astergui().update() if close: self.performDissmis(False) msg = translate("ParameterPanel", "Command '{}' successfully stored") msg = msg.format(self._name.text()) self.astergui().showMessage(msg) else: child_val = view.itemValue() self._removeCurrentView() curview = self.currentParameterView() subitem = curview.view().findItemByPath(cur_path) if subitem is not None: subitem.setItemValue(child_val) self._updateState() self.updateButtonStatus() def performDissmis(self, revert=True): """ Cancel changes and revert the command changes. """ if self.isCurrentCommand(): self.close() if revert: self.astergui().study().revert() else: self._removeCurrentView() self._updateState() self.updateButtonStatus() def showEvent(self, event): """ Reimplemented for internal reason: updates the title depending on read only state, etc. """ title = translate("ParameterPanel", "View command") \ if self.isReadOnly() else \ translate("ParameterPanel", "Edit command") self.setWindowTitle(title) hide_unused = self.astergui().action(ActionType.HideUnused) hide_unused.setVisible(True) hide_unused.setChecked(self.isReadOnly()) # update meshview meshes = avail_meshes_in_cmd(self.command()) for i, mesh in enumerate(meshes): filename, meshname = get_cmd_mesh(mesh) if filename: if i > 0: self.meshview().displayMEDFileName(filename, meshname, 1.0, False) else: self.meshview().displayMEDFileName(filename, meshname, 1.0, True) super(ParameterPanel, self).showEvent(event) def hideEvent(self, event): """ Reimplemented for internal reason: hides "Hide unused" action. """ hide_unused = self.astergui().action(ActionType.HideUnused) hide_unused.setVisible(False) super(ParameterPanel, self).hideEvent(event) def updateTranslations(self): """ Update translations in GUI elements. """ Options.use_translations = self.use_translations.isChecked() self._updateState() for i in xrange(self.views.count()): view = self.views.widget(i) view.updateTranslations() def eventFilter(self, receiver, event): """ Event filter; processes clicking ln links in What's This window. """ if receiver == self.title and event.type() == QEvent.WhatsThisClicked: QDesktopServices.openUrl(QUrl(event.href())) return super(ParameterPanel, self).eventFilter(receiver, event) def _hasModifications(self): curview = self.currentParameterView().view() \ if self.currentParameterView() is not None else None return curview.hasModifications() \ if curview is not None else False def _updateState(self): """Update state and current title label.""" disabled = self.command() is None self.setDisabled(disabled) if not disabled: disabled = self.command().gettype(ConversionLevel.NoFail) is None self._name.setDisabled(disabled) txt = [] pview = self.currentParameterView() if pview is not None: txt = pview.path().names() ppath = None txt_list = [] tooltip = "" whats_this = "" while len(txt) > 0: name = txt.pop(0) if ppath is None: ppath = ParameterPath(self.command(), name=name) else: ppath = ppath.absolutePath(name) if ppath.isInSequence(): txt_list.append("[" + name + "]") elif get_cata_typeid(ppath.keyword()) in (IDS.simp, IDS.fact): # translate keyword kwtext = Options.translate_command(ppath.command().title, name) txt_list.append(kwtext) elif get_cata_typeid(ppath.keyword()) == IDS.command: # translate command translation = Options.translate_command(name) txt_list.append(translation) if translation != name: wttext = italic(translation) + " ({})".format(bold(name)) else: wttext = bold(name) tooltip = preformat(wttext) url = self.astergui().doc_url(name) if url: wttext += " " wttext += href( image(CFG.rcfile("as_pic_help.png"), width=20, height=20), url) wttext = preformat(wttext) docs = CATA.get_command_docstring(name) if docs: wttext += "<hr>" wttext += docs whats_this = wttext self.title.setTitle(txt_list) self.title.setToolTip(tooltip) self.title.setWhatsThis(whats_this) def _removeCurrentView(self): """ Remove the parameter view for given object. Arguments: obj (Parameter): Command's parameter. """ curview = self.currentParameterView() if curview is not None: master = curview.view().masterItem() if master is not None and master.slaveItem() == curview.view(): master.setSlaveItem(None) curview.view().setMasterItem(None) view = self._parentView(curview) if view is not None: self.views.setCurrentWidget(view) hide_unused = self.astergui().action(ActionType.HideUnused) view.setUnusedVisibile(not hide_unused.isChecked()) self.views.removeWidget(curview) curview.deleteLater() self._updateState() def _viewByPath(self, path): view = None for i in xrange(self.views.count()): the_view = self.views.widget(i) if the_view.path().isEqual(path): view = the_view break return view def _parentView(self, curview): view = None path = curview.path() while path is not None and view is None: path = path.parentPath() view = self._viewByPath(path) return view def _gotoParameter(self, path, link): """ Activate the parameter view for object with given id. Arguments: uid (int): Object's UID. """ curview = self.currentParameterView() act_item = curview.view().findItemByPath(path) child_val = None wid = self._createParameterView(path, link) if act_item is not None: child_val = act_item.itemValue() act_item.setSlaveItem(wid.view()) wid.view().setMasterItem(act_item) hide_unused = self.astergui().action(ActionType.HideUnused) wid.setUnusedVisibile(not hide_unused.isChecked()) self.views.setCurrentWidget(wid) wid.view().setItemValue(child_val) self._updateState() self.updateButtonStatus() def _createParameterView(self, path, link): """ Create parameter view for given object. Arguments: path (ParameterPath): Path of parameter to edit. Returns: ParameterWindow: Parameter view for parameter path. """ # pragma pylint: disable=redefined-variable-type pview = None if link == EditorLink.Table: pview = ParameterTableWindow(path, self, self.views) elif link == EditorLink.List: pview = ParameterListWindow(path, self, self.views) elif link == EditorLink.GrMa: pview = ParameterMeshGroupWindow(path, self, self.views) else: pview = ParameterFactWindow(path, self, self.views) connect(pview.gotoParameter, self._gotoParameter) self.views.addWidget(pview) return pview def _unusedVisibility(self, ison): """ Invoked when 'Hide unused' button toggled """ curview = self.currentParameterView() curview.setUnusedVisibile(not ison) def meshview(self): """ Returns the central *MeshView* object """ return self.astergui().workSpace().panels[Panel.View] def _editComment(self): """ Invoked when 'Edit comment' button is clicked """ panel = CommentPanel(self.astergui(), owner=self) panel.node = self.command() self.astergui().workSpace().panel(Panel.Edit).setEditor(panel) def pendingStorage(self): """ Dictionnary being filled as this command is edited. """ wid = self._viewByPath(ParameterPath(self.command())) if wid is not None: return wid.view().itemValue() return None
class ValidatorQDialog(QDialog): """ Class who create Validator QDialog to edit text in Alignak-app with regexp to validate """ def __init__(self, parent=None): super(ValidatorQDialog, self).__init__(parent) self.setWindowTitle('Edit Dialog') self.setWindowFlags(Qt.FramelessWindowHint) self.setStyleSheet(settings.css_style) self.setWindowIcon(QIcon(settings.get_image('icon'))) self.setObjectName('dialog') self.setFixedSize(250, 200) # Fields self.line_edit = QLineEdit() self.valid_text = QLabel() self.validator = QRegExpValidator() self.old_text = '' def initialize(self, title, text, regexp): """ Initialize QDialog for ValidatorQDialog :param title: title of the QDialog :type title: str :param text: text to edit :type text: str :param regexp: regular expression to validate :type regexp: str """ self.old_text = text center_widget(self) # Main status_layout main_layout = QVBoxLayout(self) main_layout.setContentsMargins(0, 0, 0, 0) self.setLayout(main_layout) main_layout.addWidget(get_logo_widget(self, title)) text_title = QLabel(_("Edit your text:")) text_title.setObjectName('subtitle') main_layout.addWidget(text_title) main_layout.setAlignment(text_title, Qt.AlignCenter) main_layout.addWidget(self.get_text_widget(regexp)) def get_text_widget(self, regexp): """ Return text QWidget with QTextEdit :return: text QWidget :rtype: QWidget """ text_widget = QWidget() text_widget.setObjectName('dialog') text_layout = QVBoxLayout() text_widget.setLayout(text_layout) text_layout.addWidget(self.valid_text) qreg_exp = QRegExp(regexp) self.validator.setRegExp(qreg_exp) self.line_edit.setPlaceholderText(_('type your text...')) self.line_edit.setText(self.old_text) self.line_edit.setValidator(self.validator) self.line_edit.setFixedHeight(25) self.line_edit.textChanged.connect(self.check_text) text_layout.addWidget(self.line_edit) # Accept button accept_btn = QPushButton(_('Confirm'), self) accept_btn.clicked.connect(self.accept_text) accept_btn.setObjectName('valid') accept_btn.setMinimumHeight(30) text_layout.addWidget(accept_btn) return text_widget def check_text(self): """ Valid email with ``QRegExpValidator`` and inform user """ state = self.validator.validate(self.line_edit.text(), 0)[0] if state == QRegExpValidator.Acceptable: text = 'Valid email' color = '#27ae60' # green else: text = 'Invalid email !' color = '#e67e22' # orange self.valid_text.setStyleSheet('QLabel { color: %s; }' % color) self.valid_text.setText(text) def accept_text(self): # pragma: no cover """ Set Edit QDialog to Rejected or Accepted (prevent to patch for nothing) """ state = self.validator.validate(self.line_edit.text(), 0)[0] if self.old_text == self.line_edit.text(): self.reject() elif not self.old_text or self.old_text.isspace(): if not self.line_edit.text() or self.line_edit.text().isspace(): self.reject() else: if state == QRegExpValidator.Acceptable: self.accept() else: self.reject() elif not self.line_edit.text() or self.line_edit.text().isspace(): self.line_edit.setText('') self.accept() else: if state == QRegExpValidator.Acceptable: self.accept() else: self.reject()
class AddBrickDialog(QDialog): def __init__(self, parent, modal=True, flags=Qt.WindowFlags()): QDialog.__init__(self, parent, flags) self.model = None self._model_dir = None self.setModal(modal) self.setWindowTitle("Add FITS brick") lo = QVBoxLayout(self) lo.setContentsMargins(10, 10, 10, 10) lo.setSpacing(5) # file selector self.wfile = FileSelector(self, label="FITS filename:", dialog_label="FITS file", default_suffix="fits", file_types="FITS files (*.fits *.FITS)", file_mode=QFileDialog.ExistingFile) lo.addWidget(self.wfile) # overwrite or add mode lo1 = QGridLayout() lo.addLayout(lo1) lo1.setContentsMargins(0, 0, 0, 0) lo1.addWidget(QLabel("Padding factor:", self), 0, 0) self.wpad = QLineEdit("2", self) self.wpad.setValidator(QDoubleValidator(self)) lo1.addWidget(self.wpad, 0, 1) lo1.addWidget(QLabel("Assign source name:", self), 1, 0) self.wname = QLineEdit(self) lo1.addWidget(self.wname, 1, 1) # OK/cancel buttons lo.addSpacing(10) lo2 = QHBoxLayout() lo.addLayout(lo2) lo2.setContentsMargins(0, 0, 0, 0) lo2.setContentsMargins(5, 5, 5, 5) self.wokbtn = QPushButton("OK", self) self.wokbtn.setMinimumWidth(128) self.wokbtn.clicked.connect(self.accept) self.wokbtn.setEnabled(False) cancelbtn = QPushButton("Cancel", self) cancelbtn.setMinimumWidth(128) cancelbtn.clicked.connect(self.reject) lo2.addWidget(self.wokbtn) lo2.addStretch(1) lo2.addWidget(cancelbtn) self.setMinimumWidth(384) # signals self.wfile.filenameSelected.connect(self._fileSelected) # internal state self.qerrmsg = QErrorMessage(self) def setModel(self, model): self.model = model if model.filename(): self._model_dir = os.path.dirname(os.path.abspath( model.filename())) else: self._model_dir = os.path.abspath('.') self.wfile.setDirectory(self._model_dir) self._fileSelected(self.wfile.filename(), quiet=True) def _fileSelected(self, filename, quiet=False): self.wokbtn.setEnabled(False) if not filename: return None # check that filename matches model if not os.path.samefile(self._model_dir, os.path.dirname(filename)): self.wfile.setFilename('') if not quiet: QMessageBox.warning( self, "Directory mismatch", """<P>The FITS file must reside in the same directory as the current sky model.</P>""") self.wfile.setDirectory(self._model_dir) return None # if filename is not in model already, enable the "add to model" control for src in self.model.sources: if isinstance(getattr(src, 'shape', None), ModelClasses.FITSImage): if os.path.exists(src.shape.filename) and os.path.samefile( src.shape.filename, filename): if not quiet: QMessageBox.warning( self, "Already in model", "This FITS brick is already present in the model.") self.wfile.setFilename('') return None if not str(self.wname.text()): self.wname.setText( os.path.splitext(os.path.basename(str(filename)))[0]) self.wokbtn.setEnabled(True) return filename def accept(self): """Tries to add brick, and closes the dialog if successful.""" filename = self.wfile.filename() # read fits file busy = BusyIndicator() try: input_hdu = pyfits.open(filename)[0] except Exception as err: busy.reset_cursor() QMessageBox.warning( self, "Error reading FITS", "Error reading FITS file %s: %s" % (filename, str(err))) return # check name srcname = str(self.wname.text()) or os.path.splitext( os.path.basename(str(filename)))[0] if srcname in set([src.name for src in self.model.sources]): QMessageBox.warning( self, "Already in model", "<p>The model already contains a source named '%s'. Please select a different name.</p>" % srcname) return # get image parameters hdr = input_hdu.header max_flux = float(input_hdu.data.max()) wcs = WCS(hdr, mode='pyfits') # Get reference pixel coordinates # wcs.getCentreWCSCoords() doesn't work, as that gives us the middle of the image # So scan the header to get the CRPIX values ra0 = dec0 = 1 for iaxis in range(hdr['NAXIS']): axs = str(iaxis + 1) name = hdr.get('CTYPE' + axs, axs).upper() if name.startswith("RA"): ra0 = hdr.get('CRPIX' + axs, 1) - 1 elif name.startswith("DEC"): dec0 = hdr.get('CRPIX' + axs, 1) - 1 # convert pixel to degrees # print ra0,dec0 ra0, dec0 = wcs.pix2wcs(ra0, dec0) ra0 *= DEG dec0 *= DEG # print ModelClasses.Position.ra_hms_static(ra0) # print ModelClasses.Position.dec_sdms_static(dec0) sx, sy = wcs.getHalfSizeDeg() sx *= DEG sy *= DEG nx, ny = input_hdu.data.shape[-1:-3:-1] pos = ModelClasses.Position(ra0, dec0) flux = ModelClasses.Flux(max_flux) shape = ModelClasses.FITSImage(sx, sy, 0, os.path.basename(filename), nx, ny, pad=float(str(self.wpad.text()) or "1")) img_src = SkyModel.Source(srcname, pos, flux, shape=shape) self.model.setSources(self.model.sources + [img_src]) self.model.emitUpdate(SkyModel.SkyModel.UpdateAll, origin=self) busy.reset_cursor() return QDialog.accept(self)
class MainWindowMPDJ(QMainWindow): """Display the main window of the application where the connections and other stuff is edited by the user.""" def show(self): """Shows this window (maximized). I will work on a better solution.""" QMainWindow.showMaximized(self) def update(self): """Updates the view.""" global_properties = GlobalProperties.get_instance() mpdj_data = global_properties.mpdj_data self.tf_min_per_selection.setText( str(mpdj_data.min_units_per_node_touch)) self.tf_max_per_selection.setText( str(mpdj_data.max_units_per_node_touch)) self.tf_min_global_song_duration.setText( str(mpdj_data.global_min_song_duration)) self.tf_max_global_song_duration.setText( str(mpdj_data.global_max_song_duration)) self.cb_global_limit_overflow.setChecked( mpdj_data.limit_overspill_global) self.tf_global_node_max_overflow_minutes.setText( str(mpdj_data.global_node_max_overspill)) self.tf_global_node_max_overflow_minutes.setDisabled( not mpdj_data.limit_overspill_global) text_to_find = mpdj_data.unit_per_node_touch.gui_representation() index = self.combo_box_minutes_or_titles.findText( text_to_find, Qt.MatchFixedString) self.combo_box_minutes_or_titles.setCurrentIndex(index) # self.limit_artist_play_chk_box.setChecked( # global_properties.mpdj_data.limit_artist_in_node_touch) self.chk_box_graph_is_directed.setChecked(mpdj_data.graph_is_directed) self.setWindowTitle('MPDJ: {}'.format( global_properties.path_of_current_file)) def write_min_global_song_duration_to_mpdj(self): """Writes min global song duration to mpdj.""" global_properties = GlobalProperties.get_instance() global_properties.mpdj_data.global_min_song_duration = int( self.tf_min_global_song_duration.text()) def write_max_global_song_duration_to_mpdj(self): """Writes min global song duration to mpdj.""" global_properties = GlobalProperties.get_instance() global_properties.mpdj_data.global_max_song_duration = int( self.tf_max_global_song_duration.text()) def write_min_per_note_to_mpdj(self): """Write the selected min count per node touch to the mpdj which is currently worked on.""" global_properties = GlobalProperties.get_instance() global_properties.mpdj_data.min_units_per_node_touch = int( self.tf_min_per_selection.text()) def write_max_per_note_to_mpdj(self): """Writes the selected max count per node touch to the mpdj which is currently worked on.""" global_properties = GlobalProperties.get_instance() global_properties.mpdj_data.max_units_per_node_touch = int( self.tf_max_per_selection.text()) def write_unit_per_node_touch_to_mpdj(self): """Writes the selected unit for min and max per touch to the mpdj. This does not do anything at the moment. Has to be implemented properly""" global_properties = GlobalProperties.get_instance() selection_text = self.combo_box_minutes_or_titles.currentText() global_properties.mpdj_data.unit_per_node_touch = UnitPerNodeTouch[ selection_text.upper()] def write_limit_artists_played_to_mpdj(self): # """Write to the current mpdj if the artist are limited per node touch.""" global_properties = GlobalProperties.get_instance() state = self.limit_artist_play_chk_box.isChecked() global_properties.mpdj_data.limit_artists_in_node_touch = state def write_limit_overspill_to_mpdj(self): global_properties = GlobalProperties.get_instance() state = self.cb_global_limit_overflow.isChecked() global_properties.mpdj_data.limit_overspill_global = state def write_global_node_max_overflow_to_mpdj(self): global_properties = GlobalProperties.get_instance() global_node_max_overflow_text = self.tf_global_node_max_overflow_minutes.text( ) if global_node_max_overflow_text: new_max_overflow = int(global_node_max_overflow_text) global_properties.mpdj_data.global_node_max_overspill = new_max_overflow def write_graph_is_directed_to_mpdj(self): """Write if the graph is directed to mpd, this should be changed somehow, since this does only concern the editing of the connections.""" global_properties = GlobalProperties.get_instance() state = self.chk_box_graph_is_directed.isChecked() global_properties.mpdj_data.graph_is_directed = state def file_dialog(self, load_save_type=QFileDialog.AcceptSave): """Opens an file save dialog and returns the selected filename.""" file_save_dialog = QFileDialog(self) file_save_dialog.setFileMode(QFileDialog.AnyFile) file_save_dialog.setAcceptMode(load_save_type) file_save_dialog.setNameFilters( ["MPDJ files (*.{})".format(FILE_SUFFIX)]) file_save_dialog.selectNameFilter( "MPDJ files (*.{})".format(FILE_SUFFIX)) file_save_dialog.setDefaultSuffix((FILE_SUFFIX)) exec_value = file_save_dialog.exec() if exec_value == 0: return None file_names = file_save_dialog.selectedFiles() if len(file_names) != 1: message_box = QMessageBox() message_box.setText('Please select only one file!') message_box.setWindowTitle('Save error.') message_box.setStandardButtons(QMessageBox.Ok) message_box.setIcon(QMessageBox.Information) message_box.exec_() return None return file_names[0] def file_save_as(self): """Saves the file. opens a file_dialog which asks for the filename.""" file_name = self.file_dialog(load_save_type=QFileDialog.AcceptSave) if file_name: self.save_mpdj_data_to_file(file_name) def save_mpdj_data_to_file(self, p_file_name: str): """Saves the current mpdj data to the file by the path given in p_file_name.""" try: global_properties = GlobalProperties.get_instance() global_properties.save_mpdj_data_to_file(p_file_name) self.statusBar().showMessage('Saved to {}'.format(p_file_name), 5000) except (OSError, IOError) as exception: message_box = QMessageBox() message_box.setText('Error saving the file: {}'.format( str(exception))) message_box.setWindowTitle('Error saving the file.') message_box.setStandardButtons(QMessageBox.Ok) message_box.setIcon(QMessageBox.Warning) message_box.exec_() def file_save(self): """Saves the current mpdj data to the current file.""" global_properties = GlobalProperties.get_instance() if len(global_properties.path_of_current_file) > 0: self.save_mpdj_data_to_file(global_properties.path_of_current_file) else: self.file_save_as() def file_load(self): """Loads mpdj data from a file. Opens a file dialog which asks for the file to load.""" global_properties = GlobalProperties.get_instance() file_name = self.file_dialog(load_save_type=QFileDialog.AcceptOpen) if file_name: if global_properties.changes_happened_since_last_save: retval = show_discard_data_ok_cancel_message() if not global_properties.changes_happened_since_last_save or retval == QMessageBox.Ok: try: global_properties.load_mpdjdata_from_file(file_name) except AttributeError as err: message_box = QMessageBox() message_box.setText( 'Error reading your MPDJ-File: {}'.format(err)) message_box.setWindowTitle('Load error.') message_box.setStandardButtons(QMessageBox.Ok) message_box.setIcon(QMessageBox.Warning) message_box.exec_() def __init__(self): """Constructor""" QMainWindow.__init__(self) global_properties = GlobalProperties.get_instance() self.connection_table = ConnectionTableWidget() global_properties.add_listener(self.connection_table) self.setCentralWidget(self.connection_table) self.connection_table.update() self.menu_bar = self.menuBar() self.menu_file = self.menu_bar.addMenu('File') self.menu_file.addAction('New', file_new_clicked) self.menu_file.addAction('Open', self.file_load) self.menu_file.addSeparator() self.menu_file.addAction('Save', self.file_save) self.menu_file.addAction('Save as', self.file_save_as) self.menu_file.addSeparator() self.menu_file.addAction('Exit', sys.exit) self.menu_file = self.menu_bar.addMenu('Connections') self.make_birectional_menu = self.menu_file.addMenu( 'Make bidirectional') self.make_birectional_menu.addAction("with and", make_bidirectional_and) self.make_birectional_menu.addAction("with or", make_bidirectional_or) self.menu_selection = self.menu_bar.addMenu('Selections') self.action_add_selection = self.menu_selection.addAction( 'Add Selection') self.action_add_selection.triggered.connect( create_add_selection_window) self.action_merge_selections = self.menu_selection.addAction( 'Merge Selections') self.action_merge_selections.triggered.connect( create_merge_selectoon_window) self.setMenuBar(self.menu_bar) self.statusBar().showMessage('Welcome to mpdj!', 5000) self.mpdj_options_dock = QDockWidget("MPDJ Options Panel", self) self.mpdj_options_dock_layout = QFormLayout() self.mpdj_docked_widget = QWidget() self.tf_min_global_song_duration = QLineEdit() self.tf_min_global_song_duration.setValidator( QIntValidator(0, 2147483647)) self.mpdj_options_dock_layout.addRow('Global min song duration:', self.tf_min_global_song_duration) self.tf_min_global_song_duration.editingFinished.connect( self.write_min_global_song_duration_to_mpdj) self.tf_max_global_song_duration = QLineEdit() self.tf_max_global_song_duration.setValidator( QIntValidator(0, 2147483647)) self.mpdj_options_dock_layout.addRow('Global max song duration:', self.tf_max_global_song_duration) self.tf_max_global_song_duration.editingFinished.connect( self.write_max_global_song_duration_to_mpdj) self.tf_min_per_selection = QLineEdit() self.tf_min_per_selection.setValidator(QIntValidator(0, 2147483647)) self.mpdj_options_dock_layout.addRow('Min per Node touch:', self.tf_min_per_selection) self.tf_min_per_selection.editingFinished.connect( self.write_min_per_note_to_mpdj) self.tf_max_per_selection = QLineEdit() self.tf_max_per_selection.setValidator(QIntValidator(0, 2147483647)) self.mpdj_options_dock_layout.addRow('Max per Node touch:', self.tf_max_per_selection) self.tf_max_per_selection.editingFinished.connect( self.write_max_per_note_to_mpdj) self.combo_box_minutes_or_titles = QComboBox() self.combo_box_minutes_or_titles.addItems( [unit.gui_representation() for unit in UnitPerNodeTouch]) self.mpdj_options_dock_layout.addRow('Unit:', self.combo_box_minutes_or_titles) self.combo_box_minutes_or_titles.currentTextChanged.connect( self.write_unit_per_node_touch_to_mpdj) self.tf_global_node_max_overflow_minutes = QLineEdit() self.tf_global_node_max_overflow_minutes.setValidator( QIntValidator(0, 2147483647)) self.tf_global_node_max_overflow_minutes.editingFinished.connect( self.write_global_node_max_overflow_to_mpdj) self.cb_global_limit_overflow = QCheckBox() self.cb_global_limit_overflow.stateChanged.connect(lambda: list( map(lambda m: m(), [ lambda: self.tf_global_node_max_overflow_minutes.setDisabled( not self.cb_global_limit_overflow.isChecked()), self. write_limit_overspill_to_mpdj ]))) self.overflow_layoout = QHBoxLayout() self.overflow_layoout.addWidget(self.cb_global_limit_overflow) self.overflow_layoout.addWidget( self.tf_global_node_max_overflow_minutes) self.mpdj_options_dock_layout.addRow("Limit overflow:", self.overflow_layoout) self.mpdj_docked_widget.setLayout(self.mpdj_options_dock_layout) self.mpdj_options_dock.setWidget(self.mpdj_docked_widget) self.addDockWidget(Qt.LeftDockWidgetArea, self.mpdj_options_dock) self.chk_box_graph_is_directed = QCheckBox() self.chk_box_graph_is_directed.stateChanged.connect( self.write_graph_is_directed_to_mpdj) self.mpdj_options_dock_layout.addRow(QLabel('Graph is directed'), self.chk_box_graph_is_directed) self.opened_selection_window = None global_properties.add_listener(self) self.update()
class ValueTypeEditor(QWidget): ValueTypes = (bool, int, float, complex, str) def __init__(self, *args): QWidget.__init__(self, *args) lo = QHBoxLayout(self) lo.setContentsMargins(0, 0, 0, 0) lo.setSpacing(5) # type selector self.wtypesel = QComboBox(self) for i, tp in enumerate(self.ValueTypes): self.wtypesel.addItem(tp.__name__) self.wtypesel.activated[int].connect(self._selectTypeNum) typesel_lab = QLabel("&Type:", self) typesel_lab.setBuddy(self.wtypesel) lo.addWidget(typesel_lab, 0) lo.addWidget(self.wtypesel, 0) self.wvalue = QLineEdit(self) self.wvalue_lab = QLabel("&Value:", self) self.wvalue_lab.setBuddy(self.wvalue) self.wbool = QComboBox(self) self.wbool.addItems(["false", "true"]) self.wbool.setCurrentIndex(1) lo.addWidget(self.wvalue_lab, 0) lo.addWidget(self.wvalue, 1) lo.addWidget(self.wbool, 1) self.wvalue.hide() # make input validators self._validators = {int: QIntValidator(self), float: QDoubleValidator(self)} # select bool type initially self._selectTypeNum(0) def _selectTypeNum(self, index): tp = self.ValueTypes[index] self.wbool.setVisible(tp is bool) self.wvalue.setVisible(tp is not bool) self.wvalue_lab.setBuddy(self.wbool if tp is bool else self.wvalue) self.wvalue.setValidator(self._validators.get(tp, None)) def setValue(self, value): """Sets current value""" for i, tp in enumerate(self.ValueTypes): if isinstance(value, tp): self.wtypesel.setCurrentIndex(i) self._selectTypeNum(i) if tp is bool: self.wbool.setCurrentIndex(1 if value else 0) else: self.wvalue.setText(str(value)) return # unknown value: set bool self.setValue(True) def getValue(self): """Returns current value, or None if no legal value is set""" tp = self.ValueTypes[self.wtypesel.currentIndex()] if tp is bool: return bool(self.wbool.currentIndex()) else: try: return tp(self.wvalue.text()) except: print("Error converting input to type ", tp.__name__) traceback.print_exc() return None
class MakeBrickDialog(QDialog): def __init__(self, parent, modal=True, flags=Qt.WindowFlags()): QDialog.__init__(self, parent, flags) self.model = None self._model_dir = None self.setModal(modal) self.setWindowTitle("Convert sources to FITS brick") lo = QVBoxLayout(self) lo.setContentsMargins(10, 10, 10, 10) lo.setSpacing(5) # file selector self.wfile = FileSelector(self, label="FITS filename:", dialog_label="Output FITS file", default_suffix="fits", file_types="FITS files (*.fits *.FITS)", file_mode=QFileDialog.ExistingFile) lo.addWidget(self.wfile) # reference frequency lo1 = QHBoxLayout() lo.addLayout(lo1) lo1.setContentsMargins(0, 0, 0, 0) label = QLabel("Frequency, MHz:", self) lo1.addWidget(label) tip = """<P>If your sky model contains spectral information (such as spectral indices), then a brick may be generated for a specific frequency. If a frequency is not specified here, the reference frequency of the model sources will be assumed.</P>""" self.wfreq = QLineEdit(self) self.wfreq.setValidator(QDoubleValidator(self)) label.setToolTip(tip) self.wfreq.setToolTip(tip) lo1.addWidget(self.wfreq) # beam gain lo1 = QHBoxLayout() lo.addLayout(lo1) lo1.setContentsMargins(0, 0, 0, 0) self.wpb_apply = QCheckBox("Apply primary beam expression:", self) self.wpb_apply.setChecked(True) lo1.addWidget(self.wpb_apply) tip = """<P>If this option is specified, a primary power beam gain will be applied to the sources before inserting them into the brick. This can be any valid Python expression making use of the variables 'r' (corresponding to distance from field centre, in radians) and 'fq' (corresponding to frequency.)</P>""" self.wpb_exp = QLineEdit(self) self.wpb_apply.setToolTip(tip) self.wpb_exp.setToolTip(tip) lo1.addWidget(self.wpb_exp) # overwrite or add mode lo1 = QHBoxLayout() lo.addLayout(lo1) lo1.setContentsMargins(0, 0, 0, 0) self.woverwrite = QRadioButton("overwrite image", self) self.woverwrite.setChecked(True) lo1.addWidget(self.woverwrite) self.waddinto = QRadioButton("add into image", self) lo1.addWidget(self.waddinto) # add to model self.wadd = QCheckBox( "Add resulting brick to sky model as a FITS image component", self) lo.addWidget(self.wadd) lo1 = QHBoxLayout() lo.addLayout(lo1) lo1.setContentsMargins(0, 0, 0, 0) self.wpad = QLineEdit(self) self.wpad.setValidator(QDoubleValidator(self)) self.wpad.setText("1.1") lab = QLabel("...with padding factor:", self) lab.setToolTip( """<P>The padding factor determines the amount of null padding inserted around the image during the prediction stage. Padding alleviates the effects of tapering and detapering in the uv-brick, which can show up towards the edges of the image. For a factor of N, the image will be padded out to N times its original size. This increases memory use, so if you have no flux at the edges of the image anyway, then a pad factor of 1 is perfectly fine.</P>""") self.wpad.setToolTip(lab.toolTip()) self.wadd.toggled[bool].connect(self.wpad.setEnabled) self.wadd.toggled[bool].connect(lab.setEnabled) self.wpad.setEnabled(False) lab.setEnabled(False) lo1.addStretch(1) lo1.addWidget(lab, 0) lo1.addWidget(self.wpad, 1) self.wdel = QCheckBox( "Remove from the sky model sources that go into the brick", self) lo.addWidget(self.wdel) # OK/cancel buttons lo.addSpacing(10) lo2 = QHBoxLayout() lo.addLayout(lo2) lo2.setContentsMargins(5, 5, 5, 5) self.wokbtn = QPushButton("OK", self) self.wokbtn.setMinimumWidth(128) self.wokbtn.clicked.connect(self.accept) self.wokbtn.setEnabled(False) cancelbtn = QPushButton("Cancel", self) cancelbtn.setMinimumWidth(128) cancelbtn.clicked.connect(self.reject) lo2.addWidget(self.wokbtn) lo2.addStretch(1) lo2.addWidget(cancelbtn) self.setMinimumWidth(384) # signals self.wfile.filenameSelected.connect(self._fileSelected) # internal state self.qerrmsg = QErrorMessage(self) def setModel(self, model): self.model = model pb = self.model.primaryBeam() if pb: self.wpb_exp.setText(pb) else: self.wpb_apply.setChecked(False) self.wpb_exp.setText("") if model.filename(): self._model_dir = os.path.dirname(os.path.abspath( model.filename())) else: self._model_dir = os.path.abspath('.') self.wfile.setDirectory(self._model_dir) self._fileSelected(self.wfile.filename(), quiet=True) def _fileSelected(self, filename, quiet=False): self.wokbtn.setEnabled(False) if not filename: return None # check that filename matches model if not os.path.samefile(self._model_dir, os.path.dirname(filename)): self.wfile.setFilename('') if not quiet: QMessageBox.warning( self, "Directory mismatch", """<P>The FITS file must reside in the same directory as the current sky model.</P>""") self.wfile.setDirectory(self._model_dir) return None # read fits file busy = BusyIndicator() try: input_hdu = pyfits.open(filename)[0] hdr = input_hdu.header # get frequency, if specified for axis in range(1, hdr['NAXIS'] + 1): if hdr['CTYPE%d' % axis].upper() == 'FREQ': self.wfreq.setText(str(hdr['CRVAL%d' % axis] / 1e+6)) break except Exception as err: busy.reset_cursor() self.wfile.setFilename('') if not quiet: QMessageBox.warning( self, "Error reading FITS", "Error reading FITS file %s: %s" % (filename, str(err))) return None self.wokbtn.setEnabled(True) # if filename is not in model already, enable the "add to model" control for src in self.model.sources: if isinstance(getattr(src, 'shape', None), ModelClasses.FITSImage) \ and os.path.exists(src.shape.filename) and os.path.exists(filename) \ and os.path.samefile(src.shape.filename, filename): self.wadd.setChecked(True) self.wadd.setEnabled(False) self.wadd.setText("image already in sky model") break else: self.wadd.setText("add image to sky model") busy.reset_cursor() return filename def accept(self): """Tries to make a brick, and closes the dialog if successful.""" sources = [ src for src in self.model.sources if src.selected and src.typecode == 'pnt' ] filename = self.wfile.filename() if not self._fileSelected(filename): return # get PB expression pbfunc = None if self.wpb_apply.isChecked(): pbexp = str(self.wpb_exp.text()) try: pbfunc = eval("lambda r,fq:" + pbexp) except Exception as err: QMessageBox.warning( self, "Error parsing PB experssion", "Error parsing primary beam expression %s: %s" % (pbexp, str(err))) return # get frequency freq = str(self.wfreq.text()) freq = float(freq) * 1e+6 if freq else None # get pad factor pad = str(self.wpad.text()) pad = max(float(pad), 1) if pad else 1 # read fits file busy = BusyIndicator() try: input_hdu = pyfits.open(filename)[0] except Exception as err: busy.reset_cursor() QMessageBox.warning( self, "Error reading FITS", "Error reading FITS file %s: %s" % (filename, str(err))) return # reset data if asked to if self.woverwrite.isChecked(): input_hdu.data[...] = 0 # insert sources Imaging.restoreSources(input_hdu, sources, 0, primary_beam=pbfunc, freq=freq) # save fits file try: # pyfits seems to produce an exception: # TypeError: formatwarning() takes exactly 4 arguments (5 given) # when attempting to overwrite a file. As a workaround, remove the file first. if os.path.exists(filename): os.remove(filename) input_hdu.writeto(filename) except Exception as err: traceback.print_exc() busy.reset_cursor() QMessageBox.warning( self, "Error writing FITS", "Error writing FITS file %s: %s" % (filename, str(err))) return changed = False sources = self.model.sources # remove sources from model if asked to if self.wdel.isChecked(): sources = [ src for src in sources if not (src.selected and src.typecode == 'pnt') ] changed = True # add image to model if asked to if self.wadd.isChecked(): hdr = input_hdu.header # get image parameters max_flux = float(input_hdu.data.max()) wcs = WCS(hdr, mode='pyfits') # Get reference pixel coordinates # wcs.getCentreWCSCoords() doesn't work, as that gives us the middle of the image # So scan the header to get the CRPIX values ra0 = dec0 = 1 for iaxis in range(hdr['NAXIS']): axs = str(iaxis + 1) name = hdr.get('CTYPE' + axs, axs).upper() if name.startswith("RA"): ra0 = hdr.get('CRPIX' + axs, 1) - 1 elif name.startswith("DEC"): dec0 = hdr.get('CRPIX' + axs, 1) - 1 # convert pixel to degrees ra0, dec0 = wcs.pix2wcs(ra0, dec0) ra0 *= DEG dec0 *= DEG sx, sy = wcs.getHalfSizeDeg() sx *= DEG sy *= DEG nx, ny = input_hdu.data.shape[-1:-3:-1] # check if this image is already contained in the model for src in sources: if isinstance(getattr(src, 'shape', None), ModelClasses.FITSImage) and os.path.samefile( src.shape.filename, filename): # update source parameters src.pos.ra, src.pos.dec = ra0, dec0 src.flux.I = max_flux src.shape.ex, src.shape.ey = sx, sy src.shape.nx, src.shape.ny = nx, ny src.shape.pad = pad break # not contained, make new source object else: pos = ModelClasses.Position(ra0, dec0) flux = ModelClasses.Flux(max_flux) shape = ModelClasses.FITSImage(sx, sy, 0, os.path.basename(filename), nx, ny, pad=pad) img_src = SkyModel.Source(os.path.splitext( os.path.basename(filename))[0], pos, flux, shape=shape) sources.append(img_src) changed = True if changed: self.model.setSources(sources) self.model.emitUpdate(SkyModel.SkyModel.UpdateAll, origin=self) self.parent().showMessage("Wrote %d sources to FITS file %s" % (len(sources), filename)) busy.reset_cursor() return QDialog.accept(self)
class ConfigWidget(QWidget): def __init__(self): QWidget.__init__(self) self.main_layout = QVBoxLayout() self.l = QFormLayout() self.l2 = QHBoxLayout() self.l3 = QHBoxLayout() self.group_box = QGroupBox('Ustawienia ogólne') self.group_box2 = QGroupBox('Pobieraj metadane') self.group_box3 = QGroupBox( 'Pobieraj dodatkowe metadane i dołącz je do komentarza') # general settings self.max_results_label = QLabel('Maksymalna liczba wyników') self.max_results_label.setToolTip( 'Maksymalna liczba pobieranych metadanych. Dla książek o nieunikalnych tytułach \ pierwszy wynik może być niepoprawny') self.max_results = QLineEdit(self) self.max_results.setValidator(QIntValidator()) self.max_results.setText(str(PREFS['max_results'])) self.max_results_label.setBuddy(self.max_results) self.l.addRow(self.max_results_label, self.max_results) self.authors_search_label = QLabel('Używaj autorów do wyszukiwań') self.authors_search_label.setToolTip( 'Wyszukuj uwzględniając autorów. Może poprawić trafność wyników, ale błędni autorzy spowodują brak wyników' ) self.authors_search = QCheckBox() self.authors_search.setChecked(PREFS['authors_search']) self.authors_search_label.setBuddy(self.authors_search) self.l.addRow(self.authors_search_label, self.authors_search) self.only_first_author_label = QLabel( 'Używaj tylko pierwszego autora do wyszukiwania') self.only_first_author_label.setToolTip( 'Używaj tylko pierwszego autora do wyszukiwań, obowiązuje tylko gdy wyszukiwanie z autorami jest aktywowane' ) self.only_first_author = QCheckBox() self.only_first_author.setChecked(PREFS['only_first_author']) self.only_first_author_label.setBuddy(self.only_first_author) self.l.addRow(self.only_first_author_label, self.only_first_author) self.covers_label = QLabel('Pobieraj okładki') self.covers = QCheckBox() self.covers.setChecked(PREFS['covers']) self.covers_label.setBuddy(self.covers) self.l.addRow(self.covers_label, self.covers) self.max_covers_label = QLabel('Maksymalna liczba okładek') self.max_covers_label.setToolTip( 'Maksymalna liczba pobieranych okładek') self.max_covers = QLineEdit(self) self.max_covers.setValidator(QIntValidator()) self.max_covers.setText(str(PREFS['max_covers'])) self.max_covers_label.setBuddy(self.max_covers) self.l.addRow(self.max_covers_label, self.max_covers) self.threads_label = QLabel('Wielowątkowe przetwarzanie') self.threads_label.setToolTip( 'Przyśpiesza pracę używając wielu wątków') self.threads = QCheckBox() self.threads.setChecked(PREFS['threads']) self.threads_label.setBuddy(self.threads) self.l.addRow(self.threads_label, self.threads) self.max_threads_label = QLabel('Maksymalna liczba wątków') self.max_threads = QLineEdit(self) self.max_threads.setValidator(QIntValidator()) self.max_threads.setText(str(PREFS['max_threads'])) self.max_threads_label.setBuddy(self.max_threads) self.l.addRow(self.max_threads_label, self.max_threads) self.thread_delay_label = QLabel('Opóźnienie wątku') self.thread_delay_label.setToolTip( 'Czas oczekiwania na uruchomienie kolejnego wątku') self.thread_delay = QLineEdit(self) self.thread_delay.setValidator(QDoubleValidator()) self.thread_delay.setText(str(PREFS['thread_delay'])) self.thread_delay_label.setBuddy(self.thread_delay) self.l.addRow(self.thread_delay_label, self.thread_delay) # metadata settings if 'title' in PREFS.defaults: self.title = QCheckBox('Tytuł') self.title.setChecked(PREFS['title']) self.l2.addWidget(self.title) if 'authors' in PREFS.defaults: self.authors = QCheckBox('Autorzy') self.authors.setChecked(PREFS['authors']) self.l2.addWidget(self.authors) if 'pubdate' in PREFS.defaults: self.pubdate = QCheckBox('Data wydania') self.pubdate.setChecked(PREFS['pubdate']) self.l2.addWidget(self.pubdate) if 'publisher' in PREFS.defaults: self.publisher = QCheckBox('Wydawca') self.publisher.setChecked(PREFS['publisher']) self.l2.addWidget(self.publisher) if 'isbn' in PREFS.defaults: self.isbn = QCheckBox('ISBN') self.isbn.setChecked(PREFS['isbn']) self.l2.addWidget(self.isbn) if 'comments' in PREFS.defaults: self.comments = QCheckBox('Opis') self.comments.setChecked(PREFS['comments']) self.l2.addWidget(self.comments) if 'languages' in PREFS.defaults: self.languages = QCheckBox('Języki') self.languages.setChecked(PREFS['languages']) self.l2.addWidget(self.languages) if 'rating' in PREFS.defaults: self.rating = QCheckBox('Ocena') self.rating.setChecked(PREFS['rating']) self.l2.addWidget(self.rating) if 'tags' in PREFS.defaults: self.tags = QCheckBox('Etykiety (tagi)') self.tags.setChecked(PREFS['tags']) self.l2.addWidget(self.tags) if 'series' in PREFS.defaults: self.series = QCheckBox('Cykle') self.series.setChecked(PREFS['series']) self.l2.addWidget(self.series) if 'identifier' in PREFS.defaults: self.identifier = QCheckBox('Identyfikator') self.identifier.setChecked(PREFS['identifier']) self.l2.addWidget(self.identifier) # custom metadata if 'translators' in PREFS.defaults: self.translators = QCheckBox('Tłumaczenie') self.translators.setChecked(PREFS['translators']) self.l3.addWidget(self.translators) if 'original_title' in PREFS.defaults: self.original_title = QCheckBox('Tytuł oryginału') self.original_title.setChecked(PREFS['original_title']) self.l3.addWidget(self.original_title) if 'categories' in PREFS.defaults: self.categories = QCheckBox('Kategorie') self.categories.setChecked(PREFS['categories']) self.l3.addWidget(self.categories) if 'genres' in PREFS.defaults: self.genres = QCheckBox('Gatunki') self.genres.setChecked(PREFS['genres']) self.l3.addWidget(self.genres) self.group_box.setLayout(self.l) self.group_box2.setLayout(self.l2) self.group_box3.setLayout(self.l3) self.main_layout.addWidget(self.group_box) self.main_layout.addWidget(self.group_box2) self.main_layout.addWidget(self.group_box3) self.main_layout.setAlignment(Qt.AlignTop) self.setLayout(self.main_layout) def save_settings(self): PREFS['max_results'] = int(self.max_results.text()) PREFS['authors_search'] = self.authors_search.isChecked() PREFS['only_first_author'] = self.only_first_author.isChecked() PREFS['covers'] = self.covers.isChecked() PREFS['max_covers'] = int(self.max_covers.text()) PREFS['threads'] = self.threads.isChecked() PREFS['max_threads'] = int(self.max_threads.text()) PREFS['thread_delay'] = float(self.thread_delay.text().replace( ',', '.')) # metadata settings if 'title' in PREFS.defaults: PREFS['title'] = self.title.isChecked() if 'authors' in PREFS.defaults: PREFS['authors'] = self.authors.isChecked() if 'pubdate' in PREFS.defaults: PREFS['pubdate'] = self.pubdate.isChecked() if 'publisher' in PREFS.defaults: PREFS['publisher'] = self.publisher.isChecked() if 'isbn' in PREFS.defaults: PREFS['isbn'] = self.isbn.isChecked() if 'comments' in PREFS.defaults: PREFS['comments'] = self.comments.isChecked() if 'languages' in PREFS.defaults: PREFS['languages'] = self.languages.isChecked() if 'rating' in PREFS.defaults: PREFS['rating'] = self.rating.isChecked() if 'tags' in PREFS.defaults: PREFS['tags'] = self.tags.isChecked() if 'series' in PREFS.defaults: PREFS['series'] = self.series.isChecked() if 'identifier' in PREFS.defaults: PREFS['identifier'] = self.identifier.isChecked() # custom metadata settings if 'translators' in PREFS.defaults: PREFS['translators'] = self.translators.isChecked() if 'original_title' in PREFS.defaults: PREFS['original_title'] = self.original_title.isChecked() if 'categories' in PREFS.defaults: PREFS['categories'] = self.categories.isChecked() if 'genres' in PREFS.defaults: PREFS['genres'] = self.genres.isChecked() return PREFS