Upstream tarball 9959
[amule.git] / src / ClientListCtrl.cpp
blobb9153dc83b6acd90870a85e97efc3d92919822ad
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;
112 //! Pointer to the function which returns the old column order.
113 wxString (*m_getOldColumnOrder)();
117 //! This is the list of currently usable views, in the same order as the ViewType enum.
118 ClientListView g_listViews[] =
120 //! None: This view does nothing at all.
122 wxEmptyString,
123 NULL,
124 NULL,
125 NULL,
126 NULL,
129 //! Uploading: The clients currently being uploaded to.
131 wxT("Uploads"),
132 CUploadingView::Initialize,
133 CUploadingView::DrawCell,
134 CUploadingView::SortProc,
135 CUploadingView::GetOldColumnOrder,
138 //! Queued: The clients currently queued for uploading.
140 wxT("Queue"),
141 CQueuedView::Initialize,
142 CQueuedView::DrawCell,
143 CQueuedView::SortProc,
144 CQueuedView::GetOldColumnOrder,
147 //! Clients The complete list of all known clients.
149 wxT("Clients"),
150 CClientsView::Initialize,
151 CClientsView::DrawCell,
152 CClientsView::SortProc,
153 CClientsView::GetOldColumnOrder,
159 CClientListCtrl::CClientListCtrl( wxWindow *parent, wxWindowID winid, const wxPoint &pos, const wxSize &size, long style, const wxValidator& validator, const wxString& name )
161 CMuleListCtrl( parent, winid, pos, size, style | wxLC_OWNERDRAW, validator, name )
163 m_viewType = vtNone;
165 m_menu = NULL;
167 m_hilightBrush = CMuleColour(wxSYS_COLOUR_HIGHLIGHT).Blend(125).GetBrush();
169 m_hilightUnfocusBrush = CMuleColour(wxSYS_COLOUR_BTNSHADOW).Blend(125).GetBrush();
171 // We show the uploading-list initially
172 SetListView( vtUploading );
176 CClientListCtrl::~CClientListCtrl()
182 ViewType CClientListCtrl::GetListView()
184 return m_viewType;
188 void CClientListCtrl::SetListView( ViewType newView )
190 if ( m_viewType != newView ) {
191 if (m_viewType != vtNone) {
192 SaveSettings();
193 ClearAll();
196 m_viewType = newView;
198 const ClientListView& view = g_listViews[ (int)newView ];
200 // Initialize the selected view
201 if ( view.m_init ) {
202 view.m_init( this );
205 SetTableName( view.m_title );
206 SetSortFunc( view.m_sort );
208 if (newView != vtNone) {
209 LoadSettings();
215 void CClientListCtrl::ToggleView()
217 // Disallow toggling if the list is disabled
218 if ( m_viewType == vtNone ) {
219 return;
222 unsigned int view = (int)m_viewType + 1;
224 if ( view < itemsof(g_listViews) ) {
225 SetListView( (ViewType)(view) );
226 } else {
227 SetListView( (ViewType)(1) );
232 /////////////////////////////////////////////////////////////////////////////////////////////
233 void CClientListCtrl::OnRightClick(wxMouseEvent& event)
235 long index = CheckSelection(event);
237 if ( m_menu == NULL ) {
239 bool banned = false;
240 bool validIP = false;
241 bool isfriend = false;
242 bool hasdisabledsharedfiles = false;
244 // Check if the client is banned
245 if ( index > -1 ) {
246 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
248 banned = client->IsBanned();
249 validIP = (client->GetIP() != 0);
250 isfriend = client->IsFriend();
251 hasdisabledsharedfiles = client->HasDisabledSharedFiles();
254 m_menu = new wxMenu(_("Clients"));
255 m_menu->Append( MP_DETAIL, _("Show &Details") );
256 m_menu->Append( MP_ADDFRIEND, isfriend ? _("Remove from friends") : _("Add to Friends") );
257 m_menu->Append( MP_SHOWLIST, _("View Files") );
258 m_menu->Append( MP_SENDMESSAGE, _("Send message") );
259 m_menu->Append( MP_UNBAN, _("Unban") );
261 m_menu->AppendSeparator();
263 wxMenu* view = new wxMenu();
264 view->Append( MP_SWITCHCTRL_0 + 1, _("Show Uploads") );
265 view->Append( MP_SWITCHCTRL_0 + 2, _("Show Queue") );
266 view->Append( MP_SWITCHCTRL_0 + 3, _("Show Clients") );
268 view->Enable( MP_SWITCHCTRL_0 + (int)m_viewType, false );
270 m_menu->Append( 0, _("Select View"), view );
272 m_menu->Enable( MP_DETAIL, index > -1 );
273 m_menu->Enable( MP_SHOWLIST, index > -1 );
275 m_menu->Enable( MP_UNBAN, banned );
276 m_menu->Enable( MP_SHOWLIST, !hasdisabledsharedfiles );
277 m_menu->Enable( MP_ADDFRIEND, validIP );
278 m_menu->Enable( MP_SENDMESSAGE, validIP );
280 PopupMenu( m_menu, event.GetPosition() );
282 delete m_menu;
284 m_menu = NULL;
289 void CClientListCtrl::OnMiddleClick(wxListEvent& event)
291 long index = CheckSelection(event);
293 if (index > -1) {
294 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
296 CClientDetailDialog dialog(this, client);
298 dialog.ShowModal();
303 void CClientListCtrl::OnChangeView( wxCommandEvent& event )
305 int view = event.GetId() - MP_SWITCHCTRL_0;
307 SetListView( (ViewType)view );
311 void CClientListCtrl::OnAddFriend( wxCommandEvent& WXUNUSED(event) )
313 long index = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
315 while ( index != -1 ) {
316 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
317 if (client->IsFriend()) {
318 theApp->amuledlg->m_chatwnd->RemoveFriend(client->GetUserHash(), client->GetIP(), client->GetUserPort());
319 } else {
320 theApp->amuledlg->m_chatwnd->AddFriend( client );
322 index = GetNextItem( index, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
327 void CClientListCtrl::OnShowDetails( wxCommandEvent& WXUNUSED(event) )
329 long index = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
331 if ( index > -1 ) {
332 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
333 CClientDetailDialog dialog(this, client);
334 dialog.ShowModal();
339 void CClientListCtrl::OnViewFiles( wxCommandEvent& WXUNUSED(event) )
341 long index = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
343 if ( index > -1 ) {
344 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
345 client->RequestSharedFileList();
350 void CClientListCtrl::OnSendMessage( wxCommandEvent& WXUNUSED(event) )
352 long index = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
354 if ( index > -1 ) {
355 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
357 // These values are cached, since calling wxGetTextFromUser will
358 // start an event-loop, in which the client may be deleted.
359 wxString userName = client->GetUserName();
360 uint64 userID = GUI_ID(client->GetIP(),client->GetUserPort());
362 wxString message = ::wxGetTextFromUser( _("Send message to user"), _("Message to send:") );
364 if (!message.IsEmpty()) {
365 theApp->amuledlg->m_chatwnd->SendMessage(message, userName, userID);
371 void CClientListCtrl::OnUnbanClient( wxCommandEvent& WXUNUSED(event) )
373 long index = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
375 if ( index > -1 ) {
376 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( index ));
377 if ( client->IsBanned() ) {
378 client->UnBan();
384 void CClientListCtrl::InsertClient( CUpDownClient* client, ViewType view )
386 wxCHECK_RET(client, wxT("Attempted to add NULL client pointer."));
388 if ( ( m_viewType != view ) || ( view == vtNone ) ) {
389 return;
392 long index = InsertItem( GetItemCount(), wxEmptyString );
393 SetItemPtrData( index, reinterpret_cast<wxUIntPtr>(client) );
395 wxListItem myitem;
396 myitem.SetId( index );
397 myitem.SetBackgroundColour( CMuleColour(wxSYS_COLOUR_LISTBOX) );
399 SetItem(myitem);
401 RefreshItem( index );
405 void CClientListCtrl::RemoveClient( CUpDownClient* client, ViewType view )
407 wxCHECK_RET(client, wxT("Attempted to remove NULL client pointer."));
409 if ( ( m_viewType != view ) || ( view == vtNone ) ) {
410 return;
413 long index = FindItem( -1, reinterpret_cast<wxUIntPtr>(client) );
415 if ( index > -1 ) {
416 DeleteItem( index );
421 void CClientListCtrl::UpdateClient( CUpDownClient* client, ViewType view )
423 wxCHECK_RET(client, wxT("Attempted to update NULL client pointer."));
425 if ( ( m_viewType != view ) || ( view == vtNone ) ) {
426 return;
429 if ( theApp->amuledlg->IsDialogVisible( CamuleDlg::DT_TRANSFER_WND ) ) {
430 // Visible lines, default to all because not all platforms support the GetVisibleLines function
431 long first = 0, last = GetItemCount();
432 long result = FindItem( -1, reinterpret_cast<wxUIntPtr>(client) );
433 if ( result > -1 ) {
434 #ifndef __WXMSW__
435 GetVisibleLines( &first, &last );
436 #endif
437 if ( result >= first && result <= last) {
438 RefreshItem(result);
445 void CClientListCtrl::OnDrawItem( int item, wxDC* dc, const wxRect& rect, const wxRect& rectHL, bool highlighted )
447 // Don't do any drawing if we not being watched.
448 if ( !theApp->amuledlg || !theApp->amuledlg->IsDialogVisible( CamuleDlg::DT_TRANSFER_WND ) ) {
449 return;
452 if ( highlighted ) {
453 if ( GetFocus() ) {
454 dc->SetBackground(m_hilightBrush);
455 dc->SetTextForeground( CMuleColour(wxSYS_COLOUR_HIGHLIGHTTEXT) );
456 } else {
457 dc->SetBackground(m_hilightUnfocusBrush);
458 dc->SetTextForeground( CMuleColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
461 CMuleColour colour = GetFocus() ? m_hilightBrush.GetColour() : m_hilightUnfocusBrush.GetColour();
462 dc->SetPen( *(wxThePenList->FindOrCreatePen( colour.Blend(65), 1, wxSOLID) ));
463 } else {
464 dc->SetBackground( CMuleColour(wxSYS_COLOUR_LISTBOX).GetBrush());
465 dc->SetTextForeground( CMuleColour(wxSYS_COLOUR_WINDOWTEXT) );
466 dc->SetPen(*wxTRANSPARENT_PEN);
469 dc->SetBrush(dc->GetBackground());
470 dc->DrawRectangle(rectHL);
471 dc->SetPen(*wxTRANSPARENT_PEN);
473 CUpDownClient* client = reinterpret_cast<CUpDownClient *>(GetItemData(item));
474 wxRect cur_rect = rect;
475 cur_rect.x += 4;
477 const ClientListView& view = g_listViews[ (int)m_viewType ];
479 if ( view.m_draw ) {
480 for ( int i = 0; i < GetColumnCount(); i++ ) {
481 int width = GetColumnWidth( i );
482 if ( width ) {
483 cur_rect.width = width - 8;
485 wxDCClipper clipper( *dc, cur_rect );
487 view.m_draw( client, i, dc, cur_rect );
489 cur_rect.x += width;
495 wxString CClientListCtrl::GetTTSText(unsigned item) const
497 CUpDownClient *client = reinterpret_cast<CUpDownClient *>(GetItemData( item ));
499 return client->GetUserName();
503 wxString CClientListCtrl::GetOldColumnOrder() const
505 const ClientListView& view = g_listViews[ (int)m_viewType ];
506 if (view.m_getOldColumnOrder) {
507 return view.m_getOldColumnOrder();
509 return wxEmptyString;
513 /////////////////////////////////////////////////////////////////////////////////////////////
514 void CUploadingView::Initialize( CClientListCtrl* list )
516 list->InsertColumn( 0, _("Username"), wxLIST_FORMAT_LEFT, 150, wxT("U") );
517 list->InsertColumn( 1, _("File"), wxLIST_FORMAT_LEFT, 275, wxT("F") );
518 list->InsertColumn( 2, _("Client Software"), wxLIST_FORMAT_LEFT, 100, wxT("C") );
519 list->InsertColumn( 3, _("Speed"), wxLIST_FORMAT_LEFT, 60, wxT("S") );
520 list->InsertColumn( 4, _("Transferred"), wxLIST_FORMAT_LEFT, 65, wxT("T") );
521 list->InsertColumn( 5, _("Waited"), wxLIST_FORMAT_LEFT, 60, wxT("W") );
522 list->InsertColumn( 6, _("Upload Time"), wxLIST_FORMAT_LEFT, 60, wxT("u") );
523 list->InsertColumn( 7, _("Status"), wxLIST_FORMAT_LEFT, 110, wxT("s") );
524 list->InsertColumn( 8, _("Obtained Parts"), wxLIST_FORMAT_LEFT, 100, wxT("P") );
525 list->InsertColumn( 9, _("Upload/Download"), wxLIST_FORMAT_LEFT, 100, wxT("R") );
526 list->InsertColumn( 10, _("Remote Status"), wxLIST_FORMAT_LEFT, 100, wxT("r") );
528 // Insert any existing items on the list
529 const CClientPtrList& uploading = theApp->uploadqueue->GetUploadingList();
530 CClientPtrList::const_iterator it = uploading.begin();
531 for (; it != uploading.end(); ++it) {
532 list->InsertClient( *it, list->GetListView() );
537 wxString CUploadingView::GetOldColumnOrder()
539 return wxT("U,F,C,S,T,W,u,s,P,R,r");
543 void CUploadingView::DrawCell( CUpDownClient* client, int column, wxDC* dc, const wxRect& rect )
545 wxString buffer;
547 switch ( column ) {
548 case 0: {
549 uint8 clientImage;
551 if ( client->IsFriend() ) {
552 clientImage = Client_Friend_Smiley;
553 } else {
554 switch (client->GetClientSoft()) {
555 case SO_AMULE:
556 clientImage = Client_aMule_Smiley;
557 break;
558 case SO_MLDONKEY:
559 case SO_NEW_MLDONKEY:
560 case SO_NEW2_MLDONKEY:
561 clientImage = Client_mlDonkey_Smiley;
562 break;
563 case SO_EDONKEY:
564 case SO_EDONKEYHYBRID:
565 // Maybe we would like to make different icons?
566 clientImage = Client_eDonkeyHybrid_Smiley;
567 break;
568 case SO_EMULE:
569 clientImage = Client_eMule_Smiley;
570 break;
571 case SO_LPHANT:
572 clientImage = Client_lphant_Smiley;
573 break;
574 case SO_SHAREAZA:
575 case SO_NEW_SHAREAZA:
576 case SO_NEW2_SHAREAZA:
577 clientImage = Client_Shareaza_Smiley;
578 break;
579 case SO_LXMULE:
580 clientImage = Client_xMule_Smiley;
581 break;
582 default:
583 // cDonkey, Compat Unk
584 // No icon for those yet. Using the eMule one + '?'
585 clientImage = Client_Unknown;
586 break;
590 m_imagelist.Draw(clientImage, *dc, rect.x, rect.y + 1,
591 wxIMAGELIST_DRAW_TRANSPARENT);
593 if (client->GetScoreRatio() > 1) {
594 // Has credits, draw the gold star
595 m_imagelist.Draw(Client_CreditsYellow_Smiley, *dc, rect.x, rect.y + 1,
596 wxIMAGELIST_DRAW_TRANSPARENT );
597 } else if (client->ExtProtocolAvailable()) {
598 // Ext protocol -> Draw the '+'
599 m_imagelist.Draw(Client_ExtendedProtocol_Smiley, *dc, rect.x, rect.y + 1,
600 wxIMAGELIST_DRAW_TRANSPARENT );
603 if (client->IsIdentified()) {
604 // the 'v'
605 m_imagelist.Draw(Client_SecIdent_Smiley, *dc, rect.x, rect.y + 1,
606 wxIMAGELIST_DRAW_TRANSPARENT);
607 } else if (client->IsBadGuy()) {
608 // the 'X'
609 m_imagelist.Draw(Client_BadGuy_Smiley, *dc, rect.x, rect.y + 1,
610 wxIMAGELIST_DRAW_TRANSPARENT);
613 if (client->HasObfuscatedConnectionBeenEstablished()) {
614 // the "¿" except it's a key
615 m_imagelist.Draw(Client_Encryption_Smiley, *dc, rect.x, rect.y + 1,
616 wxIMAGELIST_DRAW_TRANSPARENT);
619 wxString userName;
620 #ifdef ENABLE_IP2COUNTRY
621 // Draw the flag
622 const CountryData& countrydata =
623 theApp->amuledlg->m_IP2Country->GetCountryData(client->GetFullIP());
624 dc->DrawBitmap(countrydata.Flag, rect.x + 20, rect.y + 5,
625 wxIMAGELIST_DRAW_TRANSPARENT);
627 userName << countrydata.Name;
628 userName << wxT(" - ");
629 #endif // ENABLE_IP2COUNTRY
630 userName << client->GetUserName();
631 dc->DrawText(userName, rect.x + 40, rect.y + 3);
633 return;
636 case 1:
637 if ( client->GetUploadFile() ) {
638 buffer = client->GetUploadFile()->GetFileName().GetPrintable();
639 } else {
640 buffer = _("N/A");
642 break;
644 case 2:
645 buffer = client->GetClientVerString();
646 break;
648 case 3:
649 buffer = wxString::Format( wxT("%.1f"), client->GetUploadDatarate() / 1024.0f );
651 buffer += wxT(" ");
652 buffer += _("kB/s");
653 break;
655 case 4:
656 buffer = CastItoXBytes(client->GetSessionUp());
657 break;
659 case 5:
660 buffer = CastSecondsToHM((client->GetWaitTime())/1000);
661 break;
663 case 6:
664 buffer = CastSecondsToHM((client->GetUpStartTimeDelay())/1000);
665 break;
667 case 7:
668 switch ( client->GetUploadState() ) {
669 case US_CONNECTING:
670 buffer = _("Connecting");
671 break;
673 case US_WAITCALLBACK:
674 buffer = _("Connecting via server");
675 break;
677 case US_UPLOADING:
678 buffer = wxT("<-- ");
679 buffer.Append(_("Transferring"));
681 if (client->GetDownloadState() == DS_DOWNLOADING) {
682 buffer.Append(wxT(" -->"));
684 break;
686 case US_ONUPLOADQUEUE:
687 buffer = _("On Queue");
688 break;
690 default:
691 buffer = _("Unknown");
693 break;
695 case 8:
696 if ( client->GetUpPartCount() ) {
697 CUploadingView::DrawStatusBar( client, dc, rect );
699 return;
701 case 9:
702 buffer = CastItoXBytes( client->GetUploadedTotal() ) +
703 wxT(" / ") + CastItoXBytes(client->GetDownloadedTotal());
704 break;
706 case 10:
707 if ( client->GetDownloadState() == DS_ONQUEUE ) {
708 if ( client->IsRemoteQueueFull() ) {
709 buffer = _("Queue Full");
710 } else {
711 if (client->GetRemoteQueueRank()) {
712 buffer = wxString::Format(_("QR: %u"), client->GetRemoteQueueRank());
713 } else {
714 buffer = _("Unknown");
717 } else if ( client->GetDownloadState() == DS_DOWNLOADING ) {
718 buffer += wxString::Format( wxT("%.1f"), client->GetKBpsDown() );
719 buffer += wxT(" ");
720 buffer += _("kB/s");
721 } else {
722 buffer = _("Unknown");
724 break;
727 dc->DrawText( buffer, rect.x, rect.y + 3 );
731 int CUploadingView::SortProc(wxUIntPtr item1, wxUIntPtr item2, long sortData)
733 CUpDownClient* client1 = (CUpDownClient*)item1;
734 CUpDownClient* client2 = (CUpDownClient*)item2;
736 // Sorting ascending or decending
737 int mode = (sortData & CMuleListCtrl::SORT_DES) ? -1 : 1;
739 switch (sortData & CMuleListCtrl::COLUMN_MASK) {
740 // Sort by username
741 case 0: return mode * client1->GetUserName().CmpNoCase( client2->GetUserName() );
744 // Sort by requested file
745 case 1: {
746 const CKnownFile* file1 = client1->GetUploadFile();
747 const CKnownFile* file2 = client2->GetUploadFile();
749 if ( file1 && file2 ) {
750 return mode * CmpAny(file1->GetFileName(), file2->GetFileName());
753 return mode * CmpAny( file1, file2 );
756 // Sort by client software
757 case 2: return mode * CompareVersions(client1, client2);
759 // Sort by speed
760 case 3: return mode * CmpAny( client1->GetUploadDatarate(), client2->GetUploadDatarate() );
762 // Sort by transferred
763 case 4: return mode * CmpAny( client1->GetSessionUp(), client2->GetSessionUp() );
765 // Sort by wait-time
766 case 5: return mode * CmpAny( client1->GetWaitTime(), client2->GetWaitTime() );
768 // Sort by upload time
769 case 6: return mode * CmpAny( client1->GetUpStartTimeDelay(), client2->GetUpStartTimeDelay() );
771 // Sort by state
772 case 7: return mode * CmpAny( client1->GetUploadState(), client2->GetUploadState() );
774 // Sort by partcount
775 case 8: return mode * CmpAny( client1->GetUpPartCount(), client2->GetUpPartCount() );
777 // Sort by U/D ratio
778 case 9: return mode * CmpAny( client2->GetDownloadedTotal(), client1->GetDownloadedTotal() );
780 // Sort by remote rank
781 case 10: return mode * CmpAny( client2->GetRemoteQueueRank(), client1->GetRemoteQueueRank() );
783 default:
784 return 0;
788 static const CMuleColour crUnavailable(240, 240, 240);
789 static const CMuleColour crFlatUnavailable(224, 224, 224);
791 static const CMuleColour crAvailable(104, 104, 104);
792 static const CMuleColour crFlatAvailable(0, 0, 0);
794 void CUploadingView::DrawStatusBar( CUpDownClient* client, wxDC* dc, const wxRect& rect1 )
796 wxRect rect = rect1;
797 rect.y += 1;
798 rect.height -= 2;
800 wxPen old_pen = dc->GetPen();
801 wxBrush old_brush = dc->GetBrush();
802 bool bFlat = thePrefs::UseFlatBar();
804 wxRect barRect = rect;
805 if (!bFlat) { // round bar has a black border, the bar itself is 1 pixel less on each border
806 barRect.x ++;
807 barRect.y ++;
808 barRect.height -= 2;
809 barRect.width -= 2;
811 static CBarShader s_StatusBar(16);
813 uint32 partCount = client->GetUpPartCount();
815 // Seems the partfile in the client object is not necessarily valid when bar is drawn for the first time.
816 // Keep it simple and make all parts same size.
817 s_StatusBar.SetFileSize(partCount * PARTSIZE);
818 s_StatusBar.SetHeight(barRect.height);
819 s_StatusBar.SetWidth(barRect.width);
820 s_StatusBar.Set3dDepth( thePrefs::Get3DDepth() );
822 uint64 uEnd = 0;
823 for ( uint64 i = 0; i < partCount; i++ ) {
824 uint64 uStart = PARTSIZE * i;
825 uEnd = uStart + PARTSIZE - 1;
827 s_StatusBar.FillRange(uStart, uEnd, client->IsUpPartAvailable(i) ? (bFlat ? crFlatAvailable : crAvailable) : (bFlat ? crFlatUnavailable : crUnavailable));
829 // fill the rest (if partStatus is empty)
830 s_StatusBar.FillRange(uEnd + 1, partCount * PARTSIZE - 1, bFlat ? crFlatUnavailable : crUnavailable);
831 s_StatusBar.Draw(dc, barRect.x, barRect.y, bFlat);
833 if (!bFlat) {
834 // Draw black border
835 dc->SetPen( *wxBLACK_PEN );
836 dc->SetBrush( *wxTRANSPARENT_BRUSH );
837 dc->DrawRectangle(rect);
840 dc->SetPen( old_pen );
841 dc->SetBrush( old_brush );
845 /////////////////////////////////////////////////////////////////////////////////////////////
846 void CQueuedView::Initialize( CClientListCtrl* list )
848 list->InsertColumn( 0, _("Username"), wxLIST_FORMAT_LEFT, 150, wxT("U") );
849 list->InsertColumn( 1, _("File"), wxLIST_FORMAT_LEFT, 275, wxT("F") );
850 list->InsertColumn( 2, _("Client Software"), wxLIST_FORMAT_LEFT, 100, wxT("C") );
851 list->InsertColumn( 3, _("File Priority"), wxLIST_FORMAT_LEFT, 110, wxT("p") );
852 list->InsertColumn( 4, _("Rating"), wxLIST_FORMAT_LEFT, 60, wxT("R") );
853 list->InsertColumn( 5, _("Score"), wxLIST_FORMAT_LEFT, 60, wxT("c") );
854 list->InsertColumn( 6, _("Asked"), wxLIST_FORMAT_LEFT, 60, wxT("A") );
855 list->InsertColumn( 7, _("Last Seen"), wxLIST_FORMAT_LEFT, 110, wxT("L") );
856 list->InsertColumn( 8, _("Entered Queue"), wxLIST_FORMAT_LEFT, 110, wxT("Q") );
857 list->InsertColumn( 9, _("Banned"), wxLIST_FORMAT_LEFT, 60, wxT("B") );
858 list->InsertColumn( 10, _("Obtained Parts"), wxLIST_FORMAT_LEFT, 100, wxT("P") );
860 // Insert any existing items on the list
861 const CClientPtrList& uploading = theApp->uploadqueue->GetWaitingList();
862 CClientPtrList::const_iterator it = uploading.begin();
863 for (; it != uploading.end(); ++it) {
864 list->InsertClient( *it, list->GetListView() );
869 wxString CQueuedView::GetOldColumnOrder()
871 return wxT("U,F,C,p,R,c,A,L,Q,B,P");
875 void CQueuedView::DrawCell( CUpDownClient* client, int column, wxDC* dc, const wxRect& rect )
877 wxString buffer;
879 switch ( column ) {
880 // These 3 are the same for both lists
881 case 0:
882 case 1:
883 case 2:
884 CUploadingView::DrawCell( client, column, dc, rect );
885 return;
887 case 3:
888 if ( client->GetUploadFile() ) {
889 buffer = PriorityToStr( client->GetUploadFile()->GetUpPriority(), false );
890 } else {
891 buffer = _("Unknown");
894 break;
896 case 4:
897 buffer = wxString::Format( wxT("%.1f"), (float)client->GetScore(false,false,true) );
898 break;
900 case 5:
901 if ( client->HasLowID() ) {
902 buffer = wxString::Format( wxT("%i %s"), client->GetScore(false), _("LowID") );
903 } else {
904 buffer = wxString::Format(wxT("%i"),client->GetScore(false));
906 break;
908 case 6:
909 buffer = wxString::Format( wxT("%i"), client->GetAskedCount() );
910 break;
912 #ifndef CLIENT_GUI
913 case 7:
914 buffer = CastSecondsToHM((::GetTickCount() - client->GetLastUpRequest())/1000);
915 break;
917 case 8:
918 buffer = CastSecondsToHM((::GetTickCount() - client->GetWaitStartTime())/1000);
919 break;
920 #else
921 case 7:
922 buffer = CastSecondsToHM(client->GetLastUpRequest()/1000);
923 break;
925 case 8:
926 buffer = CastSecondsToHM(client->GetWaitStartTime()/1000);
927 break;
928 #endif
929 case 9:
930 if ( client->IsBanned() ) {
931 buffer = _("Yes");
932 } else {
933 buffer = _("No");
936 break;
938 case 10:
939 if ( client->GetUpPartCount() ) {
940 CUploadingView::DrawStatusBar( client, dc, rect );
943 return;
946 dc->DrawText( buffer, rect.x, rect.y + 3 );
950 int CQueuedView::SortProc(wxUIntPtr item1, wxUIntPtr item2, long sortData)
952 CUpDownClient* client1 = (CUpDownClient*)item1;
953 CUpDownClient* client2 = (CUpDownClient*)item2;
955 // Ascending or decending?
956 int mode = (sortData & CMuleListCtrl::SORT_DES) ? -1 : 1;
958 switch (sortData & CMuleListCtrl::COLUMN_MASK) {
959 // Sort by username
960 case 0: return mode * client1->GetUserName().CmpNoCase( client2->GetUserName() );
962 // Sort by filename
963 case 1: {
964 const CKnownFile* file1 = client1->GetUploadFile();
965 const CKnownFile* file2 = client2->GetUploadFile();
967 if ( file1 && file2 ) {
968 return mode * CmpAny(file1->GetFileName(), file2->GetFileName());
971 // Place files with filenames on top
972 return -mode * CmpAny( file1, file2 );
975 // Sort by client software
976 case 2: return mode * CompareVersions(client1, client2);
978 // Sort by file upload-priority
979 case 3: {
980 const CKnownFile* file1 = client1->GetUploadFile();
981 const CKnownFile* file2 = client2->GetUploadFile();
983 if ( file1 && file2 ) {
984 int8 prioA = file1->GetUpPriority();
985 int8 prioB = file2->GetUpPriority();
987 // Work-around for PR_VERYLOW which has value 4. See KnownFile.h for that stupidity ...
988 return mode * CmpAny( ( prioA != PR_VERYLOW ? prioA : -1 ), ( prioB != PR_VERYLOW ? prioB : -1 ) );
991 // Place files with priorities on top
992 return -mode * CmpAny( file1, file2 );
995 // Sort by rating
996 case 4: return mode * CmpAny( client1->GetScore(false,false,true), client2->GetScore(false,false,true) );
998 // Sort by score
999 case 5: return mode * CmpAny( client1->GetScore(false), client2->GetScore(false) );
1001 // Sort by Asked count
1002 case 6: return mode * CmpAny( client1->GetAskedCount(), client2->GetAskedCount() );
1004 // Sort by Last seen
1005 case 7: return mode * CmpAny( client1->GetLastUpRequest(), client2->GetLastUpRequest() );
1007 // Sort by entered time
1008 case 8: return mode * CmpAny( client1->GetWaitStartTime(), client2->GetWaitStartTime() );
1010 // Sort by banned
1011 case 9: return mode * CmpAny( client1->IsBanned(), client2->IsBanned() );
1013 default: return 0;
1018 /////////////////////////////////////////////////////////////////////////////////////////////
1019 void CClientsView::Initialize( CClientListCtrl* list )
1021 list->InsertColumn( 0, _("Username"), wxLIST_FORMAT_LEFT, 150, wxT("U") );
1022 list->InsertColumn( 1, _("Upload Status"), wxLIST_FORMAT_LEFT, 150, wxT("S") );
1023 list->InsertColumn( 2, _("Transferred Up"), wxLIST_FORMAT_LEFT, 150, wxT("T") );
1024 list->InsertColumn( 3, _("Download Status"), wxLIST_FORMAT_LEFT, 150, wxT("s") );
1025 list->InsertColumn( 4, _("Transferred Down"), wxLIST_FORMAT_LEFT, 150, wxT("t") );
1026 list->InsertColumn( 5, _("Client Software"), wxLIST_FORMAT_LEFT, 150, wxT("C") );
1027 list->InsertColumn( 6, _("Connected"), wxLIST_FORMAT_LEFT, 150, wxT("c") );
1028 list->InsertColumn( 7, _("Userhash"), wxLIST_FORMAT_LEFT, 150, wxT("H") );
1029 list->InsertColumn( 8, _("Encrypted"), wxLIST_FORMAT_LEFT, 100, wxT("E") );
1030 list->InsertColumn( 9, _("Hide shared files"), wxLIST_FORMAT_LEFT, 100, wxT("h") );
1032 const CClientList::IDMap& clist = theApp->clientlist->GetClientList();
1033 CClientList::IDMap::const_iterator it = clist.begin();
1035 for ( ; it != clist.end(); ++it ) {
1036 list->InsertClient( it->second, list->GetListView() );
1041 wxString CClientsView::GetOldColumnOrder()
1043 return wxT("U,S,T,s,t,C,c,H,E,h");
1047 void CClientsView::DrawCell( CUpDownClient* client, int column, wxDC* dc, const wxRect& rect )
1049 wxString buffer;
1051 switch ( column ) {
1052 case 0:
1053 CUploadingView::DrawCell( client, column, dc, rect );
1054 return;
1056 case 1:
1057 CUploadingView::DrawCell( client, 7, dc, rect );
1058 return;
1060 case 2:
1061 buffer = CastItoXBytes( client->GetUploadedTotal() );
1063 break;
1065 case 3:
1066 buffer = DownloadStateToStr( client->GetDownloadState(),
1067 client->IsRemoteQueueFull() );
1068 break;
1070 case 4:
1071 buffer = CastItoXBytes( client->GetDownloadedTotal() );
1072 break;
1074 case 5:
1075 buffer = client->GetClientVerString();
1076 break;
1078 case 6:
1079 if ( client->IsConnected() ) {
1080 buffer = _("Yes");
1081 } else {
1082 buffer = _("No");
1085 break;
1087 case 7:
1088 buffer = client->GetUserHash().Encode();
1089 break;
1091 case 8:
1092 buffer = client->HasObfuscatedConnectionBeenEstablished() ?
1093 _("Yes") : _("No");
1094 break;
1096 case 9:
1097 buffer = client->GetUserName().IsEmpty() ?
1098 wxT("?") :
1099 (client->HasDisabledSharedFiles() ? _("Yes") : _("No"));
1100 break;
1103 dc->DrawText( buffer, rect.x, rect.y + 3 );
1107 int CClientsView::SortProc(wxUIntPtr item1, wxUIntPtr item2, long sortData)
1109 CUpDownClient* client1 = (CUpDownClient*)item1;
1110 CUpDownClient* client2 = (CUpDownClient*)item2;
1112 // Ascending or decending?
1113 int mode = (sortData & CMuleListCtrl::SORT_DES) ? -1 : 1;
1115 switch (sortData & CMuleListCtrl::COLUMN_MASK) {
1116 // Sort by Username
1117 case 0: return mode * client1->GetUserName().CmpNoCase( client2->GetUserName() );
1119 // Sort by Uploading-state
1120 case 1: return mode * CmpAny( client1->GetUploadState(), client2->GetUploadState() );
1122 // Sort by data-uploaded
1123 case 2:
1124 return mode * CmpAny( client1->GetUploadedTotal(), client2->GetUploadedTotal() );
1126 // Sort by Downloading-state
1127 case 3:
1128 if( client1->GetDownloadState() == client2->GetDownloadState() ){
1129 if( client1->IsRemoteQueueFull() && client2->IsRemoteQueueFull() ) {
1130 return mode * 0;
1131 } else if( client1->IsRemoteQueueFull() ) {
1132 return mode * 1;
1133 } else if( client2->IsRemoteQueueFull() ) {
1134 return mode * -1;
1135 } else {
1136 return mode * 0;
1139 return mode * CmpAny( client1->GetDownloadState(), client2->GetDownloadState() );
1141 // Sort by data downloaded
1142 case 4:
1143 return mode * CmpAny( client1->GetDownloadedTotal(), client2->GetDownloadedTotal() );
1145 // Sort by client-software
1146 case 5: return mode * CompareVersions(client1, client2);
1148 // Sort by connection
1149 case 6: return mode * CmpAny( client1->IsConnected(), client2->IsConnected() );
1151 // Sort by user-hash
1152 case 7: return mode * CmpAny( client1->GetUserHash(), client2->GetUserHash() );
1154 // Sort by Obfuscation state
1155 case 8: return mode * CmpAny( client2->HasObfuscatedConnectionBeenEstablished(), client1->HasObfuscatedConnectionBeenEstablished() );
1157 // Sort by Shared Files DISabled
1158 case 9: return mode * CmpAny( client2->HasDisabledSharedFiles(), client1->HasDisabledSharedFiles() );
1160 default:
1161 return 0;
1165 // File_checked_for_headers