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