tag editor: make file parser/generator use main loop
This commit is contained in:
@@ -43,7 +43,7 @@ using Global::wFooter;
|
|||||||
TagEditor *myTagEditor = new TagEditor;
|
TagEditor *myTagEditor = new TagEditor;
|
||||||
|
|
||||||
const std::string TagEditor::PatternsFile = config_dir + "patterns.list";
|
const std::string TagEditor::PatternsFile = config_dir + "patterns.list";
|
||||||
std::vector<std::string> TagEditor::Patterns;
|
std::deque<std::string> TagEditor::Patterns;
|
||||||
|
|
||||||
const size_t TagEditor::MiddleColumnWidth = 26;
|
const size_t TagEditor::MiddleColumnWidth = 26;
|
||||||
size_t TagEditor::LeftColumnWidth;
|
size_t TagEditor::LeftColumnWidth;
|
||||||
@@ -51,12 +51,17 @@ size_t TagEditor::MiddleColumnStartX;
|
|||||||
size_t TagEditor::RightColumnWidth;
|
size_t TagEditor::RightColumnWidth;
|
||||||
size_t TagEditor::RightColumnStartX;
|
size_t TagEditor::RightColumnStartX;
|
||||||
|
|
||||||
|
const size_t TagEditor::FParserDialogWidth = 30;
|
||||||
|
const size_t TagEditor::FParserDialogHeight = 6;
|
||||||
|
|
||||||
|
size_t TagEditor::FParserWidth;
|
||||||
|
size_t TagEditor::FParserWidthOne;
|
||||||
|
size_t TagEditor::FParserWidthTwo;
|
||||||
|
size_t TagEditor::FParserHeight;
|
||||||
|
|
||||||
void TagEditor::Init()
|
void TagEditor::Init()
|
||||||
{
|
{
|
||||||
LeftColumnWidth = COLS/2-MiddleColumnWidth/2;
|
SetDimensions();
|
||||||
MiddleColumnStartX = LeftColumnWidth+1;
|
|
||||||
RightColumnWidth = COLS-LeftColumnWidth-MiddleColumnWidth-2;
|
|
||||||
RightColumnStartX = LeftColumnWidth+MiddleColumnWidth+2;
|
|
||||||
|
|
||||||
Albums = new Menu<string_pair>(0, MainStartY, LeftColumnWidth, MainHeight, "Albums", Config.main_color, brNone);
|
Albums = new Menu<string_pair>(0, MainStartY, LeftColumnWidth, MainHeight, "Albums", Config.main_color, brNone);
|
||||||
Albums->HighlightColor(Config.active_column_color);
|
Albums->HighlightColor(Config.active_column_color);
|
||||||
@@ -80,6 +85,27 @@ void TagEditor::Init()
|
|||||||
TagTypes->CyclicScrolling(Config.use_cyclic_scrolling);
|
TagTypes->CyclicScrolling(Config.use_cyclic_scrolling);
|
||||||
TagTypes->SetItemDisplayer(Display::Generic);
|
TagTypes->SetItemDisplayer(Display::Generic);
|
||||||
|
|
||||||
|
TagTypes->AddOption("Title");
|
||||||
|
TagTypes->AddOption("Artist");
|
||||||
|
TagTypes->AddOption("Album");
|
||||||
|
TagTypes->AddOption("Year");
|
||||||
|
TagTypes->AddOption("Track");
|
||||||
|
TagTypes->AddOption("Genre");
|
||||||
|
TagTypes->AddOption("Composer");
|
||||||
|
TagTypes->AddOption("Performer");
|
||||||
|
TagTypes->AddOption("Disc");
|
||||||
|
TagTypes->AddOption("Comment");
|
||||||
|
TagTypes->AddSeparator();
|
||||||
|
TagTypes->AddOption("Filename");
|
||||||
|
TagTypes->AddSeparator();
|
||||||
|
TagTypes->AddOption("Options", 1, 1);
|
||||||
|
TagTypes->AddSeparator();
|
||||||
|
TagTypes->AddOption("Reset");
|
||||||
|
TagTypes->AddOption("Save");
|
||||||
|
TagTypes->AddSeparator();
|
||||||
|
TagTypes->AddOption("Capitalize First Letters");
|
||||||
|
TagTypes->AddOption("lower all letters");
|
||||||
|
|
||||||
Tags = new Menu<MPD::Song>(RightColumnStartX, MainStartY, RightColumnWidth, MainHeight, "Tags", Config.main_color, brNone);
|
Tags = new Menu<MPD::Song>(RightColumnStartX, MainStartY, RightColumnWidth, MainHeight, "Tags", Config.main_color, brNone);
|
||||||
Tags->HighlightColor(Config.main_highlight_color);
|
Tags->HighlightColor(Config.main_highlight_color);
|
||||||
Tags->SetTimeout(ncmpcpp_window_timeout);
|
Tags->SetTimeout(ncmpcpp_window_timeout);
|
||||||
@@ -91,27 +117,65 @@ void TagEditor::Init()
|
|||||||
Tags->SetGetStringFunction(TagToString);
|
Tags->SetGetStringFunction(TagToString);
|
||||||
Tags->SetGetStringFunctionUserData(TagTypes);
|
Tags->SetGetStringFunctionUserData(TagTypes);
|
||||||
|
|
||||||
|
FParserDialog = new Menu<std::string>((COLS-FParserDialogWidth)/2, (MainHeight-FParserDialogHeight)/2+MainStartY, FParserDialogWidth, FParserDialogHeight, "", Config.main_color, Config.window_border);
|
||||||
|
FParserDialog->SetTimeout(ncmpcpp_window_timeout);
|
||||||
|
FParserDialog->CyclicScrolling(Config.use_cyclic_scrolling);
|
||||||
|
FParserDialog->SetItemDisplayer(Display::Generic);
|
||||||
|
FParserDialog->AddOption("Get tags from filename");
|
||||||
|
FParserDialog->AddOption("Rename files");
|
||||||
|
FParserDialog->AddSeparator();
|
||||||
|
FParserDialog->AddOption("Cancel");
|
||||||
|
|
||||||
|
FParser = new Menu<std::string>((COLS-FParserWidth)/2, (MainHeight-FParserHeight)/2+MainStartY, FParserWidthOne, FParserHeight, "_", Config.main_color, Config.active_window_border);
|
||||||
|
FParser->SetTimeout(ncmpcpp_window_timeout);
|
||||||
|
FParser->CyclicScrolling(Config.use_cyclic_scrolling);
|
||||||
|
FParser->SetItemDisplayer(Display::Generic);
|
||||||
|
|
||||||
|
FParserLegend = new Scrollpad((COLS-FParserWidth)/2+FParserWidthOne, (MainHeight-FParserHeight)/2+MainStartY, FParserWidthTwo, FParserHeight, "Legend", Config.main_color, Config.window_border);
|
||||||
|
FParserLegend->SetTimeout(ncmpcpp_window_timeout);
|
||||||
|
|
||||||
|
FParserPreview = new Scrollpad((COLS-FParserWidth)/2+FParserWidthOne, (MainHeight-FParserHeight)/2+MainStartY, FParserWidthTwo, FParserHeight, "Preview", Config.main_color, Config.window_border);
|
||||||
|
FParserPreview->SetTimeout(ncmpcpp_window_timeout);
|
||||||
|
|
||||||
w = LeftColumn;
|
w = LeftColumn;
|
||||||
isInitialized = 1;
|
isInitialized = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TagEditor::Resize()
|
void TagEditor::SetDimensions()
|
||||||
{
|
{
|
||||||
LeftColumnWidth = COLS/2-MiddleColumnWidth/2;
|
LeftColumnWidth = COLS/2-MiddleColumnWidth/2;
|
||||||
MiddleColumnStartX = LeftColumnWidth+1;
|
MiddleColumnStartX = LeftColumnWidth+1;
|
||||||
RightColumnWidth = COLS-LeftColumnWidth-MiddleColumnWidth-2;
|
RightColumnWidth = COLS-LeftColumnWidth-MiddleColumnWidth-2;
|
||||||
RightColumnStartX = LeftColumnWidth+MiddleColumnWidth+2;
|
RightColumnStartX = LeftColumnWidth+MiddleColumnWidth+2;
|
||||||
|
|
||||||
|
FParserWidth = COLS*0.9;
|
||||||
|
FParserHeight = std::min(size_t(LINES*0.8), MainHeight);
|
||||||
|
FParserWidthOne = FParserWidth/2;
|
||||||
|
FParserWidthTwo = FParserWidth-FParserWidthOne;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TagEditor::Resize()
|
||||||
|
{
|
||||||
|
SetDimensions();
|
||||||
|
|
||||||
Albums->Resize(LeftColumnWidth, MainHeight);
|
Albums->Resize(LeftColumnWidth, MainHeight);
|
||||||
Dirs->Resize(LeftColumnWidth, MainHeight);
|
Dirs->Resize(LeftColumnWidth, MainHeight);
|
||||||
TagTypes->Resize(MiddleColumnWidth, MainHeight);
|
TagTypes->Resize(MiddleColumnWidth, MainHeight);
|
||||||
Tags->Resize(RightColumnWidth, MainHeight);
|
Tags->Resize(RightColumnWidth, MainHeight);
|
||||||
|
FParser->Resize(FParserWidthOne, FParserHeight);
|
||||||
|
FParserLegend->Resize(FParserWidthTwo, FParserHeight);
|
||||||
|
FParserPreview->Resize(FParserWidthTwo, FParserHeight);
|
||||||
|
|
||||||
Albums->MoveTo(0, MainStartY);
|
Albums->MoveTo(0, MainStartY);
|
||||||
Dirs->MoveTo(0, MainStartY);
|
Dirs->MoveTo(0, MainStartY);
|
||||||
TagTypes->MoveTo(MiddleColumnStartX, MainStartY);
|
TagTypes->MoveTo(MiddleColumnStartX, MainStartY);
|
||||||
Tags->MoveTo(RightColumnStartX, MainStartY);
|
Tags->MoveTo(RightColumnStartX, MainStartY);
|
||||||
|
|
||||||
|
FParserDialog->MoveTo((COLS-FParserDialogWidth)/2, (MainHeight-FParserDialogHeight)/2+MainStartY);
|
||||||
|
FParser->MoveTo((COLS-FParserWidth)/2, (MainHeight-FParserHeight)/2+MainStartY);
|
||||||
|
FParserLegend->MoveTo((COLS-FParserWidth)/2+FParserWidthOne, (MainHeight-FParserHeight)/2+MainStartY);
|
||||||
|
FParserPreview->MoveTo((COLS-FParserWidth)/2+FParserWidthOne, (MainHeight-FParserHeight)/2+MainStartY);
|
||||||
|
|
||||||
hasToBeResized = 0;
|
hasToBeResized = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,30 +198,6 @@ void TagEditor::SwitchTo()
|
|||||||
myScreen = this;
|
myScreen = this;
|
||||||
Global::RedrawHeader = 1;
|
Global::RedrawHeader = 1;
|
||||||
Refresh();
|
Refresh();
|
||||||
|
|
||||||
if (TagTypes->Empty())
|
|
||||||
{
|
|
||||||
TagTypes->AddOption("Title");
|
|
||||||
TagTypes->AddOption("Artist");
|
|
||||||
TagTypes->AddOption("Album");
|
|
||||||
TagTypes->AddOption("Year");
|
|
||||||
TagTypes->AddOption("Track");
|
|
||||||
TagTypes->AddOption("Genre");
|
|
||||||
TagTypes->AddOption("Composer");
|
|
||||||
TagTypes->AddOption("Performer");
|
|
||||||
TagTypes->AddOption("Disc");
|
|
||||||
TagTypes->AddOption("Comment");
|
|
||||||
TagTypes->AddSeparator();
|
|
||||||
TagTypes->AddOption("Filename");
|
|
||||||
TagTypes->AddSeparator();
|
|
||||||
TagTypes->AddOption("Options", 1, 1);
|
|
||||||
TagTypes->AddSeparator();
|
|
||||||
TagTypes->AddOption("Reset");
|
|
||||||
TagTypes->AddOption("Save");
|
|
||||||
TagTypes->AddSeparator();
|
|
||||||
TagTypes->AddOption("Capitalize First Letters");
|
|
||||||
TagTypes->AddOption("lower all letters");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TagEditor::Refresh()
|
void TagEditor::Refresh()
|
||||||
@@ -167,6 +207,11 @@ void TagEditor::Refresh()
|
|||||||
TagTypes->Display();
|
TagTypes->Display();
|
||||||
mvvline(MainStartY, RightColumnStartX-1, 0, MainHeight);
|
mvvline(MainStartY, RightColumnStartX-1, 0, MainHeight);
|
||||||
Tags->Display();
|
Tags->Display();
|
||||||
|
|
||||||
|
if (w == FParser)
|
||||||
|
FParserHelper->Display();
|
||||||
|
else if (w == FParserHelper)
|
||||||
|
FParser->Display();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TagEditor::Update()
|
void TagEditor::Update()
|
||||||
@@ -281,24 +326,186 @@ void TagEditor::EnterPressed()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
ShowMessage("No subdirs found");
|
ShowMessage("No subdirs found");
|
||||||
return;
|
}
|
||||||
|
else if (w == FParserDialog)
|
||||||
|
{
|
||||||
|
size_t choice = FParserDialog->RealChoice();
|
||||||
|
if (choice == 2) // cancel
|
||||||
|
{
|
||||||
|
w = TagTypes;
|
||||||
|
Refresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GetPatternList();
|
||||||
|
|
||||||
|
// prepare additional windows
|
||||||
|
|
||||||
|
FParserLegend->Clear();
|
||||||
|
*FParserLegend << "%a - artist\n";
|
||||||
|
*FParserLegend << "%t - title\n";
|
||||||
|
*FParserLegend << "%b - album\n";
|
||||||
|
*FParserLegend << "%y - year\n";
|
||||||
|
*FParserLegend << "%n - track number\n";
|
||||||
|
*FParserLegend << "%g - genre\n";
|
||||||
|
*FParserLegend << "%c - composer\n";
|
||||||
|
*FParserLegend << "%p - performer\n";
|
||||||
|
*FParserLegend << "%d - disc\n";
|
||||||
|
*FParserLegend << "%C - comment\n\n";
|
||||||
|
*FParserLegend << fmtBold << "Files:\n" << fmtBoldEnd;
|
||||||
|
for (MPD::SongList::const_iterator it = EditedSongs.begin(); it != EditedSongs.end(); ++it)
|
||||||
|
*FParserLegend << Config.color2 << " * " << clEnd << (*it)->GetName() << "\n";
|
||||||
|
FParserLegend->Flush();
|
||||||
|
|
||||||
|
if (!Patterns.empty())
|
||||||
|
Config.pattern = Patterns.front();
|
||||||
|
FParser->Clear();
|
||||||
|
FParser->Reset();
|
||||||
|
FParser->AddOption("Pattern: " + Config.pattern);
|
||||||
|
FParser->AddOption("Preview");
|
||||||
|
FParser->AddOption("Legend");
|
||||||
|
FParser->AddSeparator();
|
||||||
|
FParser->AddOption("Proceed");
|
||||||
|
FParser->AddOption("Cancel");
|
||||||
|
if (!Patterns.empty())
|
||||||
|
{
|
||||||
|
FParser->AddSeparator();
|
||||||
|
FParser->AddOption("Recent patterns", 1, 1);
|
||||||
|
FParser->AddSeparator();
|
||||||
|
for (std::deque<std::string>::const_iterator it = Patterns.begin(); it != Patterns.end(); ++it)
|
||||||
|
FParser->AddOption(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
FParser->SetTitle(choice == 0 ? "Get tags from filename" : "Rename files");
|
||||||
|
w = FParser;
|
||||||
|
FParserUsePreview = 1;
|
||||||
|
FParserHelper = FParserLegend;
|
||||||
|
FParserHelper->Display();
|
||||||
|
}
|
||||||
|
else if (w == FParser)
|
||||||
|
{
|
||||||
|
bool quit = 0;
|
||||||
|
size_t pos = FParser->RealChoice();
|
||||||
|
|
||||||
|
if (pos == 3) // save
|
||||||
|
{
|
||||||
|
pos = 1; // "preview without preview"
|
||||||
|
FParserUsePreview = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos == 0) // change pattern
|
||||||
|
{
|
||||||
|
LockStatusbar();
|
||||||
|
Statusbar() << "Pattern: ";
|
||||||
|
std::string new_pattern = wFooter->GetString(Config.pattern);
|
||||||
|
UnlockStatusbar();
|
||||||
|
if (!new_pattern.empty())
|
||||||
|
{
|
||||||
|
Config.pattern = new_pattern;
|
||||||
|
FParser->at(0) = "Pattern: ";
|
||||||
|
FParser->at(0) += Config.pattern;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pos == 1) // preview or proceed (see above if for pos == 3)
|
||||||
|
{
|
||||||
|
bool success = 1;
|
||||||
|
ShowMessage("Parsing...");
|
||||||
|
FParserPreview->Clear();
|
||||||
|
for (MPD::SongList::iterator it = EditedSongs.begin(); it != EditedSongs.end(); ++it)
|
||||||
|
{
|
||||||
|
MPD::Song &s = **it;
|
||||||
|
if (FParserDialog->Choice() == 0) // get tags from filename
|
||||||
|
{
|
||||||
|
if (FParserUsePreview)
|
||||||
|
{
|
||||||
|
*FParserPreview << fmtBold << s.GetName() << ":\n" << fmtBoldEnd;
|
||||||
|
*FParserPreview << ParseFilename(s, Config.pattern, FParserUsePreview) << "\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ParseFilename(s, Config.pattern, FParserUsePreview);
|
||||||
|
}
|
||||||
|
else // rename files
|
||||||
|
{
|
||||||
|
std::string file = s.GetName();
|
||||||
|
size_t last_dot = file.rfind(".");
|
||||||
|
std::string extension = file.substr(last_dot);
|
||||||
|
std::string new_file = GenerateFilename(s, "{" + Config.pattern + "}");
|
||||||
|
if (new_file.empty() && !FParserUsePreview)
|
||||||
|
{
|
||||||
|
ShowMessage("File \"%s\" would have an empty name!", s.GetName().c_str());
|
||||||
|
FParserUsePreview = 1;
|
||||||
|
success = 0;
|
||||||
|
}
|
||||||
|
if (!FParserUsePreview)
|
||||||
|
s.SetNewName(new_file + extension);
|
||||||
|
*FParserPreview << file << Config.color2 << " -> " << clEnd;
|
||||||
|
if (new_file.empty())
|
||||||
|
*FParserPreview << Config.empty_tags_color << Config.empty_tag << clEnd;
|
||||||
|
else
|
||||||
|
*FParserPreview << new_file << extension;
|
||||||
|
*FParserPreview << "\n\n";
|
||||||
|
if (!success)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (FParserUsePreview)
|
||||||
|
{
|
||||||
|
FParserHelper = FParserPreview;
|
||||||
|
FParserHelper->Flush();
|
||||||
|
FParserHelper->Display();
|
||||||
|
}
|
||||||
|
else if (success)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < Patterns.size(); ++i)
|
||||||
|
{
|
||||||
|
if (Patterns[i] == Config.pattern)
|
||||||
|
{
|
||||||
|
Patterns.erase(Patterns.begin()+i);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Patterns.insert(Patterns.begin(), Config.pattern);
|
||||||
|
ShowMessage("Operation finished!");
|
||||||
|
quit = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pos == 2) // show legend
|
||||||
|
{
|
||||||
|
FParserHelper = FParserLegend;
|
||||||
|
FParserHelper->Display();
|
||||||
|
}
|
||||||
|
else if (pos == 4) // cancel
|
||||||
|
{
|
||||||
|
quit = 1;
|
||||||
|
}
|
||||||
|
else // list of patterns
|
||||||
|
{
|
||||||
|
Config.pattern = FParser->Current();
|
||||||
|
FParser->at(0) = "Pattern: " + Config.pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quit)
|
||||||
|
{
|
||||||
|
SavePatternList();
|
||||||
|
w = TagTypes;
|
||||||
|
Refresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Tags->Empty()) // we need songs to deal with, don't we?
|
if ((w != TagTypes && w != Tags) || Tags->Empty()) // after this point we start dealing with tags
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// if there are selected songs, perform operations only on them
|
EditedSongs.clear();
|
||||||
MPD::SongList list;
|
if (Tags->hasSelected()) // if there are selected songs, perform operations only on them
|
||||||
if (Tags->hasSelected())
|
|
||||||
{
|
{
|
||||||
std::vector<size_t> selected;
|
std::vector<size_t> selected;
|
||||||
Tags->GetSelected(selected);
|
Tags->GetSelected(selected);
|
||||||
for (std::vector<size_t>::const_iterator it = selected.begin(); it != selected.end(); ++it)
|
for (std::vector<size_t>::const_iterator it = selected.begin(); it != selected.end(); ++it)
|
||||||
list.push_back(&(*Tags)[*it]);
|
EditedSongs.push_back(&(*Tags)[*it]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
for (size_t i = 0; i < Tags->Size(); ++i)
|
for (size_t i = 0; i < Tags->Size(); ++i)
|
||||||
list.push_back(&(*Tags)[i]);
|
EditedSongs.push_back(&(*Tags)[i]);
|
||||||
|
|
||||||
MPD::Song::GetFunction get = 0;
|
MPD::Song::GetFunction get = 0;
|
||||||
MPD::Song::SetFunction set = 0;
|
MPD::Song::SetFunction set = 0;
|
||||||
@@ -339,8 +546,8 @@ void TagEditor::EnterPressed()
|
|||||||
while (in != 'y' && in != 'n');
|
while (in != 'y' && in != 'n');
|
||||||
if (in == 'y')
|
if (in == 'y')
|
||||||
{
|
{
|
||||||
MPD::SongList::iterator it = list.begin();
|
MPD::SongList::iterator it = EditedSongs.begin();
|
||||||
for (unsigned i = 1; i <= list.size(); ++i, ++it)
|
for (unsigned i = 1; i <= EditedSongs.size(); ++i, ++it)
|
||||||
(*it)->SetTrack(i);
|
(*it)->SetTrack(i);
|
||||||
ShowMessage("Tracks numbered!");
|
ShowMessage("Tracks numbered!");
|
||||||
}
|
}
|
||||||
@@ -374,8 +581,13 @@ void TagEditor::EnterPressed()
|
|||||||
{
|
{
|
||||||
if (w == TagTypes)
|
if (w == TagTypes)
|
||||||
{
|
{
|
||||||
DealWithFilenames(list);
|
if (size_t(COLS) < FParserDialogWidth || MainHeight < FParserDialogHeight)
|
||||||
Refresh();
|
{
|
||||||
|
ShowMessage("Screen is too small to display additional windows!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FParserDialog->Reset();
|
||||||
|
w = FParserDialog;
|
||||||
}
|
}
|
||||||
else if (w == Tags)
|
else if (w == Tags)
|
||||||
{
|
{
|
||||||
@@ -404,7 +616,7 @@ void TagEditor::EnterPressed()
|
|||||||
{
|
{
|
||||||
bool success = 1;
|
bool success = 1;
|
||||||
ShowMessage("Writing changes...");
|
ShowMessage("Writing changes...");
|
||||||
for (MPD::SongList::iterator it = list.begin(); it != list.end(); ++it)
|
for (MPD::SongList::iterator it = EditedSongs.begin(); it != EditedSongs.end(); ++it)
|
||||||
{
|
{
|
||||||
ShowMessage("Writing tags in \"%s\"...", (*it)->GetName().c_str());
|
ShowMessage("Writing tags in \"%s\"...", (*it)->GetName().c_str());
|
||||||
if (!WriteTags(**it))
|
if (!WriteTags(**it))
|
||||||
@@ -431,7 +643,7 @@ void TagEditor::EnterPressed()
|
|||||||
case 13: // capitalize first letters
|
case 13: // capitalize first letters
|
||||||
{
|
{
|
||||||
ShowMessage("Processing...");
|
ShowMessage("Processing...");
|
||||||
for (MPD::SongList::iterator it = list.begin(); it != list.end(); ++it)
|
for (MPD::SongList::iterator it = EditedSongs.begin(); it != EditedSongs.end(); ++it)
|
||||||
CapitalizeFirstLetters(**it);
|
CapitalizeFirstLetters(**it);
|
||||||
ShowMessage("Done!");
|
ShowMessage("Done!");
|
||||||
break;
|
break;
|
||||||
@@ -439,7 +651,7 @@ void TagEditor::EnterPressed()
|
|||||||
case 14: // lower all letters
|
case 14: // lower all letters
|
||||||
{
|
{
|
||||||
ShowMessage("Processing...");
|
ShowMessage("Processing...");
|
||||||
for (MPD::SongList::iterator it = list.begin(); it != list.end(); ++it)
|
for (MPD::SongList::iterator it = EditedSongs.begin(); it != EditedSongs.end(); ++it)
|
||||||
LowerAllLetters(**it);
|
LowerAllLetters(**it);
|
||||||
ShowMessage("Done!");
|
ShowMessage("Done!");
|
||||||
break;
|
break;
|
||||||
@@ -454,7 +666,7 @@ void TagEditor::EnterPressed()
|
|||||||
Statusbar() << fmtBold << TagTypes->Current() << fmtBoldEnd << ": ";
|
Statusbar() << fmtBold << TagTypes->Current() << fmtBoldEnd << ": ";
|
||||||
std::string new_tag = wFooter->GetString((Tags->Current().*get)());
|
std::string new_tag = wFooter->GetString((Tags->Current().*get)());
|
||||||
UnlockStatusbar();
|
UnlockStatusbar();
|
||||||
for (MPD::SongList::iterator it = list.begin(); it != list.end(); ++it)
|
for (MPD::SongList::iterator it = EditedSongs.begin(); it != EditedSongs.end(); ++it)
|
||||||
(**it.*set)(new_tag);
|
(**it.*set)(new_tag);
|
||||||
}
|
}
|
||||||
else if (w == Tags && set)
|
else if (w == Tags && set)
|
||||||
@@ -489,7 +701,43 @@ void TagEditor::SpacePressed()
|
|||||||
|
|
||||||
void TagEditor::MouseButtonPressed(MEVENT me)
|
void TagEditor::MouseButtonPressed(MEVENT me)
|
||||||
{
|
{
|
||||||
if (!LeftColumn->Empty() && LeftColumn->hasCoords(me.x, me.y))
|
if (w == FParserDialog)
|
||||||
|
{
|
||||||
|
if (FParserDialog->hasCoords(me.x, me.y))
|
||||||
|
{
|
||||||
|
if (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED))
|
||||||
|
{
|
||||||
|
FParserDialog->Goto(me.y);
|
||||||
|
if (me.bstate & BUTTON3_PRESSED)
|
||||||
|
EnterPressed();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Screen<Window>::MouseButtonPressed(me);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (w == FParser || w == FParserHelper)
|
||||||
|
{
|
||||||
|
if (FParser->hasCoords(me.x, me.y))
|
||||||
|
{
|
||||||
|
if (w != FParser)
|
||||||
|
PrevColumn();
|
||||||
|
if (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED))
|
||||||
|
{
|
||||||
|
FParser->Goto(me.y);
|
||||||
|
if (me.bstate & BUTTON3_PRESSED)
|
||||||
|
EnterPressed();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Screen<Window>::MouseButtonPressed(me);
|
||||||
|
}
|
||||||
|
else if (FParserHelper->hasCoords(me.x, me.y))
|
||||||
|
{
|
||||||
|
if (w != FParserHelper)
|
||||||
|
NextColumn();
|
||||||
|
reinterpret_cast<Screen<Scrollpad> *>(this)->Screen<Scrollpad>::MouseButtonPressed(me);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!LeftColumn->Empty() && LeftColumn->hasCoords(me.x, me.y))
|
||||||
{
|
{
|
||||||
if (w != LeftColumn)
|
if (w != LeftColumn)
|
||||||
{
|
{
|
||||||
@@ -592,6 +840,14 @@ void TagEditor::NextColumn()
|
|||||||
w = Tags;
|
w = Tags;
|
||||||
Tags->HighlightColor(Config.active_column_color);
|
Tags->HighlightColor(Config.active_column_color);
|
||||||
}
|
}
|
||||||
|
else if (w == FParser)
|
||||||
|
{
|
||||||
|
FParser->SetBorder(Config.window_border);
|
||||||
|
FParser->Display();
|
||||||
|
w = FParserHelper;
|
||||||
|
FParserHelper->SetBorder(Config.active_window_border);
|
||||||
|
FParserHelper->Display();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TagEditor::PrevColumn()
|
void TagEditor::PrevColumn()
|
||||||
@@ -610,6 +866,14 @@ void TagEditor::PrevColumn()
|
|||||||
w = LeftColumn;
|
w = LeftColumn;
|
||||||
LeftColumn->HighlightColor(Config.active_column_color);
|
LeftColumn->HighlightColor(Config.active_column_color);
|
||||||
}
|
}
|
||||||
|
else if (w == FParserHelper)
|
||||||
|
{
|
||||||
|
FParserHelper->SetBorder(Config.window_border);
|
||||||
|
FParserHelper->Display();
|
||||||
|
w = FParser;
|
||||||
|
FParser->SetBorder(Config.active_window_border);
|
||||||
|
FParser->Display();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TagEditor::ReadTags(mpd_Song *s)
|
void TagEditor::ReadTags(mpd_Song *s)
|
||||||
@@ -888,7 +1152,7 @@ void TagEditor::SavePatternList()
|
|||||||
std::ofstream output(PatternsFile.c_str());
|
std::ofstream output(PatternsFile.c_str());
|
||||||
if (output.is_open())
|
if (output.is_open())
|
||||||
{
|
{
|
||||||
for (std::vector<std::string>::const_iterator it = Patterns.begin(); it != Patterns.end() && it != Patterns.begin()+30; ++it)
|
for (std::deque<std::string>::const_iterator it = Patterns.begin(); it != Patterns.end() && it != Patterns.begin()+30; ++it)
|
||||||
output << *it << std::endl;
|
output << *it << std::endl;
|
||||||
output.close();
|
output.close();
|
||||||
}
|
}
|
||||||
@@ -980,255 +1244,5 @@ std::string TagEditor::ParseFilename(MPD::Song &s, std::string mask, bool previe
|
|||||||
return result.str();
|
return result.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TagEditor::DealWithFilenames(MPD::SongList &v)
|
|
||||||
{
|
|
||||||
size_t width = 30;
|
|
||||||
size_t height = 6;
|
|
||||||
|
|
||||||
if (size_t(COLS) < width || MainHeight < height)
|
|
||||||
{
|
|
||||||
ShowMessage("Screen is too small to display additional windows!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GetPatternList();
|
|
||||||
|
|
||||||
Menu<std::string> *Main = new Menu<std::string>((COLS-width)/2, (MainHeight-height)/2+MainStartY, width, height, "", Config.main_color, Config.window_border);
|
|
||||||
Main->SetTimeout(ncmpcpp_window_timeout);
|
|
||||||
Main->CyclicScrolling(Config.use_cyclic_scrolling);
|
|
||||||
Main->SetItemDisplayer(Display::Generic);
|
|
||||||
Main->AddOption("Get tags from filename");
|
|
||||||
Main->AddOption("Rename files");
|
|
||||||
Main->AddSeparator();
|
|
||||||
Main->AddOption("Cancel");
|
|
||||||
Main->Display();
|
|
||||||
|
|
||||||
int input = 0;
|
|
||||||
while (!Keypressed(input, Key.Enter))
|
|
||||||
{
|
|
||||||
TraceMpdStatus();
|
|
||||||
Main->Refresh();
|
|
||||||
Main->ReadKey(input);
|
|
||||||
if (Keypressed(input, Key.Down))
|
|
||||||
Main->Scroll(wDown);
|
|
||||||
else if (Keypressed(input, Key.Up))
|
|
||||||
Main->Scroll(wUp);
|
|
||||||
}
|
|
||||||
|
|
||||||
width = COLS*0.9;
|
|
||||||
height = std::min(size_t(LINES*0.8), MainHeight);
|
|
||||||
bool exit = 0;
|
|
||||||
bool preview = 1;
|
|
||||||
size_t choice = Main->Choice();
|
|
||||||
size_t one_width = width/2;
|
|
||||||
size_t two_width = width-one_width;
|
|
||||||
|
|
||||||
delete Main;
|
|
||||||
|
|
||||||
Main = 0;
|
|
||||||
Scrollpad *Helper = 0;
|
|
||||||
Scrollpad *Legend = 0;
|
|
||||||
Scrollpad *Preview = 0;
|
|
||||||
Window *Active = 0;
|
|
||||||
|
|
||||||
if (choice != 3)
|
|
||||||
{
|
|
||||||
Legend = new Scrollpad((COLS-width)/2+one_width, (MainHeight-height)/2+MainStartY, two_width, height, "Legend", Config.main_color, Config.window_border);
|
|
||||||
Legend->SetTimeout(ncmpcpp_window_timeout);
|
|
||||||
*Legend << "%a - artist\n";
|
|
||||||
*Legend << "%t - title\n";
|
|
||||||
*Legend << "%b - album\n";
|
|
||||||
*Legend << "%y - year\n";
|
|
||||||
*Legend << "%n - track number\n";
|
|
||||||
*Legend << "%g - genre\n";
|
|
||||||
*Legend << "%c - composer\n";
|
|
||||||
*Legend << "%p - performer\n";
|
|
||||||
*Legend << "%d - disc\n";
|
|
||||||
*Legend << "%C - comment\n\n";
|
|
||||||
*Legend << fmtBold << "Files:\n" << fmtBoldEnd;
|
|
||||||
for (MPD::SongList::const_iterator it = v.begin(); it != v.end(); ++it)
|
|
||||||
*Legend << Config.color2 << " * " << clEnd << (*it)->GetName() << "\n";
|
|
||||||
Legend->Flush();
|
|
||||||
|
|
||||||
Preview = Legend->EmptyClone();
|
|
||||||
Preview->SetTitle("Preview");
|
|
||||||
Preview->SetTimeout(ncmpcpp_window_timeout);
|
|
||||||
|
|
||||||
Main = new Menu<std::string>((COLS-width)/2, (MainHeight-height)/2+MainStartY, one_width, height, "", Config.main_color, Config.active_window_border);
|
|
||||||
Main->SetTimeout(ncmpcpp_window_timeout);
|
|
||||||
Main->CyclicScrolling(Config.use_cyclic_scrolling);
|
|
||||||
Main->SetItemDisplayer(Display::Generic);
|
|
||||||
|
|
||||||
if (!Patterns.empty())
|
|
||||||
Config.pattern = Patterns.front();
|
|
||||||
Main->AddOption("Pattern: " + Config.pattern);
|
|
||||||
Main->AddOption("Preview");
|
|
||||||
Main->AddOption("Legend");
|
|
||||||
Main->AddSeparator();
|
|
||||||
Main->AddOption("Proceed");
|
|
||||||
Main->AddOption("Cancel");
|
|
||||||
if (!Patterns.empty())
|
|
||||||
{
|
|
||||||
Main->AddSeparator();
|
|
||||||
Main->AddOption("Recent patterns", 1, 1);
|
|
||||||
Main->AddSeparator();
|
|
||||||
for (std::vector<std::string>::const_iterator it = Patterns.begin(); it != Patterns.end(); ++it)
|
|
||||||
Main->AddOption(*it);
|
|
||||||
}
|
|
||||||
|
|
||||||
Active = Main;
|
|
||||||
Helper = Legend;
|
|
||||||
|
|
||||||
Main->SetTitle(!choice ? "Get tags from filename" : "Rename files");
|
|
||||||
Main->Display();
|
|
||||||
Helper->Display();
|
|
||||||
|
|
||||||
while (!exit)
|
|
||||||
{
|
|
||||||
TraceMpdStatus();
|
|
||||||
Active->Refresh();
|
|
||||||
Active->ReadKey(input);
|
|
||||||
|
|
||||||
if (Keypressed(input, Key.Up))
|
|
||||||
Active->Scroll(wUp);
|
|
||||||
else if (Keypressed(input, Key.Down))
|
|
||||||
Active->Scroll(wDown);
|
|
||||||
else if (Keypressed(input, Key.PageUp))
|
|
||||||
Active->Scroll(wPageUp);
|
|
||||||
else if (Keypressed(input, Key.PageDown))
|
|
||||||
Active->Scroll(wPageDown);
|
|
||||||
else if (Keypressed(input, Key.Home))
|
|
||||||
Active->Scroll(wHome);
|
|
||||||
else if (Keypressed(input, Key.End))
|
|
||||||
Active->Scroll(wEnd);
|
|
||||||
else if (Keypressed(input, Key.Enter) && Active == Main)
|
|
||||||
{
|
|
||||||
switch (Main->RealChoice())
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
LockStatusbar();
|
|
||||||
Statusbar() << "Pattern: ";
|
|
||||||
std::string new_pattern = wFooter->GetString(Config.pattern);
|
|
||||||
UnlockStatusbar();
|
|
||||||
if (!new_pattern.empty())
|
|
||||||
{
|
|
||||||
Config.pattern = new_pattern;
|
|
||||||
Main->at(0) = "Pattern: ";
|
|
||||||
Main->at(0) += Config.pattern;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3: // save
|
|
||||||
preview = 0;
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
bool success = 1;
|
|
||||||
ShowMessage("Parsing...");
|
|
||||||
Preview->Clear();
|
|
||||||
for (MPD::SongList::iterator it = v.begin(); it != v.end(); ++it)
|
|
||||||
{
|
|
||||||
MPD::Song &s = **it;
|
|
||||||
if (!choice)
|
|
||||||
{
|
|
||||||
if (preview)
|
|
||||||
{
|
|
||||||
*Preview << fmtBold << s.GetName() << ":\n" << fmtBoldEnd;
|
|
||||||
*Preview << ParseFilename(s, Config.pattern, preview) << "\n";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ParseFilename(s, Config.pattern, preview);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::string file = s.GetName();
|
|
||||||
size_t last_dot = file.rfind(".");
|
|
||||||
std::string extension = file.substr(last_dot);
|
|
||||||
basic_buffer<my_char_t> new_file;
|
|
||||||
new_file << TO_WSTRING(GenerateFilename(s, "{" + Config.pattern + "}"));
|
|
||||||
if (new_file.Str().empty())
|
|
||||||
{
|
|
||||||
if (preview)
|
|
||||||
new_file << clRed << "!EMPTY!" << clEnd;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ShowMessage("File \"%s\" would have an empty name!", s.GetName().c_str());
|
|
||||||
success = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!preview)
|
|
||||||
s.SetNewName(TO_STRING(new_file.Str()) + extension);
|
|
||||||
*Preview << file << Config.color2 << " -> " << clEnd << new_file << extension << "\n\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
preview = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < Patterns.size(); ++i)
|
|
||||||
{
|
|
||||||
if (Patterns[i] == Config.pattern)
|
|
||||||
{
|
|
||||||
Patterns.erase(Patterns.begin()+i);
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Patterns.insert(Patterns.begin(), Config.pattern);
|
|
||||||
}
|
|
||||||
ShowMessage("Operation finished!");
|
|
||||||
if (preview)
|
|
||||||
{
|
|
||||||
Helper = Preview;
|
|
||||||
Helper->Flush();
|
|
||||||
Helper->Display();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case 4:
|
|
||||||
{
|
|
||||||
exit = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
Helper = Legend;
|
|
||||||
Helper->Display();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
Config.pattern = Main->Current();
|
|
||||||
Main->at(0) = "Pattern: " + Config.pattern;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Keypressed(input, Key.VolumeUp) && Active == Main)
|
|
||||||
{
|
|
||||||
Active->SetBorder(Config.window_border);
|
|
||||||
Active->Display();
|
|
||||||
Active = Helper;
|
|
||||||
Active->SetBorder(Config.active_window_border);
|
|
||||||
Active->Display();
|
|
||||||
}
|
|
||||||
else if (Keypressed(input, Key.VolumeDown) && Active == Helper)
|
|
||||||
{
|
|
||||||
Active->SetBorder(Config.window_border);
|
|
||||||
Active->Display();
|
|
||||||
Active = Main;
|
|
||||||
Active->SetBorder(Config.active_window_border);
|
|
||||||
Active->Display();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SavePatternList();
|
|
||||||
delete Main;
|
|
||||||
delete Legend;
|
|
||||||
delete Preview;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#ifdef HAVE_TAGLIB_H
|
#ifdef HAVE_TAGLIB_H
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
// taglib headers
|
// taglib headers
|
||||||
#include "fileref.h"
|
#include "fileref.h"
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
@@ -37,7 +39,7 @@
|
|||||||
class TagEditor : public Screen<Window>
|
class TagEditor : public Screen<Window>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TagEditor() : itsBrowsedDir("/") { }
|
TagEditor() : FParser(0), FParserHelper(0), FParserLegend(0), FParserPreview(0), itsBrowsedDir("/") { }
|
||||||
|
|
||||||
virtual void Resize();
|
virtual void Resize();
|
||||||
virtual void SwitchTo();
|
virtual void SwitchTo();
|
||||||
@@ -80,6 +82,16 @@ class TagEditor : public Screen<Window>
|
|||||||
virtual void Init();
|
virtual void Init();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void SetDimensions();
|
||||||
|
|
||||||
|
MPD::SongList EditedSongs;
|
||||||
|
Menu<std::string> *FParserDialog;
|
||||||
|
Menu<std::string> *FParser;
|
||||||
|
Scrollpad *FParserHelper;
|
||||||
|
Scrollpad *FParserLegend;
|
||||||
|
Scrollpad *FParserPreview;
|
||||||
|
bool FParserUsePreview;
|
||||||
|
|
||||||
static std::string CapitalizeFirstLetters(const std::string &);
|
static std::string CapitalizeFirstLetters(const std::string &);
|
||||||
static void CapitalizeFirstLetters(MPD::Song &);
|
static void CapitalizeFirstLetters(MPD::Song &);
|
||||||
static void LowerAllLetters(MPD::Song &);
|
static void LowerAllLetters(MPD::Song &);
|
||||||
@@ -91,21 +103,26 @@ class TagEditor : public Screen<Window>
|
|||||||
static std::string GenerateFilename(const MPD::Song &, const std::string &);
|
static std::string GenerateFilename(const MPD::Song &, const std::string &);
|
||||||
static std::string ParseFilename(MPD::Song &, std::string, bool);
|
static std::string ParseFilename(MPD::Song &, std::string, bool);
|
||||||
|
|
||||||
static void DealWithFilenames(MPD::SongList &);
|
|
||||||
|
|
||||||
static std::string TagToString(const MPD::Song &, void *);
|
static std::string TagToString(const MPD::Song &, void *);
|
||||||
|
|
||||||
std::string itsBrowsedDir;
|
std::string itsBrowsedDir;
|
||||||
std::string itsHighlightedDir;
|
std::string itsHighlightedDir;
|
||||||
|
|
||||||
static const std::string PatternsFile;
|
static const std::string PatternsFile;
|
||||||
static std::vector<std::string> Patterns;
|
static std::deque<std::string> Patterns;
|
||||||
|
|
||||||
static const size_t MiddleColumnWidth;
|
static const size_t MiddleColumnWidth;
|
||||||
static size_t LeftColumnWidth;
|
static size_t LeftColumnWidth;
|
||||||
static size_t MiddleColumnStartX;
|
static size_t MiddleColumnStartX;
|
||||||
static size_t RightColumnWidth;
|
static size_t RightColumnWidth;
|
||||||
static size_t RightColumnStartX;
|
static size_t RightColumnStartX;
|
||||||
|
|
||||||
|
static const size_t FParserDialogWidth;
|
||||||
|
static const size_t FParserDialogHeight;
|
||||||
|
static size_t FParserWidth;
|
||||||
|
static size_t FParserWidthOne;
|
||||||
|
static size_t FParserWidthTwo;
|
||||||
|
static size_t FParserHeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern TagEditor *myTagEditor;
|
extern TagEditor *myTagEditor;
|
||||||
|
|||||||
Reference in New Issue
Block a user