Skip to content

Commit

Permalink
Add Bulk Exporter
Browse files Browse the repository at this point in the history
  • Loading branch information
psyomn committed Jul 28, 2020
1 parent 1ee78ab commit 3a89f97
Show file tree
Hide file tree
Showing 6 changed files with 511 additions and 6 deletions.
23 changes: 19 additions & 4 deletions source/app/powertabeditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
#include <dialogs/artificialharmonicdialog.h>
#include <dialogs/barlinedialog.h>
#include <dialogs/benddialog.h>
#include <dialogs/bulkconverterdialog.h>
#include <dialogs/chordnamedialog.h>
#include <dialogs/directiondialog.h>
#include <dialogs/dynamicdialog.h>
Expand Down Expand Up @@ -504,6 +505,12 @@ void PowerTabEditor::printDocument()
getScoreArea()->print(printer);
}

void PowerTabEditor::bulkConverter()
{
BulkConverterDialog dialog(this, myFileFormatManager);
dialog.exec();
}

void PowerTabEditor::printPreview()
{
// Set the window flags to Qt::Window so that the dialog can be maximized.
Expand Down Expand Up @@ -1546,7 +1553,7 @@ void PowerTabEditor::editLeftHandFingering()
LeftHandFingeringDialog dialog(this);
if (dialog.exec() == QDialog::Accepted)
{
myUndoManager->push(new AddLeftHandFingering(location,
myUndoManager->push(new AddLeftHandFingering(location,
dialog.getLeftHandFingering()),
location.getSystemIndex());
}
Expand Down Expand Up @@ -1883,6 +1890,12 @@ void PowerTabEditor::createCommands()
connect(myPrintPreviewCommand, &QAction::triggered, this,
&PowerTabEditor::printPreview);

myBulkConverterCommand = new Command(tr("Bulk Converter"),
"File.BulkConverter",
QKeySequence(), this);
connect(myBulkConverterCommand, &QAction::triggered, this,
&PowerTabEditor::bulkConverter);

myEditShortcutsCommand = new Command(tr("Customize Shortcuts..."),
"File.CustomizeShortcuts",
QKeySequence(), this);
Expand Down Expand Up @@ -2220,7 +2233,7 @@ void PowerTabEditor::createCommands()
Qt::SHIFT + Qt::Key_Left, this);
connect(myRemoveDotCommand, &QAction::triggered, this, &PowerTabEditor::removeDot);

myLeftHandFingeringCommand = new Command(tr("Left Hand Fingering..."),
myLeftHandFingeringCommand = new Command(tr("Left Hand Fingering..."),
"Notes.LeftHandFingering",
QKeySequence(), this);
myLeftHandFingeringCommand->setCheckable(true);
Expand Down Expand Up @@ -2530,7 +2543,7 @@ void PowerTabEditor::createCommands()
&PowerTabEditor::editViewFilters);

// Window Menu commands.

#ifdef Q_OS_MAC
// NextChild is Command-{ on OS X, so use the more conventional Control-Tab
// to match Safari, Finder, etc.
Expand All @@ -2540,7 +2553,7 @@ void PowerTabEditor::createCommands()
QKeySequence next_tab_seq = QKeySequence::NextChild;
QKeySequence prev_tab_seq = QKeySequence::PreviousChild;
#endif

myNextTabCommand = new Command(tr("Next Tab"), "Window.NextTab",
next_tab_seq, this);
connect(myNextTabCommand, &QAction::triggered, [=]() {
Expand Down Expand Up @@ -2723,6 +2736,8 @@ void PowerTabEditor::createMenus()
myFileMenu->addSeparator();
myRecentFilesMenu = myFileMenu->addMenu(tr("Recent Files"));
myFileMenu->addSeparator();
myFileMenu->addAction(myBulkConverterCommand);
myFileMenu->addSeparator();
myFileMenu->addAction(myEditShortcutsCommand);
myFileMenu->addAction(myEditPreferencesCommand);
myFileMenu->addSeparator();
Expand Down
8 changes: 6 additions & 2 deletions source/app/powertabeditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef APP_POWERTABEDITOR_H
#define APP_POWERTABEDITOR_H

Expand Down Expand Up @@ -84,6 +84,9 @@ private slots:
/// Prints the current document.
void printDocument();

/// Bulk conversion tool
void bulkConverter();

/// Displays a preview of the current document.
void printPreview();

Expand Down Expand Up @@ -429,6 +432,7 @@ private slots:
Command *mySaveAsCommand;
Command *myPrintCommand;
Command *myPrintPreviewCommand;
Command *myBulkConverterCommand;
QMenu *myRecentFilesMenu;
Command *myEditShortcutsCommand;
Command *myEditPreferencesCommand;
Expand Down Expand Up @@ -463,7 +467,7 @@ private slots:
Command *myPrevPositionCommand;
Command *myNextStringCommand;
Command *myPrevStringCommand;
Command *myLastPositionCommand;
Command *myLastPositionCommand;
Command *myNextStaffCommand;
Command *myPrevStaffCommand;
Command *myNextBarCommand;
Expand Down
4 changes: 4 additions & 0 deletions source/dialogs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ set( srcs
artificialharmonicdialog.cpp
barlinedialog.cpp
benddialog.cpp
bulkconverterdialog.cpp
chordnamedialog.cpp
crashdialog.cpp
directiondialog.cpp
Expand Down Expand Up @@ -41,6 +42,7 @@ set( headers
artificialharmonicdialog.h
barlinedialog.h
benddialog.h
bulkconverterdialog.h
chordnamedialog.h
crashdialog.h
directiondialog.h
Expand Down Expand Up @@ -76,6 +78,7 @@ set( moc_headers
artificialharmonicdialog.h
barlinedialog.h
benddialog.h
bulkconverterdialog.h
chordnamedialog.h
crashdialog.h
directiondialog.h
Expand Down Expand Up @@ -104,6 +107,7 @@ set( forms
artificialharmonicdialog.ui
barlinedialog.ui
benddialog.ui
bulkconverterdialog.ui
chordnamedialog.ui
crashdialog.ui
directiondialog.ui
Expand Down
236 changes: 236 additions & 0 deletions source/dialogs/bulkconverterdialog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
/*
* Copyright (C) 2020 Simon Symeonidis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "bulkconverterdialog.h"
#include "ui_bulkconverterdialog.h"

#include "formats/powertab/common.h"

#include <app/paths.h>
#include <score/score.h>

#include <QFileDialog>
#include <QFileInfo>
#include <QDebug>
#include <QThread>

std::optional<std::string> convertFile(const boost::filesystem::path& src,
const boost::filesystem::path& dst,
std::unique_ptr<FileFormatManager>& ffm)
{
QFileInfo fileInfo(QString::fromStdString(src.string()));
std::optional<FileFormat> format = ffm->findFormat(
fileInfo.suffix().toStdString());

if (!format) return "bad format";

Score score;
try
{
ffm->importFile(score, src, *format);
}
catch (const std::exception &e)
{
return "could not import file: " + src.string();
}

try
{
ffm->exportFile(score, dst, FileFormat(getPowerTabFileFormat()));
}
catch (const std::exception &e)
{
return "could not export file: " + dst.string();
}

return std::nullopt;
}

BulkConverterWorker::BulkConverterWorker(boost::filesystem::path& source,
boost::filesystem::path& destination,
bool dryRun,
std::unique_ptr<FileFormatManager>& fileFormatManager)
: QObject(), mySrc(source), myDst(destination), myDryRun(dryRun),
myFileCount(0), myFileFormatManager(fileFormatManager)
{
}

BulkConverterWorker::~BulkConverterWorker()
{
}

void BulkConverterWorker::walkAndConvert()
{
std::vector<boost::filesystem::path> children;
const std::string basePath = mySrc.string();

children.emplace_back(mySrc);

do {
boost::filesystem::path p = children.back();
children.pop_back();

if (!boost::filesystem::is_directory(p)) continue;

auto dir_it = boost::filesystem::directory_iterator(p);

for(auto& entry : boost::make_iterator_range(dir_it, {})) {
if (boost::filesystem::is_directory(entry)) {
children.emplace_back(entry);
continue;
}

// TODO: this should probably handle any supported format.
// check to see if there is a list of file formats
// like this
if (!(boost::filesystem::is_regular_file(entry) &&
boost::filesystem::extension(entry) == ".ptb"))
continue;

myFileCount++;

auto filePath = entry.path().string();
const size_t pos = filePath.find(basePath);
if (pos != std::string::npos)
filePath.erase(pos, basePath.length());

auto toPath = myDst / boost::filesystem::path(filePath);
toPath.replace_extension("pt2");

if (myDryRun) continue;

auto destBaseDir = toPath.parent_path();
if (!boost::filesystem::exists(destBaseDir))
boost::filesystem::create_directory(destBaseDir);

std::optional<std::string> error = convertFile(entry, toPath, myFileFormatManager);
if (error != std::nullopt) {
QString err = QString::fromStdString(error.value());
emit errorMessage("error processing file: " + err);
}

emit progress((int) myFileCount);
}
} while (!children.empty());

emit done();
}

BulkConverterDialog::BulkConverterDialog(QWidget *parent,
std::unique_ptr<FileFormatManager>& manager)
: QDialog(parent), ui(new Ui::BulkConverterDialog),
myBulkWorkerThread(nullptr), myBulkConverterWorker(nullptr),
myFileFormatManager(manager)
{
ui->setupUi(this);

auto flags = windowFlags();
setWindowFlags(flags | Qt::WindowStaysOnTopHint);

connect(ui->fileLocatorSource, &QAbstractButton::clicked, [=]() {
setPath(ui->sourcePathEdit);
});

connect(ui->fileLocatorDestination, &QAbstractButton::clicked, [=]() {
setPath(ui->destinationPathEdit);
});

connect(ui->convertButton, &QAbstractButton::clicked, [=](){ convert(); });

connect(ui->exitButton, &QAbstractButton::clicked, this, &QDialog::reject);
}

BulkConverterDialog::~BulkConverterDialog()
{
if (myBulkWorkerThread) {
myBulkWorkerThread->quit();
myBulkWorkerThread->wait();
}
delete ui;
}

void BulkConverterDialog::setPath(QLineEdit *edit)
{
auto dialogOptions = QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks;
QString path = QFileDialog::getExistingDirectory(
this, tr("Directory To Convert"), QDir::currentPath(), dialogOptions);

edit->setText(path);
QString src = ui->sourcePathEdit->text();
QString dst = ui->destinationPathEdit->text();
const bool bothEditsHaveValues = !src.isEmpty() && !dst.isEmpty();
ui->convertButton->setEnabled(bothEditsHaveValues);
}

void BulkConverterDialog::convert()
{
ui->convertButton->setEnabled(false);

boost::filesystem::path src = Paths::fromQString(ui->sourcePathEdit->text());
boost::filesystem::path dst = Paths::fromQString(ui->destinationPathEdit->text());

{
// set default max.
BulkConverterWorker bcw(src, dst, true, myFileFormatManager);
bcw.walkAndConvert();
const std::size_t fileCountToConvert = bcw.fileCount();
ui->progressBar->setMaximum((int) fileCountToConvert);
ui->progressBar->setValue(0);
}

// create thread to offload work in the background, such that we can
// update the progress bar with each step informing the user of the
// current state of bulk conversion.
myBulkWorkerThread = new QThread;
myBulkConverterWorker = new BulkConverterWorker(src, dst, false, myFileFormatManager);
myBulkConverterWorker->moveToThread(myBulkWorkerThread);

connect(myBulkWorkerThread, &QThread::started,
myBulkConverterWorker, &BulkConverterWorker::walkAndConvert);

connect(myBulkWorkerThread, &QThread::finished,
myBulkWorkerThread, &QObject::deleteLater);

connect(myBulkConverterWorker, &BulkConverterWorker::progress,
this, &BulkConverterDialog::progress);

connect(myBulkConverterWorker, &BulkConverterWorker::done,
myBulkConverterWorker, &QObject::deleteLater);

connect(myBulkConverterWorker, &BulkConverterWorker::done,
this, &BulkConverterDialog::enableConvertButton);

connect(myBulkConverterWorker, &BulkConverterWorker::errorMessage,
this, &BulkConverterDialog::consumeErrorMessage);

myBulkWorkerThread->start();
}

void BulkConverterDialog::progress(int pos)
{
ui->progressBar->setValue(pos);
}

void BulkConverterDialog::enableConvertButton(void)
{
ui->convertButton->setEnabled(true);
}

void BulkConverterDialog::consumeErrorMessage(QString error)
{
ui->logger->appendPlainText(error);
}
Loading

0 comments on commit 3a89f97

Please sign in to comment.