1 // CListenTimeStatisticsDlg.cpp: 实现文件
2 //
3
4 #include "stdafx.h"
5 #include "MusicPlayer2.h"
6 #include "CListenTimeStatisticsDlg.h"
7 #include "SongDataManager.h"
8 #include "FilterHelper.h"
9 #include "AudioCommon.h"
10
11
12 // CListenTimeStatisticsDlg 对话框
13
IMPLEMENT_DYNAMIC(CListenTimeStatisticsDlg,CBaseDialog)14 IMPLEMENT_DYNAMIC(CListenTimeStatisticsDlg, CBaseDialog)
15
16 CListenTimeStatisticsDlg::CListenTimeStatisticsDlg(CWnd* pParent /*=nullptr*/)
17 : CBaseDialog(IDD_LISTEN_TIME_STATISTICS_DLG, pParent)
18 {
19
20 }
21
~CListenTimeStatisticsDlg()22 CListenTimeStatisticsDlg::~CListenTimeStatisticsDlg()
23 {
24 }
25
GetDialogName() const26 CString CListenTimeStatisticsDlg::GetDialogName() const
27 {
28 return L"ListenTimeStatisticsDlg";
29 }
30
InitializeControls()31 bool CListenTimeStatisticsDlg::InitializeControls()
32 {
33 wstring temp;
34 temp = theApp.m_str_table.LoadText(L"TITLE_LISTEN_TIME");
35 SetWindowTextW(temp.c_str());
36 // IDC_LIST1
37 temp = theApp.m_str_table.LoadText(L"TXT_LISTEN_TIME_EXPORT");
38 SetDlgItemTextW(IDC_EXPORT_BUTTON, temp.c_str());
39 temp = theApp.m_str_table.LoadText(L"TXT_LISTEN_TIME_CLEAR");
40 SetDlgItemTextW(IDC_CLEAR_BUTTON, temp.c_str());
41 temp = theApp.m_str_table.LoadText(L"TXT_CLOSE");
42 SetDlgItemTextW(IDCANCEL, temp.c_str());
43
44 RepositionTextBasedControls({
45 { CtrlTextInfo::L2, IDC_EXPORT_BUTTON, CtrlTextInfo::W32 },
46 { CtrlTextInfo::L1, IDC_CLEAR_BUTTON, CtrlTextInfo::W32 },
47 { CtrlTextInfo::R1, IDCANCEL, CtrlTextInfo::W32 }
48 });
49 return true;
50 }
51
DoDataExchange(CDataExchange * pDX)52 void CListenTimeStatisticsDlg::DoDataExchange(CDataExchange* pDX)
53 {
54 CBaseDialog::DoDataExchange(pDX);
55 DDX_Control(pDX, IDC_LIST1, m_list_ctrl);
56 }
57
58
ShowData(bool size_changed)59 void CListenTimeStatisticsDlg::ShowData(bool size_changed)
60 {
61 //将vector中的数据显示到列表中
62 if(size_changed)
63 m_list_ctrl.DeleteAllItems();
64
65 int index = 0;
66 for (const auto& data : m_data_list)
67 {
68 if (size_changed)
69 m_list_ctrl.InsertItem(index, std::to_wstring(index + 1).c_str());
70 else
71 m_list_ctrl.SetItemText(index, COL_INDEX, std::to_wstring(index + 1).c_str());
72
73 m_list_ctrl.SetItemText(index, COL_TRACK, data.name.c_str());
74 m_list_ctrl.SetItemText(index, COL_PATH, data.path.c_str());
75 m_list_ctrl.SetItemText(index, COL_TOTAL_TIME, data.total_time.toString3().c_str());
76 m_list_ctrl.SetItemText(index, COL_LENGTH, data.length.toString().c_str());
77 CString str;
78 str.Format(_T("%.1f"), data.times);
79 if (str.Right(2) == _T(".0"))
80 str = str.Left(str.GetLength() - 2);
81
82 m_list_ctrl.SetItemText(index, COL_TIMES, str);
83 // 这里之前设置当前播放高亮,意义不大,去掉了
84 index++;
85 }
86 }
87
88
SongInfoToListItem(const SongInfo & song)89 CListenTimeStatisticsDlg::ListItem CListenTimeStatisticsDlg::SongInfoToListItem(const SongInfo& song)
90 {
91 ListItem list_item;
92 if (song.IsTitleEmpty() || CAudioCommon::GetAudioTypeByFileName(song.file_path) == AU_MIDI)
93 {
94 list_item.name = song.GetFileName().c_str();
95 }
96 else
97 {
98 list_item.name = (song.GetArtist() + L" - " + song.GetTitle()).c_str();
99 }
100
101 list_item.path = song.file_path;
102 list_item.total_time = Time(song.listen_time * 1000);
103 list_item.length = song.length();
104 list_item.times = static_cast<double>(song.listen_time) / song.length().toInt() * 1000;
105 return list_item;
106 }
107
BEGIN_MESSAGE_MAP(CListenTimeStatisticsDlg,CBaseDialog)108 BEGIN_MESSAGE_MAP(CListenTimeStatisticsDlg, CBaseDialog)
109 ON_BN_CLICKED(IDC_EXPORT_BUTTON, &CListenTimeStatisticsDlg::OnBnClickedExportButton)
110 ON_WM_GETMINMAXINFO()
111 ON_BN_CLICKED(IDC_CLEAR_BUTTON, &CListenTimeStatisticsDlg::OnBnClickedClearButton)
112 ON_NOTIFY(HDN_ITEMCLICK, 0, &CListenTimeStatisticsDlg::OnHdnItemclickList1)
113 END_MESSAGE_MAP()
114
115
116 // CListenTimeStatisticsDlg 消息处理程序
117
118
119 BOOL CListenTimeStatisticsDlg::OnInitDialog()
120 {
121 CBaseDialog::OnInitDialog();
122
123 // TODO: 在此添加额外的初始化
124
125 //初始化列表
126 CRect rect;
127 m_list_ctrl.GetWindowRect(rect);
128 int width[6];
129 width[0] = theApp.DPI(40);
130 width[1] = theApp.DPI(150);
131 width[3] = width[5] = theApp.DPI(60);
132 width[4] = theApp.DPI(50);
133 width[2] = rect.Width() - width[1] - width[3] - width[4] - width[5] - width[0] - theApp.DPI(20) - 1;
134 m_list_ctrl.SetExtendedStyle(m_list_ctrl.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_LABELTIP);
135 m_list_ctrl.InsertColumn(0, theApp.m_str_table.LoadText(L"TXT_SERIAL_NUMBER").c_str(), LVCFMT_LEFT, width[0]);
136 m_list_ctrl.InsertColumn(1, theApp.m_str_table.LoadText(L"TXT_TRACK").c_str(), LVCFMT_LEFT, width[1]);
137 m_list_ctrl.InsertColumn(2, theApp.m_str_table.LoadText(L"TXT_PATH").c_str(), LVCFMT_LEFT, width[2]);
138 m_list_ctrl.InsertColumn(3, theApp.m_str_table.LoadText(L"TXT_LISTEN_TIME_TOTAL_TIME").c_str(), LVCFMT_LEFT, width[3]);
139 m_list_ctrl.InsertColumn(4, theApp.m_str_table.LoadText(L"TXT_LENGTH").c_str(), LVCFMT_LEFT, width[4]);
140 m_list_ctrl.InsertColumn(5, theApp.m_str_table.LoadText(L"TXT_LISTEN_TIME_TOTAL_COUNT").c_str(), LVCFMT_LEFT, width[5]);
141
142 //获取数据
143 //从所有歌曲信息中查找累计听的时间超过指定时间的曲目添加到vector
144 CSongDataManager::GetInstance().GetSongData([&](const CSongDataManager::SongDataMap& song_data_map)
145 {
146 for (const auto& data : song_data_map)
147 {
148 SongInfo song{ data.second };
149 if (song.listen_time >= 20 && song.length() > 0)
150 {
151 song.file_path = data.first.path;
152 m_data_list.push_back(SongInfoToListItem(song));
153 }
154 }
155 });
156
157 //先按累计收听时间从大到小排序
158 std::sort(m_data_list.begin(), m_data_list.end(), [](const ListItem& a, const ListItem& b)
159 {
160 return a.total_time > b.total_time;
161 });
162
163 //再按累计次数从大到小排序,并确保累计次数相同的项目按累计时间从大到小排序
164 std::stable_sort(m_data_list.begin(), m_data_list.end(), [](const ListItem& a, const ListItem& b)
165 {
166 double times_a, times_b;
167 times_a = CCommon::DoubleRound(a.times, 1);
168 times_b = CCommon::DoubleRound(b.times, 1);
169 return times_a > times_b;
170 });
171
172 //将数据显示到列表中
173 ShowData();
174
175 return TRUE; // return TRUE unless you set the focus to a control
176 // 异常: OCX 属性页应返回 FALSE
177 }
178
179
OnBnClickedExportButton()180 void CListenTimeStatisticsDlg::OnBnClickedExportButton()
181 {
182 // TODO: 在此添加控件通知处理程序代码
183
184 //弹出保存对话框
185
186 wstring filter = FilterHelper::GetListenTimeFilter();
187 wstring file_name = theApp.m_str_table.LoadText(L"TITLE_LISTEN_TIME");
188 CString str_cur_date;
189 SYSTEMTIME cur_time;
190 GetLocalTime(&cur_time);
191 str_cur_date.Format(_T("_%.4d-%.2d-%.2d"), cur_time.wYear, cur_time.wMonth, cur_time.wDay);
192 file_name += str_cur_date;
193 CCommon::FileNameNormalize(file_name);
194
195 // 构造保存文件对话框
196 CFileDialog fileDlg(FALSE, _T("csv"), file_name.c_str(), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, filter.c_str(), this);
197 // 显示保存文件对话框
198 if (IDOK == fileDlg.DoModal())
199 {
200 //生成导出的csv文本
201 std::wstringstream wss;
202 wss << theApp.m_str_table.LoadText(L"TXT_SERIAL_NUMBER") << L','
203 << theApp.m_str_table.LoadText(L"TXT_TRACK") << L','
204 << theApp.m_str_table.LoadText(L"TXT_PATH") << L','
205 << theApp.m_str_table.LoadText(L"TXT_LISTEN_TIME_TOTAL_TIME") << L','
206 << theApp.m_str_table.LoadText(L"TXT_LENGTH") << L','
207 << theApp.m_str_table.LoadText(L"TXT_LISTEN_TIME_TOTAL_COUNT") << L'\n';
208
209 int list_size = m_list_ctrl.GetItemCount();
210 for (int i = 0; i < list_size; i++)
211 {
212 const int COLUMN = 6;
213 for (int j = 0; j < COLUMN; j++)
214 {
215 CString item_text{ m_list_ctrl.GetItemText(i, j).GetString() };
216 CCommon::StringCsvNormalize(item_text);
217 wss << item_text.GetString();
218 if (j == COLUMN - 1)
219 wss << L'\n';
220 else
221 wss << L',';
222 }
223 }
224
225 ofstream out_put{ fileDlg.GetPathName().GetString() };
226 out_put << CCommon::UnicodeToStr(wss.str(), CodeType::UTF8);
227 out_put.close();
228 }
229 }
230
231
OnBnClickedClearButton()232 void CListenTimeStatisticsDlg::OnBnClickedClearButton()
233 {
234 // TODO: 在此添加控件通知处理程序代码
235 const wstring& info = theApp.m_str_table.LoadText(L"MSG_LISTEN_TIME_CLEAR_WARNING");
236 if (MessageBox(info.c_str(), NULL, MB_ICONINFORMATION | MB_OKCANCEL) == IDOK)
237 {
238 CSongDataManager::GetInstance().ClearPlayTime();
239 m_list_ctrl.DeleteAllItems();
240 }
241 }
242
243
OnHdnItemclickList1(NMHDR * pNMHDR,LRESULT * pResult)244 void CListenTimeStatisticsDlg::OnHdnItemclickList1(NMHDR *pNMHDR, LRESULT *pResult)
245 {
246 LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);
247 // TODO: 在此添加控件通知处理程序代码
248 if (phdr->hdr.hwndFrom == m_list_ctrl.GetHeaderCtrl()->GetSafeHwnd())
249 {
250 static bool ascending = true;
251 ascending = !ascending;
252
253 static int last_item = -1;
254 if (last_item != phdr->iItem)
255 {
256 last_item = phdr->iItem;
257 ascending = false;
258 }
259
260 //对列表排序
261 switch (phdr->iItem)
262 {
263 case COL_INDEX:
264 break;
265 case COL_TRACK:
266 std::sort(m_data_list.begin(), m_data_list.end(), [](const ListItem& a, const ListItem& b) { if (ascending) return CCommon::StringCompareInLocalLanguage(a.name, b.name) < 0; else return CCommon::StringCompareInLocalLanguage(a.name, b.name) > 0; });
267 ShowData(false);
268 break;
269 case COL_PATH:
270 std::sort(m_data_list.begin(), m_data_list.end(), [](const ListItem& a, const ListItem& b) { if (ascending) return CCommon::StringCompareInLocalLanguage(a.path, b.path) < 0; else return CCommon::StringCompareInLocalLanguage(a.path, b.path) > 0; });
271 ShowData(false);
272 break;
273 case COL_TOTAL_TIME:
274 std::sort(m_data_list.begin(), m_data_list.end(), [](const ListItem& a, const ListItem& b) { if (ascending) return a.total_time < b.total_time; else return a.total_time > b.total_time; });
275 ShowData(false);
276 break;
277 case COL_LENGTH:
278 std::sort(m_data_list.begin(), m_data_list.end(), [](const ListItem& a, const ListItem& b) { if (ascending) return a.length < b.length; else return a.length > b.length; });
279 ShowData(false);
280 break;
281 case COL_TIMES:
282 std::sort(m_data_list.begin(), m_data_list.end(), [](const ListItem& a, const ListItem& b) { if (ascending) return a.times < b.times; else return a.times > b.times; });
283 ShowData(false);
284 break;
285 default:
286 break;
287 }
288 }
289 *pResult = 0;
290 }
291