xref: /haiku/src/apps/debuganalyzer/gui/AbstractWaitObjectsPage.h (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 #ifndef ABSTRACT_WAIT_OBJECTS_PAGE_H
6 #define ABSTRACT_WAIT_OBJECTS_PAGE_H
7 
8 
9 #include <stdio.h>
10 
11 #include <new>
12 
13 #include <CheckBox.h>
14 #include <GroupView.h>
15 
16 #include "table/TableColumns.h"
17 #include "table/TreeTable.h"
18 
19 
20 #define ABSTRACT_WAIT_OBJECTS_PAGE_TEMPLATE						\
21 	template<typename ModelType, typename WaitObjectGroupType,	\
22 		typename WaitObjectType>
23 #define ABSTRACT_WAIT_OBJECTS_PAGE_CLASS	\
24 	AbstractWaitObjectsPage<ModelType, WaitObjectGroupType,	WaitObjectType>
25 
26 
27 ABSTRACT_WAIT_OBJECTS_PAGE_TEMPLATE
28 class AbstractWaitObjectsPage : public BGroupView, protected TreeTableListener {
29 public:
30 								AbstractWaitObjectsPage();
31 	virtual						~AbstractWaitObjectsPage();
32 
33 			void				SetModel(ModelType* model);
34 
35 	virtual	void				MessageReceived(BMessage* message);
36 
37 	virtual	void				AttachedToWindow();
38 
39 protected:
40 			class WaitObjectsTreeModel;
41 
42 			enum {
43 				MSG_ABSTRACT_WAIT_OBJECTS_GROUP_BY_NAME		= 'awog'
44 			};
45 
46 protected:
47 			void				_UpdateTreeModel();
48 
49 protected:
50 			TreeTable*			fWaitObjectsTree;
51 			WaitObjectsTreeModel* fWaitObjectsTreeModel;
52 			ModelType*			fModel;
53 			BCheckBox*			fGroupByNameCheckBox;
54 			bool				fGroupByName;
55 
56 
57 // #pragma mark - WaitObjectsTreeModel (inner class)
58 
59 
60 class WaitObjectsTreeModel : public TreeTableModel {
61 public:
62 	WaitObjectsTreeModel(ModelType* model, bool groupByName)
63 		:
64 		fModel(model),
65 		fRootNode(NULL)
66 	{
67 		fRootNode = new RootNode(fModel, groupByName);
68 	}
69 
70 	~WaitObjectsTreeModel()
71 	{
72 		delete fRootNode;
73 	}
74 
75 	virtual void* Root() const
76 	{
77 		return fRootNode;
78 	}
79 
80 	virtual int32 CountChildren(void* parent) const
81 	{
82 		return ((Node*)parent)->CountChildren();
83 	}
84 
85 	virtual void* ChildAt(void* parent, int32 index) const
86 	{
87 		return ((Node*)parent)->ChildAt(index);
88 	}
89 
90 	virtual int32 CountColumns() const
91 	{
92 		return 6;
93 	}
94 
95 	virtual bool GetValueAt(void* object, int32 columnIndex, BVariant& value)
96 	{
97 		return ((Node*)object)->GetValueAt(columnIndex, value);
98 	}
99 
100 private:
101 	struct Node {
102 		virtual ~Node() {}
103 
104 		virtual const char* Name() const = 0;
105 		virtual uint32 Type() const = 0;
106 		virtual addr_t Object() const = 0;
107 		virtual addr_t ReferencedObject() const = 0;
108 		virtual int64 Waits() const = 0;
109 		virtual nanotime_t TotalWaitTime() const = 0;
110 
111 		virtual int32 CountChildren() const = 0;
112 		virtual void* ChildAt(int32 index) const = 0;
113 
114 		static int CompareByName(const Node* a, const Node* b)
115 		{
116 			int cmp = (int)a->Type() - (int)b->Type();
117 			return cmp == 0 ? strcmp(a->Name(), b->Name()) : cmp;
118 		}
119 
120 		bool GetValueAt(int32 columnIndex, BVariant& value)
121 		{
122 			switch (columnIndex) {
123 				case 0:
124 					value.SetTo(wait_object_type_name(Type()),
125 						B_VARIANT_DONT_COPY_DATA);
126 					return true;
127 				case 1:
128 					value.SetTo(Name(), B_VARIANT_DONT_COPY_DATA);
129 					return true;
130 				case 2:
131 				{
132 					addr_t object = Object();
133 					if (object == 0)
134 						return false;
135 
136 					char buffer[16];
137 					snprintf(buffer, sizeof(buffer), "%#lx", object);
138 					value.SetTo(buffer);
139 					return true;
140 				}
141 				case 3:
142 				{
143 					addr_t object = ReferencedObject();
144 					if (object == 0)
145 						return false;
146 
147 					char buffer[16];
148 					snprintf(buffer, sizeof(buffer), "%#lx", object);
149 					value.SetTo(buffer);
150 					return true;
151 				}
152 				case 4:
153 					value.SetTo(Waits());
154 					return true;
155 				case 5:
156 					value.SetTo(TotalWaitTime());
157 					return true;
158 				default:
159 					return false;
160 			}
161 		}
162 	};
163 
164 	struct ObjectNode : Node {
165 		WaitObjectType* object;
166 
167 		ObjectNode(WaitObjectType* object)
168 			:
169 			object(object)
170 		{
171 		}
172 
173 		virtual const char* Name() const
174 		{
175 			return object->Name();
176 		}
177 
178 		virtual uint32 Type() const
179 		{
180 			return object->Type();
181 		}
182 
183 		virtual addr_t Object() const
184 		{
185 			return object->Object();
186 		}
187 
188 		virtual addr_t ReferencedObject() const
189 		{
190 			return object->ReferencedObject();
191 		}
192 
193 		virtual int64 Waits() const
194 		{
195 			return object->Waits();
196 		}
197 
198 		virtual nanotime_t TotalWaitTime() const
199 		{
200 			return object->TotalWaitTime();
201 		}
202 
203 		virtual int32 CountChildren() const
204 		{
205 			return 0;
206 		}
207 
208 		virtual void* ChildAt(int32 index) const
209 		{
210 			return NULL;
211 		}
212 	};
213 
214 	// For GCC 2
215 	friend struct ObjectNode;
216 
217 	struct GroupNode : Node {
218 		WaitObjectGroupType*	group;
219 		BObjectList<ObjectNode>	objectNodes;
220 
221 		GroupNode(WaitObjectGroupType* group)
222 			:
223 			group(group)
224 		{
225 			int32 count = group->CountWaitObjects();
226 			for (int32 i = 0; i < count; i++) {
227 				WaitObjectType* waitObject = group->WaitObjectAt(i);
228 				if (!objectNodes.AddItem(new ObjectNode(waitObject)))
229 					throw std::bad_alloc();
230 			}
231 		}
232 
233 		virtual const char* Name() const
234 		{
235 			return group->Name();
236 		}
237 
238 		virtual uint32 Type() const
239 		{
240 			return group->Type();
241 		}
242 
243 		virtual addr_t Object() const
244 		{
245 			return group->Object();
246 		}
247 
248 		virtual addr_t ReferencedObject() const
249 		{
250 			return 0;
251 		}
252 
253 		virtual int64 Waits() const
254 		{
255 			return group->Waits();
256 		}
257 
258 		virtual nanotime_t TotalWaitTime() const
259 		{
260 			return group->TotalWaitTime();
261 		}
262 
263 		virtual int32 CountChildren() const
264 		{
265 			return objectNodes.CountItems();
266 		}
267 
268 		virtual void* ChildAt(int32 index) const
269 		{
270 			return objectNodes.ItemAt(index);
271 		}
272 	};
273 
274 	// For GCC 2
275 	friend struct GroupNode;
276 
277 	struct NodeContainerNode : Node {
278 		NodeContainerNode()
279 			:
280 			fChildren(20, true)
281 		{
282 		}
283 
284 		NodeContainerNode(BObjectList<Node>& nodes)
285 			:
286 			fChildren(20, true)
287 		{
288 			fChildren.AddList(&nodes);
289 
290 			// compute total waits and total wait time
291 			fWaits = 0;
292 			fTotalWaitTime = 0;
293 
294 			for (int32 i = 0; Node* node = fChildren.ItemAt(i); i++) {
295 				fWaits += node->Waits();
296 				fTotalWaitTime += node->TotalWaitTime();
297 			}
298 		}
299 
300 		virtual const char* Name() const
301 		{
302 			Node* child = fChildren.ItemAt(0);
303 			return child != NULL ? child->Name() : "";
304 		}
305 
306 		virtual uint32 Type() const
307 		{
308 			Node* child = fChildren.ItemAt(0);
309 			return child != NULL ? child->Type() : 0;
310 		}
311 
312 		virtual addr_t Object() const
313 		{
314 			return 0;
315 		}
316 
317 		virtual addr_t ReferencedObject() const
318 		{
319 			return 0;
320 		}
321 
322 		virtual int64 Waits() const
323 		{
324 			return fWaits;
325 		}
326 
327 		virtual nanotime_t TotalWaitTime() const
328 		{
329 			return fTotalWaitTime;
330 		}
331 
332 		virtual int32 CountChildren() const
333 		{
334 			return fChildren.CountItems();
335 		}
336 
337 		virtual void* ChildAt(int32 index) const
338 		{
339 			return fChildren.ItemAt(index);
340 		}
341 
342 	protected:
343 		BObjectList<Node>	fChildren;
344 		int64				fWaits;
345 		nanotime_t			fTotalWaitTime;
346 	};
347 
348 	struct RootNode : public NodeContainerNode {
349 		ModelType*			model;
350 
351 		RootNode(ModelType* model, bool groupByName)
352 			:
353 			model(model)
354 		{
355 			// create nodes for the wait object groups
356 			BObjectList<Node> tempChildren;
357 			BObjectList<Node>& children
358 				= groupByName ? tempChildren : NodeContainerNode::fChildren;
359 			int32 count = model->CountWaitObjectGroups();
360 			for (int32 i = 0; i < count; i++) {
361 				WaitObjectGroupType* group = model->WaitObjectGroupAt(i);
362 				if (!children.AddItem(_CreateGroupNode(group)))
363 					throw std::bad_alloc();
364 			}
365 
366 			// If we shall group the nodes by name, we create grouping nodes.
367 			if (groupByName) {
368 				if (children.CountItems() < 2) {
369 					NodeContainerNode::fChildren.AddList(&children);
370 					return;
371 				}
372 
373 				// sort the nodes by name
374 				children.SortItems(&Node::CompareByName);
375 
376 				// create groups
377 				int32 nodeCount = children.CountItems();
378 				BObjectList<Node> nameGroup;
379 				Node* previousNode = children.ItemAt(0);
380 				int32 groupNodeIndex = 0;
381 				for (int32 i = 1; i < nodeCount; i++) {
382 					Node* node = children.ItemAt(i);
383 					if (strcmp(node->Name(), previousNode->Name())) {
384 						// create the group -- or just add the node, if it's
385 						// the only one
386 						if (nameGroup.CountItems() > 1) {
387 							NodeContainerNode::fChildren.AddItem(
388 								new NodeContainerNode(nameGroup));
389 						} else
390 							NodeContainerNode::fChildren.AddItem(previousNode);
391 
392 						nameGroup.MakeEmpty();
393 						groupNodeIndex = i;
394 					}
395 
396 					// add the node
397 					nameGroup.AddItem(node);
398 
399 					previousNode = node;
400 				}
401 			}
402 		}
403 
404 	private:
405 		static Node* _CreateGroupNode(WaitObjectGroupType* group)
406 		{
407 			// If the group has only one object, just create an object node.
408 			if (group->CountWaitObjects() == 1)
409 				return new ObjectNode(group->WaitObjectAt(0));
410 
411 			return new GroupNode(group);
412 		}
413 	};
414 
415 private:
416 	ModelType*	fModel;
417 	RootNode*	fRootNode;
418 };	// WaitObjectsTreeModel
419 
420 };	// AbstractWaitObjectsPage
421 
422 
423 // #pragma mark - WaitObjectsPage
424 
425 
426 ABSTRACT_WAIT_OBJECTS_PAGE_TEMPLATE
427 ABSTRACT_WAIT_OBJECTS_PAGE_CLASS::AbstractWaitObjectsPage()
428 	:
429 	BGroupView(B_VERTICAL, 10),
430 	fWaitObjectsTree(NULL),
431 	fWaitObjectsTreeModel(NULL),
432 	fModel(NULL),
433 	fGroupByNameCheckBox(NULL),
434 	fGroupByName(false)
435 {
436 	SetName("Wait objects");
437 
438 	fWaitObjectsTree = new TreeTable("wait object list", 0);
439 	AddChild(fWaitObjectsTree->ToView());
440 
441 	fGroupByNameCheckBox = new BCheckBox("group by name checkbox",
442 		"Group by name", new BMessage(MSG_ABSTRACT_WAIT_OBJECTS_GROUP_BY_NAME));
443 	fGroupByNameCheckBox->SetValue(
444 		fGroupByName ? B_CONTROL_ON : B_CONTROL_OFF);
445 	AddChild(fGroupByNameCheckBox);
446 
447 	fWaitObjectsTree->AddColumn(new StringTableColumn(0, "Type", 80, 40, 1000,
448 		B_TRUNCATE_END, B_ALIGN_LEFT));
449 	fWaitObjectsTree->AddColumn(new StringTableColumn(1, "Name", 80, 40, 1000,
450 		B_TRUNCATE_END, B_ALIGN_LEFT));
451 	fWaitObjectsTree->AddColumn(new StringTableColumn(2, "Object", 80, 40, 1000,
452 		B_TRUNCATE_END, B_ALIGN_LEFT));
453 	fWaitObjectsTree->AddColumn(new StringTableColumn(3, "Referenced", 80, 40,
454 		1000, B_TRUNCATE_END, B_ALIGN_LEFT));
455 	fWaitObjectsTree->AddColumn(new Int64TableColumn(4, "Waits", 80, 20,
456 		1000, B_TRUNCATE_END, B_ALIGN_RIGHT));
457 	fWaitObjectsTree->AddColumn(new NanotimeTableColumn(5, "Wait time", 80,
458 		20, 1000, false, B_TRUNCATE_END, B_ALIGN_RIGHT));
459 
460 	fWaitObjectsTree->AddTreeTableListener(this);
461 }
462 
463 
464 ABSTRACT_WAIT_OBJECTS_PAGE_TEMPLATE
465 ABSTRACT_WAIT_OBJECTS_PAGE_CLASS::~AbstractWaitObjectsPage()
466 {
467 	fWaitObjectsTree->SetTreeTableModel(NULL);
468 	delete fWaitObjectsTreeModel;
469 }
470 
471 
472 ABSTRACT_WAIT_OBJECTS_PAGE_TEMPLATE
473 void
474 ABSTRACT_WAIT_OBJECTS_PAGE_CLASS::SetModel(ModelType* model)
475 {
476 	if (model == fModel)
477 		return;
478 
479 	if (fModel != NULL) {
480 		fWaitObjectsTree->SetTreeTableModel(NULL);
481 		delete fWaitObjectsTreeModel;
482 		fWaitObjectsTreeModel = NULL;
483 	}
484 
485 	fModel = model;
486 
487 	if (fModel != NULL)
488 		_UpdateTreeModel();
489 }
490 
491 
492 ABSTRACT_WAIT_OBJECTS_PAGE_TEMPLATE
493 void
494 ABSTRACT_WAIT_OBJECTS_PAGE_CLASS::MessageReceived(BMessage* message)
495 {
496 	switch (message->what) {
497 		case MSG_ABSTRACT_WAIT_OBJECTS_GROUP_BY_NAME:
498 			fGroupByName = fGroupByNameCheckBox->Value() == B_CONTROL_ON;
499 			_UpdateTreeModel();
500 			break;
501 		default:
502 			BGroupView::MessageReceived(message);
503 			break;
504 	}
505 }
506 
507 
508 ABSTRACT_WAIT_OBJECTS_PAGE_TEMPLATE
509 void
510 ABSTRACT_WAIT_OBJECTS_PAGE_CLASS::AttachedToWindow()
511 {
512 	fGroupByNameCheckBox->SetTarget(this);
513 }
514 
515 
516 ABSTRACT_WAIT_OBJECTS_PAGE_TEMPLATE
517 void
518 ABSTRACT_WAIT_OBJECTS_PAGE_CLASS::_UpdateTreeModel()
519 {
520 	if (fModel != NULL) {
521 		fWaitObjectsTree->SetTreeTableModel(NULL);
522 		delete fWaitObjectsTreeModel;
523 		fWaitObjectsTreeModel = NULL;
524 	}
525 
526 	if (fModel != NULL) {
527 		try {
528 			fWaitObjectsTreeModel = new WaitObjectsTreeModel(fModel,
529 				fGroupByName);
530 		} catch (std::bad_alloc) {
531 			// TODO: Report error!
532 		}
533 		fWaitObjectsTree->SetTreeTableModel(fWaitObjectsTreeModel);
534 		fWaitObjectsTree->ResizeAllColumnsToPreferred();
535 	}
536 }
537 
538 
539 #endif	// ABSTRACT_WAIT_OBJECTS_PAGE_H
540