BTRFS: Implement BTree::Path and change _Find.
[haiku.git] / src / apps / devices / DevicesView.cpp
bloba487813710503c5afdd991dcab169ee5cc0200d2
1 /*
2 * Copyright 2008-2009 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
5 * Authors:
6 * Pieter Panman
7 */
10 #include <Application.h>
11 #include <Catalog.h>
12 #include <LayoutBuilder.h>
13 #include <MenuBar.h>
14 #include <ScrollView.h>
15 #include <String.h>
17 #include <iostream>
19 #include "DevicesView.h"
21 #undef B_TRANSLATION_CONTEXT
22 #define B_TRANSLATION_CONTEXT "DevicesView"
24 DevicesView::DevicesView()
26 BView("DevicesView", B_WILL_DRAW | B_FRAME_EVENTS)
28 CreateLayout();
29 RescanDevices();
30 RebuildDevicesOutline();
34 void
35 DevicesView::CreateLayout()
37 BMenuBar* menuBar = new BMenuBar("menu");
38 BMenu* menu = new BMenu(B_TRANSLATE("Devices"));
39 BMenuItem* item;
40 menu->AddItem(new BMenuItem(B_TRANSLATE("Refresh devices"),
41 new BMessage(kMsgRefresh), 'R'));
42 menu->AddItem(item = new BMenuItem(B_TRANSLATE("Report compatibility"),
43 new BMessage(kMsgReportCompatibility)));
44 item->SetEnabled(false);
45 menu->AddItem(item = new BMenuItem(B_TRANSLATE(
46 "Generate system information"), new BMessage(kMsgGenerateSysInfo)));
47 item->SetEnabled(false);
48 menu->AddSeparatorItem();
49 menu->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
50 new BMessage(B_QUIT_REQUESTED), 'Q'));
51 menu->SetTargetForItems(this);
52 item->SetTarget(be_app);
53 menuBar->AddItem(menu);
55 fDevicesOutline = new BOutlineListView("devices_list");
56 fDevicesOutline->SetTarget(this);
57 fDevicesOutline->SetSelectionMessage(new BMessage(kMsgSelectionChanged));
59 BScrollView *scrollView = new BScrollView("devicesScrollView",
60 fDevicesOutline, B_WILL_DRAW | B_FRAME_EVENTS, true, true);
61 // Horizontal scrollbar doesn't behave properly like the vertical
62 // scrollbar... If you make the view bigger (exposing a larger percentage
63 // of the view), it does not adjust the width of the scroll 'dragger'
64 // why? Bug? In scrollview or in outlinelistview?
66 BPopUpMenu* orderByPopupMenu = new BPopUpMenu("orderByMenu");
67 BMenuItem* byCategory = new BMenuItem(B_TRANSLATE("Category"),
68 new BMessage(kMsgOrderCategory));
69 BMenuItem* byConnection = new BMenuItem(B_TRANSLATE("Connection"),
70 new BMessage(kMsgOrderConnection));
71 byCategory->SetMarked(true);
72 fOrderBy = byCategory->IsMarked() ? ORDER_BY_CATEGORY :
73 ORDER_BY_CONNECTION;
74 orderByPopupMenu->AddItem(byCategory);
75 orderByPopupMenu->AddItem(byConnection);
76 fOrderByMenu = new BMenuField(B_TRANSLATE("Order by:"), orderByPopupMenu);
78 fTabView = new BTabView("fTabView", B_WIDTH_FROM_LABEL);
80 fBasicTab = new BTab();
81 fBasicView = new PropertyListPlain("basicView");
82 fTabView->AddTab(fBasicView, fBasicTab);
83 fBasicTab->SetLabel(B_TRANSLATE("Basic information"));
85 fDeviceTypeTab = new BTab();
86 fBusView = new PropertyListPlain("busView");
87 fTabView->AddTab(fBusView, fDeviceTypeTab);
88 fDeviceTypeTab->SetLabel(B_TRANSLATE("Bus"));
90 fDetailedTab = new BTab();
91 fAttributesView = new PropertyList("attributesView");
92 fTabView->AddTab(fAttributesView, fDetailedTab);
93 fDetailedTab->SetLabel(B_TRANSLATE("Detailed"));
95 BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
96 .Add(menuBar)
97 .AddSplit(B_HORIZONTAL)
98 .SetInsets(B_USE_WINDOW_SPACING)
99 .AddGroup(B_VERTICAL)
100 .Add(fOrderByMenu, 1)
101 .Add(scrollView, 2)
102 .End()
103 .Add(fTabView, 2);
107 void
108 DevicesView::RescanDevices()
110 // Empty the outline and delete the devices in the list, incl. categories
111 fDevicesOutline->MakeEmpty();
112 DeleteDevices();
113 DeleteCategoryMap();
115 // Fill the devices list
116 status_t error;
117 device_node_cookie rootCookie;
118 if ((error = init_dm_wrapper()) < 0) {
119 std::cerr << "Error initializing device manager: " << strerror(error)
120 << std::endl;
121 return;
124 get_root(&rootCookie);
125 AddDeviceAndChildren(&rootCookie, NULL);
127 uninit_dm_wrapper();
129 CreateCategoryMap();
133 void
134 DevicesView::DeleteDevices()
136 while (fDevices.size() > 0) {
137 delete fDevices.back();
138 fDevices.pop_back();
143 void
144 DevicesView::CreateCategoryMap()
146 CategoryMapIterator iter;
147 for (unsigned int i = 0; i < fDevices.size(); i++) {
148 Category category = fDevices[i]->GetCategory();
149 if (category < 0 || category >= kCategoryStringLength) {
150 std::cerr << "CreateCategoryMap: device " << fDevices[i]->GetName()
151 << " returned an unknown category index (" << category << "). "
152 << "Skipping device." << std::endl;
153 continue;
156 const char* categoryName = kCategoryString[category];
158 iter = fCategoryMap.find(category);
159 if (iter == fCategoryMap.end()) {
160 // This category has not yet been added, add it.
161 fCategoryMap[category] = new Device(NULL, BUS_NONE, CAT_NONE,
162 categoryName);
168 void
169 DevicesView::DeleteCategoryMap()
171 CategoryMapIterator iter;
172 for (iter = fCategoryMap.begin(); iter != fCategoryMap.end(); iter++) {
173 delete iter->second;
175 fCategoryMap.clear();
180 DevicesView::SortItemsCompare(const BListItem *item1,
181 const BListItem *item2)
183 const BStringItem* stringItem1 = dynamic_cast<const BStringItem*>(item1);
184 const BStringItem* stringItem2 = dynamic_cast<const BStringItem*>(item2);
185 if (!(stringItem1 && stringItem2)) {
186 // is this check necessary?
187 std::cerr << "Could not cast BListItem to BStringItem, file a bug\n";
188 return 0;
190 return Compare(stringItem1->Text(), stringItem2->Text());
194 void
195 DevicesView::RebuildDevicesOutline()
197 // Rearranges existing Devices into the proper hierarchy
198 fDevicesOutline->MakeEmpty();
200 if (fOrderBy == ORDER_BY_CONNECTION) {
201 for (unsigned int i = 0; i < fDevices.size(); i++) {
202 if (fDevices[i]->GetPhysicalParent() == NULL) {
203 // process each parent device and its children
204 fDevicesOutline->AddItem(fDevices[i]);
205 AddChildrenToOutlineByConnection(fDevices[i]);
208 } else if (fOrderBy == ORDER_BY_CATEGORY) {
209 // Add all categories to the outline
210 CategoryMapIterator iter;
211 for (iter = fCategoryMap.begin(); iter != fCategoryMap.end(); iter++) {
212 fDevicesOutline->AddItem(iter->second);
215 // Add all devices under the categories
216 for (unsigned int i = 0; i < fDevices.size(); i++) {
217 Category category = fDevices[i]->GetCategory();
219 iter = fCategoryMap.find(category);
220 if (iter == fCategoryMap.end()) {
221 std::cerr
222 << "Tried to add device without category, file a bug\n";
223 continue;
224 } else {
225 fDevicesOutline->AddUnder(fDevices[i], iter->second);
228 fDevicesOutline->SortItemsUnder(NULL, true, SortItemsCompare);
230 // TODO: Implement BY_BUS
234 void
235 DevicesView::AddChildrenToOutlineByConnection(Device* parent)
237 for (unsigned int i = 0; i < fDevices.size(); i++) {
238 if (fDevices[i]->GetPhysicalParent() == parent) {
239 fDevicesOutline->AddUnder(fDevices[i], parent);
240 AddChildrenToOutlineByConnection(fDevices[i]);
246 void
247 DevicesView::AddDeviceAndChildren(device_node_cookie *node, Device* parent)
249 Attributes attributes;
250 Device* newDevice = NULL;
252 // Copy all its attributes,
253 // necessary because we can only request them once from the device manager
254 char data[256];
255 struct device_attr_info attr;
256 attr.cookie = 0;
257 attr.node_cookie = *node;
258 attr.value.raw.data = data;
259 attr.value.raw.length = sizeof(data);
261 while (dm_get_next_attr(&attr) == B_OK) {
262 BString attrString;
263 switch (attr.type) {
264 case B_STRING_TYPE:
265 attrString << attr.value.string;
266 break;
267 case B_UINT8_TYPE:
268 attrString << attr.value.ui8;
269 break;
270 case B_UINT16_TYPE:
271 attrString << attr.value.ui16;
272 break;
273 case B_UINT32_TYPE:
274 attrString << attr.value.ui32;
275 break;
276 case B_UINT64_TYPE:
277 attrString << attr.value.ui64;
278 break;
279 default:
280 attrString << "Raw data";
282 attributes.push_back(Attribute(attr.name, attrString));
285 // Determine what type of device it is and create it
286 for (unsigned int i = 0; i < attributes.size(); i++) {
287 // Devices Root
288 if (attributes[i].fName == B_DEVICE_PRETTY_NAME
289 && attributes[i].fValue == "Devices Root") {
290 newDevice = new Device(parent, BUS_NONE,
291 CAT_COMPUTER, B_TRANSLATE("Computer"));
292 break;
295 // ACPI Controller
296 if (attributes[i].fName == B_DEVICE_PRETTY_NAME
297 && attributes[i].fValue == "ACPI") {
298 newDevice = new Device(parent, BUS_ACPI,
299 CAT_BUS, B_TRANSLATE("ACPI bus"));
300 break;
303 // PCI bus
304 if (attributes[i].fName == B_DEVICE_PRETTY_NAME
305 && attributes[i].fValue == "PCI") {
306 newDevice = new Device(parent, BUS_PCI,
307 CAT_BUS, B_TRANSLATE("PCI bus"));
308 break;
311 // ISA bus
312 if (attributes[i].fName == B_DEVICE_BUS
313 && attributes[i].fValue == "isa") {
314 newDevice = new Device(parent, BUS_ISA,
315 CAT_BUS, B_TRANSLATE("ISA bus"));
316 break;
319 // PCI device
320 if (attributes[i].fName == B_DEVICE_BUS
321 && attributes[i].fValue == "pci") {
322 newDevice = new DevicePCI(parent);
323 break;
326 // ACPI device
327 if (attributes[i].fName == B_DEVICE_BUS
328 && attributes[i].fValue == "acpi") {
329 newDevice = new DeviceACPI(parent);
330 break;
333 // ATA / SCSI / IDE controller
334 if (attributes[i].fName == "controller_name") {
335 newDevice = new Device(parent, BUS_PCI,
336 CAT_MASS, attributes[i].fValue);
339 // SCSI device node
340 if (attributes[i].fName == B_DEVICE_BUS
341 && attributes[i].fValue == "scsi") {
342 newDevice = new DeviceSCSI(parent);
343 break;
346 // Last resort, lets look for a pretty name
347 if (attributes[i].fName == B_DEVICE_PRETTY_NAME) {
348 newDevice = new Device(parent, BUS_NONE,
349 CAT_NONE, attributes[i].fValue);
350 break;
354 // A completely unknown device
355 if (newDevice == NULL) {
356 newDevice = new Device(parent, BUS_NONE,
357 CAT_NONE, B_TRANSLATE("Unknown device"));
360 // Add its attributes to the device, initialize it and add to the list.
361 for (unsigned int i = 0; i < attributes.size(); i++) {
362 newDevice->SetAttribute(attributes[i].fName, attributes[i].fValue);
364 newDevice->InitFromAttributes();
365 fDevices.push_back(newDevice);
367 // Process children
368 status_t err;
369 device_node_cookie child = *node;
371 if (get_child(&child) != B_OK)
372 return;
374 do {
375 AddDeviceAndChildren(&child, newDevice);
376 } while ((err = get_next_child(&child)) == B_OK);
380 DevicesView::~DevicesView()
382 DeleteDevices();
386 void
387 DevicesView::MessageReceived(BMessage *msg)
389 switch (msg->what) {
390 case kMsgSelectionChanged:
392 int32 selected = fDevicesOutline->CurrentSelection(0);
393 if (selected >= 0) {
394 Device* device = (Device*)fDevicesOutline->ItemAt(selected);
395 fBasicView->AddAttributes(device->GetBasicAttributes());
396 fBusView->AddAttributes(device->GetBusAttributes());
397 fAttributesView->AddAttributes(device->GetAllAttributes());
398 fDeviceTypeTab->SetLabel(device->GetBusTabName());
399 // hmm the label doesn't automatically refresh
400 fTabView->Invalidate();
402 break;
405 case kMsgOrderCategory:
407 fOrderBy = ORDER_BY_CATEGORY;
408 RescanDevices();
409 RebuildDevicesOutline();
410 break;
413 case kMsgOrderConnection:
415 fOrderBy = ORDER_BY_CONNECTION;
416 RescanDevices();
417 RebuildDevicesOutline();
418 break;
421 case kMsgRefresh:
423 RescanDevices();
424 RebuildDevicesOutline();
425 break;
428 case kMsgReportCompatibility:
430 break;
433 case kMsgGenerateSysInfo:
435 break;
438 default:
439 BView::MessageReceived(msg);
440 break;