Upstream tarball 20080603
[amule.git] / src / ClientListCtrl.cpp
blob625424747041e4af888a9ea86b01218b7c49bee0
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 "Color.h"
38 #include "DataToText.h"
39 #ifdef ENABLE_IP2COUNTRY
40 #include "IP2Country.h" // Needed for IP2Country
41 #endif
42 #include "KnownFile.h"
43 #include "Preferences.h"
44 #include "updownclient.h"
45 #include "UploadQueue.h"
47 #include <wx/menu.h>
48 #include <wx/textdlg.h>
49 #include <wx/dc.h>
50 #include <wx/settings.h>
52 ////////////////////////////////////////////////////////////
53 // Sorter functions.
55 int CompareVersions(const CUpDownClient* client1, const CUpDownClient* client2)
57 if (client1->GetClientSoft() != client2->GetClientSoft()) {
58 return client1->GetSoftStr().Cmp(client2->GetSoftStr());
61 if (client1->GetVersion() != client2->GetVersion()) {
62 return CmpAny(client1->GetVersion(), client2->GetVersion());
65 return client1->GetClientModString().Cmp(client2->GetClientModString());
69 ////////////////////////////////////////////////////////////
70 // CClientListCtrl
73 BEGIN_EVENT_TABLE( CClientListCtrl, CMuleListCtrl )
74 EVT_RIGHT_DOWN(CClientListCtrl::OnRightClick)
75 EVT_LIST_ITEM_MIDDLE_CLICK(-1, CClientListCtrl::OnMiddleClick)
77 EVT_MENU( MP_DETAIL, CClientListCtrl::OnShowDetails )
78 EVT_MENU( MP_ADDFRIEND, CClientListCtrl::OnAddFriend )
79 EVT_MENU( MP_SHOWLIST, CClientListCtrl::OnViewFiles )
80 EVT_MENU( MP_SENDMESSAGE, CClientListCtrl::OnSendMessage )
81 EVT_MENU( MP_UNBAN, CClientListCtrl::OnUnbanClient )
82 EVT_MENU_RANGE( MP_SWITCHCTRL_0, MP_SWITCHCTRL_9, CClientListCtrl::OnChangeView )
83 END_EVENT_TABLE()
86 #define m_imagelist theApp->amuledlg->m_imagelist
89 /**
90 * This struct is used to keep track of the different view-types.
92 * Each view has a number of attributes, namely a title and serveral functions
93 * which are used by the CClientListCtrl class. This struct is used to store these
94 * for easier access.
96 * Please note that none of the values are required, however for a fully functional
97 * view, it is nescesarry to specificy all of them.
99 struct ClientListView
101 //! The name of the view, this is used to load and save column-preferences.
102 wxString m_title;
104 //! Pointer to the initialization function.
105 void (*m_init)(CClientListCtrl*);
107 //! Pointer to the drawing function
108 void (*m_draw)(CUpDownClient*, int, wxDC*, const wxRect&);
110 //! Pointer to the sorting function.
111 MuleListCtrlCompare m_sort;
115 //! This is the list of currently usable views, in the same order as the ViewType enum.
116 ClientListView g_listViews[] =
118 //! None: This view does nothing at all.
120 wxEmptyString,
121 NULL,
122 NULL,
123 NULL,
126 //! Uploading: The clients currently being uploaded to.
128 wxT("Uploads"),
129 CUploadingView::Initialize,
130 CUploadingView::DrawCell,
131 CUploadingView::SortProc,
134 //! Queued: The clients currently queued for uploading.
136 wxT("Queue"),
137 CQueuedView::Initialize,
138 CQueuedView::DrawCell,
139 CQueuedView::SortProc,
142 //! Clients The complete list of all known clients.
144 wxT("Clients"),
145 CClientsView::Initialize,
146 CClientsView::DrawCell,
147 CClientsView::SortProc,
153 CClientListCtrl::CClientListCtrl( wxWindow *parent, wxWindowID winid, const wxPoint &pos, const wxSize &size, long style, const wxValidator& validator, const wxString& name )
155 CMuleListCtrl( parent, winid, pos, size, style | wxLC_OWNERDRAW, validator, name )
157 m_viewType = vtNone;
159 m_menu = NULL;
161 wxColour col = SYSCOLOR( wxSYS_COLOUR_HIGHLIGHT );
162 m_hilightBrush = new wxBrush( BLEND( col, 125), wxSOLID );
164 col = SYSCOLOR( wxSYS_COLOUR_BTNSHADOW );
165 m_hilightUnfocusBrush = new wxBrush( BLEND( col, 125), wxSOLID );
168 // We show the uploading-list initially
169 SetListView( vtUploading );
173 CClientListCtrl::~CClientListCtrl()
175 delete m_hilightBrush;
176 delete m_hilightUnfocusBrush;
180 ViewType CClientListCtrl::GetListView()
182 return m_viewType;
186 void CClientListCtrl::SetListView( ViewType newView )
188 if ( m_viewType != newView ) {
189 if (m_viewType != vtNone) {
190 SaveSettings();
191 ClearAll();
194 m_viewType = newView;
196 const ClientListView& view = g_listViews[ (int)newView ];
198 // Initialize the selected view
199 if ( view.m_init ) {
200 view.m_init( this );
203 SetTableName( view.m_title );
204 SetSortFunc( view.m_sort );
206 if (newView != vtNone) {
207 LoadSettings();
213 void CClientListCtrl::ToggleView()
215 // Disallow toggling if the list is disabled
216 if ( m_viewType == vtNone ) {
217 return;
220 unsigned int view = (int)m_viewType + 1;
222 if ( view < itemsof(g_listViews) ) {
223 SetListView( (ViewType)(view) );
224 } else {
225 SetListView( (ViewType)(1) );
230 /////////////////////////////////////////////////////////////////////////////////////////////
231 void CClientListCtrl::OnRightClick(wxMouseEvent& event)
233 long index = CheckSelection(event);
235 if ( m_menu == NULL ) {
237 bool banned = false;
238 bool validIP = false;
239 bool isfriend = false;
240 bool hasdisabledsharedfiles = false;
242 // Check if the client is banned
243 if ( index > -1 ) {
244 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
246 banned = client->IsBanned();
247 validIP = (client->GetIP() != 0);
248 isfriend = client->IsFriend();
249 hasdisabledsharedfiles = client->HasDisabledSharedFiles();
252 m_menu = new wxMenu(_("Clients"));
253 m_menu->Append( MP_DETAIL, _("Show &Details") );
254 m_menu->Append( MP_ADDFRIEND, isfriend ? _("Remove from friends") : _("Add to Friends") );
255 m_menu->Append( MP_SHOWLIST, _("View Files") );
256 m_menu->Append( MP_SENDMESSAGE, _("Send message") );
257 m_menu->Append( MP_UNBAN, _("Unban") );
259 m_menu->AppendSeparator();
261 wxMenu* view = new wxMenu();
262 view->Append( MP_SWITCHCTRL_0 + 1, _("Show Uploads") );
263 view->Append( MP_SWITCHCTRL_0 + 2, _("Show Queue") );
264 view->Append( MP_SWITCHCTRL_0 + 3, _("Show Clients") );
266 view->Enable( MP_SWITCHCTRL_0 + (int)m_viewType, false );
268 m_menu->Append( 0, _("Select View"), view );
270 m_menu->Enable( MP_DETAIL, index > -1 );
271 m_menu->Enable( MP_SHOWLIST, index > -1 );
273 m_menu->Enable( MP_UNBAN, banned );
274 m_menu->Enable( MP_SHOWLIST, !hasdisabledsharedfiles );
275 m_menu->Enable( MP_ADDFRIEND, validIP );
276 m_menu->Enable( MP_SENDMESSAGE, validIP );
278 PopupMenu( m_menu, event.GetPosition() );
280 delete m_menu;
282 m_menu = NULL;
287 void CClientListCtrl::OnMiddleClick(wxListEvent& event)
289 long index = CheckSelection(event);
291 if (index > -1) {
292 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
294 CClientDetailDialog dialog(this, client);
296 dialog.ShowModal();
301 void CClientListCtrl::OnChangeView( wxCommandEvent& event )
303 int view = event.GetId() - MP_SWITCHCTRL_0;
305 SetListView( (ViewType)view );
309 void CClientListCtrl::OnAddFriend( wxCommandEvent& WXUNUSED(event) )
311 long index = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
313 while ( index != -1 ) {
314 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
315 if (client->IsFriend()) {
316 theApp->amuledlg->m_chatwnd->RemoveFriend(client->GetUserHash(), client->GetIP(), client->GetUserPort());
317 } else {
318 theApp->amuledlg->m_chatwnd->AddFriend( client );
320 index = GetNextItem( index, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
325 void CClientListCtrl::OnShowDetails( wxCommandEvent& WXUNUSED(event) )
327 long index = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
329 if ( index > -1 ) {
330 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
331 CClientDetailDialog dialog(this, client);
332 dialog.ShowModal();
337 void CClientListCtrl::OnViewFiles( wxCommandEvent& WXUNUSED(event) )
339 long index = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
341 if ( index > -1 ) {
342 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
343 client->RequestSharedFileList();
348 void CClientListCtrl::OnSendMessage( wxCommandEvent& WXUNUSED(event) )
350 long index = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
352 if ( index > -1 ) {
353 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
355 // These values are cached, since calling wxGetTextFromUser will
356 // start an event-loop, in which the client may be deleted.
357 wxString userName = client->GetUserName();
358 uint64 userID = GUI_ID(client->GetIP(),client->GetUserPort());
360 wxString message = ::wxGetTextFromUser( _("Send message to user"), _("Message to send:") );
362 if (!message.IsEmpty()) {
363 theApp->amuledlg->m_chatwnd->SendMessage(message, userName, userID);
369 void CClientListCtrl::OnUnbanClient( wxCommandEvent& WXUNUSED(event) )
371 long index = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
373 if ( index > -1 ) {
374 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
375 if ( client->IsBanned() ) {
376 client->UnBan();
382 void CClientListCtrl::InsertClient( CUpDownClient* client, ViewType view )
384 wxCHECK_RET(client, wxT("Attempted to add NULL client pointer."));
386 if ( ( m_viewType != view ) || ( view == vtNone ) ) {
387 return;
390 long index = InsertItem( GetItemCount(), wxEmptyString );
391 SetItemPtrData( index, reinterpret_cast<wxUIntPtr>(client) );
393 wxListItem myitem;
394 myitem.SetId( index );
395 myitem.SetBackgroundColour( SYSCOLOR(wxSYS_COLOUR_LISTBOX) );
397 SetItem(myitem);
399 RefreshItem( index );
403 void CClientListCtrl::RemoveClient( CUpDownClient* client, ViewType view )
405 wxCHECK_RET(client, wxT("Attempted to remove NULL client pointer."));
407 if ( ( m_viewType != view ) || ( view == vtNone ) ) {
408 return;
411 long index = FindItem( -1, reinterpret_cast<wxUIntPtr>(client) );
413 if ( index > -1 ) {
414 DeleteItem( index );
419 void CClientListCtrl::UpdateClient( CUpDownClient* client, ViewType view )
421 wxCHECK_RET(client, wxT("Attempted to update NULL client pointer."));
423 if ( ( m_viewType != view ) || ( view == vtNone ) ) {
424 return;
427 if ( theApp->amuledlg->IsDialogVisible( CamuleDlg::DT_TRANSFER_WND ) ) {
428 // Visible lines, default to all because not all platforms support the GetVisibleLines function
429 long first = 0, last = GetItemCount();
430 long result = FindItem( -1, reinterpret_cast<wxUIntPtr>(client) );
431 if ( result > -1 ) {
432 #ifndef __WXMSW__
433 GetVisibleLines( &first, &last );
434 #endif
435 if ( result >= first && result <= last) {
436 RefreshItem(result);
443 void CClientListCtrl::OnDrawItem( int item, wxDC* dc, const wxRect& rect, const wxRect& rectHL, bool highlighted )
445 // Don't do any drawing if we not being watched.
446 if ( !theApp->amuledlg || !theApp->amuledlg->IsDialogVisible( CamuleDlg::DT_TRANSFER_WND ) ) {
447 return;
450 if ( highlighted ) {
451 if ( GetFocus() ) {
452 dc->SetBackground(*m_hilightBrush);
453 dc->SetTextForeground( SYSCOLOR(wxSYS_COLOUR_HIGHLIGHTTEXT) );
454 } else {
455 dc->SetBackground(*m_hilightUnfocusBrush);
456 dc->SetTextForeground( SYSCOLOR(wxSYS_COLOUR_HIGHLIGHTTEXT));
459 wxColour colour = GetFocus() ? m_hilightBrush->GetColour() : m_hilightUnfocusBrush->GetColour();
460 dc->SetPen( wxPen( BLEND(colour, 65), 1, wxSOLID) );
461 } else {
462 dc->SetBackground( wxBrush( SYSCOLOR(wxSYS_COLOUR_LISTBOX), wxSOLID ) );
463 dc->SetTextForeground( SYSCOLOR(wxSYS_COLOUR_WINDOWTEXT) );
464 dc->SetPen(*wxTRANSPARENT_PEN);
467 dc->SetBrush(dc->GetBackground());
468 dc->DrawRectangle(rectHL);
469 dc->SetPen(*wxTRANSPARENT_PEN);
471 CUpDownClient* client = reinterpret_cast<CUpDownClient *>(GetItemData(item));
472 wxRect cur_rect = rect;
473 cur_rect.x += 4;
475 const ClientListView& view = g_listViews[ (int)m_viewType ];
477 if ( view.m_draw ) {
478 for ( int i = 0; i < GetColumnCount(); i++ ) {
479 int width = GetColumnWidth( i );
480 if ( width ) {
481 cur_rect.width = width - 8;
483 wxDCClipper clipper( *dc, cur_rect );
485 view.m_draw( client, i, dc, cur_rect );
487 cur_rect.x += width;
493 wxString CClientListCtrl::GetTTSText(unsigned item) const
495 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( item ));
497 return client->GetUserName();
501 /////////////////////////////////////////////////////////////////////////////////////////////
502 void CUploadingView::Initialize( CClientListCtrl* list )
504 list->InsertColumn( 0, _("Username"), wxLIST_FORMAT_LEFT, 150 );
505 list->InsertColumn( 1, _("File"), wxLIST_FORMAT_LEFT, 275 );
506 list->InsertColumn( 2, _("Client Software"), wxLIST_FORMAT_LEFT, 100 );
507 list->InsertColumn( 3, _("Speed"), wxLIST_FORMAT_LEFT, 60 );
508 list->InsertColumn( 4, _("Transferred"), wxLIST_FORMAT_LEFT, 65 );
509 list->InsertColumn( 5, _("Waited"), wxLIST_FORMAT_LEFT, 60 );
510 list->InsertColumn( 6, _("Upload Time"), wxLIST_FORMAT_LEFT, 60 );
511 list->InsertColumn( 7, _("Status"), wxLIST_FORMAT_LEFT, 110 );
512 list->InsertColumn( 8, _("Obtained Parts"), wxLIST_FORMAT_LEFT, 100 );
513 list->InsertColumn( 9, _("Upload/Download"), wxLIST_FORMAT_LEFT, 100 );
514 list->InsertColumn( 10, _("Remote Status"), wxLIST_FORMAT_LEFT, 100 );
516 // Insert any existing items on the list
517 const CClientPtrList& uploading = theApp->uploadqueue->GetUploadingList();
518 CClientPtrList::const_iterator it = uploading.begin();
519 for (; it != uploading.end(); ++it) {
520 list->InsertClient( *it, list->GetListView() );
525 void CUploadingView::DrawCell( CUpDownClient* client, int column, wxDC* dc, const wxRect& rect )
527 wxString buffer;
529 switch ( column ) {
530 case 0: {
531 uint8 clientImage;
533 if ( client->IsFriend() ) {
534 clientImage = Client_Friend_Smiley;
535 } else {
536 switch (client->GetClientSoft()) {
537 case SO_AMULE:
538 clientImage = Client_aMule_Smiley;
539 break;
540 case SO_MLDONKEY:
541 case SO_NEW_MLDONKEY:
542 case SO_NEW2_MLDONKEY:
543 clientImage = Client_mlDonkey_Smiley;
544 break;
545 case SO_EDONKEY:
546 case SO_EDONKEYHYBRID:
547 // Maybe we would like to make different icons?
548 clientImage = Client_eDonkeyHybrid_Smiley;
549 break;
550 case SO_EMULE:
551 clientImage = Client_eMule_Smiley;
552 break;
553 case SO_LPHANT:
554 clientImage = Client_lphant_Smiley;
555 break;
556 case SO_SHAREAZA:
557 case SO_NEW_SHAREAZA:
558 case SO_NEW2_SHAREAZA:
559 clientImage = Client_Shareaza_Smiley;
560 break;
561 case SO_LXMULE:
562 clientImage = Client_xMule_Smiley;
563 break;
564 default:
565 // cDonkey, Compat Unk
566 // No icon for those yet. Using the eMule one + '?'
567 clientImage = Client_Unknown;
568 break;
572 m_imagelist.Draw(clientImage, *dc, rect.x, rect.y + 1,
573 wxIMAGELIST_DRAW_TRANSPARENT);
575 if (client->GetScoreRatio() > 1) {
576 // Has credits, draw the gold star
577 m_imagelist.Draw(Client_CreditsYellow_Smiley, *dc, rect.x, rect.y + 1,
578 wxIMAGELIST_DRAW_TRANSPARENT );
579 } else if (client->ExtProtocolAvailable()) {
580 // Ext protocol -> Draw the '+'
581 m_imagelist.Draw(Client_ExtendedProtocol_Smiley, *dc, rect.x, rect.y + 1,
582 wxIMAGELIST_DRAW_TRANSPARENT );
585 if (client->IsIdentified()) {
586 // the 'v'
587 m_imagelist.Draw(Client_SecIdent_Smiley, *dc, rect.x, rect.y + 1,
588 wxIMAGELIST_DRAW_TRANSPARENT);
589 } else if (client->IsBadGuy()) {
590 // the 'X'
591 m_imagelist.Draw(Client_BadGuy_Smiley, *dc, rect.x, rect.y + 1,
592 wxIMAGELIST_DRAW_TRANSPARENT);
595 if (client->HasObfuscatedConnectionBeenEstablished()) {
596 // the "¿" except it's a key
597 m_imagelist.Draw(Client_Encryption_Smiley, *dc, rect.x, rect.y + 1,
598 wxIMAGELIST_DRAW_TRANSPARENT);
601 wxString userName;
602 #ifdef ENABLE_IP2COUNTRY
603 // Draw the flag
604 const CountryData& countrydata =
605 theApp->amuledlg->m_IP2Country->GetCountryData(client->GetFullIP());
606 dc->DrawBitmap(countrydata.Flag, rect.x + 20, rect.y + 5,
607 wxIMAGELIST_DRAW_TRANSPARENT);
609 userName << countrydata.Name;
610 userName << wxT(" - ");
611 #endif // ENABLE_IP2COUNTRY
612 userName << client->GetUserName();
613 dc->DrawText(userName, rect.x + 40, rect.y + 3);
615 return;
618 case 1:
619 if ( client->GetUploadFile() ) {
620 buffer = client->GetUploadFile()->GetFileName().GetPrintable();
621 } else {
622 buffer = _("N/A");
624 break;
626 case 2:
627 buffer = client->GetClientVerString();
628 break;
630 case 3:
631 buffer = wxString::Format( wxT("%.1f"), client->GetUploadDatarate() / 1024.0f );
633 buffer += wxT(" ");
634 buffer += _("kB/s");
635 break;
637 case 4:
638 buffer = CastItoXBytes(client->GetSessionUp());
639 break;
641 case 5:
642 buffer = CastSecondsToHM((client->GetWaitTime())/1000);
643 break;
645 case 6:
646 buffer = CastSecondsToHM((client->GetUpStartTimeDelay())/1000);
647 break;
649 case 7:
650 switch ( client->GetUploadState() ) {
651 case US_CONNECTING:
652 buffer = _("Connecting");
653 break;
655 case US_WAITCALLBACK:
656 buffer = _("Connecting via server");
657 break;
659 case US_UPLOADING:
660 buffer = wxT("<-- ");
661 buffer.Append(_("Transferring"));
663 if (client->GetDownloadState() == DS_DOWNLOADING) {
664 buffer.Append(wxT(" -->"));
666 break;
668 case US_ONUPLOADQUEUE:
669 buffer = _("On Queue");
670 break;
672 default:
673 buffer = _("Unknown");
675 break;
677 case 8:
678 if ( client->GetUpPartCount() ) {
679 CUploadingView::DrawStatusBar( client, dc, rect );
681 return;
683 case 9:
684 buffer = CastItoXBytes( client->GetUploadedTotal() ) +
685 wxT(" / ") + CastItoXBytes(client->GetDownloadedTotal());
686 break;
688 case 10:
689 if ( client->GetDownloadState() == DS_ONQUEUE ) {
690 if ( client->IsRemoteQueueFull() ) {
691 buffer = _("Queue Full");
692 } else {
693 if (client->GetRemoteQueueRank()) {
694 buffer = wxString::Format(_("QR: %u"), client->GetRemoteQueueRank());
695 } else {
696 buffer = _("Unknown");
699 } else if ( client->GetDownloadState() == DS_DOWNLOADING ) {
700 buffer += wxString::Format( wxT("%.1f"), client->GetKBpsDown() );
701 buffer += wxT(" ");
702 buffer += _("kB/s");
703 } else {
704 buffer = _("Unknown");
706 break;
709 dc->DrawText( buffer, rect.x, rect.y + 3 );
713 int CUploadingView::SortProc(wxUIntPtr item1, wxUIntPtr item2, long sortData)
715 CUpDownClient* client1 = (CUpDownClient*)item1;
716 CUpDownClient* client2 = (CUpDownClient*)item2;
718 // Sorting ascending or decending
719 int mode = (sortData & CMuleListCtrl::SORT_DES) ? -1 : 1;
721 switch (sortData & CMuleListCtrl::COLUMN_MASK) {
722 // Sort by username
723 case 0: return mode * client1->GetUserName().CmpNoCase( client2->GetUserName() );
726 // Sort by requested file
727 case 1: {
728 const CKnownFile* file1 = client1->GetUploadFile();
729 const CKnownFile* file2 = client2->GetUploadFile();
731 if ( file1 && file2 ) {
732 return mode * CmpAny(file1->GetFileName(), file2->GetFileName());
735 return mode * CmpAny( file1, file2 );
738 // Sort by client software
739 case 2: return mode * CompareVersions(client1, client2);
741 // Sort by speed
742 case 3: return mode * CmpAny( client1->GetUploadDatarate(), client2->GetUploadDatarate() );
744 // Sort by transferred
745 case 4: return mode * CmpAny( client1->GetSessionUp(), client2->GetSessionUp() );
747 // Sort by wait-time
748 case 5: return mode * CmpAny( client1->GetWaitTime(), client2->GetWaitTime() );
750 // Sort by upload time
751 case 6: return mode * CmpAny( client1->GetUpStartTimeDelay(), client2->GetUpStartTimeDelay() );
753 // Sort by state
754 case 7: return mode * CmpAny( client1->GetUploadState(), client2->GetUploadState() );
756 // Sort by partcount
757 case 8: return mode * CmpAny( client1->GetUpPartCount(), client2->GetUpPartCount() );
759 // Sort by U/D ratio
760 case 9: return mode * CmpAny( client2->GetDownloadedTotal(), client1->GetDownloadedTotal() );
762 // Sort by remote rank
763 case 10: return mode * CmpAny( client2->GetRemoteQueueRank(), client1->GetRemoteQueueRank() );
765 default:
766 return 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 crUnavailable = ( bFlat ? RGB( 224, 224, 224 ) : RGB( 240, 240, 240 ) );
791 uint32 crAvailable = ( bFlat ? RGB( 0, 0, 0 ) : RGB( 104, 104, 104 ) );
793 uint32 partCount = client->GetUpPartCount();
795 // Seems the partfile in the client object is not necessarily valid when bar is drawn for the first time.
796 // Keep it simple and make all parts same size.
797 s_StatusBar.SetFileSize(partCount * PARTSIZE);
798 s_StatusBar.SetHeight(barRect.height);
799 s_StatusBar.SetWidth(barRect.width);
800 s_StatusBar.Set3dDepth( thePrefs::Get3DDepth() );
802 uint64 uEnd = 0;
803 for ( uint64 i = 0; i < partCount; i++ ) {
804 uint64 uStart = PARTSIZE * i;
805 uEnd = uStart + PARTSIZE - 1;
807 uint32 color = client->IsUpPartAvailable(i) ? crAvailable : crUnavailable;
808 s_StatusBar.FillRange(uStart, uEnd, color);
810 // fill the rest (if partStatus is empty)
811 s_StatusBar.FillRange(uEnd + 1, partCount * PARTSIZE - 1, crUnavailable);
812 s_StatusBar.Draw(dc, barRect.x, barRect.y, bFlat);
814 if (!bFlat) {
815 // Draw black border
816 dc->SetPen( *wxBLACK_PEN );
817 dc->SetBrush( *wxTRANSPARENT_BRUSH );
818 dc->DrawRectangle(rect);
821 dc->SetPen( old_pen );
822 dc->SetBrush( old_brush );
826 /////////////////////////////////////////////////////////////////////////////////////////////
827 void CQueuedView::Initialize( CClientListCtrl* list )
829 list->InsertColumn( 0, _("Username"), wxLIST_FORMAT_LEFT, 150 );
830 list->InsertColumn( 1, _("File"), wxLIST_FORMAT_LEFT, 275 );
831 list->InsertColumn( 2, _("Client Software"), wxLIST_FORMAT_LEFT, 100 );
832 list->InsertColumn( 3, _("File Priority"), wxLIST_FORMAT_LEFT, 110 );
833 list->InsertColumn( 4, _("Rating"), wxLIST_FORMAT_LEFT, 60 );
834 list->InsertColumn( 5, _("Score"), wxLIST_FORMAT_LEFT, 60 );
835 list->InsertColumn( 6, _("Asked"), wxLIST_FORMAT_LEFT, 60 );
836 list->InsertColumn( 7, _("Last Seen"), wxLIST_FORMAT_LEFT, 110 );
837 list->InsertColumn( 8, _("Entered Queue"), wxLIST_FORMAT_LEFT, 110 );
838 list->InsertColumn( 9, _("Banned"), wxLIST_FORMAT_LEFT, 60 );
839 list->InsertColumn( 10, _("Obtained Parts"), wxLIST_FORMAT_LEFT, 100 );
841 // Insert any existing items on the list
842 // Insert any existing items on the list
843 const CClientPtrList& uploading = theApp->uploadqueue->GetWaitingList();
844 CClientPtrList::const_iterator it = uploading.begin();
845 for (; it != uploading.end(); ++it) {
846 list->InsertClient( *it, list->GetListView() );
851 void CQueuedView::DrawCell( CUpDownClient* client, int column, wxDC* dc, const wxRect& rect )
853 wxString buffer;
855 switch ( column ) {
856 // These 3 are the same for both lists
857 case 0:
858 case 1:
859 case 2:
860 CUploadingView::DrawCell( client, column, dc, rect );
861 return;
863 case 3:
864 if ( client->GetUploadFile() ) {
865 buffer = PriorityToStr( client->GetUploadFile()->GetUpPriority(), false );
866 } else {
867 buffer = _("Unknown");
870 break;
872 case 4:
873 buffer = wxString::Format( wxT("%.1f"), (float)client->GetScore(false,false,true) );
874 break;
876 case 5:
877 if ( client->HasLowID() ) {
878 buffer = wxString::Format( wxT("%i %s"), client->GetScore(false), _("LowID") );
879 } else {
880 buffer = wxString::Format(wxT("%i"),client->GetScore(false));
882 break;
884 case 6:
885 buffer = wxString::Format( wxT("%i"), client->GetAskedCount() );
886 break;
888 #ifndef CLIENT_GUI
889 case 7:
890 buffer = CastSecondsToHM((::GetTickCount() - client->GetLastUpRequest())/1000);
891 break;
893 case 8:
894 buffer = CastSecondsToHM((::GetTickCount() - client->GetWaitStartTime())/1000);
895 break;
896 #else
897 case 7:
898 buffer = CastSecondsToHM(client->GetLastUpRequest()/1000);
899 break;
901 case 8:
902 buffer = CastSecondsToHM(client->GetWaitStartTime()/1000);
903 break;
904 #endif
905 case 9:
906 if ( client->IsBanned() ) {
907 buffer = _("Yes");
908 } else {
909 buffer = _("No");
912 break;
914 case 10:
915 if ( client->GetUpPartCount() ) {
916 CUploadingView::DrawStatusBar( client, dc, rect );
919 return;
922 dc->DrawText( buffer, rect.x, rect.y + 3 );
926 int CQueuedView::SortProc(wxUIntPtr item1, wxUIntPtr item2, long sortData)
928 CUpDownClient* client1 = (CUpDownClient*)item1;
929 CUpDownClient* client2 = (CUpDownClient*)item2;
931 // Ascending or decending?
932 int mode = (sortData & CMuleListCtrl::SORT_DES) ? -1 : 1;
934 switch (sortData & CMuleListCtrl::COLUMN_MASK) {
935 // Sort by username
936 case 0: return mode * client1->GetUserName().CmpNoCase( client2->GetUserName() );
938 // Sort by filename
939 case 1: {
940 const CKnownFile* file1 = client1->GetUploadFile();
941 const CKnownFile* file2 = client2->GetUploadFile();
943 if ( file1 && file2 ) {
944 return mode * CmpAny(file1->GetFileName(), file2->GetFileName());
947 // Place files with filenames on top
948 return -mode * CmpAny( file1, file2 );
951 // Sort by client software
952 case 2: return mode * CompareVersions(client1, client2);
954 // Sort by file upload-priority
955 case 3: {
956 const CKnownFile* file1 = client1->GetUploadFile();
957 const CKnownFile* file2 = client2->GetUploadFile();
959 if ( file1 && file2 ) {
960 int8 prioA = file1->GetUpPriority();
961 int8 prioB = file2->GetUpPriority();
963 // Work-around for PR_VERYLOW which has value 4. See KnownFile.h for that stupidity ...
964 return mode * CmpAny( ( prioA != PR_VERYLOW ? prioA : -1 ), ( prioB != PR_VERYLOW ? prioB : -1 ) );
967 // Place files with priorities on top
968 return -mode * CmpAny( file1, file2 );
971 // Sort by rating
972 case 4: return mode * CmpAny( client1->GetScore(false,false,true), client2->GetScore(false,false,true) );
974 // Sort by score
975 case 5: return mode * CmpAny( client1->GetScore(false), client2->GetScore(false) );
977 // Sort by Asked count
978 case 6: return mode * CmpAny( client1->GetAskedCount(), client2->GetAskedCount() );
980 // Sort by Last seen
981 case 7: return mode * CmpAny( client1->GetLastUpRequest(), client2->GetLastUpRequest() );
983 // Sort by entered time
984 case 8: return mode * CmpAny( client1->GetWaitStartTime(), client2->GetWaitStartTime() );
986 // Sort by banned
987 case 9: return mode * CmpAny( client1->IsBanned(), client2->IsBanned() );
989 default: return 0;
994 /////////////////////////////////////////////////////////////////////////////////////////////
995 void CClientsView::Initialize( CClientListCtrl* list )
997 list->InsertColumn( 0, _("Username"), wxLIST_FORMAT_LEFT, 150 );
998 list->InsertColumn( 1, _("Upload Status"), wxLIST_FORMAT_LEFT, 150 );
999 list->InsertColumn( 2, _("Transferred Up"), wxLIST_FORMAT_LEFT, 150 );
1000 list->InsertColumn( 3, _("Download Status"), wxLIST_FORMAT_LEFT, 150 );
1001 list->InsertColumn( 4, _("Transferred Down"), wxLIST_FORMAT_LEFT, 150 );
1002 list->InsertColumn( 5, _("Client Software"), wxLIST_FORMAT_LEFT, 150 );
1003 list->InsertColumn( 6, _("Connected"), wxLIST_FORMAT_LEFT, 150 );
1004 list->InsertColumn( 7, _("Userhash"), wxLIST_FORMAT_LEFT, 150 );
1005 list->InsertColumn( 8, _("Encrypted"), wxLIST_FORMAT_LEFT, 100 );
1006 list->InsertColumn( 9, _("Hide shared files"), wxLIST_FORMAT_LEFT, 100 );
1008 const CClientList::IDMap& clist = theApp->clientlist->GetClientList();
1009 CClientList::IDMap::const_iterator it = clist.begin();
1011 for ( ; it != clist.end(); ++it ) {
1012 list->InsertClient( it->second, list->GetListView() );
1017 void CClientsView::DrawCell( CUpDownClient* client, int column, wxDC* dc, const wxRect& rect )
1019 wxString buffer;
1021 switch ( column ) {
1022 case 0:
1023 CUploadingView::DrawCell( client, column, dc, rect );
1024 return;
1026 case 1:
1027 CUploadingView::DrawCell( client, 7, dc, rect );
1028 return;
1030 case 2:
1031 buffer = CastItoXBytes( client->GetUploadedTotal() );
1033 break;
1035 case 3:
1036 buffer = DownloadStateToStr( client->GetDownloadState(),
1037 client->IsRemoteQueueFull() );
1038 break;
1040 case 4:
1041 buffer = CastItoXBytes( client->GetDownloadedTotal() );
1042 break;
1044 case 5:
1045 buffer = client->GetClientVerString();
1046 break;
1048 case 6:
1049 if ( client->IsConnected() ) {
1050 buffer = _("Yes");
1051 } else {
1052 buffer = _("No");
1055 break;
1057 case 7:
1058 buffer = client->GetUserHash().Encode();
1059 break;
1061 case 8:
1062 buffer = client->HasObfuscatedConnectionBeenEstablished() ?
1063 _("Yes") : _("No");
1064 break;
1066 case 9:
1067 buffer = client->GetUserName().IsEmpty() ?
1068 wxT("?") :
1069 (client->HasDisabledSharedFiles() ? _("Yes") : _("No"));
1070 break;
1073 dc->DrawText( buffer, rect.x, rect.y + 3 );
1077 int CClientsView::SortProc(wxUIntPtr item1, wxUIntPtr item2, long sortData)
1079 CUpDownClient* client1 = (CUpDownClient*)item1;
1080 CUpDownClient* client2 = (CUpDownClient*)item2;
1082 // Ascending or decending?
1083 int mode = (sortData & CMuleListCtrl::SORT_DES) ? -1 : 1;
1085 switch (sortData & CMuleListCtrl::COLUMN_MASK) {
1086 // Sort by Username
1087 case 0: return mode * client1->GetUserName().CmpNoCase( client2->GetUserName() );
1089 // Sort by Uploading-state
1090 case 1: return mode * CmpAny( client1->GetUploadState(), client2->GetUploadState() );
1092 // Sort by data-uploaded
1093 case 2:
1094 return mode * CmpAny( client1->GetUploadedTotal(), client2->GetUploadedTotal() );
1096 // Sort by Downloading-state
1097 case 3:
1098 if( client1->GetDownloadState() == client2->GetDownloadState() ){
1099 if( client1->IsRemoteQueueFull() && client2->IsRemoteQueueFull() ) {
1100 return mode * 0;
1101 } else if( client1->IsRemoteQueueFull() ) {
1102 return mode * 1;
1103 } else if( client2->IsRemoteQueueFull() ) {
1104 return mode * -1;
1105 } else {
1106 return mode * 0;
1109 return mode * CmpAny( client1->GetDownloadState(), client2->GetDownloadState() );
1111 // Sort by data downloaded
1112 case 4:
1113 return mode * CmpAny( client1->GetDownloadedTotal(), client2->GetDownloadedTotal() );
1115 // Sort by client-software
1116 case 5: return mode * CompareVersions(client1, client2);
1118 // Sort by connection
1119 case 6: return mode * CmpAny( client1->IsConnected(), client2->IsConnected() );
1121 // Sort by user-hash
1122 case 7: return mode * CmpAny( client1->GetUserHash(), client2->GetUserHash() );
1124 // Sort by Obfuscation state
1125 case 8: return mode * CmpAny( client2->HasObfuscatedConnectionBeenEstablished(), client1->HasObfuscatedConnectionBeenEstablished() );
1127 // Sort by Shared Files DISabled
1128 case 9: return mode * CmpAny( client2->HasDisabledSharedFiles(), client1->HasDisabledSharedFiles() );
1130 default:
1131 return 0;
1135 // File_checked_for_headers