1 /* PlaylistContextMenu.cpp */
2 
3 /* Copyright (C) 2011-2020 Michael Lugmair (Lucio Carreras)
4  *
5  * This file is part of sayonara player
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11 
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16 
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "PlaylistContextMenu.h"
22 #include "PlaylistBookmarksMenu.h"
23 
24 #include "Gui/Playlist/PlaylistActionMenu.h"
25 #include "Gui/Utils/Icons.h"
26 #include "Gui/Utils/Widgets/RatingLabel.h"
27 
28 #include "Interfaces/DynamicPlayback.h"
29 
30 #include "Utils/globals.h"
31 #include "Utils/Language/Language.h"
PrivateBottomBarButton::Private32 #include "Utils/MetaData/MetaData.h"
33 
34 using Playlist::ContextMenu;
BottomBarButton(const QIcon & icon,QWidget * parent)35 using Playlist::BookmarksMenu;
36 using Playlist::ActionMenu;
37 
38 namespace
39 {
40 	ContextMenu::Entries analyzeTrack(const MetaData& track)
41 	{
42 		const auto isLibraryTrack = (track.id() >= 0);
setIcon(const QIcon & icon)43 		const auto isLocalTrack = (track.radioMode() == RadioMode::Off);
44 
45 		return ((isLibraryTrack) ? ContextMenu::EntryBookmarks : 0) |
46 		       ((isLibraryTrack) ? ContextMenu::EntryFindInLibrary : 0) |
47 		       ((isLocalTrack) ? ContextMenu::EntryRating : 0) |
paintEvent(QPaintEvent * e)48 		       ContextMenu::EntryLyrics;
49 	}
50 }
51 
52 struct ContextMenu::Private
53 {
54 	QMap<ContextMenu::Entry, QAction*> entryActionMap;
55 
56 	QMenu* ratingMenu;
57 	BookmarksMenu* bookmarksMenu;
58 	QMenu* playlistModeMenu;
59 	QAction* playlistModeAction;
60 
61 	Private(DynamicPlaybackChecker* dynamicPlaybackChecker, ContextMenu* parent) :
62 		ratingMenu {new QMenu(parent)},
63 		bookmarksMenu {new BookmarksMenu(parent)},
64 		playlistModeMenu {new ActionMenu(dynamicPlaybackChecker, parent)},
65 		playlistModeAction {parent->addMenu(playlistModeMenu)}
66 	{
67 		entryActionMap[EntryRating] = parent->addMenu(ratingMenu);
68 		entryActionMap[EntryBookmarks] = parent->addMenu(bookmarksMenu);
69 		entryActionMap[EntryCurrentTrack] = new QAction(parent);
70 		entryActionMap[EntryFindInLibrary] = new QAction(parent);
71 		entryActionMap[EntryReverse] = new QAction(parent);
72 
73 		parent->addActions
74 			({
75 				 entryActionMap[EntryReverse],
76 				 entryActionMap[EntryCurrentTrack],
77 				 entryActionMap[EntryFindInLibrary],
78 			 });
79 	}
80 };
81 
82 ContextMenu::ContextMenu(DynamicPlaybackChecker* dynamicPlaybackChecker, QWidget* parent) :
83 	Library::ContextMenu(parent)
84 {
85 	m = Pimpl::make<Private>(dynamicPlaybackChecker, this);
86 
87 	QList<QAction*> ratingActions;
88 	for(auto i = +Rating::Zero; i != +Rating::Last; i++)
89 	{
90 		ratingActions << initRatingAction(static_cast<Rating>(i), m->ratingMenu);
91 	}
92 
93 	m->ratingMenu->addActions(ratingActions);
94 
95 	connect(m->entryActionMap[EntryCurrentTrack], &QAction::triggered, this, &ContextMenu::sigJumpToCurrentTrack);
96 	connect(m->entryActionMap[EntryFindInLibrary], &QAction::triggered, this, &ContextMenu::sigFindTrackTriggered);
97 	connect(m->entryActionMap[EntryReverse], &QAction::triggered, this, &ContextMenu::sigReverseTriggered);
98 
99 	connect(m->bookmarksMenu, &BookmarksMenu::sigBookmarkPressed, this, &ContextMenu::bookmarkPressed);
100 
101 	skinChanged();
102 }
103 
104 ContextMenu::~ContextMenu() = default;
105 
106 ContextMenu::Entries ContextMenu::entries() const
107 {
108 	auto entries = Library::ContextMenu::entries();
109 
110 	for(auto it = m->entryActionMap.begin(); it != m->entryActionMap.end(); it++)
111 	{
112 		if(it.value()->isVisible())
113 		{
114 			entries |= it.key();
115 		}
116 	}
117 
118 	return entries;
119 }
120 
121 void ContextMenu::showActions(ContextMenu::Entries entries)
122 {
123 	Library::ContextMenu::showActions(entries);
124 
125 	for(auto it = m->entryActionMap.begin(); it != m->entryActionMap.end(); it++)
126 	{
127 		const auto isVisible = (entries & it.key());
128 		it.value()->setVisible(isVisible);
129 	}
130 }
131 
132 void ContextMenu::setRating(Rating rating)
133 {
134 	const auto actions = m->ratingMenu->actions();
135 	for(auto* action : actions)
136 	{
137 		const auto data = action->data().value<Rating>();
138 		action->setChecked(data == rating);
139 	}
140 
141 	const auto ratingText = Lang::get(Lang::Rating);
142 
143 	const auto text = (rating != Rating::Zero && rating != Rating::Last)
144 	                  ? QString("%1 (%2)").arg(ratingText).arg(+rating)
145 	                  : static_cast<QString>(ratingText);
146 
147 	m->entryActionMap[EntryRating]->setText(text);
148 }
149 
150 ContextMenu::Entries ContextMenu::setTrack(const MetaData& track, bool isCurrentTrack)
151 {
152 	const auto isLibraryTrack = (track.id() >= 0);
153 
154 	m->bookmarksMenu->setTrack(track, (isCurrentTrack && isLibraryTrack));
155 	setRating(track.rating());
156 
157 	return analyzeTrack(track);
158 }
159 
160 void ContextMenu::clearTrack()
161 {
162 	m->bookmarksMenu->setTrack(MetaData(), false);
163 	setRating(Rating::Last);
164 }
165 
166 QAction* ContextMenu::initRatingAction(Rating rating, QObject* parent)
167 {
168 	auto* action = new QAction(QString::number(+rating), parent);
169 
170 	action->setData(QVariant::fromValue(rating));
171 	action->setCheckable(true);
172 
173 	connect(action, &QAction::triggered, this, [&]([[maybe_unused]] const auto b) {
174 		emit sigRatingChanged(rating);
175 	});
176 
177 	return action;
178 }
179 
180 void ContextMenu::languageChanged()
181 {
182 	Library::ContextMenu::languageChanged();
183 
184 	m->entryActionMap[EntryRating]->setText(Lang::get(Lang::Rating));
185 	m->entryActionMap[EntryBookmarks]->setText(Lang::get(Lang::Bookmarks));
186 	m->entryActionMap[EntryCurrentTrack]->setText(tr("Jump to current track") + QString("    "));
187 	m->entryActionMap[EntryFindInLibrary]->setText(tr("Show track in library") + QString("    "));
188 	m->entryActionMap[EntryReverse]->setText(Lang::get(Lang::ReverseOrder));
189 	m->playlistModeAction->setText(tr("Playlist mode"));
190 
191 	m->entryActionMap[EntryCurrentTrack]->setShortcut(QKeySequence(Qt::ControlModifier | Qt::Key_J));
192 	m->entryActionMap[EntryFindInLibrary]->setShortcut(QKeySequence(Qt::ControlModifier | Qt::Key_G));
193 }
194 
195 void ContextMenu::skinChanged()
196 {
197 	Library::ContextMenu::skinChanged();
198 
199 	using namespace Gui;
200 	m->entryActionMap[EntryRating]->setIcon(Icons::icon(Icons::Star));
201 	m->entryActionMap[EntryFindInLibrary]->setIcon(Icons::icon(Icons::Search));
202 }
203 
204 void ContextMenu::bookmarkPressed(Seconds timestamp)
205 {
206 	emit sigBookmarkPressed(timestamp);
207 }
208