2 // This file is part of the aMule Project.
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 )
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
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.
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>
33 #include "BarShader.h" // Needed for CBarShader
35 #include "ClientDetailDialog.h"
36 #include "ClientList.h"
38 #include "DataToText.h"
39 #ifdef ENABLE_IP2COUNTRY
40 #include "IP2Country.h" // Needed for IP2Country
42 #include "KnownFile.h"
43 #include "Preferences.h"
44 #include "updownclient.h"
45 #include "UploadQueue.h"
48 #include <wx/textdlg.h>
50 #include <wx/settings.h>
52 ////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////
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
)
86 #define m_imagelist theApp->amuledlg->m_imagelist
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
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.
101 //! The name of the view, this is used to load and save column-preferences.
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.
126 //! Uploading: The clients currently being uploaded to.
129 CUploadingView::Initialize
,
130 CUploadingView::DrawCell
,
131 CUploadingView::SortProc
,
134 //! Queued: The clients currently queued for uploading.
137 CQueuedView::Initialize
,
138 CQueuedView::DrawCell
,
139 CQueuedView::SortProc
,
142 //! Clients The complete list of all known 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
)
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()
186 void CClientListCtrl::SetListView( ViewType newView
)
188 if ( m_viewType
!= newView
) {
189 if (m_viewType
!= vtNone
) {
194 m_viewType
= newView
;
196 const ClientListView
& view
= g_listViews
[ (int)newView
];
198 // Initialize the selected view
203 SetTableName( view
.m_title
);
204 SetSortFunc( view
.m_sort
);
206 if (newView
!= vtNone
) {
213 void CClientListCtrl::ToggleView()
215 // Disallow toggling if the list is disabled
216 if ( m_viewType
== vtNone
) {
220 unsigned int view
= (int)m_viewType
+ 1;
222 if ( view
< itemsof(g_listViews
) ) {
223 SetListView( (ViewType
)(view
) );
225 SetListView( (ViewType
)(1) );
230 /////////////////////////////////////////////////////////////////////////////////////////////
231 void CClientListCtrl::OnRightClick(wxMouseEvent
& event
)
233 long index
= CheckSelection(event
);
235 if ( m_menu
== NULL
) {
238 bool validIP
= false;
239 bool isfriend
= false;
240 bool hasdisabledsharedfiles
= false;
242 // Check if the client is banned
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() );
287 void CClientListCtrl::OnMiddleClick(wxListEvent
& event
)
289 long index
= CheckSelection(event
);
292 CUpDownClient
*client
= reinterpret_cast<CUpDownClient
*>(GetItemData( index
));
294 CClientDetailDialog
dialog(this, client
);
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());
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
);
330 CUpDownClient
*client
= reinterpret_cast<CUpDownClient
*>(GetItemData( index
));
331 CClientDetailDialog
dialog(this, client
);
337 void CClientListCtrl::OnViewFiles( wxCommandEvent
& WXUNUSED(event
) )
339 long index
= GetNextItem( -1, wxLIST_NEXT_ALL
, wxLIST_STATE_SELECTED
);
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
);
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
);
374 CUpDownClient
*client
= reinterpret_cast<CUpDownClient
*>(GetItemData( index
));
375 if ( client
->IsBanned() ) {
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
) ) {
390 long index
= InsertItem( GetItemCount(), wxEmptyString
);
391 SetItemPtrData( index
, reinterpret_cast<wxUIntPtr
>(client
) );
394 myitem
.SetId( index
);
395 myitem
.SetBackgroundColour( SYSCOLOR(wxSYS_COLOUR_LISTBOX
) );
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
) ) {
411 long index
= FindItem( -1, reinterpret_cast<wxUIntPtr
>(client
) );
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
) ) {
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
) );
433 GetVisibleLines( &first
, &last
);
435 if ( result
>= first
&& result
<= last
) {
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
) ) {
452 dc
->SetBackground(*m_hilightBrush
);
453 dc
->SetTextForeground( SYSCOLOR(wxSYS_COLOUR_HIGHLIGHTTEXT
) );
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
) );
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
;
475 const ClientListView
& view
= g_listViews
[ (int)m_viewType
];
478 for ( int i
= 0; i
< GetColumnCount(); i
++ ) {
479 int width
= GetColumnWidth( i
);
481 cur_rect
.width
= width
- 8;
483 wxDCClipper
clipper( *dc
, cur_rect
);
485 view
.m_draw( client
, i
, dc
, cur_rect
);
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
)
533 if ( client
->IsFriend() ) {
534 clientImage
= Client_Friend_Smiley
;
536 switch (client
->GetClientSoft()) {
538 clientImage
= Client_aMule_Smiley
;
541 case SO_NEW_MLDONKEY
:
542 case SO_NEW2_MLDONKEY
:
543 clientImage
= Client_mlDonkey_Smiley
;
546 case SO_EDONKEYHYBRID
:
547 // Maybe we would like to make different icons?
548 clientImage
= Client_eDonkeyHybrid_Smiley
;
551 clientImage
= Client_eMule_Smiley
;
554 clientImage
= Client_lphant_Smiley
;
557 case SO_NEW_SHAREAZA
:
558 case SO_NEW2_SHAREAZA
:
559 clientImage
= Client_Shareaza_Smiley
;
562 clientImage
= Client_xMule_Smiley
;
565 // cDonkey, Compat Unk
566 // No icon for those yet. Using the eMule one + '?'
567 clientImage
= Client_Unknown
;
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()) {
587 m_imagelist
.Draw(Client_SecIdent_Smiley
, *dc
, rect
.x
, rect
.y
+ 1,
588 wxIMAGELIST_DRAW_TRANSPARENT
);
589 } else if (client
->IsBadGuy()) {
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
);
602 #ifdef ENABLE_IP2COUNTRY
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);
619 if ( client
->GetUploadFile() ) {
620 buffer
= client
->GetUploadFile()->GetFileName().GetPrintable();
627 buffer
= client
->GetClientVerString();
631 buffer
= wxString::Format( wxT("%.1f"), client
->GetUploadDatarate() / 1024.0f
);
638 buffer
= CastItoXBytes(client
->GetSessionUp());
642 buffer
= CastSecondsToHM((client
->GetWaitTime())/1000);
646 buffer
= CastSecondsToHM((client
->GetUpStartTimeDelay())/1000);
650 switch ( client
->GetUploadState() ) {
652 buffer
= _("Connecting");
655 case US_WAITCALLBACK
:
656 buffer
= _("Connecting via server");
660 buffer
= wxT("<-- ");
661 buffer
.Append(_("Transferring"));
663 if (client
->GetDownloadState() == DS_DOWNLOADING
) {
664 buffer
.Append(wxT(" -->"));
668 case US_ONUPLOADQUEUE
:
669 buffer
= _("On Queue");
673 buffer
= _("Unknown");
678 if ( client
->GetUpPartCount() ) {
679 CUploadingView::DrawStatusBar( client
, dc
, rect
);
684 buffer
= CastItoXBytes( client
->GetUploadedTotal() ) +
685 wxT(" / ") + CastItoXBytes(client
->GetDownloadedTotal());
689 if ( client
->GetDownloadState() == DS_ONQUEUE
) {
690 if ( client
->IsRemoteQueueFull() ) {
691 buffer
= _("Queue Full");
693 if (client
->GetRemoteQueueRank()) {
694 buffer
= wxString::Format(_("QR: %u"), client
->GetRemoteQueueRank());
696 buffer
= _("Unknown");
699 } else if ( client
->GetDownloadState() == DS_DOWNLOADING
) {
700 buffer
+= wxString::Format( wxT("%.1f"), client
->GetKBpsDown() );
704 buffer
= _("Unknown");
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
) {
723 case 0: return mode
* client1
->GetUserName().CmpNoCase( client2
->GetUserName() );
726 // Sort by requested file
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
);
742 case 3: return mode
* CmpAny( client1
->GetUploadDatarate(), client2
->GetUploadDatarate() );
744 // Sort by transferred
745 case 4: return mode
* CmpAny( client1
->GetSessionUp(), client2
->GetSessionUp() );
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() );
754 case 7: return mode
* CmpAny( client1
->GetUploadState(), client2
->GetUploadState() );
757 case 8: return mode
* CmpAny( client1
->GetUpPartCount(), client2
->GetUpPartCount() );
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() );
771 void CUploadingView::DrawStatusBar( CUpDownClient
* client
, wxDC
* dc
, const wxRect
& rect1
)
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
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() );
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
);
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
)
856 // These 3 are the same for both lists
860 CUploadingView::DrawCell( client
, column
, dc
, rect
);
864 if ( client
->GetUploadFile() ) {
865 buffer
= PriorityToStr( client
->GetUploadFile()->GetUpPriority(), false );
867 buffer
= _("Unknown");
873 buffer
= wxString::Format( wxT("%.1f"), (float)client
->GetScore(false,false,true) );
877 if ( client
->HasLowID() ) {
878 buffer
= wxString::Format( wxT("%i %s"), client
->GetScore(false), _("LowID") );
880 buffer
= wxString::Format(wxT("%i"),client
->GetScore(false));
885 buffer
= wxString::Format( wxT("%i"), client
->GetAskedCount() );
890 buffer
= CastSecondsToHM((::GetTickCount() - client
->GetLastUpRequest())/1000);
894 buffer
= CastSecondsToHM((::GetTickCount() - client
->GetWaitStartTime())/1000);
898 buffer
= CastSecondsToHM(client
->GetLastUpRequest()/1000);
902 buffer
= CastSecondsToHM(client
->GetWaitStartTime()/1000);
906 if ( client
->IsBanned() ) {
915 if ( client
->GetUpPartCount() ) {
916 CUploadingView::DrawStatusBar( client
, dc
, rect
);
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
) {
936 case 0: return mode
* client1
->GetUserName().CmpNoCase( client2
->GetUserName() );
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
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
);
972 case 4: return mode
* CmpAny( client1
->GetScore(false,false,true), client2
->GetScore(false,false,true) );
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() );
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() );
987 case 9: return mode
* CmpAny( client1
->IsBanned(), client2
->IsBanned() );
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
)
1023 CUploadingView::DrawCell( client
, column
, dc
, rect
);
1027 CUploadingView::DrawCell( client
, 7, dc
, rect
);
1031 buffer
= CastItoXBytes( client
->GetUploadedTotal() );
1036 buffer
= DownloadStateToStr( client
->GetDownloadState(),
1037 client
->IsRemoteQueueFull() );
1041 buffer
= CastItoXBytes( client
->GetDownloadedTotal() );
1045 buffer
= client
->GetClientVerString();
1049 if ( client
->IsConnected() ) {
1058 buffer
= client
->GetUserHash().Encode();
1062 buffer
= client
->HasObfuscatedConnectionBeenEstablished() ?
1067 buffer
= client
->GetUserName().IsEmpty() ?
1069 (client
->HasDisabledSharedFiles() ? _("Yes") : _("No"));
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
) {
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
1094 return mode
* CmpAny( client1
->GetUploadedTotal(), client2
->GetUploadedTotal() );
1096 // Sort by Downloading-state
1098 if( client1
->GetDownloadState() == client2
->GetDownloadState() ){
1099 if( client1
->IsRemoteQueueFull() && client2
->IsRemoteQueueFull() ) {
1101 } else if( client1
->IsRemoteQueueFull() ) {
1103 } else if( client2
->IsRemoteQueueFull() ) {
1109 return mode
* CmpAny( client1
->GetDownloadState(), client2
->GetDownloadState() );
1111 // Sort by data downloaded
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() );
1135 // File_checked_for_headers