Feature: Pattern import/export (#5891)

* Init

* Suggested changes by @IanCaio, thanks!

* Selecting one file to import is enough.

* Explicit use of TimePos in favour of int where expected, as suggested.

* Make pattern import/export future proof with using DataFile instead of custom code to read/write the pattern file.

* Remove unused/duplicate imports

* Make import/export dialogs file-ext filter consistent.

Co-authored-by: CYBERDEViL <cyberdevil@notabug.org>
This commit is contained in:
cyber-bridge
2021-03-21 15:40:12 +01:00
committed by GitHub
parent 5ad034ade3
commit 4a99904ff6
4 changed files with 122 additions and 2 deletions

View File

@@ -52,6 +52,7 @@ public:
ClipboardData,
JournalData,
EffectSettings,
NotePattern,
TypeCount
} ;
typedef Types Type;

View File

@@ -47,6 +47,7 @@ class QPixmap;
class QScrollBar;
class QString;
class QMenu;
class QToolButton;
class ComboBox;
class NotePlayHandle;
@@ -530,6 +531,8 @@ signals:
private slots:
void updateAfterPatternChange();
void ghostPatternSet( bool state );
void exportPattern();
void importPattern();
private:
void patternRenamed();
@@ -539,6 +542,7 @@ private:
PianoRoll* m_editor;
QToolButton* m_fileToolsButton;
ComboBox * m_zoomingComboBox;
ComboBox * m_zoomingYComboBox;
ComboBox * m_quantizeComboBox;

View File

@@ -83,7 +83,8 @@ DataFile::typeDescStruct
{ DataFile::DragNDropData, "dnddata" },
{ DataFile::ClipboardData, "clipboard-data" },
{ DataFile::JournalData, "journaldata" },
{ DataFile::EffectSettings, "effectsettings" }
{ DataFile::EffectSettings, "effectsettings" },
{ DataFile::NotePattern, "pattern" }
} ;
@@ -185,6 +186,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" ||
@@ -286,7 +293,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 );

View File

@@ -31,6 +31,7 @@
#include <QKeyEvent>
#include <QLabel>
#include <QLayout>
#include <QMessageBox>
#include <QMdiArea>
#include <QPainter>
#include <QPointer>
@@ -66,6 +67,7 @@
#include "StepRecorderWidget.h"
#include "TextFloat.h"
#include "TimeLineWidget.h"
#include "FileDialog.h"
using std::move;
@@ -4736,6 +4738,29 @@ PianoRollWindow::PianoRollWindow() :
notesActionsToolBar->addSeparator();
notesActionsToolBar->addWidget(quantizeButton);
// -- 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" ) );
@@ -4987,12 +5012,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);
}
}
@@ -5158,10 +5185,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);
}
}
@@ -5176,6 +5205,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