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