2 * Copyright 2008-2009 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
10 #include <Application.h>
12 #include <LayoutBuilder.h>
14 #include <ScrollView.h>
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
)
30 RebuildDevicesOutline();
35 DevicesView::CreateLayout()
37 BMenuBar
* menuBar
= new BMenuBar("menu");
38 BMenu
* menu
= new BMenu(B_TRANSLATE("Devices"));
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
:
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)
97 .AddSplit(B_HORIZONTAL
)
98 .SetInsets(B_USE_WINDOW_SPACING
)
100 .Add(fOrderByMenu
, 1)
108 DevicesView::RescanDevices()
110 // Empty the outline and delete the devices in the list, incl. categories
111 fDevicesOutline
->MakeEmpty();
115 // Fill the devices list
117 device_node_cookie rootCookie
;
118 if ((error
= init_dm_wrapper()) < 0) {
119 std::cerr
<< "Error initializing device manager: " << strerror(error
)
124 get_root(&rootCookie
);
125 AddDeviceAndChildren(&rootCookie
, NULL
);
134 DevicesView::DeleteDevices()
136 while (fDevices
.size() > 0) {
137 delete fDevices
.back();
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
;
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
,
169 DevicesView::DeleteCategoryMap()
171 CategoryMapIterator iter
;
172 for (iter
= fCategoryMap
.begin(); iter
!= fCategoryMap
.end(); iter
++) {
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";
190 return Compare(stringItem1
->Text(), stringItem2
->Text());
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()) {
222 << "Tried to add device without category, file a bug\n";
225 fDevicesOutline
->AddUnder(fDevices
[i
], iter
->second
);
228 fDevicesOutline
->SortItemsUnder(NULL
, true, SortItemsCompare
);
230 // TODO: Implement BY_BUS
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
]);
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
255 struct device_attr_info attr
;
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
) {
265 attrString
<< attr
.value
.string
;
268 attrString
<< attr
.value
.ui8
;
271 attrString
<< attr
.value
.ui16
;
274 attrString
<< attr
.value
.ui32
;
277 attrString
<< attr
.value
.ui64
;
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
++) {
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"));
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"));
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"));
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"));
320 if (attributes
[i
].fName
== B_DEVICE_BUS
321 && attributes
[i
].fValue
== "pci") {
322 newDevice
= new DevicePCI(parent
);
327 if (attributes
[i
].fName
== B_DEVICE_BUS
328 && attributes
[i
].fValue
== "acpi") {
329 newDevice
= new DeviceACPI(parent
);
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
);
340 if (attributes
[i
].fName
== B_DEVICE_BUS
341 && attributes
[i
].fValue
== "scsi") {
342 newDevice
= new DeviceSCSI(parent
);
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
);
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
);
369 device_node_cookie child
= *node
;
371 if (get_child(&child
) != B_OK
)
375 AddDeviceAndChildren(&child
, newDevice
);
376 } while ((err
= get_next_child(&child
)) == B_OK
);
380 DevicesView::~DevicesView()
387 DevicesView::MessageReceived(BMessage
*msg
)
390 case kMsgSelectionChanged
:
392 int32 selected
= fDevicesOutline
->CurrentSelection(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();
405 case kMsgOrderCategory
:
407 fOrderBy
= ORDER_BY_CATEGORY
;
409 RebuildDevicesOutline();
413 case kMsgOrderConnection
:
415 fOrderBy
= ORDER_BY_CONNECTION
;
417 RebuildDevicesOutline();
424 RebuildDevicesOutline();
428 case kMsgReportCompatibility
:
433 case kMsgGenerateSysInfo
:
439 BView::MessageReceived(msg
);