1 // 2 // This file is part of the aMule Project. 3 // 4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org ) 5 // Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net ) 6 // 7 // Any parts of this program derived from the xMule, lMule or eMule project, 8 // or contributed by third-party developers are copyrighted by their 9 // respective authors. 10 // 11 // Any parts of this program derived from the xMule, lMule or eMule project, 12 // or contributed by third-party developers are copyrighted by their 13 // respective authors. 14 // 15 // This program is free software; you can redistribute it and/or modify 16 // it under the terms of the GNU General Public License as published by 17 // the Free Software Foundation; either version 2 of the License, or 18 // (at your option) any later version. 19 // 20 // This program is distributed in the hope that it will be useful, 21 // but WITHOUT ANY WARRANTY; without even the implied warranty of 22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 // GNU General Public License for more details. 24 // 25 // You should have received a copy of the GNU General Public License 26 // along with this program; if not, write to the Free Software 27 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 28 // 29 30 31 #include "muuli_wdr.h" // Needed for ID_CLOSEWNDFD,...,IDC_APPLY 32 #include "FileDetailDialog.h" // Interface declarations 33 #include "FileDetailListCtrl.h" // Needed for CFileDetailListCtrl 34 #include "CommentDialogLst.h" // Needed for CCommentDialogLst 35 #include "PartFile.h" // Needed for CPartFile 36 #include "amule.h" // Needed for theApp 37 #include "SharedFileList.h" // Needed for CSharedFileList 38 #include "OtherFunctions.h" 39 #include "MuleColour.h" 40 41 #define ID_MY_TIMER 1652 42 43 //IMPLEMENT_DYNAMIC(CFileDetailDialog, CDialog) 44 BEGIN_EVENT_TABLE(CFileDetailDialog,wxDialog) 45 EVT_BUTTON(ID_CLOSEWNDFD, CFileDetailDialog::OnClosewnd) 46 EVT_BUTTON(IDC_BUTTONSTRIP, CFileDetailDialog::OnBnClickedButtonStrip) 47 EVT_BUTTON(IDC_TAKEOVER, CFileDetailDialog::OnBnClickedTakeOver) 48 EVT_LIST_ITEM_ACTIVATED(IDC_LISTCTRLFILENAMES, CFileDetailDialog::OnListClickedTakeOver) 49 EVT_BUTTON(IDC_CMTBT, CFileDetailDialog::OnBnClickedShowComment) 50 EVT_TEXT(IDC_FILENAME, CFileDetailDialog::OnTextFileNameChange) 51 EVT_BUTTON(IDC_APPLY_AND_CLOSE, CFileDetailDialog::OnBnClickedOk) 52 EVT_BUTTON(IDC_APPLY, CFileDetailDialog::OnBnClickedApply) 53 EVT_BUTTON(IDC_PREVFILE, CFileDetailDialog::OnBnClickedPrevFile) 54 EVT_BUTTON(IDC_NEXTFILE, CFileDetailDialog::OnBnClickedNextFile) 55 EVT_TIMER(ID_MY_TIMER,CFileDetailDialog::OnTimer) 56 END_EVENT_TABLE() 57 58 CFileDetailDialog::CFileDetailDialog(wxWindow *parent, std::vector<CPartFile *> & files, int index) 59 : 60 wxDialog(parent, -1, _("File Details"), wxDefaultPosition, wxDefaultSize, 61 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX | wxMINIMIZE_BOX), 62 m_files(files), 63 m_index(index), 64 m_filenameChanged(false) 65 { 66 m_timer.SetOwner(this, ID_MY_TIMER); 67 m_timer.Start(5000); 68 wxSizer *content = fileDetails(this, true); 69 m_file = m_files[m_index]; 70 UpdateData(true); 71 content->SetSizeHints(this); 72 content->Show(this, true); 73 } 74 75 CFileDetailDialog::~CFileDetailDialog() 76 { 77 m_timer.Stop(); 78 } 79 80 void CFileDetailDialog::OnTimer(wxTimerEvent& WXUNUSED(evt)) 81 { 82 UpdateData(false); 83 } 84 85 void CFileDetailDialog::OnClosewnd(wxCommandEvent& WXUNUSED(evt)) 86 { 87 EndModal(0); 88 } 89 90 void CFileDetailDialog::UpdateData(bool resetFilename) 91 { 92 wxString bufferS; 93 CastChild(IDC_FNAME, wxStaticText)->SetLabel(MakeStringEscaped(m_file->GetFileName().TruncatePath(60))); 94 CastChild(IDC_METFILE, wxStaticText)->SetLabel(MakeStringEscaped(m_file->GetFullName().TruncatePath(60, true))); 95 96 if (resetFilename) { 97 resetValueForFilenameTextEdit(); 98 } 99 100 CastChild(IDC_FHASH,wxStaticText)->SetLabel(m_file->GetFileHash().Encode()); 101 bufferS = CFormat(wxT("%u bytes (%s)")) % m_file->GetFileSize() % CastItoXBytes(m_file->GetFileSize()); 102 CastChild(IDC_FSIZE,wxControl)->SetLabel(bufferS); 103 CastChild(IDC_PFSTATUS,wxControl)->SetLabel(m_file->getPartfileStatus()); 104 bufferS = CFormat(wxT("%i (%i)")) % m_file->GetPartCount() % m_file->GetHashCount(); 105 CastChild(IDC_PARTCOUNT,wxControl)->SetLabel(bufferS); 106 CastChild(IDC_TRANSFERRED,wxControl)->SetLabel(CastItoXBytes(m_file->GetTransferred())); 107 CastChild(IDC_FD_STATS1,wxControl)->SetLabel(CastItoXBytes(m_file->GetLostDueToCorruption())); 108 CastChild(IDC_FD_STATS2,wxControl)->SetLabel(CastItoXBytes(m_file->GetGainDueToCompression())); 109 CastChild(IDC_FD_STATS3,wxControl)->SetLabel(CastItoIShort(m_file->TotalPacketsSavedDueToICH())); 110 CastChild(IDC_COMPLSIZE,wxControl)->SetLabel(CastItoXBytes(m_file->GetCompletedSize())); 111 bufferS = CFormat(_("%.1f%% done")) % m_file->GetPercentCompleted(); 112 CastChild(IDC_PROCCOMPL,wxControl)->SetLabel(bufferS); 113 bufferS = CFormat(_("%.2f kB/s")) % m_file->GetKBpsDown(); 114 CastChild(IDC_DATARATE,wxControl)->SetLabel(bufferS); 115 bufferS = CFormat(wxT("%i")) % m_file->GetSourceCount(); 116 CastChild(IDC_SOURCECOUNT,wxControl)->SetLabel(bufferS); 117 bufferS = CFormat(wxT("%i")) % m_file->GetTransferingSrcCount(); 118 CastChild(IDC_SOURCECOUNT2,wxControl)->SetLabel(bufferS); 119 bufferS = CFormat(wxT("%i (%.1f%%)")) 120 % m_file->GetAvailablePartCount() 121 % ((m_file->GetAvailablePartCount() * 100.0)/ m_file->GetPartCount()); 122 CastChild(IDC_PARTAVAILABLE,wxControl)->SetLabel(bufferS); 123 bufferS = CastSecondsToHM(m_file->GetDlActiveTime()); 124 CastChild(IDC_DLACTIVETIME, wxControl)->SetLabel(bufferS); 125 126 if (m_file->lastseencomplete==0) { 127 bufferS = wxString(_("Unknown")).MakeLower(); 128 } else { 129 wxDateTime last_seen(m_file->lastseencomplete); 130 bufferS = last_seen.FormatISODate() + wxT(" ") + last_seen.FormatISOTime(); 131 } 132 133 CastChild(IDC_LASTSEENCOMPL,wxControl)->SetLabel(bufferS); 134 setEnableForApplyButton(); 135 // disable "Show all comments" button if there are no comments 136 FileRatingList list; 137 m_file->GetRatingAndComments(list); 138 CastChild(IDC_CMTBT, wxControl)->Enable(!list.empty()); 139 FillSourcenameList(); 140 Layout(); 141 } 142 143 // CFileDetailDialog message handlers 144 145 void CFileDetailDialog::FillSourcenameList() 146 { 147 CFileDetailListCtrl* pmyListCtrl; 148 int itempos; 149 int inserted = 0; 150 pmyListCtrl = CastChild(IDC_LISTCTRLFILENAMES, CFileDetailListCtrl ); 151 152 // reset 153 for (int i=0;i<pmyListCtrl->GetItemCount();i++){ 154 SourcenameItem *item = reinterpret_cast<SourcenameItem *>(pmyListCtrl->GetItemData(i)); 155 item->count = 0; 156 } 157 158 // update 159 #ifdef CLIENT_GUI 160 const SourcenameItemMap &sources = m_file->GetSourcenameItemMap(); 161 for (SourcenameItemMap::const_iterator it = sources.begin(); it != sources.end(); ++it) { 162 const SourcenameItem &cur_src = it->second; 163 itempos = pmyListCtrl->FindItem(-1,cur_src.name); 164 if (itempos == -1) { 165 int itemid = pmyListCtrl->InsertItem(0, cur_src.name); 166 SourcenameItem *item = new SourcenameItem(cur_src.name, cur_src.count); 167 pmyListCtrl->SetItemPtrData(0, reinterpret_cast<wxUIntPtr>(item)); 168 // background.. argh -- PA: was in old version - do we still need this? 169 wxListItem tmpitem; 170 tmpitem.m_itemId = itemid; 171 tmpitem.SetBackgroundColour(CMuleColour(wxSYS_COLOUR_LISTBOX)); 172 pmyListCtrl->SetItem(tmpitem); 173 inserted++; 174 } else { 175 SourcenameItem *item = reinterpret_cast<SourcenameItem *>(pmyListCtrl->GetItemData(itempos)); 176 item->count = cur_src.count; 177 } 178 } 179 #else // CLIENT_GUI 180 const CKnownFile::SourceSet& sources = m_file->GetSourceList(); 181 CKnownFile::SourceSet::const_iterator it = sources.begin(); 182 for ( ; it != sources.end(); ++it ) { 183 const CClientRef &cur_src = *it; 184 if (cur_src.GetRequestFile() != m_file || 185 cur_src.GetClientFilename().Length() == 0) { 186 continue; 187 } 188 189 itempos = pmyListCtrl->FindItem(-1,cur_src.GetClientFilename()); 190 if (itempos == -1) { 191 int itemid = pmyListCtrl->InsertItem(0, cur_src.GetClientFilename()); 192 SourcenameItem *item = new SourcenameItem(cur_src.GetClientFilename(), 1); 193 pmyListCtrl->SetItemPtrData(0, reinterpret_cast<wxUIntPtr>(item)); 194 // background.. argh -- PA: was in old version - do we still need this? 195 wxListItem tmpitem; 196 tmpitem.m_itemId=itemid; 197 tmpitem.SetBackgroundColour(CMuleColour(wxSYS_COLOUR_LISTBOX)); 198 pmyListCtrl->SetItem(tmpitem); 199 inserted++; 200 } else { 201 SourcenameItem *item = reinterpret_cast<SourcenameItem *>(pmyListCtrl->GetItemData(itempos)); 202 item->count++; 203 } 204 } 205 #endif // CLIENT_GUI 206 207 // remove 0'er and update counts 208 for (int i = 0; i < pmyListCtrl->GetItemCount(); ++i) { 209 SourcenameItem *item = reinterpret_cast<SourcenameItem *>(pmyListCtrl->GetItemData(i)); 210 if (item->count == 0) { 211 delete item; 212 pmyListCtrl->DeleteItem(i); 213 i--; // PA: one step back is enough, no need to go back to 0 214 } else { 215 pmyListCtrl->SetItem(i, 1, CFormat(wxT("%i")) % item->count); 216 } 217 } 218 219 if (inserted) { 220 pmyListCtrl->SortList(); 221 } 222 // no need to call Layout() here, it's called in UpdateData() 223 } 224 225 226 void CFileDetailDialog::OnBnClickedShowComment(wxCommandEvent& WXUNUSED(evt)) 227 { 228 CCommentDialogLst(this,m_file).ShowModal(); 229 } 230 231 232 void CFileDetailDialog::resetValueForFilenameTextEdit() 233 { 234 CastChild(IDC_FILENAME, wxTextCtrl)->SetValue(m_file->GetFileName().GetPrintable()); 235 m_filenameChanged = false; 236 setEnableForApplyButton(); 237 } 238 239 240 void CFileDetailDialog::setValueForFilenameTextEdit(const wxString &s) 241 { 242 CastChild(IDC_FILENAME, wxTextCtrl)->SetValue(s); 243 m_filenameChanged = true; 244 setEnableForApplyButton(); 245 } 246 247 248 void CFileDetailDialog::setEnableForApplyButton() 249 { 250 bool enabled = 251 m_file->GetStatus() != PS_COMPLETE && 252 m_file->GetStatus() != PS_COMPLETING && 253 m_filenameChanged; 254 CastChild(IDC_APPLY, wxControl)->Enable(enabled); 255 // Make OK button default so Text can be applied by hitting return 256 CastChild(enabled ? IDC_APPLY_AND_CLOSE : ID_CLOSEWNDFD, wxButton)->SetDefault(); 257 } 258 259 260 void CFileDetailDialog::OnTextFileNameChange(wxCommandEvent& WXUNUSED(evt)) 261 { 262 m_filenameChanged = true; 263 setEnableForApplyButton(); 264 } 265 266 267 void CFileDetailDialog::OnBnClickedOk(wxCommandEvent& evt) 268 { 269 OnBnClickedApply(evt); 270 OnClosewnd(evt); 271 } 272 273 274 void CFileDetailDialog::OnBnClickedApply(wxCommandEvent& WXUNUSED(evt)) 275 { 276 CPath fileName = CPath(CastChild(IDC_FILENAME, wxTextCtrl)->GetValue()); 277 278 if (fileName.IsOk() && (fileName != m_file->GetFileName())) { 279 if (theApp->sharedfiles->RenameFile(m_file, fileName)) { 280 FindWindow(IDC_FNAME)->SetLabel(MakeStringEscaped(m_file->GetFileName().GetPrintable())); 281 FindWindow(IDC_METFILE)->SetLabel(m_file->GetFullName().GetPrintable()); 282 283 resetValueForFilenameTextEdit(); 284 285 Layout(); 286 } 287 } 288 } 289 290 291 void CFileDetailDialog::OnBnClickedPrevFile(wxCommandEvent&) 292 { 293 if (--m_index < 0) { 294 m_index = m_files.size() - 1; 295 } 296 m_file = m_files[m_index]; 297 UpdateData(true); 298 } 299 300 301 void CFileDetailDialog::OnBnClickedNextFile(wxCommandEvent&) 302 { 303 if (++m_index == (int) m_files.size()) { 304 m_index = 0; 305 } 306 m_file = m_files[m_index]; 307 UpdateData(true); 308 } 309 310 311 static bool IsDigit(const wxChar ch) 312 { 313 switch (ch) { 314 case '0': 315 case '1': 316 case '2': 317 case '3': 318 case '4': 319 case '5': 320 case '6': 321 case '7': 322 case '8': 323 case '9': return true; 324 } 325 return false; 326 } 327 328 static bool IsWordSeparator(const wxChar ch) 329 { 330 switch (ch) { 331 case '.': 332 case ',': 333 case '(': 334 case ')': 335 case '[': 336 case ']': 337 case '{': 338 case '}': 339 case '-': 340 case '"': 341 case ' ': return true; 342 } 343 return false; 344 } 345 346 static void ReplaceWord(wxString& str, const wxString& replaceFrom, const wxString& replaceTo, bool numbers = false) 347 { 348 unsigned int i = 0; 349 unsigned int l = replaceFrom.Length(); 350 while (i < str.Length()) { 351 if (str.Mid(i, l) == replaceFrom) { 352 if ((i == 0 || IsWordSeparator(str.GetChar(i-1))) && 353 ((i == str.Length() - l || IsWordSeparator(str.GetChar(i+l))) || 354 (numbers && IsDigit(str.GetChar(i+l))))) { 355 str.replace(i, l, replaceTo); 356 } 357 i += replaceTo.Length() - 1; 358 } 359 i++; 360 } 361 } 362 363 void CFileDetailDialog::OnBnClickedButtonStrip(wxCommandEvent& WXUNUSED(evt)) 364 { 365 wxString filename; 366 filename = CastChild(IDC_FILENAME, wxTextCtrl)->GetValue(); 367 368 int extpos = filename.Find('.', true); 369 wxString ext; 370 if (extpos > 0) { 371 // get the extension - we do not modify it except make it lowercase 372 ext = filename.Mid(extpos); 373 ext.MakeLower(); 374 // get rid of extension and replace . with space 375 filename.Truncate(extpos); 376 filename.Replace(wxT("."),wxT(" ")); 377 } 378 379 // Replace Space-holders with Spaces 380 filename.Replace(wxT("_"),wxT(" ")); 381 filename.Replace(wxT("%20"),wxT(" ")); 382 383 // Some additional formatting 384 filename.Replace(wxT("hYPNOTiC"), wxEmptyString); 385 filename.MakeLower(); 386 filename.Replace(wxT("xxx"), wxT("XXX")); 387 // filename.Replace(wxT("xdmnx"), wxEmptyString); 388 // filename.Replace(wxT("pmp"), wxEmptyString); 389 // filename.Replace(wxT("dws"), wxEmptyString); 390 filename.Replace(wxT("www pornreactor com"), wxEmptyString); 391 filename.Replace(wxT("sharereactor"), wxEmptyString); 392 filename.Replace(wxT("found via www filedonkey com"), wxEmptyString); 393 filename.Replace(wxT("deviance"), wxEmptyString); 394 filename.Replace(wxT("adunanza"), wxEmptyString); 395 filename.Replace(wxT("-ftv"), wxEmptyString); 396 filename.Replace(wxT("flt"), wxEmptyString); 397 filename.Replace(wxT("[]"), wxEmptyString); 398 filename.Replace(wxT("()"), wxEmptyString); 399 400 // Change CD, CD#, VCD{,#}, DVD{,#}, ISO, PC to uppercase 401 ReplaceWord(filename, wxT("cd"), wxT("CD"), true); 402 ReplaceWord(filename, wxT("vcd"), wxT("VCD"), true); 403 ReplaceWord(filename, wxT("dvd"), wxT("DVD"), true); 404 ReplaceWord(filename, wxT("iso"), wxT("ISO"), false); 405 ReplaceWord(filename, wxT("pc"), wxT("PC"), false); 406 407 // Make leading Caps 408 // and delete 1+ spaces 409 if (filename.Length()>1) 410 { 411 bool last_char_space = true; 412 bool last_char_wordseparator = true; 413 unsigned int i = 0; 414 415 do { 416 wxChar c = filename.GetChar(i); 417 if (c == ' ') { 418 if (last_char_space) { 419 filename.Remove(i, 1); 420 i--; 421 } else { 422 last_char_space = true; 423 } 424 } else if (c == '.') { 425 if (last_char_space && i > 0) { 426 i--; 427 filename.Remove(i, 1); 428 } 429 last_char_space = false; 430 } else { 431 if (last_char_wordseparator) { 432 wxString tempStr(c); 433 tempStr.MakeUpper(); 434 filename.SetChar(i, tempStr.GetChar(0)); 435 last_char_space = false; 436 } 437 } 438 last_char_wordseparator = IsWordSeparator(c); 439 i++; 440 } while (i < filename.Length()); 441 442 if (last_char_space && i > 0) { 443 filename.Remove(i-1, 1); 444 } 445 } 446 447 // should stay lowercase 448 ReplaceWord(filename, wxT("By"), wxT("by")); 449 450 // re-add extension 451 filename += ext; 452 453 setValueForFilenameTextEdit(filename); 454 } 455 456 void CFileDetailDialog::OnBnClickedTakeOver(wxCommandEvent& WXUNUSED(evt)) 457 { 458 CFileDetailListCtrl* pmyListCtrl; 459 pmyListCtrl = CastChild( IDC_LISTCTRLFILENAMES, CFileDetailListCtrl ); 460 if (pmyListCtrl->GetSelectedItemCount() > 0) { 461 // get first selected item (there is only one) 462 long pos = pmyListCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); 463 if (pos != -1) { // shouldn't happen, we checked if something is selected 464 setValueForFilenameTextEdit(pmyListCtrl->GetItemText(pos)); 465 } 466 } 467 } 468 469 void CFileDetailDialog::OnListClickedTakeOver(wxListEvent& WXUNUSED(evt)) 470 { 471 wxCommandEvent ev; 472 OnBnClickedTakeOver(ev); 473 } 474 // File_checked_for_headers 475