xref: /MusicPlayer2/MusicPlayer2/TagSelBaseDlg.cpp (revision 2aca5e84f5bc842a46a998a6bc9acf7827b6a33e)
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