|
|
|
|
@@ -252,15 +252,16 @@ void setWindowsDimensions()
|
|
|
|
|
FooterHeight = Config.statusbar_visibility ? 2 : 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool askYesNoQuestion(const boost::format &fmt)
|
|
|
|
|
void confirmAction(const boost::format &description)
|
|
|
|
|
{
|
|
|
|
|
Statusbar::ScopedLock lock;
|
|
|
|
|
Statusbar::put() << fmt.str()
|
|
|
|
|
Statusbar::put() << description.str()
|
|
|
|
|
<< " [" << NC::Format::Bold << 'y' << NC::Format::NoBold
|
|
|
|
|
<< '/' << NC::Format::Bold << 'n' << NC::Format::NoBold
|
|
|
|
|
<< "] ";
|
|
|
|
|
auto answer = Statusbar::Helpers::promptReturnOneOf({"y", "n"});
|
|
|
|
|
return answer == "y";
|
|
|
|
|
if (answer == "n")
|
|
|
|
|
throw NC::PromptAborted(std::move(answer));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isMPDMusicDirSet()
|
|
|
|
|
@@ -678,38 +679,37 @@ void DeleteBrowserItems::run()
|
|
|
|
|
question = boost::format("Delete %1% \"%2%\"?")
|
|
|
|
|
% itemTypeToString(item.type) % wideShorten(iname, COLS-question.size()-10);
|
|
|
|
|
}
|
|
|
|
|
bool yes = askYesNoQuestion(question);
|
|
|
|
|
if (yes)
|
|
|
|
|
confirmAction(question);
|
|
|
|
|
bool success = true;
|
|
|
|
|
auto list = getSelectedOrCurrent(
|
|
|
|
|
myBrowser->main().begin(),
|
|
|
|
|
myBrowser->main().end(),
|
|
|
|
|
myBrowser->main().currentI()
|
|
|
|
|
);
|
|
|
|
|
for (const auto &item : list)
|
|
|
|
|
{
|
|
|
|
|
bool success = true;
|
|
|
|
|
auto list = getSelectedOrCurrent(myBrowser->main().begin(), myBrowser->main().end(), myBrowser->main().currentI());
|
|
|
|
|
for (auto it = list.begin(); it != list.end(); ++it)
|
|
|
|
|
const MPD::Item &i = item->value();
|
|
|
|
|
std::string iname = i.type == MPD::itSong ? i.song->getName() : i.name;
|
|
|
|
|
std::string errmsg;
|
|
|
|
|
if (myBrowser->deleteItem(i, errmsg))
|
|
|
|
|
{
|
|
|
|
|
const MPD::Item &i = (*it)->value();
|
|
|
|
|
std::string iname = i.type == MPD::itSong ? i.song->getName() : i.name;
|
|
|
|
|
std::string errmsg;
|
|
|
|
|
if (myBrowser->deleteItem(i, errmsg))
|
|
|
|
|
{
|
|
|
|
|
const char msg[] = "\"%1%\" deleted";
|
|
|
|
|
Statusbar::printf(msg, wideShorten(iname, COLS-const_strlen(msg)));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Statusbar::print(errmsg);
|
|
|
|
|
success = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
const char msg[] = "\"%1%\" deleted";
|
|
|
|
|
Statusbar::printf(msg, wideShorten(iname, COLS-const_strlen(msg)));
|
|
|
|
|
}
|
|
|
|
|
if (success)
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (myBrowser->isLocal())
|
|
|
|
|
myBrowser->GetDirectory(myBrowser->CurrentDir());
|
|
|
|
|
else
|
|
|
|
|
Mpd.UpdateDirectory(myBrowser->CurrentDir());
|
|
|
|
|
Statusbar::print(errmsg);
|
|
|
|
|
success = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Statusbar::print("Aborted");
|
|
|
|
|
if (success)
|
|
|
|
|
{
|
|
|
|
|
if (myBrowser->isLocal())
|
|
|
|
|
myBrowser->GetDirectory(myBrowser->CurrentDir());
|
|
|
|
|
else
|
|
|
|
|
Mpd.UpdateDirectory(myBrowser->CurrentDir());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DeleteStoredPlaylist::canBeRun() const
|
|
|
|
|
@@ -727,20 +727,19 @@ void DeleteStoredPlaylist::run()
|
|
|
|
|
else
|
|
|
|
|
question = boost::format("Delete playlist \"%1%\"?")
|
|
|
|
|
% wideShorten(myPlaylistEditor->Playlists.current().value(), COLS-question.size()-10);
|
|
|
|
|
bool yes = askYesNoQuestion(question);
|
|
|
|
|
if (yes)
|
|
|
|
|
{
|
|
|
|
|
auto list = getSelectedOrCurrent(myPlaylistEditor->Playlists.begin(), myPlaylistEditor->Playlists.end(), myPlaylistEditor->Playlists.currentI());
|
|
|
|
|
for (auto it = list.begin(); it != list.end(); ++it)
|
|
|
|
|
Mpd.DeletePlaylist((*it)->value());
|
|
|
|
|
Statusbar::printf("%1% deleted", list.size() == 1 ? "Playlist" : "Playlists");
|
|
|
|
|
// force playlists update. this happens automatically, but only after call
|
|
|
|
|
// to Key::read, therefore when we call PlaylistEditor::Update, it won't
|
|
|
|
|
// yet see it, so let's point that it needs to update it.
|
|
|
|
|
myPlaylistEditor->requestPlaylistsUpdate();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Statusbar::print("Aborted");
|
|
|
|
|
confirmAction(question);
|
|
|
|
|
auto list = getSelectedOrCurrent(
|
|
|
|
|
myPlaylistEditor->Playlists.begin(),
|
|
|
|
|
myPlaylistEditor->Playlists.end(),
|
|
|
|
|
myPlaylistEditor->Playlists.currentI()
|
|
|
|
|
);
|
|
|
|
|
for (const auto &item : list)
|
|
|
|
|
Mpd.DeletePlaylist(item->value());
|
|
|
|
|
Statusbar::printf("%1% deleted", list.size() == 1 ? "Playlist" : "Playlists");
|
|
|
|
|
// force playlists update. this happens automatically, but only after call
|
|
|
|
|
// to Key::read, therefore when we call PlaylistEditor::Update, it won't
|
|
|
|
|
// yet see it, so let's point that it needs to update it.
|
|
|
|
|
myPlaylistEditor->requestPlaylistsUpdate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ReplaySong::run()
|
|
|
|
|
@@ -774,16 +773,11 @@ void SavePlaylist::run()
|
|
|
|
|
Statusbar::put() << "Save playlist as: ";
|
|
|
|
|
playlist_name = wFooter->prompt();
|
|
|
|
|
}
|
|
|
|
|
if (playlist_name.find("/") != std::string::npos)
|
|
|
|
|
{
|
|
|
|
|
Statusbar::print("Playlist name must not contain slashes");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (myPlaylist->main().isFiltered())
|
|
|
|
|
{
|
|
|
|
|
Mpd.StartCommandsList();
|
|
|
|
|
for (size_t i = 0; i < myPlaylist->main().size(); ++i)
|
|
|
|
|
Mpd.AddToPlaylist(playlist_name, myPlaylist->main()[i].value());
|
|
|
|
|
for (const auto &item : myPlaylist->main())
|
|
|
|
|
Mpd.AddToPlaylist(playlist_name, item.value());
|
|
|
|
|
Mpd.CommitCommandsList();
|
|
|
|
|
Statusbar::printf("Filtered items added to playlist \"%1%\"", playlist_name);
|
|
|
|
|
}
|
|
|
|
|
@@ -798,19 +792,12 @@ void SavePlaylist::run()
|
|
|
|
|
{
|
|
|
|
|
if (e.code() == MPD_SERVER_ERROR_EXIST)
|
|
|
|
|
{
|
|
|
|
|
bool yes = askYesNoQuestion(
|
|
|
|
|
confirmAction(
|
|
|
|
|
boost::format("Playlist \"%1%\" already exists, overwrite?") % playlist_name
|
|
|
|
|
);
|
|
|
|
|
if (yes)
|
|
|
|
|
{
|
|
|
|
|
Mpd.DeletePlaylist(playlist_name);
|
|
|
|
|
Mpd.SavePlaylist(playlist_name);
|
|
|
|
|
Statusbar::print("Playlist overwritten");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Statusbar::print("Aborted");
|
|
|
|
|
if (myScreen == myPlaylist)
|
|
|
|
|
myPlaylist->EnableHighlighting();
|
|
|
|
|
Mpd.DeletePlaylist(playlist_name);
|
|
|
|
|
Mpd.SavePlaylist(playlist_name);
|
|
|
|
|
Statusbar::print("Playlist overwritten");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw e;
|
|
|
|
|
@@ -1751,16 +1738,12 @@ void CropMainPlaylist::run()
|
|
|
|
|
// cropping doesn't make sense in this case
|
|
|
|
|
if (w.size() <= 1)
|
|
|
|
|
return;
|
|
|
|
|
bool yes = true;
|
|
|
|
|
if (Config.ask_before_clearing_playlists)
|
|
|
|
|
yes = askYesNoQuestion("Do you really want to crop main playlist?");
|
|
|
|
|
if (yes)
|
|
|
|
|
{
|
|
|
|
|
Statusbar::print("Cropping playlist...");
|
|
|
|
|
selectCurrentIfNoneSelected(w);
|
|
|
|
|
cropPlaylist(w, boost::bind(&MPD::Connection::Delete, _1, _2));
|
|
|
|
|
Statusbar::print("Playlist cropped");
|
|
|
|
|
}
|
|
|
|
|
confirmAction("Do you really want to crop main playlist?");
|
|
|
|
|
Statusbar::print("Cropping playlist...");
|
|
|
|
|
selectCurrentIfNoneSelected(w);
|
|
|
|
|
cropPlaylist(w, boost::bind(&MPD::Connection::Delete, _1, _2));
|
|
|
|
|
Statusbar::print("Playlist cropped");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CropPlaylist::canBeRun() const
|
|
|
|
|
@@ -1776,34 +1759,24 @@ void CropPlaylist::run()
|
|
|
|
|
return;
|
|
|
|
|
assert(!myPlaylistEditor->Playlists.empty());
|
|
|
|
|
std::string playlist = myPlaylistEditor->Playlists.current().value();
|
|
|
|
|
bool yes = true;
|
|
|
|
|
if (Config.ask_before_clearing_playlists)
|
|
|
|
|
yes = askYesNoQuestion(
|
|
|
|
|
boost::format("Do you really want to crop playlist \"%1%\"?") % playlist
|
|
|
|
|
);
|
|
|
|
|
if (yes)
|
|
|
|
|
{
|
|
|
|
|
selectCurrentIfNoneSelected(w);
|
|
|
|
|
Statusbar::printf("Cropping playlist \"%1%\"...", playlist);
|
|
|
|
|
cropPlaylist(w, boost::bind(&MPD::Connection::PlaylistDelete, _1, playlist, _2));
|
|
|
|
|
Statusbar::printf("Playlist \"%1%\" cropped", playlist);
|
|
|
|
|
}
|
|
|
|
|
confirmAction(boost::format("Do you really want to crop playlist \"%1%\"?") % playlist);
|
|
|
|
|
selectCurrentIfNoneSelected(w);
|
|
|
|
|
Statusbar::printf("Cropping playlist \"%1%\"...", playlist);
|
|
|
|
|
cropPlaylist(w, boost::bind(&MPD::Connection::PlaylistDelete, _1, playlist, _2));
|
|
|
|
|
Statusbar::printf("Playlist \"%1%\" cropped", playlist);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClearMainPlaylist::run()
|
|
|
|
|
{
|
|
|
|
|
bool yes = true;
|
|
|
|
|
if (Config.ask_before_clearing_playlists)
|
|
|
|
|
yes = askYesNoQuestion("Do you really want to clear main playlist?");
|
|
|
|
|
if (yes)
|
|
|
|
|
{
|
|
|
|
|
auto delete_fun = boost::bind(&MPD::Connection::Delete, _1, _2);
|
|
|
|
|
auto clear_fun = boost::bind(&MPD::Connection::ClearMainPlaylist, _1);
|
|
|
|
|
Statusbar::printf("Deleting items...");
|
|
|
|
|
clearPlaylist(myPlaylist->main(), delete_fun, clear_fun);
|
|
|
|
|
Statusbar::printf("Items deleted");
|
|
|
|
|
myPlaylist->main().reset();
|
|
|
|
|
}
|
|
|
|
|
confirmAction("Do you really want to clear main playlist?");
|
|
|
|
|
auto delete_fun = boost::bind(&MPD::Connection::Delete, _1, _2);
|
|
|
|
|
auto clear_fun = boost::bind(&MPD::Connection::ClearMainPlaylist, _1);
|
|
|
|
|
Statusbar::printf("Deleting items...");
|
|
|
|
|
clearPlaylist(myPlaylist->main(), delete_fun, clear_fun);
|
|
|
|
|
Statusbar::printf("Items deleted");
|
|
|
|
|
myPlaylist->main().reset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ClearPlaylist::canBeRun() const
|
|
|
|
|
@@ -1816,19 +1789,13 @@ void ClearPlaylist::run()
|
|
|
|
|
if (myPlaylistEditor->Playlists.empty())
|
|
|
|
|
return;
|
|
|
|
|
std::string playlist = myPlaylistEditor->Playlists.current().value();
|
|
|
|
|
bool yes = true;
|
|
|
|
|
if (Config.ask_before_clearing_playlists)
|
|
|
|
|
yes = askYesNoQuestion(
|
|
|
|
|
boost::format("Do you really want to clear playlist \"%1%\"?") % playlist
|
|
|
|
|
);
|
|
|
|
|
if (yes)
|
|
|
|
|
{
|
|
|
|
|
auto delete_fun = boost::bind(&MPD::Connection::PlaylistDelete, _1, playlist, _2);
|
|
|
|
|
auto clear_fun = boost::bind(&MPD::Connection::ClearPlaylist, _1, playlist);
|
|
|
|
|
Statusbar::printf("Deleting items from \"%1%\"...", playlist);
|
|
|
|
|
clearPlaylist(myPlaylistEditor->Content, delete_fun, clear_fun);
|
|
|
|
|
Statusbar::printf("Items deleted from \"%1%\"", playlist);
|
|
|
|
|
}
|
|
|
|
|
confirmAction(boost::format("Do you really want to clear playlist \"%1%\"?") % playlist);
|
|
|
|
|
auto delete_fun = boost::bind(&MPD::Connection::PlaylistDelete, _1, playlist, _2);
|
|
|
|
|
auto clear_fun = boost::bind(&MPD::Connection::ClearPlaylist, _1, playlist);
|
|
|
|
|
Statusbar::printf("Deleting items from \"%1%\"...", playlist);
|
|
|
|
|
clearPlaylist(myPlaylistEditor->Content, delete_fun, clear_fun);
|
|
|
|
|
Statusbar::printf("Items deleted from \"%1%\"", playlist);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SortPlaylist::canBeRun() const
|
|
|
|
|
|