xref: /MusicPlayer2/MusicPlayer2/FindListDlg.cpp (revision 93532e0c7b11da0fd5f48dd951f1119db4d17ab8)
1 // FindListDlg.cpp: 实现文件
2 //
3 
4 #include "stdafx.h"
5 #include "MusicPlayer2.h"
6 #include "afxdialogex.h"
7 #include "FindListDlg.h"
8 #include "UiMediaLibItemMgr.h"
9 #include "MusicPlayerCmdHelper.h"
10 #include "FolderPropertiesDlg.h"
11 #include "PlaylistPropertiesDlg.h"
12 #include "MediaLibItemPropertiesDlg.h"
13 
14 // CFindListDlg 对话框
15 
IMPLEMENT_DYNAMIC(CFindListDlg,CTabDlg)16 IMPLEMENT_DYNAMIC(CFindListDlg, CTabDlg)
17 
18 CFindListDlg::CFindListDlg(CWnd* pParent /*=nullptr*/)
19     : CTabDlg(IDD_FIND_LIST_DIALOG, pParent)
20 {
21 
22 }
23 
~CFindListDlg()24 CFindListDlg::~CFindListDlg()
25 {
26 }
27 
InitListData()28 void CFindListDlg::InitListData()
29 {
30     if (!m_initialized)
31     {
32         m_list_data.clear();
33         //添加所有最近播放项目
34         CListCache list_cache(LT_ALL);
35         list_cache.reload();
36         AddListCacheData(list_cache);
37         //添加媒体库项目
38         AddMediaLibItem(CMediaClassifier::CT_ARTIST);
39         AddMediaLibItem(CMediaClassifier::CT_ALBUM);
40         AddMediaLibItem(CMediaClassifier::CT_GENRE);
41         AddMediaLibItem(CMediaClassifier::CT_YEAR);
42         AddMediaLibItem(CMediaClassifier::CT_TYPE);
43         //添加媒体库中的所有文件夹
44         AddAllFolders();
45 
46         //设置到列表
47         ShowList();
48 
49         m_initialized = true;
50     }
51 }
52 
OnTabEntered()53 void CFindListDlg::OnTabEntered()
54 {
55     if (!m_initialized)
56         SetPlaySelectedEnable(false);
57     else
58         SetPlaySelectedEnable(m_list_ctrl.GetCurSel() > 0);
59     InitListData();
60 }
61 
AddListCacheData(const CListCache & list_cache)62 void CFindListDlg::AddListCacheData(const CListCache& list_cache)
63 {
64     for (int i{}; i < list_cache.size(); i++)
65     {
66         CListCtrlEx::RowData row_data;
67         const auto& list_data = list_cache.at(i);
68         row_data[COL_NAME] = list_data.GetDisplayName();
69         row_data[COL_TRACK_NUM] = std::to_wstring(list_data.total_num);
70         m_list_data.push_back(std::move(row_data));
71         FindListItem list_item;
72         list_item.list_data = list_data;
73         list_item.item_from = ItemFrom::RECENT_PLAYED;
74         m_all_list_items.push_back(list_item);
75     }
76 }
77 
AddMediaLibItem(CMediaClassifier::ClassificationType type)78 void CFindListDlg::AddMediaLibItem(CMediaClassifier::ClassificationType type)
79 {
80     //这里考虑即使没有在媒体库设置中勾选“将只有一项的分类归到其他类中”,也应该添加所有项目
81 	int item_count = CUiMediaLibItemMgr::Instance().GetItemCount(type);
82 	for (int i{}; i < item_count; i++)
83 	{
84 		ListItem list_data;
85 		list_data.type = LT_MEDIA_LIB;
86 		list_data.medialib_type = type;
87 		list_data.path = CUiMediaLibItemMgr::Instance().GetItemName(type, i);
88 		list_data.total_num = CUiMediaLibItemMgr::Instance().GetItemSongCount(type, i);
89 		auto iter = std::find(m_all_list_items.begin(), m_all_list_items.end(), list_data);
90 		//不添加重复的项目
91 		if (iter == m_all_list_items.end())
92 		{
93 			FindListItem list_item;
94 			list_item.list_data = list_data;
95 			list_item.item_from = ItemFrom::MEDIALIB_ITEM;
96 			m_all_list_items.push_back(list_item);
97 			CListCtrlEx::RowData row_data;
98 			row_data[COL_NAME] = CUiMediaLibItemMgr::Instance().GetItemDisplayName(type, i);
99 			row_data[COL_TRACK_NUM] = std::to_wstring(list_data.total_num);
100 			m_list_data.push_back(std::move(row_data));
101 		}
102 	}
103 }
104 
AddAllFolders()105 void CFindListDlg::AddAllFolders()
106 {
107     const auto& folder_nodes = CUiFolderExploreMgr::Instance().GetRootNodes();
108     for (const auto& folder_node : folder_nodes)
109     {
110         //遍历每个顶级文件夹节点
111         folder_node->IterateNodeInOrder([&](UiElement::TreeElement::Node* node) -> bool {
112             std::wstring folder_path = UiElement::FolderExploreTree::GetNodePath(node);		//文件夹路径
113             std::wstring track_num = node->texts[UiElement::FolderExploreTree::COL_COUNT];	//曲目数
114             ListItem list_data;
115             list_data.type = LT_FOLDER;
116             list_data.path = folder_path + L'\\';	//文件夹路径末尾添加一个反斜杠,使得其格式和CListCache中的文件夹一致
117             list_data.total_num = _wtoi(track_num.c_str());
118             auto iter = std::find(m_all_list_items.begin(), m_all_list_items.end(), list_data);
119             //不添加重复的项目
120             if (iter == m_all_list_items.end())
121             {
122                 FindListItem list_item;
123                 list_item.list_data = list_data;
124                 list_item.item_from = ItemFrom::FOLDER_EXPLORE;
125                 m_all_list_items.push_back(list_item);
126                 CListCtrlEx::RowData row_data;
127                 row_data[COL_NAME] = folder_path;
128                 row_data[COL_TRACK_NUM] = track_num;
129                 m_list_data.push_back(std::move(row_data));
130             }
131             return false;
132         }, false);
133     }
134 }
135 
ShowList()136 void CFindListDlg::ShowList()
137 {
138     if (m_searched)
139         m_list_ctrl.SetListData(&m_list_data_searched);
140     else
141         m_list_ctrl.SetListData(&m_list_data);
142 
143     //更新图标
144     if (m_searched)
145     {
146         for (int i{}; i < static_cast<int>(m_search_result.size()); i++)
147         {
148             int index = m_search_result[i];
149             if (index >= 0 && index < static_cast<int>(m_all_list_items.size()))
150             {
151                 IconMgr::IconType icon = m_all_list_items[index].list_data.GetTypeIcon();
152                 m_list_ctrl.SetItemIcon(i, theApp.m_icon_mgr.GetHICON(icon, IconMgr::IconStyle::IS_OutlinedDark, IconMgr::IconSize::IS_DPI_16));
153             }
154         }
155     }
156     else
157     {
158         for (int i{}; i < static_cast<int>(m_all_list_items.size()); i++)
159         {
160             IconMgr::IconType icon = m_all_list_items[i].list_data.GetTypeIcon();
161             m_list_ctrl.SetItemIcon(i, theApp.m_icon_mgr.GetHICON(icon, IconMgr::IconStyle::IS_OutlinedDark, IconMgr::IconSize::IS_DPI_16));
162         }
163     }
164 }
165 
QuickSearch(const wstring & key_word)166 void CFindListDlg::QuickSearch(const wstring& key_word)
167 {
168     m_list_data_searched.clear();
169     m_search_result.clear();
170     if (!key_word.empty())
171     {
172         for (int i{}; i < static_cast<int>(m_list_data.size()); ++i)
173         {
174             const auto& item{ m_list_data[i] };
175             const vector<int> search_col{ COL_NAME };
176             for (int col : search_col)
177             {
178                 if (theApp.m_chinese_pingyin_res.IsStringMatchWithPingyin(key_word, item.at(col)))
179                 {
180                     m_list_data_searched.push_back(item);
181                     m_search_result.push_back(i);
182                     break;
183                 }
184             }
185         }
186     }
187 }
188 
SetPlaySelectedEnable(bool enable)189 void CFindListDlg::SetPlaySelectedEnable(bool enable)
190 {
191     CWnd* pParent = GetParentWindow();
192     ::SendMessage(pParent->GetSafeHwnd(), WM_PLAY_SELECTED_BTN_ENABLE, WPARAM(enable), 0);
193 }
194 
GetSelectedItem() const195 CFindListDlg::FindListItem CFindListDlg::GetSelectedItem() const
196 {
197     FindListItem list_item;
198     int cur_sel = m_list_ctrl.GetCurSel();
199     if (m_searched)
200     {
201         if (cur_sel >= 0 && cur_sel < static_cast<int>(m_search_result.size()))
202         {
203             int index = m_search_result[cur_sel];
204             if (index >= 0 && index < static_cast<int>(m_all_list_items.size()))
205             {
206                 list_item = m_all_list_items[index];
207             }
208         }
209     }
210     else
211     {
212         if (cur_sel >= 0 && cur_sel < static_cast<int>(m_all_list_items.size()))
213         {
214             list_item = m_all_list_items[cur_sel];
215         }
216     }
217     return list_item;
218 }
219 
DoDataExchange(CDataExchange * pDX)220 void CFindListDlg::DoDataExchange(CDataExchange* pDX)
221 {
222     CTabDlg::DoDataExchange(pDX);
223     DDX_Control(pDX, IDC_SONG_LIST, m_list_ctrl);
224     DDX_Control(pDX, IDC_SEARCH_EDIT, m_search_edit);
225 }
226 
227 
BEGIN_MESSAGE_MAP(CFindListDlg,CTabDlg)228 BEGIN_MESSAGE_MAP(CFindListDlg, CTabDlg)
229     ON_MESSAGE(WM_SEARCH_EDIT_BTN_CLICKED, &CFindListDlg::OnSearchEditBtnClicked)
230     ON_EN_CHANGE(IDC_SEARCH_EDIT, &CFindListDlg::OnEnChangeSearchEdit)
231     ON_NOTIFY(NM_CLICK, IDC_SONG_LIST, &CFindListDlg::OnNMClickSongList)
232     ON_WM_SIZE()
233     ON_NOTIFY(NM_DBLCLK, IDC_SONG_LIST, &CFindListDlg::OnNMDblclkSongList)
234     ON_NOTIFY(NM_RCLICK, IDC_SONG_LIST, &CFindListDlg::OnNMRClickSongList)
235     ON_COMMAND(ID_PLAY_ITEM, &CFindListDlg::OnPlayItem)
236     ON_COMMAND(ID_COPY_TEXT, &CFindListDlg::OnCopyText)
237     ON_COMMAND(ID_VIEW_IN_MEDIA_LIB, &CFindListDlg::OnViewInMediaLib)
238     ON_COMMAND(ID_LIB_RECENT_PLAYED_ITEM_PROPERTIES, &CFindListDlg::OnLibRecentPlayedItemProperties)
239     ON_WM_INITMENU()
240 END_MESSAGE_MAP()
241 
242 
243 // CFindListDlg 消息处理程序
244 
245 
246 BOOL CFindListDlg::OnInitDialog()
247 {
248     CTabDlg::OnInitDialog();
249 
250     //初始化列表控件
251     m_list_ctrl.SetExtendedStyle(m_list_ctrl.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_LABELTIP);
252     m_list_ctrl.InsertColumn(COL_NAME, theApp.m_str_table.LoadText(L"TXT_NAME").c_str(), LVCFMT_LEFT, theApp.DPI(320));
253     m_list_ctrl.InsertColumn(COL_TRACK_NUM, theApp.m_str_table.LoadText(L"TXT_NUM_OF_TRACK").c_str(), LVCFMT_LEFT, theApp.DPI(140));
254     m_list_ctrl.SetCtrlAEnable(true);
255     m_list_ctrl.SetRowHeight(theApp.DPI(24), theApp.DPI(18));
256 
257     m_search_edit.SetCueBanner(theApp.m_str_table.LoadText(L"TXT_SEARCH_PROMPT_ALL_LIST").c_str(), TRUE);
258 
259 
260     return TRUE;  // return TRUE unless you set the focus to a control
261     // 异常: OCX 属性页应返回 FALSE
262 }
263 
264 
OnOK()265 void CFindListDlg::OnOK()
266 {
267     //获取选中的项目
268     FindListItem list_item = GetSelectedItem();
269     if (!list_item.list_data.empty())
270     {
271         CMusicPlayerCmdHelper helper;
272         helper.OnListItemSelected(list_item.list_data, true);
273     }
274 
275     CTabDlg::OnOK();
276 }
277 
278 
OnSearchEditBtnClicked(WPARAM wParam,LPARAM lParam)279 afx_msg LRESULT CFindListDlg::OnSearchEditBtnClicked(WPARAM wParam, LPARAM lParam)
280 {
281     //点击搜索框中的叉按钮时清除搜索结果
282     if (m_searched)
283     {
284         //清除搜索结果
285         m_searched = false;
286         m_search_edit.SetWindowText(_T(""));
287         ShowList();
288     }
289     return 0;
290 }
291 
292 
OnEnChangeSearchEdit()293 void CFindListDlg::OnEnChangeSearchEdit()
294 {
295     // TODO:  如果该控件是 RICHEDIT 控件,它将不
296     // 发送此通知,除非重写 CTabDlg::OnInitDialog()
297     // 函数并调用 CRichEditCtrl().SetEventMask(),
298     // 同时将 ENM_CHANGE 标志“或”运算到掩码中。
299 
300     CString str;
301     m_search_edit.GetWindowText(str);
302     QuickSearch(wstring(str));
303     m_searched = !str.IsEmpty();
304     ShowList();
305 }
306 
307 
OnNMClickSongList(NMHDR * pNMHDR,LRESULT * pResult)308 void CFindListDlg::OnNMClickSongList(NMHDR* pNMHDR, LRESULT* pResult)
309 {
310     LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
311     // TODO: 在此添加控件通知处理程序代码
312     SetPlaySelectedEnable(pNMItemActivate->iItem != -1);
313 
314     *pResult = 0;
315 }
316 
317 
OnSize(UINT nType,int cx,int cy)318 void CFindListDlg::OnSize(UINT nType, int cx, int cy)
319 {
320     CTabDlg::OnSize(nType, cx, cy);
321 
322     if (m_list_ctrl.m_hWnd != NULL && nType != SIZE_MINIMIZED)
323     {
324         //调整列表中项目的宽度
325         CRect rect;
326         m_list_ctrl.GetWindowRect(rect);
327         int list_width{ rect.Width() - theApp.DPI(20) - 1 };        //列表控件宽度减去留给垂直滚动条的宽度余量
328         int width0, width1;
329         width1 = theApp.DPI(60);
330         width0 = list_width - width1;
331         m_list_ctrl.SetColumnWidth(COL_NAME, width0);
332         m_list_ctrl.SetColumnWidth(COL_TRACK_NUM, width1);
333     }
334 }
335 
336 
OnNMDblclkSongList(NMHDR * pNMHDR,LRESULT * pResult)337 void CFindListDlg::OnNMDblclkSongList(NMHDR* pNMHDR, LRESULT* pResult)
338 {
339     LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
340     OnPlayItem();
341     *pResult = 0;
342 }
343 
344 
OnNMRClickSongList(NMHDR * pNMHDR,LRESULT * pResult)345 void CFindListDlg::OnNMRClickSongList(NMHDR* pNMHDR, LRESULT* pResult)
346 {
347     LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
348 
349     //弹出右键菜单
350     CMenu* pContextMenu = theApp.m_menu_mgr.GetMenu(MenuMgr::FindListMenu);
351     m_list_ctrl.ShowPopupMenu(pContextMenu, pNMItemActivate->iItem, this);
352     *pResult = 0;
353 }
354 
355 
OnPlayItem()356 void CFindListDlg::OnPlayItem()
357 {
358     //向父窗口发送IDOK命令
359     CWnd* pParent = GetParentWindow();
360     ::SendMessage(pParent->GetSafeHwnd(), WM_COMMAND, IDOK, 0);
361 }
362 
363 
OnCopyText()364 void CFindListDlg::OnCopyText()
365 {
366     FindListItem list_item = GetSelectedItem();
367     if (list_item.list_data.empty())
368         return;
369     if (!CCommon::CopyStringToClipboard(list_item.list_data.GetDisplayName()))
370         AfxMessageBox(theApp.m_str_table.LoadText(L"MSG_COPY_CLIPBOARD_FAILED").c_str(), MB_ICONWARNING);
371 }
372 
373 
OnViewInMediaLib()374 void CFindListDlg::OnViewInMediaLib()
375 {
376     FindListItem list_item = GetSelectedItem();
377     if (list_item.list_data.empty())
378         return;
379     CMusicPlayerCmdHelper helper;
380     helper.OnViewInMediaLib(list_item.list_data);
381 }
382 
383 
OnLibRecentPlayedItemProperties()384 void CFindListDlg::OnLibRecentPlayedItemProperties()
385 {
386     FindListItem list_item = GetSelectedItem();
387     if (list_item.list_data.empty())
388         return;
389     if (list_item.list_data.type == LT_FOLDER)
390     {
391         CFolderPropertiesDlg dlg(list_item.list_data);
392         dlg.DoModal();
393     }
394     else if (list_item.list_data.type == LT_PLAYLIST)
395     {
396         CPlaylistPropertiesDlg dlg(list_item.list_data);
397         dlg.DoModal();
398     }
399     else if (list_item.list_data.type == LT_MEDIA_LIB)
400     {
401         CMediaLibItemPropertiesDlg dlg(list_item.list_data);
402         dlg.DoModal();
403     }
404 }
405 
406 
OnInitMenu(CMenu * pMenu)407 void CFindListDlg::OnInitMenu(CMenu* pMenu)
408 {
409     CTabDlg::OnInitMenu(pMenu);
410 
411     FindListItem list_item = GetSelectedItem();
412     bool select_valid = m_list_ctrl.GetCurSel() >= 0;
413     pMenu->EnableMenuItem(ID_PLAY_ITEM, MF_BYCOMMAND | (select_valid ? MF_ENABLED : MF_GRAYED));
414     pMenu->EnableMenuItem(ID_COPY_TEXT, MF_BYCOMMAND | (select_valid ? MF_ENABLED : MF_GRAYED));
415     pMenu->EnableMenuItem(ID_VIEW_IN_MEDIA_LIB, MF_BYCOMMAND | (select_valid && (list_item.item_from == ItemFrom::RECENT_PLAYED || list_item.item_from == ItemFrom::MEDIALIB_ITEM) ? MF_ENABLED : MF_GRAYED));
416     pMenu->EnableMenuItem(ID_LIB_RECENT_PLAYED_ITEM_PROPERTIES, MF_BYCOMMAND | (select_valid && list_item.item_from == ItemFrom::RECENT_PLAYED ? MF_ENABLED : MF_GRAYED));
417 }
418