diff --git a/include/DataFile.h b/include/DataFile.h index 5d6ead5adb3..f7e5e612a9b 100644 --- a/include/DataFile.h +++ b/include/DataFile.h @@ -52,6 +52,7 @@ class LMMS_EXPORT DataFile : public QDomDocument ClipboardData, JournalData, EffectSettings, + NotePattern, TypeCount } ; typedef Types Type; diff --git a/include/PianoRoll.h b/include/PianoRoll.h index 5e0ea0762c9..0ec57f35ffe 100644 --- a/include/PianoRoll.h +++ b/include/PianoRoll.h @@ -47,6 +47,7 @@ class QPixmap; class QScrollBar; class QString; class QMenu; +class QToolButton; class ComboBox; class NotePlayHandle; @@ -497,6 +498,8 @@ class PianoRollWindow : public Editor, SerializingObject private slots: void updateAfterPatternChange(); void ghostPatternSet( bool state ); + void exportPattern(); + void importPattern(); private: void patternRenamed(); @@ -506,6 +509,7 @@ private slots: PianoRoll* m_editor; + QToolButton* m_fileToolsButton; ComboBox * m_zoomingComboBox; ComboBox * m_zoomingYComboBox; ComboBox * m_quantizeComboBox; diff --git a/src/core/DataFile.cpp b/src/core/DataFile.cpp index 9dc413566d7..ab83cd7934c 100644 --- a/src/core/DataFile.cpp +++ b/src/core/DataFile.cpp @@ -82,7 +82,8 @@ DataFile::typeDescStruct { DataFile::DragNDropData, "dnddata" }, { DataFile::ClipboardData, "clipboard-data" }, { DataFile::JournalData, "journaldata" }, - { DataFile::EffectSettings, "effectsettings" } + { DataFile::EffectSettings, "effectsettings" }, + { DataFile::NotePattern, "pattern" } } ; @@ -184,6 +185,12 @@ bool DataFile::validate( QString extension ) return true; } break; + case Type::NotePattern: + if (extension == "xpt" || extension == "xptz") + { + return true; + } + break; case Type::UnknownType: if (! ( extension == "mmp" || extension == "mpt" || extension == "mmpz" || extension == "xpf" || extension == "xml" || @@ -285,7 +292,8 @@ bool DataFile::writeFile( const QString& filename ) return false; } - if( fullName.section( '.', -1 ) == "mmpz" ) + const QString extension = fullName.section('.', -1); + if (extension == "mmpz" || extension == "xptz") { QString xml; QTextStream ts( &xml ); diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index cee6870b7a3..97307f1628e 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,7 @@ #include "StepRecorderWidget.h" #include "TextFloat.h" #include "TimeLineWidget.h" +#include "FileDialog.h" using std::move; @@ -4403,6 +4405,29 @@ PianoRollWindow::PianoRollWindow() : notesActionsToolBar->addSeparator(); notesActionsToolBar->addAction( quantizeAction ); + // -- File actions + DropToolBar* fileActionsToolBar = addDropToolBarToTop(tr("File actions")); + + // -- File ToolButton + m_fileToolsButton = new QToolButton(m_toolBar); + m_fileToolsButton->setIcon(embed::getIconPixmap("file")); + m_fileToolsButton->setPopupMode(QToolButton::InstantPopup); + + // Import / export + QAction* importAction = new QAction(embed::getIconPixmap("project_import"), + tr("Import pattern"), m_fileToolsButton); + + QAction* exportAction = new QAction(embed::getIconPixmap("project_export"), + tr("Export pattern"), m_fileToolsButton); + + m_fileToolsButton->addAction(importAction); + m_fileToolsButton->addAction(exportAction); + fileActionsToolBar->addWidget(m_fileToolsButton); + + connect(importAction, SIGNAL(triggered()), this, SLOT(importPattern())); + connect(exportAction, SIGNAL(triggered()), this, SLOT(exportPattern())); + // -- End File actions + // Copy + paste actions DropToolBar *copyPasteActionsToolBar = addDropToolBarToTop( tr( "Copy paste controls" ) ); @@ -4614,12 +4639,14 @@ void PianoRollWindow::setCurrentPattern( Pattern* pattern ) if ( pattern ) { setWindowTitle( tr( "Piano-Roll - %1" ).arg( pattern->name() ) ); + m_fileToolsButton->setEnabled(true); connect( pattern->instrumentTrack(), SIGNAL( nameChanged() ), this, SLOT( updateAfterPatternChange()) ); connect( pattern, SIGNAL( dataChanged() ), this, SLOT( updateAfterPatternChange() ) ); } else { setWindowTitle( tr( "Piano-Roll - no pattern" ) ); + m_fileToolsButton->setEnabled(false); } } @@ -4785,10 +4812,12 @@ void PianoRollWindow::patternRenamed() if ( currentPattern() ) { setWindowTitle( tr( "Piano-Roll - %1" ).arg( currentPattern()->name() ) ); + m_fileToolsButton->setEnabled(true); } else { setWindowTitle( tr( "Piano-Roll - no pattern" ) ); + m_fileToolsButton->setEnabled(false); } } @@ -4803,6 +4832,84 @@ void PianoRollWindow::ghostPatternSet( bool state ) +void PianoRollWindow::exportPattern() +{ + FileDialog exportDialog(this, tr("Export pattern"), "", + tr("XML pattern file (*.xpt *.xptz)")); + + exportDialog.setAcceptMode(FileDialog::AcceptSave); + + if (exportDialog.exec() == QDialog::Accepted && + !exportDialog.selectedFiles().isEmpty() && + !exportDialog.selectedFiles().first().isEmpty()) + { + QString suffix = + ConfigManager::inst()->value("app", "nommpz").toInt() == 0 + ? "xptz" + : "xpt"; + exportDialog.setDefaultSuffix(suffix); + + const QString fullPath = exportDialog.selectedFiles()[0]; + DataFile dataFile(DataFile::NotePattern); + m_editor->m_pattern->saveSettings(dataFile, dataFile.content()); + + if (dataFile.writeFile(fullPath)) + { + TextFloat::displayMessage(tr("Export pattern success"), + tr("Pattern saved to %1").arg(fullPath), + embed::getIconPixmap("project_export"), 4000); + } + } +} + + + + +void PianoRollWindow::importPattern() +{ + // Overwrite confirmation. + if (!m_editor->m_pattern->empty() && + QMessageBox::warning( + NULL, + tr("Import pattern."), + tr("You are about to import a pattern, this will " + "overwrite your current pattern. Do you want to " + "continue?"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes + ) != QMessageBox::Yes) + { + return; + } + + FileDialog importDialog(this, tr("Open pattern"), "", + tr("XML pattern file (*.xpt *.xptz)")); + importDialog.setFileMode(FileDialog::ExistingFile); + + if (importDialog.exec() == QDialog::Accepted && + !importDialog.selectedFiles().isEmpty()) + { + const QString fullPath = importDialog.selectedFiles()[0]; + DataFile dataFile(fullPath); + + if (dataFile.head().isNull()) + { + return; + } + + TimePos pos = m_editor->m_pattern->startPosition(); // Backup position in timeline. + + m_editor->m_pattern->loadSettings(dataFile.content()); + m_editor->m_pattern->movePosition(pos); + + TextFloat::displayMessage(tr("Import pattern success"), + tr("Imported pattern %1!").arg(fullPath), + embed::getIconPixmap("project_import"), 4000); + } +} + + + + void PianoRollWindow::focusInEvent( QFocusEvent * event ) { // when the window is given focus, also give focus to the actual piano roll