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 
27 #include <cmath>		// Needed for std::ceil
28 
29 #include "ColorFrameCtrl.h"	// Needed for CColorFrameCtrl
30 #include "OtherFunctions.h"	// Needed for CastChild()
31 #include "OScopeCtrl.h"		// Needed for COScopeCtrl
32 #include "Preferences.h"	// Needed for thePrefs
33 #include "muuli_wdr.h"		// Needed for statsDlg()
34 #include "StatisticsDlg.h"	// Interface declarations
35 #include "Statistics.h"
36 
37 
38 class CTreeItemData : public wxTreeItemData
39 {
40       public:
CTreeItemData(uint32_t uniqueid)41 	explicit CTreeItemData(uint32_t uniqueid)
42 		: m_uniqueid(uniqueid)
43 	{}
44 
GetUniqueId() const45 	uint32_t GetUniqueId() const throw() { return m_uniqueid; }
SetUniqueId(uint32_t val)46 	void SetUniqueId(uint32_t val) throw() { m_uniqueid = val; }
47 
48       private:
49 	uint32_t m_uniqueid;
50 };
51 
52 
53 // CStatisticsDlg panel
54 
getColors(unsigned num)55 const wxColour& CStatisticsDlg::getColors(unsigned num)
56 {
57 	wxCHECK(num < 15, *wxBLACK);
58 
59 	return acrStat[num];
60 }
61 
CStatisticsDlg(wxWindow * pParent,CStatistics * stats)62 CStatisticsDlg::CStatisticsDlg(wxWindow* pParent, CStatistics* stats)
63 : wxPanel(pParent, -1)
64 {
65 	wxSizer* content=statsDlg(this,TRUE);
66 	content->Show(this,TRUE);
67 
68 	pscopeDL	= CastChild( wxT("dloadScope"), COScopeCtrl );
69 	pscopeDL->graph_type = GRAPH_DOWN;
70 	pscopeUL	= CastChild( wxT("uloadScope"), COScopeCtrl );
71 	pscopeUL->graph_type = GRAPH_UP;
72 	pscopeConn	= CastChild( wxT("otherScope"), COScopeCtrl );
73 	pscopeConn->graph_type = GRAPH_CONN;
74 	stattree	= CastChild( wxT("statTree"),	wxTreeCtrl  );
75 
76 	m_stats = stats;
77 }
78 
79 
80 
~CStatisticsDlg()81 CStatisticsDlg::~CStatisticsDlg()
82 {
83 
84 }
85 
Init()86 void CStatisticsDlg::Init()
87 {
88 	InitGraphs();
89 	InitTree();
90 }
91 
92 
InitGraphs()93 void CStatisticsDlg::InitGraphs()
94 {
95 	// called after preferences get initialised
96 	for (int index=0; index<=10; ++index) {
97 		ApplyStatsColor(index);
98 	}
99 
100 	pscopeDL->SetRanges(0.0, (float)(thePrefs::GetMaxGraphDownloadRate()+4));
101 	pscopeDL->SetYUnits(_("kB/s"));
102 	pscopeUL->SetRanges(0.0, (float)(thePrefs::GetMaxGraphUploadRate()+4));
103 	pscopeUL->SetYUnits(_("kB/s"));
104 	pscopeConn->SetRanges(0.0, (float)(thePrefs::GetStatsMax()));
105 	pscopeConn->SetYUnits(wxEmptyString);
106 
107 	SetUpdatePeriod(thePrefs::GetTrafficOMeterInterval());
108 }
109 
110 
111 // this array is now used to store the current color settings and to define the defaults
112 wxColour CStatisticsDlg::acrStat[cntStatColors] =
113 	{
114 		wxColour(0,0,64), wxColour(192,192,255), wxColour(128, 255, 128), wxColour(0, 210, 0),
115 		wxColour(0, 128, 0), wxColour(255, 128, 128), wxColour(200, 0, 0), wxColour(140, 0, 0),
116 		wxColour(150, 150, 255), wxColour(192, 0, 192), wxColour(255, 255, 128), wxColour(0, 0, 0),
117 		wxColour(128, 255, 128), wxColour(0, 210, 0), wxColour(0, 128, 0)
118 	};
119 
ApplyStatsColor(int index)120 void CStatisticsDlg::ApplyStatsColor(int index)
121 {
122 	static char aTrend[] = { 0,0,  2,     1,     0,           2,     1,     0,          1,    2,    0 };
123 	static int aRes[] = { 0,0, IDC_C0,IDC_C0_3,IDC_C0_2,  IDC_C1,IDC_C1_3,IDC_C1_2,  IDC_S0,IDC_S3,IDC_S1 };
124 	static COScopeCtrl** apscope[] = { NULL, NULL, &pscopeDL,&pscopeDL,&pscopeDL, &pscopeUL,&pscopeUL,&pscopeUL, &pscopeConn,&pscopeConn,&pscopeConn };
125 
126 	const wxColour& cr = acrStat[index];
127 
128 	int iRes = aRes[index];
129 	int iTrend = aTrend[index];
130 	COScopeCtrl** ppscope = apscope[index];
131 	CColorFrameCtrl* ctrl;
132 	switch (index) {
133 		case 0:
134 				pscopeDL->SetBackgroundColor(cr);
135 				pscopeUL->SetBackgroundColor(cr);
136 				pscopeConn->SetBackgroundColor(cr);
137 				break;
138 		case 1:
139 				pscopeDL->SetGridColor(cr);
140 				pscopeUL->SetGridColor(cr);
141 				pscopeConn->SetGridColor(cr);
142 				break;
143 		case 2:  case 3:  case 4:
144 		case 5:  case 6:  case 7:
145 		case 8:  case 9:  case 10:
146 				(*ppscope)->SetPlotColor(cr, iTrend);
147 				if ((ctrl = CastChild(iRes, CColorFrameCtrl)) == NULL) {
148 					throw wxString(CFormat(wxT("CStatisticsDlg::ApplyStatsColor: control missing (%d)\n")) % iRes);
149 				}
150 				ctrl->SetBackgroundBrushColour(cr);
151 				ctrl->SetFrameBrushColour(*wxBLACK);
152 				break;
153 		default:
154 				break; // ignore unknown index, like SysTray speedbar color
155 	}
156 }
157 
UpdateStatGraphs(const uint32 peakconnections,const GraphUpdateInfo & update)158 void CStatisticsDlg::UpdateStatGraphs(const uint32 peakconnections, const GraphUpdateInfo& update)
159 {
160 
161 	std::vector<float *> v1(3);
162 	v1[0] = const_cast<float *>(&update.downloads[0]);
163 	v1[1] = const_cast<float *>(&update.downloads[1]);
164 	v1[2] = const_cast<float *>(&update.downloads[2]);
165 	const std::vector<float *> &apfDown(v1);
166 	std::vector<float *> v2(3);
167 	v2[0] = const_cast<float *>(&update.uploads[0]);
168 	v2[1] = const_cast<float *>(&update.uploads[1]);
169 	v2[2] = const_cast<float *>(&update.uploads[2]);
170 	const std::vector<float *> &apfUp(v2);
171 	std::vector<float *> v3(3);
172 	v3[0] = const_cast<float *>(&update.connections[0]);
173 	v3[1] = const_cast<float *>(&update.connections[1]);
174 	v3[2] = const_cast<float *>(&update.connections[2]);
175 	const std::vector<float *> &apfConn(v3);
176 
177 	if (!IsShownOnScreen()) {
178 		pscopeDL->DelayPoints();
179 		pscopeUL->DelayPoints();
180 		pscopeConn->DelayPoints();
181 	}
182 
183 	static unsigned nScalePrev=1;
184 	unsigned nScale = (unsigned)std::ceil((float)peakconnections / pscopeConn->GetUpperLimit());
185 	if (nScale != nScalePrev) {
186 		nScalePrev = nScale;
187 		wxStaticText* label = CastChild( ID_ACTIVEC, wxStaticText );
188 
189 		label->SetLabel(CFormat(_("Active connections (1:%u)")) % nScale);
190 		label->GetParent()->Layout();
191 
192 		pscopeConn->SetRange(0.0, (float)nScale*pscopeConn->GetUpperLimit(), 1);
193 	}
194 
195 	if (!IsShownOnScreen()) {
196 		return;
197 	}
198 
199 	pscopeDL->AppendPoints(update.timestamp, apfDown);
200 	pscopeUL->AppendPoints(update.timestamp, apfUp);
201 	pscopeConn->AppendPoints(update.timestamp, apfConn);
202 }
203 
204 
SetUpdatePeriod(int step)205 void CStatisticsDlg::SetUpdatePeriod(int step)
206 {
207 	// this gets called after the value in Preferences/Statistics/Update delay has been changed
208 	if (step == 0) {
209 		pscopeDL->Stop();
210 		pscopeUL->Stop();
211 		pscopeConn->Stop();
212 	} else {
213 		pscopeDL->Reset(step);
214 		pscopeUL->Reset(step);
215 		pscopeConn->Reset(step);
216 	}
217 }
218 
219 
ResetAveragingTime()220 void CStatisticsDlg::ResetAveragingTime()
221 {
222 	// this gets called after the value in Preferences/Statistics/time for running avg has been changed
223 	pscopeDL->InvalidateGraph();
224 	pscopeUL->InvalidateGraph();
225 }
226 
227 
SetARange(bool SetDownload,int maxValue)228 void CStatisticsDlg::SetARange(bool SetDownload,int maxValue)
229 {
230 	if ( SetDownload ) {
231 		pscopeDL->SetRanges( 0, maxValue + 4 );
232 	} else {
233 		pscopeUL->SetRanges( 0, maxValue + 4 );
234 	}
235 }
236 
237 
InitTree()238 void  CStatisticsDlg::InitTree()
239 {
240 #ifndef CLIENT_GUI
241 	wxTreeItemId root =
242 #endif
243 		stattree->AddRoot(theStats::GetTreeRoot()->GetDisplayString());
244 
245 	ShowStatistics(true);
246 
247 #ifndef CLIENT_GUI
248 	// Expand root
249 	stattree->Expand(root);
250 
251 	// Expand main items
252 	wxTreeItemIdValue cookie;
253 	wxTreeItemId expand_it = stattree->GetFirstChild(root,cookie);
254 
255 	while(expand_it.IsOk()) {
256 		stattree->Expand(expand_it);
257 		// Next on this level
258 		expand_it = stattree->GetNextSibling(expand_it);
259 	}
260 #endif
261 }
262 
GetExpandedNodes(NodeIdSet & nodeset,const wxTreeItemId & root)263 void CStatisticsDlg::GetExpandedNodes(NodeIdSet& nodeset, const wxTreeItemId& root)
264 {
265 	wxTreeItemIdValue cookie;
266 	wxTreeItemId temp_it = stattree->GetFirstChild(root,cookie);
267 
268 	while (temp_it.IsOk()) {
269 		if (stattree->IsExpanded(temp_it)) {
270 			nodeset.insert(dynamic_cast<CTreeItemData*>(stattree->GetItemData(temp_it))->GetUniqueId());
271 		}
272 		if (stattree->ItemHasChildren(temp_it)) {
273 			GetExpandedNodes(nodeset, temp_it);
274 		}
275 		temp_it = stattree->GetNextSibling(temp_it);
276 	}
277 }
278 
ShowStatistics(bool init)279 void CStatisticsDlg::ShowStatistics(bool init)
280 {
281 	NodeIdSet ExpandedNodes;
282 
283 	// If it's not the first initialization of the tree, i.e. application startup
284 	if (!init) {
285 		GetExpandedNodes(ExpandedNodes, stattree->GetRootItem());
286 		// Update sorting / get tree via EC
287 		m_stats->UpdateStatsTree();
288 	}
289 
290 	CStatTreeItemBase* treeRoot = theStats::GetTreeRoot();
291 	wxTreeItemId root = stattree->GetRootItem();
292 	FillTree(treeRoot, root, ExpandedNodes);
293 #ifdef CLIENT_GUI
294 	if (!init) {
295 		static bool firstUpdate = true;
296 		if (firstUpdate) {
297 			// Expand root
298 			root = stattree->GetRootItem();
299 			stattree->Expand(root);
300 
301 			// Expand main items
302 			wxTreeItemIdValue cookie;
303 			wxTreeItemId expand_it = stattree->GetFirstChild(root,cookie);
304 
305 			while(expand_it.IsOk()) {
306 				stattree->Expand(expand_it);
307 				// Next on this level
308 				expand_it = stattree->GetNextSibling(expand_it);
309 			}
310 			firstUpdate = false;
311 		}
312 	}
313 #endif
314 }
315 
316 
317 #ifdef CLIENT_GUI
RebuildStatTreeRemote(const CECTag * tag)318 void CStatisticsDlg::RebuildStatTreeRemote(const CECTag * tag)
319 {
320 	m_stats->RebuildStatTreeRemote(tag);
321 }
322 #endif
323 
324 
FillTree(CStatTreeItemBase * statssubtree,wxTreeItemId & StatsGUITree,const NodeIdSet & expandednodes)325 void CStatisticsDlg::FillTree(CStatTreeItemBase* statssubtree, wxTreeItemId& StatsGUITree, const NodeIdSet& expandednodes)
326 {
327 	wxMutexLocker lock(statssubtree->GetLock());
328 
329 #ifndef CLIENT_GUI
330 	StatTreeItemIterator temp_it = statssubtree->GetFirstVisibleChild(thePrefs::GetMaxClientVersions());
331 #else
332 	StatTreeItemIterator temp_it = statssubtree->GetFirstVisibleChild();
333 #endif
334 
335 	wxTreeItemIdValue cookie;
336 	wxTreeItemId temp_GUI_it = stattree->GetFirstChild(StatsGUITree,cookie);
337 
338 	while (!statssubtree->IsAtEndOfList(temp_it)) {
339 		wxTreeItemId temp_item;
340 		if (temp_GUI_it.IsOk()) {
341 			// There's already a child there, update it.
342 			stattree->SetItemText(temp_GUI_it, (*temp_it)->GetDisplayString());
343 			temp_item = temp_GUI_it;
344 			uint32_t uid = (*temp_it)->GetUniqueId();
345 			dynamic_cast<CTreeItemData*>(stattree->GetItemData(temp_GUI_it))->SetUniqueId(uid);
346 			if (expandednodes.find(uid) != expandednodes.end()) {
347 				stattree->Expand(temp_GUI_it);
348 			} else {
349 				stattree->Collapse(temp_GUI_it);
350 			}
351 			temp_GUI_it = stattree->GetNextSibling(temp_GUI_it);
352 		} else {
353 			// No more child on GUI, add them.
354 			temp_item = stattree->AppendItem(StatsGUITree,(*temp_it)->GetDisplayString());
355 			stattree->SetItemData(temp_item, new CTreeItemData((*temp_it)->GetUniqueId()));
356 		}
357 		// Has childs?
358 		if ((*temp_it)->HasVisibleChildren()) {
359 			FillTree((*temp_it), temp_item, expandednodes);
360 		} else {
361 			stattree->DeleteChildren(temp_item);
362 		}
363 		statssubtree->GetNextVisibleChild(temp_it);
364 	}
365 
366 	// What if GUI has more items than tree?
367 	// Delete the extra items.
368 	while (temp_GUI_it.IsOk()) {
369 		wxTreeItemId backup_node = stattree->GetNextSibling(temp_GUI_it);
370 		stattree->DeleteChildren(temp_GUI_it);
371 		stattree->Delete(temp_GUI_it);
372 		temp_GUI_it = backup_node;
373 	}
374 }
375 // File_checked_for_headers
376