Improve speed of category tab title updates
[amule.git] / src / StatTree.cpp
blobf7e6b1050bcf4eb1b8d0439678bc7472d92f9db7
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) 2005-2008 Dévai Tamás ( gonosztopi@amule.org )
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 "StatTree.h"
28 #include <wx/intl.h>
29 #include "OtherFunctions.h"
31 #ifndef CLIENT_GUI
33 #include <common/Format.h> // Needed for CFormat
35 #define a_brackets_b(a,b) (a + wxT(" (") + b + wxT(")"))
37 #endif /* !CLIENT_GUI */
39 #include <ec/cpp/ECTag.h> // Needed for CECTag
41 #ifdef CLIENT_GUI
42 #include <ec/cpp/ECSpecialTags.h> // Needed for CEC_StatTree_Node_Tag
44 #else
46 uint32_t NewStatTreeItemId()
48 static uint32_t lastid = 0;
50 return ++lastid;
52 #endif
54 /* CStatTreeItemBase */
56 #ifdef CLIENT_GUI
57 CStatTreeItemBase::CStatTreeItemBase(const CECTag *tag)
58 : m_label(((CEC_StatTree_Node_Tag*)tag)->GetDisplayString())
59 , m_uniqueid(tag->GetTagByNameSafe(EC_TAG_STATTREE_NODEID)->GetInt())
61 wxASSERT(tag->GetTagName() == EC_TAG_STATTREE_NODE);
63 for (CECTag::const_iterator it = tag->begin(); it != tag->end(); it++) {
64 const CECTag *tmp = & *it;
65 if (tmp->GetTagName() == EC_TAG_STATTREE_NODE) {
66 m_children.push_back(new CStatTreeItemBase(tmp));
70 #endif /* CLIENT_GUI */
72 CStatTreeItemBase::~CStatTreeItemBase()
74 DeleteContents(m_children);
77 #ifndef CLIENT_GUI
78 CStatTreeItemBase* CStatTreeItemBase::AddChild(
79 CStatTreeItemBase* child,
80 uint32_t id,
81 bool skipOneLevel)
83 wxMutexLocker lock(m_lock);
85 if (skipOneLevel) {
86 child->m_parent = m_parent;
87 } else {
88 child->m_parent = this;
90 child->m_id = id;
92 if (m_flags & stSortChildren) {
93 std::list<CStatTreeItemBase*>::iterator it = m_children.begin();
94 while (it != m_children.end() && id < (*it)->m_id) {
95 ++it;
97 m_children.insert(it, child);
98 } else {
99 m_children.push_back(child);
101 return child;
103 #endif /* !CLIENT_GUI */
105 bool CStatTreeItemBase::HasVisibleChildren()
107 wxMutexLocker lock(m_lock);
109 for (std::list<CStatTreeItemBase*>::const_iterator it = m_children.begin();
110 it != m_children.end(); ++it) {
111 if ((*it)->IsVisible()) {
112 return true;
115 return false;
118 #ifndef CLIENT_GUI
119 bool CStatTreeItemBase::HasChildWithId(uint32_t id)
121 wxMutexLocker lock(m_lock);
123 for (std::list<CStatTreeItemBase*>::const_iterator it = m_children.begin();
124 it != m_children.end(); ++it) {
125 if ((*it)->m_id == id) {
126 return true;
129 return false;
132 CStatTreeItemBase* CStatTreeItemBase::GetChildById(uint32_t id)
134 wxMutexLocker lock(m_lock);
136 for (std::list<CStatTreeItemBase*>::const_iterator it = m_children.begin();
137 it != m_children.end(); ++it) {
138 if ((*it)->m_id == id) {
139 return *it;
142 return NULL;
145 // Note: these functions do not lock the list, because it is already locked at the time they're called
146 StatTreeItemIterator CStatTreeItemBase::GetFirstVisibleChild(uint32_t max_children)
148 StatTreeItemIterator it = m_children.begin();
149 m_visible_counter = --max_children;
150 while (it != m_children.end() && !(*it)->IsVisible()) ++it;
151 return it;
154 void CStatTreeItemBase::GetNextVisibleChild(StatTreeItemIterator& it)
156 if (m_flags & stCapChildren) {
157 if (m_visible_counter == 0) {
158 it = m_children.end();
159 return;
160 } else {
161 --m_visible_counter;
164 if (it != m_children.end()) ++it;
165 while (it != m_children.end() && !(*it)->IsVisible()) ++it;
169 // Anything below is only for core.
172 bool CStatTreeItemBase::ValueSort(const CStatTreeItemBase* a, const CStatTreeItemBase* b)
174 if (a->m_id < 0x00000100 || a->m_id > 0x7fffffff || b->m_id < 0x00000100 || b->m_id > 0x7fffffff) {
175 return a->m_id > b->m_id;
176 } else {
177 return ((CStatTreeItemCounter*)a)->GetValue() > ((CStatTreeItemCounter*)b)->GetValue();
181 #ifndef AMULE_DAEMON
182 wxString CStatTreeItemBase::GetDisplayString() const
184 return wxGetTranslation(m_label);
186 #endif
188 CECTag *CStatTreeItemBase::CreateECTag(uint32_t max_children)
190 if (IsVisible()) {
191 wxMutexLocker lock(m_lock);
192 CECTag *tag = new CECTag(EC_TAG_STATTREE_NODE, m_label);
193 tag->AddTag(CECTag(EC_TAG_STATTREE_NODEID, m_uniqueid));
194 AddECValues(tag);
195 m_visible_counter = max_children - 1;
196 for (std::list<CStatTreeItemBase*>::const_iterator it = m_children.begin();
197 it != m_children.end(); ++it) {
198 CECTag *tmp = (*it)->CreateECTag(max_children);
199 if (tmp) {
200 tag->AddTag(*tmp);
201 delete tmp;
202 if (m_flags & stCapChildren) {
203 if (m_visible_counter == 0) {
204 break;
205 } else {
206 --m_visible_counter;
211 return tag;
212 } else {
213 return NULL;
218 /* CStatTreeItemSimple */
220 #ifndef AMULE_DAEMON
221 wxString CStatTreeItemSimple::GetDisplayString() const
223 switch (m_valuetype) {
224 case vtInteger:
225 switch (m_displaymode) {
226 case dmTime: return CFormat(wxGetTranslation(m_label)) % CastSecondsToHM(m_intvalue);
227 case dmBytes: return CFormat(wxGetTranslation(m_label)) % CastItoXBytes(m_intvalue);
228 default: return CFormat(wxGetTranslation(m_label)) % m_intvalue;
230 case vtFloat: return CFormat(wxGetTranslation(m_label)) % m_floatvalue;
231 case vtString: return CFormat(wxGetTranslation(m_label)) % m_stringvalue;
232 default: return wxGetTranslation(m_label);
235 #endif
237 bool CStatTreeItemSimple::IsVisible() const
239 if (m_flags & stHideIfZero) {
240 switch (m_valuetype) {
241 case vtInteger: return m_intvalue != 0;
242 case vtFloat: return m_floatvalue != 0.0;
243 case vtString: return !m_stringvalue.IsEmpty();
244 default: return false;
247 return true;
250 void CStatTreeItemSimple::AddECValues(CECTag *tag) const
252 switch (m_valuetype) {
253 case vtInteger: {
254 if (m_displaymode == dmTime) {
255 CECTag value(EC_TAG_STAT_NODE_VALUE, (uint32)m_intvalue);
256 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_TIME));
257 tag->AddTag(value);
258 } else {
259 CECTag value(EC_TAG_STAT_NODE_VALUE, (uint64)m_intvalue);
260 if (m_displaymode == dmBytes) {
261 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_BYTES));
263 tag->AddTag(value);
265 break;
267 case vtFloat: {
268 CECTag value(EC_TAG_STAT_NODE_VALUE, m_floatvalue);
269 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_DOUBLE));
270 tag->AddTag(value);
271 break;
273 case vtString: {
274 CECTag value(EC_TAG_STAT_NODE_VALUE, m_stringvalue);
275 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_STRING));
276 tag->AddTag(value);
277 break;
279 default:
280 break;
285 /* CStatTreeItemCounterTmpl */
287 #ifndef AMULE_DAEMON
288 template<typename _Tp>
289 wxString CStatTreeItemCounterTmpl<_Tp>::GetDisplayString() const
291 wxString my_label = wxGetTranslation(m_label);
292 // This is needed for client names, for example
293 if (my_label == m_label) {
294 if (m_label.Right(4) == wxT(": %s")) {
295 my_label = wxGetTranslation(
296 m_label.Mid(0, m_label.Length() - 4)) +
297 wxString(wxT(": %s"));
300 CFormat label(my_label);
301 if (m_displaymode == dmBytes) {
302 return label % CastItoXBytes(m_value);
303 } else {
304 wxString result = CFormat(wxT("%u")) % m_value;
305 if ((m_flags & stShowPercent) && m_parent) {
306 result += CFormat(wxT(" (%.2f%%)")) % (((double)m_value / ((CStatTreeItemCounterTmpl<_Tp>*)m_parent)->m_value) * 100.0);
308 return label % result;
312 template wxString CStatTreeItemCounter::GetDisplayString() const;
313 template wxString CStatTreeItemNativeCounter::GetDisplayString() const;
315 #endif
317 template<typename _Tp>
318 void CStatTreeItemCounterTmpl<_Tp>::AddECValues(CECTag *tag) const
320 CECTag value(EC_TAG_STAT_NODE_VALUE, (uint64)m_value);
321 if (m_displaymode == dmBytes) {
322 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_BYTES));
323 } else {
324 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_ISTRING));
325 if ((m_flags & stShowPercent) && m_parent) {
326 CECTag tmp(EC_TAG_STAT_NODE_VALUE,
327 ((double)m_value / ((CStatTreeItemCounterTmpl<_Tp>*)m_parent)->m_value) * 100.0);
328 tmp.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_DOUBLE));
329 value.AddTag(tmp);
332 tag->AddTag(value);
335 template void CStatTreeItemCounter::AddECValues(CECTag *tag) const;
336 template void CStatTreeItemNativeCounter::AddECValues(CECTag *tag) const;
338 /* CStatTreeItemUlDlCounter */
340 #ifndef AMULE_DAEMON
341 wxString CStatTreeItemUlDlCounter::GetDisplayString() const
343 return CFormat(wxGetTranslation(m_label)) %
344 a_brackets_b(CastItoXBytes(m_value), CastItoXBytes(m_value + m_totalfunc()));
346 #endif
348 void CStatTreeItemUlDlCounter::AddECValues(CECTag *tag) const
350 CECTag value(EC_TAG_STAT_NODE_VALUE, m_value);
351 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_BYTES));
352 CECTag tmp(EC_TAG_STAT_NODE_VALUE, m_value + m_totalfunc());
353 tmp.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_BYTES));
354 value.AddTag(tmp);
355 tag->AddTag(value);
359 /* CStatTreeItemCounterMax */
361 #ifndef AMULE_DAEMON
362 wxString CStatTreeItemCounterMax::GetDisplayString() const
364 return CFormat(wxGetTranslation(m_label)) % m_value;
366 #endif
368 void CStatTreeItemCounterMax::AddECValues(CECTag *tag) const
370 tag->AddTag(CECTag(EC_TAG_STAT_NODE_VALUE, (uint64)m_value));
374 /* CStatTreeItemPackets */
376 #ifndef AMULE_DAEMON
377 wxString CStatTreeItemPackets::GetDisplayString() const
379 return CFormat(wxGetTranslation(m_label)) %
380 a_brackets_b(CastItoXBytes(m_bytes), CastItoIShort(m_packets));
382 #endif
384 void CStatTreeItemPackets::AddECValues(CECTag *tag) const
386 CECTag value(EC_TAG_STAT_NODE_VALUE, m_bytes);
387 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_BYTES));
388 CECTag tmp(EC_TAG_STAT_NODE_VALUE, (uint64)m_packets);
389 tmp.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_ISHORT));
390 value.AddTag(tmp);
391 tag->AddTag(value);
395 /* CStatTreeItemPacketTotals */
397 #ifndef AMULE_DAEMON
398 wxString CStatTreeItemPacketTotals::GetDisplayString() const
400 uint32_t tmp_packets = m_packets;
401 uint64_t tmp_bytes = m_bytes;
402 for (std::vector<CStatTreeItemPackets*>::const_iterator it = m_counters.begin();
403 it != m_counters.end(); ++it) {
404 tmp_packets += (*it)->m_packets;
405 tmp_bytes += (*it)->m_bytes;
408 return CFormat(wxGetTranslation(m_label)) %
409 a_brackets_b(CastItoXBytes(tmp_bytes), CastItoIShort(tmp_packets));
411 #endif
413 void CStatTreeItemPacketTotals::AddECValues(CECTag *tag) const
415 uint32_t tmp_packets = m_packets;
416 uint64_t tmp_bytes = m_bytes;
417 for (std::vector<CStatTreeItemPackets*>::const_iterator it = m_counters.begin();
418 it != m_counters.end(); ++it) {
419 tmp_packets += (*it)->m_packets;
420 tmp_bytes += (*it)->m_bytes;
423 CECTag value(EC_TAG_STAT_NODE_VALUE, tmp_bytes);
424 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_BYTES));
425 CECTag tmp(EC_TAG_STAT_NODE_VALUE, (uint64)tmp_packets);
426 tmp.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_ISHORT));
427 value.AddTag(tmp);
428 tag->AddTag(value);
432 /* CStatTreeItemTimer */
434 #ifndef AMULE_DAEMON
435 wxString CStatTreeItemTimer::GetDisplayString() const
437 return CFormat(wxGetTranslation(m_label)) %
438 CastSecondsToHM(m_value ? GetTimerSeconds() : 0);
440 #endif
442 void CStatTreeItemTimer::AddECValues(CECTag *tag) const
444 CECTag value(EC_TAG_STAT_NODE_VALUE,
445 m_value ? (uint32)GetTimerSeconds() : (uint32)0);
446 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_TIME));
447 tag->AddTag(value);
451 /* CStatTreeItemAverage */
453 #ifndef AMULE_DAEMON
454 wxString CStatTreeItemAverage::GetDisplayString() const
456 if ((*m_divisor) != 0) {
457 switch (m_displaymode) {
458 case dmBytes:
459 return CFormat(wxGetTranslation(m_label)) %
460 CastItoXBytes((*m_dividend)/(*m_divisor));
461 case dmTime:
462 return CFormat(wxGetTranslation(m_label)) %
463 CastSecondsToHM((*m_dividend)/(*m_divisor));
464 default:
465 return CFormat(wxGetTranslation(m_label)) %
466 (CFormat(wxT("%u")) % ((uint64)(*m_dividend)/(*m_divisor))).GetString();
468 } else {
469 return CFormat(wxGetTranslation(m_label)) % wxT("-");
472 #endif
474 void CStatTreeItemAverage::AddECValues(CECTag *tag) const
476 if ((*m_divisor) != 0) {
477 uint64 data = (*m_dividend)/(*m_divisor);
478 if (m_displaymode == dmTime) {
479 CECTag value(EC_TAG_STAT_NODE_VALUE, (uint32)data);
480 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_TIME));
481 tag->AddTag(value);
482 } else {
483 CECTag value(EC_TAG_STAT_NODE_VALUE, data);
484 if (m_displaymode == dmBytes) {
485 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_BYTES));
487 tag->AddTag(value);
489 } else {
490 CECTag value(EC_TAG_STAT_NODE_VALUE, wxString(wxT("-")));
491 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_STRING));
492 tag->AddTag(value);
497 /* CStatTreeItemAverageSpeed */
499 #ifndef AMULE_DAEMON
500 wxString CStatTreeItemAverageSpeed::GetDisplayString() const
502 uint64 time = m_timer->GetTimerSeconds();
503 if (time) {
504 return CFormat(wxGetTranslation(m_label)) % CastItoSpeed((*m_counter)/time);
505 } else {
506 return CFormat(wxGetTranslation(m_label)) % CastItoSpeed(0);
509 #endif
511 void CStatTreeItemAverageSpeed::AddECValues(CECTag *tag) const
513 uint64 time = m_timer->GetTimerSeconds();
514 if (time) {
515 CECTag value(EC_TAG_STAT_NODE_VALUE, (uint32)((*m_counter)/time));
516 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_SPEED));
517 tag->AddTag(value);
518 } else {
519 CECTag value(EC_TAG_STAT_NODE_VALUE, (uint32)0);
520 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_SPEED));
521 tag->AddTag(value);
526 /* CStatTreeItemRatio */
528 wxString CStatTreeItemRatio::GetString() const
530 wxString ret;
531 double v1 = m_counter1->GetValue();
532 double v2 = m_counter2->GetValue();
533 if (v1 > 0 && v2 > 0) {
534 if (v2 < v1) {
535 ret = CFormat(wxT("%.2f : 1")) % (v1 / v2);
536 } else {
537 ret = CFormat(wxT("1 : %.2f")) % (v2 / v1);
540 if (m_totalfunc1 && m_totalfunc2) {
541 double t1 = m_totalfunc1() + v1;
542 double t2 = m_totalfunc2() + v2;
543 if (t2 < t1) {
544 ret += CFormat(wxT(" (%.2f : 1)")) % (t1 / t2);
545 } else {
546 ret += CFormat(wxT(" (1 : %.2f)")) % (t2 / t1);
549 } else {
550 ret = _("Not available");
552 return ret;
555 #ifndef AMULE_DAEMON
556 wxString CStatTreeItemRatio::GetDisplayString() const
558 return CFormat(wxGetTranslation(m_label)) % GetString();
560 #endif
562 void CStatTreeItemRatio::AddECValues(CECTag *tag) const
564 CECTag value(EC_TAG_STAT_NODE_VALUE, GetString());
565 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_STRING));
566 tag->AddTag(value);
570 /* CStatTreeItemReconnects */
572 #ifndef AMULE_DAEMON
573 wxString CStatTreeItemReconnects::GetDisplayString() const
575 return CFormat(wxGetTranslation(m_label)) % (m_value ? m_value - 1 : 0);
577 #endif
579 void CStatTreeItemReconnects::AddECValues(CECTag *tag) const
581 tag->AddTag(CECTag(EC_TAG_STAT_NODE_VALUE,
582 m_value ? (uint64)(m_value - 1) : (uint64)0));
585 /* CStatTreeItemMaxConnLimitReached */
587 #ifndef AMULE_DAEMON
588 wxString CStatTreeItemMaxConnLimitReached::GetDisplayString() const
590 if (m_count) {
591 return CFormat(wxGetTranslation(m_label)) %
592 (CFormat(wxT("%i : %s %s")) % m_count % m_time.FormatISODate() % m_time.FormatISOTime());
593 } else {
594 return CFormat(wxGetTranslation(m_label)) % _("Never");
597 #endif
599 void CStatTreeItemMaxConnLimitReached::AddECValues(CECTag *tag) const
601 wxString result;
602 if (m_count) {
603 result = CFormat(wxT("%i : %s %s")) % m_count % m_time.FormatISODate() % m_time.FormatISOTime();
604 } else {
605 result = wxTRANSLATE("Never");
607 CECTag value(EC_TAG_STAT_NODE_VALUE, result);
608 value.AddTag(CECTag(EC_TAG_STAT_VALUE_TYPE, (uint8)EC_VALUE_STRING));
609 tag->AddTag(value);
612 /* CStatTreeItemTotalClients */
614 #ifndef AMULE_DAEMON
615 wxString CStatTreeItemTotalClients::GetDisplayString() const
617 return CFormat(wxGetTranslation(m_label)) %
618 (m_known->GetValue() + m_unknown->GetValue()) %
619 m_known->GetValue();
621 #endif
623 void CStatTreeItemTotalClients::AddECValues(CECTag *tag) const
625 CECTag value1(EC_TAG_STAT_NODE_VALUE,
626 (uint64)(m_known->GetValue() + m_unknown->GetValue()));
627 tag->AddTag(value1);
628 CECTag value2(EC_TAG_STAT_NODE_VALUE,
629 (uint64)m_known->GetValue());
630 tag->AddTag(value2);
633 #endif /* !CLIENT_GUI */
634 // File_checked_for_headers