def __init__(self, names, txt, parent=None): QDialog.__init__(self, parent) self.l = l = QVBoxLayout(self) self.setLayout(l) self.la = la = QLabel(_('Create a Virtual Library based on %s') % txt) l.addWidget(la) self._names = QListWidget(self) self._names.addItems(QStringList(sorted(names, key=sort_key))) self._names.setSelectionMode(self._names.ExtendedSelection) l.addWidget(self._names) self._or = QRadioButton(_('Match any of the selected %s names')%txt) self._and = QRadioButton(_('Match all of the selected %s names')%txt) self._or.setChecked(True) l.addWidget(self._or) l.addWidget(self._and) self.bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.bb.accepted.connect(self.accept) self.bb.rejected.connect(self.reject) l.addWidget(self.bb) self.resize(self.sizeHint())
class SelectNames(QDialog): # {{{ def __init__(self, names, txt, parent=None): QDialog.__init__(self, parent) self.l = l = QVBoxLayout(self) self.setLayout(l) self.la = la = QLabel(_("Create a Virtual Library based on %s") % txt) l.addWidget(la) self._names = QListWidget(self) self._names.addItems(QStringList(sorted(names, key=sort_key))) self._names.setSelectionMode(self._names.ExtendedSelection) l.addWidget(self._names) self._or = QRadioButton(_("Match any of the selected %s names") % txt) self._and = QRadioButton(_("Match all of the selected %s names") % txt) self._or.setChecked(True) l.addWidget(self._or) l.addWidget(self._and) self.bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.bb.accepted.connect(self.accept) self.bb.rejected.connect(self.reject) l.addWidget(self.bb) self.resize(self.sizeHint()) @property def names(self): for item in self._names.selectedItems(): yield unicode(item.data(Qt.DisplayRole).toString()) @property def match_type(self): return " and " if self._and.isChecked() else " or "
def __init__(self, names, txt, parent=None): QDialog.__init__(self, parent) self.l = l = QVBoxLayout(self) self.setLayout(l) self.la = la = QLabel(_('Create a Virtual Library based on %s') % txt) l.addWidget(la) self._names = QListWidget(self) self._names.addItems(QStringList(sorted(names, key=sort_key))) self._names.setSelectionMode(self._names.ExtendedSelection) l.addWidget(self._names) self._or = QRadioButton(_('Match any of the selected %s names') % txt) self._and = QRadioButton(_('Match all of the selected %s names') % txt) self._or.setChecked(True) l.addWidget(self._or) l.addWidget(self._and) self.bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.bb.accepted.connect(self.accept) self.bb.rejected.connect(self.reject) l.addWidget(self.bb) self.resize(self.sizeHint())
def __init__(self, names, parent=None): QDialog.__init__(self, parent) self.setWindowTitle(_('Choose master file')) self.l = l = QVBoxLayout() self.setLayout(l) self.la = la = QLabel( _('Choose the master file. All selected files will be merged into the master file:' )) la.setWordWrap(True) l.addWidget(la) self.sa = sa = QScrollArea(self) l.addWidget(sa) self.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) l.addWidget(bb) bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) self.w = w = QWidget(self) w.l = QVBoxLayout() w.setLayout(w.l) buttons = self.buttons = [QRadioButton(n) for n in names] buttons[0].setChecked(True) map(w.l.addWidget, buttons) sa.setWidget(w) self.resize(self.sizeHint() + QSize(150, 20))
def __init__(self, parentWidget, text = '', isChecked = False, setAsDefault = False ): """ Appends a QRadioButton widget to <parentWidget>, a property manager group box. Appends a QCheckBox (Qt) widget to the bottom of I{parentWidget}, a Property Manager group box. @param parentWidget: The parent group box containing this widget. @type parentWidget: PM_GroupBox @param text: The text that appears to the right of the radio button. @type text: str @param isChecked: Set's the radio button's check state. The default is True. @type isChecked: bool @param setAsDefault: If True, will restore I{isChecked} when the "Restore Defaults" button is clicked. @type setAsDefault: bool @see: U{B{QRadioButton}<http://doc.trolltech.com/4/qradiobutton.html>} """ QRadioButton.__init__(self) self.parentWidget = parentWidget self.setAsDefault = setAsDefault self.setText(text) self.setCheckable(True) self.setChecked(isChecked) self.defaultIsChecked = isChecked self.setAsDefault = setAsDefault parentWidget.addPmWidget(self)
def __init__(self, parent=None): QFrame.__init__(self, parent) self.setFocusPolicy(Qt.StrongFocus) self.setAutoFillBackground(True) self.capture = 0 self.setFrameShape(self.StyledPanel) self.setFrameShadow(self.Raised) self._layout = l = QGridLayout(self) self.setLayout(l) self.header = QLabel('') l.addWidget(self.header, 0, 0, 1, 2) self.use_default = QRadioButton('') self.use_custom = QRadioButton(_('Custom')) l.addWidget(self.use_default, 1, 0, 1, 3) l.addWidget(self.use_custom, 2, 0, 1, 3) self.use_custom.toggled.connect(self.custom_toggled) off = 2 for which in (1, 2): text = _('&Shortcut:') if which == 1 else _('&Alternate shortcut:') la = QLabel(text) la.setStyleSheet('QLabel { margin-left: 1.5em }') l.addWidget(la, off + which, 0, 1, 3) setattr(self, 'label%d' % which, la) button = QPushButton(_('None'), self) button.clicked.connect(partial(self.capture_clicked, which=which)) button.keyPressEvent = partial(self.key_press_event, which=which) setattr(self, 'button%d' % which, button) clear = QToolButton(self) clear.setIcon(QIcon(I('clear_left.png'))) clear.clicked.connect(partial(self.clear_clicked, which=which)) setattr(self, 'clear%d' % which, clear) l.addWidget(button, off + which, 1, 1, 1) l.addWidget(clear, off + which, 2, 1, 1) la.setBuddy(button) self.done_button = doneb = QPushButton(_('Done'), self) l.addWidget(doneb, 0, 2, 1, 1) doneb.clicked.connect(lambda: self.editing_done.emit(self)) l.setColumnStretch(0, 100) self.custom_toggled(False)
def __init__(self, parent=None): QFrame.__init__(self, parent) self.setFocusPolicy(Qt.StrongFocus) self.setAutoFillBackground(True) self.capture = 0 self.setFrameShape(self.StyledPanel) self.setFrameShadow(self.Raised) self._layout = l = QGridLayout(self) self.setLayout(l) self.header = QLabel('') l.addWidget(self.header, 0, 0, 1, 2) self.use_default = QRadioButton('') self.use_custom = QRadioButton(_('Custom')) l.addWidget(self.use_default, 1, 0, 1, 3) l.addWidget(self.use_custom, 2, 0, 1, 3) self.use_custom.toggled.connect(self.custom_toggled) off = 2 for which in (1, 2): text = _('&Shortcut:') if which == 1 else _('&Alternate shortcut:') la = QLabel(text) la.setStyleSheet('QLabel { margin-left: 1.5em }') l.addWidget(la, off+which, 0, 1, 3) setattr(self, 'label%d'%which, la) button = QPushButton(_('None'), self) button.clicked.connect(partial(self.capture_clicked, which=which)) button.keyPressEvent = partial(self.key_press_event, which=which) setattr(self, 'button%d'%which, button) clear = QToolButton(self) clear.setIcon(QIcon(I('clear_left.png'))) clear.clicked.connect(partial(self.clear_clicked, which=which)) setattr(self, 'clear%d'%which, clear) l.addWidget(button, off+which, 1, 1, 1) l.addWidget(clear, off+which, 2, 1, 1) la.setBuddy(button) self.done_button = doneb = QPushButton(_('Done'), self) l.addWidget(doneb, 0, 2, 1, 1) doneb.clicked.connect(lambda : self.editing_done.emit(self)) l.setColumnStretch(0, 100) self.custom_toggled(False)
def __init__(self, parentWidget, text='', isChecked=False, setAsDefault=False): """ Appends a QRadioButton widget to <parentWidget>, a property manager group box. Appends a QCheckBox (Qt) widget to the bottom of I{parentWidget}, a Property Manager group box. @param parentWidget: The parent group box containing this widget. @type parentWidget: PM_GroupBox @param text: The text that appears to the right of the radio button. @type text: str @param isChecked: Set's the radio button's check state. The default is True. @type isChecked: bool @param setAsDefault: If True, will restore I{isChecked} when the "Restore Defaults" button is clicked. @type setAsDefault: bool @see: U{B{QRadioButton}<http://doc.trolltech.com/4/qradiobutton.html>} """ QRadioButton.__init__(self) self.parentWidget = parentWidget self.setAsDefault = setAsDefault self.setText(text) self.setCheckable(True) self.setChecked(isChecked) self.defaultIsChecked = isChecked self.setAsDefault = setAsDefault parentWidget.addPmWidget(self)
class SelectNames(QDialog): # {{{ def __init__(self, names, txt, parent=None): QDialog.__init__(self, parent) self.l = l = QVBoxLayout(self) self.setLayout(l) self.la = la = QLabel(_('Create a Virtual Library based on %s') % txt) l.addWidget(la) self._names = QListWidget(self) self._names.addItems(QStringList(sorted(names, key=sort_key))) self._names.setSelectionMode(self._names.ExtendedSelection) l.addWidget(self._names) self._or = QRadioButton(_('Match any of the selected %s names') % txt) self._and = QRadioButton(_('Match all of the selected %s names') % txt) self._or.setChecked(True) l.addWidget(self._or) l.addWidget(self._and) self.bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.bb.accepted.connect(self.accept) self.bb.rejected.connect(self.reject) l.addWidget(self.bb) self.resize(self.sizeHint()) @property def names(self): for item in self._names.selectedItems(): yield unicode(item.data(Qt.DisplayRole).toString()) @property def match_type(self): return ' and ' if self._and.isChecked() else ' or '
class StartPage(QWizardPage): def __init__(self, dirname, purrlogs, parent=None, create=None, message=None): QWizardPage.__init__(self, parent) self.dirname = dirname self.purrlogs = purrlogs or [] bg = QButtonGroup(self) lo = QVBoxLayout() self.setLayout(lo) # set page titles self.setTitle("Starting PURR") message and self.setSubTitle(message) if not purrlogs: self.rbs_log = [] else: # add options for existing purrlogs self.rbs_log = [QRadioButton("Load %s" % Kittens.utils.collapseuser(log)) for log in purrlogs] for rb in self.rbs_log: lo.addWidget(rb) bg.addButton(rb) QObject.connect(rb, SIGNAL("toggled(bool)"), self.checkCompleteness) self.rbs_log[0].setChecked(True) # add option to load another purrlog lo1 = QHBoxLayout() self.rb_other = QRadioButton("Load purrlog from:") lo1.addWidget(self.rb_other) bg.addButton(self.rb_other) self.wother = QLineEdit() self.wother.setReadOnly(True) lo1.addWidget(self.wother, 1) pb = QPushButton(pixmaps.folder_open.icon(), "") QObject.connect(pb, SIGNAL("clicked()"), self._select_other_dialog) QObject.connect(self.rb_other, SIGNAL("toggled(bool)"), pb.setEnabled) QObject.connect(self.rb_other, SIGNAL("toggled(bool)"), self.wother.setEnabled) QObject.connect(self.rb_other, SIGNAL("toggled(bool)"), self.checkCompleteness) pb.setEnabled(False) self.wother.setEnabled(False) lo1.addWidget(pb) lo.addLayout(lo1) self.load_path = None # add option to create new purrlog lo1 = QHBoxLayout() self.rb_create = QRadioButton("Create new purrlog:") lo1.addWidget(self.rb_create) bg.addButton(self.rb_create) self.wcreate = QLineEdit() lo1.addWidget(self.wcreate, 1) pb = QPushButton(pixmaps.folder_open.icon(), "") QObject.connect(pb, SIGNAL("clicked()"), self._select_create_dialog) QObject.connect(self.rb_create, SIGNAL("toggled(bool)"), pb.setEnabled) QObject.connect(self.rb_create, SIGNAL("toggled(bool)"), self.wcreate.setEnabled) QObject.connect(self.rb_create, SIGNAL("toggled(bool)"), self.checkCompleteness) QObject.connect(self.wcreate, SIGNAL("editingFinished()"), self._validate_create_filename) pb.setEnabled(False) self.wcreate.setEnabled(False) # this holds the last validated name self._validated_create_path = None self._validated_result = False # generate default name for a new purrlog self.create_path = os.path.join(dirname, "purrlog") num = 0 while os.path.exists(self.create_path): self.create_path = os.path.join(dirname, "purrlog.%d" % num) num += 1 # This will be not None as long as a valid name is entered self.create_path = Kittens.utils.collapseuser(os.path.normpath(self.create_path)) if create: self.wcreate.setText(create or Kittens.utils.collapseuser(create)) # this will emit checkCompleteness(), causing a _validate_create_filename() call, causing the content of the wcreate widget # to be validated and copied to create_path if valid, or reset from create_path if invalid self.rb_create.setChecked(True) else: self.wcreate.setText(self.create_path) lo1.addWidget(pb) lo.addLayout(lo1) # make create option default, if no purrlogs if not purrlogs: self.rb_create.setChecked(True) def _select_other_dialog(self): path = str(QFileDialog.getExistingDirectory(self, "Select purrlog", self.dirname)) if not path: return if not Purr.Purrer.is_purrlog(path): QMessageBox.warning(self, "Invalid purrlog", "The path you have selected, <tt>%s</tt>, does not refer to a valid purrlog." % Kittens.utils.collapseuser( path)) return self.load_path = path self.wother.setText(Kittens.utils.collapseuser(path)) self.checkCompleteness() def _validate_create_filename(self, path=None, check=True): if path is None: path = str(self.wcreate.text()) # if we have already validated this path, then return the last validation result. # This is mostly to keep from bombarding the user with repeated error dialogs. if self._validated_create_path == path: return self._validated_result self._validated_create_path = path self._validated_result = False; # set to True if all checks pass # now process the path. Normalize it, and expand "~" path = os.path.expanduser(os.path.normpath(path)) # if not absolute, join to current directory if not os.path.isabs(path): path = os.path.join(self.dirname, path) # collapse to "~" (for error messages) path0 = Kittens.utils.collapseuser(path) if os.path.exists(path): QMessageBox.warning(self, "Can't create purrlog", """Unable to create purrlog <tt>%s</tt>: file or directory already exists. Please select another name""" % path0) self.create_path and self.wcreate.setText(Kittens.utils.collapseuser(self.create_path)) return False if not os.access(os.path.dirname(os.path.normpath(path)) or '.', os.W_OK): QMessageBox.warning(self, "Can't create purrlog", """Unable to create purrlog <tt>%s</tt>: can't write to parent directory. Please select another path.""" % path0) self.create_path and self.wcreate.setText(Kittens.utils.collapseuser(self.create_path)) return False self.create_path = path self.wcreate.setText(path0) self._validated_result = True; # set to True if all checks pass if check: self.checkCompleteness() return True def _select_create_dialog(self): path = str(QFileDialog.getSaveFileName(self, "Create new purrlog", self.create_path)) if path: self._validate_create_filename(path) def checkCompleteness(self, toggled=None): if toggled and hasattr(self, 'rb_other') and self.rb_other.isChecked() and not self.load_path: self._select_other_dialog() else: self.emit(SIGNAL("completeChanged()")) def isComplete(self): if hasattr(self, 'rb_create') and self.rb_create.isChecked(): return self._validate_create_filename(check=False) and bool(self.create_path) if hasattr(self, 'rb_other') and self.rb_other.isChecked(): return bool(self.load_path) return True def selectedPath(self): for (rb, log) in zip(self.rbs_log, self.purrlogs): if rb.isChecked(): return log if self.rb_other.isChecked(): return self.load_path if self.rb_create.isChecked(): return self.create_path return None
def __init__(self, parentWidget, title = '', label = '', labelColumn = 0, buttonList = [], checkedId = -1, setAsDefault = False, spanWidth = True, borders = True ): """ Appends a PM_RadioButtonList widget to the bottom of I{parentWidget}, the Property Manager dialog or group box. @param parentWidget: The parent group box containing this widget. @type parentWidget: PM_GroupBox or PM_Dialog @param title: The group box title. @type title: str @param label: The label for the coordinate spinbox. @type label: str @param labelColumn: The column in the parentWidget's grid layout to which this widget's label will be added. The labelColum can only be E{0} or E{1} @type labelColumn: int @param buttonList: A list of I{button info lists}. There is one button info list for each radio button in the list. The button info list contains the following three items: 1). Button Id (int), 2). Button text (str), 3). Button tool tip (str). @type buttonList: list @param spanWidth: If True, the widget and its label will span the width of the group box. Its label will appear directly above the widget (unless the label is empty) and is left justified. @type spanWidth: bool (default False) @param borders: If true (default), this widget will have borders displayed. otherwise the won't be any outside borders around the set of radio buttons this class provides @type borders: boolean """ # Intializing label, labelColumn etc is needed before doing # PM_GroupBox.__init__. This is done so that # self.parentWidget.addPmWidget(self) done at the end of __init__ # works properly. # 'self.parentWidget.addPmWidget(self)' is done to avoid a bug where a # groupbox is always appended as the 'last widget' when its # parentWidget is also a groupbox. This is due to other PM widgets #(e.g. PM_PushButton)add themselves to their parent widget in their #__init__ using self.parentWidget.addPmWidget(self). So doing the #same thing here. More general fix is needed in PM_GroupBox code # --Ninad 2007-11-14 (comment copied from PM_coordinateSpinBoxes) self.label = label self.labelColumn = labelColumn self.spanWidth = spanWidth if label: # Create this widget's QLabel. self.labelWidget = QLabel() self.labelWidget.setText(label) PM_GroupBox.__init__(self, parentWidget, title) # These are needed to properly maintain the height of the grid if # all buttons in a row are hidden via hide(). self.vBoxLayout.setMargin(0) self.vBoxLayout.setSpacing(0) self.buttonGroup = QButtonGroup() self.buttonGroup.setExclusive(True) self.parentWidget = parentWidget self.buttonList = buttonList if setAsDefault: self.setDefaultCheckedId(checkedId) self.buttonsById = {} self.buttonsByText = {} # Create radio button list from button info. for buttonInfo in buttonList: buttonId = buttonInfo[0] buttonText = buttonInfo[1] buttonToolTip = buttonInfo[2] button = QRadioButton(self) button.setText(buttonText) button.setToolTip(buttonToolTip) # Not working. button.setCheckable(True) if checkedId == buttonId: button.setChecked(True) self.buttonGroup.addButton(button, buttonId) self.vBoxLayout.addWidget(button) self.buttonsById[buttonId] = button self.buttonsByText[buttonText] = button if isinstance(self.parentWidget, PM_GroupBox): self.parentWidget.addPmWidget(self) else: #@@ Should self be added to self.parentWidget's widgetList? #don't know. Retaining old code -- Ninad 2008-06-23 self._widgetList.append(self) self._rowCount += 1 if not borders: #reset the style sheet so that there are no borders around the #radio button set this class provides. self.setStyleSheet(self._getAlternateStyleSheet())
class Editor(QFrame): # {{{ editing_done = pyqtSignal(object) def __init__(self, parent=None): QFrame.__init__(self, parent) self.setFocusPolicy(Qt.StrongFocus) self.setAutoFillBackground(True) self.capture = 0 self.setFrameShape(self.StyledPanel) self.setFrameShadow(self.Raised) self._layout = l = QGridLayout(self) self.setLayout(l) self.header = QLabel('') l.addWidget(self.header, 0, 0, 1, 2) self.use_default = QRadioButton('') self.use_custom = QRadioButton(_('Custom')) l.addWidget(self.use_default, 1, 0, 1, 3) l.addWidget(self.use_custom, 2, 0, 1, 3) self.use_custom.toggled.connect(self.custom_toggled) off = 2 for which in (1, 2): text = _('&Shortcut:') if which == 1 else _('&Alternate shortcut:') la = QLabel(text) la.setStyleSheet('QLabel { margin-left: 1.5em }') l.addWidget(la, off+which, 0, 1, 3) setattr(self, 'label%d'%which, la) button = QPushButton(_('None'), self) button.clicked.connect(partial(self.capture_clicked, which=which)) button.keyPressEvent = partial(self.key_press_event, which=which) setattr(self, 'button%d'%which, button) clear = QToolButton(self) clear.setIcon(QIcon(I('clear_left.png'))) clear.clicked.connect(partial(self.clear_clicked, which=which)) setattr(self, 'clear%d'%which, clear) l.addWidget(button, off+which, 1, 1, 1) l.addWidget(clear, off+which, 2, 1, 1) la.setBuddy(button) self.done_button = doneb = QPushButton(_('Done'), self) l.addWidget(doneb, 0, 2, 1, 1) doneb.clicked.connect(lambda : self.editing_done.emit(self)) l.setColumnStretch(0, 100) self.custom_toggled(False) def initialize(self, shortcut, all_shortcuts): self.header.setText('<b>%s: %s</b>'%(_('Customize'), shortcut['name'])) self.all_shortcuts = all_shortcuts self.shortcut = shortcut self.default_keys = [QKeySequence(k, QKeySequence.PortableText) for k in shortcut['default_keys']] self.current_keys = list(shortcut['keys']) default = ', '.join([unicode(k.toString(k.NativeText)) for k in self.default_keys]) if not default: default = _('None') current = ', '.join([unicode(k.toString(k.NativeText)) for k in self.current_keys]) if not current: current = _('None') self.use_default.setText(_('Default: %(deflt)s [Currently not conflicting: %(curr)s]')% dict(deflt=default, curr=current)) if shortcut['set_to_default']: self.use_default.setChecked(True) else: self.use_custom.setChecked(True) for key, which in zip(self.current_keys, [1,2]): button = getattr(self, 'button%d'%which) button.setText(key.toString(key.NativeText)) def custom_toggled(self, checked): for w in ('1', '2'): for o in ('label', 'button', 'clear'): getattr(self, o+w).setEnabled(checked) def capture_clicked(self, which=1): self.capture = which button = getattr(self, 'button%d'%which) button.setText(_('Press a key...')) button.setFocus(Qt.OtherFocusReason) button.setStyleSheet('QPushButton { font-weight: bold}') def clear_clicked(self, which=0): button = getattr(self, 'button%d'%which) button.setText(_('None')) def key_press_event(self, ev, which=0): code = ev.key() if self.capture == 0 or code in (0, Qt.Key_unknown, Qt.Key_Shift, Qt.Key_Control, Qt.Key_Alt, Qt.Key_Meta, Qt.Key_AltGr, Qt.Key_CapsLock, Qt.Key_NumLock, Qt.Key_ScrollLock): return QWidget.keyPressEvent(self, ev) button = getattr(self, 'button%d'%which) button.setStyleSheet('QPushButton { font-weight: normal}') mods = int(ev.modifiers()) & ~Qt.KeypadModifier txt = unicode(ev.text()) if txt and txt.lower() == txt.upper(): # We have a symbol like ! or > etc. In this case the value of code # already includes Shift, so remove it mods &= ~Qt.ShiftModifier sequence = QKeySequence(code|mods) button.setText(sequence.toString(QKeySequence.NativeText)) self.capture = 0 dup_desc = self.dup_check(sequence) if dup_desc is not None: error_dialog(self, _('Already assigned'), unicode(sequence.toString(QKeySequence.NativeText)) + ' ' + _('already assigned to') + ' ' + dup_desc, show=True) self.clear_clicked(which=which) def dup_check(self, sequence): for sc in self.all_shortcuts: if sc is self.shortcut: continue for k in sc['keys']: if k == sequence: return sc['name'] @property def custom_keys(self): if self.use_default.isChecked(): return None ans = [] for which in (1, 2): button = getattr(self, 'button%d'%which) t = unicode(button.text()) if t == _('None'): continue ks = QKeySequence(t, QKeySequence.NativeText) if not ks.isEmpty(): ans.append(ks) return tuple(ans)
def __init__(self, parent, modal=True, flags=Qt.WindowFlags()): QDialog.__init__(self, parent, flags) self.setModal(modal) self.setWindowTitle("Convert sources to FITS brick") lo = QVBoxLayout(self) lo.setMargin(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()) QObject.connect(self.wadd, SIGNAL("toggled(bool)"), self.wpad.setEnabled) QObject.connect(self.wadd, SIGNAL("toggled(bool)"), 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(0, 0, 0, 0) lo2.setMargin(5) self.wokbtn = QPushButton("OK", self) self.wokbtn.setMinimumWidth(128) QObject.connect(self.wokbtn, SIGNAL("clicked()"), self.accept) self.wokbtn.setEnabled(False) cancelbtn = QPushButton("Cancel", self) cancelbtn.setMinimumWidth(128) QObject.connect(cancelbtn, SIGNAL("clicked()"), self.reject) lo2.addWidget(self.wokbtn) lo2.addStretch(1) lo2.addWidget(cancelbtn) self.setMinimumWidth(384) # signals QObject.connect(self.wfile, SIGNAL("filenameSelected"), self._fileSelected) # internal state self.qerrmsg = QErrorMessage(self)
class MakeBrickDialog(QDialog): def __init__(self, parent, modal=True, flags=Qt.WindowFlags()): QDialog.__init__(self, parent, flags) self.setModal(modal) self.setWindowTitle("Convert sources to FITS brick") lo = QVBoxLayout(self) lo.setMargin(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()) QObject.connect(self.wadd, SIGNAL("toggled(bool)"), self.wpad.setEnabled) QObject.connect(self.wadd, SIGNAL("toggled(bool)"), 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(0, 0, 0, 0) lo2.setMargin(5) self.wokbtn = QPushButton("OK", self) self.wokbtn.setMinimumWidth(128) QObject.connect(self.wokbtn, SIGNAL("clicked()"), self.accept) self.wokbtn.setEnabled(False) cancelbtn = QPushButton("Cancel", self) cancelbtn.setMinimumWidth(128) QObject.connect(cancelbtn, SIGNAL("clicked()"), self.reject) lo2.addWidget(self.wokbtn) lo2.addStretch(1) lo2.addWidget(cancelbtn) self.setMinimumWidth(384) # signals QObject.connect(self.wfile, SIGNAL("filenameSelected"), 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 = None 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") 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 = None 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 = None 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 = None return QDialog.accept(self)
class Editor(QFrame): # {{{ editing_done = pyqtSignal(object) def __init__(self, parent=None): QFrame.__init__(self, parent) self.setFocusPolicy(Qt.StrongFocus) self.setAutoFillBackground(True) self.capture = 0 self.setFrameShape(self.StyledPanel) self.setFrameShadow(self.Raised) self._layout = l = QGridLayout(self) self.setLayout(l) self.header = QLabel('') l.addWidget(self.header, 0, 0, 1, 2) self.use_default = QRadioButton('') self.use_custom = QRadioButton(_('Custom')) l.addWidget(self.use_default, 1, 0, 1, 3) l.addWidget(self.use_custom, 2, 0, 1, 3) self.use_custom.toggled.connect(self.custom_toggled) off = 2 for which in (1, 2): text = _('&Shortcut:') if which == 1 else _('&Alternate shortcut:') la = QLabel(text) la.setStyleSheet('QLabel { margin-left: 1.5em }') l.addWidget(la, off + which, 0, 1, 3) setattr(self, 'label%d' % which, la) button = QPushButton(_('None'), self) button.clicked.connect(partial(self.capture_clicked, which=which)) button.keyPressEvent = partial(self.key_press_event, which=which) setattr(self, 'button%d' % which, button) clear = QToolButton(self) clear.setIcon(QIcon(I('clear_left.png'))) clear.clicked.connect(partial(self.clear_clicked, which=which)) setattr(self, 'clear%d' % which, clear) l.addWidget(button, off + which, 1, 1, 1) l.addWidget(clear, off + which, 2, 1, 1) la.setBuddy(button) self.done_button = doneb = QPushButton(_('Done'), self) l.addWidget(doneb, 0, 2, 1, 1) doneb.clicked.connect(lambda: self.editing_done.emit(self)) l.setColumnStretch(0, 100) self.custom_toggled(False) def initialize(self, shortcut, all_shortcuts): self.header.setText('<b>%s: %s</b>' % (_('Customize'), shortcut['name'])) self.all_shortcuts = all_shortcuts self.shortcut = shortcut self.default_keys = [ QKeySequence(k, QKeySequence.PortableText) for k in shortcut['default_keys'] ] self.current_keys = list(shortcut['keys']) default = ', '.join( [unicode(k.toString(k.NativeText)) for k in self.default_keys]) if not default: default = _('None') current = ', '.join( [unicode(k.toString(k.NativeText)) for k in self.current_keys]) if not current: current = _('None') self.use_default.setText( _('Default: %(deflt)s [Currently not conflicting: %(curr)s]') % dict(deflt=default, curr=current)) if shortcut['set_to_default']: self.use_default.setChecked(True) else: self.use_custom.setChecked(True) for key, which in zip(self.current_keys, [1, 2]): button = getattr(self, 'button%d' % which) button.setText(key.toString(key.NativeText)) def custom_toggled(self, checked): for w in ('1', '2'): for o in ('label', 'button', 'clear'): getattr(self, o + w).setEnabled(checked) def capture_clicked(self, which=1): self.capture = which button = getattr(self, 'button%d' % which) button.setText(_('Press a key...')) button.setFocus(Qt.OtherFocusReason) button.setStyleSheet('QPushButton { font-weight: bold}') def clear_clicked(self, which=0): button = getattr(self, 'button%d' % which) button.setText(_('None')) def key_press_event(self, ev, which=0): code = ev.key() if self.capture == 0 or code in (0, Qt.Key_unknown, Qt.Key_Shift, Qt.Key_Control, Qt.Key_Alt, Qt.Key_Meta, Qt.Key_AltGr, Qt.Key_CapsLock, Qt.Key_NumLock, Qt.Key_ScrollLock): return QWidget.keyPressEvent(self, ev) button = getattr(self, 'button%d' % which) button.setStyleSheet('QPushButton { font-weight: normal}') mods = int(ev.modifiers()) & ~Qt.KeypadModifier txt = unicode(ev.text()) if txt and txt.lower() == txt.upper(): # We have a symbol like ! or > etc. In this case the value of code # already includes Shift, so remove it mods &= ~Qt.ShiftModifier sequence = QKeySequence(code | mods) button.setText(sequence.toString(QKeySequence.NativeText)) self.capture = 0 dup_desc = self.dup_check(sequence) if dup_desc is not None: error_dialog(self, _('Already assigned'), unicode(sequence.toString(QKeySequence.NativeText)) + ' ' + _('already assigned to') + ' ' + dup_desc, show=True) self.clear_clicked(which=which) def dup_check(self, sequence): for sc in self.all_shortcuts: if sc is self.shortcut: continue for k in sc['keys']: if k == sequence: return sc['name'] @property def custom_keys(self): if self.use_default.isChecked(): return None ans = [] for which in (1, 2): button = getattr(self, 'button%d' % which) t = unicode(button.text()) if t == _('None'): continue ks = QKeySequence(t, QKeySequence.NativeText) if not ks.isEmpty(): ans.append(ks) return tuple(ans)
def __init__(self, parentWidget, title='', label='', labelColumn=0, buttonList=[], checkedId=-1, setAsDefault=False, spanWidth=True, borders=True): """ Appends a PM_RadioButtonList widget to the bottom of I{parentWidget}, the Property Manager dialog or group box. @param parentWidget: The parent group box containing this widget. @type parentWidget: PM_GroupBox or PM_Dialog @param title: The group box title. @type title: str @param label: The label for the coordinate spinbox. @type label: str @param labelColumn: The column in the parentWidget's grid layout to which this widget's label will be added. The labelColum can only be E{0} or E{1} @type labelColumn: int @param buttonList: A list of I{button info lists}. There is one button info list for each radio button in the list. The button info list contains the following three items: 1). Button Id (int), 2). Button text (str), 3). Button tool tip (str). @type buttonList: list @param spanWidth: If True, the widget and its label will span the width of the group box. Its label will appear directly above the widget (unless the label is empty) and is left justified. @type spanWidth: bool (default False) @param borders: If true (default), this widget will have borders displayed. otherwise the won't be any outside borders around the set of radio buttons this class provides @type borders: boolean """ # Intializing label, labelColumn etc is needed before doing # PM_GroupBox.__init__. This is done so that # self.parentWidget.addPmWidget(self) done at the end of __init__ # works properly. # 'self.parentWidget.addPmWidget(self)' is done to avoid a bug where a # groupbox is always appended as the 'last widget' when its # parentWidget is also a groupbox. This is due to other PM widgets #(e.g. PM_PushButton)add themselves to their parent widget in their #__init__ using self.parentWidget.addPmWidget(self). So doing the #same thing here. More general fix is needed in PM_GroupBox code # --Ninad 2007-11-14 (comment copied from PM_coordinateSpinBoxes) self.label = label self.labelColumn = labelColumn self.spanWidth = spanWidth if label: # Create this widget's QLabel. self.labelWidget = QLabel() self.labelWidget.setText(label) PM_GroupBox.__init__(self, parentWidget, title) # These are needed to properly maintain the height of the grid if # all buttons in a row are hidden via hide(). self.vBoxLayout.setMargin(0) self.vBoxLayout.setSpacing(0) self.buttonGroup = QButtonGroup() self.buttonGroup.setExclusive(True) self.parentWidget = parentWidget self.buttonList = buttonList if setAsDefault: self.setDefaultCheckedId(checkedId) self.buttonsById = {} self.buttonsByText = {} # Create radio button list from button info. for buttonInfo in buttonList: buttonId = buttonInfo[0] buttonText = buttonInfo[1] buttonToolTip = buttonInfo[2] button = QRadioButton(self) button.setText(buttonText) button.setToolTip(buttonToolTip) # Not working. button.setCheckable(True) if checkedId == buttonId: button.setChecked(True) self.buttonGroup.addButton(button, buttonId) self.vBoxLayout.addWidget(button) self.buttonsById[buttonId] = button self.buttonsByText[buttonText] = button if isinstance(self.parentWidget, PM_GroupBox): self.parentWidget.addPmWidget(self) else: #@@ Should self be added to self.parentWidget's widgetList? #don't know. Retaining old code -- Ninad 2008-06-23 self._widgetList.append(self) self._rowCount += 1 if not borders: #reset the style sheet so that there are no borders around the #radio button set this class provides. self.setStyleSheet(self._getAlternateStyleSheet())
def __init__(self, parent, modal=True, flags=Qt.WindowFlags()): QDialog.__init__(self, parent, flags) self.setModal(modal) self.setWindowTitle("Convert sources to FITS brick") lo = QVBoxLayout(self) lo.setMargin(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()) QObject.connect(self.wadd, SIGNAL("toggled(bool)"), self.wpad.setEnabled) QObject.connect(self.wadd, SIGNAL("toggled(bool)"), 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(0, 0, 0, 0) lo2.setMargin(5) self.wokbtn = QPushButton("OK", self) self.wokbtn.setMinimumWidth(128) QObject.connect(self.wokbtn, SIGNAL("clicked()"), self.accept) self.wokbtn.setEnabled(False) cancelbtn = QPushButton("Cancel", self) cancelbtn.setMinimumWidth(128) QObject.connect(cancelbtn, SIGNAL("clicked()"), self.reject) lo2.addWidget(self.wokbtn) lo2.addStretch(1) lo2.addWidget(cancelbtn) self.setMinimumWidth(384) # signals QObject.connect(self.wfile, SIGNAL("filenameSelected"), self._fileSelected) # internal state self.qerrmsg = QErrorMessage(self)
def setup_ui(self): # {{{ self._g = g = QHBoxLayout(self) self.setLayout(g) self._l = l = QVBoxLayout() g.addLayout(l) fmts = sorted(x.upper() for x in self.fmts) self.fmt_choice_box = QGroupBox(_('Choose the format to unpack:'), self) self._fl = fl = QHBoxLayout() self.fmt_choice_box.setLayout(self._fl) self.fmt_choice_buttons = [QRadioButton(y, self) for y in fmts] for x in self.fmt_choice_buttons: fl.addWidget(x, stretch=10 if x is self.fmt_choice_buttons[-1] else 0) l.addWidget(self.fmt_choice_box) self.fmt_choice_box.setVisible(len(fmts) > 1) self.help_label = QLabel(_('''\ <h2>About Unpack Book</h2> <p>Unpack Book allows you to fine tune the appearance of an ebook by making small changes to its internals. In order to use Unpack Book, you need to know a little bit about HTML and CSS, technologies that are used in ebooks. Follow the steps:</p> <br> <ol> <li>Click "Explode Book": This will "explode" the book into its individual internal components.<br></li> <li>Right click on any individual file and select "Open with..." to edit it in your favorite text editor.<br></li> <li>When you are done: <b>close the file browser window and the editor windows you used to make your tweaks</b>. Then click the "Rebuild Book" button, to update the book in your calibre library.</li> </ol>''')) self.help_label.setWordWrap(True) self._fr = QFrame() self._fr.setFrameShape(QFrame.VLine) g.addWidget(self._fr) g.addWidget(self.help_label) self._b = b = QGridLayout() left, top, right, bottom = b.getContentsMargins() top += top b.setContentsMargins(left, top, right, bottom) l.addLayout(b, stretch=10) self.explode_button = QPushButton(QIcon(I('wizard.png')), _('&Explode Book')) self.preview_button = QPushButton(QIcon(I('view.png')), _('&Preview Book')) self.cancel_button = QPushButton(QIcon(I('window-close.png')), _('&Cancel')) self.rebuild_button = QPushButton(QIcon(I('exec.png')), _('&Rebuild Book')) self.explode_button.setToolTip( _('Explode the book to edit its components')) self.preview_button.setToolTip( _('Preview the result of your changes')) self.cancel_button.setToolTip( _('Abort without saving any changes')) self.rebuild_button.setToolTip( _('Save your changes and update the book in the calibre library')) a = b.addWidget a(self.explode_button, 0, 0, 1, 1) a(self.preview_button, 0, 1, 1, 1) a(self.cancel_button, 1, 0, 1, 1) a(self.rebuild_button, 1, 1, 1, 1) for x in ('explode', 'preview', 'cancel', 'rebuild'): getattr(self, x+'_button').clicked.connect(getattr(self, x)) self.msg = QLabel('dummy', self) self.msg.setVisible(False) self.msg.setStyleSheet(''' QLabel { text-align: center; background-color: white; color: black; border-width: 1px; border-style: solid; border-radius: 20px; font-size: x-large; font-weight: bold; } ''') self.resize(self.sizeHint() + QSize(40, 10))
class MakeBrickDialog(QDialog): def __init__(self, parent, modal=True, flags=Qt.WindowFlags()): QDialog.__init__(self, parent, flags) self.setModal(modal) self.setWindowTitle("Convert sources to FITS brick") lo = QVBoxLayout(self) lo.setMargin(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()) QObject.connect(self.wadd, SIGNAL("toggled(bool)"), self.wpad.setEnabled) QObject.connect(self.wadd, SIGNAL("toggled(bool)"), 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(0, 0, 0, 0) lo2.setMargin(5) self.wokbtn = QPushButton("OK", self) self.wokbtn.setMinimumWidth(128) QObject.connect(self.wokbtn, SIGNAL("clicked()"), self.accept) self.wokbtn.setEnabled(False) cancelbtn = QPushButton("Cancel", self) cancelbtn.setMinimumWidth(128) QObject.connect(cancelbtn, SIGNAL("clicked()"), self.reject) lo2.addWidget(self.wokbtn) lo2.addStretch(1) lo2.addWidget(cancelbtn) self.setMinimumWidth(384) # signals QObject.connect(self.wfile, SIGNAL("filenameSelected"), 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 = None 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") 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 = None 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 = None 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 = None return QDialog.accept(self)
def __init__(self, dirname, purrlogs, parent=None, create=None, message=None): QWizardPage.__init__(self, parent) self.dirname = dirname self.purrlogs = purrlogs or [] bg = QButtonGroup(self) lo = QVBoxLayout() self.setLayout(lo) # set page titles self.setTitle("Starting PURR") message and self.setSubTitle(message) if not purrlogs: self.rbs_log = [] else: # add options for existing purrlogs self.rbs_log = [QRadioButton("Load %s" % Kittens.utils.collapseuser(log)) for log in purrlogs] for rb in self.rbs_log: lo.addWidget(rb) bg.addButton(rb) QObject.connect(rb, SIGNAL("toggled(bool)"), self.checkCompleteness) self.rbs_log[0].setChecked(True) # add option to load another purrlog lo1 = QHBoxLayout() self.rb_other = QRadioButton("Load purrlog from:") lo1.addWidget(self.rb_other) bg.addButton(self.rb_other) self.wother = QLineEdit() self.wother.setReadOnly(True) lo1.addWidget(self.wother, 1) pb = QPushButton(pixmaps.folder_open.icon(), "") QObject.connect(pb, SIGNAL("clicked()"), self._select_other_dialog) QObject.connect(self.rb_other, SIGNAL("toggled(bool)"), pb.setEnabled) QObject.connect(self.rb_other, SIGNAL("toggled(bool)"), self.wother.setEnabled) QObject.connect(self.rb_other, SIGNAL("toggled(bool)"), self.checkCompleteness) pb.setEnabled(False) self.wother.setEnabled(False) lo1.addWidget(pb) lo.addLayout(lo1) self.load_path = None # add option to create new purrlog lo1 = QHBoxLayout() self.rb_create = QRadioButton("Create new purrlog:") lo1.addWidget(self.rb_create) bg.addButton(self.rb_create) self.wcreate = QLineEdit() lo1.addWidget(self.wcreate, 1) pb = QPushButton(pixmaps.folder_open.icon(), "") QObject.connect(pb, SIGNAL("clicked()"), self._select_create_dialog) QObject.connect(self.rb_create, SIGNAL("toggled(bool)"), pb.setEnabled) QObject.connect(self.rb_create, SIGNAL("toggled(bool)"), self.wcreate.setEnabled) QObject.connect(self.rb_create, SIGNAL("toggled(bool)"), self.checkCompleteness) QObject.connect(self.wcreate, SIGNAL("editingFinished()"), self._validate_create_filename) pb.setEnabled(False) self.wcreate.setEnabled(False) # this holds the last validated name self._validated_create_path = None self._validated_result = False # generate default name for a new purrlog self.create_path = os.path.join(dirname, "purrlog") num = 0 while os.path.exists(self.create_path): self.create_path = os.path.join(dirname, "purrlog.%d" % num) num += 1 # This will be not None as long as a valid name is entered self.create_path = Kittens.utils.collapseuser(os.path.normpath(self.create_path)) if create: self.wcreate.setText(create or Kittens.utils.collapseuser(create)) # this will emit checkCompleteness(), causing a _validate_create_filename() call, causing the content of the wcreate widget # to be validated and copied to create_path if valid, or reset from create_path if invalid self.rb_create.setChecked(True) else: self.wcreate.setText(self.create_path) lo1.addWidget(pb) lo.addLayout(lo1) # make create option default, if no purrlogs if not purrlogs: self.rb_create.setChecked(True)
def setup_ui(self): self.setWindowIcon(QIcon(I('diff.png'))) self.stacks = st = QStackedLayout(self) self.busy = BusyWidget(self) self.w = QWidget(self) st.addWidget(self.busy), st.addWidget(self.w) self.setLayout(st) self.l = l = QGridLayout() self.w.setLayout(l) self.view = v = DiffView(self, show_open_in_editor=self.show_open_in_editor) l.addWidget(v, l.rowCount(), 0, 1, -1) r = l.rowCount() self.bp = b = QToolButton(self) b.setIcon(QIcon(I('back.png'))) b.clicked.connect(partial(self.view.next_change, -1)) b.setToolTip(_('Go to previous change') + ' [p]') b.setText(_('&Previous change')), b.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) l.addWidget(b, r, 0) self.bn = b = QToolButton(self) b.setIcon(QIcon(I('forward.png'))) b.clicked.connect(partial(self.view.next_change, 1)) b.setToolTip(_('Go to next change') + ' [n]') b.setText(_('&Next change')), b.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) l.addWidget(b, r, 1) self.search = s = HistoryLineEdit2(self) s.initialize('diff_search_history') l.addWidget(s, r, 2) s.setPlaceholderText(_('Search for text')) s.returnPressed.connect(partial(self.do_search, False)) self.sbn = b = QToolButton(self) b.setIcon(QIcon(I('arrow-down.png'))) b.clicked.connect(partial(self.do_search, False)) b.setToolTip(_('Find next match')) b.setText(_('Next &match')), b.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) l.addWidget(b, r, 3) self.sbp = b = QToolButton(self) b.setIcon(QIcon(I('arrow-up.png'))) b.clicked.connect(partial(self.do_search, True)) b.setToolTip(_('Find previous match')) b.setText(_('P&revious match')), b.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) l.addWidget(b, r, 4) self.lb = b = QRadioButton(_('Left panel'), self) b.setToolTip(_('Perform search in the left panel')) l.addWidget(b, r, 5) self.rb = b = QRadioButton(_('Right panel'), self) b.setToolTip(_('Perform search in the right panel')) l.addWidget(b, r, 6) b.setChecked(True) self.pb = b = QToolButton(self) b.setIcon(QIcon(I('config.png'))) b.setText(_('&Options')), b.setToolButtonStyle( Qt.ToolButtonTextBesideIcon) b.setToolTip(_('Change how the differences are displayed')) b.setPopupMode(b.InstantPopup) m = QMenu(b) b.setMenu(m) cm = self.cm = QMenu(_('Lines of context around each change')) for i in (3, 5, 10, 50): cm.addAction( _('Show %d lines of context') % i, partial(self.change_context, i)) cm.addAction(_('Show all text'), partial(self.change_context, None)) self.beautify_action = m.addAction('', self.toggle_beautify) self.set_beautify_action_text() m.addMenu(cm) l.addWidget(b, r, 7) self.hl = QHBoxLayout() l.addLayout(self.hl, l.rowCount(), 0, 1, -1) self.names = QLabel('') self.hl.addWidget(self.names, r) self.bb.setStandardButtons(self.bb.Close) if self.revert_button_msg is not None: self.rvb = b = self.bb.addButton(self.revert_button_msg, self.bb.ActionRole) b.setIcon(QIcon(I('edit-undo.png'))), b.setAutoDefault(False) b.clicked.connect(self.revert_requested) b.clicked.connect(self.reject) self.bb.button(self.bb.Close).setDefault(True) self.hl.addWidget(self.bb, r) self.view.setFocus(Qt.OtherFocusReason)
def create_widgets(self): gridLayout = QGridLayout() groupBox = QGroupBox( 'Rendering controls' ) groupBox.setFlat(True) groupBox2 = QGroupBox( 'DBSCAN centroids' ) groupBox2.setFlat(True) groupBox3 = QGroupBox( 'Electrode filter' ) groupBox3.setFlat(True) gridLayout.addWidget(groupBox) gridLayout.addWidget(groupBox3) gridLayout.addWidget(groupBox2) # rendering controls self.visi_label = QLabel( 'show electrodes' ) self.visi = QCheckBox() self.visi.setChecked(False) self.fall_off_label = QLabel( 'fall-off' ) self.fall_off = QSlider(Qt.Horizontal) self.fall_off.setRange(1, 100) # data set dependent self.thickness_label = QLabel( 'thickness' ) self.thickness = QSlider(Qt.Horizontal) self.thickness.setRange(1, 100) # data set dependent self.trans_label = QLabel( 'force translucency' ) self.forced_translucency = QCheckBox() self.forced_translucency.setChecked(False) # dbscan controls #self.view_button_grp = QButtonGroup() self.all_electrodes = QRadioButton('show all') self.only_clusters = QRadioButton('show clusters') self.only_noise = QRadioButton('show noise') self.all_electrodes.setEnabled(False) self.all_electrodes.setChecked(True) self.only_clusters.setEnabled(False) self.only_noise.setEnabled(False) #self.view_button_grp.addButton( self.all_electrodes ) #self.view_button_grp.addButton( self.only_clusters ) #self.view_button_grp.addButton( self.only_noise ) #gridLayout.addWidget(self.view_button_grp) self.eps_label = QLabel( 'epsilon' ) self.eps_spinbox = QDoubleSpinBox() self.eps_spinbox.setRange(0.1, 10) self.eps_spinbox.setSingleStep(0.1) self.min_points_label = QLabel( 'min points' ) self.min_spinbox = QSpinBox() self.min_spinbox.setRange(1, 20) self.min_spinbox.setSingleStep(1) self.button = QPushButton('Recalculate') self.button.setCheckable(True) self.browser = QTextBrowser() vbox = QVBoxLayout() vbox2 = QVBoxLayout() vbox3 = QVBoxLayout() vbox.addWidget( self.visi_label ) vbox.addWidget( self.visi ) vbox.addWidget( self.fall_off_label ) vbox.addWidget( self.fall_off ) vbox.addWidget( self.thickness_label ) vbox.addWidget( self.thickness ) vbox.addWidget( self.trans_label ) vbox.addWidget( self.forced_translucency ) vbox2.addWidget( self.eps_label ) vbox2.addWidget( self.eps_spinbox ) vbox2.addWidget( self.min_points_label ) vbox2.addWidget( self.min_spinbox ) vbox2.addWidget( self.button ) vbox2.addWidget( self.browser ) vbox3.addWidget( self.all_electrodes ) vbox3.addWidget( self.only_clusters ) vbox3.addWidget( self.only_noise ) groupBox.setLayout(vbox) groupBox2.setLayout(vbox2) groupBox3.setLayout(vbox3) self.setLayout(gridLayout) self.layout().setSizeConstraint( QLayout.SetFixedSize )
class dbsElectrodeControlsDialog(QDialog): def __init__(self, callback, parent=None): QDialog.__init__(self, parent) self.callback = callback self.create_widgets() #self.layout_widgets() self.create_connections() self.setModal(False) self.setWindowTitle('Electrode Controls') self.layout().setSizeConstraint(QLayout.SetFixedSize) self.saved_params = dict() def create_widgets(self): gridLayout = QGridLayout() groupBox = QGroupBox( 'Rendering controls' ) groupBox.setFlat(True) groupBox2 = QGroupBox( 'DBSCAN centroids' ) groupBox2.setFlat(True) groupBox3 = QGroupBox( 'Electrode filter' ) groupBox3.setFlat(True) gridLayout.addWidget(groupBox) gridLayout.addWidget(groupBox3) gridLayout.addWidget(groupBox2) # rendering controls self.visi_label = QLabel( 'show electrodes' ) self.visi = QCheckBox() self.visi.setChecked(False) self.fall_off_label = QLabel( 'fall-off' ) self.fall_off = QSlider(Qt.Horizontal) self.fall_off.setRange(1, 100) # data set dependent self.thickness_label = QLabel( 'thickness' ) self.thickness = QSlider(Qt.Horizontal) self.thickness.setRange(1, 100) # data set dependent self.trans_label = QLabel( 'force translucency' ) self.forced_translucency = QCheckBox() self.forced_translucency.setChecked(False) # dbscan controls #self.view_button_grp = QButtonGroup() self.all_electrodes = QRadioButton('show all') self.only_clusters = QRadioButton('show clusters') self.only_noise = QRadioButton('show noise') self.all_electrodes.setEnabled(False) self.all_electrodes.setChecked(True) self.only_clusters.setEnabled(False) self.only_noise.setEnabled(False) #self.view_button_grp.addButton( self.all_electrodes ) #self.view_button_grp.addButton( self.only_clusters ) #self.view_button_grp.addButton( self.only_noise ) #gridLayout.addWidget(self.view_button_grp) self.eps_label = QLabel( 'epsilon' ) self.eps_spinbox = QDoubleSpinBox() self.eps_spinbox.setRange(0.1, 10) self.eps_spinbox.setSingleStep(0.1) self.min_points_label = QLabel( 'min points' ) self.min_spinbox = QSpinBox() self.min_spinbox.setRange(1, 20) self.min_spinbox.setSingleStep(1) self.button = QPushButton('Recalculate') self.button.setCheckable(True) self.browser = QTextBrowser() vbox = QVBoxLayout() vbox2 = QVBoxLayout() vbox3 = QVBoxLayout() vbox.addWidget( self.visi_label ) vbox.addWidget( self.visi ) vbox.addWidget( self.fall_off_label ) vbox.addWidget( self.fall_off ) vbox.addWidget( self.thickness_label ) vbox.addWidget( self.thickness ) vbox.addWidget( self.trans_label ) vbox.addWidget( self.forced_translucency ) vbox2.addWidget( self.eps_label ) vbox2.addWidget( self.eps_spinbox ) vbox2.addWidget( self.min_points_label ) vbox2.addWidget( self.min_spinbox ) vbox2.addWidget( self.button ) vbox2.addWidget( self.browser ) vbox3.addWidget( self.all_electrodes ) vbox3.addWidget( self.only_clusters ) vbox3.addWidget( self.only_noise ) groupBox.setLayout(vbox) groupBox2.setLayout(vbox2) groupBox3.setLayout(vbox3) self.setLayout(gridLayout) self.layout().setSizeConstraint( QLayout.SetFixedSize ) def create_connections(self): self.visi.stateChanged.connect(self.__toggleVisibility) self.fall_off.valueChanged.connect(self.__setOpacityFalloff) self.thickness.valueChanged.connect(self.__setLineThickness) self.forced_translucency.stateChanged.connect(self.__toggleForceTranslucency) self.button.pressed.connect(self.__calculateDBSCANClusters) self.all_electrodes.toggled.connect(self.__setElectrodeTypeVisible) self.only_clusters.toggled.connect(self.__setElectrodeTypeVisible) self.only_noise.toggled.connect(self.__setElectrodeTypeVisible) def __setElectrodeTypeVisible(self): av = self.parent().active_vol vdata = self.parent()._vdata[av] if self.all_electrodes.isChecked(): vdata.setAllElectrodesVisible() elif self.only_clusters.isChecked(): vdata.setElectrodeClustersVisible() elif self.only_noise.isChecked(): vdata.setElectrodeNoiseVisible() def __calculateDBSCANClusters(self): av = self.parent().active_vol vdata = self.parent()._vdata[av] vdata.setDBSCANEps( self.eps_spinbox.value() ) vdata.setDBSCANMinPts( self.min_spinbox.value() ) vdata.clusterWithDBSCAN() count = vdata.electrode_centroid_clustering.dbscan_clusters labels = vdata.electrode_centroid_clustering.dbscan_results.labels_ out = 'Estimated number of clusters: %d\n' % count #self.browser.setText('Estimated number of clusters: %d' % count) for patnum, score in enumerate(labels): out += 'Patient {0}: {1}\n'.format(patnum, score) self.browser.setText(out) vdata.setElectrodeClustersVisible() self.only_clusters.setChecked(True) def __toggleVisibility(self): av = self.parent().active_vol vdata = self.parent()._vdata[av]._electrodes on = False if self.visi.checkState(): on = True self.all_electrodes.setEnabled(True) self.only_clusters.setEnabled(True) self.only_noise.setEnabled(True) else: self.all_electrodes.setEnabled(False) self.only_clusters.setEnabled(False) self.only_noise.setEnabled(False) for electrode in vdata: electrode.setVis(on) self.apply() def __toggleForceTranslucency(self): av = self.parent().active_vol vdata = self.parent()._vdata[av]._electrodes on = False if self.forced_translucency.checkState(): on = True for electrode in vdata: electrode.forceTranslucency(on) self.apply() def __setOpacityFalloff(self): av = self.parent().active_vol vdata = self.parent()._vdata[av]._electrodes #self.fall_off.setValue( vdata[-1].fall_off ) for electrode in vdata: electrode.setFallOff(self.fall_off.value() / 10.0) self.apply() def __setLineThickness(self): av = self.parent().active_vol vdata = self.parent()._vdata[av]._electrodes for electrode in vdata: electrode.setThickness(self.thickness.value() / 10.0) self.apply() def saveCurrentParams(self, av, fresh_load = False): #av = self.parent().active_vol #vdata = self.parent()._vdata[av]._electrodes if av not in self.saved_params.keys(): self.saved_params[av] = ElectrodeParameters() self.saved_params[av].electrodes_show = self.visi.isChecked() self.saved_params[av].electrodes_all = self.all_electrodes.isChecked() self.saved_params[av].electrodes_clusters = self.only_clusters.isChecked() self.saved_params[av].electrodes_noise = self.only_noise.isChecked() self.saved_params[av].falloff = self.fall_off.value() self.saved_params[av].thickness = self.thickness.value() self.saved_params[av].transp = self.forced_translucency.isChecked() self.saved_params[av].fresh_load = fresh_load def updateWidgetValues(self, av, default = False): #av = self.parent().active_vol #vdata = self.parent()._vdata[av]._electrodes if av not in self.saved_params.keys(): self.saved_params[av] = ElectrodeParameters() if default: # todo: need to have default values in one place for assignment self.visi.setChecked( False ) self.all_electrodes.setChecked( False ) self.only_clusters.setChecked( False ) self.only_noise.setChecked( False ) self.fall_off.setValue( 1 ) self.thickness.setValue( 10 ) self.forced_translucency.setChecked( False ) else: self.visi.setChecked( self.saved_params[av].electrodes_show ) self.all_electrodes.setChecked( self.saved_params[av].electrodes_all ) self.only_clusters.setChecked( self.saved_params[av].electrodes_clusters ) self.only_noise.setChecked( self.saved_params[av].electrodes_noise ) self.fall_off.setValue( self.saved_params[av].falloff ) self.thickness.setValue( self.saved_params[av].thickness ) self.forced_translucency.setChecked( self.saved_params[av].transp ) def apply(self): av = self.parent().active_vol self.parent().vol_qvtk_widgets[av].update()