1 // TagModeSelectBaseDlg.cpp: 实现文件
2 //
3
4 #include "stdafx.h"
5 #include "MusicPlayer2.h"
6 #include "TagSelBaseDlg.h"
7 #include "FilePathHelper.h"
8 #include "IniHelper.h"
9
10
11 // CTagSelBaseDlg 对话框
12
13 IMPLEMENT_DYNAMIC(CTagSelBaseDlg, CBaseDialog)
14
15 const wstring CTagSelBaseDlg::FORMULAR_TITLE = L"%(Title)";
16 const wstring CTagSelBaseDlg::FORMULAR_ARTIST = L"%(Artist)";
17 const wstring CTagSelBaseDlg::FORMULAR_ALBUM = L"%(Album)";
18 const wstring CTagSelBaseDlg::FORMULAR_TRACK = L"%(Track)";
19 const wstring CTagSelBaseDlg::FORMULAR_YEAR = L"%(Year)";
20 const wstring CTagSelBaseDlg::FORMULAR_GENRE = L"%(Genre)";
21 const wstring CTagSelBaseDlg::FORMULAR_COMMENT = L"%(Comment)";
22 const wstring CTagSelBaseDlg::FORMULAR_ORIGINAL = L"%(Original)";
23 const vector<wstring> CTagSelBaseDlg::default_formular{ FORMULAR_ARTIST + L" - " + FORMULAR_TITLE, FORMULAR_TITLE + L" - " + FORMULAR_ARTIST, FORMULAR_TRACK + L"." + FORMULAR_ARTIST + L" - " + FORMULAR_TITLE };
24
CTagSelBaseDlg(bool original_str_disable,CWnd * pParent)25 CTagSelBaseDlg::CTagSelBaseDlg(bool original_str_disable, CWnd* pParent /*=nullptr*/)
26 : CBaseDialog(IDD_TAG_MODE_SELECT_DIALOG, pParent), m_original_str_disable{ original_str_disable }
27 {
28
29 }
30
~CTagSelBaseDlg()31 CTagSelBaseDlg::~CTagSelBaseDlg()
32 {
33 }
34
GetTagFromFileName(const wstring & formular,const wstring & file_name,SongInfo & song_info)35 void CTagSelBaseDlg::GetTagFromFileName(const wstring& formular, const wstring& file_name, SongInfo& song_info)
36 {
37 wstring str_format = formular;
38 std::map<size_t, wstring> identifiers; //保存标识符,int为标识符在formualr中的索引
39
40 //查找每个标识符的位置,并保存在identifers中,FORMULAR_ORIGINAL不参与推测
41 const vector<wstring> FORMULARS{ FORMULAR_TITLE, FORMULAR_ARTIST, FORMULAR_ALBUM, FORMULAR_TRACK, FORMULAR_YEAR, FORMULAR_GENRE, FORMULAR_COMMENT };
42 for (const auto& f : FORMULARS)
43 {
44 size_t index = str_format.find(f);
45 if (index != wstring::npos)
46 {
47 identifiers[index] = f;
48 }
49 }
50
51 const wchar_t* SPLITER = L"|";
52
53 //将标识符全部替换成|
54 for (const auto& item : identifiers)
55 {
56 CCommon::StringReplace(str_format, item.second, SPLITER);
57 }
58 //取得分割符
59 vector<wstring> seprators;
60 CCommon::StringSplit(str_format, SPLITER, seprators, true, false);
61
62 //用分割符分割文件名
63 vector<wstring> results;
64 CCommon::StringSplitWithSeparators(file_name, seprators, results);
65
66 //获取分割结果
67 if (results.empty())
68 {
69 song_info.title = file_name;
70 }
71 else
72 {
73 size_t index{};
74 for (const auto& item : identifiers)
75 {
76 if (index < results.size())
77 {
78 wstring result = results[index];
79 if (item.second == FORMULAR_TITLE)
80 song_info.title = result;
81 else if (item.second == FORMULAR_ARTIST)
82 song_info.artist = result;
83 else if (item.second == FORMULAR_ALBUM)
84 song_info.album = result;
85 else if (item.second == FORMULAR_TRACK)
86 song_info.track = _wtoi(result.c_str());
87 else if (item.second == FORMULAR_YEAR)
88 song_info.SetYear(result.c_str());
89 else if (item.second == FORMULAR_GENRE)
90 song_info.genre = result;
91 else if (item.second == FORMULAR_COMMENT)
92 song_info.comment = result;
93 }
94 index++;
95 }
96 }
97 }
98
FileNameFromTag(wstring formular,const SongInfo & song_info)99 wstring CTagSelBaseDlg::FileNameFromTag(wstring formular, const SongInfo& song_info)
100 {
101 vector<pair<wstring, wstring>> replacements = {
102 { FORMULAR_TITLE, song_info.GetTitle() },
103 { FORMULAR_ARTIST, song_info.GetFirstArtist() },
104 { FORMULAR_ALBUM, song_info.GetAlbum() },
105 { FORMULAR_TRACK, std::to_wstring(song_info.track) },
106 { FORMULAR_GENRE, song_info.GetGenre() },
107 { FORMULAR_YEAR, song_info.GetYear() },
108 { FORMULAR_COMMENT, song_info.comment },
109 { FORMULAR_ORIGINAL, CFilePathHelper(song_info.file_path).GetFileNameWithoutExtension() }
110 };
111 // 这里的先查找出所有格式字符串再替换是为了彻底规避普通的替换被来自song_info的字符串干扰(虽然几乎不可能发生)
112 std::map<size_t, size_t> find_result; // 键是pos,值是replacements的索引
113 size_t item_index{};
114 for (const auto& item : replacements)
115 {
116 size_t pos = 0;
117 while ((pos = formular.find(item.first, pos)) != wstring::npos)
118 {
119 find_result.emplace(pos, item_index); // 这里的pos一定不会重复(除非FORMULAR_*有问题)
120 pos += item.first.size();
121 }
122 ++item_index;
123 }
124 // 逆序遍历以免需要修改first中存储的pos
125 for (auto riter = find_result.rbegin(); riter != find_result.rend(); ++riter)
126 {
127 formular.replace(riter->first, replacements[riter->second].first.size(), replacements[riter->second].second);
128 }
129 CCommon::FileNameNormalize(formular);
130 // 这里给出的文件名可能太长,调用方可能需要截断(不应在这里进行)
131 return formular;
132 }
133
SaveConfig() const134 void CTagSelBaseDlg::SaveConfig() const
135 {
136 CIniHelper ini(theApp.m_config_path);
137 ini.WriteBool(L"tag_edit", L"insert_when_clicked", m_insert_when_clicked);
138 ini.WriteStringList(L"tag_edit", L"default_formular", m_default_formular);
139 ini.Save();
140 }
141
LoadConfig()142 void CTagSelBaseDlg::LoadConfig()
143 {
144 CIniHelper ini(theApp.m_config_path);
145 m_insert_when_clicked = ini.GetBool(L"tag_edit", L"insert_when_clicked", true);
146 ini.GetStringList(L"tag_edit", L"default_formular", m_default_formular, default_formular);
147 }
148
InitComboList()149 void CTagSelBaseDlg::InitComboList()
150 {
151 wstring first_item;
152 m_format_combo.ResetContent();
153 for (const auto& formular : m_default_formular)
154 {
155 //如果隐藏了“原文件名”按钮,则不在下拉列表中添加含有“原文件名”的项
156 if (m_original_str_disable)
157 {
158 if (formular.find(FORMULAR_ORIGINAL) != std::wstring::npos)
159 continue;
160 }
161 if (first_item.empty())
162 first_item = formular;
163 m_format_combo.AddString(formular.c_str());
164 }
165 if (m_format_combo.GetCount() == 0) // 如果为空那么添加一个作为默认
166 m_format_combo.AddString(default_formular[0].c_str());
167 m_format_combo.AddString(theApp.m_str_table.LoadText(L"TXT_TAG_SEL_CLEAR_HISTORY").c_str());
168 m_format_combo.SetCurSel(0);
169 }
170
IsStringContainsFormular(const wstring & str) const171 bool CTagSelBaseDlg::IsStringContainsFormular(const wstring& str) const
172 {
173 const vector<wstring> formular_list{ FORMULAR_TITLE, FORMULAR_ARTIST, FORMULAR_ALBUM, FORMULAR_TRACK, FORMULAR_GENRE, FORMULAR_YEAR, FORMULAR_COMMENT, FORMULAR_ORIGINAL };
174 for (const auto& formular : formular_list)
175 {
176 if (str.find(formular) != wstring::npos)
177 return true;
178 }
179 return false;
180 }
181
InsertFormular(const wstring & str_formular)182 void CTagSelBaseDlg::InsertFormular(const wstring& str_formular)
183 {
184 if (str_formular.empty())
185 return;
186 //向m_default_formular中插入一项
187 auto iter = std::find(m_default_formular.begin(), m_default_formular.end(), str_formular);
188 if (iter != m_default_formular.end()) // 如果列表中包含要插入的项,将其移动到第一项
189 std::rotate(m_default_formular.begin(), iter, iter + 1);
190 else // 列表中没有包含要插入的项(或列表为空),就将其插入到最前面
191 m_default_formular.insert(m_default_formular.begin(), str_formular);
192 }
193
OnTagBtnClicked(const wstring & tag)194 void CTagSelBaseDlg::OnTagBtnClicked(const wstring& tag)
195 {
196 if (m_insert_when_clicked)
197 {
198 CString str;
199 m_format_combo.GetWindowText(str);
200 str += tag.c_str();
201 m_format_combo.SetWindowText(str);
202 }
203 else
204 CCommon::CopyStringToClipboard(tag);
205 }
206
InitializeControls()207 bool CTagSelBaseDlg::InitializeControls()
208 {
209 // IDC_INFO_STATIC
210 // IDC_COMBO1
211 wstring temp;
212 temp = theApp.m_str_table.LoadText(L"TXT_PROPERTY_DLG_TAG_TITLE");
213 SetDlgItemTextW(IDC_TXT_PROPERTY_DLG_TAG_TITLE_STATIC, temp.c_str());
214 SetDlgItemTextW(IDC_TITLE_BUTTON, FORMULAR_TITLE.c_str());
215 temp = theApp.m_str_table.LoadText(L"TXT_PROPERTY_DLG_TAG_ARTIST");
216 SetDlgItemTextW(IDC_TXT_PROPERTY_DLG_TAG_ARTIST_STATIC, temp.c_str());
217 SetDlgItemTextW(IDC_ARTIST_BUTTON, FORMULAR_ARTIST.c_str());
218 temp = theApp.m_str_table.LoadText(L"TXT_PROPERTY_DLG_TAG_ALBUM");
219 SetDlgItemTextW(IDC_TXT_PROPERTY_DLG_TAG_ALBUM_STATIC, temp.c_str());
220 SetDlgItemTextW(IDC_ALBUM_BUTTON, FORMULAR_ALBUM.c_str());
221 temp = theApp.m_str_table.LoadText(L"TXT_PROPERTY_DLG_TAG_TRACK");
222 SetDlgItemTextW(IDC_TXT_PROPERTY_DLG_TAG_TRACK_STATIC, temp.c_str());
223 SetDlgItemTextW(IDC_TRACK_BUTTON, FORMULAR_TRACK.c_str());
224 temp = theApp.m_str_table.LoadText(L"TXT_PROPERTY_DLG_TAG_YEAR");
225 SetDlgItemTextW(IDC_TXT_PROPERTY_DLG_TAG_YEAR_STATIC, temp.c_str());
226 SetDlgItemTextW(IDC_YEAR_BUTTON, FORMULAR_YEAR.c_str());
227 temp = theApp.m_str_table.LoadText(L"TXT_PROPERTY_DLG_TAG_GENRE");
228 SetDlgItemTextW(IDC_TXT_PROPERTY_DLG_TAG_GENRE_STATIC, temp.c_str());
229 SetDlgItemTextW(IDC_GENRE_BUTTON, FORMULAR_GENRE.c_str());
230 temp = theApp.m_str_table.LoadText(L"TXT_PROPERTY_DLG_TAG_COMMENT");
231 SetDlgItemTextW(IDC_TXT_PROPERTY_DLG_TAG_COMMENT_STATIC, temp.c_str());
232 SetDlgItemTextW(IDC_COMMENT_BUTTON, FORMULAR_COMMENT.c_str());
233 temp = theApp.m_str_table.LoadText(L"TXT_TAG_SEL_ORIGINAL");
234 SetDlgItemTextW(IDC_ORIGINAL_STATIC, temp.c_str());
235 SetDlgItemTextW(IDC_ORIGINAL_BUTTON, FORMULAR_ORIGINAL.c_str());
236 temp = theApp.m_str_table.LoadText(L"TXT_TAG_SEL_CLICK_BTN_SEL");
237 SetDlgItemTextW(IDC_TXT_TAG_SEL_CLICK_BTN_SEL_STATIC, temp.c_str());
238 temp = theApp.m_str_table.LoadText(L"TXT_TAG_SEL_CLICK_BTN_INS");
239 SetDlgItemTextW(IDC_INSERT_RADIO, temp.c_str());
240 temp = theApp.m_str_table.LoadText(L"TXT_TAG_SEL_CLICK_BTN_COPY");
241 SetDlgItemTextW(IDC_COPY_RADIO, temp.c_str());
242 // IDOK
243 // IDCANCEL
244
245 RepositionTextBasedControls({
246 { CtrlTextInfo::L1, IDC_TXT_PROPERTY_DLG_TAG_TITLE_STATIC },
247 { CtrlTextInfo::C0, IDC_TITLE_BUTTON },
248 { CtrlTextInfo::L1, IDC_TXT_PROPERTY_DLG_TAG_ALBUM_STATIC },
249 { CtrlTextInfo::C0, IDC_ALBUM_BUTTON },
250 { CtrlTextInfo::L1, IDC_TXT_PROPERTY_DLG_TAG_YEAR_STATIC },
251 { CtrlTextInfo::C0, IDC_YEAR_BUTTON },
252 { CtrlTextInfo::L1, IDC_TXT_PROPERTY_DLG_TAG_COMMENT_STATIC },
253 { CtrlTextInfo::C0, IDC_COMMENT_BUTTON }
254 }, CtrlTextInfo::W96);
255 RepositionTextBasedControls({
256 { CtrlTextInfo::L1, IDC_TXT_PROPERTY_DLG_TAG_ARTIST_STATIC },
257 { CtrlTextInfo::C0, IDC_ARTIST_BUTTON },
258 { CtrlTextInfo::L1, IDC_TXT_PROPERTY_DLG_TAG_TRACK_STATIC },
259 { CtrlTextInfo::C0, IDC_TRACK_BUTTON },
260 { CtrlTextInfo::L1, IDC_TXT_PROPERTY_DLG_TAG_GENRE_STATIC },
261 { CtrlTextInfo::C0, IDC_GENRE_BUTTON },
262 { CtrlTextInfo::L1, IDC_ORIGINAL_STATIC },
263 { CtrlTextInfo::C0, IDC_ORIGINAL_BUTTON }
264 }, CtrlTextInfo::W96);
265 RepositionTextBasedControls({
266 { CtrlTextInfo::L3, IDC_TXT_TAG_SEL_CLICK_BTN_SEL_STATIC },
267 { CtrlTextInfo::L2, IDC_INSERT_RADIO, CtrlTextInfo::W16 },
268 { CtrlTextInfo::L1, IDC_COPY_RADIO, CtrlTextInfo::W16 }
269 });
270 RepositionTextBasedControls({
271 { CtrlTextInfo::R1, IDOK, CtrlTextInfo::W32 },
272 { CtrlTextInfo::R2, IDCANCEL, CtrlTextInfo::W32 }
273 });
274 return true;
275 }
276
DoDataExchange(CDataExchange * pDX)277 void CTagSelBaseDlg::DoDataExchange(CDataExchange* pDX)
278 {
279 CBaseDialog::DoDataExchange(pDX);
280 DDX_Control(pDX, IDC_COMBO1, m_format_combo);
281 }
282
283
BEGIN_MESSAGE_MAP(CTagSelBaseDlg,CBaseDialog)284 BEGIN_MESSAGE_MAP(CTagSelBaseDlg, CBaseDialog)
285 ON_BN_CLICKED(IDC_TITLE_BUTTON, &CTagSelBaseDlg::OnBnClickedTitleButton)
286 ON_BN_CLICKED(IDC_ARTIST_BUTTON, &CTagSelBaseDlg::OnBnClickedArtistButton)
287 ON_BN_CLICKED(IDC_ALBUM_BUTTON, &CTagSelBaseDlg::OnBnClickedAlbumButton)
288 ON_BN_CLICKED(IDC_TRACK_BUTTON, &CTagSelBaseDlg::OnBnClickedTrackButton)
289 ON_BN_CLICKED(IDC_YEAR_BUTTON, &CTagSelBaseDlg::OnBnClickedYearButton)
290 ON_BN_CLICKED(IDC_GENRE_BUTTON, &CTagSelBaseDlg::OnBnClickedGenreButton)
291 ON_BN_CLICKED(IDC_COMMENT_BUTTON, &CTagSelBaseDlg::OnBnClickedCommentButton)
292 ON_BN_CLICKED(IDC_ORIGINAL_BUTTON, &CTagSelBaseDlg::OnBnClickedOriginalButton)
293 ON_CBN_SELCHANGE(IDC_COMBO1, &CTagSelBaseDlg::OnCbnSelchangeCombo1)
294 ON_BN_CLICKED(IDC_INSERT_RADIO, &CTagSelBaseDlg::OnBnClickedInsertRadio)
295 ON_BN_CLICKED(IDC_COPY_RADIO, &CTagSelBaseDlg::OnBnClickedCopyRadio)
296 ON_WM_DESTROY()
297 END_MESSAGE_MAP()
298
299
300 // CTagModeSelectDlg 消息处理程序
301
302
303 BOOL CTagSelBaseDlg::OnInitDialog()
304 {
305 CBaseDialog::OnInitDialog();
306
307 // TODO: 在此添加额外的初始化
308 LoadConfig();
309
310 if (m_insert_when_clicked)
311 CheckDlgButton(IDC_INSERT_RADIO, TRUE);
312 else
313 CheckDlgButton(IDC_COPY_RADIO, TRUE);
314
315 InsertFormular(m_init_insert_formular);
316 InitComboList();
317
318 if (m_original_str_disable)
319 {
320 ShowDlgCtrl(IDC_ORIGINAL_STATIC, false);
321 ShowDlgCtrl(IDC_ORIGINAL_BUTTON, false);
322 }
323
324 return TRUE; // return TRUE unless you set the focus to a control
325 // 异常: OCX 属性页应返回 FALSE
326 }
327
328
OnBnClickedTitleButton()329 void CTagSelBaseDlg::OnBnClickedTitleButton()
330 {
331 OnTagBtnClicked(FORMULAR_TITLE);
332 }
333
334
OnBnClickedArtistButton()335 void CTagSelBaseDlg::OnBnClickedArtistButton()
336 {
337 OnTagBtnClicked(FORMULAR_ARTIST);
338 }
339
340
OnBnClickedAlbumButton()341 void CTagSelBaseDlg::OnBnClickedAlbumButton()
342 {
343 OnTagBtnClicked(FORMULAR_ALBUM);
344 }
345
346
OnBnClickedTrackButton()347 void CTagSelBaseDlg::OnBnClickedTrackButton()
348 {
349 OnTagBtnClicked(FORMULAR_TRACK);
350 }
351
352
OnBnClickedYearButton()353 void CTagSelBaseDlg::OnBnClickedYearButton()
354 {
355 OnTagBtnClicked(FORMULAR_YEAR);
356 }
357
358
OnBnClickedGenreButton()359 void CTagSelBaseDlg::OnBnClickedGenreButton()
360 {
361 OnTagBtnClicked(FORMULAR_GENRE);
362 }
363
364
OnBnClickedCommentButton()365 void CTagSelBaseDlg::OnBnClickedCommentButton()
366 {
367 OnTagBtnClicked(FORMULAR_COMMENT);
368 }
369
370
OnBnClickedOriginalButton()371 void CTagSelBaseDlg::OnBnClickedOriginalButton()
372 {
373 OnTagBtnClicked(FORMULAR_ORIGINAL);
374 }
375
376
OnCbnSelchangeCombo1()377 void CTagSelBaseDlg::OnCbnSelchangeCombo1()
378 {
379 // TODO: 在此添加控件通知处理程序代码
380 int cur_sel = m_format_combo.GetCurSel();
381 if (cur_sel == m_format_combo.GetCount() - 1)
382 {
383 const wstring& info = theApp.m_str_table.LoadText(L"MSG_TAG_SEL_CLEAR_HISTORY_INQUIRY");
384 if (MessageBox(info.c_str(), NULL, MB_ICONINFORMATION | MB_OKCANCEL) == IDOK)
385 {
386 m_default_formular = default_formular;
387 InitComboList();
388 }
389 m_format_combo.SetCurSel(0);
390 }
391 else
392 {
393 CString str;
394 m_format_combo.GetWindowText(str);
395 InsertFormular(str.GetString());
396 }
397 }
398
399
OnBnClickedInsertRadio()400 void CTagSelBaseDlg::OnBnClickedInsertRadio()
401 {
402 // TODO: 在此添加控件通知处理程序代码
403 m_insert_when_clicked = true;
404 }
405
406
OnBnClickedCopyRadio()407 void CTagSelBaseDlg::OnBnClickedCopyRadio()
408 {
409 // TODO: 在此添加控件通知处理程序代码
410 m_insert_when_clicked = false;
411 }
412
413
OnDestroy()414 void CTagSelBaseDlg::OnDestroy()
415 {
416 CBaseDialog::OnDestroy();
417
418 // TODO: 在此处添加消息处理程序代码
419 CString str;
420 m_format_combo.GetWindowText(str);
421 m_formular_selected = str.GetString();
422 // 不保存没有formular的项目(因为没有复用可能性)
423 auto new_end = std::remove_if(m_default_formular.begin(), m_default_formular.end(),
424 [this](const wstring& item) { return !IsStringContainsFormular(item); });
425 m_default_formular.erase(new_end, m_default_formular.end());
426 SaveConfig();
427 }
428
429
OnOK()430 void CTagSelBaseDlg::OnOK()
431 {
432 // TODO: 在此添加专用代码和/或调用基类
433 CString str;
434 m_format_combo.GetWindowText(str);
435 InsertFormular(str.GetString());
436
437 CBaseDialog::OnOK();
438 }
439