Exemplo n.º 1
0
class StaffGroup(_base.Container):
    @staticmethod
    def title(_=_base.translate):
        return _("Staff Group")

    def accepts(self):
        return (StaffGroup, _base.Part)

    def createWidgets(self, layout):
        self.systemStartLabel = QLabel()
        self.systemStart = QComboBox()
        self.systemStartLabel.setBuddy(self.systemStart)
        self.systemStart.setModel(
            listmodel.ListModel(
                (
                    # L10N: Brace like a piano staff
                    (lambda: _("Brace"), 'system_start_brace'),
                    # L10N: Bracket like a choir staff
                    (lambda: _("Bracket"), 'system_start_bracket'),
                    # L10N: Square bracket like a sub-group
                    (lambda: _("Square"), 'system_start_square'),
                ),
                self.systemStart,
                display=listmodel.translate_index(0),
                icon=lambda item: symbols.icon(item[1])))
        self.systemStart.setIconSize(QSize(64, 64))
        self.connectBarLines = QCheckBox(checked=True)

        box = QHBoxLayout()
        box.addWidget(self.systemStartLabel)
        box.addWidget(self.systemStart)
        layout.addLayout(box)
        layout.addWidget(self.connectBarLines)

    def translateWidgets(self):
        self.systemStartLabel.setText(_("Type:"))
        self.connectBarLines.setText(_("Connect Barlines"))
        self.connectBarLines.setToolTip(
            _("If checked, barlines are connected between the staves."))
        self.systemStart.model().update()

    def build(self, data, builder):
        s = self.systemStart.currentIndex()
        b = self.connectBarLines.isChecked()
        if s == 0:
            node = ly.dom.GrandStaff()
            if not b:
                ly.dom.Line("\\remove Span_bar_engraver", node.getWith())
        else:
            node = ly.dom.StaffGroup() if b else ly.dom.ChoirStaff()
            if s == 2:
                node.getWith()['systemStartDelimiter'] = ly.dom.Scheme(
                    "'SystemStartSquare")
        data.nodes.append(node)
        data.music = ly.dom.Simr(node)
Exemplo n.º 2
0
class StaffGroup(_base.Container):
    @staticmethod
    def title(_=_base.translate):
        return _("Staff Group")

    def accepts(self):
        return (StaffGroup, _base.Part)

    def createWidgets(self, layout):
        self.systemStartLabel = QLabel()
        self.systemStart = QComboBox()
        self.systemStartLabel.setBuddy(self.systemStart)
        self.systemStart.setModel(listmodel.ListModel((
            # L10N: Brace like a piano staff
            (lambda: _("Brace"), 'system_start_brace'),
            # L10N: Bracket like a choir staff
            (lambda: _("Bracket"), 'system_start_bracket'),
            # L10N: Square bracket like a sub-group
            (lambda: _("Square"), 'system_start_square'),
            ), self.systemStart, display=listmodel.translate_index(0),
            icon=lambda item: symbols.icon(item[1])))
        self.systemStart.setIconSize(QSize(64, 64))
        self.connectBarLines = QCheckBox(checked=True)
        
        box = QHBoxLayout()
        box.addWidget(self.systemStartLabel)
        box.addWidget(self.systemStart)
        layout.addLayout(box)
        layout.addWidget(self.connectBarLines)
    
    def translateWidgets(self):
        self.systemStartLabel.setText(_("Type:"))
        self.connectBarLines.setText(_("Connect Barlines"))
        self.connectBarLines.setToolTip(_("If checked, barlines are connected between the staves."))
        self.systemStart.model().update()
    
    def build(self, data, builder):
        s = self.systemStart.currentIndex()
        b = self.connectBarLines.isChecked()
        if s == 0:
            node = ly.dom.GrandStaff()
            if not b:
                ly.dom.Line("\\remove Span_bar_engraver", node.getWith())
        else:
            node = ly.dom.StaffGroup() if b else ly.dom.ChoirStaff()
            if s == 2:
                node.getWith()['systemStartDelimiter'] = ly.dom.Scheme("'SystemStartSquare")
        data.nodes.append(node)
        data.music = ly.dom.Simr(node)
Exemplo n.º 3
0
class RecentPathsWComboMixin(RecentPathsWidgetMixin):
    """
    Adds file combo handling to :obj:`RecentPathsWidgetMixin`.

    The mixin constructs a combo box `self.file_combo` and provides a method
    `set_file_list` for updating its content. The mixin also overloads the
    inherited `add_path` and `select_file` to call `set_file_list`.
    """

    def __init__(self):
        super().__init__()
        self.file_combo = \
            QComboBox(self, sizeAdjustPolicy=QComboBox.AdjustToContents)

    def add_path(self, filename):
        """Add (or move) a file name to the top of recent paths"""
        super().add_path(filename)
        self.set_file_list()

    def select_file(self, n):
        """Move the n-th file to the top of the list"""
        super().select_file(n)
        self.set_file_list()

    def set_file_list(self):
        """
        Sets the items in the file list combo
        """
        self._check_init()
        self.file_combo.clear()
        if not self.recent_paths:
            self.file_combo.addItem("(none)")
            self.file_combo.model().item(0).setEnabled(False)
        else:
            for i, recent in enumerate(self.recent_paths):
                self.file_combo.addItem(recent.basename)
                self.file_combo.model().item(i).setToolTip(recent.abspath)

    def workflowEnvChanged(self, key, value, oldvalue):
        super().workflowEnvChanged(key, value, oldvalue)
        if key == "basedir":
            self.set_file_list()
Exemplo n.º 4
0
class RecentPathsWComboMixin(RecentPathsWidgetMixin):
    """
    Adds file combo handling to :obj:`RecentPathsWidgetMixin`.

    The mixin constructs a combo box `self.file_combo` and provides a method
    `set_file_list` for updating its content. The mixin also overloads the
    inherited `add_path` and `select_file` to call `set_file_list`.
    """
    def __init__(self):
        super().__init__()
        self.file_combo = \
            QComboBox(self, sizeAdjustPolicy=QComboBox.AdjustToContents)

    def add_path(self, filename):
        """Add (or move) a file name to the top of recent paths"""
        super().add_path(filename)
        self.set_file_list()

    def select_file(self, n):
        """Move the n-th file to the top of the list"""
        super().select_file(n)
        self.set_file_list()

    def set_file_list(self):
        """
        Sets the items in the file list combo
        """
        self._check_init()
        self.file_combo.clear()
        if not self.recent_paths:
            self.file_combo.addItem("(none)")
            self.file_combo.model().item(0).setEnabled(False)
        else:
            for i, recent in enumerate(self.recent_paths):
                self.file_combo.addItem(recent.basename)
                self.file_combo.model().item(i).setToolTip(recent.abspath)

    def workflowEnvChanged(self, key, value, oldvalue):
        super().workflowEnvChanged(key, value, oldvalue)
        if key == "basedir":
            self.set_file_list()
Exemplo n.º 5
0
class ChordNames(object):
    def createWidgets(self, layout):
        self.chordStyleLabel = QLabel()
        self.chordStyle = QComboBox()
        self.chordStyleLabel.setBuddy(self.chordStyle)
        self.chordStyle.setModel(listmodel.ListModel(chordNameStyles, self.chordStyle,
            display=listmodel.translate))
        self.guitarFrets = QCheckBox()
        
        box = QHBoxLayout()
        box.addWidget(self.chordStyleLabel)
        box.addWidget(self.chordStyle)
        layout.addLayout(box)
        layout.addWidget(self.guitarFrets)
        
    def translateWidgets(self):
        self.chordStyleLabel.setText(_("Chord style:"))
        self.guitarFrets.setText(_("Guitar fret diagrams"))
        self.guitarFrets.setToolTip(_(
            "Show predefined guitar fret diagrams below the chord names "
            "(LilyPond 2.12 and above)."))
        self.chordStyle.model().update()

    def build(self, data, builder):
        p = ly.dom.ChordNames()
        a = data.assign('chordNames')
        ly.dom.Identifier(a.name, p)
        s = ly.dom.ChordMode(a)
        ly.dom.Identifier(data.globalName, s).after = 1
        i = self.chordStyle.currentIndex()
        if i > 0:
            ly.dom.Line('\\{0}Chords'.format(
                ('german', 'semiGerman', 'italian', 'french')[i-1]), s)
        ly.dom.LineComment(_("Chords follow here."), s)
        ly.dom.BlankLine(s)
        data.nodes.append(p)
        if self.guitarFrets.isChecked():
            f = ly.dom.FretBoards()
            ly.dom.Identifier(a.name, f)
            data.nodes.append(f)
            data.includes.append("predefined-guitar-fretboards.ly")
Exemplo n.º 6
0
class Drums(_base.Part):
    @staticmethod
    def title(_=_base.translate):
        return _("Drums")

    @staticmethod
    def short(_=_base.translate):
        return _("abbreviation for Drums", "Dr.")

    def createWidgets(self, layout):
        self.voicesLabel = QLabel()
        self.voices = QSpinBox(minimum=1, maximum=4, value=1)
        self.drumStyleLabel = QLabel()
        self.drumStyle = QComboBox()
        self.drumStyle.setModel(
            listmodel.ListModel(drumStyles,
                                self.drumStyle,
                                display=listmodel.translate))
        self.drumStems = QCheckBox()

        box = QHBoxLayout()
        box.addWidget(self.voicesLabel)
        box.addWidget(self.voices)
        layout.addLayout(box)
        box = QHBoxLayout()
        box.addWidget(self.drumStyleLabel)
        box.addWidget(self.drumStyle)
        layout.addLayout(box)
        layout.addWidget(self.drumStems)

    def translateWidgets(self):
        self.voicesLabel.setText(_("Voices:"))
        self.drumStyleLabel.setText(_("Style:"))
        self.drumStems.setText(_("Remove stems"))
        self.drumStems.setToolTip(_("Remove the stems from the drum notes."))
        self.drumStyle.model().update()

    def assignDrums(self, data, name=None):
        """Creates an empty name = \drummode assignment.

        Returns the assignment.
        
        """
        a = data.assign(name)
        s = ly.dom.DrumMode(a)
        ly.dom.Identifier(data.globalName, s)
        ly.dom.LineComment(_("Drums follow here."), s)
        ly.dom.BlankLine(s)
        return a

    def build(self, data, builder):
        p = ly.dom.DrumStaff()
        s = ly.dom.Simr(p)
        if self.voices.value() > 1:
            for i in range(1, self.voices.value() + 1):
                q = ly.dom.Seq(ly.dom.DrumVoice(parent=s))
                ly.dom.Text('\\voice' + ly.util.int2text(i), q)
                a = self.assignDrums(data, 'drum' + ly.util.int2text(i))
                ly.dom.Identifier(a.name, q)
        else:
            a = self.assignDrums(data, 'drum')
            ly.dom.Identifier(a.name, s)
        builder.setInstrumentNamesFromPart(p, self, data)
        i = self.drumStyle.currentIndex()
        if i > 0:
            v = ('drums', 'timbales', 'congas', 'bongos', 'percussion')[i]
            p.getWith()['drumStyleTable'] = ly.dom.Scheme(v + '-style')
            v = (5, 2, 2, 2, 1)[i]
            ly.dom.Line("\\override StaffSymbol #'line-count = #{0}".format(v),
                        p.getWith())
        if self.drumStems.isChecked():
            ly.dom.Line("\\override Stem #'stencil = ##f", p.getWith())
            ly.dom.Line(
                "\\override Stem #'length = #3  % " + _("keep some distance."),
                p.getWith())
        data.nodes.append(p)
Exemplo n.º 7
0
class ScoreProperties(object):
    """This is only the base class, it should be mixed in with a widget or a different way."""

    def createWidgets(self):
        """Creates all widgets."""
        self.createKeySignatureWidget()
        self.createTimeSignatureWidget()
        self.createPickupWidget()
        self.createMetronomeWidget()
        self.createTempoWidget()
        
    def layoutWidgets(self, layout):
        """Adds all widgets to a vertical layout."""
        self.layoutKeySignatureWidget(layout)
        self.layoutTimeSignatureWidget(layout)
        self.layoutPickupWidget(layout)
        self.layoutMetronomeWidget(layout)
        self.layoutTempoWidget(layout)
        
    def translateWidgets(self):
        self.translateKeySignatureWidget()
        self.translateTimeSignatureWidget()
        self.translatePickupWidget()
        self.tranlateMetronomeWidget()
        self.translateTempoWidget()
    
    def ly(self, node, builder):
        """Adds appropriate LilyPond command nodes to the parent node.
        
        Settings from the builder are used where that makes sense.
        All widgets must be present.
        
        """
        self.lyKeySignature(node, builder)
        self.lyTimeSignature(node, builder)
        self.lyPickup(node, builder)
        self.lyTempo(node, builder)
    
    def globalSection(self, builder):
        """Returns a sequential expression between { } containing the output of ly()."""
        seq = ly.dom.Seq()
        self.ly(seq, builder)
        return seq
        
    # Key signature
    def createKeySignatureWidget(self):
        self.keySignatureLabel = QLabel()
        self.keyNote = QComboBox()
        self.keyNote.setModel(listmodel.ListModel(keyNames['nederlands'], self.keyNote))
        self.keyMode = QComboBox()
        self.keyMode.setModel(listmodel.ListModel(modes, self.keyMode, display=listmodel.translate_index(1)))
        self.keySignatureLabel.setBuddy(self.keyNote)
        
    def translateKeySignatureWidget(self):
        self.keySignatureLabel.setText(_("Key signature:"))
        self.keyMode.model().update()
    
    def layoutKeySignatureWidget(self, layout):
        """Adds our widgets to a layout, assuming it is a QVBoxLayout."""
        box = QHBoxLayout()
        box.addWidget(self.keySignatureLabel)
        box.addWidget(self.keyNote)
        box.addWidget(self.keyMode)
        layout.addLayout(box)

    def setPitchLanguage(self, language='nederlands'):
        self.keyNote.model()._data = keyNames[language or 'nederlands']
        self.keyNote.model().update()
    
    def lyKeySignature(self, node, builder):
        """Adds the key signature to the ly.dom node parent."""
        note, alter = keys[self.keyNote.currentIndex()]
        alter = fractions.Fraction(alter, 2)
        mode = modes[self.keyMode.currentIndex()][0]
        ly.dom.KeySignature(note, alter, mode, node).after = 1
        
    # Time signature
    def createTimeSignatureWidget(self):
        self.timeSignatureLabel = QLabel()
        self.timeSignature = QComboBox(editable=True)
        icons = {
            '(4/4)': symbols.icon('time_c44'),
            '(2/2)': symbols.icon('time_c22'),
        }
        self.timeSignature.setModel(listmodel.ListModel(timeSignaturePresets, self.timeSignature,
            icon=icons.get))
        self.timeSignature.setCompleter(None)
        self.timeSignatureLabel.setBuddy(self.timeSignature)
    
    def translateTimeSignatureWidget(self):
        self.timeSignatureLabel.setText(_("Time signature:"))
    
    def layoutTimeSignatureWidget(self, layout):
        """Adds our widgets to a layout, assuming it is a QVBoxLayout."""
        box = QHBoxLayout()
        box.addWidget(self.timeSignatureLabel)
        box.addWidget(self.timeSignature)
        layout.addLayout(box)
    
    def lyTimeSignature(self, node, builder):
        """Adds the time signature to the ly.dom node parent."""
        sig = self.timeSignature.currentText().strip()
        if '+' in sig:
            pass # TODO: implement support for \compoundMeter
        else:
            if sig == '(2/2)':
                ly.dom.TimeSignature(2, 2, node).after = 1
            elif sig == '(4/4)':
                ly.dom.TimeSignature(4, 4, node).after = 1
            else:
                match = re.search(r'(\d+).*?(\d+)', sig)
                if match:
                    if builder.lyVersion >= (2, 11, 44):
                        ly.dom.Line(r"\numericTimeSignature", node)
                    else:
                        ly.dom.Line(r"\override Staff.TimeSignature #'style = #'()", node)
                    num, beat = map(int, match.group(1, 2))
                    ly.dom.TimeSignature(num, beat, node).after = 1

    # Pickup bar
    def createPickupWidget(self):
        self.pickupLabel = QLabel()
        self.pickup = QComboBox()
        pickups = ['']
        pickups.extend(durations)
        self.pickup.setModel(listmodel.ListModel(pickups, self.pickup,
            display = lambda item: item or _("None"),
            icon = lambda item: symbols.icon('note_{0}'.format(item.replace('.', 'd'))) if item else None))
        self.pickup.view().setIconSize(QSize(22, 22))
        self.pickupLabel.setBuddy(self.pickup)
        
    def translatePickupWidget(self):
        self.pickupLabel.setText(_("Pickup measure:"))
        self.pickup.model().update()
        
    def layoutPickupWidget(self, layout):
        box = QHBoxLayout()
        box.addWidget(self.pickupLabel)
        box.addWidget(self.pickup)
        layout.addLayout(box)
    
    def lyPickup(self, node, builder):
         if self.pickup.currentIndex() > 0:
            dur, dots = partialDurations[self.pickup.currentIndex() - 1]
            ly.dom.Partial(dur, dots, parent=node)
    
    # Metronome value
    def createMetronomeWidget(self):
        self.metronomeLabel = QLabel()
        self.metronomeNote = QComboBox()
        self.metronomeNote.setModel(listmodel.ListModel(durations, display=None,
            icon = lambda item: symbols.icon('note_{0}'.format(item.replace('.', 'd')))))
        self.metronomeNote.setCurrentIndex(durations.index('4'))
        self.metronomeNote.view().setIconSize(QSize(22, 22))
        self.metronomeEqualSign = QLabel('=')
        self.metronomeEqualSign.setFixedWidth(self.metronomeEqualSign.minimumSizeHint().width())
        self.metronomeValue = QComboBox(editable=True)
        self.metronomeValue.setModel(listmodel.ListModel(metronomeValues, self.metronomeValue,
            display=format))
        self.metronomeValue.setCompleter(None)
        self.metronomeValue.setValidator(QIntValidator(0, 999, self.metronomeValue))
        self.metronomeValue.setCurrentIndex(metronomeValues.index(100))
        self.metronomeTempo = widgets.tempobutton.TempoButton()
        self.metronomeTempo.tempo.connect(self.setMetronomeValue)
        self.metronomeLabel.setBuddy(self.metronomeNote)
    
    def layoutMetronomeWidget(self, layout):
        box = QHBoxLayout(spacing=0)
        box.addWidget(self.metronomeLabel)
        box.addWidget(self.metronomeNote)
        box.addWidget(self.metronomeEqualSign)
        box.addWidget(self.metronomeValue)
        box.addWidget(self.metronomeTempo)
        layout.addLayout(box)
        
    def tranlateMetronomeWidget(self):
        self.metronomeLabel.setText(_("Metronome mark:"))
    
    def setMetronomeValue(self, bpm):
        """ Tap the tempo tap button """
        l = [abs(t - bpm) for t in metronomeValues]
        m = min(l)
        if m < 6:
            self.metronomeValue.setCurrentIndex(l.index(m))

    # Tempo indication
    def createTempoWidget(self):
        self.tempoLabel = QLabel()
        self.tempo = widgets.lineedit.LineEdit()
        completionmodel.complete(self.tempo, "scorewiz/completion/scoreproperties/tempo")
        self.tempo.completer().setCaseSensitivity(Qt.CaseInsensitive)
        self.tempoLabel.setBuddy(self.tempo)

    def layoutTempoWidget(self, layout):
        box = QHBoxLayout()
        box.addWidget(self.tempoLabel)
        box.addWidget(self.tempo)
        layout.addLayout(box)

    def translateTempoWidget(self):
        self.tempoLabel.setText(_("Tempo indication:"))

    def lyTempo(self, node, builder):
        """Returns an appropriate tempo indication."""
        text = self.tempo.text().strip()
        if builder.showMetronomeMark:
            dur = durations[self.metronomeNote.currentIndex()]
            val = self.metronomeValue.currentText()
        elif text:
            dur = None
            val = None
        else:
            return
        tempo = ly.dom.Tempo(dur, val, node)
        if text:
            ly.dom.QuotedString(text, tempo)

    def lyMidiTempo(self, node):
        """Sets the configured tempo in the tempoWholesPerMinute variable."""
        node['tempoWholesPerMinute'] = ly.dom.Scheme(self.schemeMidiTempo())
    
    def schemeMidiTempo(self):
        """Returns a string with the tempo like '(ly:make-moment 100 4)' from the settings."""
        base, mul = midiDurations[self.metronomeNote.currentIndex()]
        val = int(self.metronomeValue.currentText()) * mul
        return "(ly:make-moment {0} {1})".format(val, base)
    
    def lySimpleMidiTempo(self, node):
        """Return a simple \tempo x=y node for the currently set tempo."""
        dur = durations[self.metronomeNote.currentIndex()]
        val = self.metronomeValue.currentText()
        return ly.dom.Tempo(dur, val, node)
Exemplo n.º 8
0
class TablaturePart(_base.Part):
    """Base class for tablature instrument part types."""

    octave = 0
    clef = None
    transposition = None
    tunings = ()  # may contain a list of tunings.
    tabFormat = ''  # can contain a tablatureFormat value.

    def createWidgets(self, layout):
        self.staffTypeLabel = QLabel()
        self.staffType = QComboBox()
        self.staffTypeLabel.setBuddy(self.staffType)
        self.staffType.setModel(
            listmodel.ListModel(tablatureStaffTypes,
                                self.staffType,
                                display=listmodel.translate))
        box = QHBoxLayout()
        layout.addLayout(box)
        box.addWidget(self.staffTypeLabel)
        box.addWidget(self.staffType)
        if self.tunings:
            self.createTuningWidgets(layout)
            self.staffType.activated.connect(self.slotTabEnable)
            self.slotTabEnable(0)

    def createTuningWidgets(self, layout):
        self.tuningLabel = QLabel()
        self.tuning = QComboBox()
        self.tuningLabel.setBuddy(self.tuning)
        tunings = [('', lambda: _("Default"))]
        tunings.extend(self.tunings)
        tunings.append(('', lambda: _("Custom tuning")))
        self.tuning.setModel(
            listmodel.ListModel(tunings,
                                self.tuning,
                                display=listmodel.translate_index(1)))
        self.tuning.setCurrentIndex(1)
        self.customTuning = QLineEdit(enabled=False)
        completionmodel.complete(
            self.customTuning,
            "scorewiz/completion/plucked_strings/custom_tuning")
        self.tuning.currentIndexChanged.connect(self.slotCustomTuningEnable)
        box = QHBoxLayout()
        layout.addLayout(box)
        box.addWidget(self.tuningLabel)
        box.addWidget(self.tuning)
        layout.addWidget(self.customTuning)

    def translateWidgets(self):
        self.staffTypeLabel.setText(_("Staff type:"))
        self.staffType.model().update()
        if self.tunings:
            self.translateTuningWidgets()

    def translateTuningWidgets(self):
        self.tuningLabel.setText(_("Tuning:"))
        self.customTuning.setToolTip('<qt>' + _(
            "Select custom tuning in the combobox and "
            "enter a custom tuning here, e.g. <code>e, a d g b e'</code>. "
            "Use absolute note names in the same language as you want to use "
            "in your document (by default: \"nederlands\")."))
        try:
            self.customTuning.setPlaceholderText(_("Custom tuning..."))
        except AttributeError:
            pass  # only in Qt 4.7+
        self.tuning.model().update()

    def slotTabEnable(self, enable):
        """Called when the user changes the staff type.
        
        Non-zero if the user wants a TabStaff.
        
        """
        self.tuning.setEnabled(bool(enable))
        if enable:
            self.slotCustomTuningEnable(self.tuning.currentIndex())
        else:
            self.customTuning.setEnabled(False)

    def slotCustomTuningEnable(self, index):
        self.customTuning.setEnabled(index > len(self.tunings))

    def voiceCount(self):
        """Returns the number of voices.
        
        Inherit to make this user-settable.
        
        """
        return 1

    def build(self, data, builder):
        # First make assignments for the voices we want to create
        numVoices = self.voiceCount()
        if numVoices == 1:
            voices = (ly.util.mkid(data.name()), )
        elif numVoices == 2:
            order = 1, 2
            voices = 'upper', 'lower'
        elif numVoices == 3:
            order = 1, 3, 2
            voices = 'upper', 'middle', 'lower'
        else:
            order = 1, 2, 3, 4
            voices = [
                ly.util.mkid(data.name(), "voice") + ly.util.int2text(i)
                for i in order
            ]

        assignments = [
            data.assignMusic(name, self.octave, self.transposition)
            for name in voices
        ]

        staffType = self.staffType.currentIndex()
        if staffType in (0, 2):
            # create a normal staff
            staff = ly.dom.Staff()
            seq = ly.dom.Seqr(staff)
            if self.clef:
                ly.dom.Clef(self.clef, seq)
            mus = ly.dom.Simr(seq)
            for a in assignments[:-1]:
                ly.dom.Identifier(a.name, mus)
                ly.dom.VoiceSeparator(mus)
            ly.dom.Identifier(assignments[-1].name, mus)
            builder.setMidiInstrument(staff, self.midiInstrument)

        if staffType in (1, 2):
            # create a tab staff
            tabstaff = ly.dom.TabStaff()
            if self.tabFormat:
                tabstaff.getWith()['tablatureFormat'] = ly.dom.Scheme(
                    self.tabFormat)
            self.setTunings(tabstaff)
            sim = ly.dom.Simr(tabstaff)
            if numVoices == 1:
                ly.dom.Identifier(assignments[0].name, sim)
            else:
                for num, a in zip(order, assignments):
                    s = ly.dom.Seq(ly.dom.TabVoice(parent=sim))
                    ly.dom.Text('\\voice' + ly.util.int2text(num), s)
                    ly.dom.Identifier(a.name, s)

        if staffType == 0:
            # only a normal staff
            p = staff
        elif staffType == 1:
            # only a TabStaff
            builder.setMidiInstrument(tabstaff, self.midiInstrument)
            p = tabstaff
        else:
            # both TabStaff and normal staff
            p = ly.dom.StaffGroup()
            s = ly.dom.Sim(p)
            s.append(staff)
            s.append(tabstaff)

        builder.setInstrumentNamesFromPart(p, self, data)
        data.nodes.append(p)

    def setTunings(self, tab):
        if self.tunings:
            i = self.tuning.currentIndex()
            if i == 0:
                return
            elif i > len(self.tunings):
                value = ly.dom.Text("\\stringTuning <{0}>".format(
                    self.customTuning.text()))
            else:
                tuning = self.tunings[self.tuning.currentIndex() - 1][0]
                value = ly.dom.Scheme(tuning)
            tab.getWith()['stringTunings'] = value
Exemplo n.º 9
0
class InstrumentNames(QGroupBox):
    def __init__(self, parent):
        super(InstrumentNames, self).__init__(parent,
                                              checkable=True,
                                              checked=True)

        grid = QGridLayout()
        self.setLayout(grid)

        self.firstSystemLabel = QLabel()
        self.firstSystem = QComboBox()
        self.firstSystemLabel.setBuddy(self.firstSystem)
        self.otherSystemsLabel = QLabel()
        self.otherSystems = QComboBox()
        self.otherSystemsLabel.setBuddy(self.otherSystems)
        self.languageLabel = QLabel()
        self.language = QComboBox()
        self.languageLabel.setBuddy(self.language)

        self.firstSystem.setModel(
            listmodel.ListModel((lambda: _("Long"), lambda: _("Short")),
                                self.firstSystem,
                                display=listmodel.translate))
        self.otherSystems.setModel(
            listmodel.ListModel(
                (lambda: _("Long"), lambda: _("Short"), lambda: _("None")),
                self.otherSystems,
                display=listmodel.translate))

        self._langs = l = ['', 'C']
        l.extend(sorted(po.available()))

        def display(lang):
            if lang == 'C':
                return _("English (untranslated)")
            elif not lang:
                return _("Default")
            return language_names.languageName(lang, po.setup.current())

        self.language.setModel(
            listmodel.ListModel(l, self.language, display=display))

        grid.addWidget(self.firstSystemLabel, 0, 0)
        grid.addWidget(self.firstSystem, 0, 1)
        grid.addWidget(self.otherSystemsLabel, 1, 0)
        grid.addWidget(self.otherSystems, 1, 1)
        grid.addWidget(self.languageLabel, 2, 0)
        grid.addWidget(self.language, 2, 1)
        app.translateUI(self)
        self.loadSettings()
        self.window().finished.connect(self.saveSettings)

    def translateUI(self):
        self.setTitle(_("Instrument names"))
        self.firstSystemLabel.setText(_("First system:"))
        self.otherSystemsLabel.setText(_("Other systems:"))
        self.languageLabel.setText(_("Language:"))
        self.firstSystem.setToolTip(
            _("Use long or short instrument names before the first system."))
        self.otherSystems.setToolTip(
            _("Use short, long or no instrument names before the next systems."
              ))
        self.language.setToolTip(
            _("Which language to use for the instrument names."))
        self.firstSystem.model().update()
        self.otherSystems.model().update()
        self.language.model().update()

    def getLanguage(self):
        """Returns the language the user has set.
        
        '' means:  default (use same translation as system)
        'C' means: English (untranslated)
        or a language code that is available in Frescobaldi's translation.
        
        """
        return self._langs[self.language.currentIndex()]

    def loadSettings(self):
        s = QSettings()
        s.beginGroup('scorewiz/instrumentnames')
        self.setChecked(s.value('enabled', True, bool))
        allow = ['long', 'short']
        first = s.value('first', '', type(""))
        self.firstSystem.setCurrentIndex(
            allow.index(first) if first in allow else 0)
        allow = ['long', 'short', 'none']
        other = s.value('other', '', type(""))
        self.otherSystems.setCurrentIndex(
            allow.index(other) if other in allow else 2)
        language = s.value('language', '', type(""))
        self.language.setCurrentIndex(
            self._langs.index(language) if language in self._langs else 0)

    def saveSettings(self):
        s = QSettings()
        s.beginGroup('scorewiz/instrumentnames')
        s.setValue('enable', self.isChecked())
        s.setValue('first', ('long', 'short')[self.firstSystem.currentIndex()])
        s.setValue('other',
                   ('long', 'short', 'none')[self.otherSystems.currentIndex()])
        s.setValue('language', self._langs[self.language.currentIndex()])
class OWImportImages(widget.OWWidget):
    name = "Import Images"
    description = "Import images from a directory(s)"
    icon = "icons/ImportImages.svg"
    priority = 110

    outputs = [("Data", Orange.data.Table)]

    #: list of recent paths
    recent_paths = settings.Setting([])  # type: List[RecentPath]
    currentPath = settings.Setting(None)

    want_main_area = False
    resizing_enabled = False

    Modality = Qt.ApplicationModal
    # Modality = Qt.WindowModal

    MaxRecentItems = 20

    def __init__(self):
        super().__init__()
        #: widget's runtime state
        self.__state = State.NoState
        self._imageMeta = []
        self._imageCategories = {}

        self.__invalidated = False
        self.__pendingTask = None

        vbox = gui.vBox(self.controlArea)
        hbox = gui.hBox(vbox)
        self.recent_cb = QComboBox(
            sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon,
            minimumContentsLength=16,
        )
        self.recent_cb.activated[int].connect(self.__onRecentActivated)
        icons = standard_icons(self)

        browseaction = QAction(
            "Open/Load Images", self,
            iconText="\N{HORIZONTAL ELLIPSIS}",
            icon=icons.dir_open_icon,
            toolTip="Select a directory from which to load the images"
        )
        browseaction.triggered.connect(self.__runOpenDialog)
        reloadaction = QAction(
            "Reload", self,
            icon=icons.reload_icon,
            toolTip="Reload current image set"
        )
        reloadaction.triggered.connect(self.reload)
        self.__actions = namespace(
            browse=browseaction,
            reload=reloadaction,
        )

        browsebutton = QPushButton(
            browseaction.iconText(),
            icon=browseaction.icon(),
            toolTip=browseaction.toolTip(),
            clicked=browseaction.trigger
        )
        reloadbutton = QPushButton(
            reloadaction.iconText(),
            icon=reloadaction.icon(),
            clicked=reloadaction.trigger,
            default=True,
        )

        hbox.layout().addWidget(self.recent_cb)
        hbox.layout().addWidget(browsebutton)
        hbox.layout().addWidget(reloadbutton)

        self.addActions([browseaction, reloadaction])

        reloadaction.changed.connect(
            lambda: reloadbutton.setEnabled(reloadaction.isEnabled())
        )
        box = gui.vBox(vbox, "Info")
        self.infostack = QStackedWidget()

        self.info_area = QLabel(
            text="No image set selected",
            wordWrap=True
        )
        self.progress_widget = QProgressBar(
            minimum=0, maximum=0
        )
        self.cancel_button = QPushButton(
            "Cancel", icon=icons.cancel_icon,
        )
        self.cancel_button.clicked.connect(self.cancel)

        w = QWidget()
        vlayout = QVBoxLayout()
        vlayout.setContentsMargins(0, 0, 0, 0)
        hlayout = QHBoxLayout()
        hlayout.setContentsMargins(0, 0, 0, 0)

        hlayout.addWidget(self.progress_widget)
        hlayout.addWidget(self.cancel_button)
        vlayout.addLayout(hlayout)

        self.pathlabel = TextLabel()
        self.pathlabel.setTextElideMode(Qt.ElideMiddle)
        self.pathlabel.setAttribute(Qt.WA_MacSmallSize)

        vlayout.addWidget(self.pathlabel)
        w.setLayout(vlayout)

        self.infostack.addWidget(self.info_area)
        self.infostack.addWidget(w)

        box.layout().addWidget(self.infostack)

        self.__initRecentItemsModel()
        self.__invalidated = True
        self.__executor = ThreadExecutor(self)

        QApplication.postEvent(self, QEvent(RuntimeEvent.Init))

    def __initRecentItemsModel(self):
        if self.currentPath is not None and \
                not os.path.isdir(self.currentPath):
            self.currentPath = None

        recent_paths = []
        for item in self.recent_paths:
            if os.path.isdir(item.abspath):
                recent_paths.append(item)
        recent_paths = recent_paths[:OWImportImages.MaxRecentItems]
        recent_model = self.recent_cb.model()
        for pathitem in recent_paths:
            item = RecentPath_asqstandarditem(pathitem)
            recent_model.appendRow(item)

        self.recent_paths = recent_paths

        if self.currentPath is not None and \
                os.path.isdir(self.currentPath) and self.recent_paths and \
                os.path.samefile(self.currentPath, self.recent_paths[0].abspath):
            self.recent_cb.setCurrentIndex(0)
        else:
            self.currentPath = None
            self.recent_cb.setCurrentIndex(-1)
        self.__actions.reload.setEnabled(self.currentPath is not None)

    def customEvent(self, event):
        """Reimplemented."""
        if event.type() == RuntimeEvent.Init:
            if self.__invalidated:
                try:
                    self.start()
                finally:
                    self.__invalidated = False

        super().customEvent(event)

    def __runOpenDialog(self):
        startdir = os.path.expanduser("~/")
        if self.recent_paths:
            startdir = self.recent_paths[0].abspath

        if OWImportImages.Modality == Qt.WindowModal:
            dlg = QFileDialog(
                self, "Select Top Level Directory", startdir,
                acceptMode=QFileDialog.AcceptOpen,
                modal=True,
            )
            dlg.setFileMode(QFileDialog.Directory)
            dlg.setOption(QFileDialog.ShowDirsOnly)
            dlg.setDirectory(startdir)
            dlg.setAttribute(Qt.WA_DeleteOnClose)

            @dlg.accepted.connect
            def on_accepted():
                dirpath = dlg.selectedFiles()
                if dirpath:
                    self.setCurrentPath(dirpath[0])
                    self.start()
            dlg.open()
        else:
            dirpath = QFileDialog.getExistingDirectory(
                self, "Select Top Level Directory", startdir
            )
            if dirpath:
                self.setCurrentPath(dirpath)
                self.start()

    def __onRecentActivated(self, index):
        item = self.recent_cb.itemData(index)
        if item is None:
            return
        assert isinstance(item, RecentPath)
        self.setCurrentPath(item.abspath)
        self.start()

    def __updateInfo(self):
        if self.__state == State.NoState:
            text = "No image set selected"
        elif self.__state == State.Processing:
            text = "Processing"
        elif self.__state == State.Done:
            nvalid = sum(imeta.isvalid for imeta in self._imageMeta)
            ncategories = len(self._imageCategories)
            if ncategories < 2:
                text = "{} images".format(nvalid)
            else:
                text = "{} images / {} categories".format(nvalid, ncategories)
        elif self.__state == State.Cancelled:
            text = "Cancelled"
        elif self.__state == State.Error:
            text = "Error state"
        else:
            assert False

        self.info_area.setText(text)

        if self.__state == State.Processing:
            self.infostack.setCurrentIndex(1)
        else:
            self.infostack.setCurrentIndex(0)

    def setCurrentPath(self, path):
        """
        Set the current root image path to path

        If the path does not exists or is not a directory the current path
        is left unchanged

        Parameters
        ----------
        path : str
            New root import path.

        Returns
        -------
        status : bool
            True if the current root import path was successfully
            changed to path.
        """
        if self.currentPath is not None and path is not None and \
                os.path.isdir(self.currentPath) and os.path.isdir(path) and \
                os.path.samefile(self.currentPath, path):
            return True

        if not os.path.exists(path):
            warnings.warn("'{}' does not exist".format(path), UserWarning)
            return False
        elif not os.path.isdir(path):
            warnings.warn("'{}' is not a directory".format(path), UserWarning)
            return False

        newindex = self.addRecentPath(path)
        self.recent_cb.setCurrentIndex(newindex)
        if newindex >= 0:
            self.currentPath = path
        else:
            self.currentPath = None
        self.__actions.reload.setEnabled(self.currentPath is not None)

        if self.__state == State.Processing:
            self.cancel()

        return True

    def addRecentPath(self, path):
        """
        Prepend a path entry to the list of recent paths

        If an entry with the same path already exists in the recent path
        list it is moved to the first place

        Parameters
        ----------
        path : str
        """
        existing = None
        for pathitem in self.recent_paths:
            if os.path.samefile(pathitem.abspath, path):
                existing = pathitem
                break

        model = self.recent_cb.model()

        if existing is not None:
            selected_index = self.recent_paths.index(existing)
            assert model.item(selected_index).data(Qt.UserRole) is existing
            self.recent_paths.remove(existing)
            row = model.takeRow(selected_index)
            self.recent_paths.insert(0, existing)
            model.insertRow(0, row)
        else:
            item = RecentPath(path, None, None)
            self.recent_paths.insert(0, item)
            model.insertRow(0, RecentPath_asqstandarditem(item))
        return 0

    def __setRuntimeState(self, state):
        assert state in State
        self.setBlocking(state == State.Processing)
        message = ""
        if state == State.Processing:
            assert self.__state in [State.Done,
                                    State.NoState,
                                    State.Error,
                                    State.Cancelled]
            message = "Processing"
        elif state == State.Done:
            assert self.__state == State.Processing
        elif state == State.Cancelled:
            assert self.__state == State.Processing
            message = "Cancelled"
        elif state == State.Error:
            message = "Error during processing"
        elif state == State.NoState:
            message = ""
        else:
            assert False

        self.__state = state

        if self.__state == State.Processing:
            self.infostack.setCurrentIndex(1)
        else:
            self.infostack.setCurrentIndex(0)

        self.setStatusMessage(message)
        self.__updateInfo()

    def reload(self):
        """
        Restart the image scan task
        """
        if self.__state == State.Processing:
            self.cancel()

        self._imageMeta = []
        self._imageCategories = {}
        self.start()

    def start(self):
        """
        Start/execute the image indexing operation
        """
        self.error()

        self.__invalidated = False
        if self.currentPath is None:
            return

        if self.__state == State.Processing:
            assert self.__pendingTask is not None
            log.info("Starting a new task while one is in progress. "
                     "Cancel the existing task (dir:'{}')"
                     .format(self.__pendingTask.startdir))
            self.cancel()

        startdir = self.currentPath

        self.__setRuntimeState(State.Processing)

        report_progress = methodinvoke(
            self, "__onReportProgress", (object,))

        task = ImageScan(startdir, report_progress=report_progress)

        # collect the task state in one convenient place
        self.__pendingTask = taskstate = namespace(
            task=task,
            startdir=startdir,
            future=None,
            watcher=None,
            cancelled=False,
            cancel=None,
        )

        def cancel():
            # Cancel the task and disconnect
            if taskstate.future.cancel():
                pass
            else:
                taskstate.task.cancelled = True
                taskstate.cancelled = True
                try:
                    taskstate.future.result(timeout=3)
                except UserInterruptError:
                    pass
                except TimeoutError:
                    log.info("The task did not stop in in a timely manner")
            taskstate.watcher.finished.disconnect(self.__onRunFinished)

        taskstate.cancel = cancel

        def run_image_scan_task_interupt():
            try:
                return task.run()
            except UserInterruptError:
                # Suppress interrupt errors, so they are not logged
                return

        taskstate.future = self.__executor.submit(run_image_scan_task_interupt)
        taskstate.watcher = FutureWatcher(taskstate.future)
        taskstate.watcher.finished.connect(self.__onRunFinished)

    @Slot()
    def __onRunFinished(self):
        assert QThread.currentThread() is self.thread()
        assert self.__state == State.Processing
        assert self.__pendingTask is not None
        assert self.sender() is self.__pendingTask.watcher
        assert self.__pendingTask.future.done()
        task = self.__pendingTask
        self.__pendingTask = None

        try:
            image_meta = task.future.result()
        except Exception as err:
            sys.excepthook(*sys.exc_info())
            state = State.Error
            image_meta = []
            self.error(traceback.format_exc())
        else:
            state = State.Done
            self.error()

        categories = {}

        for imeta in image_meta:
            # derive categories from the path relative to the starting dir
            dirname = os.path.dirname(imeta.path)
            relpath = os.path.relpath(dirname, task.startdir)
            categories[dirname] = relpath

        self._imageMeta = image_meta
        self._imageCategories = categories

        self.__setRuntimeState(state)
        self.commit()

    def cancel(self):
        """
        Cancel current pending task (if any).
        """
        if self.__state == State.Processing:
            assert self.__pendingTask is not None
            self.__pendingTask.cancel()
            self.__pendingTask = None
            self.__setRuntimeState(State.Cancelled)

    @Slot(object)
    def __onReportProgress(self, arg):
        # report on scan progress from a worker thread
        # arg must be a namespace(count: int, lastpath: str)
        assert QThread.currentThread() is self.thread()
        if self.__state == State.Processing:
            self.pathlabel.setText(prettyfypath(arg.lastpath))

    def commit(self):
        """
        Create and commit a Table from the collected image meta data.
        """
        if self._imageMeta:
            categories = self._imageCategories
            if len(categories) > 1:
                cat_var = Orange.data.DiscreteVariable(
                    "category", values=list(sorted(categories.values()))
                )
            else:
                cat_var = None
            # Image name (file basename without the extension)
            imagename_var = Orange.data.StringVariable("image name")
            # Full fs path
            image_var = Orange.data.StringVariable("image")
            image_var.attributes["type"] = "image"
            # file size/width/height
            size_var = Orange.data.ContinuousVariable(
                "size", number_of_decimals=0)
            width_var = Orange.data.ContinuousVariable(
                "width", number_of_decimals=0)
            height_var = Orange.data.ContinuousVariable(
                "height", number_of_decimals=0)
            domain = Orange.data.Domain(
                [], [cat_var] if cat_var is not None else [],
                [imagename_var, image_var, size_var, width_var, height_var]
            )
            cat_data = []
            meta_data = []

            for imgmeta in self._imageMeta:
                if imgmeta.isvalid:
                    if cat_var is not None:
                        category = categories.get(os.path.dirname(imgmeta.path))
                        cat_data.append([cat_var.to_val(category)])
                    else:
                        cat_data.append([])
                    basename = os.path.basename(imgmeta.path)
                    imgname, _ = os.path.splitext(basename)

                    meta_data.append(
                        [imgname, imgmeta.path, imgmeta.size,
                         imgmeta.width, imgmeta.height]
                    )

            cat_data = numpy.array(cat_data, dtype=float)
            meta_data = numpy.array(meta_data, dtype=object)
            table = Orange.data.Table.from_numpy(
                domain, numpy.empty((len(cat_data), 0), dtype=float),
                cat_data, meta_data
            )
        else:
            table = None

        self.send("Data", table)

    def onDeleteWidget(self):
        self.cancel()
        self.__executor.shutdown(wait=True)
Exemplo n.º 11
0
class QuestionDlg(QDialog):
    def __init__(self, parent=None):
        super(QuestionDlg,self).__init__(parent)
        # self.setStyleSheet("background-image:url('image/panelbg.jpg'); border: 2px; border-radius 2px;")
        # self.createDb()
        # return

        self.db = QSqlDatabase.addDatabase("QSQLITE");  
        self.db.setDatabaseName("studentNew.db")
        if not self.db.open():
            QMessageBox.warning(None, "错误",  "数据库连接失败: %s" % self.db.lastError().text())
            sys.exit(1)

        self.g_curClassName = ""
        self.deleteTmpdata()

        self.setWindowFlags(Qt.CustomizeWindowHint)
        # self.setStyleSheet("border: 2px; border-radius 2px;")
        # self.setWindowFlags(Qt.FramelessWindowHint)
        self.setStyleSheet("background-color: rgba(132, 171, 208, 200);")

        self.tabWidget=QTabWidget(self)
        self.tabWidget.currentChanged.connect(self.changeTab)
        # tabWidget.setTabShape(QTabWidget.Triangular)
        self.tabWidget.setStyleSheet("QTabWidget::pane{border-width:1px;border-color:rgb(48, 104, 151);\
            border-style: outset;background-color: rgb(132, 171, 208);\
            background: transparent;} \
            QTabWidget::tab-bar{border-width:0px;}\
            QTabBar::tab { height: 60px; width: 260px; color:rgb(0, 0, 255); font-size:20px; font-weight:bold;} \
            QTabBar::tab:hover{background:rgb(255,255, 255, 100);} \
            QTabBar::tab:selected{border-color:green;background-color:white;color:green;}")
        # tabWidget.setStyleSheet("QTabBar::tab:hover{background:rgb(255,255, 255, 100);}")
        self.btngroup = QButtonGroup()
        self.popMenu = QMenu(self)
        entry1 = self.popMenu.addAction("正确")
        self.connect(entry1,SIGNAL('triggered()'), lambda : self.answerRight())
        entry2 = self.popMenu.addAction("错误")
        self.connect(entry2,SIGNAL('triggered()'), lambda : self.answerWrong())
        entry3 = self.popMenu.addAction("替换")
        self.connect(entry3,SIGNAL('triggered()'), lambda : self.resetStudent())

        # Create the first tab page.
        self.w1=QWidget()
        self.w1.setAccessibleName("w1tab")
        self.genOneTab()
        
        # Create the second tab page.
        self.w2=QWidget()
        self.w2.setAccessibleName("w2tab")        
        self.genTwoTab()

        self.tabWidget.addTab(self.w1,"")
        self.tabWidget.addTab(self.w2,"班级学生信息管理")
        self.tabWidget.resize(940,700)

        btnclose = QPushButton(self)
        btnclose.setToolTip("关闭")
        btnclose.setText("╳")
        btnclose.setGeometry(915, 5, 20, 20)
        btnclose.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255)")
        btnclose.clicked.connect(self.close)
        btnMinimized = QPushButton(self)
        btnMinimized.setToolTip("最小化")
        btnMinimized.setText("▁")
        btnMinimized.setGeometry(890, 5, 20, 20)
        btnMinimized.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255)")
        btnMinimized.clicked.connect(lambda: self.showMinimized())
        self.btnSysMenu = QPushButton(self)
        # self.btnSysMenu.setText("▼")
        self.btnSysMenu.setGeometry(865, 5, 20, 20)
        self.btnSysMenu.setToolTip("系统设置")
        self.btnSysMenu.clicked.connect(lambda: self.showMinimized())
        menufont = QFont("宋体", 10)
        popMenu = QMenu(self)
        entry1 = popMenu.addAction("所有学生提问信息清零")
        entry1.setFont(menufont)
        self.connect(entry1,SIGNAL('triggered()'), self.initStudent)
        entry2 = popMenu.addAction("清除本堂课提问人员")
        entry2.setFont(menufont)
        self.connect(entry2,SIGNAL('triggered()'), self.deleteTmpdata)
        entry3 = popMenu.addAction("关于...")
        entry3.setFont(menufont)
        self.connect(entry3,SIGNAL('triggered()'), self.aboutMe)
        entry4 = popMenu.addAction("导出...")
        entry4.setFont(menufont)
        self.connect(entry4,SIGNAL('triggered()'), self.exportNotice)

        self.btnSysMenu.setMenu(popMenu)
        self.btnSysMenu.setStyleSheet("QPushButton::menu-indicator {image: url('image/sysmenu.png');subcontrol-position: right center;} ")
        # self.btnSysMenu.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255);")

        authorinfo = QLabel(self.tabWidget)
        # authorinfo.setToolTip("关闭")
        authorinfo.setText("程序设计:汕头市大华路第一小学 赵小娜,有任何问题请反馈至[email protected]。")
        authorinfo.setGeometry(20, 665, 470, 26)
        authorinfo.setFont(QFont('Courier New'))
        authorinfo.setStyleSheet("background-color:rgba(255, 255, 255,160); font-size:12px;border: 1px solid rgb(60,200,255,200);color:rgba(0,0,0,220);border-radius:12px;")

        self.setWindowTitle("课堂随机提问")
        self.setWindowIcon(QIcon("image/start.ico"))
        self.setGeometry(100, 20, 940, 700)

        # self.changeTab()

        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2)

        self.btn_start.setMyarg('start')
        
        # print(self.btn_start.getMyarg())

        self.connect(self.btn_start, SIGNAL("clicked()"), self.startChoice)
        # self.connect(self.w1title, SIGNAL("currentIndexChanged(int)"), self.changeTitle)
        # self.connect(self.btn_start2, SIGNAL("clicked()"), self.startChoice)
        # self.connect(self.w2title, SIGNAL("currentIndexChanged(int)"), self.changeTitle)
        self.btngroup.buttonClicked[int].connect(self.btns_click)
        # self.connect(self.btn_start,  SIGNAL("myslot(PyQt_PyObject)"), self.myslot)  
        # self.connect(self.btngroup, SIGNAL("buttonClicked(int)"), lambda:self.btns_click())

    def myslot(self, text):  
        # print(text, self.dict_choices)
        self.g_curbtn = text
        if self.g_curbtn not in self.dict_choices:
            self.btnSysMenu.setFocus()
            return

        # print(self.btngroup.button(int(self.g_curbtn)).parent())
        # print(type(self.btngroup.button(int(self.g_curbtn)).parentWidget()))
        pos = self.btngroup.button(int(self.g_curbtn)).parent().mapToGlobal(self.btngroup.button(int(self.g_curbtn)).pos())
        width = self.btngroup.button(int(self.g_curbtn)).rect().height()
        # print("-----", pos, width)
        pos.setY(pos.y()+width-5)

        indx = 0
        for istate in self.dict_choices[self.g_curbtn]:
            if istate == '1':
                self.popMenu.actions()[indx].setEnabled(True)
            elif istate == '0':
                self.popMenu.actions()[indx].setEnabled(False)
            indx += 1
        self.popMenu.exec_(pos)
        self.btnSysMenu.setFocus()
    # def on_context_menu(self, point):
    #     print(point)
    #     self.popMenu.exec_(self.button.mapToGlobal(point)) 

    def btns_click(self, btnid):
        # curclassname = self.tabWidget.tabText(0)
        query = QSqlQuery(self.db)
        # cur = conn.cursor()
        today = datetime.date.today()
        self.g_curbtn = str(btnid).zfill(2)
        if self.g_curbtn not in self.dict_choices:
            self.btngroup.button(int(self.g_curbtn)).setStyleSheet(stylesheetstr_new)
            query.exec_("select count(*) from tmprecord where stusn='" + str(self.g_curbtn) + "'")
            query.next()            
            if query.value(0) == 0:
                query.prepare("insert into tmprecord (classname, stusn, datequestion) values (:classname, :stusn, :datequestion)")
                query.bindValue(":classname", self.g_curClassName)
                query.bindValue(":stusn", self.g_curbtn)
                query.bindValue(":datequestion", today)
                query.exec_() 
                
            self.dict_choices[self.g_curbtn] = "111"
        else:
            self.btngroup.button(int(self.g_curbtn)).setStyleSheet(stylesheetstr_old)
            self.btngroup.button(int(self.g_curbtn)).setIcon(QIcon())            
            query.exec_("delete from tmprecord where stusn='"+ str(self.g_curbtn) + "'")            
            self.dict_choices.pop(self.g_curbtn)

        self.btnSysMenu.setFocus()

    def exportNotice(self):
        query = QSqlQuery(self.db)
        query.exec_("select stusn, stuname, classname, rightquestions, wrongquestions from student" ) 
        lstInfo = [["学号","姓名", "班级", "回答正确次数", "回答错误次数"]]
        while(query.next()):
            lstInfo.append([query.value(0),query.value(1),query.value(2),query.value(3),query.value(4)])

        from xlwt import Workbook,easyxf
        book = Workbook(encoding='ascii')
            # 'pattern: pattern solid,  fore_colour white;'
        style = easyxf(
            'font: height 280, name 黑体;'
            'align: vertical center, horizontal center;'
            )
        style2 = easyxf('font: height 260, name 仿宋_GB2312, bold True; align: vertical center, horizontal left;')
        style3 = easyxf('font: height 260, name 仿宋_GB2312, bold True; align: vertical center, horizontal left, wrap True;')

        sheet1 = book.add_sheet('学生提问情况汇总',cell_overwrite_ok=True)
        # sheet1.write(0,7,flagtxt, easyxf('font: height 200, name 黑体;align: vertical center, horizontal right;'))
        sheet1.write_merge(0,0,0,4, '学生提问情况汇总表',style)
        sheet1.row(0).height_mismatch = 1
        sheet1.row(0).height = 5*256

        sheet1.col(0).width = 10*256
        sheet1.col(1).width = 25*256
        sheet1.col(2).width = 25*256
        sheet1.col(3).width = 20*256
        sheet1.col(4).width = 20*256
        
        tmprows = 1
        for item in lstInfo:
            stusn               = item[0]
            stuname             = item[1]
            classname           = item[2]
            rightquestions      = item[3]
            wrongquestions      = item[4]

            sheet1.write(tmprows,0,stusn, style2)
            sheet1.write(tmprows,1,stuname, style2)
            sheet1.write(tmprows,2,classname, style2)
            sheet1.write(tmprows,3,rightquestions, style2)
            sheet1.write(tmprows,4,wrongquestions, style2)
            tmprows += 1
        # print(tmprows)
        sheet1.header_str = "".encode()
        sheet1.footer_str = "".encode()

        # book.save('d:/simple.xls')
        # print(QDir.home().dirName() , QDir.homePath ())
        filename = QDir.homePath () + "\学生提问情况汇总表.xls" 
        try:
            book.save(filename)
        except  Exception as e:
            QMessageBox.warning(self, "写入错误", "错误号:"+str(e.errno)+"\n错误描述:"+e.strerror+"\n请关闭已经打开的%s文档!" % filename)
        QMessageBox.about (self, "导出成功", "请查看文档:%s" % filename)

    def aboutMe(self):
        strinfo = """本软件采用python3.4编写,界面采用qt4.8的python绑定。
                    \n版本所有:汕头市大华路第一小学赵小娜老师。
                    \n有任何问题请反馈至[email protected]。
                    """
        QMessageBox.information(None, "关于", strinfo)
        
    def initStudent(self):
        query = QSqlQuery(self.db)
        ret = query.exec_("update student set wrongquestions=0") 
        ret = query.exec_("update student set rightquestions=0")  
        QMessageBox.information(None, "提示", "已清除所有学生的累计提问情况。")


    def deleteTmpdata(self):
        query = QSqlQuery(self.db)
        ret = query.exec_("delete from tmprecord where 1=1" )   
        if self.g_curClassName != "":     
            QMessageBox.information(None, "提示", "已清除本次软件启动后的所有已提问过的学生。")
  
    def changeTab(self):
        # pass
        curtab = self.tabWidget.currentIndex()
        # print(curtab, "-")
        if curtab == 1:  ## when click the second tab page ,then pass.
            return
            
        # cur = conn.cursor()
        query = QSqlQuery(self.db)

        ## if current classname is null, then set current tabpage display the first class of classtable
        if self.g_curClassName == "":
            ret = query.exec_("select classname from classtable")
            query.next()
            self.g_curClassName = query.value(0)
            
        self.tabWidget.setTabText(0, self.g_curClassName)
        # print(1)
        strwhere = " and classname like '" + self.g_curClassName + "' ORDER BY stusn"

        self.g_curbtn = ""
        self.dict_choices = {}
        self.studentSnlst = []

        ## clearn the question data of temp record .
        ret= query.exec_("delete from tmprecord where 1=1")
        ret = query.exec_("select stusn, stuname from student where 1=1 " + strwhere)

        ## now update the global data "self.btngroup"
        for indx in range(0, 56):
            self.btngroup.button(indx+1).setText("")
            self.btngroup.button(indx+1).setMyarg(None)       
            self.btngroup.button(indx+1).setStyleSheet(stylesheetstr_old)
            self.btngroup.button(indx+1).setIcon(QIcon())
            self.btngroup.button(indx+1).setEnabled(False)
            self.studentSnlst.append([indx+1,])

        inum = 0
        while (query.next()): 
            inum += 1            
            self.btngroup.button(inum).setText(query.value(1))
            self.btngroup.button(inum).setMyarg(query.value(0))       
            self.btngroup.button(inum).setStyleSheet(stylesheetstr_old)
            self.btngroup.button(inum).setIcon(QIcon())
            self.btngroup.button(inum).setEnabled(True)

        # print(inum, len(self.btngroup.buttons()))        

        self.group_animation = groupAnimation(self.studentSnlst, self.btngroup)

    def mousePressEvent(self, event):
        # print('a')
        if event.button() == Qt.RightButton:
            QDialog.mousePressEvent(self,event)
            return
        # print(event.sender(), event.button())
        self.offset = event.pos()
        # print(self.offset)

    def mouseMoveEvent(self, event):
        # print('sss')
        if hasattr(self, 'offset'):
            x=event.globalX()
            y=event.globalY()
            x_w = self.offset.x()
            y_w = self.offset.y()
            self.move(x-x_w, y-y_w)
        else:
            pass

    #######======= studentModel ============###############
    def newStudent(self):
        # Calc the missing number:
        row = self.StudentModel.rowCount()

        if row > 0:
            oldNumList = []
            for i in range(0, row):
                oldNumList.append(int(self.StudentModel.index(i,2).data()))
            
            allNumberList = list(range(1, oldNumList[-1]+1))
            for i in range(0, allNumberList[-1]):
                if oldNumList[i] != allNumberList[i]:
                    missingNum = allNumberList[i]
                    break
            if len(oldNumList) == len(allNumberList):
                missingNum = allNumberList[i] +1
        else:
            missingNum = 1

        self.StudentModel.insertRow(row)
        self.StudentView.scrollToBottom()
        self.StudentModel.setData(self.StudentModel.index(row, 1), self.g_curClassName)
        self.StudentModel.setData(self.StudentModel.index(row, 2), str(missingNum).zfill(2))
        self.StudentModel.setData(self.StudentModel.index(row, 4), 0)
        self.StudentModel.setData(self.StudentModel.index(row, 5), 0)

    def removeStudent(self):
        index = self.StudentView.currentIndex()
        row = index.row()             
        if QMessageBox.question(self, "删除确认", "是否要删除当前选中记录?", "确定", "取消") == 0:
            self.StudentModel.removeRows(row, 1)
            self.StudentModel.submitAll()
            self.StudentModel.database().commit()

    def revertStudent(self):
        self.StudentModel.revertAll()
        self.StudentModel.database().rollback()

    def saveStudent(self):
        self.StudentModel.database().transaction()
        if self.StudentModel.submitAll():
            self.StudentModel.database().commit()
            # print("save success!  ->commit")
        else:
            self.StudentModel.revertAll()
            self.StudentModel.database().rollback()

    #######======= classModel ============###############
    def newClass(self):
        row = self.ClassnameModel.rowCount()
        self.ClassnameModel.insertRow(row)

    def removeClass(self):
        index = self.ClassnameView.currentIndex()
        row = index.row()   
        curClassname =  index.sibling(index.row(),0).data()
        strwhere = "classname like '" + curClassname + "'"
        self.StudentModel.setFilter(strwhere)
        self.StudentModel.select()
        # print(self.StudentModel.rowCount(), "----", )
        if QMessageBox.question(self, "删除确认", "删除班级意味着会删除本班所有人员信息。是否要删除当前选中记录?", "确定", "取消") == 0:
            self.ClassnameModel.removeRows(row, 1)
            self.ClassnameModel.submitAll()
            self.ClassnameModel.database().commit()

            self.StudentModel.removeRows(0, self.StudentModel.rowCount())
            self.StudentModel.submitAll()
            self.StudentModel.database().commit()

    def revertClass(self):
        self.ClassnameModel.revertAll()
        self.ClassnameModel.database().rollback()

    def saveClass(self):
        query = QSqlQuery(self.db)

        # record the old class name
        lstOldClassName = {}
        lstOldClassid = []
        query.exec_("select rowid, classname from classtable" )        
        while(query.next()):
            lstOldClassName[query.value(0)] = query.value(1)
            lstOldClassid.append(query.value(0))
        # print(lstOldClassName)

        # Update the class Table
        self.ClassnameModel.database().transaction()
        if self.ClassnameModel.submitAll():
            self.ClassnameModel.database().commit()
            # print("save success!  ->commit")
        else:
            QMessageBox.warning(None, "错误",  "请检查班级中名称,不能出现同名班级!")
            self.ClassnameModel.revertAll()
            self.ClassnameModel.database().rollback()

        # print(lstOldClassid)

        lstNewClassName = {}
        query.exec_("select rowid, classname from classtable where rowid in " + str(tuple(lstOldClassid)) )        
        while(query.next()):
            lstNewClassName[query.value(0)] = query.value(1)            

        # print(lstOldClassName, '=========')
        # print(lstNewClassName, '~~~~~~~~~')

        for i in lstOldClassName:
            oldclassname = lstOldClassName[i]
            newclassname = lstNewClassName[i]
            if oldclassname != newclassname:
                # print(oldclassname, newclassname, '++++++++')
                # print("update student set classname=" + newclassname + " where classname='" + oldclassname + "'")
                query.exec_("update student set classname='" + newclassname + "' where classname='" + oldclassname + "'")
                self.StudentModel.setFilter("classname = '" + newclassname + "'")
                self.StudentModel.select()

        lstClassName = []      
        query.exec_("select classname from classtable" ) 
        while(query.next()):
            lstClassName.append(query.value(0))
        self.StudentView.setItemDelegateForColumn(1,  ComboBoxDelegate(self, lstClassName, self.db))

    def dbclick(self, indx):
        if type(indx.sibling(indx.row(),0).data()) != QPyNullVariant:
            classname = indx.sibling(indx.row(),0).data()
            
            strwhere = "classname like '" + classname + "'"
            self.StudentModel.setFilter(strwhere)
            self.StudentModel.setSort(2, Qt.AscendingOrder)
            self.StudentModel.select()
            
            self.g_curClassName = classname
            self.tabWidget.setTabText(0, self.g_curClassName)

    def dbclick2(self, indx):
        if indx.column() == 2:
            self.StudentView.setEditTriggers(QAbstractItemView.NoEditTriggers)
        else:
            self.StudentView.setEditTriggers(QAbstractItemView.DoubleClicked)
        

    def genTwoTab(self, tabtitle=""):
        # Create the tab title sytle.
        tabtitle = QLabel()
        tabtitle.setFont(QFont('Courier New', 20))
        tabtitle.setText("班级学生信息管理")
        tabtitle.setStyleSheet("border: 1px solid blue; color:rgba(0,0,255, 220);\
            background-color:rgba(201,201,201,60);\
            border-radius: 6px; \
            padding: 1px 18px 1px 20px;\
            min-width: 8em;")
        tabtitle.setMinimumHeight(50);
        titleLayout = QHBoxLayout()
        titleLayout.addWidget(tabtitle)
        titleLayout.setAlignment(tabtitle, Qt.AlignCenter)

       
        # Create the classnameView
        self.ClassnameView = QTableView()
        self.ClassnameModel = QSqlTableModel(self.ClassnameView)
        self.ClassnameModel.setTable("classtable")
        # self.ClassnameModel.setRelation(2, QSqlRelation("mentalmodel", "id", "name"));
        self.ClassnameModel.setEditStrategy(QSqlTableModel.OnManualSubmit)
        self.ClassnameModel.select()

        self.ClassnameModel.setHeaderData(0, Qt.Horizontal, "班级名称")

        # for indx, iheader in enumerate(["classid", "classname"]):
        #     self.ClassnameModel.setHeaderData(indx+1, Qt.Horizontal, iheader)
    
        self.ClassnameView.setModel(self.ClassnameModel)
        # self.ClassnameView.setColumnHidden(0, True)
        # self.ClassnameView.show()
        self.ClassnameView.verticalHeader().setFixedWidth(30)
        self.ClassnameView.verticalHeader().setStyleSheet("color: red;font-size:20px; ");
        self.ClassnameView.setStyleSheet("QTableView{background-color: rgb(250, 250, 200, 0);"  
                    "alternate-background-color: rgb(141, 163, 0);}"
                    "QTableView::item:hover {background-color: rgba(100,200,220,100);} ") 
        self.ClassnameView.setStyleSheet("font-size:16px; ");
        self.ClassnameView.setSelectionMode(QAbstractItemView.SingleSelection)
        # self.ClassnameView.dataChanged.connect(self.dataChanged)

        # self.ClassnameView.setSizePolicy(QSizePolicy.Expanding,     QSizePolicy.Expanding)

        # the second list
        self.StudentView = QTableView()
        self.StudentModel = QSqlTableModel(self.StudentView)
        self.StudentModel.setTable("student")
        # self.StudentModel.setRelation(2, QSqlRelation("mentalmodel", "id", "name"));
        self.StudentModel.setEditStrategy(QSqlTableModel.OnManualSubmit)
        # self.StudentModel.select()

        query = QSqlQuery(self.db)
        strwhere = " 1=1 "
        if self.g_curClassName == "":
            ret = query.exec_("select classname from classtable")
            query.next()
            firstClassName = query.value(0)
            strwhere += " and classname like '" + firstClassName + "'"
            
        self.StudentModel.setFilter(strwhere)
        self.StudentModel.select()

        for indx, iheader in enumerate(["班级名称", "学生编号", "学生姓名", "答对次数", "答错次数"]):
            self.StudentModel.setHeaderData(indx+1, Qt.Horizontal, iheader)
    
        self.StudentView.setModel(self.StudentModel)
        self.StudentView.setColumnHidden(0, True)

        # query = QSqlQuery(self.db)  
        lstClassName = []      
        query.exec_("select classname from classtable" ) 
        while(query.next()):
            lstClassName.append(query.value(0))

        self.StudentView.setItemDelegateForColumn(1,  ComboBoxDelegate(self, lstClassName, self.db))
        # self.StudentView.show()
        self.StudentView.verticalHeader().setFixedWidth(30)
        self.StudentView.verticalHeader().setStyleSheet("color: red;font-size:20px; background-color: rgb(250, 250, 200, 100)");
        self.StudentView.setStyleSheet("QTableView{background-color: rgb(250, 250, 200, 0);"  
                    "alternate-background-color: rgb(141, 163, 250);}"
                    "QTableView::item:hover {background-color: rgba(10,200,100,200);} "
                    ) 
        self.StudentView.setStyleSheet("font-size:16px;")
        self.StudentView.setSelectionMode(QAbstractItemView.SingleSelection)
        self.StudentView.doubleClicked.connect(self.dbclick2)

        btn_lst1_layout = QGridLayout()
        newusrbtn       = QPushButton("新增")
        savebtn         = QPushButton("保存")
        revertbtn       = QPushButton("撤销")
        removebtn       = QPushButton("删除")
        btn_lst1_layout.addWidget(newusrbtn, 0, 0)
        btn_lst1_layout.addWidget(savebtn, 0, 1)
        btn_lst1_layout.addWidget(revertbtn, 1, 0)
        btn_lst1_layout.addWidget(removebtn, 1, 1)

        newusrbtn.clicked.connect(self.newClass)
        savebtn.clicked.connect(self.saveClass)
        revertbtn.clicked.connect(self.revertClass)
        removebtn.clicked.connect(self.removeClass)

        self.ClassnameView.doubleClicked.connect(self.dbclick)
        

        btnbox2 = QDialogButtonBox(Qt.Horizontal)
        newusrbtn2       = QPushButton("新增")
        savebtn2         = QPushButton("保存")
        revertbtn2       = QPushButton("撤销")
        removebtn2       = QPushButton("删除")
        btnbox2.addButton(newusrbtn2, QDialogButtonBox.ActionRole);
        btnbox2.addButton(savebtn2, QDialogButtonBox.ActionRole);
        btnbox2.addButton(revertbtn2, QDialogButtonBox.ActionRole);
        btnbox2.addButton(removebtn2, QDialogButtonBox.ActionRole);

        newusrbtn2.clicked.connect(self.newStudent)
        savebtn2.clicked.connect(self.saveStudent)
        revertbtn2.clicked.connect(self.revertStudent)
        removebtn2.clicked.connect(self.removeStudent)

        # left list layout
        lst_layout_1 = QVBoxLayout()
        lst_layout_1.addWidget(self.ClassnameView)
        lst_layout_1.addLayout(btn_lst1_layout)

        lst_layout_2 = QVBoxLayout()
        lst_layout_2.addWidget(self.StudentView)
        lst_layout_2.addWidget(btnbox2)
        
        lstlayout = QHBoxLayout()
        lstlayout.setMargin(5)
        # lstlayout.addLayout(findbox)
        lstlayout.addLayout(lst_layout_1, 2)
        lstlayout.setMargin(5)
        lstlayout.addLayout(lst_layout_2, 5)
            
        labelClass = QLabel("")
        labelClass.setStyleSheet("background-color:rgba(255, 255, 255,0); color:rgba(0,0,0,0);")
        labelClass.setFixedHeight(40)
        # labelClass.setFixedWidth(100)
        # labelClass.setFont(QFont('宋体', 10))

        bottomlayout = QHBoxLayout()        
        bottomlayout.addWidget(labelClass)        

        tab2layout = QVBoxLayout()
        tab2layout.addLayout(titleLayout)       
        tab2layout.addLayout(lstlayout)
        tab2layout.addLayout(bottomlayout)
        self.w2.setLayout(tab2layout)
        self.w2.setStyleSheet("background-color: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 1 #228888);")
      
    def genOneTab(self):

        tabtitle = QLabel()
        # tabtitle.setFixedHeight(40)
        # tabtitle.setFixedWidth(160)        
        self.btn_start = MyButton("开始")
        self.choicenum_text = QComboBox()
        self.choicenum_text.setObjectName('w1combonums')
        # self.w1title.setStyleSheet("background-image:url('image/panelbg.jpg');")
        
        # Set the title style                
        tabtitle.setFont(QFont('Courier New', 20))
        tabtitle.setText("随堂提问演板")
        tabtitle.setStyleSheet("border: 1px solid blue; color:rgba(0,0,255, 220);\
            background-color:rgba(201,201,201,60);\
            border-radius: 6px; \
            padding: 1px 18px 1px 20px;\
            min-width: 8em;")
        tabtitle.setMinimumHeight(50);
        titleLayout = QHBoxLayout()
        titleLayout.addWidget(tabtitle)
        titleLayout.setAlignment(tabtitle, Qt.AlignCenter)
       
        btnlayout = QGridLayout()
        tmpnum = 0
        for inum in range(0,56):
            irow = tmpnum // g_cols
            icol = tmpnum % g_cols
            tmpnum += 1
            btnlayout.setRowMinimumHeight(irow, 80)
            tmpbtn = MyButton("")
            tmpbtn.setMyarg(None)
            # tmpbtn.setFixedHeight(20)
            tmpbtn.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding))
            tmpbtn.setStyleSheet("border: 1px solid rgb(55,55,255,100);background-color: rgba(255,255,255,20);font-size:16px;")
            self.connect(tmpbtn,  SIGNAL("myslot(PyQt_PyObject)"), self.myslot)
            tmpbtn.setAutoDefault(False)
            self.btngroup.addButton(tmpbtn, inum+1) # stusn is from 1 start

            btnlayout.addWidget(tmpbtn, irow, icol)


        self.btn_start.setIcon(QIcon("image/start.png"))
        self.btn_start.setStyleSheet("border: 1px solid yellow;")
        self.btn_start.setFixedHeight(40)
        self.btn_start.setFixedWidth(100)
        self.btn_start.setFont(QFont('宋体', 18))
        # self.choicenum_text.setFixedHeight(45)
        # self.choicenum_text.setFixedWidth(60)

        ## Set the combox number style
        self.choicenum_text.setFont(QFont('Courier New', 20))
        self.choicenum_text.setFixedHeight(45)
        self.choicenum_text.setStyleSheet("border: 2px solid blue; color:red;font-weight:light;font-size:26px;\
            border-radius: 6px; \
            min-width: 2em; ")
        self.choicenum_text.setEditable(True)
        self.choicenum_text.lineEdit().setReadOnly(True);
        self.choicenum_text.lineEdit().setAlignment(Qt.AlignCenter);

        model = self.choicenum_text.model()
        for row in list(range(1, 7)):
            item = QStandardItem(str(row))
            item.setTextAlignment(Qt.AlignCenter)
            item.setForeground(QColor('red'))
            item.setBackground(QColor(0,200,50, 130))
            model.appendRow(item)
        self.choicenum_text.setCurrentIndex(2)
        # self.choicenum_text.setStyleSheet ("QComboBox::drop-down {border-width: 100px;}")
        # self.choicenum_text.setStyleSheet ("QComboBox::down-arrow {image: url(image/downarrow.png);top: 10px;left: 1px;}")

        bottomlayout = QHBoxLayout()
        bottomlayout.setSizeConstraint(QLayout.SetFixedSize)
        bottomlayout.addStretch(10)
        bottomlayout.addWidget(self.btn_start)
        bottomlayout.setSpacing(5)
        bottomlayout.addWidget(self.choicenum_text)

        tab1layout = QVBoxLayout()
        tab1layout.addLayout(titleLayout)       
        tab1layout.addLayout(btnlayout)
        tab1layout.addLayout(bottomlayout)
                
        self.w1.setLayout(tab1layout)
        self.w1.setStyleSheet("background-color: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 1 #228888);")
         
    def startChoice(self, usernum="", oldbtn=""): 
        # print(oldbtn, 1)

        if oldbtn == "":
            self.dict_choices = {}

        strwhere = " and classname like '" + self.g_curClassName + "'"

        allstudent = []
        lstrecord = []
        query = QSqlQuery(self.db)        
        query.exec_("select stusn from tmprecord where 1=1 " + strwhere) 
        while(query.next()):
            lstrecord.append(query.value(0))
        # print(lstrecord, 'record', "select stusn from student where stusn not in " + str(tuple(lstrecord)))

        query.exec_("select stusn from student where stusn not in " + str(tuple(lstrecord)) + strwhere)
        while(query.next()):
            allstudent.append(query.value(0))

        if usernum == "":
            nums = int(self.choicenum_text.currentText())
        else:
            nums = usernum
        if nums >= len(allstudent):
            query.exec_("delete from tmprecord where 1=1 " + strwhere) #delete tmp date no today            
            allstudent = []
            query.exec_("select stusn from student where 1=1 " + strwhere)
            while(query.next()):
                allstudent.append(query.value(0))
        
        if oldbtn == "":
            random.seed()
            lstchoices = random.sample(allstudent, nums)
            for ibtn in lstchoices:
                self.dict_choices[ibtn] = "111"

            self.group_animation.start()
            QTimer.singleShot(1200, self.stopmovie)
        else:
            random.seed()
            otherbtn = random.sample(allstudent, 1)[0]
            # self.btngroup.button(int(otherbtn)).setFocus()
            self.dict_choices.pop(oldbtn)
            self.dict_choices[otherbtn] = '111'
            self.stopmovie()
        self.btnSysMenu.setFocus()

    def stopmovie(self):
        self.group_animation.stop()
        for isn in self.studentSnlst:
            # print(isn)
            self.btngroup.button(int(isn[0])).setStyleSheet(stylesheetstr_old)
            self.btngroup.button(int(isn[0])).setIcon(QIcon())
        
        classname = self.tabWidget.tabText(0)
        query = QSqlQuery(self.db)        
        today = datetime.date.today()
        for ibtn in self.dict_choices:
            self.btngroup.button(int(ibtn)).setStyleSheet(stylesheetstr_new)
            query.exec_("select count(*) from tmprecord where stusn='" + str(ibtn) + "'")
            query.next()
            if query.value(0) == 0:               
                query.prepare("insert into tmprecord (classname, stusn, datequestion) values (:classname, :stusn, :datequestion)")
                query.bindValue(":classname", classname)
                query.bindValue(":stusn", ibtn)
                query.bindValue(":datequestion", today)
                query.exec_()
    
    def answerRight(self):
        # print(self.g_curbtn)
        value = self.g_curbtn
        if value not in self.dict_choices:
            return

        self.btngroup.button(int(value)).setIcon(QIcon("image/smile.png"))
        self.btngroup.button(int(value)).setIconSize(QSize(20,20))
        
        query = QSqlQuery(self.db)
        query.exec_("select rightquestions from student where stusn='" + value + "'")
        query.next()
        studentRightQuestions = query.value(0) + 1
        query.exec_("update student set rightquestions=" + str(studentRightQuestions) + " where stusn='" + value + "'")
                
        ###########
        if self.dict_choices[value] == "101":
            query.exec_("select wrongquestions from student where stusn='" + value + "'")
            query.next()
            studentWrongQuestions = query.value(0) - 1
            query.exec_("update student set wrongquestions=" + str(studentWrongQuestions) + " where stusn='" + value + "'")
            
        self.dict_choices[value] = "011"

    def answerWrong(self):
        value = self.g_curbtn
        if value not in self.dict_choices:
            return

        self.btngroup.button(int(value)).setIcon(QIcon("image/cry.png"))
        self.btngroup.button(int(value)).setIconSize(QSize(20,20))
        # self.btngroup.button(int(value)).setStyleSheet("border-image: url(image/ex_stu.png);")
        
        query = QSqlQuery(self.db)
        query.exec_("select wrongquestions from student where stusn='" + value + "'")
        query.next()
        studentWrongQuestions = query.value(0) + 1
        query.exec_("update student set wrongquestions=" + str(studentWrongQuestions) + " where stusn='" + value + "'")
        
        if self.dict_choices[value] == "011":
            query.exec_("select rightquestions from student where stusn='" + value + "'")
            query.next()
            studentRightQuestions = query.value(0) - 1
            query.exec_("update student set rightquestions=" + str(studentRightQuestions) + " where stusn='" + value + "'")
            
        self.dict_choices[value] = "101"

    def resetStudent(self):
        value = self.g_curbtn
        if value not in self.dict_choices:
            return

        query = QSqlQuery(self.db)

        if self.dict_choices[value] == "011":        
            query.exec_("select rightquestions from student where stusn='" + value + "'")
            query.next()
            studentRightQuestions = query.value(0) - 1
            query.exec_("update student set rightquestions=" + str(studentRightQuestions) + " where stusn='" + value + "'")

        if self.dict_choices[value] == "101":
            query.exec_("select wrongquestions from student where stusn='" + value + "'")
            query.next()
            studentWrongQuestions = query.value(0) - 1
            query.exec_("update student set wrongquestions=" + str(studentWrongQuestions) + " where stusn='" + value + "'")
            
        self.startChoice(usernum=1, oldbtn=value)
        # print("---reset___")

        # curmenu.actions()[0].setEnabled(True)
        # curmenu.actions()[1].setEnabled(True)
        # self.choiceOneStudent(value)

    def createDb(self):
        conn = sqlite3.connect("studentNew.db") 
        cur = conn.cursor()
        sqlstr = 'create table student (id integer primary key, \
            classname varchar(20), \
            stusn varchar(20), \
            stuname varchar(20), \
            rightquestions integer, \
            wrongquestions integer, \
            FOREIGN KEY(classname) REFERENCES classtable(classname))'
        # print(sqlstr)

        sqlstr2 = 'create table tmprecord (id integer primary key, \
            classname varchar(20), \
            stusn varchar(20), \
            datequestion date)'

        sqlstr3 = 'create table classtable (classname varchar(20) PRIMARY KEY)'
        
        cur.execute(sqlstr3)
        conn.commit()
        cur.execute(sqlstr2)
        conn.commit()
        cur.execute(sqlstr)
        conn.commit()

        strdelete = "delete from student where 1=1"
        cur.execute(strdelete)
        conn.commit()
        strdelete = "delete from tmprecord where 1=1"
        cur.execute(strdelete)
        conn.commit()
        # print(sqlstr2)

        # cur.execute(sqlstr) 
        # conn.commit()
        # cur.execute(sqlstr2) 
        # conn.commit()

        # insert example data
        strsql = "insert into classtable values (?)"
        cur.execute(strsql, ("三(3)班",))
        conn.commit()
        cur.execute(strsql, ("三(4)班",))
        conn.commit()


        a03lst = ["曾忆谊","赵佳泉","翁文秀","林珑","郑铭洁","林泽思","吴崇霖","陈思嘉","欧阳月孜","郭展羽","詹伟哲","黄佳仪","杨秋霞","周奕子","林楚杰","欧伊涵","许腾誉","陈唯凯","陈树凯","林彦君","张钰佳","高锴","杨博凯","林妙菲","林楚鸿","陈展烯","姚静茵","吴欣桐","范思杰","肖佳","马思广","许一帆","姚奕帆","陈海珣","吴黛莹","吴育桐","肖凯帆","林欣阳","叶茂霖","姚楷臻","陈嘉豪","陈琦","杨子楷","陈炎宏","陈幸仪","杨景畅","罗暖婷","郑馨"]
        a04lst = ["罗恩琪","王可","曾祥威","谢濡婷","温嘉凯","许洁仪","肖欣淇","陈凯佳","林天倩","李乐海","吴文慧","黄文婷","万誉","陈进盛","张裕涵","陈振嘉","王巧玲","林珮琪","陈炜楷","杨健","赵泽锴","张凤临","蔡子丹","陈烨杰","廖妍希","林树超","夏培轩","陈锦森","李星","蔡依婷","姚容创","姚凯扬","沈嘉克","周凡","张玉川","邱金迅","陈菲敏","陈星翰","朱煜楷","郑泽洪","钱剑非","罗奕丰","陈杜炜","林知钦"]
        strsql = "insert into student values (?, ?, ?, ?,?,?)" 
        for i in list(range(0,len(a03lst))):
            cur.execute(strsql, (None, "三(3)班", str(i+1).zfill(2), a03lst[i], 0, 0))
            conn.commit()
        strsql = "insert into student values (?, ?, ?, ?,?,?)" 
        for i in list(range(0,len(a04lst))):
            cur.execute(strsql, (None, "三(4)班", str(i+1).zfill(2), a04lst[i], 0, 0))
            conn.commit()
        cur.close()
Exemplo n.º 12
0
class TablaturePart(_base.Part):
    """Base class for tablature instrument part types."""

    octave = 0
    clef = None
    transposition = None
    tunings = ()  # may contain a list of tunings.
    tabFormat = ""  # can contain a tablatureFormat value.

    def createWidgets(self, layout):
        self.staffTypeLabel = QLabel()
        self.staffType = QComboBox()
        self.staffTypeLabel.setBuddy(self.staffType)
        self.staffType.setModel(listmodel.ListModel(tablatureStaffTypes, self.staffType, display=listmodel.translate))
        box = QHBoxLayout()
        layout.addLayout(box)
        box.addWidget(self.staffTypeLabel)
        box.addWidget(self.staffType)
        if self.tunings:
            self.createTuningWidgets(layout)
            self.staffType.activated.connect(self.slotTabEnable)
            self.slotTabEnable(0)

    def createTuningWidgets(self, layout):
        self.tuningLabel = QLabel()
        self.tuning = QComboBox()
        self.tuningLabel.setBuddy(self.tuning)
        tunings = [("", lambda: _("Default"))]
        tunings.extend(self.tunings)
        self.tuning.setModel(listmodel.ListModel(tunings, self.tuning, display=listmodel.translate_index(1)))
        self.tuning.setCurrentIndex(1)
        box = QHBoxLayout()
        layout.addLayout(box)
        box.addWidget(self.tuningLabel)
        box.addWidget(self.tuning)

    def translateWidgets(self):
        self.staffTypeLabel.setText(_("Staff type:"))
        self.staffType.model().update()
        if self.tunings:
            self.translateTuningWidgets()

    def translateTuningWidgets(self):
        self.tuningLabel.setText(_("Tuning:"))
        self.tuning.model().update()

    def slotTabEnable(self, enable):
        """Called when the user changes the staff type.
        
        Non-zero if the user wants a TabStaff.
        
        """
        self.tuning.setEnabled(bool(enable))

    def voiceCount(self):
        """Returns the number of voices.
        
        Inherit to make this user-settable.
        
        """
        return 1

    def build(self, data, builder):
        # First make assignments for the voices we want to create
        numVoices = self.voiceCount()
        if numVoices == 1:
            voices = (ly.util.mkid(data.name()),)
        elif numVoices == 2:
            order = 1, 2
            voices = "upper", "lower"
        elif numVoices == 3:
            order = 1, 3, 2
            voices = "upper", "middle", "lower"
        else:
            order = 1, 2, 3, 4
            voices = [ly.util.mkid(data.name(), "voice") + ly.util.int2text(i) for i in order]

        assignments = [data.assignMusic(name, self.octave, self.transposition) for name in voices]

        staffType = self.staffType.currentIndex()
        if staffType in (0, 2):
            # create a normal staff
            staff = ly.dom.Staff()
            seq = ly.dom.Seqr(staff)
            if self.clef:
                ly.dom.Clef(self.clef, seq)
            mus = ly.dom.Simr(seq)
            for a in assignments[:-1]:
                ly.dom.Identifier(a.name, mus)
                ly.dom.VoiceSeparator(mus)
            ly.dom.Identifier(assignments[-1].name, mus)
            builder.setMidiInstrument(staff, self.midiInstrument)

        if staffType in (1, 2):
            # create a tab staff
            tabstaff = ly.dom.TabStaff()
            if self.tabFormat:
                tabstaff.getWith()["tablatureFormat"] = ly.dom.Scheme(self.tabFormat)
            self.setTunings(tabstaff)
            sim = ly.dom.Simr(tabstaff)
            if numVoices == 1:
                ly.dom.Identifier(assignments[0].name, sim)
            else:
                for num, a in zip(order, assignments):
                    s = ly.dom.Seq(ly.dom.TabVoice(parent=sim))
                    ly.dom.Text("\\voice" + ly.util.int2text(num), s)
                    ly.dom.Identifier(a.name, s)

        if staffType == 0:
            # only a normal staff
            p = staff
        elif staffType == 1:
            # only a TabStaff
            builder.setMidiInstrument(tabstaff, self.midiInstrument)
            p = tabstaff
        else:
            # both TabStaff and normal staff
            p = ly.dom.StaffGroup()
            s = ly.dom.Sim(p)
            s.append(staff)
            s.append(tabstaff)

        builder.setInstrumentNamesFromPart(p, self, data)
        data.nodes.append(p)

    def setTunings(self, tab):
        if self.tunings and self.tuning.currentIndex() > 0:
            tuning = self.tunings[self.tuning.currentIndex() - 1][0]
            tab.getWith()["stringTunings"] = ly.dom.Scheme(tuning)
Exemplo n.º 13
0
class InstrumentNames(QGroupBox):
    def __init__(self, parent):
        super(InstrumentNames, self).__init__(parent, checkable=True, checked=True)
        
        grid = QGridLayout()
        self.setLayout(grid)
        
        self.firstSystemLabel = QLabel()
        self.firstSystem = QComboBox()
        self.firstSystemLabel.setBuddy(self.firstSystem)
        self.otherSystemsLabel = QLabel()
        self.otherSystems = QComboBox()
        self.otherSystemsLabel.setBuddy(self.otherSystems)
        self.languageLabel = QLabel()
        self.language = QComboBox()
        self.languageLabel.setBuddy(self.language)

        self.firstSystem.setModel(listmodel.ListModel(
            (lambda: _("Long"), lambda: _("Short")), self.firstSystem,
            display = listmodel.translate))
        self.otherSystems.setModel(listmodel.ListModel(
            (lambda: _("Long"), lambda: _("Short"), lambda: _("None")), self.otherSystems,
            display = listmodel.translate))
        
        self._langs = l = ['','C']
        l.extend(sorted(po.available()))
        def display(lang):
            if lang == 'C':
                return _("English (untranslated)")
            elif not lang:
                return _("Default")
            return language_names.languageName(lang, po.setup.current())
        self.language.setModel(listmodel.ListModel(l, self.language, display=display))
        
        grid.addWidget(self.firstSystemLabel, 0, 0)
        grid.addWidget(self.firstSystem, 0, 1)
        grid.addWidget(self.otherSystemsLabel, 1, 0)
        grid.addWidget(self.otherSystems, 1, 1)
        grid.addWidget(self.languageLabel, 2, 0)
        grid.addWidget(self.language, 2, 1)
        app.translateUI(self)
        self.loadSettings()
        self.window().finished.connect(self.saveSettings)
        
    def translateUI(self):
        self.setTitle(_("Instrument names"))
        self.firstSystemLabel.setText(_("First system:"))
        self.otherSystemsLabel.setText(_("Other systems:"))
        self.languageLabel.setText(_("Language:"))
        self.firstSystem.setToolTip(_(
            "Use long or short instrument names before the first system."))
        self.otherSystems.setToolTip(_(
            "Use short, long or no instrument names before the next systems."))
        self.language.setToolTip(_(
            "Which language to use for the instrument names."))
        self.firstSystem.model().update()
        self.otherSystems.model().update()
        self.language.model().update()
    
    def getLanguage(self):
        """Returns the language the user has set.
        
        '' means:  default (use same translation as system)
        'C' means: English (untranslated)
        or a language code that is available in Frescobaldi's translation.
        
        """
        return self._langs[self.language.currentIndex()]

    def loadSettings(self):
        s = QSettings()
        s.beginGroup('scorewiz/instrumentnames')
        self.setChecked(s.value('enabled', True, bool))
        allow = ['long', 'short']
        first = s.value('first', '', type(""))
        self.firstSystem.setCurrentIndex(allow.index(first) if first in allow else 0)
        allow = ['long', 'short', 'none']
        other = s.value('other', '', type(""))
        self.otherSystems.setCurrentIndex(allow.index(other) if other in allow else 2)
        language = s.value('language', '', type(""))
        self.language.setCurrentIndex(self._langs.index(language) if language in self._langs else 0)
    
    def saveSettings(self):
        s = QSettings()
        s.beginGroup('scorewiz/instrumentnames')
        s.setValue('enable', self.isChecked())
        s.setValue('first', ('long', 'short')[self.firstSystem.currentIndex()])
        s.setValue('other', ('long', 'short', 'none')[self.otherSystems.currentIndex()])
        s.setValue('language', self._langs[self.language.currentIndex()])
Exemplo n.º 14
0
class Choir(VocalPart):
    @staticmethod
    def title(_=_base.translate):
        return _("Choir")

    def createWidgets(self, layout):
        self.label = QLabel(wordWrap=True)
        self.voicingLabel = QLabel()
        self.voicing = QComboBox(editable=True)
        self.voicingLabel.setBuddy(self.voicing)
        self.voicing.setCompleter(None)
        self.voicing.setValidator(QRegExpValidator(
            QRegExp("[SATB]+(-[SATB]+)*", Qt.CaseInsensitive), self.voicing))
        self.voicing.addItems((
            'SA-TB', 'S-A-T-B',
            'SA', 'S-A', 'SS-A', 'S-S-A',
            'TB', 'T-B', 'TT-B', 'T-T-B',
            'SS-A-T-B', 'S-A-TT-B', 'SS-A-TT-B',
            'S-S-A-T-T-B', 'S-S-A-A-T-T-B-B',
            ))
        self.lyricsLabel = QLabel()
        self.lyrics = QComboBox()
        self.lyricsLabel.setBuddy(self.lyrics)
        self.lyrics.setModel(listmodel.ListModel(lyricStyles, self.lyrics,
            display=listmodel.translate_index(0),
            tooltip=listmodel.translate_index(1)))
        self.lyrics.setCurrentIndex(0)
        self.pianoReduction = QCheckBox()
        self.rehearsalMidi = QCheckBox()
        
        layout.addWidget(self.label)
        box = QHBoxLayout()
        layout.addLayout(box)
        box.addWidget(self.voicingLabel)
        box.addWidget(self.voicing)
        self.createStanzaWidget(layout)
        box = QHBoxLayout()
        layout.addLayout(box)
        box.addWidget(self.lyricsLabel)
        box.addWidget(self.lyrics)
        self.createAmbitusWidget(layout)
        layout.addWidget(self.pianoReduction)
        layout.addWidget(self.rehearsalMidi)
    
    def translateWidgets(self):
        self.translateStanzaWidget()
        self.translateAmbitusWidget()
        self.lyrics.model().update()
        self.label.setText('<p>{0} <i>({1})</i></p>'.format(
            _("Please select the voices for the choir. "
              "Use the letters S, A, T, or B. A hyphen denotes a new staff."),
            _("Hint: For a double choir you can use two choir parts.")))
        self.voicingLabel.setText(_("Voicing:"))
        self.lyricsLabel.setText(_("Lyrics:"))
        self.pianoReduction.setText(_("Piano reduction"))
        self.pianoReduction.setToolTip(_(
            "Adds an automatically generated piano reduction."))
        self.rehearsalMidi.setText(_("Rehearsal MIDI files"))
        self.rehearsalMidi.setToolTip(_(
            "Creates a rehearsal MIDI file for every voice, "
            "even if no MIDI output is generated for the main score."))

    def build(self, data, builder):
        # normalize voicing
        staves = self.voicing.currentText().upper()
        # remove unwanted characters
        staves = re.sub(r'[^SATB-]+', '', staves)
        # remove double hyphens, and from begin and end
        staves = re.sub('-+', '-', staves).strip('-')
        if not staves:
            return
        
        splitStaves = staves.split('-')
        numStaves = len(splitStaves)
        staffCIDs = collections.defaultdict(int)    # number same-name staff Context-IDs
        voiceCounter = collections.defaultdict(int) # dict to number same voice types
        maxNumVoices = max(map(len, splitStaves))   # largest number of voices
        numStanzas = self.stanzas.value()
        lyrics = collections.defaultdict(list)      # lyrics grouped by stanza number
        pianoReduction = collections.defaultdict(list)
        rehearsalMidis = []
        
        p = ly.dom.ChoirStaff()
        choir = ly.dom.Sim(p)
        data.nodes.append(p)
        
        # print main instrumentName if there are more choirs, and we
        # have more than one staff.
        if numStaves > 1 and data.num:
            builder.setInstrumentNames(p,
                builder.instrumentName(lambda _: _("Choir"), data.num),
                builder.instrumentName(lambda _: _("abbreviation for Choir", "Ch."), data.num))
        
        # get the preferred way of adding lyrics
        lyrAllSame, lyrEachSame, lyrEachDiff, lyrSpread = (
            self.lyrics.currentIndex() == i for i in range(4))
        lyrEach = lyrEachSame or lyrEachDiff
        
        # stanzas to print (0 = don't print stanza number):
        if numStanzas == 1:
            allStanzas = [0]
        else:
            allStanzas = list(range(1, numStanzas + 1))
        
        # Which stanzas to print where:
        if lyrSpread and numStanzas > 1 and numStaves > 2:
            spaces = numStaves - 1
            count, rest = divmod(max(numStanzas, spaces), spaces)
            stanzaSource = itertools.cycle(allStanzas)
            stanzaGroups = (itertools.islice(stanzaSource, num)
                            for num in itertools.chain(
                                itertools.repeat(count + 1, rest),
                                itertools.repeat(count, numStaves - rest)))
        else:
            stanzaGroups = itertools.repeat(allStanzas, numStaves)
        
        # a function to set staff affinity (in LilyPond 2.13.4 and above):
        if builder.lyVersion >= (2, 13, 4):
            def setStaffAffinity(context, affinity):
                ly.dom.Line("\\override VerticalAxisGroup "
                     "#'staff-affinity = #" + affinity, context.getWith())
        else:
            def setStaffAffinity(lyricsContext, affinity):
                pass
        
        # a function to make a column markup:
        if builder.lyVersion >= (2, 11, 57):
            columnCommand = 'center-column'
        else:
            columnCommand = 'center-align'
        def makeColumnMarkup(names):
            node = ly.dom.Markup()
            column = ly.dom.MarkupEnclosed(columnCommand, node)
            for name in names:
                ly.dom.QuotedString(name, column)
            return node
        
        stavesLeft = numStaves
        for staff, stanzas in zip(splitStaves, stanzaGroups):
            # are we in the last staff?
            stavesLeft -= 1
            # the number of voices in this staff
            numVoices = len(staff)
            # sort the letters in order SATB
            staff = ''.join(i * staff.count(i) for i in 'SATB')
            # Create the staff for the voices
            s = ly.dom.Staff(parent=choir)
            builder.setMidiInstrument(s, self.midiInstrument)
            
            # Build a list of the voices in this staff.
            # Each entry is a tuple(name, num).
            # name is one of 'S', 'A', 'T', or 'B'
            # num is an integer: 0 when a voice occurs only once, or >= 1 when
            # there are more voices of the same type (e.g. Soprano I and II)
            voices = []
            for voice in staff:
                if staves.count(voice) > 1:
                    voiceCounter[voice] += 1
                voices.append((voice, voiceCounter[voice]))
            
            # Add the instrument names to the staff:
            if numVoices == 1:
                voice, num = voices[0]
                longName = builder.instrumentName(voice2Voice[voice].title, num)
                shortName = builder.instrumentName(voice2Voice[voice].short, num)
                builder.setInstrumentNames(s, longName, shortName)
            else:
                # stack instrument names (long and short) in a markup column.
                # long names
                longNames = makeColumnMarkup(
                    builder.instrumentName(voice2Voice[voice].title, num) for voice, num in voices)
                shortNames = makeColumnMarkup(
                    builder.instrumentName(voice2Voice[voice].short, num) for voice, num in voices)
                builder.setInstrumentNames(s, longNames, shortNames)
            
            # Make the { } or << >> holder for this staff's children.
            # If *all* staves have only one voice, addlyrics is used.
            # In that case, don't remove the braces.
            staffMusic = (ly.dom.Seq if lyrEach and maxNumVoices == 1 else
                          ly.dom.Seqr if numVoices == 1 else ly.dom.Simr)(s)
            
            # Set the clef for this staff:
            if 'B' in staff:
                ly.dom.Clef('bass', staffMusic)
            elif 'T' in staff:
                ly.dom.Clef('treble_8', staffMusic)

            # Determine voice order (\voiceOne, \voiceTwo etc.)
            if numVoices == 1:
                order = (0,)
            elif numVoices == 2:
                order = 1, 2
            elif staff in ('SSA', 'TTB'):
                order = 1, 3, 2
            elif staff in ('SAA', 'TBB'):
                order = 1, 2, 4
            elif staff in ('SSAA', 'TTBB'):
                order = 1, 3, 2, 4
            else:
                order = range(1, numVoices + 1)
            
            # What name would the staff get if we need to refer to it?
            # If a name (like 's' or 'sa') is already in use in this part,
            # just add a number ('ss2' or 'sa2', etc.)
            staffCIDs[staff] += 1
            cid = ly.dom.Reference(staff.lower() +
                str(staffCIDs[staff] if staffCIDs[staff] > 1 else ""))
            
            # Create voices and their lyrics:
            for (voice, num), voiceNum in zip(voices, order):
                name = voice2id[voice]
                if num:
                    name += ly.util.int2text(num)
                a = data.assignMusic(name, voice2Voice[voice].octave)
                lyrName = name + 'Verse' if lyrEachDiff else 'verse'
            
                # Use \addlyrics if all staves have exactly one voice.
                if lyrEach and maxNumVoices == 1:
                    for verse in stanzas:
                        lyrics[verse].append((ly.dom.AddLyrics(s), lyrName))
                    ly.dom.Identifier(a.name, staffMusic)
                else:
                    voiceName = voice2id[voice] + str(num or '')
                    v = ly.dom.Voice(voiceName, parent=staffMusic)
                    voiceMusic = ly.dom.Seqr(v)
                    if voiceNum:
                        ly.dom.Text('\\voice' + ly.util.int2text(voiceNum), voiceMusic)
                    ly.dom.Identifier(a.name, voiceMusic)
                    
                    if stanzas and (lyrEach or (voiceNum <= 1 and
                                    (stavesLeft or numStaves == 1))):
                        # Create the lyrics. If they should be above the staff,
                        # give the staff a suitable name, and use alignAbove-
                        # Context to align the Lyrics above the staff.
                        above = voiceNum & 1 if lyrEach else False
                        if above and s.cid is None:
                            s.cid = cid

                        for verse in stanzas:
                            l = ly.dom.Lyrics(parent=choir)
                            if above:
                                l.getWith()['alignAboveContext'] = cid
                                setStaffAffinity(l, "DOWN")
                            elif not lyrEach and stavesLeft:
                                setStaffAffinity(l, "CENTER")
                            lyrics[verse].append((ly.dom.LyricsTo(voiceName, l), lyrName))

                # Add ambitus:
                if self.ambitus.isChecked():
                    ambitusContext = (s if numVoices == 1 else v).getWith()
                    ly.dom.Line('\\consists "Ambitus_engraver"', ambitusContext)
                    if voiceNum > 1:
                        ly.dom.Line("\\override Ambitus #'X-offset = #{0}".format(
                                 (voiceNum - 1) * 2.0), ambitusContext)
            
                pianoReduction[voice].append(a.name)
                rehearsalMidis.append((voice, num, a.name, lyrName))
            
        # Assign the lyrics, so their definitions come after the note defs.
        # (These refs are used again below in the midi rehearsal routine.)
        refs = {}
        for verse in allStanzas:
            for node, name in lyrics[verse]:
                if (name, verse) not in refs:
                    refs[(name, verse)] = self.assignLyrics(data, name, verse).name
                ly.dom.Identifier(refs[(name, verse)], node)

        # Create the piano reduction if desired
        if self.pianoReduction.isChecked():
            a = data.assign('pianoReduction')
            data.nodes.append(ly.dom.Identifier(a.name))
            piano = ly.dom.PianoStaff(parent=a)
            
            sim = ly.dom.Sim(piano)
            rightStaff = ly.dom.Staff(parent=sim)
            leftStaff = ly.dom.Staff(parent=sim)
            right = ly.dom.Seq(rightStaff)
            left = ly.dom.Seq(leftStaff)
            
            # Determine the ordering of voices in the staves
            upper = pianoReduction['S'] + pianoReduction['A']
            lower = pianoReduction['T'] + pianoReduction['B']
            
            preferUpper = 1
            if not upper:
                # Male choir
                upper = pianoReduction['T']
                lower = pianoReduction['B']
                ly.dom.Clef("treble_8", right)
                ly.dom.Clef("bass", left)
                preferUpper = 0
            elif not lower:
                # Female choir
                upper = pianoReduction['S']
                lower = pianoReduction['A']
            else:
                ly.dom.Clef("bass", left)

            # Otherwise accidentals can be confusing
            ly.dom.Line("#(set-accidental-style 'piano)", right)
            ly.dom.Line("#(set-accidental-style 'piano)", left)
            
            # Move voices if unevenly spread
            if abs(len(upper) - len(lower)) > 1:
                voices = upper + lower
                half = (len(voices) + preferUpper) // 2
                upper = voices[:half]
                lower = voices[half:]
            
            for staff, voices in (ly.dom.Simr(right), upper), (ly.dom.Simr(left), lower):
                if voices:
                    for v in voices[:-1]:
                        ly.dom.Identifier(v, staff)
                        ly.dom.VoiceSeparator(staff).after = 1
                    ly.dom.Identifier(voices[-1], staff)

            # Make the piano part somewhat smaller
            ly.dom.Line("fontSize = #-1", piano.getWith())
            ly.dom.Line("\\override StaffSymbol #'staff-space = #(magstep -1)",
                piano.getWith())
            
            # Nice to add Mark engravers
            ly.dom.Line('\\consists "Mark_engraver"', rightStaff.getWith())
            ly.dom.Line('\\consists "Metronome_mark_engraver"', rightStaff.getWith())
            
            # Keep piano reduction out of the MIDI output
            if builder.midi:
                ly.dom.Line('\\remove "Staff_performer"', rightStaff.getWith())
                ly.dom.Line('\\remove "Staff_performer"', leftStaff.getWith())
        
        # Create MIDI files if desired
        if self.rehearsalMidi.isChecked():
            a = data.assign('rehearsalMidi')
            rehearsalMidi = a.name
            
            func = ly.dom.SchemeList(a)
            func.pre = '#\n(' # hack
            ly.dom.Text('define-music-function', func)
            ly.dom.Line('(parser location name midiInstrument lyrics) '
                 '(string? string? ly:music?)', func)
            choir = ly.dom.Sim(ly.dom.Command('unfoldRepeats', ly.dom.SchemeLily(func)))
            
            data.afterblocks.append(ly.dom.Comment(_("Rehearsal MIDI files:")))
            
            for voice, num, ref, lyrName in rehearsalMidis:
                # Append voice to the rehearsalMidi function
                name = voice2id[voice] + str(num or '')
                seq = ly.dom.Seq(ly.dom.Voice(name, parent=ly.dom.Staff(name, parent=choir)))
                if builder.lyVersion < (2, 18, 0):
                    ly.dom.Text('<>\\f', seq) # add one dynamic
                ly.dom.Identifier(ref, seq) # add the reference to the voice
                
                book = ly.dom.Book()
                
                # Append score to the aftermath (stuff put below the main score)
                suffix = "choir{0}-{1}".format(data.num, name) if data.num else name
                if builder.lyVersion < (2, 12, 0):
                    data.afterblocks.append(
                        ly.dom.Line('#(define output-suffix "{0}")'.format(suffix)))
                else:
                    ly.dom.Line('\\bookOutputSuffix "{0}"'.format(suffix), book)
                data.afterblocks.append(book)
                data.afterblocks.append(ly.dom.BlankLine())
                score = ly.dom.Score(book)
                
                # TODO: make configurable
                midiInstrument = voice2Midi[voice]

                cmd = ly.dom.Command(rehearsalMidi, score)
                ly.dom.QuotedString(name, cmd)
                ly.dom.QuotedString(midiInstrument, cmd)
                ly.dom.Identifier(refs[(lyrName, allStanzas[0])], cmd)
                ly.dom.Midi(score)
            
            ly.dom.Text("\\context Staff = $name", choir)
            seq = ly.dom.Seq(choir)
            ly.dom.Line("\\set Score.midiMinimumVolume = #0.5", seq)
            ly.dom.Line("\\set Score.midiMaximumVolume = #0.5", seq)
            ly.dom.Line("\\set Score.tempoWholesPerMinute = #" + data.scoreProperties.schemeMidiTempo(), seq)
            ly.dom.Line("\\set Staff.midiMinimumVolume = #0.8", seq)
            ly.dom.Line("\\set Staff.midiMaximumVolume = #1.0", seq)
            ly.dom.Line("\\set Staff.midiInstrument = $midiInstrument", seq)
            lyr = ly.dom.Lyrics(parent=choir)
            lyr.getWith()['alignBelowContext'] = ly.dom.Text('$name')
            ly.dom.Text("\\lyricsto $name $lyrics", lyr)
Exemplo n.º 15
0
class ScoreProperties(object):
    """This is only the base class, it should be mixed in with a widget or a different way."""
    def createWidgets(self):
        """Creates all widgets."""
        self.createKeySignatureWidget()
        self.createTimeSignatureWidget()
        self.createPickupWidget()
        self.createMetronomeWidget()
        self.createTempoWidget()

    def layoutWidgets(self, layout):
        """Adds all widgets to a vertical layout."""
        self.layoutKeySignatureWidget(layout)
        self.layoutTimeSignatureWidget(layout)
        self.layoutPickupWidget(layout)
        self.layoutMetronomeWidget(layout)
        self.layoutTempoWidget(layout)

    def translateWidgets(self):
        self.translateKeySignatureWidget()
        self.translateTimeSignatureWidget()
        self.translatePickupWidget()
        self.tranlateMetronomeWidget()
        self.translateTempoWidget()

    def ly(self, node, builder):
        """Adds appropriate LilyPond command nodes to the parent node.
        
        Settings from the builder are used where that makes sense.
        All widgets must be present.
        
        """
        self.lyKeySignature(node, builder)
        self.lyTimeSignature(node, builder)
        self.lyPickup(node, builder)
        self.lyTempo(node, builder)

    def globalSection(self, builder):
        """Returns a sequential expression between { } containing the output of ly()."""
        seq = ly.dom.Seq()
        self.ly(seq, builder)
        return seq

    # Key signature
    def createKeySignatureWidget(self):
        self.keySignatureLabel = QLabel()
        self.keyNote = QComboBox()
        self.keyNote.setModel(
            listmodel.ListModel(keyNames['nederlands'], self.keyNote))
        self.keyMode = QComboBox()
        self.keyMode.setModel(
            listmodel.ListModel(modes,
                                self.keyMode,
                                display=listmodel.translate_index(1)))
        self.keySignatureLabel.setBuddy(self.keyNote)

    def translateKeySignatureWidget(self):
        self.keySignatureLabel.setText(_("Key signature:"))
        self.keyMode.model().update()

    def layoutKeySignatureWidget(self, layout):
        """Adds our widgets to a layout, assuming it is a QVBoxLayout."""
        box = QHBoxLayout()
        box.addWidget(self.keySignatureLabel)
        box.addWidget(self.keyNote)
        box.addWidget(self.keyMode)
        layout.addLayout(box)

    def setPitchLanguage(self, language='nederlands'):
        self.keyNote.model()._data = keyNames[language or 'nederlands']
        self.keyNote.model().update()

    def lyKeySignature(self, node, builder):
        """Adds the key signature to the ly.dom node parent."""
        note, alter = keys[self.keyNote.currentIndex()]
        alter = fractions.Fraction(alter, 2)
        mode = modes[self.keyMode.currentIndex()][0]
        ly.dom.KeySignature(note, alter, mode, node).after = 1

    # Time signature
    def createTimeSignatureWidget(self):
        self.timeSignatureLabel = QLabel()
        self.timeSignature = QComboBox(editable=True)
        icons = {
            '(4/4)': symbols.icon('time_c44'),
            '(2/2)': symbols.icon('time_c22'),
        }
        self.timeSignature.setModel(
            listmodel.ListModel(timeSignaturePresets,
                                self.timeSignature,
                                icon=icons.get))
        self.timeSignature.setCompleter(None)
        self.timeSignatureLabel.setBuddy(self.timeSignature)

    def translateTimeSignatureWidget(self):
        self.timeSignatureLabel.setText(_("Time signature:"))

    def layoutTimeSignatureWidget(self, layout):
        """Adds our widgets to a layout, assuming it is a QVBoxLayout."""
        box = QHBoxLayout()
        box.addWidget(self.timeSignatureLabel)
        box.addWidget(self.timeSignature)
        layout.addLayout(box)

    def lyTimeSignature(self, node, builder):
        """Adds the time signature to the ly.dom node parent."""
        sig = self.timeSignature.currentText().strip()
        if '+' in sig:
            pass  # TODO: implement support for \compoundMeter
        else:
            if sig == '(2/2)':
                ly.dom.TimeSignature(2, 2, node).after = 1
            elif sig == '(4/4)':
                ly.dom.TimeSignature(4, 4, node).after = 1
            else:
                match = re.search(r'(\d+).*?(\d+)', sig)
                if match:
                    if builder.lyVersion >= (2, 11, 44):
                        ly.dom.Line(r"\numericTimeSignature", node)
                    else:
                        ly.dom.Line(
                            r"\override Staff.TimeSignature #'style = #'()",
                            node)
                    num, beat = map(int, match.group(1, 2))
                    ly.dom.TimeSignature(num, beat, node).after = 1

    # Pickup bar
    def createPickupWidget(self):
        self.pickupLabel = QLabel()
        self.pickup = QComboBox()
        pickups = ['']
        pickups.extend(durations)
        self.pickup.setModel(
            listmodel.ListModel(pickups,
                                self.pickup,
                                display=lambda item: item or _("None"),
                                icon=lambda item: symbols.icon(
                                    'note_{0}'.format(item.replace('.', 'd')))
                                if item else None))
        self.pickup.view().setIconSize(QSize(22, 22))
        self.pickupLabel.setBuddy(self.pickup)

    def translatePickupWidget(self):
        self.pickupLabel.setText(_("Pickup measure:"))
        self.pickup.model().update()

    def layoutPickupWidget(self, layout):
        box = QHBoxLayout()
        box.addWidget(self.pickupLabel)
        box.addWidget(self.pickup)
        layout.addLayout(box)

    def lyPickup(self, node, builder):
        if self.pickup.currentIndex() > 0:
            dur, dots = partialDurations[self.pickup.currentIndex() - 1]
            ly.dom.Partial(dur, dots, parent=node)

    # Metronome value
    def createMetronomeWidget(self):
        self.metronomeLabel = QLabel()
        self.metronomeNote = QComboBox()
        self.metronomeNote.setModel(
            listmodel.ListModel(
                durations,
                display=None,
                icon=lambda item: symbols.icon('note_{0}'.format(
                    item.replace('.', 'd')))))
        self.metronomeNote.setCurrentIndex(durations.index('4'))
        self.metronomeNote.view().setIconSize(QSize(22, 22))
        self.metronomeEqualSign = QLabel('=')
        self.metronomeEqualSign.setFixedWidth(
            self.metronomeEqualSign.minimumSizeHint().width())
        self.metronomeValue = QComboBox(editable=True)
        self.metronomeValue.setModel(
            listmodel.ListModel(metronomeValues,
                                self.metronomeValue,
                                display=format))
        self.metronomeValue.setCompleter(None)
        self.metronomeValue.setValidator(
            QIntValidator(0, 999, self.metronomeValue))
        self.metronomeValue.setCurrentIndex(metronomeValues.index(100))
        self.metronomeTempo = widgets.tempobutton.TempoButton()
        self.metronomeTempo.tempo.connect(self.setMetronomeValue)
        self.metronomeLabel.setBuddy(self.metronomeNote)
        self.metronomeRound = QCheckBox()

    def layoutMetronomeWidget(self, layout):
        grid = QGridLayout()
        grid.addWidget(self.metronomeLabel, 0, 0)

        box = QHBoxLayout(spacing=0)
        box.addWidget(self.metronomeNote)
        box.addWidget(self.metronomeEqualSign)
        box.addWidget(self.metronomeValue)
        box.addWidget(self.metronomeTempo)
        grid.addLayout(box, 0, 1)

        grid.addWidget(self.metronomeRound, 1, 1)
        layout.addLayout(grid)

    def tranlateMetronomeWidget(self):
        self.metronomeLabel.setText(_("Metronome mark:"))
        self.metronomeRound.setText(_("Round tap tempo value"))
        self.metronomeRound.setToolTip(
            _("Round the entered tap tempo to a common value."))

    def setMetronomeValue(self, bpm):
        """ Tap the tempo tap button """
        if self.metronomeRound.isChecked():
            l = [abs(t - bpm) for t in metronomeValues]
            m = min(l)
            if m < 6:
                self.metronomeValue.setCurrentIndex(l.index(m))

        else:
            self.metronomeValue.setEditText(str(bpm))

    # Tempo indication
    def createTempoWidget(self):
        self.tempoLabel = QLabel()
        self.tempo = widgets.lineedit.LineEdit()
        completionmodel.complete(self.tempo,
                                 "scorewiz/completion/scoreproperties/tempo")
        self.tempo.completer().setCaseSensitivity(Qt.CaseInsensitive)
        self.tempoLabel.setBuddy(self.tempo)

    def layoutTempoWidget(self, layout):
        box = QHBoxLayout()
        box.addWidget(self.tempoLabel)
        box.addWidget(self.tempo)
        layout.addLayout(box)

    def translateTempoWidget(self):
        self.tempoLabel.setText(_("Tempo indication:"))

    def lyTempo(self, node, builder):
        """Returns an appropriate tempo indication."""
        text = self.tempo.text().strip()
        if builder.showMetronomeMark:
            dur = durations[self.metronomeNote.currentIndex()]
            val = self.metronomeValue.currentText() or '60'
        elif text:
            dur = None
            val = None
        else:
            return
        tempo = ly.dom.Tempo(dur, val, node)
        if text:
            ly.dom.QuotedString(text, tempo)

    def lyMidiTempo(self, node):
        """Sets the configured tempo in the tempoWholesPerMinute variable."""
        node['tempoWholesPerMinute'] = ly.dom.Scheme(self.schemeMidiTempo())

    def schemeMidiTempo(self):
        """Returns a string with the tempo like '(ly:make-moment 100 4)' from the settings."""
        base, mul = midiDurations[self.metronomeNote.currentIndex()]
        val = int(self.metronomeValue.currentText() or '60') * mul
        return "(ly:make-moment {0} {1})".format(val, base)

    def lySimpleMidiTempo(self, node):
        r"""Return a simple \tempo x=y node for the currently set tempo."""
        dur = durations[self.metronomeNote.currentIndex()]
        val = self.metronomeValue.currentText() or '60'
        return ly.dom.Tempo(dur, val, node)
class OWImportImages(widget.OWWidget):
    name = "Import Images"
    description = "Import images from a directory(s)"
    icon = "icons/ImportImages.svg"
    priority = 110

    outputs = [("Data", Orange.data.Table)]

    #: list of recent paths
    recent_paths = settings.Setting([])  # type: List[RecentPath]
    currentPath = settings.Setting(None)

    want_main_area = False
    resizing_enabled = False

    Modality = Qt.ApplicationModal
    # Modality = Qt.WindowModal

    MaxRecentItems = 20

    def __init__(self):
        super().__init__()
        #: widget's runtime state
        self.__state = State.NoState
        self._imageMeta = []
        self._imageCategories = {}

        self.__invalidated = False
        self.__pendingTask = None

        vbox = gui.vBox(self.controlArea)
        hbox = gui.hBox(vbox)
        self.recent_cb = QComboBox(
            sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon,
            minimumContentsLength=16,
        )
        self.recent_cb.activated[int].connect(self.__onRecentActivated)
        icons = standard_icons(self)

        browseaction = QAction(
            "Open/Load Images",
            self,
            iconText="\N{HORIZONTAL ELLIPSIS}",
            icon=icons.dir_open_icon,
            toolTip="Select a directory from which to load the images")
        browseaction.triggered.connect(self.__runOpenDialog)
        reloadaction = QAction("Reload",
                               self,
                               icon=icons.reload_icon,
                               toolTip="Reload current image set")
        reloadaction.triggered.connect(self.reload)
        self.__actions = namespace(
            browse=browseaction,
            reload=reloadaction,
        )

        browsebutton = QPushButton(browseaction.iconText(),
                                   icon=browseaction.icon(),
                                   toolTip=browseaction.toolTip(),
                                   clicked=browseaction.trigger)
        reloadbutton = QPushButton(
            reloadaction.iconText(),
            icon=reloadaction.icon(),
            clicked=reloadaction.trigger,
            default=True,
        )

        hbox.layout().addWidget(self.recent_cb)
        hbox.layout().addWidget(browsebutton)
        hbox.layout().addWidget(reloadbutton)

        self.addActions([browseaction, reloadaction])

        reloadaction.changed.connect(
            lambda: reloadbutton.setEnabled(reloadaction.isEnabled()))
        box = gui.vBox(vbox, "Info")
        self.infostack = QStackedWidget()

        self.info_area = QLabel(text="No image set selected", wordWrap=True)
        self.progress_widget = QProgressBar(minimum=0, maximum=0)
        self.cancel_button = QPushButton(
            "Cancel",
            icon=icons.cancel_icon,
        )
        self.cancel_button.clicked.connect(self.cancel)

        w = QWidget()
        vlayout = QVBoxLayout()
        vlayout.setContentsMargins(0, 0, 0, 0)
        hlayout = QHBoxLayout()
        hlayout.setContentsMargins(0, 0, 0, 0)

        hlayout.addWidget(self.progress_widget)
        hlayout.addWidget(self.cancel_button)
        vlayout.addLayout(hlayout)

        self.pathlabel = TextLabel()
        self.pathlabel.setTextElideMode(Qt.ElideMiddle)
        self.pathlabel.setAttribute(Qt.WA_MacSmallSize)

        vlayout.addWidget(self.pathlabel)
        w.setLayout(vlayout)

        self.infostack.addWidget(self.info_area)
        self.infostack.addWidget(w)

        box.layout().addWidget(self.infostack)

        self.__initRecentItemsModel()
        self.__invalidated = True
        self.__executor = ThreadExecutor(self)

        QApplication.postEvent(self, QEvent(RuntimeEvent.Init))

    def __initRecentItemsModel(self):
        if self.currentPath is not None and \
                not os.path.isdir(self.currentPath):
            self.currentPath = None

        recent_paths = []
        for item in self.recent_paths:
            if os.path.isdir(item.abspath):
                recent_paths.append(item)
        recent_paths = recent_paths[:OWImportImages.MaxRecentItems]
        recent_model = self.recent_cb.model()
        for pathitem in recent_paths:
            item = RecentPath_asqstandarditem(pathitem)
            recent_model.appendRow(item)

        self.recent_paths = recent_paths

        if self.currentPath is not None and \
                os.path.isdir(self.currentPath) and self.recent_paths and \
                os.path.samefile(self.currentPath, self.recent_paths[0].abspath):
            self.recent_cb.setCurrentIndex(0)
        else:
            self.currentPath = None
            self.recent_cb.setCurrentIndex(-1)
        self.__actions.reload.setEnabled(self.currentPath is not None)

    def customEvent(self, event):
        """Reimplemented."""
        if event.type() == RuntimeEvent.Init:
            if self.__invalidated:
                try:
                    self.start()
                finally:
                    self.__invalidated = False

        super().customEvent(event)

    def __runOpenDialog(self):
        startdir = os.path.expanduser("~/")
        if self.recent_paths:
            startdir = self.recent_paths[0].abspath

        if OWImportImages.Modality == Qt.WindowModal:
            dlg = QFileDialog(
                self,
                "Select Top Level Directory",
                startdir,
                acceptMode=QFileDialog.AcceptOpen,
                modal=True,
            )
            dlg.setFileMode(QFileDialog.Directory)
            dlg.setOption(QFileDialog.ShowDirsOnly)
            dlg.setDirectory(startdir)
            dlg.setAttribute(Qt.WA_DeleteOnClose)

            @dlg.accepted.connect
            def on_accepted():
                dirpath = dlg.selectedFiles()
                if dirpath:
                    self.setCurrentPath(dirpath[0])
                    self.start()

            dlg.open()
        else:
            dirpath = QFileDialog.getExistingDirectory(
                self, "Select Top Level Directory", startdir)
            if dirpath:
                self.setCurrentPath(dirpath)
                self.start()

    def __onRecentActivated(self, index):
        item = self.recent_cb.itemData(index)
        if item is None:
            return
        assert isinstance(item, RecentPath)
        self.setCurrentPath(item.abspath)
        self.start()

    def __updateInfo(self):
        if self.__state == State.NoState:
            text = "No image set selected"
        elif self.__state == State.Processing:
            text = "Processing"
        elif self.__state == State.Done:
            nvalid = sum(imeta.isvalid for imeta in self._imageMeta)
            ncategories = len(self._imageCategories)
            if ncategories < 2:
                text = "{} images".format(nvalid)
            else:
                text = "{} images / {} categories".format(nvalid, ncategories)
        elif self.__state == State.Cancelled:
            text = "Cancelled"
        elif self.__state == State.Error:
            text = "Error state"
        else:
            assert False

        self.info_area.setText(text)

        if self.__state == State.Processing:
            self.infostack.setCurrentIndex(1)
        else:
            self.infostack.setCurrentIndex(0)

    def setCurrentPath(self, path):
        """
        Set the current root image path to path

        If the path does not exists or is not a directory the current path
        is left unchanged

        Parameters
        ----------
        path : str
            New root import path.

        Returns
        -------
        status : bool
            True if the current root import path was successfully
            changed to path.
        """
        if self.currentPath is not None and path is not None and \
                os.path.isdir(self.currentPath) and os.path.isdir(path) and \
                os.path.samefile(self.currentPath, path):
            return True

        if not os.path.exists(path):
            warnings.warn("'{}' does not exist".format(path), UserWarning)
            return False
        elif not os.path.isdir(path):
            warnings.warn("'{}' is not a directory".format(path), UserWarning)
            return False

        newindex = self.addRecentPath(path)
        self.recent_cb.setCurrentIndex(newindex)
        if newindex >= 0:
            self.currentPath = path
        else:
            self.currentPath = None
        self.__actions.reload.setEnabled(self.currentPath is not None)

        if self.__state == State.Processing:
            self.cancel()

        return True

    def addRecentPath(self, path):
        """
        Prepend a path entry to the list of recent paths

        If an entry with the same path already exists in the recent path
        list it is moved to the first place

        Parameters
        ----------
        path : str
        """
        existing = None
        for pathitem in self.recent_paths:
            if os.path.samefile(pathitem.abspath, path):
                existing = pathitem
                break

        model = self.recent_cb.model()

        if existing is not None:
            selected_index = self.recent_paths.index(existing)
            assert model.item(selected_index).data(Qt.UserRole) is existing
            self.recent_paths.remove(existing)
            row = model.takeRow(selected_index)
            self.recent_paths.insert(0, existing)
            model.insertRow(0, row)
        else:
            item = RecentPath(path, None, None)
            self.recent_paths.insert(0, item)
            model.insertRow(0, RecentPath_asqstandarditem(item))
        return 0

    def __setRuntimeState(self, state):
        assert state in State
        self.setBlocking(state == State.Processing)
        message = ""
        if state == State.Processing:
            assert self.__state in [
                State.Done, State.NoState, State.Error, State.Cancelled
            ]
            message = "Processing"
        elif state == State.Done:
            assert self.__state == State.Processing
        elif state == State.Cancelled:
            assert self.__state == State.Processing
            message = "Cancelled"
        elif state == State.Error:
            message = "Error during processing"
        elif state == State.NoState:
            message = ""
        else:
            assert False

        self.__state = state

        if self.__state == State.Processing:
            self.infostack.setCurrentIndex(1)
        else:
            self.infostack.setCurrentIndex(0)

        self.setStatusMessage(message)
        self.__updateInfo()

    def reload(self):
        """
        Restart the image scan task
        """
        if self.__state == State.Processing:
            self.cancel()

        self._imageMeta = []
        self._imageCategories = {}
        self.start()

    def start(self):
        """
        Start/execute the image indexing operation
        """
        self.error()

        self.__invalidated = False
        if self.currentPath is None:
            return

        if self.__state == State.Processing:
            assert self.__pendingTask is not None
            log.info("Starting a new task while one is in progress. "
                     "Cancel the existing task (dir:'{}')".format(
                         self.__pendingTask.startdir))
            self.cancel()

        startdir = self.currentPath

        self.__setRuntimeState(State.Processing)

        report_progress = methodinvoke(self, "__onReportProgress", (object, ))

        task = ImageScan(startdir, report_progress=report_progress)

        # collect the task state in one convenient place
        self.__pendingTask = taskstate = namespace(
            task=task,
            startdir=startdir,
            future=None,
            watcher=None,
            cancelled=False,
            cancel=None,
        )

        def cancel():
            # Cancel the task and disconnect
            if taskstate.future.cancel():
                pass
            else:
                taskstate.task.cancelled = True
                taskstate.cancelled = True
                try:
                    taskstate.future.result(timeout=3)
                except UserInterruptError:
                    pass
                except TimeoutError:
                    log.info("The task did not stop in in a timely manner")
            taskstate.watcher.finished.disconnect(self.__onRunFinished)

        taskstate.cancel = cancel

        def run_image_scan_task_interupt():
            try:
                return task.run()
            except UserInterruptError:
                # Suppress interrupt errors, so they are not logged
                return

        taskstate.future = self.__executor.submit(run_image_scan_task_interupt)
        taskstate.watcher = FutureWatcher(taskstate.future)
        taskstate.watcher.finished.connect(self.__onRunFinished)

    @Slot()
    def __onRunFinished(self):
        assert QThread.currentThread() is self.thread()
        assert self.__state == State.Processing
        assert self.__pendingTask is not None
        assert self.sender() is self.__pendingTask.watcher
        assert self.__pendingTask.future.done()
        task = self.__pendingTask
        self.__pendingTask = None

        try:
            image_meta = task.future.result()
        except Exception as err:
            sys.excepthook(*sys.exc_info())
            state = State.Error
            image_meta = []
            self.error(traceback.format_exc())
        else:
            state = State.Done
            self.error()

        categories = {}

        for imeta in image_meta:
            # derive categories from the path relative to the starting dir
            dirname = os.path.dirname(imeta.path)
            relpath = os.path.relpath(dirname, task.startdir)
            categories[dirname] = relpath

        self._imageMeta = image_meta
        self._imageCategories = categories

        self.__setRuntimeState(state)
        self.commit()

    def cancel(self):
        """
        Cancel current pending task (if any).
        """
        if self.__state == State.Processing:
            assert self.__pendingTask is not None
            self.__pendingTask.cancel()
            self.__pendingTask = None
            self.__setRuntimeState(State.Cancelled)

    @Slot(object)
    def __onReportProgress(self, arg):
        # report on scan progress from a worker thread
        # arg must be a namespace(count: int, lastpath: str)
        assert QThread.currentThread() is self.thread()
        if self.__state == State.Processing:
            self.pathlabel.setText(prettyfypath(arg.lastpath))

    def commit(self):
        """
        Create and commit a Table from the collected image meta data.
        """
        if self._imageMeta:
            categories = self._imageCategories
            if len(categories) > 1:
                cat_var = Orange.data.DiscreteVariable(
                    "category", values=list(sorted(categories.values())))
            else:
                cat_var = None
            # Image name (file basename without the extension)
            imagename_var = Orange.data.StringVariable("image name")
            # Full fs path
            image_var = Orange.data.StringVariable("image")
            image_var.attributes["type"] = "image"
            # file size/width/height
            size_var = Orange.data.ContinuousVariable("size",
                                                      number_of_decimals=0)
            width_var = Orange.data.ContinuousVariable("width",
                                                       number_of_decimals=0)
            height_var = Orange.data.ContinuousVariable("height",
                                                        number_of_decimals=0)
            domain = Orange.data.Domain(
                [], [cat_var] if cat_var is not None else [],
                [imagename_var, image_var, size_var, width_var, height_var])
            cat_data = []
            meta_data = []

            for imgmeta in self._imageMeta:
                if imgmeta.isvalid:
                    if cat_var is not None:
                        category = categories.get(os.path.dirname(
                            imgmeta.path))
                        cat_data.append([cat_var.to_val(category)])
                    else:
                        cat_data.append([])
                    basename = os.path.basename(imgmeta.path)
                    imgname, _ = os.path.splitext(basename)

                    meta_data.append([
                        imgname, imgmeta.path, imgmeta.size, imgmeta.width,
                        imgmeta.height
                    ])

            cat_data = numpy.array(cat_data, dtype=float)
            meta_data = numpy.array(meta_data, dtype=object)
            table = Orange.data.Table.from_numpy(
                domain, numpy.empty((len(cat_data), 0), dtype=float), cat_data,
                meta_data)
        else:
            table = None

        self.send("Data", table)

    def onDeleteWidget(self):
        self.cancel()
        self.__executor.shutdown(wait=True)
Exemplo n.º 17
0
class TablaturePart(_base.Part):
    """Base class for tablature instrument part types."""
    
    octave = 0
    clef = None
    transposition = None
    tunings = ()    # may contain a list of tunings.
    tabFormat = ''  # can contain a tablatureFormat value.
    
    def createWidgets(self, layout):
        self.staffTypeLabel = QLabel()
        self.staffType = QComboBox()
        self.staffTypeLabel.setBuddy(self.staffType)
        self.staffType.setModel(listmodel.ListModel(tablatureStaffTypes,
            self.staffType, display=listmodel.translate))
        box = QHBoxLayout()
        layout.addLayout(box)
        box.addWidget(self.staffTypeLabel)
        box.addWidget(self.staffType)
        if self.tunings:
            self.createTuningWidgets(layout)
            self.staffType.activated.connect(self.slotTabEnable)
            self.slotTabEnable(0)
        
    def createTuningWidgets(self, layout):
        self.tuningLabel = QLabel()
        self.tuning = QComboBox()
        self.tuningLabel.setBuddy(self.tuning)
        tunings = [('', lambda: _("Default"))]
        tunings.extend(self.tunings)
        tunings.append(('', lambda: _("Custom tuning")))
        self.tuning.setModel(listmodel.ListModel(tunings, self.tuning,
            display=listmodel.translate_index(1)))
        self.tuning.setCurrentIndex(1)
        self.customTuning = QLineEdit(enabled=False)
        completionmodel.complete(self.customTuning,
            "scorewiz/completion/plucked_strings/custom_tuning")
        self.tuning.currentIndexChanged.connect(self.slotCustomTuningEnable)
        box = QHBoxLayout()
        layout.addLayout(box)
        box.addWidget(self.tuningLabel)
        box.addWidget(self.tuning)
        layout.addWidget(self.customTuning)
    
    def translateWidgets(self):
        self.staffTypeLabel.setText(_("Staff type:"))
        self.staffType.model().update()
        if self.tunings:
            self.translateTuningWidgets()
    
    def translateTuningWidgets(self):
        self.tuningLabel.setText(_("Tuning:"))
        self.customTuning.setToolTip('<qt>' + _(
            "Select custom tuning in the combobox and "
            "enter a custom tuning here, e.g. <code>e, a d g b e'</code>. "
            "Use absolute note names in the same language as you want to use "
            "in your document (by default: \"nederlands\")."))
        try:
            self.customTuning.setPlaceholderText(_("Custom tuning..."))
        except AttributeError:
            pass # only in Qt 4.7+
        self.tuning.model().update()
    
    def slotTabEnable(self, enable):
        """Called when the user changes the staff type.
        
        Non-zero if the user wants a TabStaff.
        
        """
        self.tuning.setEnabled(bool(enable))
        if enable:
            self.slotCustomTuningEnable(self.tuning.currentIndex())
        else:
            self.customTuning.setEnabled(False)
    
    def slotCustomTuningEnable(self, index):
        self.customTuning.setEnabled(index > len(self.tunings))
    
    def voiceCount(self):
        """Returns the number of voices.
        
        Inherit to make this user-settable.
        
        """
        return 1
        
    def build(self, data, builder):
        # First make assignments for the voices we want to create
        numVoices = self.voiceCount()
        if numVoices == 1:
            voices = (ly.util.mkid(data.name()),)
        elif numVoices == 2:
            order = 1, 2
            voices = 'upper', 'lower'
        elif numVoices == 3:
            order = 1, 3, 2
            voices = 'upper', 'middle', 'lower'
        else:
            order = 1, 2, 3, 4
            voices = [ly.util.mkid(data.name(), "voice") + ly.util.int2text(i) for i in order]
        
        assignments = [data.assignMusic(name, self.octave, self.transposition)
                       for name in voices]
        
        staffType = self.staffType.currentIndex()
        if staffType in (0, 2):
            # create a normal staff
            staff = ly.dom.Staff()
            seq = ly.dom.Seqr(staff)
            if self.clef:
                ly.dom.Clef(self.clef, seq)
            mus = ly.dom.Simr(seq)
            for a in assignments[:-1]:
                ly.dom.Identifier(a.name, mus)
                ly.dom.VoiceSeparator(mus)
            ly.dom.Identifier(assignments[-1].name, mus)
            builder.setMidiInstrument(staff, self.midiInstrument)
        
        if staffType in (1, 2):
            # create a tab staff
            tabstaff = ly.dom.TabStaff()
            if self.tabFormat:
                tabstaff.getWith()['tablatureFormat'] = ly.dom.Scheme(self.tabFormat)
            self.setTunings(tabstaff)
            sim = ly.dom.Simr(tabstaff)
            if numVoices == 1:
                ly.dom.Identifier(assignments[0].name, sim)
            else:
                for num, a in zip(order, assignments):
                    s = ly.dom.Seq(ly.dom.TabVoice(parent=sim))
                    ly.dom.Text('\\voice' + ly.util.int2text(num), s)
                    ly.dom.Identifier(a.name, s)
        
        if staffType == 0:
            # only a normal staff
            p = staff
        elif staffType == 1:
            # only a TabStaff
            builder.setMidiInstrument(tabstaff, self.midiInstrument)
            p = tabstaff
        else:
            # both TabStaff and normal staff
            p = ly.dom.StaffGroup()
            s = ly.dom.Sim(p)
            s.append(staff)
            s.append(tabstaff)
        
        builder.setInstrumentNamesFromPart(p, self, data)
        data.nodes.append(p)

    def setTunings(self, tab):
        if self.tunings:
            i = self.tuning.currentIndex()
            if i == 0:
                return
            elif i > len(self.tunings):
                value = ly.dom.Text("\\stringTuning <{0}>".format(self.customTuning.text()))
            else:
                tuning = self.tunings[self.tuning.currentIndex() - 1][0]
                value = ly.dom.Scheme(tuning)
            tab.getWith()['stringTunings'] = value
Exemplo n.º 18
0
class SvgView(QWidget):
    def __init__(self, dockwidget):
        super(SvgView, self).__init__(dockwidget)
        
        self._document = None
        self._setting_zoom = False
        
        self.view = view.View(self)
        
        self.pageLabel = QLabel()
        self.pageCombo = QComboBox(sizeAdjustPolicy=QComboBox.AdjustToContents)
		
        layout = QVBoxLayout(spacing=0)
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)
        hbox = QHBoxLayout(spacing=0)
        hbox.addWidget(self.pageLabel)
        hbox.addWidget(self.pageCombo)
        
        self.zoomInButton = QToolButton(autoRaise=True)
        self.zoomOutButton = QToolButton(autoRaise=True)
        self.zoomOriginalButton = QToolButton(autoRaise=True)
        self.zoomNumber = QSpinBox(minimum=10, maximum=1000, suffix='%')
        ac = dockwidget.actionCollection
        self.zoomInButton.setDefaultAction(ac.svg_zoom_in)
        self.zoomOutButton.setDefaultAction(ac.svg_zoom_out)
        self.zoomOriginalButton.setDefaultAction(ac.svg_zoom_original)
        hbox.addWidget(self.zoomInButton)
        hbox.addWidget(self.zoomNumber)
        hbox.addWidget(self.zoomOutButton)
        hbox.addWidget(self.zoomOriginalButton)
        
        self.resetButton = QPushButton("reload", self)
        self.resetButton.clicked.connect(self.reLoadDoc)
        hbox.addWidget(self.resetButton)
        
        self.saveButton = QPushButton("save edits", self)
        self.saveButton.clicked.connect(self.callSave)
        hbox.addWidget(self.saveButton)
        
        hbox.addStretch(1)
        layout.addLayout(hbox)
        layout.addWidget(self.view)
        
        app.jobFinished.connect(self.initSvg)
        app.documentClosed.connect(self.slotDocumentClosed)
        app.documentLoaded.connect(self.initSvg)
        self.pageCombo.currentIndexChanged.connect(self.changePage)
        self.zoomNumber.valueChanged.connect(self.slotZoomNumberChanged)
        self.view.zoomFactorChanged.connect(self.slotViewZoomChanged)
        dockwidget.mainwindow().currentDocumentChanged.connect(self.initSvg)
        self.zoomNumber.setValue(100)
        doc = dockwidget.mainwindow().currentDocument()
        if doc:
            self.initSvg(doc)
        app.translateUI(self)
    
    def translateUI(self):
        self.pageLabel.setText(_("Page:"))
        
    def mainwindow(self):
        return self.parent().mainwindow()       
        
    def initSvg(self, doc):
        """Opens first page of score after compilation"""
        if doc == self.mainwindow().currentDocument():
            files = svgfiles.SvgFiles.instance(doc)
            model = files.model() # forces update
            if files:
                self._document = doc
                with qutil.signalsBlocked(self.pageCombo):
                    self.pageCombo.setModel(model)
                    self.pageCombo.setCurrentIndex(files.current)
                self.view.load(files.url(files.current))
                
    def reLoadDoc(self):
        """Reloads current document."""
        if self._document:
            self.initSvg(self._document)
            
    def callSave(self):
        """Call save function"""
        self.view.evalSave()
		
    def getCurrent(self):
        files = svgfiles.SvgFiles.instance(self._document)
        return files.filename(files.current)
			
    def slotZoomNumberChanged(self, value):
        self._setting_zoom = True
        self.view.setZoomFactor(value / 100.0)
        self._setting_zoom = False
    
    def slotViewZoomChanged(self):
        if not self._setting_zoom:
            self.zoomNumber.setValue(int(self.view.zoomFactor() * 100))
    
    def changePage(self, page_index):
        """change page of score"""
        doc = self._document
        if doc:
            files = svgfiles.SvgFiles.instance(doc)
            if files:
                files.current = page_index
                svg = files.url(page_index)
                self.view.load(svg)
		
    def slotDocumentClosed(self, doc):
        if doc == self._document:
            self._document = None
            if self.pageCombo.model():
                self.pageCombo.model().deleteLater()
            self.pageCombo.clear()
            self.pageCombo.update() # otherwise it doesn't redraw
            self.view.clear()
Exemplo n.º 19
0
class Drums(_base.Part):
    @staticmethod
    def title(_=_base.translate):
        return _("Drums")
    
    @staticmethod
    def short(_=_base.translate):
        return _("abbreviation for Drums", "Dr.")
        
    def createWidgets(self, layout):
        self.voicesLabel = QLabel()
        self.voices = QSpinBox(minimum=1, maximum=4, value=1)
        self.drumStyleLabel = QLabel()
        self.drumStyle = QComboBox()
        self.drumStyle.setModel(listmodel.ListModel(drumStyles, self.drumStyle, display=listmodel.translate))
        self.drumStems = QCheckBox()
        
        box = QHBoxLayout()
        box.addWidget(self.voicesLabel)
        box.addWidget(self.voices)
        layout.addLayout(box)
        box = QHBoxLayout()
        box.addWidget(self.drumStyleLabel)
        box.addWidget(self.drumStyle)
        layout.addLayout(box)
        layout.addWidget(self.drumStems)
        
    def translateWidgets(self):
        self.voicesLabel.setText(_("Voices:"))
        self.drumStyleLabel.setText(_("Style:"))
        self.drumStems.setText(_("Remove stems"))
        self.drumStems.setToolTip(_("Remove the stems from the drum notes."))
        self.drumStyle.model().update()
    
    def assignDrums(self, data, name = None):
        """Creates an empty name = \drummode assignment.

        Returns the assignment.
        
        """
        a = data.assign(name)
        s = ly.dom.DrumMode(a)
        ly.dom.Identifier(data.globalName, s)
        ly.dom.LineComment(_("Drums follow here."), s)
        ly.dom.BlankLine(s)
        return a

    def build(self, data, builder):
        p = ly.dom.DrumStaff()
        s = ly.dom.Simr(p)
        if self.voices.value() > 1:
            for i in range(1, self.voices.value() + 1):
                q = ly.dom.Seq(ly.dom.DrumVoice(parent=s))
                ly.dom.Text('\\voice' + ly.util.int2text(i), q)
                a = self.assignDrums(data, 'drum' + ly.util.int2text(i))
                ly.dom.Identifier(a.name, q)
        else:
            a = self.assignDrums(data, 'drum')
            ly.dom.Identifier(a.name, s)
        builder.setInstrumentNamesFromPart(p, self, data)
        i = self.drumStyle.currentIndex()
        if i > 0:
            v = ('drums', 'timbales', 'congas', 'bongos', 'percussion')[i]
            p.getWith()['drumStyleTable'] = ly.dom.Scheme(v + '-style')
            v = (5, 2, 2, 2, 1)[i]
            ly.dom.Line("\\override StaffSymbol #'line-count = #{0}".format(v), p.getWith())
        if self.drumStems.isChecked():
            ly.dom.Line("\\override Stem #'stencil = ##f", p.getWith())
            ly.dom.Line("\\override Stem #'length = #3  % " + _("keep some distance."),
                p.getWith())
        data.nodes.append(p)