1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
10 //
11 // 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.
15 //
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
24 //
25 
26 #include "ServerListCtrl.h"	// Interface declarations
27 
28 #include <common/MenuIDs.h>
29 
30 #include <wx/menu.h>
31 #include <wx/stattext.h>
32 #include <wx/msgdlg.h>
33 #include <wx/settings.h>
34 
35 #include "amule.h"		// Needed for theApp
36 #include "DownloadQueue.h"	// Needed for CDownloadQueue
37 #ifdef ENABLE_IP2COUNTRY
38 	#include "IP2Country.h"	// Needed for IP2Country
39 	#include "amuleDlg.h"	// Needed for IP2Country
40 #endif
41 #include "ServerList.h"		// Needed for CServerList
42 #include "ServerConnect.h"	// Needed for CServerConnect
43 #include "Server.h"		// Needed for CServer and SRV_PR_*
44 #include "Logger.h"
45 #include <common/Format.h>	// Needed for CFormat
46 #include "Preferences.h"	// Needed for thePrefs
47 
48 
49 #define CMuleColour(x) (wxSystemSettings::GetColour(x))
50 
51 
BEGIN_EVENT_TABLE(CServerListCtrl,CMuleListCtrl)52 BEGIN_EVENT_TABLE(CServerListCtrl,CMuleListCtrl)
53 	EVT_LIST_ITEM_RIGHT_CLICK( -1,	CServerListCtrl::OnItemRightClicked)
54 	EVT_LIST_ITEM_ACTIVATED( -1,	CServerListCtrl::OnItemActivated )
55 
56 	EVT_MENU( MP_PRIOLOW,			CServerListCtrl::OnPriorityChange )
57 	EVT_MENU( MP_PRIONORMAL,		CServerListCtrl::OnPriorityChange )
58 	EVT_MENU( MP_PRIOHIGH,			CServerListCtrl::OnPriorityChange )
59 
60 	EVT_MENU( MP_ADDTOSTATIC,		CServerListCtrl::OnStaticChange )
61 	EVT_MENU( MP_REMOVEFROMSTATIC,	CServerListCtrl::OnStaticChange )
62 
63 	EVT_MENU( MP_CONNECTTO,			CServerListCtrl::OnConnectToServer )
64 
65 	EVT_MENU( MP_REMOVE,			CServerListCtrl::OnRemoveServers )
66 	EVT_MENU( MP_REMOVEALL,			CServerListCtrl::OnRemoveServers )
67 
68 	EVT_MENU( MP_GETED2KLINK,		CServerListCtrl::OnGetED2kURL )
69 
70 	EVT_CHAR( CServerListCtrl::OnKeyPressed )
71 END_EVENT_TABLE()
72 
73 
74 
75 CServerListCtrl::CServerListCtrl( wxWindow *parent, wxWindowID winid, const wxPoint& pos, const wxSize& size,
76                                   long style, const wxValidator& validator, const wxString& name )
77 	: CMuleListCtrl( parent, winid, pos, size, style, validator, name )
78 {
79 	// Setting the sorter function.
80 	SetSortFunc( SortProc );
81 
82 	// Set the table-name (for loading and saving preferences).
83 	SetTableName( wxT("Server") );
84 
85 	m_connected = 0;
86 
87 	InsertColumn( COLUMN_SERVER_NAME,	_("Server Name"),	wxLIST_FORMAT_LEFT, 150, wxT("N") );
88 	InsertColumn( COLUMN_SERVER_ADDR,	_("Address"),		wxLIST_FORMAT_LEFT, 140, wxT("A") );
89 	InsertColumn( COLUMN_SERVER_PORT,	_("Port"),		wxLIST_FORMAT_LEFT,  25, wxT("P") );
90 	InsertColumn( COLUMN_SERVER_DESC,	_("Description"),	wxLIST_FORMAT_LEFT, 150, wxT("D") );
91 	InsertColumn( COLUMN_SERVER_PING,	_("Ping"),		wxLIST_FORMAT_LEFT,  25, wxT("p") );
92 	InsertColumn( COLUMN_SERVER_USERS,	_("Users"),		wxLIST_FORMAT_LEFT,  40, wxT("U") );
93 	InsertColumn( COLUMN_SERVER_FILES,	_("Files"),		wxLIST_FORMAT_LEFT,  45, wxT("F") );
94 	InsertColumn( COLUMN_SERVER_PRIO,	_("Priority"),		wxLIST_FORMAT_LEFT,  60, wxT("r") );
95 	InsertColumn( COLUMN_SERVER_FAILS,	_("Failed"),		wxLIST_FORMAT_LEFT,  40, wxT("f") );
96 	InsertColumn( COLUMN_SERVER_STATIC,	_("Static"),		wxLIST_FORMAT_LEFT,  40, wxT("S") );
97 	InsertColumn( COLUMN_SERVER_VERSION,	_("Version"),		wxLIST_FORMAT_LEFT,  80, wxT("V") );
98 	#ifdef __DEBUG__
99 	InsertColumn( COLUMN_SERVER_TCPFLAGS,	wxT("TCP Flags"),	wxLIST_FORMAT_LEFT,  80, wxT("t") );
100 	InsertColumn( COLUMN_SERVER_UDPFLAGS,	wxT("UDP Flags"),	wxLIST_FORMAT_LEFT,  80, wxT("u") );
101 	#endif
102 
103 
104 	LoadSettings();
105 }
106 
107 
GetOldColumnOrder() const108 wxString CServerListCtrl::GetOldColumnOrder() const
109 {
110 	return wxT("N,A,P,D,p,U,F,r,f,S,V,t,u");
111 }
112 
113 
~CServerListCtrl()114 CServerListCtrl::~CServerListCtrl()
115 {
116 }
117 
118 
AddServer(CServer * toadd)119 void CServerListCtrl::AddServer( CServer* toadd )
120 {
121 	// RefreshServer will add the server.
122 	// This also means that we have simple duplicity checking. ;)
123 	RefreshServer( toadd );
124 
125 	ShowServerCount();
126 }
127 
128 
RemoveServer(CServer * server)129 void CServerListCtrl::RemoveServer(CServer* server)
130 {
131 	long result = FindItem(-1, reinterpret_cast<wxUIntPtr>(server));
132 	if ( result != -1 ) {
133 		DeleteItem(result);
134 		ShowServerCount();
135 	}
136 }
137 
138 
RemoveAllServers(int state)139 void CServerListCtrl::RemoveAllServers(int state)
140 {
141 	int pos = GetNextItem( -1, wxLIST_NEXT_ALL, state);
142 	bool connected = theApp->IsConnectedED2K() ||
143 	  theApp->serverconnect->IsConnecting();
144 
145 	while ( pos != -1 ) {
146 		CServer* server = reinterpret_cast<CServer*>(GetItemData(pos));
147 
148 		if (server == m_connected && connected) {
149 			wxMessageBox(_("You are connected to a server you are trying to delete. Please disconnect first. The server was NOT deleted."), _("Info"), wxOK, this);
150 			++pos;
151 		} else if (server->IsStaticMember()) {
152 			const wxString name = (!server->GetListName() ? wxString(_("(Unknown name)")) : server->GetListName());
153 
154 			if (wxMessageBox(CFormat(_("Are you sure you want to delete the static server %s")) % name, _("Cancel"), wxICON_QUESTION | wxYES_NO, this) == wxYES) {
155 				theApp->serverlist->SetStaticServer(server, false);
156 				DeleteItem( pos );
157 				theApp->serverlist->RemoveServer( server );
158 			} else {
159 				++pos;
160 			}
161 		} else {
162 			DeleteItem( pos );
163 			theApp->serverlist->RemoveServer( server );
164 		}
165 
166 		pos = GetNextItem(pos - 1, wxLIST_NEXT_ALL, state);
167 	}
168 
169 	ShowServerCount();
170 }
171 
172 
RefreshServer(CServer * server)173 void CServerListCtrl::RefreshServer( CServer* server )
174 {
175 	// Cant really refresh a NULL server
176 	if (!server) {
177 		return;
178 	}
179 
180 	wxUIntPtr ptr = reinterpret_cast<wxUIntPtr>(server);
181 	long itemnr = FindItem( -1, ptr );
182 	if ( itemnr == -1 ) {
183 		// We are not at the sure that the server isn't in the list, so we can re-add
184 		itemnr = InsertItem( GetInsertPos( ptr ), server->GetListName() );
185 		SetItemPtrData( itemnr, ptr );
186 
187 		wxListItem item;
188 		item.SetId( itemnr );
189 		item.SetBackgroundColour(CMuleColour(wxSYS_COLOUR_LISTBOX));
190 		SetItem( item );
191 	}
192 
193 	wxString serverName;
194 #ifdef ENABLE_IP2COUNTRY
195 	// Get the country name
196 	if (theApp->amuledlg->m_IP2Country->IsEnabled() && thePrefs::IsGeoIPEnabled()) {
197 		const CountryData& countrydata = theApp->amuledlg->m_IP2Country->GetCountryData(server->GetFullIP());
198 		serverName << countrydata.Name;
199 		serverName << wxT(" - ");
200 	}
201 #endif // ENABLE_IP2COUNTRY
202 	serverName << server->GetListName();
203 	SetItem(itemnr, COLUMN_SERVER_NAME, serverName);
204 	SetItem(itemnr, COLUMN_SERVER_ADDR, server->GetAddress());
205 	if (server->GetAuxPortsList().IsEmpty()) {
206 		SetItem( itemnr, COLUMN_SERVER_PORT,
207 			CFormat(wxT("%u")) % server->GetPort());
208 	} else {
209 		SetItem( itemnr, COLUMN_SERVER_PORT,
210 			CFormat(wxT("%u (%s)")) % server->GetPort() % server->GetAuxPortsList());
211 	}
212 	SetItem( itemnr, COLUMN_SERVER_DESC, server->GetDescription() );
213 
214 	if ( server->GetPing() ) {
215 		SetItem( itemnr, COLUMN_SERVER_PING,
216 			CastSecondsToHM(server->GetPing()/1000, server->GetPing() % 1000 ) );
217 	} else {
218 		SetItem( itemnr, COLUMN_SERVER_PING, wxEmptyString );
219 	}
220 
221 	if ( server->GetUsers() ) {
222 		SetItem( itemnr, COLUMN_SERVER_USERS,
223 			CFormat(wxT("%u")) % server->GetUsers());
224 	} else {
225 		SetItem( itemnr, COLUMN_SERVER_USERS, wxEmptyString );
226 	}
227 
228 	if ( server->GetFiles() ) {
229 		SetItem( itemnr, COLUMN_SERVER_FILES,
230 			CFormat(wxT("%u")) % server->GetFiles());
231 	} else {
232 		SetItem( itemnr, COLUMN_SERVER_FILES, wxEmptyString );
233 	}
234 
235 	switch ( server->GetPreferences() ) {
236 		case SRV_PR_LOW:	SetItem(itemnr, COLUMN_SERVER_PRIO, _("Low"));		break;
237 		case SRV_PR_NORMAL:	SetItem(itemnr, COLUMN_SERVER_PRIO, _("Normal"));	break;
238 		case SRV_PR_HIGH:	SetItem(itemnr, COLUMN_SERVER_PRIO, _("High") );	break;
239 		default:		SetItem(itemnr, COLUMN_SERVER_PRIO, wxT("---"));	// this should never happen
240 	}
241 
242 	SetItem( itemnr, COLUMN_SERVER_FAILS, CFormat(wxT("%u")) % server->GetFailedCount());
243 	SetItem( itemnr, COLUMN_SERVER_STATIC, ( server->IsStaticMember() ? _("Yes") : _("No") ) );
244 	SetItem( itemnr, COLUMN_SERVER_VERSION, server->GetVersion() );
245 
246 	#if defined(__DEBUG__) && !defined(CLIENT_GUI)
247 	wxString flags;
248 	/* TCP */
249 	if (server->GetTCPFlags() & SRV_TCPFLG_COMPRESSION) {
250 		flags += wxT("c");
251 	}
252 	if (server->GetTCPFlags() & SRV_TCPFLG_NEWTAGS) {
253 		flags += wxT("n");
254 	}
255 	if (server->GetTCPFlags() & SRV_TCPFLG_UNICODE) {
256 		flags += wxT("u");
257 	}
258 	if (server->GetTCPFlags() & SRV_TCPFLG_RELATEDSEARCH) {
259 		flags += wxT("r");
260 	}
261 	if (server->GetTCPFlags() & SRV_TCPFLG_TYPETAGINTEGER) {
262 		flags += wxT("t");
263 	}
264 	if (server->GetTCPFlags() & SRV_TCPFLG_LARGEFILES) {
265 		flags += wxT("l");
266 	}
267 	if (server->GetTCPFlags() & SRV_TCPFLG_TCPOBFUSCATION) {
268 		flags += wxT("o");
269 	}
270 
271 	SetItem( itemnr, COLUMN_SERVER_TCPFLAGS, flags );
272 
273 	/* UDP */
274 	flags.Clear();
275 	if (server->GetUDPFlags() & SRV_UDPFLG_EXT_GETSOURCES) {
276 		flags += wxT("g");
277 	}
278 	if (server->GetUDPFlags() & SRV_UDPFLG_EXT_GETFILES) {
279 		flags += wxT("f");
280 	}
281 	if (server->GetUDPFlags() & SRV_UDPFLG_NEWTAGS) {
282 		flags += wxT("n");
283 	}
284 	if (server->GetUDPFlags() & SRV_UDPFLG_UNICODE) {
285 		flags += wxT("u");
286 	}
287 	if (server->GetUDPFlags() & SRV_UDPFLG_EXT_GETSOURCES2) {
288 		flags += wxT("G");
289 	}
290 	if (server->GetUDPFlags() & SRV_UDPFLG_LARGEFILES) {
291 		flags += wxT("l");
292 	}
293 	if (server->GetUDPFlags() & SRV_UDPFLG_UDPOBFUSCATION) {
294 		flags += wxT("o");
295 	}
296 	if (server->GetUDPFlags() & SRV_UDPFLG_TCPOBFUSCATION) {
297 		flags += wxT("O");
298 	}
299 	SetItem( itemnr, COLUMN_SERVER_UDPFLAGS, flags );
300 
301 	#endif
302 
303 	// Deletions of items causes rather large ammount of flicker, so to
304 	// avoid this, we resort the list to ensure correct ordering.
305 	if (!IsItemSorted(itemnr)) {
306 		SortList();
307 	}
308 }
309 
310 
HighlightServer(const CServer * server,bool highlight)311 void CServerListCtrl::HighlightServer( const CServer* server, bool highlight )
312 {
313 	// Unset the old highlighted server if we are going to set a new one
314 	if ( m_connected && highlight ) {
315 		// A recursive call to do the real work.
316 		HighlightServer( m_connected, false );
317 
318 		m_connected = 0;
319 	}
320 
321 	long itemnr = FindItem( -1,  reinterpret_cast<wxUIntPtr>(server) );
322 	if ( itemnr > -1 ) {
323 		wxListItem item;
324 		item.SetId( itemnr );
325 
326 		if ( GetItem( item ) ) {
327 			wxFont font = GetFont();
328 
329 			if ( highlight ) {
330 				font.SetWeight( wxBOLD );
331 
332 				m_connected = server;
333 			}
334 
335 			item.SetFont( font );
336 
337 			SetItem( item );
338 		}
339 	}
340 }
341 
342 
ShowServerCount()343 void CServerListCtrl::ShowServerCount()
344 {
345 	wxStaticText* label = CastByName( wxT("serverListLabel"), GetParent(), wxStaticText );
346 
347 	if ( label ) {
348 		label->SetLabel(CFormat(_("Servers (%i)")) % GetItemCount());
349 		label->GetParent()->Layout();
350 	}
351 }
352 
353 
OnItemActivated(wxListEvent & event)354 void CServerListCtrl::OnItemActivated( wxListEvent& event )
355 {
356 	// Unselect all items but the activated one
357 	long item = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
358 	while ( item > -1 ) {
359 		SetItemState( item, 0, wxLIST_STATE_SELECTED);
360 
361 		item = GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
362 	}
363 
364 	SetItemState( event.GetIndex(), wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
365 
366 	wxCommandEvent nulEvt;
367 	OnConnectToServer( nulEvt );
368 }
369 
370 
OnItemRightClicked(wxListEvent & event)371 void CServerListCtrl::OnItemRightClicked(wxListEvent& event)
372 {
373 	// Check if clicked item is selected. If not, unselect all and select it.
374 	long index = CheckSelection(event);
375 
376 	bool enable_reconnect = false;
377 	bool enable_static_on = false;
378 	bool enable_static_off = false;
379 
380 	// Gather information on the selected items
381 	while ( index > -1 ) {
382 		CServer* server = reinterpret_cast<CServer*>(GetItemData(index));
383 
384 		// The current server is selected, so we might display the reconnect option
385 		if (server == m_connected) {
386 			enable_reconnect = true;
387 		}
388 
389 		// We want to know which options should be enabled, either one or both
390 		enable_static_on	|= !server->IsStaticMember();
391 		enable_static_off	|=  server->IsStaticMember();
392 
393 		index = GetNextItem( index, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
394 	}
395 
396 
397 	wxMenu* serverMenu = new wxMenu(_("Server"));
398 	wxMenu* serverPrioMenu = new wxMenu();
399 	serverPrioMenu->Append( MP_PRIOLOW, _("Low") );
400 	serverPrioMenu->Append( MP_PRIONORMAL, _("Normal") );
401 	serverPrioMenu->Append( MP_PRIOHIGH, _("High") );
402 	serverMenu->Append( MP_CONNECTTO, _("Connect to server") );
403 	serverMenu->Append( 12345, _("Priority"), serverPrioMenu );
404 
405 	serverMenu->AppendSeparator();
406 
407 	if (GetSelectedItemCount() == 1) {
408 		serverMenu->Append( MP_ADDTOSTATIC, _("Mark server as static") );
409 		serverMenu->Append( MP_REMOVEFROMSTATIC, _("Mark server as non-static") );
410 	} else {
411 		serverMenu->Append( MP_ADDTOSTATIC, _("Mark servers as static") );
412 		serverMenu->Append( MP_REMOVEFROMSTATIC, _("Mark servers as non-static") );
413 	}
414 
415 	serverMenu->AppendSeparator();
416 
417 	if (GetSelectedItemCount() == 1) {
418 		serverMenu->Append( MP_REMOVE, _("Remove server") );
419 	} else {
420 		serverMenu->Append( MP_REMOVE, _("Remove servers") );
421 	}
422 	serverMenu->Append( MP_REMOVEALL, _("Remove all servers") );
423 
424 	serverMenu->AppendSeparator();
425 
426 	if (GetSelectedItemCount() == 1) {
427 		serverMenu->Append( MP_GETED2KLINK, _("Copy eD2k link to clipboard") );
428 	} else {
429 		serverMenu->Append( MP_GETED2KLINK, _("Copy eD2k links to clipboard") );
430 	}
431 
432 	serverMenu->Enable( MP_REMOVEFROMSTATIC,	enable_static_off );
433 	serverMenu->Enable( MP_ADDTOSTATIC,			enable_static_on  );
434 
435 	if ( GetSelectedItemCount() == 1 ) {
436 		if ( enable_reconnect )
437 			serverMenu->SetLabel( MP_CONNECTTO, _("Reconnect to server") );
438 	} else {
439 		serverMenu->Enable( MP_CONNECTTO, false );
440 	}
441 
442 
443 	PopupMenu( serverMenu, event.GetPoint() );
444 	delete serverMenu;
445 }
446 
447 
OnPriorityChange(wxCommandEvent & event)448 void CServerListCtrl::OnPriorityChange( wxCommandEvent& event )
449 {
450 	uint32 priority = 0;
451 
452 	switch ( event.GetId() ) {
453 		case MP_PRIOLOW:		priority = SRV_PR_LOW;		break;
454 		case MP_PRIONORMAL:		priority = SRV_PR_NORMAL;	break;
455 		case MP_PRIOHIGH:		priority = SRV_PR_HIGH;		break;
456 
457 		default:
458 			return;
459 	}
460 
461 
462 	ItemDataList items = GetSelectedItems();
463 
464 	for ( unsigned int i = 0; i < items.size(); ++i ) {
465 		CServer* server = reinterpret_cast<CServer*>(items[i]);
466 		theApp->serverlist->SetServerPrio(server, priority);
467 	}
468 }
469 
470 
OnStaticChange(wxCommandEvent & event)471 void CServerListCtrl::OnStaticChange( wxCommandEvent& event )
472 {
473 	bool isStatic = ( event.GetId() == MP_ADDTOSTATIC );
474 
475 	ItemDataList items = GetSelectedItems();
476 
477 	for ( unsigned int i = 0; i < items.size(); ++i ) {
478 		CServer* server = reinterpret_cast<CServer*>(items[i]);
479 
480 		// Only update items that have the wrong setting
481 		if ( server->IsStaticMember() != isStatic ) {
482 			theApp->serverlist->SetStaticServer(server, isStatic);
483 		}
484 	}
485 }
486 
487 
OnConnectToServer(wxCommandEvent & WXUNUSED (event))488 void CServerListCtrl::OnConnectToServer( wxCommandEvent& WXUNUSED(event) )
489 {
490 	int item = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
491 
492 	if ( item > -1 ) {
493 		if ( theApp->IsConnectedED2K() ) {
494 			theApp->serverconnect->Disconnect();
495 		}
496 
497 		theApp->serverconnect->ConnectToServer( reinterpret_cast<CServer*>(GetItemData(item)) );
498 	}
499 }
500 
501 
OnGetED2kURL(wxCommandEvent & WXUNUSED (event))502 void CServerListCtrl::OnGetED2kURL( wxCommandEvent& WXUNUSED(event) )
503 {
504 	int pos = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
505 
506 	wxString URL;
507 
508 	while ( pos != -1 ) {
509 		CServer* server = reinterpret_cast<CServer*>(GetItemData(pos));
510 
511 		URL += CFormat(wxT("ed2k://|server|%s|%d|/\n"))	% server->GetFullIP() % server->GetPort();
512 
513 		pos = GetNextItem( pos, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
514 	}
515 
516 	URL.RemoveLast();
517 
518 	theApp->CopyTextToClipboard( URL );
519 }
520 
521 
OnRemoveServers(wxCommandEvent & event)522 void CServerListCtrl::OnRemoveServers( wxCommandEvent& event )
523 {
524 	if ( event.GetId() == MP_REMOVEALL ) {
525 		if ( GetItemCount() ) {
526 			wxString question = _("Are you sure that you wish to delete all servers?");
527 
528 			if ( wxMessageBox( question, _("Cancel"), wxICON_QUESTION | wxYES_NO, this) == wxYES ) {
529 				if ( theApp->serverconnect->IsConnecting() ) {
530 					theApp->downloadqueue->StopUDPRequests();
531 					theApp->serverconnect->StopConnectionTry();
532 					theApp->serverconnect->Disconnect();
533 				}
534 
535 				RemoveAllServers(wxLIST_STATE_DONTCARE);
536 			}
537 		}
538 	} else if ( event.GetId() == MP_REMOVE ) {
539 		if ( GetSelectedItemCount() ) {
540 			wxString question;
541 			if (GetSelectedItemCount() == 1) {
542 				question = _("Are you sure that you wish to delete the selected server?");
543 			} else {
544 				question = _("Are you sure that you wish to delete the selected servers?");
545 			}
546 
547 			if ( wxMessageBox( question, _("Cancel"), wxICON_QUESTION | wxYES_NO, this) == wxYES ) {
548 				RemoveAllServers(wxLIST_STATE_SELECTED);
549 			}
550 		}
551 	}
552 }
553 
554 
OnKeyPressed(wxKeyEvent & event)555 void CServerListCtrl::OnKeyPressed( wxKeyEvent& event )
556 {
557 	// Check if delete was pressed
558 	if ((event.GetKeyCode() == WXK_DELETE) || (event.GetKeyCode() == WXK_NUMPAD_DELETE)) {
559 		wxCommandEvent evt;
560 		evt.SetId( MP_REMOVE );
561 		OnRemoveServers( evt );
562 	} else {
563 		event.Skip();
564 	}
565 }
566 
567 
SortProc(wxUIntPtr item1,wxUIntPtr item2,long sortData)568 int CServerListCtrl::SortProc(wxUIntPtr item1, wxUIntPtr item2, long sortData)
569 {
570 	CServer* server1 = reinterpret_cast<CServer*>(item1);
571 	CServer* server2 = reinterpret_cast<CServer*>(item2);
572 
573 	int mode = (sortData & CMuleListCtrl::SORT_DES) ? -1 : 1;
574 
575 	switch (sortData & CMuleListCtrl::COLUMN_MASK) {
576 		// Sort by server-name
577 		case COLUMN_SERVER_NAME:
578 			return mode * server1->GetListName().CmpNoCase(server2->GetListName());
579 
580 		// Sort by address
581 		case COLUMN_SERVER_ADDR:
582 			{
583 				if ( server1->HasDynIP() && server2->HasDynIP()) {
584 					return mode * server1->GetDynIP().CmpNoCase( server2->GetDynIP() );
585 				} else if (server1->HasDynIP()) {
586 					return mode * -1;
587 				} else if (server2->HasDynIP()) {
588 					return mode * 1;
589 				} else {
590 					uint32 a = wxUINT32_SWAP_ALWAYS(server1->GetIP());
591 					uint32 b = wxUINT32_SWAP_ALWAYS(server2->GetIP());
592 					return mode * CmpAny(a, b);
593 				}
594 			}
595 		// Sort by port
596 		case COLUMN_SERVER_PORT: return mode * CmpAny( server1->GetPort(), server2->GetPort() );
597 		// Sort by description
598 		case COLUMN_SERVER_DESC: return mode * server1->GetDescription().CmpNoCase( server2->GetDescription() );
599 		// Sort by Ping
600 		// The -1 ensures that a value of zero (no ping known) is sorted last.
601 		case COLUMN_SERVER_PING: return mode * CmpAny( server1->GetPing() - 1, server2->GetPing() -1 );
602 		// Sort by user-count
603 		case COLUMN_SERVER_USERS: return mode * CmpAny( server1->GetUsers(), server2->GetUsers() );
604 		// Sort by file-count
605 		case COLUMN_SERVER_FILES: return mode * CmpAny( server1->GetFiles(), server2->GetFiles() );
606 		// Sort by priority
607 		case COLUMN_SERVER_PRIO:
608 			{
609 				uint32 srv_pr1 = server1->GetPreferences();
610 				uint32 srv_pr2 = server2->GetPreferences();
611 				switch ( srv_pr1 ) {
612 					case SRV_PR_HIGH:	srv_pr1 = SRV_PR_MAX; break;
613 					case SRV_PR_NORMAL:	srv_pr1 = SRV_PR_MID; break;
614 					case SRV_PR_LOW:	srv_pr1 = SRV_PR_MIN; break;
615 					default:		return 0;
616 				}
617 				switch ( srv_pr2 ) {
618 					case SRV_PR_HIGH:	srv_pr2 = SRV_PR_MAX; break;
619 					case SRV_PR_NORMAL:	srv_pr2 = SRV_PR_MID; break;
620 					case SRV_PR_LOW:	srv_pr2 = SRV_PR_MIN; break;
621 					default:		return 0;
622 				}
623 				return mode * CmpAny( srv_pr1, srv_pr2 );
624 			}
625 		// Sort by failure-count
626 		case COLUMN_SERVER_FAILS: return mode * CmpAny( server1->GetFailedCount(), server2->GetFailedCount() );
627 		// Sort by static servers
628 		case COLUMN_SERVER_STATIC:
629 			{
630 				return mode * CmpAny( server2->IsStaticMember(), server1->IsStaticMember() );
631 			}
632 		// Sort by version
633 		case COLUMN_SERVER_VERSION: return mode * FuzzyStrCmp(server1->GetVersion(), server2->GetVersion());
634 
635 		default:
636 			return 0;
637 	}
638 }
639 // File_checked_for_headers
640