1 // FolderExploreDlg.cpp: 实现文件
2 //
3
4 #include "stdafx.h"
5 #include "MusicPlayer2.h"
6 #include "Player.h"
7 #include "FolderExploreDlg.h"
8 #include "AudioCommon.h"
9 #include "MusicPlayerCmdHelper.h"
10 #include "PropertyDlg.h"
11 #include "Playlist.h"
12 #include "AddToPlaylistDlg.h"
13 #include "SongDataManager.h"
14
15
16 // CFolderExploreDlg 对话框
17
IMPLEMENT_DYNAMIC(CFolderExploreDlg,CMediaLibTabDlg)18 IMPLEMENT_DYNAMIC(CFolderExploreDlg, CMediaLibTabDlg)
19
20 CFolderExploreDlg::CFolderExploreDlg(CWnd* pParent /*=nullptr*/)
21 : CMediaLibTabDlg(IDD_FOLDER_EXPLORE_DIALOG, pParent)
22 {
23
24 }
25
~CFolderExploreDlg()26 CFolderExploreDlg::~CFolderExploreDlg()
27 {
28 }
29
RefreshData()30 void CFolderExploreDlg::RefreshData()
31 {
32 ShowFolderTree();
33 }
34
GetSongsSelected(std::vector<SongInfo> & song_list) const35 void CFolderExploreDlg::GetSongsSelected(std::vector<SongInfo>& song_list) const
36 {
37 if (m_left_selected)
38 {
39 CAudioCommon::GetAudioFiles(m_folder_path_selected, song_list, 20000, true);
40 }
41 else
42 {
43 CMediaLibTabDlg::GetSongsSelected(song_list);
44 }
45 }
46
RefreshSongList()47 void CFolderExploreDlg::RefreshSongList()
48 {
49 ShowSongList();
50 }
51
ShowFolderTree()52 void CFolderExploreDlg::ShowFolderTree()
53 {
54 m_initialized = true;
55 CString search_key_word;
56 m_search_edit.GetWindowText(search_key_word);
57 m_searched = !search_key_word.IsEmpty();
58 if (m_searched) //要进入搜索状态前,先保存当前树的展开收缩状态
59 m_folder_explore_tree.SaveExpandState();
60
61 m_folder_explore_tree.DeleteAllItems();
62 //wstring default_folder = CCommon::GetSpecialDir(CSIDL_MYMUSIC);
63 for(const auto& default_folder : theApp.m_media_lib_setting_data.media_folders)
64 {
65 m_folder_explore_tree.InsertPath(default_folder.c_str(), NULL, [&](const CString& folder_path)
66 {
67 if (!CAudioCommon::IsPathContainsAudioFile(wstring(folder_path), true)) //排除不包含音频文件的目录
68 return false;
69 if (m_searched)
70 return CCommon::IsFolderMatchKeyWord(wstring(folder_path), wstring(search_key_word));
71 return true;
72 });
73 }
74
75 if (m_searched)
76 m_folder_explore_tree.ExpandAll();
77 else
78 m_folder_explore_tree.RestoreExpandState(); //不是搜索状态,树刷新后恢复展开收缩状态
79 }
80
ShowSongList()81 void CFolderExploreDlg::ShowSongList()
82 {
83 CWaitCursor wait_cursor;
84 SetDlgItemText(IDC_PATH_STATIC, m_folder_path_selected.c_str());
85
86 //获取歌曲列表
87 m_right_items.clear();
88
89 // 此处在主线程更新cue条目到媒体库并加载歌曲信息,如果有大量cue且没有提前“更新媒体库”第一次进行耗时可能很长
90 // 播放左侧目录的OpenFolder包含子文件夹所以这里也包含子文件夹
91 CAudioCommon::GetAudioFiles(m_folder_path_selected, m_right_items, MAX_SONG_NUM, true);
92
93 bool exit_flag{};
94 int update_cnt{};
95 // 这里仍然使用GetCueTracks而不是GetAudioInfo是因为后者涉及忽略短文件设置,实际执行的OpenFolder无视设置加入短文件
96 // 我希望此处预览(至少数量上)与OpenFolder结果一致,但不希望只为看一下(预览)就把无关(短)文件加入媒体库
97 CAudioCommon::GetCueTracks(m_right_items, update_cnt, exit_flag, MR_MIN_REQUIRED);
98 // 加载歌曲信息
99 CSongDataManager::GetInstance().LoadSongsInfo(m_right_items);
100
101 //显示到列表控件中
102 m_list_data.clear();
103 for (const auto& item : m_right_items)
104 {
105 CListCtrlEx::RowData row_data;
106 row_data[COL_FILE_NAME] = item.GetFileName();
107 row_data[COL_TITLE] = item.GetTitle();
108 row_data[COL_ARTIST] = item.GetArtist();
109 row_data[COL_ALBUM] = item.GetAlbum();
110 row_data[COL_PATH] = item.file_path;
111 m_list_data.push_back(std::move(row_data));
112 }
113 m_song_list_ctrl.SetListData(&m_list_data);
114 }
115
FolderTreeClicked(HTREEITEM hItem)116 void CFolderExploreDlg::FolderTreeClicked(HTREEITEM hItem)
117 {
118 m_left_selected = true;
119 wstring folder_path_selected{ m_folder_explore_tree.GetItemPath(hItem) };
120 if (folder_path_selected != m_folder_path_selected)
121 {
122 m_folder_path_selected = folder_path_selected;
123 ShowSongList();
124 }
125 m_right_selected_item = -1; // 点击左侧列表时清空右侧列表选中项
126 m_right_selected_items.clear();
127 m_song_list_ctrl.SelectNone();
128 SetButtonsEnable(CCommon::FolderExist(folder_path_selected));
129 }
130
SongListClicked(int index)131 void CFolderExploreDlg::SongListClicked(int index)
132 {
133 m_left_selected = false;
134 m_right_selected_item = index;
135 m_song_list_ctrl.GetItemSelected(m_right_selected_items);
136 SetButtonsEnable(!m_right_selected_items.empty());
137 }
138
SetButtonsEnable(bool enable)139 void CFolderExploreDlg::SetButtonsEnable(bool enable)
140 {
141 CWnd* pParent = GetParentWindow();
142 ::SendMessage(pParent->GetSafeHwnd(), WM_PLAY_SELECTED_BTN_ENABLE, WPARAM(enable), 0);
143 }
144
GetNewPlaylistName() const145 wstring CFolderExploreDlg::GetNewPlaylistName() const
146 {
147 std::wstring default_name;
148 //如果选中了左侧列表,则添加到新建播放列表时名称自动填上选中项的名称
149 default_name = m_folder_explore_tree.GetItemText(m_tree_item_selected);
150 CCommon::FileNameNormalize(default_name);
151 return default_name;
152 }
153
OnTabEntered()154 void CFolderExploreDlg::OnTabEntered()
155 {
156 if (!m_initialized)
157 {
158 CWaitCursor wait_cursor;
159 //注意,在这里向左侧树填充数据可能会比较缓慢,因此放到这里处理,而不在OnInitDialog()中处理,
160 //即只有当标签切换到“文件夹浏览”时才填充数据,以加快“媒体库”对话框的打开速度
161 ShowFolderTree();
162 }
163 bool play_enable;
164 if (m_left_selected)
165 play_enable = CCommon::FolderExist(m_folder_path_selected);
166 else
167 play_enable = (!m_right_selected_items.empty());
168 SetButtonsEnable(play_enable);
169 }
170
GetSongList() const171 const vector<SongInfo>& CFolderExploreDlg::GetSongList() const
172 {
173 return m_right_items;
174 }
175
GetItemSelected() const176 int CFolderExploreDlg::GetItemSelected() const
177 {
178 return m_right_selected_item;
179 }
180
GetItemsSelected() const181 const vector<int>& CFolderExploreDlg::GetItemsSelected() const
182 {
183 return m_right_selected_items;
184 }
185
AfterDeleteFromDisk(const std::vector<SongInfo> & files)186 void CFolderExploreDlg::AfterDeleteFromDisk(const std::vector<SongInfo>& files)
187 {
188 //删除成功,则刷新列表
189 ShowSongList();
190 }
191
GetSelectedString() const192 wstring CFolderExploreDlg::GetSelectedString() const
193 {
194 return wstring(m_selected_string);
195 }
196
DoDataExchange(CDataExchange * pDX)197 void CFolderExploreDlg::DoDataExchange(CDataExchange* pDX)
198 {
199 CMediaLibTabDlg::DoDataExchange(pDX);
200 DDX_Control(pDX, IDC_MFCEDITBROWSE1, m_search_edit);
201 DDX_Control(pDX, IDC_FOLDER_EXPLORE_TREE, m_folder_explore_tree);
202 DDX_Control(pDX, IDC_SONG_LIST, m_song_list_ctrl);
203 DDX_Control(pDX, IDC_HSPLITER_STATIC, m_splitter_ctrl);
204 }
205
206
BEGIN_MESSAGE_MAP(CFolderExploreDlg,CMediaLibTabDlg)207 BEGIN_MESSAGE_MAP(CFolderExploreDlg, CMediaLibTabDlg)
208 ON_NOTIFY(NM_RCLICK, IDC_FOLDER_EXPLORE_TREE, &CFolderExploreDlg::OnNMRClickFolderExploreTree)
209 ON_NOTIFY(NM_CLICK, IDC_FOLDER_EXPLORE_TREE, &CFolderExploreDlg::OnNMClickFolderExploreTree)
210 ON_NOTIFY(NM_CLICK, IDC_SONG_LIST, &CFolderExploreDlg::OnNMClickSongList)
211 ON_NOTIFY(NM_RCLICK, IDC_SONG_LIST, &CFolderExploreDlg::OnNMRClickSongList)
212 ON_NOTIFY(NM_DBLCLK, IDC_FOLDER_EXPLORE_TREE, &CFolderExploreDlg::OnNMDblclkFolderExploreTree)
213 ON_NOTIFY(NM_DBLCLK, IDC_SONG_LIST, &CFolderExploreDlg::OnNMDblclkSongList)
214 ON_EN_CHANGE(IDC_MFCEDITBROWSE1, &CFolderExploreDlg::OnEnChangeMfceditbrowse1)
215 ON_MESSAGE(WM_SEARCH_EDIT_BTN_CLICKED, &CFolderExploreDlg::OnSearchEditBtnClicked)
216 ON_COMMAND(ID_BROWSE_PATH, &CFolderExploreDlg::OnBrowsePath)
217 END_MESSAGE_MAP()
218
219
220 // CFolderExploreDlg 消息处理程序
221
222
223 BOOL CFolderExploreDlg::OnInitDialog()
224 {
225 CMediaLibTabDlg::OnInitDialog();
226
227 // TODO: 在此添加额外的初始化
228
229 //为树控件设置图标
230 CSize icon_size = IconMgr::GetIconSize(IconMgr::IconSize::IS_DPI_16);
231 CImageList ImageList;
232 ImageList.Create(icon_size.cx, icon_size.cy, ILC_COLOR32 | ILC_MASK, 2, 2);
233 ImageList.Add(theApp.m_icon_mgr.GetHICON(IconMgr::IconType::IT_Folder, IconMgr::IconStyle::IS_Color, IconMgr::IconSize::IS_DPI_16));
234 m_folder_explore_tree.SetImageList(&ImageList, TVSIL_NORMAL);
235 ImageList.Detach();
236
237 //设置行高
238 m_folder_explore_tree.SetItemHeight(theApp.DPI(22));
239
240 if(!theApp.m_media_lib_setting_data.show_tree_tool_tips)
241 m_folder_explore_tree.ModifyStyle(0, TVS_NOTOOLTIPS);
242
243 //填充数据
244 //注意,在这里向左侧树填充数据可能会比较缓慢,因此放到OnTabEntered()函数中处理,
245 //即只有当标签切换到“文件夹浏览”时才填充数据,以加载“媒体库”对话框的打开速度
246 //ShowFolderTree();
247
248 //初始化右侧列表
249 m_song_list_ctrl.SetExtendedStyle(m_song_list_ctrl.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_LABELTIP);
250 //CRect rc_song_list;
251 //m_song_list_ctrl.GetWindowRect(rc_song_list);
252 m_song_list_ctrl.InsertColumn(0, theApp.m_str_table.LoadText(L"TXT_FILE_NAME").c_str(), LVCFMT_LEFT, theApp.DPI(200));
253 m_song_list_ctrl.InsertColumn(1, theApp.m_str_table.LoadText(L"TXT_TITLE").c_str(), LVCFMT_LEFT, theApp.DPI(180));
254 m_song_list_ctrl.InsertColumn(2, theApp.m_str_table.LoadText(L"TXT_ARTIST").c_str(), LVCFMT_LEFT, theApp.DPI(100));
255 m_song_list_ctrl.InsertColumn(3, theApp.m_str_table.LoadText(L"TXT_ALBUM").c_str(), LVCFMT_LEFT, theApp.DPI(100));
256 m_song_list_ctrl.InsertColumn(4, theApp.m_str_table.LoadText(L"TXT_FILE_PATH").c_str(), LVCFMT_LEFT, theApp.DPI(600));
257 m_song_list_ctrl.SetCtrlAEnable(true);
258
259 m_search_edit.SetCueBanner(theApp.m_str_table.LoadText(L"TXT_SEARCH_PROMPT_FORDER").c_str(), TRUE);
260
261 //初始化分隔条
262 m_splitter_ctrl.AttachCtrlAsLeftPane(IDC_FOLDER_EXPLORE_TREE);
263 m_splitter_ctrl.AttachCtrlAsLeftPane(IDC_MFCEDITBROWSE1);
264 m_splitter_ctrl.AttachCtrlAsRightPane(IDC_PATH_STATIC);
265 m_splitter_ctrl.AttachCtrlAsRightPane(IDC_SONG_LIST);
266
267 return TRUE; // return TRUE unless you set the focus to a control
268 // 异常: OCX 属性页应返回 FALSE
269 }
270
271
OnNMRClickFolderExploreTree(NMHDR * pNMHDR,LRESULT * pResult)272 void CFolderExploreDlg::OnNMRClickFolderExploreTree(NMHDR *pNMHDR, LRESULT *pResult)
273 {
274 // TODO: 在此添加控件通知处理程序代码
275 if (pNMHDR->hwndFrom == m_folder_explore_tree.GetSafeHwnd())
276 {
277 CPoint point(GetMessagePos());
278 unsigned int nFlags = 0;
279 m_folder_explore_tree.ScreenToClient(&point);
280 HTREEITEM hItem = m_folder_explore_tree.HitTest(point, &nFlags);
281 m_tree_item_selected = hItem;
282 m_selected_string = m_folder_explore_tree.GetItemText(hItem);
283
284 m_folder_explore_tree.SetFocus();
285 m_folder_explore_tree.SelectItem(hItem);
286 if ((nFlags & TVHT_ONITEM || nFlags & TVHT_ONITEMRIGHT || nFlags & TVHT_ONITEMINDENT) && (hItem != NULL))
287 {
288 FolderTreeClicked(hItem);
289
290 GetCursorPos(&point);
291 if(hItem != NULL)
292 {
293 CRect item_rect;
294 m_folder_explore_tree.GetItemRect(hItem, item_rect, FALSE);
295 CRect window_rect;
296 m_folder_explore_tree.GetWindowRect(window_rect); //获取列表控件的矩形区域(以屏幕左上角为原点)
297 point.y = window_rect.top + item_rect.bottom; //设置鼠标要弹出的y坐标为选中项目的下边框位置,防止右键菜单挡住选中的项目
298 }
299 CMenu* pMenu = theApp.m_menu_mgr.GetMenu(MenuMgr::LibFolderExploreMenu);
300 pMenu->TrackPopupMenu(TPM_LEFTBUTTON | TPM_LEFTALIGN, point.x, point.y, this);
301 }
302 }
303
304 *pResult = 0;
305 }
306
307
OnNMClickFolderExploreTree(NMHDR * pNMHDR,LRESULT * pResult)308 void CFolderExploreDlg::OnNMClickFolderExploreTree(NMHDR *pNMHDR, LRESULT *pResult)
309 {
310 // TODO: 在此添加控件通知处理程序代码
311 if (pNMHDR->hwndFrom == m_folder_explore_tree.GetSafeHwnd())
312 {
313 CPoint point(GetMessagePos());
314 unsigned int nFlags = 0;
315 m_folder_explore_tree.ScreenToClient(&point);
316 HTREEITEM hItem = m_folder_explore_tree.HitTest(point, &nFlags);
317 m_tree_item_selected = hItem;
318 if ((nFlags & TVHT_ONITEM) && (hItem != NULL))
319 {
320 FolderTreeClicked(hItem);
321 }
322
323 //点击加减号时
324 if ((nFlags & TVHT_ONITEMBUTTON) && (hItem != NULL))
325 {
326 bool expand = (m_folder_explore_tree.GetItemState(hItem, TVIS_EXPANDED)&TVIS_EXPANDED) == TVIS_EXPANDED;
327 //保存当前点击节点的展开状态,由于这时item的状态还没有改变,所以要对expand取反
328 m_folder_explore_tree.SaveItemExpandState(hItem, !expand);
329 }
330
331 //m_folder_explore_tree.SetFocus();
332 //m_folder_explore_tree.SelectItem(hItem);
333 }
334 *pResult = 0;
335 }
336
337
OnNMClickSongList(NMHDR * pNMHDR,LRESULT * pResult)338 void CFolderExploreDlg::OnNMClickSongList(NMHDR *pNMHDR, LRESULT *pResult)
339 {
340 LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
341 // TODO: 在此添加控件通知处理程序代码
342 SongListClicked(pNMItemActivate->iItem);
343 *pResult = 0;
344 }
345
346
OnNMRClickSongList(NMHDR * pNMHDR,LRESULT * pResult)347 void CFolderExploreDlg::OnNMRClickSongList(NMHDR *pNMHDR, LRESULT *pResult)
348 {
349 LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
350 // TODO: 在此添加控件通知处理程序代码
351 SongListClicked(pNMItemActivate->iItem);
352 m_selected_string = m_song_list_ctrl.GetItemText(pNMItemActivate->iItem, pNMItemActivate->iSubItem);
353
354 if(!m_right_selected_items.empty())
355 {
356 //弹出右键菜单
357 CMenu* pMenu = theApp.m_menu_mgr.GetMenu(MenuMgr::LibRightMenu);
358 ASSERT(pMenu != nullptr);
359 if (pMenu != nullptr)
360 {
361 m_song_list_ctrl.ShowPopupMenu(pMenu, pNMItemActivate->iItem, this);
362 }
363 }
364 *pResult = 0;
365 }
366
367
OnNMDblclkFolderExploreTree(NMHDR * pNMHDR,LRESULT * pResult)368 void CFolderExploreDlg::OnNMDblclkFolderExploreTree(NMHDR *pNMHDR, LRESULT *pResult)
369 {
370 // TODO: 在此添加控件通知处理程序代码
371 CPoint point(GetMessagePos());
372 unsigned int nFlags = 0;
373 m_folder_explore_tree.ScreenToClient(&point);
374 HTREEITEM hItem = m_folder_explore_tree.HitTest(point, &nFlags);
375 if ((nFlags & TVHT_ONITEM) && (hItem != NULL))
376 {
377 OnOK();
378 }
379
380 *pResult = 0;
381 }
382
383
OnNMDblclkSongList(NMHDR * pNMHDR,LRESULT * pResult)384 void CFolderExploreDlg::OnNMDblclkSongList(NMHDR *pNMHDR, LRESULT *pResult)
385 {
386 LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
387 // TODO: 在此添加控件通知处理程序代码
388 OnOK();
389 *pResult = 0;
390 }
391
392
OnEnChangeMfceditbrowse1()393 void CFolderExploreDlg::OnEnChangeMfceditbrowse1()
394 {
395 // TODO: 如果该控件是 RICHEDIT 控件,它将不
396 // 发送此通知,除非重写 CMediaLibTabDlg::OnInitDialog()
397 // 函数并调用 CRichEditCtrl().SetEventMask(),
398 // 同时将 ENM_CHANGE 标志“或”运算到掩码中。
399
400 // TODO: 在此添加控件通知处理程序代码
401 ShowFolderTree();
402 }
403
404
OnSearchEditBtnClicked(WPARAM wParam,LPARAM lParam)405 afx_msg LRESULT CFolderExploreDlg::OnSearchEditBtnClicked(WPARAM wParam, LPARAM lParam)
406 {
407 if(m_searched)
408 {
409 m_search_edit.SetWindowText(_T(""));
410 }
411 return 0;
412 }
413
414
OnOK()415 void CFolderExploreDlg::OnOK()
416 {
417 // TODO: 在此添加专用代码和/或调用基类
418 if (m_left_selected) //选中左侧树时,播放选中文件夹
419 {
420 wstring folder_path{ m_folder_explore_tree.GetItemPath(m_tree_item_selected) };
421 CMusicPlayerCmdHelper helper(this);
422 if (helper.OnOpenFolder(folder_path, true, true))
423 {
424 CTabDlg::OnOK();
425 CWnd* pParent = GetParentWindow();
426 if (pParent != nullptr)
427 ::PostMessage(pParent->GetSafeHwnd(), WM_COMMAND, IDOK, 0);
428 }
429 }
430 else
431 {
432 CMediaLibTabDlg::OnOK();
433 }
434 }
435
436
OnBrowsePath()437 void CFolderExploreDlg::OnBrowsePath()
438 {
439 // TODO: 在此添加命令处理程序代码
440 if (m_left_selected) //选中左侧树时,播放选中文件夹
441 {
442 wstring folder_path{ m_folder_explore_tree.GetItemPath(m_tree_item_selected) };
443 ShellExecute(NULL, _T("open"), _T("explorer"), folder_path.c_str(), NULL, SW_SHOWNORMAL);
444 }
445 }
446