1 /* TagFromPath.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 "GUI_TagFromPath.h"
22
23 #include "Gui/TagEdit/ui_GUI_TagFromPath.h"
24 #include "Utils/Tagging/Tagging.h"
25 #include "Utils/Message/Message.h"
26 #include "Utils/Language/Language.h"
27
28 #include <QDesktopServices>
29 #include <QMap>
30
31 using namespace Tagging;
32
33 struct GUI_TagFromPath::Private
34 {
35 QString currentFilepath;
36 QMap<TagName, ReplacedString> tagReplaceStringMap;
37 };
38
GUI_TagFromPath(QWidget * parent)39 GUI_TagFromPath::GUI_TagFromPath(QWidget* parent) :
40 Gui::Widget(parent)
41 {
42 m = Pimpl::make<Private>();
43
44 ui = new Ui::GUI_TagFromPath();
45 ui->setupUi(this);
46
47 showErrorFrame(false);
48
49 connect(ui->btnApplyTag, &QPushButton::clicked, this, [&]() {
50 clearInvalidFilepaths();
51 emit sigApply();
52 });
53
54 connect(ui->btnApplyTagAll, &QPushButton::clicked, this, [&]() {
55 clearInvalidFilepaths();
56 emit sigApplyAll();
57 });
58
59 connect(ui->leTag, &QLineEdit::textChanged, this, &GUI_TagFromPath::tagTextChanged);
60 connect(ui->btnTagHelp, &QPushButton::clicked, this, &GUI_TagFromPath::btnTagHelpClicked);
61
62 initButtons();
63 languageChanged();
64 }
65
66 GUI_TagFromPath::~GUI_TagFromPath() = default;
67
initButtons()68 void GUI_TagFromPath::initButtons()
69 {
70 connect(ui->btnTitle, &QPushButton::toggled, this, [&](const auto b) {
71 btnChecked(ui->btnTitle, b, TagTitle);
72 });
73
74 connect(ui->btnArtist, &QPushButton::toggled, this, [&](const auto b) {
75 btnChecked(ui->btnArtist, b, TagArtist);
76 });
77
78 connect(ui->btnAlbum, &QPushButton::toggled, this, [&](const auto b) {
79 btnChecked(ui->btnAlbum, b, TagAlbum);
80 });
81
82 connect(ui->btnTrackNumber, &QPushButton::toggled, this, [&](const auto b) {
83 btnChecked(ui->btnTrackNumber, b, TagTrackNum);
84 });
85
86 connect(ui->btnYear, &QPushButton::toggled, this, [&](const auto b) {
87 btnChecked(ui->btnYear, b, TagYear);
88 });
89
90 connect(ui->btnDiscNumber, &QPushButton::toggled, this, [&](const auto b) {
91 btnChecked(ui->btnDiscNumber, b, TagDisc);
92 });
93 }
94
checkIfAnyButtonIsChecked() const95 bool GUI_TagFromPath::checkIfAnyButtonIsChecked() const
96 {
97 return (ui->btnAlbum->isChecked() ||
98 ui->btnArtist->isChecked() ||
99 ui->btnTitle->isChecked() ||
100 ui->btnYear->isChecked() ||
101 ui->btnDiscNumber->isChecked() ||
102 ui->btnTrackNumber->isChecked());
103 }
104
setFilepath(const QString & filepath)105 void GUI_TagFromPath::setFilepath(const QString& filepath)
106 {
107 m->currentFilepath = filepath;
108
109 if(ui->leTag->text().isEmpty() || !checkIfAnyButtonIsChecked())
110 {
111 ui->leTag->setText(filepath);
112 }
113
114 const auto expression = Tagging::Expression(ui->leTag->text(), filepath);
115 setTagColors(expression.isValid());
116
117 const auto tagType = Tagging::getTagType(filepath);
118 const auto tagTypeString = Tagging::tagTypeToString(tagType);
119
120 ui->labTagType->setText(tr("Tag") + ": " + tagTypeString);
121 }
122
reset()123 void GUI_TagFromPath::reset()
124 {
125 ui->leTag->clear();
126 ui->leTag->setEnabled(true);
127 ui->lvInvalidFilepaths->clear();
128
129 ui->btnAlbum->setChecked(false);
130 ui->btnArtist->setChecked(false);
131 ui->btnTitle->setChecked(false);
132 ui->btnYear->setChecked(false);
133 ui->btnDiscNumber->setChecked(false);
134 ui->btnTrackNumber->setChecked(false);
135 }
136
setTagColors(bool valid)137 void GUI_TagFromPath::setTagColors(bool valid)
138 {
139 const auto stylesheet = (valid)
140 ? QStringLiteral("font-family: mono; font-size: 120%;")
141 : QStringLiteral("font-family: mono; font-size: 120%; color: red;");
142
143 ui->leTag->setStyleSheet(stylesheet);
144 ui->btnApplyTag->setEnabled(valid);
145 ui->btnApplyTagAll->setEnabled(valid);
146 }
147
tagTextChanged(const QString & tagString)148 void GUI_TagFromPath::tagTextChanged(const QString& tagString)
149 {
150 const auto expression = Tagging::Expression(tagString, m->currentFilepath);
151 setTagColors(expression.isValid());
152 }
153
clearInvalidFilepaths()154 void GUI_TagFromPath::clearInvalidFilepaths()
155 {
156 showErrorFrame(false);
157 ui->lvInvalidFilepaths->clear();
158 }
159
addInvalidFilepath(const QString & filepath)160 void GUI_TagFromPath::addInvalidFilepath(const QString& filepath)
161 {
162 showErrorFrame(true);
163 ui->lvInvalidFilepaths->addItem(filepath);
164 }
165
replaceSelectedTagText(TagName tagName,bool buttonChecked)166 bool GUI_TagFromPath::replaceSelectedTagText(TagName tagName, bool buttonChecked)
167 {
168 const auto textSelection = ui->leTag->textSelection();
169
170 if(buttonChecked && (textSelection.selectionStart < 0))
171 {
172 Message::info(tr("Please select text first"));
173 return false;
174 }
175
176 auto lineEditText = ui->leTag->text();
177 const auto tagString = Tagging::tagNameToString(tagName);
178
179 if(buttonChecked)
180 {
181 const auto selectedText = lineEditText.mid(textSelection.selectionStart, textSelection.selectionSize);
182
183 lineEditText.replace(textSelection.selectionStart, textSelection.selectionSize, tagString);
184 m->tagReplaceStringMap[tagName] = selectedText;
185
186 ui->leTag->setText(lineEditText);
187 }
188
189 else
190 {
191 lineEditText.replace(tagString, m->tagReplaceStringMap[tagName]);
192 m->tagReplaceStringMap.remove(tagName);
193
194 ui->leTag->setText(lineEditText);
195 }
196
197 const auto expression = Tagging::Expression(lineEditText, m->currentFilepath);
198 setTagColors(expression.isValid());
199
200 return true;
201 }
202
btnChecked(QPushButton * btn,bool b,TagName tagName)203 void GUI_TagFromPath::btnChecked(QPushButton* btn, bool b, TagName tagName)
204 {
205 ui->labTagFromPathWarning->setVisible(false);
206 ui->lvInvalidFilepaths->setVisible(false);
207
208 if(!replaceSelectedTagText(tagName, b))
209 {
210 btn->setChecked(false);
211 }
212 }
213
showErrorFrame(bool b)214 void GUI_TagFromPath::showErrorFrame(bool b)
215 {
216 ui->swTagFromPath->setCurrentIndex(b ? 0 : 1);
217 }
218
btnTagHelpClicked()219 void GUI_TagFromPath::btnTagHelpClicked()
220 {
221 const auto url = QUrl(QStringLiteral("https://sayonara-player.com/faq.php#tag-edit"));
222 QDesktopServices::openUrl(url);
223 }
224
languageChanged()225 void GUI_TagFromPath::languageChanged()
226 {
227 ui->retranslateUi(this);
228
229 ui->btnTitle->setText(Lang::get(Lang::Title));
230 ui->btnAlbum->setText(Lang::get(Lang::Album));
231 ui->btnArtist->setText(Lang::get(Lang::Artist));
232 ui->btnYear->setText(Lang::get(Lang::Year));
233 ui->btnTrackNumber->setText(Lang::get(Lang::TrackNo).toFirstUpper());
234 ui->labTagFromPathWarning->setText(Lang::get(Lang::Warning));
235
236 ui->btnApplyTagAll->setText(Lang::get(Lang::Apply) + ": " + Lang::get(Lang::All).toFirstUpper());
237 ui->btnApplyTag->setText(Lang::get(Lang::Apply) + ": " + Lang::get(Lang::Title).toFirstUpper());
238 }
239
getRegexString() const240 QString GUI_TagFromPath::getRegexString() const
241 {
242 return ui->leTag->text();
243 }
244