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:
@@ -52,6 +52,7 @@ public:
|
||||
ClipboardData,
|
||||
JournalData,
|
||||
EffectSettings,
|
||||
NotePattern,
|
||||
TypeCount
|
||||
} ;
|
||||
typedef Types Type;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user