Пример #1
0
 def __init__(self, parent=None, fakeStartup=False, filename=None):
     '''
     Constructor
     '''
     self._fakeStartup = fakeStartup
     super(DrumBurp, self).__init__(parent)
     self._state = None
     self._asciiSettings = None
     self._printer = None
     self.setupUi(self)
     self.scoreScene = None
     self.paperBox.blockSignals(True)
     self.paperBox.clear()
     self._knownPageHeights = []
     printer = QPrinter()
     printer.setOutputFileName("invalid.pdf")
     for name in dir(QPrinter):
         attr = getattr(QPrinter, name)
         if (isinstance(attr, QPrinter.PageSize) and name != "Custom"):
             self.paperBox.addItem(name)
             printer.setPaperSize(attr)
             self._knownPageHeights.append(printer.pageRect().height())
     self._pageHeight = printer.paperRect().height()
     self.paperBox.blockSignals(False)
     settings = self._makeQSettings()
     self.recentFiles = [
         unicode(fname)
         for fname in settings.value("RecentFiles").toStringList()
         if os.path.exists(unicode(fname))
     ]
     if filename is None:
         filename = (None
                     if len(self.recentFiles) == 0 else self.recentFiles[0])
     self.filename = filename
     self.addToRecentFiles()
     self.updateRecentFiles()
     self.songProperties = QDisplayProperties()
     # Create scene
     self.scoreScene = QScore(self)
     self.restoreGeometry(settings.value("Geometry").toByteArray())
     self.restoreState(settings.value("MainWindow/State").toByteArray())
     self.statusbar.addPermanentWidget(QFrame())
     self.availableNotesLabel = QLabel()
     self.availableNotesLabel.setMinimumWidth(250)
     self.statusbar.addPermanentWidget(self.availableNotesLabel)
     self._infoBar = QLabel()
     self.statusbar.addPermanentWidget(self._infoBar)
     self._initializeState()
     self.setSections()
     QTimer.singleShot(0, self._startUp)
     self.actionCheckOnStartup.setChecked(
         settings.value("CheckOnStartup").toBool())
Пример #2
0
 def __init__(self, parent = None, fakeStartup = False, filename = None):
     '''
     Constructor
     '''
     self._fakeStartup = fakeStartup
     super(DrumBurp, self).__init__(parent)
     self._state = None
     self._asciiSettings = None
     self._printer = None
     self.setupUi(self)
     self.scoreScene = None
     self.paperBox.blockSignals(True)
     self.paperBox.clear()
     self._knownPageHeights = []
     printer = QPrinter()
     printer.setOutputFileName("invalid.pdf")
     for name in dir(QPrinter):
         attr = getattr(QPrinter, name)
         if (isinstance(attr, QPrinter.PageSize)
             and name != "Custom"):
             self.paperBox.addItem(name)
             printer.setPaperSize(attr)
             self._knownPageHeights.append(printer.pageRect().height())
     self._pageHeight = printer.paperRect().height()
     self.paperBox.blockSignals(False)
     settings = self._makeQSettings()
     self.recentFiles = [unicode(fname) for fname in
                         settings.value("RecentFiles").toStringList()
                         if os.path.exists(unicode(fname))]
     if filename is None:
         filename = (None
                     if len(self.recentFiles) == 0
                     else self.recentFiles[0])
     self.filename = filename
     self.addToRecentFiles()
     self.updateRecentFiles()
     self.songProperties = QDisplayProperties()
     # Create scene
     self.scoreScene = QScore(self)
     self.restoreGeometry(settings.value("Geometry").toByteArray())
     self.restoreState(settings.value("MainWindow/State").toByteArray())
     self.statusbar.addPermanentWidget(QFrame())
     self.availableNotesLabel = QLabel()
     self.availableNotesLabel.setMinimumWidth(250)
     self.statusbar.addPermanentWidget(self.availableNotesLabel)
     self._infoBar = QLabel()
     self.statusbar.addPermanentWidget(self._infoBar)
     self._initializeState()
     self.setSections()
     QTimer.singleShot(0, self._startUp)
     self.actionCheckOnStartup.setChecked(settings.value("CheckOnStartup").toBool())
Пример #3
0
class DrumBurp(QMainWindow, Ui_DrumBurpWindow):
    '''
    classdocs
    '''
    def __init__(self, parent=None, fakeStartup=False, filename=None):
        '''
        Constructor
        '''
        self._fakeStartup = fakeStartup
        super(DrumBurp, self).__init__(parent)
        self._state = None
        self._asciiSettings = None
        self._printer = None
        self.setupUi(self)
        self.scoreScene = None
        self.paperBox.blockSignals(True)
        self.paperBox.clear()
        self._knownPageHeights = []
        printer = QPrinter()
        printer.setOutputFileName("invalid.pdf")
        for name in dir(QPrinter):
            attr = getattr(QPrinter, name)
            if (isinstance(attr, QPrinter.PageSize) and name != "Custom"):
                self.paperBox.addItem(name)
                printer.setPaperSize(attr)
                self._knownPageHeights.append(printer.pageRect().height())
        self._pageHeight = printer.paperRect().height()
        self.paperBox.blockSignals(False)
        settings = self._makeQSettings()
        self.recentFiles = [
            unicode(fname)
            for fname in settings.value("RecentFiles").toStringList()
            if os.path.exists(unicode(fname))
        ]
        if filename is None:
            filename = (None
                        if len(self.recentFiles) == 0 else self.recentFiles[0])
        self.filename = filename
        self.addToRecentFiles()
        self.updateRecentFiles()
        self.songProperties = QDisplayProperties()
        # Create scene
        errored_files = []
        try:
            self.scoreScene = QScore(self)
        except:
            errored_files.append(self.filename)
            try:
                self.recentFiles.remove(self.filename)
            except ValueError:
                pass
            self.filename = None
            self.scoreScene = QScore(self)

        self.restoreGeometry(settings.value("Geometry").toByteArray())
        self.restoreState(settings.value("MainWindow/State").toByteArray())
        self.statusbar.addPermanentWidget(QFrame())
        self.availableNotesLabel = QLabel()
        self.availableNotesLabel.setMinimumWidth(250)
        self.statusbar.addPermanentWidget(self.availableNotesLabel)
        self._infoBar = QLabel()
        self.statusbar.addPermanentWidget(self._infoBar)
        self._initializeState()
        self.setSections()
        self._versionThread = VersionCheckThread()
        self._versionThread.finished.connect(self._finishedVersionCheck)
        QTimer.singleShot(0, lambda: self._startUp(errored_files))
        self.actionCheckOnStartup.setChecked(
            settings.value("CheckOnStartup").toBool())

    def _connectSignals(self, props, scene):
        # Connect signals
        props.fontChanged.connect(self._setNoteFont)
        props.noteSizeChanged.connect(self.noteSizeSpinBox.setValue)
        props.sectionFontChanged.connect(self._setSectionFont)
        props.sectionFontSizeChanged.connect(self._setSectionFontSize)
        props.metadataFontChanged.connect(self._setMetadataFont)
        props.metadataFontSizeChanged.connect(self._setMetadataSize)
        scene.dirtySignal.connect(self.setWindowModified)
        scene.dragHighlight.connect(self.actionLoopBars.setEnabled)
        scene.dragHighlight.connect(self.actionPlayOnce.setEnabled)
        scene.dragHighlight.connect(self.actionCopyMeasures.setEnabled)
        scene.dragHighlight.connect(self.checkPasteMeasure)
        scene.dragHighlight.connect(self.actionClearMeasures.setEnabled)
        scene.dragHighlight.connect(self.actionDeleteMeasures.setEnabled)
        scene.sceneFormatted.connect(self.sceneFormatted)
        scene.playing.connect(self._scorePlaying)
        scene.currentHeadsChanged.connect(self.availableNotesLabel.setText)
        scene.statusMessageSet.connect(self._setStatusFromScene)
        scene.lilysizeChanged.connect(self._setLilySize)
        scene.lilypagesChanged.connect(self._setLilyPages)
        scene.lilyFillChanged.connect(self._setLilyFill)
        self.paperBox.currentIndexChanged.connect(self._setPaperSize)
        props.kitDataVisibleChanged.connect(self._setKitDataVisible)
        props.emptyLinesVisibleChanged.connect(self._setEmptyLinesVisible)
        props.measureCountsVisibleChanged.connect(
            self._setMeasureCountsVisible)
        props.metadataVisibilityChanged.connect(self._setMetadataVisible)
        props.beatCountVisibleChanged.connect(self._setBeatCountVisible)
        DBMidi.SONGEND_SIGNAL.connect(self.musicDone)
        DBMidi.HIGHLIGHT_SIGNAL.connect(self.highlightPlayingMeasure)

    def _initializeState(self):
        props = self.songProperties
        scene = self.scoreScene
        self.scoreView.setScene(scene)
        self._connectSignals(props, scene)
        # Fonts
        self.fontComboBox.setWritingSystem(QFontDatabase.Latin)
        self.sectionFontCombo.setWritingSystem(QFontDatabase.Latin)
        self.sectionFontCombo.setWritingSystem(QFontDatabase.Latin)
        self.lineSpaceSlider.setValue(scene.systemSpacing)
        font = props.noteFont
        if font is None:
            font = scene.font()
        font.setPointSize(props.noteFontSize)
        self.fontComboBox.setCurrentFont(font)
        self.noteSizeSpinBox.setValue(props.noteFontSize)
        font = props.sectionFont
        if font is None:
            font = scene.font()
        font.setPointSize(props.sectionFontSize)
        self.sectionFontCombo.setCurrentFont(font)
        self.sectionFontSizeSpinbox.setValue(props.sectionFontSize)
        font = props.metadataFont
        if font is None:
            font = scene.font()
        font.setPointSize(props.metadataFontSize)
        self.metadataFontCombo.setCurrentFont(font)
        self.metadataFontSizeSpinbox.setValue(props.metadataFontSize)
        # Visibility toggles
        self.actionShowDrumKey.setChecked(props.kitDataVisible)
        self.actionShowEmptyLines.setChecked(props.emptyLinesVisible)
        self.actionShowScoreInfo.setChecked(props.metadataVisible)
        self.actionShowBeatCount.setChecked(props.beatCountVisible)
        self.actionShowMeasureCounts.setChecked(props.measureCountsVisible)
        # Set doable actions
        self.actionPlayOnce.setEnabled(False)
        self.actionLoopBars.setEnabled(False)
        self.actionCopyMeasures.setEnabled(False)
        self.actionPasteMeasures.setEnabled(False)
        self.actionFillPasteMeasures.setEnabled(False)
        self.actionClearMeasures.setEnabled(False)
        self.actionDeleteMeasures.setEnabled(False)
        self.MIDIToolBar.setEnabled(DBMidi.HAS_MIDI)
        # Undo/redo
        self.actionUndo.setEnabled(False)
        self.actionRedo.setEnabled(False)
        scene.canUndoChanged.connect(self.actionUndo.setEnabled)
        changeUndoText = lambda txt: self.actionUndo.setText("Undo " + txt)
        scene.undoTextChanged.connect(changeUndoText)
        scene.canRedoChanged.connect(self.actionRedo.setEnabled)
        changeRedoText = lambda txt: self.actionRedo.setText("Redo " + txt)
        scene.redoTextChanged.connect(changeRedoText)
        # Default beat
        self._beatChanged(scene.defaultCount)
        self.widthSpinBox.setValue(scene.scoreWidth)
        self.lilypondSize.setValue(scene.score.lilysize)
        self.lilyPagesBox.setValue(scene.score.lilypages)
        self.lilyFillButton.setChecked(scene.score.lilyFill)

    def _startUp(self, errored_files):
        self.scoreView.startUp()
        self.updateStatus("Welcome to %s v%s" % (APPNAME, DB_VERSION))
        self.scoreView.setFocus()
        if self.actionCheckOnStartup.isChecked():
            #             self.on_actionCheckForUpdates_triggered()
            self._versionThread.start()
        if errored_files:
            QMessageBox.warning(
                self, "Problem during startup",
                "Error opening files:\n %s" % "\n".join(errored_files))

    def _makeQSettings(self):
        if self._fakeStartup:
            return FakeQSettings()
        else:
            return QSettings()

    def _setPaperSize(self, unusedIndex):
        self.scoreScene.setPaperSize(self.paperBox.currentText())

    def _setNoteFont(self):
        props = self.songProperties
        self.fontComboBox.setCurrentFont(props.noteFont)

    def _setSectionFont(self):
        props = self.songProperties
        self.sectionFontCombo.setCurrentFont(props.sectionFont)

    def _setSectionFontSize(self):
        props = self.songProperties
        self.sectionFontSizeSpinbox.setValue(props.sectionFontSize)

    def _setMetadataFont(self):
        props = self.songProperties
        self.metadataFontCombo.setCurrentFont(props.metadataFont)

    def _setMetadataSize(self):
        props = self.songProperties
        self.metadataFontSizeSpinbox.setValue(props.metadataFontSize)

    def _setKitDataVisible(self):
        props = self.songProperties
        if props.kitDataVisible != self.actionShowDrumKey.isChecked():
            self.actionShowDrumKey.setChecked(props.kitDataVisible)

    def _setMetadataVisible(self):
        props = self.songProperties
        if props.metadataVisible != self.actionShowScoreInfo.isChecked():
            self.actionShowScoreInfo.setChecked(props.metadataVisible)

    def _setEmptyLinesVisible(self):
        props = self.songProperties
        if props.emptyLinesVisible != self.actionShowEmptyLines.isChecked():
            self.actionShowEmptyLines.setChecked(props.emptyLinesVisible)

    def _setBeatCountVisible(self):
        props = self.songProperties
        if props.beatCountVisible != self.actionShowBeatCount.isChecked():
            self.actionShowBeatCount.setChecked(props.beatCountVisible)

    def _setMeasureCountsVisible(self):
        props = self.songProperties
        if props.measureCountsVisible != self.actionShowMeasureCounts.isChecked(
        ):
            self.actionShowMeasureCounts.setChecked(props.measureCountsVisible)

    def updateStatus(self, message):
        self.statusBar().showMessage(message, 5000)
        if self.filename is not None:
            self.setWindowTitle("DrumBurp v%s - %s[*]" %
                                (DB_VERSION, os.path.basename(self.filename)))
        else:
            self.setWindowTitle("DrumBurp v%s - Untitled[*]" % DB_VERSION)
        self.setWindowModified(self.scoreScene.dirty)

    def okToContinue(self):
        if self.scoreScene.dirty:
            reply = QMessageBox.question(self, "DrumBurp - Unsaved Changes",
                                         "Save unsaved changes?",
                                         QMessageBox.Yes, QMessageBox.No,
                                         QMessageBox.Cancel)
            if reply == QMessageBox.Cancel:
                return False
            elif reply == QMessageBox.Yes:
                if not self.fileSave():
                    msg = ("DrumBurp could not save the file."
                           "\n\n"
                           "Continue anyway? "
                           "All unsaved changes will be lost!")
                    failReply = QMessageBox.warning(self, "Failed Save!", msg,
                                                    QMessageBox.Yes,
                                                    QMessageBox.No)
                    return failReply == QMessageBox.Yes
        return True

    def closeEvent(self, event):
        if self.okToContinue():
            settings = self._makeQSettings()
            settings.setValue("RecentFiles", QVariant(self.recentFiles))
            settings.setValue("Geometry", QVariant(self.saveGeometry()))
            settings.setValue("MainWindow/State", QVariant(self.saveState()))
            settings.setValue("CheckOnStartup",
                              QVariant(self.actionCheckOnStartup.isChecked()))
            self.songProperties.save(settings)
            self._versionThread.exit()
            self._versionThread.wait(1000)
            if not self._versionThread.isFinished():
                self._versionThread.terminate()
        else:
            event.ignore()

    @pyqtSignature("")
    def on_actionFitInWindow_triggered(self):
        widthInPixels = self.scoreView.width()
        maxColumns = self.songProperties.maxColumns(widthInPixels)
        self.widthSpinBox.setValue(maxColumns)
        self.scoreScene.reBuild()

    @pyqtSignature("")
    def on_actionLoad_triggered(self):
        if not self.okToContinue():
            return
        caption = "Choose a DrumBurp file to open"
        directory = self.filename
        if len(self.recentFiles) > 0:
            directory = os.path.dirname(self.recentFiles[-1])
        else:
            loc = QDesktopServices.HomeLocation
            directory = QDesktopServices.storageLocation(loc)
        fname = QFileDialog.getOpenFileName(parent=self,
                                            caption=caption,
                                            directory=directory,
                                            filter="DrumBurp files (*.brp)")
        if len(fname) == 0:
            return
        if self.scoreScene.loadScore(fname):
            self._beatChanged(self.scoreScene.defaultCount)
            self.lilypondSize.setValue(self.scoreScene.score.lilysize)
            self.lilyPagesBox.setValue(self.scoreScene.score.lilypages)
            self.filename = unicode(fname)
            self.updateStatus("Successfully loaded %s" % self.filename)
            self.addToRecentFiles()
            self.updateRecentFiles()

    def _getFileName(self):
        directory = self.filename
        if directory is None:
            suggestion = unicode(self.scoreScene.title)
            if len(suggestion) == 0:
                suggestion = "Untitled"
            suggestion = os.extsep.join([suggestion, "brp"])
            if len(self.recentFiles) > 0:
                directory = os.path.dirname(self.recentFiles[-1])
            else:
                home = QDesktopServices.HomeLocation
                directory = unicode(QDesktopServices.storageLocation(home))
            directory = os.path.join(directory, suggestion)
        if os.path.splitext(directory)[-1] == os.extsep + 'brp':
            directory = os.path.splitext(directory)[0]
        caption = "Choose a DrumBurp file to save"
        fname = QFileDialog.getSaveFileName(parent=self,
                                            caption=caption,
                                            directory=directory,
                                            filter="DrumBurp files (*.brp)")
        if len(fname) == 0:
            return False
        self.filename = unicode(fname)
        return True

    def fileSave(self):
        if self.filename is None:
            if not self._getFileName():
                return False
            self.addToRecentFiles()
            self.updateRecentFiles()
        return self.scoreScene.saveScore(self.filename)

    @pyqtSignature("")
    def on_actionSave_triggered(self):
        if self.fileSave():
            self.updateStatus("Successfully saved %s" % self.filename)

    @pyqtSignature("")
    def on_actionSaveAs_triggered(self):
        if self._getFileName():
            self.scoreScene.saveScore(self.filename)
            self.updateStatus("Successfully saved %s" % self.filename)
            self.addToRecentFiles()
            self.updateRecentFiles()

    @pyqtSignature("")
    def on_actionNew_triggered(self):
        if self.okToContinue():
            counter = self.scoreScene.defaultCount
            registry = self.songProperties.counterRegistry
            dialog = QNewScoreDialog(self, counter, registry)
            if dialog.exec_():
                nMeasures, counter, kit = dialog.getValues()
                self.scoreScene.newScore(kit,
                                         numMeasures=nMeasures,
                                         counter=counter)
                self.filename = None
                self.updateRecentFiles()
                self._beatChanged(counter)
                self.updateStatus("Created a new blank score")

    def addToRecentFiles(self):
        if self.filename is not None:
            if self.filename in self.recentFiles:
                self.recentFiles.remove(self.filename)
            self.recentFiles.insert(0, self.filename)
            if len(self.recentFiles) > 10:
                self.recentFiles.pop()

    def updateRecentFiles(self):
        self.menuRecentScores.clear()
        for fname in self.recentFiles:
            if fname != self.filename and os.path.exists(fname):

                def openRecentFile(bool_, filename=fname):
                    if not self.okToContinue():
                        return
                    if self.scoreScene.loadScore(filename):
                        self.filename = filename
                        self.updateStatus("Successfully loaded %s" % filename)
                        self.addToRecentFiles()
                        self.updateRecentFiles()

                action = self.menuRecentScores.addAction(fname)
                action.setIcon(DBIcons.getIcon("score"))
                action.triggered.connect(openRecentFile)

    def _beatChanged(self, counter):
        if counter != self.scoreScene.defaultCount:
            self.scoreScene.defaultCount = counter
        self.defaultMeasureButton.setText(counter.countString())

    def _systemSpacingChanged(self, value):
        if value != self.scoreScene.systemSpacing:
            self.scoreScene.systemSpacing = value
        self.lineSpaceSlider.setValue(value)

    def hideEvent(self, event):
        self._state = self.saveState()
        super(DrumBurp, self).hideEvent(event)

    def showEvent(self, event):
        if self._state is not None:
            self.restoreState(self._state)
            self._state = None
        super(DrumBurp, self).showEvent(event)

    @pyqtSignature("")
    def on_actionExportASCII_triggered(self):
        fname = self.filename
        if self.filename is None:
            home = QDesktopServices.HomeLocation
            fname = QDesktopServices.storageLocation(home)
            fname = os.path.join(str(fname), 'Untitled.txt')
        if os.path.splitext(fname)[-1] == '.brp':
            fname = os.path.splitext(fname)[0] + '.txt'
        props = self.songProperties
        self._asciiSettings = props.generateAsciiSettings(self._asciiSettings)
        asciiDialog = QAsciiExportDialog(fname,
                                         parent=self,
                                         settings=self._asciiSettings)
        if not asciiDialog.exec_():
            return
        fname = asciiDialog.getFilename()
        self._asciiSettings = asciiDialog.getOptions()
        try:
            asciiBuffer = StringIO()
            exporter = AsciiExport.Exporter(self.scoreScene.score,
                                            self._asciiSettings)
            exporter.export(asciiBuffer)
        except StandardError:
            QMessageBox.warning(self.parent(), "ASCII generation failed!",
                                "Could not generate ASCII for this score!")
            raise
        try:
            with open(fname, 'w') as txtHandle:
                txtHandle.write(asciiBuffer.getvalue())
        except StandardError:
            QMessageBox.warning(self.parent(), "Export failed!",
                                "Could not export to " + fname)
            raise
        else:
            self.updateStatus("Successfully exported ASCII to " + fname)

    @pyqtSignature("")
    def on_actionPrint_triggered(self):
        if self._printer is None:
            self._printer = QPrinter()
        self._printer = QPrinter(QPrinterInfo(self._printer),
                                 QPrinter.HighResolution)
        self._printer.setPaperSize(self._getPaperSize())
        dialog = QPrintPreviewDialog(self._printer, parent=self)

        def updatePages(qprinter):
            self.scoreScene.printScore(qprinter, self.scoreView)

        dialog.paintRequested.connect(updatePages)
        dialog.exec_()

    @pyqtSignature("")
    def on_actionExportPDF_triggered(self):
        try:
            printer = QPrinter(mode=QPrinter.HighResolution)
            printer.setPaperSize(self._getPaperSize())
            printer.setOutputFormat(QPrinter.PdfFormat)
            if self.filename:
                outfileName = list(os.path.splitext(self.filename)[:-1])
                outfileName = os.extsep.join(outfileName + ["pdf"])
            else:
                outfileName = "Untitled.pdf"
            printer.setOutputFileName(outfileName)
            printer.setPaperSize(self._getPaperSize())
            dialog = QPrintPreviewDialog(printer, parent=self)

            def updatePages(qprinter):
                self.scoreScene.printScore(qprinter, self.scoreView)

            dialog.paintRequested.connect(updatePages)
            dialog.exec_()
            self.updateStatus("Exported to PDF %s" % outfileName)
        except StandardError:
            QMessageBox.warning(self.parent(), "Export failed!",
                                "Could not export PDF to " + outfileName)

    @pyqtSignature("")
    def on_actionExportLilypond_triggered(self):
        lilyBuffer = StringIO()
        try:
            lyScore = LilypondScore(self.scoreScene.score)
            lyScore.write(lilyBuffer)
        except LilypondProblem, exc:
            QMessageBox.warning(
                self.parent(), "Lilypond impossible",
                "Cannot export Lilypond for this score: %s" % exc.__doc__)
        except StandardError, exc:
            QMessageBox.warning(
                self.parent(), "Export failed!",
                "Error generating Lilypond for this score: %s" % exc.__doc__)
            raise
Пример #4
0
class DrumBurp(QMainWindow, Ui_DrumBurpWindow):
    '''
    classdocs
    '''

    def __init__(self, parent = None, fakeStartup = False, filename = None):
        '''
        Constructor
        '''
        self._fakeStartup = fakeStartup
        super(DrumBurp, self).__init__(parent)
        self._state = None
        self._asciiSettings = None
        self._printer = None
        self.setupUi(self)
        self.scoreScene = None
        self.paperBox.blockSignals(True)
        self.paperBox.clear()
        self._knownPageHeights = []
        printer = QPrinter()
        printer.setOutputFileName("invalid.pdf")
        for name in dir(QPrinter):
            attr = getattr(QPrinter, name)
            if (isinstance(attr, QPrinter.PageSize)
                and name != "Custom"):
                self.paperBox.addItem(name)
                printer.setPaperSize(attr)
                self._knownPageHeights.append(printer.pageRect().height())
        self._pageHeight = printer.paperRect().height()
        self.paperBox.blockSignals(False)
        settings = self._makeQSettings()
        self.recentFiles = [unicode(fname) for fname in
                            settings.value("RecentFiles").toStringList()
                            if os.path.exists(unicode(fname))]
        if filename is None:
            filename = (None
                        if len(self.recentFiles) == 0
                        else self.recentFiles[0])
        self.filename = filename
        self.addToRecentFiles()
        self.updateRecentFiles()
        self.songProperties = QDisplayProperties()
        # Create scene
        self.scoreScene = QScore(self)
        self.restoreGeometry(settings.value("Geometry").toByteArray())
        self.restoreState(settings.value("MainWindow/State").toByteArray())
        self.statusbar.addPermanentWidget(QFrame())
        self.availableNotesLabel = QLabel()
        self.availableNotesLabel.setMinimumWidth(250)
        self.statusbar.addPermanentWidget(self.availableNotesLabel)
        self._infoBar = QLabel()
        self.statusbar.addPermanentWidget(self._infoBar)
        self._initializeState()
        self.setSections()
        QTimer.singleShot(0, self._startUp)
        self.actionCheckOnStartup.setChecked(settings.value("CheckOnStartup").toBool())

    def _connectSignals(self, props, scene):
        # Connect signals
        props.fontChanged.connect(self._setNoteFont)
        props.noteSizeChanged.connect(self.noteSizeSpinBox.setValue)
        props.sectionFontChanged.connect(self._setSectionFont)
        props.sectionFontSizeChanged.connect(self._setSectionFontSize)
        props.metadataFontChanged.connect(self._setMetadataFont)
        props.metadataFontSizeChanged.connect(self._setMetadataSize)
        scene.dirtySignal.connect(self.setWindowModified)
        scene.dragHighlight.connect(self.actionLoopBars.setEnabled)
        scene.dragHighlight.connect(self.actionPlayOnce.setEnabled)
        scene.dragHighlight.connect(self.actionCopyMeasures.setEnabled)
        scene.dragHighlight.connect(self.checkPasteMeasure)
        scene.dragHighlight.connect(self.actionClearMeasures.setEnabled)
        scene.dragHighlight.connect(self.actionDeleteMeasures.setEnabled)
        scene.sceneFormatted.connect(self.sceneFormatted)
        scene.playing.connect(self._scorePlaying)
        scene.currentHeadsChanged.connect(self.availableNotesLabel.setText)
        scene.statusMessageSet.connect(self._setStatusFromScene)
        scene.lilysizeChanged.connect(self._setLilySize)
        scene.lilypagesChanged.connect(self._setLilyPages)
        scene.lilyFillChanged.connect(self._setLilyFill)
        self.paperBox.currentIndexChanged.connect(self._setPaperSize)
        props.kitDataVisibleChanged.connect(self._setKitDataVisible)
        props.emptyLinesVisibleChanged.connect(self._setEmptyLinesVisible)
        props.measureCountsVisibleChanged.connect(self._setMeasureCountsVisible)
        props.metadataVisibilityChanged.connect(self._setMetadataVisible)
        props.beatCountVisibleChanged.connect(self._setBeatCountVisible)
        DBMidi.SONGEND_SIGNAL.connect(self.musicDone)
        DBMidi.HIGHLIGHT_SIGNAL.connect(self.highlightPlayingMeasure)

    def _initializeState(self):
        props = self.songProperties
        scene = self.scoreScene
        self.scoreView.setScene(scene)
        self._connectSignals(props, scene)
        # Fonts
        self.fontComboBox.setWritingSystem(QFontDatabase.Latin)
        self.sectionFontCombo.setWritingSystem(QFontDatabase.Latin)
        self.sectionFontCombo.setWritingSystem(QFontDatabase.Latin)
        self.lineSpaceSlider.setValue(scene.systemSpacing)
        font = props.noteFont
        if font is None:
            font = scene.font()
        font.setPointSize(props.noteFontSize)
        self.fontComboBox.setCurrentFont(font)
        self.noteSizeSpinBox.setValue(props.noteFontSize)
        font = props.sectionFont
        if font is None:
            font = scene.font()
        font.setPointSize(props.sectionFontSize)
        self.sectionFontCombo.setCurrentFont(font)
        self.sectionFontSizeSpinbox.setValue(props.sectionFontSize)
        font = props.metadataFont
        if font is None:
            font = scene.font()
        font.setPointSize(props.metadataFontSize)
        self.metadataFontCombo.setCurrentFont(font)
        self.metadataFontSizeSpinbox.setValue(props.metadataFontSize)
        # Visibility toggles
        self.actionShowDrumKey.setChecked(props.kitDataVisible)
        self.actionShowEmptyLines.setChecked(props.emptyLinesVisible)
        self.actionShowScoreInfo.setChecked(props.metadataVisible)
        self.actionShowBeatCount.setChecked(props.beatCountVisible)
        self.actionShowMeasureCounts.setChecked(props.measureCountsVisible)
        # Set doable actions
        self.actionPlayOnce.setEnabled(False)
        self.actionLoopBars.setEnabled(False)
        self.actionCopyMeasures.setEnabled(False)
        self.actionPasteMeasures.setEnabled(False)
        self.actionFillPasteMeasures.setEnabled(False)
        self.actionClearMeasures.setEnabled(False)
        self.actionDeleteMeasures.setEnabled(False)
        self.MIDIToolBar.setEnabled(DBMidi.HAS_MIDI)
        # Undo/redo
        self.actionUndo.setEnabled(False)
        self.actionRedo.setEnabled(False)
        scene.canUndoChanged.connect(self.actionUndo.setEnabled)
        changeUndoText = lambda txt:self.actionUndo.setText("Undo " + txt)
        scene.undoTextChanged.connect(changeUndoText)
        scene.canRedoChanged.connect(self.actionRedo.setEnabled)
        changeRedoText = lambda txt:self.actionRedo.setText("Redo " + txt)
        scene.redoTextChanged.connect(changeRedoText)
        # Default beat
        self._beatChanged(scene.defaultCount)
        self.widthSpinBox.setValue(scene.scoreWidth)
        self.lilypondSize.setValue(scene.score.lilysize)
        self.lilyPagesBox.setValue(scene.score.lilypages)
        self.lilyFillButton.setChecked(scene.score.lilyFill)


    def _startUp(self):
        self.scoreView.startUp()
        self.updateStatus("Welcome to %s v%s" % (APPNAME, DB_VERSION))
        self.scoreView.setFocus()
        if self.actionCheckOnStartup.isChecked():
            self.on_actionCheckForUpdates_triggered()


    def _makeQSettings(self):
        if self._fakeStartup:
            return FakeQSettings()
        else:
            return QSettings()

    def _setPaperSize(self, unusedIndex):
        self.scoreScene.setPaperSize(self.paperBox.currentText())

    def _setNoteFont(self):
        props = self.songProperties
        self.fontComboBox.setCurrentFont(props.noteFont)

    def _setSectionFont(self):
        props = self.songProperties
        self.sectionFontCombo.setCurrentFont(props.sectionFont)

    def _setSectionFontSize(self):
        props = self.songProperties
        self.sectionFontSizeSpinbox.setValue(props.sectionFontSize)

    def _setMetadataFont(self):
        props = self.songProperties
        self.metadataFontCombo.setCurrentFont(props.metadataFont)

    def _setMetadataSize(self):
        props = self.songProperties
        self.metadataFontSizeSpinbox.setValue(props.metadataFontSize)

    def _setKitDataVisible(self):
        props = self.songProperties
        if props.kitDataVisible != self.actionShowDrumKey.isChecked():
            self.actionShowDrumKey.setChecked(props.kitDataVisible)

    def _setMetadataVisible(self):
        props = self.songProperties
        if props.metadataVisible != self.actionShowScoreInfo.isChecked():
            self.actionShowScoreInfo.setChecked(props.metadataVisible)

    def _setEmptyLinesVisible(self):
        props = self.songProperties
        if props.emptyLinesVisible != self.actionShowEmptyLines.isChecked():
            self.actionShowEmptyLines.setChecked(props.emptyLinesVisible)

    def _setBeatCountVisible(self):
        props = self.songProperties
        if props.beatCountVisible != self.actionShowBeatCount.isChecked():
            self.actionShowBeatCount.setChecked(props.beatCountVisible)

    def _setMeasureCountsVisible(self):
        props = self.songProperties
        if props.measureCountsVisible != self.actionShowMeasureCounts.isChecked():
            self.actionShowMeasureCounts.setChecked(props.measureCountsVisible)

    def updateStatus(self, message):
        self.statusBar().showMessage(message, 5000)
        if self.filename is not None:
            self.setWindowTitle("DrumBurp v%s - %s[*]"
                                % (DB_VERSION, os.path.basename(self.filename)))
        else:
            self.setWindowTitle("DrumBurp v%s - Untitled[*]" % DB_VERSION)
        self.setWindowModified(self.scoreScene.dirty)

    def okToContinue(self):
        if self.scoreScene.dirty:
            reply = QMessageBox.question(self,
                                         "DrumBurp - Unsaved Changes",
                                         "Save unsaved changes?",
                                         QMessageBox.Yes,
                                         QMessageBox.No,
                                         QMessageBox.Cancel)
            if reply == QMessageBox.Cancel:
                return False
            elif reply == QMessageBox.Yes:
                if not self.fileSave():
                    msg = ("DrumBurp could not save the file."
                           "\n\n"
                           "Continue anyway? "
                           "All unsaved changes will be lost!")
                    failReply = QMessageBox.warning(self,
                                                    "Failed Save!",
                                                    msg,
                                                    QMessageBox.Yes,
                                                    QMessageBox.No)
                    return failReply == QMessageBox.Yes
        return True

    def closeEvent(self, event):
        if self.okToContinue():
            settings = self._makeQSettings()
            settings.setValue("RecentFiles",
                              QVariant(self.recentFiles))
            settings.setValue("Geometry",
                              QVariant(self.saveGeometry()))
            settings.setValue("MainWindow/State",
                              QVariant(self.saveState()))
            settings.setValue("CheckOnStartup",
                              QVariant(self.actionCheckOnStartup.isChecked()))
            self.songProperties.save(settings)
        else:
            event.ignore()

    @pyqtSignature("")
    def on_actionFitInWindow_triggered(self):
        widthInPixels = self.scoreView.width()
        maxColumns = self.songProperties.maxColumns(widthInPixels)
        self.widthSpinBox.setValue(maxColumns)
        self.scoreScene.reBuild()

    @pyqtSignature("")
    def on_actionLoad_triggered(self):
        if not self.okToContinue():
            return
        caption = "Choose a DrumBurp file to open"
        directory = self.filename
        if len(self.recentFiles) > 0:
            directory = os.path.dirname(self.recentFiles[-1])
        else:
            loc = QDesktopServices.HomeLocation
            directory = QDesktopServices.storageLocation(loc)
        fname = QFileDialog.getOpenFileName(parent = self,
                                            caption = caption,
                                            directory = directory,
                                            filter = "DrumBurp files (*.brp)")
        if len(fname) == 0:
            return
        if self.scoreScene.loadScore(fname):
            self._beatChanged(self.scoreScene.defaultCount)
            self.lilypondSize.setValue(self.scoreScene.score.lilysize)
            self.lilyPagesBox.setValue(self.scoreScene.score.lilypages)
            self.filename = unicode(fname)
            self.updateStatus("Successfully loaded %s" % self.filename)
            self.addToRecentFiles()
            self.updateRecentFiles()

    def _getFileName(self):
        directory = self.filename
        if directory is None:
            suggestion = unicode(self.scoreScene.title)
            if len(suggestion) == 0:
                suggestion = "Untitled"
            suggestion = os.extsep.join([suggestion, "brp"])
            if len(self.recentFiles) > 0:
                directory = os.path.dirname(self.recentFiles[-1])
            else:
                home = QDesktopServices.HomeLocation
                directory = unicode(QDesktopServices.storageLocation(home))
            directory = os.path.join(directory,
                                     suggestion)
        if os.path.splitext(directory)[-1] == os.extsep + 'brp':
            directory = os.path.splitext(directory)[0]
        caption = "Choose a DrumBurp file to save"
        fname = QFileDialog.getSaveFileName(parent = self,
                                            caption = caption,
                                            directory = directory,
                                            filter = "DrumBurp files (*.brp)")
        if len(fname) == 0 :
            return False
        self.filename = unicode(fname)
        return True

    def fileSave(self):
        if self.filename is None:
            if not self._getFileName():
                return False
            self.addToRecentFiles()
            self.updateRecentFiles()
        return self.scoreScene.saveScore(self.filename)

    @pyqtSignature("")
    def on_actionSave_triggered(self):
        if self.fileSave():
            self.updateStatus("Successfully saved %s" % self.filename)

    @pyqtSignature("")
    def on_actionSaveAs_triggered(self):
        if self._getFileName():
            self.scoreScene.saveScore(self.filename)
            self.updateStatus("Successfully saved %s" % self.filename)
            self.addToRecentFiles()
            self.updateRecentFiles()

    @pyqtSignature("")
    def on_actionNew_triggered(self):
        if self.okToContinue():
            counter = self.scoreScene.defaultCount
            registry = self.songProperties.counterRegistry
            dialog = QNewScoreDialog(self,
                                     counter,
                                     registry)
            if dialog.exec_():
                nMeasures, counter, kit = dialog.getValues()
                self.scoreScene.newScore(kit,
                                         numMeasures = nMeasures,
                                         counter = counter)
                self.filename = None
                self.updateRecentFiles()
                self._beatChanged(counter)
                self.updateStatus("Created a new blank score")

    def addToRecentFiles(self):
        if self.filename is not None:
            if self.filename in self.recentFiles:
                self.recentFiles.remove(self.filename)
            self.recentFiles.insert(0, self.filename)
            if len(self.recentFiles) > 10:
                self.recentFiles.pop()

    def updateRecentFiles(self):
        self.menuRecentScores.clear()
        for fname in self.recentFiles:
            if fname != self.filename and os.path.exists(fname):
                def openRecentFile(bool_, filename = fname):
                    if not self.okToContinue():
                        return
                    if self.scoreScene.loadScore(filename):
                        self.filename = filename
                        self.updateStatus("Successfully loaded %s" % filename)
                        self.addToRecentFiles()
                        self.updateRecentFiles()
                action = self.menuRecentScores.addAction(fname)
                action.setIcon(DBIcons.getIcon("score"))
                action.triggered.connect(openRecentFile)

    def _beatChanged(self, counter):
        if counter != self.scoreScene.defaultCount:
            self.scoreScene.defaultCount = counter
        self.defaultMeasureButton.setText(counter.countString())

    def _systemSpacingChanged(self, value):
        if value != self.scoreScene.systemSpacing:
            self.scoreScene.systemSpacing = value
        self.lineSpaceSlider.setValue(value)

    def hideEvent(self, event):
        self._state = self.saveState()
        super(DrumBurp, self).hideEvent(event)

    def showEvent(self, event):
        if self._state is not None:
            self.restoreState(self._state)
            self._state = None
        super(DrumBurp, self).showEvent(event)

    @pyqtSignature("")
    def on_actionExportASCII_triggered(self):
        fname = self.filename
        if self.filename is None:
            home = QDesktopServices.HomeLocation
            fname = QDesktopServices.storageLocation(home)
            fname = os.path.join(str(fname), 'Untitled.txt')
        if os.path.splitext(fname)[-1] == '.brp':
            fname = os.path.splitext(fname)[0] + '.txt'
        props = self.songProperties
        self._asciiSettings = props.generateAsciiSettings(self._asciiSettings)
        asciiDialog = QAsciiExportDialog(fname, parent = self,
                                         settings = self._asciiSettings)
        if not asciiDialog.exec_():
            return
        fname = asciiDialog.getFilename()
        self._asciiSettings = asciiDialog.getOptions()
        try:
            asciiBuffer = StringIO()
            exporter = AsciiExport.Exporter(self.scoreScene.score,
                                            self._asciiSettings)
            exporter.export(asciiBuffer)
        except StandardError:
            QMessageBox.warning(self.parent(), "ASCII generation failed!",
                                "Could not generate ASCII for this score!")
            raise
        try:
            with open(fname, 'w') as txtHandle:
                txtHandle.write(asciiBuffer.getvalue())
        except StandardError:
            QMessageBox.warning(self.parent(), "Export failed!",
                                "Could not export to " + fname)
            raise
        else:
            self.updateStatus("Successfully exported ASCII to " + fname)

    @pyqtSignature("")
    def on_actionPrint_triggered(self):
        if self._printer is None:
            self._printer = QPrinter()
        self._printer = QPrinter(QPrinterInfo(self._printer),
                                 QPrinter.HighResolution)
        self._printer.setPaperSize(self._getPaperSize())
        dialog = QPrintPreviewDialog(self._printer, parent = self)
        def updatePages(qprinter):
            self.scoreScene.printScore(qprinter, self.scoreView)
        dialog.paintRequested.connect(updatePages)
        dialog.exec_()

    @pyqtSignature("")
    def on_actionExportPDF_triggered(self):
        try:
            printer = QPrinter(mode = QPrinter.HighResolution)
            printer.setPaperSize(self._getPaperSize())
            printer.setOutputFormat(QPrinter.PdfFormat)
            if self.filename:
                outfileName = list(os.path.splitext(self.filename)[:-1])
                outfileName = os.extsep.join(outfileName + ["pdf"])
            else:
                outfileName = "Untitled.pdf"
            printer.setOutputFileName(outfileName)
            printer.setPaperSize(self._getPaperSize())
            dialog = QPrintPreviewDialog(printer, parent = self)
            def updatePages(qprinter):
                self.scoreScene.printScore(qprinter, self.scoreView)
            dialog.paintRequested.connect(updatePages)
            dialog.exec_()
            self.updateStatus("Exported to PDF %s" % outfileName)
        except StandardError:
            QMessageBox.warning(self.parent(), "Export failed!",
                                "Could not export PDF to " + outfileName)

    @pyqtSignature("")
    def on_actionExportLilypond_triggered(self):
        lilyBuffer = StringIO()
        try:
            lyScore = LilypondScore(self.scoreScene.score)
            lyScore.write(lilyBuffer)
        except LilypondProblem, exc:
            QMessageBox.warning(self.parent(), "Lilypond impossible",
                                "Cannot export Lilypond for this score: %s"
                                % exc.__doc__)
        except StandardError, exc:
            QMessageBox.warning(self.parent(), "Export failed!",
                                "Error generating Lilypond for this score: %s"
                                % exc.__doc__)
            raise