Upstream tarball 20080708
[amule.git] / src / ClientListCtrl.cpp
blobdd8b5964a666d1c7498dff5b5ce6986adecc28da
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002 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.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "ClientListCtrl.h"
28 #include <protocol/ed2k/ClientSoftware.h>
29 #include <common/MenuIDs.h>
31 #include "amule.h"
32 #include "amuleDlg.h"
33 #include "BarShader.h" // Needed for CBarShader
34 #include "ChatWnd.h"
35 #include "ClientDetailDialog.h"
36 #include "ClientList.h"
37 #include "DataToText.h"
38 #ifdef ENABLE_IP2COUNTRY
39 #include "IP2Country.h" // Needed for IP2Country
40 #endif
41 #include "KnownFile.h"
42 #include "Preferences.h"
43 #include "updownclient.h"
44 #include "UploadQueue.h"
46 #include <wx/menu.h>
47 #include <wx/textdlg.h>
48 #include <wx/dc.h>
49 #include <wx/settings.h>
51 ////////////////////////////////////////////////////////////
52 // Sorter functions.
54 int CompareVersions(const CUpDownClient* client1, const CUpDownClient* client2)
56 if (client1->GetClientSoft() != client2->GetClientSoft()) {
57 return client1->GetSoftStr().Cmp(client2->GetSoftStr());
60 if (client1->GetVersion() != client2->GetVersion()) {
61 return CmpAny(client1->GetVersion(), client2->GetVersion());
64 return client1->GetClientModString().Cmp(client2->GetClientModString());
68 ////////////////////////////////////////////////////////////
69 // CClientListCtrl
72 BEGIN_EVENT_TABLE( CClientListCtrl, CMuleListCtrl )
73 EVT_RIGHT_DOWN(CClientListCtrl::OnRightClick)
74 EVT_LIST_ITEM_MIDDLE_CLICK(-1, CClientListCtrl::OnMiddleClick)
76 EVT_MENU( MP_DETAIL, CClientListCtrl::OnShowDetails )
77 EVT_MENU( MP_ADDFRIEND, CClientListCtrl::OnAddFriend )
78 EVT_MENU( MP_SHOWLIST, CClientListCtrl::OnViewFiles )
79 EVT_MENU( MP_SENDMESSAGE, CClientListCtrl::OnSendMessage )
80 EVT_MENU( MP_UNBAN, CClientListCtrl::OnUnbanClient )
81 EVT_MENU_RANGE( MP_SWITCHCTRL_0, MP_SWITCHCTRL_9, CClientListCtrl::OnChangeView )
82 END_EVENT_TABLE()
85 #define m_imagelist theApp->amuledlg->m_imagelist
88 /**
89 * This struct is used to keep track of the different view-types.
91 * Each view has a number of attributes, namely a title and serveral functions
92 * which are used by the CClientListCtrl class. This struct is used to store these
93 * for easier access.
95 * Please note that none of the values are required, however for a fully functional
96 * view, it is nescesarry to specificy all of them.
98 struct ClientListView
100 //! The name of the view, this is used to load and save column-preferences.
101 wxString m_title;
103 //! Pointer to the initialization function.
104 void (*m_init)(CClientListCtrl*);
106 //! Pointer to the drawing function
107 void (*m_draw)(CUpDownClient*, int, wxDC*, const wxRect&);
109 //! Pointer to the sorting function.
110 MuleListCtrlCompare m_sort;
114 //! This is the list of currently usable views, in the same order as the ViewType enum.
115 ClientListView g_listViews[] =
117 //! None: This view does nothing at all.
119 wxEmptyString,
120 NULL,
121 NULL,
122 NULL,
125 //! Uploading: The clients currently being uploaded to.
127 wxT("Uploads"),
128 CUploadingView::Initialize,
129 CUploadingView::DrawCell,
130 CUploadingView::SortProc,
133 //! Queued: The clients currently queued for uploading.
135 wxT("Queue"),
136 CQueuedView::Initialize,
137 CQueuedView::DrawCell,
138 CQueuedView::SortProc,
141 //! Clients The complete list of all known clients.
143 wxT("Clients"),
144 CClientsView::Initialize,
145 CClientsView::DrawCell,
146 CClientsView::SortProc,
152 CClientListCtrl::CClientListCtrl( wxWindow *parent, wxWindowID winid, const wxPoint &pos, const wxSize &size, long style, const wxValidator& validator, const wxString& name )
154 CMuleListCtrl( parent, winid, pos, size, style | wxLC_OWNERDRAW, validator, name )
156 m_viewType = vtNone;
158 m_menu = NULL;
160 m_hilightBrush = *(wxTheBrushList->FindOrCreateBrush( CMuleColour(wxSYS_COLOUR_HIGHLIGHT).Blend(125), wxSOLID ));
162 m_hilightUnfocusBrush = *(wxTheBrushList->FindOrCreateBrush( CMuleColour(wxSYS_COLOUR_BTNSHADOW).Blend(125), wxSOLID ));
164 // We show the uploading-list initially
165 SetListView( vtUploading );
169 CClientListCtrl::~CClientListCtrl()
175 ViewType CClientListCtrl::GetListView()
177 return m_viewType;
181 void CClientListCtrl::SetListView( ViewType newView )
183 if ( m_viewType != newView ) {
184 if (m_viewType != vtNone) {
185 SaveSettings();
186 ClearAll();
189 m_viewType = newView;
191 const ClientListView& view = g_listViews[ (int)newView ];
193 // Initialize the selected view
194 if ( view.m_init ) {
195 view.m_init( this );
198 SetTableName( view.m_title );
199 SetSortFunc( view.m_sort );
201 if (newView != vtNone) {
202 LoadSettings();
208 void CClientListCtrl::ToggleView()
210 // Disallow toggling if the list is disabled
211 if ( m_viewType == vtNone ) {
212 return;
215 unsigned int view = (int)m_viewType + 1;
217 if ( view < itemsof(g_listViews) ) {
218 SetListView( (ViewType)(view) );
219 } else {
220 SetListView( (ViewType)(1) );
225 /////////////////////////////////////////////////////////////////////////////////////////////
226 void CClientListCtrl::OnRightClick(wxMouseEvent& event)
228 long index = CheckSelection(event);
230 if ( m_menu == NULL ) {
232 bool banned = false;
233 bool validIP = false;
234 bool isfriend = false;
235 bool hasdisabledsharedfiles = false;
237 // Check if the client is banned
238 if ( index > -1 ) {
239 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
241 banned = client->IsBanned();
242 validIP = (client->GetIP() != 0);
243 isfriend = client->IsFriend();
244 hasdisabledsharedfiles = client->HasDisabledSharedFiles();
247 m_menu = new wxMenu(_("Clients"));
248 m_menu->Append( MP_DETAIL, _("Show &Details") );
249 m_menu->Append( MP_ADDFRIEND, isfriend ? _("Remove from friends") : _("Add to Friends") );
250 m_menu->Append( MP_SHOWLIST, _("View Files") );
251 m_menu->Append( MP_SENDMESSAGE, _("Send message") );
252 m_menu->Append( MP_UNBAN, _("Unban") );
254 m_menu->AppendSeparator();
256 wxMenu* view = new wxMenu();
257 view->Append( MP_SWITCHCTRL_0 + 1, _("Show Uploads") );
258 view->Append( MP_SWITCHCTRL_0 + 2, _("Show Queue") );
259 view->Append( MP_SWITCHCTRL_0 + 3, _("Show Clients") );
261 view->Enable( MP_SWITCHCTRL_0 + (int)m_viewType, false );
263 m_menu->Append( 0, _("Select View"), view );
265 m_menu->Enable( MP_DETAIL, index > -1 );
266 m_menu->Enable( MP_SHOWLIST, index > -1 );
268 m_menu->Enable( MP_UNBAN, banned );
269 m_menu->Enable( MP_SHOWLIST, !hasdisabledsharedfiles );
270 m_menu->Enable( MP_ADDFRIEND, validIP );
271 m_menu->Enable( MP_SENDMESSAGE, validIP );
273 PopupMenu( m_menu, event.GetPosition() );
275 delete m_menu;
277 m_menu = NULL;
282 void CClientListCtrl::OnMiddleClick(wxListEvent& event)
284 long index = CheckSelection(event);
286 if (index > -1) {
287 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
289 CClientDetailDialog dialog(this, client);
291 dialog.ShowModal();
296 void CClientListCtrl::OnChangeView( wxCommandEvent& event )
298 int view = event.GetId() - MP_SWITCHCTRL_0;
300 SetListView( (ViewType)view );
304 void CClientListCtrl::OnAddFriend( wxCommandEvent& WXUNUSED(event) )
306 long index = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
308 while ( index != -1 ) {
309 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
310 if (client->IsFriend()) {
311 theApp->amuledlg->m_chatwnd->RemoveFriend(client->GetUserHash(), client->GetIP(), client->GetUserPort());
312 } else {
313 theApp->amuledlg->m_chatwnd->AddFriend( client );
315 index = GetNextItem( index, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
320 void CClientListCtrl::OnShowDetails( wxCommandEvent& WXUNUSED(event) )
322 long index = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
324 if ( index > -1 ) {
325 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
326 CClientDetailDialog dialog(this, client);
327 dialog.ShowModal();
332 void CClientListCtrl::OnViewFiles( wxCommandEvent& WXUNUSED(event) )
334 long index = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
336 if ( index > -1 ) {
337 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
338 client->RequestSharedFileList();
343 void CClientListCtrl::OnSendMessage( wxCommandEvent& WXUNUSED(event) )
345 long index = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
347 if ( index > -1 ) {
348 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
350 // These values are cached, since calling wxGetTextFromUser will
351 // start an event-loop, in which the client may be deleted.
352 wxString userName = client->GetUserName();
353 uint64 userID = GUI_ID(client->GetIP(),client->GetUserPort());
355 wxString message = ::wxGetTextFromUser( _("Send message to user"), _("Message to send:") );
357 if (!message.IsEmpty()) {
358 theApp->amuledlg->m_chatwnd->SendMessage(message, userName, userID);
364 void CClientListCtrl::OnUnbanClient( wxCommandEvent& WXUNUSED(event) )
366 long index = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
368 if ( index > -1 ) {
369 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
370 if ( client->IsBanned() ) {
371 client->UnBan();
377 void CClientListCtrl::InsertClient( CUpDownClient* client, ViewType view )
379 wxCHECK_RET(client, wxT("Attempted to add NULL client pointer."));
381 if ( ( m_viewType != view ) || ( view == vtNone ) ) {
382 return;
385 long index = InsertItem( GetItemCount(), wxEmptyString );
386 SetItemPtrData( index, reinterpret_cast<wxUIntPtr>(client) );
388 wxListItem myitem;
389 myitem.SetId( index );
390 myitem.SetBackgroundColour( CMuleColour(wxSYS_COLOUR_LISTBOX) );
392 SetItem(myitem);
394 RefreshItem( index );
398 void CClientListCtrl::RemoveClient( CUpDownClient* client, ViewType view )
400 wxCHECK_RET(client, wxT("Attempted to remove NULL client pointer."));
402 if ( ( m_viewType != view ) || ( view == vtNone ) ) {
403 return;
406 long index = FindItem( -1, reinterpret_cast<wxUIntPtr>(client) );
408 if ( index > -1 ) {
409 DeleteItem( index );
414 void CClientListCtrl::UpdateClient( CUpDownClient* client, ViewType view )
416 wxCHECK_RET(client, wxT("Attempted to update NULL client pointer."));
418 if ( ( m_viewType != view ) || ( view == vtNone ) ) {
419 return;
422 if ( theApp->amuledlg->IsDialogVisible( CamuleDlg::DT_TRANSFER_WND ) ) {
423 // Visible lines, default to all because not all platforms support the GetVisibleLines function
424 long first = 0, last = GetItemCount();
425 long result = FindItem( -1, reinterpret_cast<wxUIntPtr>(client) );
426 if ( result > -1 ) {
427 #ifndef __WXMSW__
428 GetVisibleLines( &first, &last );
429 #endif
430 if ( result >= first && result <= last) {
431 RefreshItem(result);
438 void CClientListCtrl::OnDrawItem( int item, wxDC* dc, const wxRect& rect, const wxRect& rectHL, bool highlighted )
440 // Don't do any drawing if we not being watched.
441 if ( !theApp->amuledlg || !theApp->amuledlg->IsDialogVisible( CamuleDlg::DT_TRANSFER_WND ) ) {
442 return;
445 if ( highlighted ) {
446 if ( GetFocus() ) {
447 dc->SetBackground(m_hilightBrush);
448 dc->SetTextForeground( CMuleColour(wxSYS_COLOUR_HIGHLIGHTTEXT) );
449 } else {
450 dc->SetBackground(m_hilightUnfocusBrush);
451 dc->SetTextForeground( CMuleColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
454 CMuleColour colour = GetFocus() ? m_hilightBrush.GetColour() : m_hilightUnfocusBrush.GetColour();
455 dc->SetPen( *(wxThePenList->FindOrCreatePen( colour.Blend(65), 1, wxSOLID) ));
456 } else {
457 dc->SetBackground( *(wxTheBrushList->FindOrCreateBrush( CMuleColour(wxSYS_COLOUR_LISTBOX), wxSOLID ) ));
458 dc->SetTextForeground( CMuleColour(wxSYS_COLOUR_WINDOWTEXT) );
459 dc->SetPen(*wxTRANSPARENT_PEN);
462 dc->SetBrush(dc->GetBackground());
463 dc->DrawRectangle(rectHL);
464 dc->SetPen(*wxTRANSPARENT_PEN);
466 CUpDownClient* client = reinterpret_cast<CUpDownClient *>(GetItemData(item));
467 wxRect cur_rect = rect;
468 cur_rect.x += 4;
470 const ClientListView& view = g_listViews[ (int)m_viewType ];
472 if ( view.m_draw ) {
473 for ( int i = 0; i < GetColumnCount(); i++ ) {
474 int width = GetColumnWidth( i );
475 if ( width ) {
476 cur_rect.width = width - 8;
478 wxDCClipper clipper( *dc, cur_rect );
480 view.m_draw( client, i, dc, cur_rect );
482 cur_rect.x += width;
488 wxString CClientListCtrl::GetTTSText(unsigned item) const
490 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( item ));
492 return client->GetUserName();
496 /////////////////////////////////////////////////////////////////////////////////////////////
497 void CUploadingView::Initialize( CClientListCtrl* list )
499 list->InsertColumn( 0, _("Username"), wxLIST_FORMAT_LEFT, 150 );
500 list->InsertColumn( 1, _("File"), wxLIST_FORMAT_LEFT, 275 );
501 list->InsertColumn( 2, _("Client Software"), wxLIST_FORMAT_LEFT, 100 );
502 list->InsertColumn( 3, _("Speed"), wxLIST_FORMAT_LEFT, 60 );
503 list->InsertColumn( 4, _("Transferred"), wxLIST_FORMAT_LEFT, 65 );
504 list->InsertColumn( 5, _("Waited"), wxLIST_FORMAT_LEFT, 60 );
505 list->InsertColumn( 6, _("Upload Time"), wxLIST_FORMAT_LEFT, 60 );
506 list->InsertColumn( 7, _("Status"), wxLIST_FORMAT_LEFT, 110 );
507 list->InsertColumn( 8, _("Obtained Parts"), wxLIST_FORMAT_LEFT, 100 );
508 list->InsertColumn( 9, _("Upload/Download"), wxLIST_FORMAT_LEFT, 100 );
509 list->InsertColumn( 10, _("Remote Status"), wxLIST_FORMAT_LEFT, 100 );
511 // Insert any existing items on the list
512 const CClientPtrList& uploading = theApp->uploadqueue->GetUploadingList();
513 CClientPtrList::const_iterator it = uploading.begin();
514 for (; it != uploading.end(); ++it) {
515 list->InsertClient( *it, list->GetListView() );
520 void CUploadingView::DrawCell( CUpDownClient* client, int column, wxDC* dc, const wxRect& rect )
522 wxString buffer;
524 switch ( column ) {
525 case 0: {
526 uint8 clientImage;
528 if ( client->IsFriend() ) {
529 clientImage = Client_Friend_Smiley;
530 } else {
531 switch (client->GetClientSoft()) {
532 case SO_AMULE:
533 clientImage = Client_aMule_Smiley;
534 break;
535 case SO_MLDONKEY:
536 case SO_NEW_MLDONKEY:
537 case SO_NEW2_MLDONKEY:
538 clientImage = Client_mlDonkey_Smiley;
539 break;
540 case SO_EDONKEY:
541 case SO_EDONKEYHYBRID:
542 // Maybe we would like to make different icons?
543 clientImage = Client_eDonkeyHybrid_Smiley;
544 break;
545 case SO_EMULE:
546 clientImage = Client_eMule_Smiley;
547 break;
548 case SO_LPHANT:
549 clientImage = Client_lphant_Smiley;
550 break;
551 case SO_SHAREAZA:
552 case SO_NEW_SHAREAZA:
553 case SO_NEW2_SHAREAZA:
554 clientImage = Client_Shareaza_Smiley;
555 break;
556 case SO_LXMULE:
557 clientImage = Client_xMule_Smiley;
558 break;
559 default:
560 // cDonkey, Compat Unk
561 // No icon for those yet. Using the eMule one + '?'
562 clientImage = Client_Unknown;
563 break;
567 m_imagelist.Draw(clientImage, *dc, rect.x, rect.y + 1,
568 wxIMAGELIST_DRAW_TRANSPARENT);
570 if (client->GetScoreRatio() > 1) {
571 // Has credits, draw the gold star
572 m_imagelist.Draw(Client_CreditsYellow_Smiley, *dc, rect.x, rect.y + 1,
573 wxIMAGELIST_DRAW_TRANSPARENT );
574 } else if (client->ExtProtocolAvailable()) {
575 // Ext protocol -> Draw the '+'
576 m_imagelist.Draw(Client_ExtendedProtocol_Smiley, *dc, rect.x, rect.y + 1,
577 wxIMAGELIST_DRAW_TRANSPARENT );
580 if (client->IsIdentified()) {
581 // the 'v'
582 m_imagelist.Draw(Client_SecIdent_Smiley, *dc, rect.x, rect.y + 1,
583 wxIMAGELIST_DRAW_TRANSPARENT);
584 } else if (client->IsBadGuy()) {
585 // the 'X'
586 m_imagelist.Draw(Client_BadGuy_Smiley, *dc, rect.x, rect.y + 1,
587 wxIMAGELIST_DRAW_TRANSPARENT);
590 if (client->HasObfuscatedConnectionBeenEstablished()) {
591 // the "¿" except it's a key
592 m_imagelist.Draw(Client_Encryption_Smiley, *dc, rect.x, rect.y + 1,
593 wxIMAGELIST_DRAW_TRANSPARENT);
596 wxString userName;
597 #ifdef ENABLE_IP2COUNTRY
598 // Draw the flag
599 const CountryData& countrydata =
600 theApp->amuledlg->m_IP2Country->GetCountryData(client->GetFullIP());
601 dc->DrawBitmap(countrydata.Flag, rect.x + 20, rect.y + 5,
602 wxIMAGELIST_DRAW_TRANSPARENT);
604 userName << countrydata.Name;
605 userName << wxT(" - ");
606 #endif // ENABLE_IP2COUNTRY
607 userName << client->GetUserName();
608 dc->DrawText(userName, rect.x + 40, rect.y + 3);
610 return;
613 case 1:
614 if ( client->GetUploadFile() ) {
615 buffer = client->GetUploadFile()->GetFileName().GetPrintable();
616 } else {
617 buffer = _("N/A");
619 break;
621 case 2:
622 buffer = client->GetClientVerString();
623 break;
625 case 3:
626 buffer = wxString::Format( wxT("%.1f"), client->GetUploadDatarate() / 1024.0f );
628 buffer += wxT(" ");
629 buffer += _("kB/s");
630 break;
632 case 4:
633 buffer = CastItoXBytes(client->GetSessionUp());
634 break;
636 case 5:
637 buffer = CastSecondsToHM((client->GetWaitTime())/1000);
638 break;
640 case 6:
641 buffer = CastSecondsToHM((client->GetUpStartTimeDelay())/1000);
642 break;
644 case 7:
645 switch ( client->GetUploadState() ) {
646 case US_CONNECTING:
647 buffer = _("Connecting");
648 break;
650 case US_WAITCALLBACK:
651 buffer = _("Connecting via server");
652 break;
654 case US_UPLOADING:
655 buffer = wxT("<-- ");
656 buffer.Append(_("Transferring"));
658 if (client->GetDownloadState() == DS_DOWNLOADING) {
659 buffer.Append(wxT(" -->"));
661 break;
663 case US_ONUPLOADQUEUE:
664 buffer = _("On Queue");
665 break;
667 default:
668 buffer = _("Unknown");
670 break;
672 case 8:
673 if ( client->GetUpPartCount() ) {
674 CUploadingView::DrawStatusBar( client, dc, rect );
676 return;
678 case 9:
679 buffer = CastItoXBytes( client->GetUploadedTotal() ) +
680 wxT(" / ") + CastItoXBytes(client->GetDownloadedTotal());
681 break;
683 case 10:
684 if ( client->GetDownloadState() == DS_ONQUEUE ) {
685 if ( client->IsRemoteQueueFull() ) {
686 buffer = _("Queue Full");
687 } else {
688 if (client->GetRemoteQueueRank()) {
689 buffer = wxString::Format(_("QR: %u"), client->GetRemoteQueueRank());
690 } else {
691 buffer = _("Unknown");
694 } else if ( client->GetDownloadState() == DS_DOWNLOADING ) {
695 buffer += wxString::Format( wxT("%.1f"), client->GetKBpsDown() );
696 buffer += wxT(" ");
697 buffer += _("kB/s");
698 } else {
699 buffer = _("Unknown");
701 break;
704 dc->DrawText( buffer, rect.x, rect.y + 3 );
708 int CUploadingView::SortProc(wxUIntPtr item1, wxUIntPtr item2, long sortData)
710 CUpDownClient* client1 = (CUpDownClient*)item1;
711 CUpDownClient* client2 = (CUpDownClient*)item2;
713 // Sorting ascending or decending
714 int mode = (sortData & CMuleListCtrl::SORT_DES) ? -1 : 1;
716 switch (sortData & CMuleListCtrl::COLUMN_MASK) {
717 // Sort by username
718 case 0: return mode * client1->GetUserName().CmpNoCase( client2->GetUserName() );
721 // Sort by requested file
722 case 1: {
723 const CKnownFile* file1 = client1->GetUploadFile();
724 const CKnownFile* file2 = client2->GetUploadFile();
726 if ( file1 && file2 ) {
727 return mode * CmpAny(file1->GetFileName(), file2->GetFileName());
730 return mode * CmpAny( file1, file2 );
733 // Sort by client software
734 case 2: return mode * CompareVersions(client1, client2);
736 // Sort by speed
737 case 3: return mode * CmpAny( client1->GetUploadDatarate(), client2->GetUploadDatarate() );
739 // Sort by transferred
740 case 4: return mode * CmpAny( client1->GetSessionUp(), client2->GetSessionUp() );
742 // Sort by wait-time
743 case 5: return mode * CmpAny( client1->GetWaitTime(), client2->GetWaitTime() );
745 // Sort by upload time
746 case 6: return mode * CmpAny( client1->GetUpStartTimeDelay(), client2->GetUpStartTimeDelay() );
748 // Sort by state
749 case 7: return mode * CmpAny( client1->GetUploadState(), client2->GetUploadState() );
751 // Sort by partcount
752 case 8: return mode * CmpAny( client1->GetUpPartCount(), client2->GetUpPartCount() );
754 // Sort by U/D ratio
755 case 9: return mode * CmpAny( client2->GetDownloadedTotal(), client1->GetDownloadedTotal() );
757 // Sort by remote rank
758 case 10: return mode * CmpAny( client2->GetRemoteQueueRank(), client1->GetRemoteQueueRank() );
760 default:
761 return 0;
765 static const CMuleColour crUnavailable(240, 240, 240);
766 static const CMuleColour crFlatUnavailable(224, 224, 224);
768 static const CMuleColour crAvailable(104, 104, 104);
769 static const CMuleColour crFlatAvailable(0, 0, 0);
771 void CUploadingView::DrawStatusBar( CUpDownClient* client, wxDC* dc, const wxRect& rect1 )
773 wxRect rect = rect1;
774 rect.y += 1;
775 rect.height -= 2;
777 wxPen old_pen = dc->GetPen();
778 wxBrush old_brush = dc->GetBrush();
779 bool bFlat = thePrefs::UseFlatBar();
781 wxRect barRect = rect;
782 if (!bFlat) { // round bar has a black border, the bar itself is 1 pixel less on each border
783 barRect.x ++;
784 barRect.y ++;
785 barRect.height -= 2;
786 barRect.width -= 2;
788 static CBarShader s_StatusBar(16);
790 uint32 partCount = client->GetUpPartCount();
792 // Seems the partfile in the client object is not necessarily valid when bar is drawn for the first time.
793 // Keep it simple and make all parts same size.
794 s_StatusBar.SetFileSize(partCount * PARTSIZE);
795 s_StatusBar.SetHeight(barRect.height);
796 s_StatusBar.SetWidth(barRect.width);
797 s_StatusBar.Set3dDepth( thePrefs::Get3DDepth() );
799 uint64 uEnd = 0;
800 for ( uint64 i = 0; i < partCount; i++ ) {
801 uint64 uStart = PARTSIZE * i;
802 uEnd = uStart + PARTSIZE - 1;
804 s_StatusBar.FillRange(uStart, uEnd, client->IsUpPartAvailable(i) ? (bFlat ? crFlatAvailable : crAvailable) : (bFlat ? crFlatUnavailable : crUnavailable));
806 // fill the rest (if partStatus is empty)
807 s_StatusBar.FillRange(uEnd + 1, partCount * PARTSIZE - 1, bFlat ? crFlatUnavailable : crUnavailable);
808 s_StatusBar.Draw(dc, barRect.x, barRect.y, bFlat);
810 if (!bFlat) {
811 // Draw black border
812 dc->SetPen( *wxBLACK_PEN );
813 dc->SetBrush( *wxTRANSPARENT_BRUSH );
814 dc->DrawRectangle(rect);
817 dc->SetPen( old_pen );
818 dc->SetBrush( old_brush );
822 /////////////////////////////////////////////////////////////////////////////////////////////
823 void CQueuedView::Initialize( CClientListCtrl* list )
825 list->InsertColumn( 0, _("Username"), wxLIST_FORMAT_LEFT, 150 );
826 list->InsertColumn( 1, _("File"), wxLIST_FORMAT_LEFT, 275 );
827 list->InsertColumn( 2, _("Client Software"), wxLIST_FORMAT_LEFT, 100 );
828 list->InsertColumn( 3, _("File Priority"), wxLIST_FORMAT_LEFT, 110 );
829 list->InsertColumn( 4, _("Rating"), wxLIST_FORMAT_LEFT, 60 );
830 list->InsertColumn( 5, _("Score"), wxLIST_FORMAT_LEFT, 60 );
831 list->InsertColumn( 6, _("Asked"), wxLIST_FORMAT_LEFT, 60 );
832 list->InsertColumn( 7, _("Last Seen"), wxLIST_FORMAT_LEFT, 110 );
833 list->InsertColumn( 8, _("Entered Queue"), wxLIST_FORMAT_LEFT, 110 );
834 list->InsertColumn( 9, _("Banned"), wxLIST_FORMAT_LEFT, 60 );
835 list->InsertColumn( 10, _("Obtained Parts"), wxLIST_FORMAT_LEFT, 100 );
837 // Insert any existing items on the list
838 // Insert any existing items on the list
839 const CClientPtrList& uploading = theApp->uploadqueue->GetWaitingList();
840 CClientPtrList::const_iterator it = uploading.begin();
841 for (; it != uploading.end(); ++it) {
842 list->InsertClient( *it, list->GetListView() );
847 void CQueuedView::DrawCell( CUpDownClient* client, int column, wxDC* dc, const wxRect& rect )
849 wxString buffer;
851 switch ( column ) {
852 // These 3 are the same for both lists
853 case 0:
854 case 1:
855 case 2:
856 CUploadingView::DrawCell( client, column, dc, rect );
857 return;
859 case 3:
860 if ( client->GetUploadFile() ) {
861 buffer = PriorityToStr( client->GetUploadFile()->GetUpPriority(), false );
862 } else {
863 buffer = _("Unknown");
866 break;
868 case 4:
869 buffer = wxString::Format( wxT("%.1f"), (float)client->GetScore(false,false,true) );
870 break;
872 case 5:
873 if ( client->HasLowID() ) {
874 buffer = wxString::Format( wxT("%i %s"), client->GetScore(false), _("LowID") );
875 } else {
876 buffer = wxString::Format(wxT("%i"),client->GetScore(false));
878 break;
880 case 6:
881 buffer = wxString::Format( wxT("%i"), client->GetAskedCount() );
882 break;
884 #ifndef CLIENT_GUI
885 case 7:
886 buffer = CastSecondsToHM((::GetTickCount() - client->GetLastUpRequest())/1000);
887 break;
889 case 8:
890 buffer = CastSecondsToHM((::GetTickCount() - client->GetWaitStartTime())/1000);
891 break;
892 #else
893 case 7:
894 buffer = CastSecondsToHM(client->GetLastUpRequest()/1000);
895 break;
897 case 8:
898 buffer = CastSecondsToHM(client->GetWaitStartTime()/1000);
899 break;
900 #endif
901 case 9:
902 if ( client->IsBanned() ) {
903 buffer = _("Yes");
904 } else {
905 buffer = _("No");
908 break;
910 case 10:
911 if ( client->GetUpPartCount() ) {
912 CUploadingView::DrawStatusBar( client, dc, rect );
915 return;
918 dc->DrawText( buffer, rect.x, rect.y + 3 );
922 int CQueuedView::SortProc(wxUIntPtr item1, wxUIntPtr item2, long sortData)
924 CUpDownClient* client1 = (CUpDownClient*)item1;
925 CUpDownClient* client2 = (CUpDownClient*)item2;
927 // Ascending or decending?
928 int mode = (sortData & CMuleListCtrl::SORT_DES) ? -1 : 1;
930 switch (sortData & CMuleListCtrl::COLUMN_MASK) {
931 // Sort by username
932 case 0: return mode * client1->GetUserName().CmpNoCase( client2->GetUserName() );
934 // Sort by filename
935 case 1: {
936 const CKnownFile* file1 = client1->GetUploadFile();
937 const CKnownFile* file2 = client2->GetUploadFile();
939 if ( file1 && file2 ) {
940 return mode * CmpAny(file1->GetFileName(), file2->GetFileName());
943 // Place files with filenames on top
944 return -mode * CmpAny( file1, file2 );
947 // Sort by client software
948 case 2: return mode * CompareVersions(client1, client2);
950 // Sort by file upload-priority
951 case 3: {
952 const CKnownFile* file1 = client1->GetUploadFile();
953 const CKnownFile* file2 = client2->GetUploadFile();
955 if ( file1 && file2 ) {
956 int8 prioA = file1->GetUpPriority();
957 int8 prioB = file2->GetUpPriority();
959 // Work-around for PR_VERYLOW which has value 4. See KnownFile.h for that stupidity ...
960 return mode * CmpAny( ( prioA != PR_VERYLOW ? prioA : -1 ), ( prioB != PR_VERYLOW ? prioB : -1 ) );
963 // Place files with priorities on top
964 return -mode * CmpAny( file1, file2 );
967 // Sort by rating
968 case 4: return mode * CmpAny( client1->GetScore(false,false,true), client2->GetScore(false,false,true) );
970 // Sort by score
971 case 5: return mode * CmpAny( client1->GetScore(false), client2->GetScore(false) );
973 // Sort by Asked count
974 case 6: return mode * CmpAny( client1->GetAskedCount(), client2->GetAskedCount() );
976 // Sort by Last seen
977 case 7: return mode * CmpAny( client1->GetLastUpRequest(), client2->GetLastUpRequest() );
979 // Sort by entered time
980 case 8: return mode * CmpAny( client1->GetWaitStartTime(), client2->GetWaitStartTime() );
982 // Sort by banned
983 case 9: return mode * CmpAny( client1->IsBanned(), client2->IsBanned() );
985 default: return 0;
990 /////////////////////////////////////////////////////////////////////////////////////////////
991 void CClientsView::Initialize( CClientListCtrl* list )
993 list->InsertColumn( 0, _("Username"), wxLIST_FORMAT_LEFT, 150 );
994 list->InsertColumn( 1, _("Upload Status"), wxLIST_FORMAT_LEFT, 150 );
995 list->InsertColumn( 2, _("Transferred Up"), wxLIST_FORMAT_LEFT, 150 );
996 list->InsertColumn( 3, _("Download Status"), wxLIST_FORMAT_LEFT, 150 );
997 list->InsertColumn( 4, _("Transferred Down"), wxLIST_FORMAT_LEFT, 150 );
998 list->InsertColumn( 5, _("Client Software"), wxLIST_FORMAT_LEFT, 150 );
999 list->InsertColumn( 6, _("Connected"), wxLIST_FORMAT_LEFT, 150 );
1000 list->InsertColumn( 7, _("Userhash"), wxLIST_FORMAT_LEFT, 150 );
1001 list->InsertColumn( 8, _("Encrypted"), wxLIST_FORMAT_LEFT, 100 );
1002 list->InsertColumn( 9, _("Hide shared files"), wxLIST_FORMAT_LEFT, 100 );
1004 const CClientList::IDMap& clist = theApp->clientlist->GetClientList();
1005 CClientList::IDMap::const_iterator it = clist.begin();
1007 for ( ; it != clist.end(); ++it ) {
1008 list->InsertClient( it->second, list->GetListView() );
1013 void CClientsView::DrawCell( CUpDownClient* client, int column, wxDC* dc, const wxRect& rect )
1015 wxString buffer;
1017 switch ( column ) {
1018 case 0:
1019 CUploadingView::DrawCell( client, column, dc, rect );
1020 return;
1022 case 1:
1023 CUploadingView::DrawCell( client, 7, dc, rect );
1024 return;
1026 case 2:
1027 buffer = CastItoXBytes( client->GetUploadedTotal() );
1029 break;
1031 case 3:
1032 buffer = DownloadStateToStr( client->GetDownloadState(),
1033 client->IsRemoteQueueFull() );
1034 break;
1036 case 4:
1037 buffer = CastItoXBytes( client->GetDownloadedTotal() );
1038 break;
1040 case 5:
1041 buffer = client->GetClientVerString();
1042 break;
1044 case 6:
1045 if ( client->IsConnected() ) {
1046 buffer = _("Yes");
1047 } else {
1048 buffer = _("No");
1051 break;
1053 case 7:
1054 buffer = client->GetUserHash().Encode();
1055 break;
1057 case 8:
1058 buffer = client->HasObfuscatedConnectionBeenEstablished() ?
1059 _("Yes") : _("No");
1060 break;
1062 case 9:
1063 buffer = client->GetUserName().IsEmpty() ?
1064 wxT("?") :
1065 (client->HasDisabledSharedFiles() ? _("Yes") : _("No"));
1066 break;
1069 dc->DrawText( buffer, rect.x, rect.y + 3 );
1073 int CClientsView::SortProc(wxUIntPtr item1, wxUIntPtr item2, long sortData)
1075 CUpDownClient* client1 = (CUpDownClient*)item1;
1076 CUpDownClient* client2 = (CUpDownClient*)item2;
1078 // Ascending or decending?
1079 int mode = (sortData & CMuleListCtrl::SORT_DES) ? -1 : 1;
1081 switch (sortData & CMuleListCtrl::COLUMN_MASK) {
1082 // Sort by Username
1083 case 0: return mode * client1->GetUserName().CmpNoCase( client2->GetUserName() );
1085 // Sort by Uploading-state
1086 case 1: return mode * CmpAny( client1->GetUploadState(), client2->GetUploadState() );
1088 // Sort by data-uploaded
1089 case 2:
1090 return mode * CmpAny( client1->GetUploadedTotal(), client2->GetUploadedTotal() );
1092 // Sort by Downloading-state
1093 case 3:
1094 if( client1->GetDownloadState() == client2->GetDownloadState() ){
1095 if( client1->IsRemoteQueueFull() && client2->IsRemoteQueueFull() ) {
1096 return mode * 0;
1097 } else if( client1->IsRemoteQueueFull() ) {
1098 return mode * 1;
1099 } else if( client2->IsRemoteQueueFull() ) {
1100 return mode * -1;
1101 } else {
1102 return mode * 0;
1105 return mode * CmpAny( client1->GetDownloadState(), client2->GetDownloadState() );
1107 // Sort by data downloaded
1108 case 4:
1109 return mode * CmpAny( client1->GetDownloadedTotal(), client2->GetDownloadedTotal() );
1111 // Sort by client-software
1112 case 5: return mode * CompareVersions(client1, client2);
1114 // Sort by connection
1115 case 6: return mode * CmpAny( client1->IsConnected(), client2->IsConnected() );
1117 // Sort by user-hash
1118 case 7: return mode * CmpAny( client1->GetUserHash(), client2->GetUserHash() );
1120 // Sort by Obfuscation state
1121 case 8: return mode * CmpAny( client2->HasObfuscatedConnectionBeenEstablished(), client1->HasObfuscatedConnectionBeenEstablished() );
1123 // Sort by Shared Files DISabled
1124 case 9: return mode * CmpAny( client2->HasDisabledSharedFiles(), client1->HasDisabledSharedFiles() );
1126 default:
1127 return 0;
1131 // File_checked_for_headers