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 "
Example #3
0
    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())
Example #4
0
    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)
Example #6
0
    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)
Example #7
0
    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)
Example #8
0
    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)
Example #9
0
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 '
Example #10
0
    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
Example #11
0
 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())
Example #12
0
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)
Example #13
0
 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)
Example #14
0
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)
Example #15
0
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())
Example #17
0
 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)
Example #18
0
    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))
Example #19
0
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)
Example #20
0
        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)
Example #21
0
    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)
Example #22
0
 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 )
Example #23
0
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()