991 lines
28 KiB
C++
991 lines
28 KiB
C++
|
/**********************************************************************
|
||
|
|
||
|
Audacity: A Digital Audio Editor
|
||
|
|
||
|
ExportMultiple.cpp
|
||
|
|
||
|
Dominic Mazzoni
|
||
|
|
||
|
*******************************************************************//**
|
||
|
|
||
|
\class ExportMultiple
|
||
|
\brief Presents a dialog box allowing the user to export multiple files
|
||
|
either by exporting each track as a separate file, or by
|
||
|
exporting each label as a separate file.
|
||
|
|
||
|
*//********************************************************************/
|
||
|
|
||
|
#include "../Audacity.h"
|
||
|
|
||
|
#include <wx/defs.h>
|
||
|
#include <wx/button.h>
|
||
|
#include <wx/checkbox.h>
|
||
|
#include <wx/choice.h>
|
||
|
#include <wx/dialog.h>
|
||
|
#include <wx/dirdlg.h>
|
||
|
#include <wx/dynarray.h>
|
||
|
#include <wx/event.h>
|
||
|
#include <wx/filedlg.h>
|
||
|
#include <wx/filefn.h>
|
||
|
#include <wx/filename.h>
|
||
|
#include <wx/intl.h>
|
||
|
#include <wx/msgdlg.h>
|
||
|
#include <wx/radiobut.h>
|
||
|
#include <wx/sizer.h>
|
||
|
#include <wx/statbox.h>
|
||
|
#include <wx/stattext.h>
|
||
|
#include <wx/textctrl.h>
|
||
|
#include <wx/textdlg.h>
|
||
|
|
||
|
#include "Export.h"
|
||
|
#include "ExportMultiple.h"
|
||
|
|
||
|
#include "../Internat.h"
|
||
|
#include "../FileFormats.h"
|
||
|
#include "../FileNames.h"
|
||
|
#include "../LabelTrack.h"
|
||
|
#include "../Project.h"
|
||
|
#include "../Prefs.h"
|
||
|
#include "../Tags.h"
|
||
|
|
||
|
|
||
|
/* define our dynamic array of export settings */
|
||
|
#include <wx/arrimpl.cpp> // much hackery
|
||
|
WX_DEFINE_OBJARRAY( ExportKitArray )
|
||
|
|
||
|
enum {
|
||
|
FormatID = 10001,
|
||
|
OptionsID,
|
||
|
DirID,
|
||
|
CreateID,
|
||
|
ChooseID,
|
||
|
LabelID,
|
||
|
FirstID,
|
||
|
FirstFileNameID,
|
||
|
TrackID,
|
||
|
ByNameID,
|
||
|
ByNumberID,
|
||
|
PrefixID,
|
||
|
OverwriteID
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// ExportMultiple methods
|
||
|
//
|
||
|
|
||
|
BEGIN_EVENT_TABLE(ExportMultiple, wxDialog)
|
||
|
EVT_CHOICE(FormatID, ExportMultiple::OnFormat)
|
||
|
EVT_BUTTON(OptionsID, ExportMultiple::OnOptions)
|
||
|
EVT_BUTTON(CreateID, ExportMultiple::OnCreate)
|
||
|
EVT_BUTTON(ChooseID, ExportMultiple::OnChoose)
|
||
|
EVT_BUTTON(wxID_OK, ExportMultiple::OnExport)
|
||
|
EVT_BUTTON(wxID_CANCEL, ExportMultiple::OnCancel)
|
||
|
EVT_RADIOBUTTON(LabelID, ExportMultiple::OnLabel)
|
||
|
EVT_RADIOBUTTON(TrackID, ExportMultiple::OnTrack)
|
||
|
EVT_RADIOBUTTON(ByNameID, ExportMultiple::OnByName)
|
||
|
EVT_RADIOBUTTON(ByNumberID, ExportMultiple::OnByNumber)
|
||
|
EVT_CHECKBOX(FirstID, ExportMultiple::OnFirst)
|
||
|
EVT_TEXT(FirstFileNameID, ExportMultiple::OnFirstFileName)
|
||
|
EVT_TEXT(PrefixID, ExportMultiple::OnPrefix)
|
||
|
END_EVENT_TABLE()
|
||
|
|
||
|
BEGIN_EVENT_TABLE(SuccessDialog, wxDialog)
|
||
|
EVT_LIST_KEY_DOWN(wxID_ANY, SuccessDialog::OnKeyDown)
|
||
|
EVT_LIST_ITEM_ACTIVATED(wxID_ANY, SuccessDialog::OnItemActivated) // happens when <enter> is pressed with list item having focus
|
||
|
END_EVENT_TABLE()
|
||
|
|
||
|
BEGIN_EVENT_TABLE(MouseEvtHandler, wxEvtHandler)
|
||
|
EVT_LEFT_DCLICK(MouseEvtHandler::OnMouse)
|
||
|
END_EVENT_TABLE()
|
||
|
|
||
|
ExportMultiple::ExportMultiple(AudacityProject *project)
|
||
|
: wxDialog(project, wxID_ANY, wxString(_("Export Multiple")))
|
||
|
{
|
||
|
mProject = project;
|
||
|
mTracks = project->GetTracks();
|
||
|
mPlugins = mExporter.GetPlugins();
|
||
|
|
||
|
this->CountTracksAndLabels();
|
||
|
|
||
|
// create array of characters not allowed in file names
|
||
|
wxString forbid = wxFileName::GetForbiddenChars();
|
||
|
for(unsigned int i=0; i < forbid.Length(); i++)
|
||
|
exclude.Add( forbid.Mid(i, 1) );
|
||
|
|
||
|
ShuttleGui S(this, eIsCreatingFromPrefs);
|
||
|
|
||
|
// Creating some of the widgets cause cause events to fire
|
||
|
// and we don't want that until after we're completely
|
||
|
// created. (Observed on Windows)
|
||
|
mInitialized = false;
|
||
|
PopulateOrExchange(S);
|
||
|
mInitialized = true;
|
||
|
|
||
|
Layout();
|
||
|
Fit();
|
||
|
SetMinSize(GetSize());
|
||
|
Center();
|
||
|
|
||
|
EnableControls();
|
||
|
}
|
||
|
|
||
|
ExportMultiple::~ExportMultiple()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void ExportMultiple::CountTracksAndLabels()
|
||
|
{
|
||
|
mLabels = NULL;
|
||
|
mNumLabels = 0;
|
||
|
mNumWaveTracks = 0;
|
||
|
|
||
|
Track* pTrack;
|
||
|
for (pTrack = mIterator.First(mTracks); pTrack != NULL; pTrack = mIterator.Next())
|
||
|
{
|
||
|
switch (pTrack->GetKind())
|
||
|
{
|
||
|
// Count WaveTracks, and for linked pairs, count only the second of the pair.
|
||
|
case Track::Wave:
|
||
|
{
|
||
|
if (pTrack->GetLinked() == false)
|
||
|
mNumWaveTracks++;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Only support one label track???
|
||
|
case Track::Label:
|
||
|
{
|
||
|
// Supports only one LabelTrack.
|
||
|
if (mLabels == NULL) {
|
||
|
mLabels = (LabelTrack*)pTrack;
|
||
|
mNumLabels = mLabels->GetNumLabels();
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int ExportMultiple::ShowModal()
|
||
|
{
|
||
|
if (mNumWaveTracks < 2 && mNumLabels < 1) {
|
||
|
::wxMessageBox(_("If you have more than one Audio Track, you can export each track as a separate file,\nor if you have a Label Track, you can export a new file for each label.\n\nThis project does not have multiple tracks or a Label Track, so you cannot export multiple files."),
|
||
|
_("Can't export multiple files"),
|
||
|
wxOK | wxCENTRE, this);
|
||
|
return wxID_CANCEL;
|
||
|
}
|
||
|
|
||
|
if (mNumLabels < 1) {
|
||
|
mLabel->Enable(false);
|
||
|
mTrack->SetValue(true);
|
||
|
mLabel->SetValue(false);
|
||
|
}
|
||
|
|
||
|
if (mNumWaveTracks < 2) {
|
||
|
mTrack->Enable(false);
|
||
|
mLabel->SetValue(true);
|
||
|
mTrack->SetValue(false);
|
||
|
}
|
||
|
|
||
|
EnableControls();
|
||
|
|
||
|
return wxDialog::ShowModal();
|
||
|
}
|
||
|
|
||
|
void ExportMultiple::PopulateOrExchange(ShuttleGui& S)
|
||
|
{
|
||
|
|
||
|
wxString name = mProject->GetName();
|
||
|
|
||
|
mPluginIndex = -1;
|
||
|
|
||
|
wxString defaultFormat = gPrefs->Read(wxT("/Export/Format"),
|
||
|
wxT("WAV"));
|
||
|
|
||
|
mFilterIndex = 0;
|
||
|
|
||
|
for (size_t i = 0; i < mPlugins.GetCount(); i++) {
|
||
|
for (int j = 0; j < mPlugins[i]->GetFormatCount(); j++)
|
||
|
{
|
||
|
if (mPlugins[i]->GetFormat(j) == defaultFormat) {
|
||
|
mPluginIndex = i;
|
||
|
mSubFormatIndex = j;
|
||
|
}
|
||
|
if (mPluginIndex == -1) mFilterIndex++;
|
||
|
}
|
||
|
}
|
||
|
if (mPluginIndex == -1)
|
||
|
{
|
||
|
mPluginIndex = 0;
|
||
|
mFilterIndex = 0;
|
||
|
mSubFormatIndex = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
S.SetBorder(5);
|
||
|
S.StartMultiColumn(4, true);
|
||
|
{
|
||
|
wxArrayString formats;
|
||
|
|
||
|
for (size_t i = 0; i < mPlugins.GetCount(); i++) {
|
||
|
for (int j = 0; j < mPlugins[i]->GetFormatCount(); j++)
|
||
|
{
|
||
|
formats.Add(mPlugins[i]->GetDescription(j));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
mFormat = S.Id(FormatID)
|
||
|
.TieChoice(_("Export format:"),
|
||
|
wxT("/Export/MultipleFormat"),
|
||
|
mPlugins[mPluginIndex]->GetFormat(mSubFormatIndex),
|
||
|
formats,
|
||
|
formats);
|
||
|
S.Id(OptionsID).AddButton(_("Options..."));
|
||
|
S.AddVariableText(wxT(""), false);
|
||
|
|
||
|
mDir = S.Id(DirID)
|
||
|
.TieTextBox(_("Export location:"),
|
||
|
wxT("/Export/MultiplePath"),
|
||
|
gPrefs->Read(wxT("/Export/Path"), ::wxGetCwd()),
|
||
|
64);
|
||
|
S.Id(ChooseID).AddButton(_("Choose..."));
|
||
|
S.Id(CreateID).AddButton(_("Create"));
|
||
|
}
|
||
|
S.EndMultiColumn();
|
||
|
|
||
|
S.StartHorizontalLay(wxEXPAND, true);
|
||
|
{
|
||
|
S.SetBorder(5);
|
||
|
S.StartStatic(_("Split files based on:"), true);
|
||
|
{
|
||
|
S.StartMultiColumn(2, false);
|
||
|
S.SetStretchyCol(1);
|
||
|
{
|
||
|
// Row 1
|
||
|
S.SetBorder(1);
|
||
|
mLabel = S.Id(LabelID)
|
||
|
.AddRadioButton(wxT(""));
|
||
|
mLabel->SetName(_("Labels"));
|
||
|
S.SetBorder(3);
|
||
|
mLabelLabel = S.AddVariableText(_("Labels"), false);
|
||
|
|
||
|
// Row 2
|
||
|
S.AddVariableText(wxT(""), false);
|
||
|
mFirst = S.Id(FirstID)
|
||
|
.AddCheckBox(_("Include audio before first label"), wxT("false"));
|
||
|
|
||
|
// Row 3
|
||
|
S.AddVariableText(wxT(""), false);
|
||
|
S.StartHorizontalLay(wxEXPAND, false);
|
||
|
{
|
||
|
mFirstFileLabel = S.AddVariableText(_("First file name:"), true);
|
||
|
mFirstFileName = S.Id(FirstFileNameID)
|
||
|
.TieTextBox(wxT(""),
|
||
|
name,
|
||
|
30);
|
||
|
mFirstFileName->SetName(_("First file name"));
|
||
|
}
|
||
|
S.EndHorizontalLay();
|
||
|
|
||
|
// Row 4
|
||
|
S.SetBorder(1);
|
||
|
mTrack = S.Id(TrackID)
|
||
|
.AddRadioButtonToGroup(wxT(""));
|
||
|
mTrack->SetName(_("Tracks"));
|
||
|
S.SetBorder(3);
|
||
|
mTrackLabel = S.AddVariableText(_("Tracks"), false);
|
||
|
}
|
||
|
S.EndMultiColumn();
|
||
|
}
|
||
|
S.EndStatic();
|
||
|
|
||
|
S.SetBorder(5);
|
||
|
S.StartStatic(_("Name files:"), false);
|
||
|
{
|
||
|
S.StartMultiColumn(2, false);
|
||
|
S.SetStretchyCol(1);
|
||
|
{
|
||
|
// Row 1
|
||
|
S.SetBorder(1);
|
||
|
mByName = S.Id(ByNameID)
|
||
|
.AddRadioButton(wxT(""));
|
||
|
mByName->SetName(_("Using Label/Track Name"));
|
||
|
S.SetBorder(3);
|
||
|
mByNameLabel = S.AddVariableText(_("Using Label/Track Name"), false);
|
||
|
|
||
|
// Row 2
|
||
|
S.SetBorder(1);
|
||
|
mByNumber = S.Id(ByNumberID)
|
||
|
.AddRadioButtonToGroup(wxT(""));
|
||
|
mByNumber->SetName(_("Numbering consecutively"));
|
||
|
S.SetBorder(3);
|
||
|
mByNumberLabel = S.AddVariableText(_("Numbering consecutively"), false);
|
||
|
|
||
|
// Row 3
|
||
|
S.AddVariableText(wxT(""), false);
|
||
|
S.StartHorizontalLay(wxEXPAND, false);
|
||
|
{
|
||
|
mPrefixLabel = S.AddVariableText(_("File name prefix:"), true);
|
||
|
mPrefix = S.Id(PrefixID)
|
||
|
.TieTextBox(wxT(""),
|
||
|
name,
|
||
|
30);
|
||
|
mPrefix->SetName(_("File name prefix"));
|
||
|
}
|
||
|
S.EndHorizontalLay();
|
||
|
}
|
||
|
S.EndMultiColumn();
|
||
|
}
|
||
|
S.EndStatic();
|
||
|
}
|
||
|
S.EndHorizontalLay();
|
||
|
|
||
|
S.SetBorder(5);
|
||
|
S.StartHorizontalLay(wxEXPAND, false);
|
||
|
{
|
||
|
mOverwrite = S.Id(OverwriteID)
|
||
|
.AddCheckBox(_("Overwrite existing files"), wxT("true"));
|
||
|
}
|
||
|
S.EndHorizontalLay();
|
||
|
|
||
|
S.AddStandardButtons();
|
||
|
mExport = (wxButton *)wxWindow::FindWindowById(wxID_OK, this);
|
||
|
mExport->SetLabel(_("Export"));
|
||
|
|
||
|
}
|
||
|
|
||
|
void ExportMultiple::EnableControls()
|
||
|
{
|
||
|
bool enable;
|
||
|
|
||
|
if (!mInitialized) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
mFirst->Enable(mLabel->GetValue());
|
||
|
|
||
|
enable = mLabel->GetValue() &&
|
||
|
mByName->GetValue() &&
|
||
|
mFirst->GetValue();
|
||
|
mFirstFileLabel->Enable(enable);
|
||
|
mFirstFileName->Enable(enable);
|
||
|
|
||
|
enable = mByNumber->GetValue();
|
||
|
mPrefixLabel->Enable(enable);
|
||
|
mPrefix->Enable(enable);
|
||
|
|
||
|
bool ok = true;
|
||
|
|
||
|
if (mLabel->GetValue() && mFirst->GetValue() &&
|
||
|
mFirstFileName->GetValue() == wxT("") &&
|
||
|
mPrefix->GetValue() == wxT(""))
|
||
|
ok = false;
|
||
|
|
||
|
if (mByNumber->GetValue() &&
|
||
|
mPrefix->GetValue() == wxT(""))
|
||
|
ok = false;
|
||
|
|
||
|
mExport->Enable(ok);
|
||
|
}
|
||
|
|
||
|
void ExportMultiple::OnFormat(wxCommandEvent& event)
|
||
|
{
|
||
|
EnableControls();
|
||
|
}
|
||
|
|
||
|
void ExportMultiple::OnOptions(wxCommandEvent& event)
|
||
|
{
|
||
|
const int sel = mFormat->GetSelection();
|
||
|
if (sel != wxNOT_FOUND)
|
||
|
{
|
||
|
size_t c = 0;
|
||
|
for (size_t i = 0; i < mPlugins.GetCount(); i++)
|
||
|
{
|
||
|
for (int j = 0; j < mPlugins[i]->GetFormatCount(); j++)
|
||
|
{
|
||
|
if ((size_t)sel == c)
|
||
|
{
|
||
|
mPluginIndex = i;
|
||
|
mSubFormatIndex = j;
|
||
|
}
|
||
|
c++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
mPlugins[mPluginIndex]->DisplayOptions(this,mSubFormatIndex);
|
||
|
}
|
||
|
|
||
|
void ExportMultiple::OnCreate(wxCommandEvent& event)
|
||
|
{
|
||
|
wxFileName fn;
|
||
|
|
||
|
fn.AssignDir(mDir->GetValue());
|
||
|
|
||
|
bool ok = fn.Mkdir(0777, wxPATH_MKDIR_FULL);
|
||
|
|
||
|
if (!ok) {
|
||
|
// Mkdir will produce an error dialog
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
::wxMessageBox(wxString::Format(_("\"%s\" successfully created."),
|
||
|
fn.GetPath().c_str()),
|
||
|
_("Export Multiple"),
|
||
|
wxOK | wxCENTRE, this);
|
||
|
}
|
||
|
|
||
|
void ExportMultiple::OnChoose(wxCommandEvent& event)
|
||
|
{
|
||
|
wxDirDialog dlog(this,
|
||
|
_("Choose a location to save the exported files"),
|
||
|
mDir->GetValue());
|
||
|
dlog.ShowModal();
|
||
|
if (dlog.GetPath() != wxT(""))
|
||
|
mDir->SetValue(dlog.GetPath());
|
||
|
}
|
||
|
|
||
|
void ExportMultiple::OnLabel(wxCommandEvent& event)
|
||
|
{
|
||
|
EnableControls();
|
||
|
}
|
||
|
|
||
|
void ExportMultiple::OnFirst(wxCommandEvent& event)
|
||
|
{
|
||
|
EnableControls();
|
||
|
}
|
||
|
|
||
|
void ExportMultiple::OnFirstFileName(wxCommandEvent& event)
|
||
|
{
|
||
|
EnableControls();
|
||
|
}
|
||
|
|
||
|
void ExportMultiple::OnTrack(wxCommandEvent& event)
|
||
|
{
|
||
|
EnableControls();
|
||
|
}
|
||
|
|
||
|
void ExportMultiple::OnByName(wxCommandEvent& event)
|
||
|
{
|
||
|
EnableControls();
|
||
|
}
|
||
|
|
||
|
void ExportMultiple::OnByNumber(wxCommandEvent& event)
|
||
|
{
|
||
|
EnableControls();
|
||
|
}
|
||
|
|
||
|
void ExportMultiple::OnPrefix(wxCommandEvent& event)
|
||
|
{
|
||
|
EnableControls();
|
||
|
}
|
||
|
|
||
|
void ExportMultiple::OnCancel(wxCommandEvent& event)
|
||
|
{
|
||
|
EndModal(0);
|
||
|
}
|
||
|
|
||
|
void ExportMultiple::OnExport(wxCommandEvent& event)
|
||
|
{
|
||
|
ShuttleGui S(this, eIsSavingToPrefs);
|
||
|
PopulateOrExchange(S);
|
||
|
|
||
|
// Make sure the output directory is in good shape
|
||
|
if (!DirOk()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
mFilterIndex = mFormat->GetSelection();
|
||
|
if (mFilterIndex != wxNOT_FOUND)
|
||
|
{
|
||
|
size_t c = 0;
|
||
|
for (size_t i = 0; i < mPlugins.GetCount(); i++)
|
||
|
{
|
||
|
for (int j = 0; j < mPlugins[i]->GetFormatCount(); j++)
|
||
|
{
|
||
|
if ((size_t)mFilterIndex == c)
|
||
|
{ // this is the selected format. Store the plug-in and sub-format
|
||
|
// needed to acheive it.
|
||
|
mPluginIndex = i;
|
||
|
mSubFormatIndex = j;
|
||
|
}
|
||
|
c++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// bool overwrite = mOverwrite->GetValue();
|
||
|
int ok;
|
||
|
mExported.Empty();
|
||
|
|
||
|
if (mLabel->GetValue()) {
|
||
|
ok = ExportMultipleByLabel(mByName->GetValue(),
|
||
|
mPrefix->GetValue());
|
||
|
}
|
||
|
else {
|
||
|
ok = ExportMultipleByTrack(mByName->GetValue(),
|
||
|
mPrefix->GetValue());
|
||
|
}
|
||
|
|
||
|
// Give 'em the result
|
||
|
{
|
||
|
wxString msg;
|
||
|
msg.Printf(
|
||
|
ok == eProgressSuccess ? _("Successfully exported the following %ld file(s).")
|
||
|
: (ok == eProgressFailed ? _("Something went wrong after exporting the following %ld file(s).")
|
||
|
: (ok == eProgressCancelled ? _("Export canceled after exporting the following %ld file(s).")
|
||
|
: (ok == eProgressStopped ? _("Export stopped after exporting the following %ld file(s).")
|
||
|
: _("Something went really wrong after exporting the following %ld file(s).")
|
||
|
)
|
||
|
)
|
||
|
), mExported.GetCount());
|
||
|
|
||
|
SuccessDialog dlg(this,
|
||
|
wxID_ANY,
|
||
|
wxString(_("Export Multiple")));
|
||
|
ShuttleGui S(&dlg, eIsCreating);
|
||
|
S.StartVerticalLay();
|
||
|
{
|
||
|
S.AddTitle(msg);
|
||
|
S.SetStyle(wxLC_LIST | wxLC_SINGLE_SEL | wxLC_HRULES | wxSUNKEN_BORDER);
|
||
|
wxListCtrl *l = S.AddListControl();
|
||
|
l->SetBackgroundStyle(wxBG_STYLE_COLOUR);
|
||
|
#if defined (__WXGTK__)
|
||
|
// setting dlg.GetBackgroundColour does not work as expected in wxGTK
|
||
|
l->SetBackgroundColour(wxColour(wxT("wxNullColour")));
|
||
|
#else
|
||
|
l->SetBackgroundColour(dlg.GetBackgroundColour());
|
||
|
#endif
|
||
|
l->Refresh();
|
||
|
for (size_t i = 0; i < mExported.GetCount(); i++) {
|
||
|
l->InsertItem(i, mExported[i]);
|
||
|
}
|
||
|
|
||
|
S.AddStandardButtons(eOkButton);
|
||
|
l->SetFocus();
|
||
|
|
||
|
// this handles double-click and prevents item activation when a list-item is double-clicked
|
||
|
MouseEvtHandler *mouseHdlr = new MouseEvtHandler();
|
||
|
l->PushEventHandler(mouseHdlr);
|
||
|
}
|
||
|
dlg.Fit();
|
||
|
dlg.Center();
|
||
|
dlg.ShowModal();
|
||
|
}
|
||
|
|
||
|
if (ok == eProgressSuccess || ok == eProgressStopped) {
|
||
|
EndModal(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool ExportMultiple::DirOk()
|
||
|
{
|
||
|
wxFileName fn;
|
||
|
|
||
|
fn.AssignDir(mDir->GetValue());
|
||
|
|
||
|
if (fn.DirExists()) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
wxString prompt;
|
||
|
|
||
|
prompt.Printf(_("\"%s\" doesn't exist.\n\nWould you like to create it?"),
|
||
|
fn.GetFullPath().c_str());
|
||
|
|
||
|
int action = wxMessageBox(prompt,
|
||
|
wxT("Warning"),
|
||
|
wxYES_NO | wxICON_EXCLAMATION);
|
||
|
if (action != wxYES) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return fn.Mkdir(0777, wxPATH_MKDIR_FULL);
|
||
|
}
|
||
|
|
||
|
int ExportMultiple::ExportMultipleByLabel(bool byName, wxString prefix)
|
||
|
{
|
||
|
wxASSERT(mProject);
|
||
|
bool tagsPrompt = mProject->GetShowId3Dialog();
|
||
|
int numFiles = mNumLabels;
|
||
|
int l = 0; // counter for files done
|
||
|
ExportKitArray exportSettings; // dynamic array we will use to store the
|
||
|
// settings needed to do the exports with in
|
||
|
exportSettings.Alloc(numFiles); // allocated some guessed space to use
|
||
|
|
||
|
// Account for exporting before first label
|
||
|
if (mFirst->GetValue()) {
|
||
|
l--;
|
||
|
numFiles++;
|
||
|
}
|
||
|
|
||
|
// Figure out how many channels we should export
|
||
|
int channels = (mTracks->GetNumExportChannels(false));
|
||
|
|
||
|
wxArrayString otherNames; // keep track of file names we will use, so we
|
||
|
// don't duplicate them
|
||
|
ExportKit setting; // the current batch of settings
|
||
|
setting.destfile.SetPath(mDir->GetValue());
|
||
|
setting.destfile.SetExt(mPlugins[mPluginIndex]->GetExtension(mSubFormatIndex));
|
||
|
wxLogDebug(wxT("Plug-in index = %d, Sub-format = %d"), mPluginIndex, mSubFormatIndex);
|
||
|
wxLogDebug(wxT("File extension is %s"), setting.destfile.GetExt().c_str());
|
||
|
wxString name; // used to hold file name whilst we mess with it
|
||
|
wxString title; // un-messed-with title of file for tagging with
|
||
|
|
||
|
const LabelStruct *info = NULL;
|
||
|
/* Examine all labels a first time, sort out all data but don't do any
|
||
|
* exporting yet (so this run is quick but interactive) */
|
||
|
while (l < mNumLabels) {
|
||
|
|
||
|
// Get file name and starting time
|
||
|
if (l < 0) {
|
||
|
// create wxFileName for output file
|
||
|
name = (mFirstFileName->GetValue());
|
||
|
setting.t0 = 0.0;
|
||
|
}
|
||
|
else {
|
||
|
info = mLabels->GetLabel(l);
|
||
|
name = (info->title);
|
||
|
setting.t0 = info->t;
|
||
|
}
|
||
|
|
||
|
// Figure out the ending time
|
||
|
if (info && info->t < info->t1) {
|
||
|
setting.t1 = info->t1;
|
||
|
}
|
||
|
else if (l < mNumLabels-1) {
|
||
|
const LabelStruct *info1 = mLabels->GetLabel(l+1);
|
||
|
setting.t1 = info1->t;
|
||
|
}
|
||
|
else {
|
||
|
setting.t1 = mTracks->GetEndTime();
|
||
|
}
|
||
|
|
||
|
// store title of label to use in tags
|
||
|
title = name;
|
||
|
|
||
|
// Numbering files...
|
||
|
if (!byName) {
|
||
|
if (numFiles > 9)
|
||
|
name.Printf(wxT("%s-%02d"), prefix.c_str(), l+1);
|
||
|
else
|
||
|
name.Printf(wxT("%s-%d"), prefix.c_str(), l+1);
|
||
|
}
|
||
|
|
||
|
// store sanitised and user checjed name in object
|
||
|
setting.destfile.SetName(MakeFileName(name));
|
||
|
|
||
|
wxASSERT(setting.destfile.IsOk()); // scream if file name is broke
|
||
|
|
||
|
// Make sure the (final) file name is unique within the set of exports
|
||
|
FileNames::MakeNameUnique(otherNames, setting.destfile);
|
||
|
|
||
|
/* do the metadata for this file */
|
||
|
// copy project metadata to start with
|
||
|
setting.filetags = *(mProject->GetTags());
|
||
|
// over-ride with values
|
||
|
setting.filetags.SetTag(TAG_TITLE, title);
|
||
|
setting.filetags.SetTag(TAG_TRACK, l+1);
|
||
|
// let the user have a crack at editing it, exit if cancelled
|
||
|
if (!setting.filetags.ShowEditDialog(mProject,_("Edit metadata"), tagsPrompt))
|
||
|
return false;
|
||
|
|
||
|
/* add the settings to the array of settings to be used for export */
|
||
|
exportSettings.Add(setting);
|
||
|
|
||
|
l++; // next label, count up one
|
||
|
}
|
||
|
|
||
|
int ok = eProgressSuccess; // did it work?
|
||
|
int count = 0; // count the number of sucessful runs
|
||
|
ExportKit activeSetting; // pointer to the settings in use for this export
|
||
|
/* Go round again and do the exporting (so this run is slow but
|
||
|
* non-interactive) */
|
||
|
for (count = 0; count < numFiles; count++) {
|
||
|
/* get the settings to use for the export from the array */
|
||
|
activeSetting = exportSettings[count];
|
||
|
|
||
|
// Export it
|
||
|
ok = DoExport(channels, activeSetting.destfile, false, activeSetting.t0, activeSetting.t1, activeSetting.filetags);
|
||
|
if (ok != eProgressSuccess && ok != eProgressStopped) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
int ExportMultiple::ExportMultipleByTrack(bool byName,
|
||
|
wxString prefix)
|
||
|
{
|
||
|
wxASSERT(mProject);
|
||
|
bool tagsPrompt = mProject->GetShowId3Dialog();
|
||
|
Track *tr, *tr2;
|
||
|
int channels = 0; // how many channels export?
|
||
|
int l = 0; // track counter
|
||
|
int numTracks = 0;
|
||
|
int ok = eProgressSuccess;
|
||
|
wxArrayString otherNames;
|
||
|
wxArrayPtrVoid selected; /**< Array of pointers to the tracks which were
|
||
|
selected when we started */
|
||
|
ExportKitArray exportSettings; // dynamic array we will use to store the
|
||
|
// settings needed to do the exports with in
|
||
|
exportSettings.Alloc(mNumLabels); // allocated some guessed space to use
|
||
|
ExportKit setting; // the current batch of settings
|
||
|
setting.destfile.SetPath(mDir->GetValue());
|
||
|
setting.destfile.SetExt(mPlugins[mPluginIndex]->GetExtension(mSubFormatIndex));
|
||
|
|
||
|
wxString name; // used to hold file name whilst we mess with it
|
||
|
wxString title; // un-messed-with title of file for tagging with
|
||
|
|
||
|
/* Remember which tracks were selected, and set them to unselected */
|
||
|
for (tr = mIterator.First(mTracks); tr != NULL; tr = mIterator.Next()) {
|
||
|
if (tr->GetKind() != Track::Wave) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (tr->GetSelected()) {
|
||
|
selected.Add(tr);
|
||
|
tr->SetSelected(false);
|
||
|
}
|
||
|
|
||
|
if (!tr->GetLinked()) {
|
||
|
numTracks++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Examine all tracks in turn, collecting export information */
|
||
|
for (tr = mIterator.First(mTracks); tr != NULL; tr = mIterator.Next()) {
|
||
|
|
||
|
// Only want wave tracks
|
||
|
if (tr->GetKind() != Track::Wave) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Get the times for the track
|
||
|
setting.t0 = tr->GetStartTime();
|
||
|
setting.t1 = tr->GetEndTime();
|
||
|
|
||
|
// Check for a linked track
|
||
|
tr2 = NULL;
|
||
|
if (tr->GetLinked()) {
|
||
|
tr2 = mIterator.Next();
|
||
|
if (tr2) {
|
||
|
|
||
|
// Make sure it gets included
|
||
|
if (tr2->GetStartTime() < setting.t0) {
|
||
|
setting.t0 = tr2->GetStartTime();
|
||
|
}
|
||
|
|
||
|
if (tr2->GetEndTime() > setting.t1) {
|
||
|
setting.t1 = tr2->GetEndTime();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// number of export channels?
|
||
|
if (tr2 == NULL && tr->GetChannel() == WaveTrack::MonoChannel &&
|
||
|
((WaveTrack *)tr)->GetPan() == 0.0)
|
||
|
channels = 1;
|
||
|
else
|
||
|
channels = 2;
|
||
|
|
||
|
// Get name and title
|
||
|
title = tr->GetName();
|
||
|
if (byName) {
|
||
|
name = title;
|
||
|
}
|
||
|
else {
|
||
|
if (numTracks > 9) {
|
||
|
name = (wxString::Format(wxT("%s-%02d"), prefix.c_str(), l+1));
|
||
|
}
|
||
|
else {
|
||
|
name = (wxString::Format(wxT("%s-%d"), prefix.c_str(), l+1));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// store sanitised and user checked name in object
|
||
|
setting.destfile.SetName(MakeFileName(name));
|
||
|
|
||
|
if (setting.destfile.GetName().IsEmpty())
|
||
|
{ // user cancelled dialogue, or deleted everything in feild.
|
||
|
// either way, cancel
|
||
|
return false;
|
||
|
}
|
||
|
wxASSERT(setting.destfile.IsOk()); // scream if file name is broke
|
||
|
|
||
|
// Make sure the (final) file name is unique within the set of exports
|
||
|
FileNames::MakeNameUnique(otherNames, setting.destfile);
|
||
|
|
||
|
/* do the metadata for this file */
|
||
|
// copy project metadata to start with
|
||
|
setting.filetags = *(mProject->GetTags());
|
||
|
// over-ride with values
|
||
|
setting.filetags.SetTag(TAG_TITLE, title);
|
||
|
setting.filetags.SetTag(TAG_TRACK, l+1);
|
||
|
// let the user have a crack at editing it, exit if cancelled
|
||
|
if (!setting.filetags.ShowEditDialog(mProject,_("Edit metadata"), tagsPrompt))
|
||
|
return false;
|
||
|
|
||
|
/* add the settings to the array of settings to be used for export */
|
||
|
exportSettings.Add(setting);
|
||
|
|
||
|
l++; // next track, count up one
|
||
|
}
|
||
|
// end of user-interactive data gathering loop, start of export processing
|
||
|
// loop
|
||
|
int count = 0; // count the number of sucessful runs
|
||
|
ExportKit activeSetting; // pointer to the settings in use for this export
|
||
|
for (tr = mIterator.First(mTracks); tr != NULL; tr = mIterator.Next()) {
|
||
|
|
||
|
// Only want wave tracks
|
||
|
if (tr->GetKind() != Track::Wave) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/* Select the track */
|
||
|
tr->SetSelected(true);
|
||
|
|
||
|
// Check for a linked track
|
||
|
tr2 = NULL;
|
||
|
if (tr->GetLinked()) {
|
||
|
tr2 = mIterator.Next();
|
||
|
if (tr2) {
|
||
|
// Select it also
|
||
|
tr2->SetSelected(true);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* get the settings to use for the export from the array */
|
||
|
activeSetting = exportSettings[count];
|
||
|
// export data
|
||
|
ok = DoExport(channels, activeSetting.destfile, true, activeSetting.t0, activeSetting.t1, activeSetting.filetags);
|
||
|
|
||
|
// Reset selection state
|
||
|
tr->SetSelected(false);
|
||
|
if (tr2) {
|
||
|
tr2->SetSelected(false);
|
||
|
}
|
||
|
|
||
|
// Stop if an error occurred
|
||
|
if (ok != eProgressSuccess && ok != eProgressStopped) {
|
||
|
break;
|
||
|
}
|
||
|
// increment export counter
|
||
|
count++;
|
||
|
|
||
|
}
|
||
|
|
||
|
// Restore the selection states
|
||
|
for (size_t i = 0; i < mSelected.GetCount(); i++) {
|
||
|
((Track *) selected[i])->SetSelected(true);
|
||
|
}
|
||
|
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
int ExportMultiple::DoExport(int channels,
|
||
|
wxFileName name,
|
||
|
bool selectedOnly,
|
||
|
double t0,
|
||
|
double t1,
|
||
|
Tags tags)
|
||
|
{
|
||
|
wxLogDebug(wxT("Doing multiple Export: File name \"%s\""), (name.GetFullName()).c_str());
|
||
|
wxLogDebug(wxT("Channels: %i, Start: %lf, End: %lf "), channels, t0, t1);
|
||
|
if (selectedOnly) wxLogDebug(wxT("Selected Region Only"));
|
||
|
else wxLogDebug(wxT("Whole Project"));
|
||
|
|
||
|
if (name.GetName().IsEmpty()) {
|
||
|
name.SetName(wxT("untitled"));
|
||
|
}
|
||
|
|
||
|
if (mOverwrite->GetValue()) {
|
||
|
// Make sure we don't overwrite (corrupt) alias files
|
||
|
if (!mProject->GetDirManager()->EnsureSafeFilename(name)) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
int i = 2;
|
||
|
wxString base(name.GetName());
|
||
|
while (name.FileExists()) {
|
||
|
name.SetName(wxString::Format(wxT("%s-%d"), base.c_str(), i++));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Call the format export routine
|
||
|
int success = mPlugins[mPluginIndex]->Export(mProject,
|
||
|
channels,
|
||
|
name.GetFullPath(),
|
||
|
selectedOnly,
|
||
|
t0,
|
||
|
t1,
|
||
|
NULL,
|
||
|
&tags,
|
||
|
mSubFormatIndex);
|
||
|
|
||
|
if (success == eProgressSuccess || success == eProgressStopped) {
|
||
|
mExported.Add(name.GetFullPath());
|
||
|
}
|
||
|
|
||
|
return success;
|
||
|
}
|
||
|
|
||
|
wxString ExportMultiple::MakeFileName(wxString input)
|
||
|
{
|
||
|
wxString newname; // name we are generating
|
||
|
|
||
|
// strip out anything that isn't allowed in file names on this platform
|
||
|
newname = Internat::SanitiseFilename(input, wxT("_"));
|
||
|
|
||
|
if(!newname.IsSameAs(input))
|
||
|
{ // need to get user to fix file name
|
||
|
// build the dialog
|
||
|
wxString msg;
|
||
|
msg.Printf(_("Label %s is not a legal file name. You cannot use any of: %s\nUse..."), input.c_str(), wxFileName::GetForbiddenChars().c_str());
|
||
|
wxTextEntryDialog dlg( this, msg, _("Save As..."), newname );
|
||
|
|
||
|
// And tell the validator about excluded chars
|
||
|
dlg.SetTextValidator( wxFILTER_EXCLUDE_CHAR_LIST );
|
||
|
wxTextValidator *tv = dlg.GetTextValidator();
|
||
|
tv->SetExcludes(exclude);
|
||
|
|
||
|
// Show the dialog and bail if the user cancels
|
||
|
if( dlg.ShowModal() == wxID_CANCEL )
|
||
|
{
|
||
|
return wxEmptyString;
|
||
|
}
|
||
|
// Extract the name from the dialog
|
||
|
newname = dlg.GetValue();
|
||
|
} // phew - end of file name sanitisation procedure
|
||
|
return newname;
|
||
|
}
|
||
|
void SuccessDialog::OnKeyDown(wxListEvent& event)
|
||
|
{
|
||
|
if (event.GetKeyCode() == WXK_RETURN)
|
||
|
EndModal(1);
|
||
|
else
|
||
|
event.Skip(); // allow standard behaviour
|
||
|
}
|
||
|
|
||
|
void SuccessDialog::OnItemActivated(wxListEvent& event)
|
||
|
{
|
||
|
EndModal(1);
|
||
|
}
|
||
|
|
||
|
void MouseEvtHandler::OnMouse(wxMouseEvent& event)
|
||
|
{
|
||
|
event.Skip(false);
|
||
|
}
|
||
|
|
||
|
// Indentation settings for Vim and Emacs and unique identifier for Arch, a
|
||
|
// version control system. Please do not modify past this point.
|
||
|
//
|
||
|
// Local Variables:
|
||
|
// c-basic-offset: 3
|
||
|
// indent-tabs-mode: nil
|
||
|
// End:
|
||
|
//
|
||
|
// vim: et sts=3 sw=3
|
||
|
// arch-tag: d6904b91-a320-4194-8d60-caa9175b6bb4
|