xref: /haiku/src/apps/debugger/user_interface/gui/teams_window/TeamsListView.cpp (revision 97f11716bfaa0f385eb0e28a52bf56a5023b9e99)
1 /*
2  * Copyright 2009-2010, Philippe Houdoin, phoudoin@haiku-os.org. All rights reserved.
3  * Copyright 2013-2018, Rene Gollent, rene@gollent.com.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 #include "TeamsListView.h"
8 
9 #include <algorithm>
10 #include <new>
11 
12 #include <stdio.h>
13 #include <string.h>
14 
15 #include <AppMisc.h>
16 #include <Bitmap.h>
17 #include <ColumnTypes.h>
18 #include <ControlLook.h>
19 #include <FindDirectory.h>
20 #include <MimeType.h>
21 #include <MessageRunner.h>
22 #include <NodeInfo.h>
23 #include <Path.h>
24 #include <Roster.h>
25 #include <String.h>
26 
27 #include <AutoLocker.h>
28 
29 #include "TargetHostInterface.h"
30 
31 
32 enum {
33 	MSG_SELECTED_INTERFACE_CHANGED = 'seic',
34 	MSG_TEAM_ADDED = 'tead',
35 	MSG_TEAM_REMOVED = 'tere',
36 	MSG_TEAM_RENAMED = 'tern'
37 };
38 
39 
40 // #pragma mark - BitmapStringField
41 
42 
BBitmapStringField(BBitmap * bitmap,const char * string)43 BBitmapStringField::BBitmapStringField(BBitmap* bitmap, const char* string)
44 	:
45 	Inherited(string),
46 	fBitmap(bitmap)
47 {
48 }
49 
50 
~BBitmapStringField()51 BBitmapStringField::~BBitmapStringField()
52 {
53 	delete fBitmap;
54 }
55 
56 
57 void
SetBitmap(BBitmap * bitmap)58 BBitmapStringField::SetBitmap(BBitmap* bitmap)
59 {
60 	delete fBitmap;
61 	fBitmap = bitmap;
62 	// TODO: cause a redraw?
63 }
64 
65 
66 // #pragma mark - TeamsColumn
67 
68 
69 float TeamsColumn::sTextMargin = 0.0;
70 
71 
TeamsColumn(const char * title,float width,float minWidth,float maxWidth,uint32 truncateMode,alignment align)72 TeamsColumn::TeamsColumn(const char* title, float width, float minWidth,
73 		float maxWidth, uint32 truncateMode, alignment align)
74 	:
75 	Inherited(title, width, minWidth, maxWidth, align),
76 	fTruncateMode(truncateMode)
77 {
78 	SetWantsEvents(true);
79 }
80 
81 
82 void
DrawField(BField * field,BRect rect,BView * parent)83 TeamsColumn::DrawField(BField* field, BRect rect, BView* parent)
84 {
85 	BBitmapStringField* bitmapField
86 		= dynamic_cast<BBitmapStringField*>(field);
87 	BStringField* stringField = dynamic_cast<BStringField*>(field);
88 
89 	if (bitmapField) {
90 		const BBitmap* bitmap = bitmapField->Bitmap();
91 
92 		// figure out the placement
93 		float x = 0.0;
94 		BRect r = bitmap ? bitmap->Bounds() : BRect(0, 0, 15, 15);
95 		float y = rect.top + ((rect.Height() - r.Height()) / 2);
96 		float width = 0.0;
97 
98 		switch (Alignment()) {
99 			default:
100 			case B_ALIGN_LEFT:
101 			case B_ALIGN_CENTER:
102 				x = rect.left + sTextMargin;
103 				width = rect.right - (x + r.Width()) - (2 * sTextMargin);
104 				r.Set(x + r.Width(), rect.top, rect.right - width, rect.bottom);
105 				break;
106 
107 			case B_ALIGN_RIGHT:
108 				x = rect.right - sTextMargin - r.Width();
109 				width = (x - rect.left - (2 * sTextMargin));
110 				r.Set(rect.left, rect.top, rect.left + width, rect.bottom);
111 				break;
112 		}
113 
114 		if (width != bitmapField->Width()) {
115 			BString truncatedString(bitmapField->String());
116 			parent->TruncateString(&truncatedString, fTruncateMode, width + 2);
117 			bitmapField->SetClippedString(truncatedString.String());
118 			bitmapField->SetWidth(width);
119 		}
120 
121 		// draw the bitmap
122 		if (bitmap) {
123 			parent->SetDrawingMode(B_OP_ALPHA);
124 			parent->DrawBitmap(bitmap, BPoint(x, y));
125 			parent->SetDrawingMode(B_OP_OVER);
126 		}
127 
128 		// draw the string
129 		DrawString(bitmapField->ClippedString(), parent, r);
130 
131 	} else if (stringField) {
132 
133 		float width = rect.Width() - (2 * sTextMargin);
134 
135 		if (width != stringField->Width()) {
136 			BString truncatedString(stringField->String());
137 
138 			parent->TruncateString(&truncatedString, fTruncateMode, width + 2);
139 			stringField->SetClippedString(truncatedString.String());
140 			stringField->SetWidth(width);
141 		}
142 
143 		DrawString(stringField->ClippedString(), parent, rect);
144 	}
145 }
146 
147 
148 float
GetPreferredWidth(BField * _field,BView * parent) const149 TeamsColumn::GetPreferredWidth(BField *_field, BView* parent) const
150 {
151 	BBitmapStringField* bitmapField
152 		= dynamic_cast<BBitmapStringField*>(_field);
153 	BStringField* stringField = dynamic_cast<BStringField*>(_field);
154 
155 	float parentWidth = Inherited::GetPreferredWidth(_field, parent);
156 	float width = 0.0;
157 
158 	if (bitmapField) {
159 		const BBitmap* bitmap = bitmapField->Bitmap();
160 		BFont font;
161 		parent->GetFont(&font);
162 		width = font.StringWidth(bitmapField->String()) + 3 * sTextMargin;
163 		if (bitmap)
164 			width += bitmap->Bounds().Width();
165 		else
166 			width += 16;
167 	} else if (stringField) {
168 		BFont font;
169 		parent->GetFont(&font);
170 		width = font.StringWidth(stringField->String()) + 2 * sTextMargin;
171 	}
172 	return max_c(width, parentWidth);
173 }
174 
175 
176 bool
AcceptsField(const BField * field) const177 TeamsColumn::AcceptsField(const BField* field) const
178 {
179 	return dynamic_cast<const BStringField*>(field) != NULL;
180 }
181 
182 
183 void
InitTextMargin(BView * parent)184 TeamsColumn::InitTextMargin(BView* parent)
185 {
186 	BFont font;
187 	parent->GetFont(&font);
188 	sTextMargin = ceilf(font.Size() * 0.8);
189 }
190 
191 
192 // #pragma mark - TeamRow
193 
194 
195 enum {
196 	kNameColumn,
197 	kIDColumn
198 };
199 
200 
TeamRow(TeamInfo * info)201 TeamRow::TeamRow(TeamInfo* info)
202 	: BRow(ceilf(be_control_look->DefaultLabelSpacing() * 3.3f))
203 {
204 	_SetTo(info);
205 }
206 
207 
208 bool
NeedsUpdate(TeamInfo * info)209 TeamRow::NeedsUpdate(TeamInfo* info)
210 {
211 	// Check if we need to rebuilt the row's fields because the team critical
212 	// info (basically, app image running under that team ID) has changed
213 
214 	if (info->Arguments() != fTeamInfo.Arguments()) {
215 		_SetTo(info);
216 		return true;
217 	}
218 
219 	return false;
220 }
221 
222 
223 status_t
_SetTo(TeamInfo * info)224 TeamRow::_SetTo(TeamInfo* info)
225 {
226 	fTeamInfo = *info;
227 
228 	app_info appInfo;
229 	status_t status = be_roster->GetRunningAppInfo(fTeamInfo.TeamID(),
230 		&appInfo);
231 	if (status != B_OK) {
232 		// Not an application known to be_roster
233 
234 		if (fTeamInfo.TeamID() == B_SYSTEM_TEAM) {
235 			// Get icon and name from kernel image
236 			system_info	systemInfo;
237 			get_system_info(&systemInfo);
238 
239 			BPath kernelPath;
240 			find_directory(B_BEOS_SYSTEM_DIRECTORY, &kernelPath);
241 			kernelPath.Append(systemInfo.kernel_name);
242 
243 			get_ref_for_path(kernelPath.Path(), &appInfo.ref);
244 
245 		} else
246 			BPrivate::get_app_ref(fTeamInfo.TeamID(), &appInfo.ref);
247 	}
248 
249 	BBitmap* icon = new BBitmap(BRect(BPoint(0, 0),
250 		be_control_look->ComposeIconSize(B_MINI_ICON)), B_RGBA32);
251 
252 	icon_size iconSize = (icon_size)(icon->Bounds().Width() + 1);
253 	status = BNodeInfo::GetTrackerIcon(&appInfo.ref, icon, iconSize);
254 	if (status != B_OK) {
255 		BMimeType genericAppType(B_APP_MIME_TYPE);
256 		status = genericAppType.GetIcon(icon, iconSize);
257 	}
258 
259 	if (status != B_OK) {
260 		delete icon;
261 		icon = NULL;
262 	}
263 
264 	BString tmp;
265 	tmp << fTeamInfo.TeamID();
266 
267 	SetField(new BBitmapStringField(icon, fTeamInfo.Arguments()), kNameColumn);
268 	SetField(new BStringField(tmp), kIDColumn);
269 
270 	return status;
271 }
272 
273 
274 //	#pragma mark - TeamsListView
275 
276 
TeamsListView(const char * name)277 TeamsListView::TeamsListView(const char* name)
278 	:
279 	Inherited(name, B_NAVIGABLE, B_PLAIN_BORDER),
280 	TargetHost::Listener(),
281 	TeamsWindow::Listener(),
282 	fInterface(NULL),
283 	fHost(NULL)
284 {
285 	AddColumn(new TeamsColumn("Name", 400, 100, 600,
286 		B_TRUNCATE_BEGINNING), kNameColumn);
287 	AddColumn(new TeamsColumn("ID", 80, 40, 100,
288 		B_TRUNCATE_MIDDLE, B_ALIGN_RIGHT), kIDColumn);
289 	SetSortingEnabled(false);
290 }
291 
292 
~TeamsListView()293 TeamsListView::~TeamsListView()
294 {
295 	if (fHost != NULL)
296 		fHost->ReleaseReference();
297 }
298 
299 
300 void
AttachedToWindow()301 TeamsListView::AttachedToWindow()
302 {
303 	Inherited::AttachedToWindow();
304 	TeamsColumn::InitTextMargin(ScrollView());
305 }
306 
307 
308 void
DetachedFromWindow()309 TeamsListView::DetachedFromWindow()
310 {
311 	Inherited::DetachedFromWindow();
312 	_SetInterface(NULL);
313 }
314 
315 
316 void
MessageReceived(BMessage * message)317 TeamsListView::MessageReceived(BMessage* message)
318 {
319 	switch (message->what) {
320 		case MSG_SELECTED_INTERFACE_CHANGED:
321 		{
322 			TargetHostInterface* interface;
323 			if (message->FindPointer("interface", reinterpret_cast<void**>(
324 					&interface)) == B_OK) {
325 				_SetInterface(interface);
326 			}
327 			break;
328 		}
329 
330 		case MSG_TEAM_ADDED:
331 		{
332 			TeamInfo* info;
333 			team_id team;
334 			if (message->FindInt32("team", &team) != B_OK)
335 				break;
336 
337 			TargetHost* host = fInterface->GetTargetHost();
338 			AutoLocker<TargetHost> hostLocker(host);
339 			info = host->TeamInfoByID(team);
340 			if (info == NULL)
341 				break;
342 
343 			TeamRow* row = new TeamRow(info);
344 			AddRow(row);
345 			break;
346 		}
347 
348 		case MSG_TEAM_REMOVED:
349 		{
350 			team_id team;
351 			if (message->FindInt32("team", &team) != B_OK)
352 				break;
353 
354 			TeamRow* row = FindTeamRow(team);
355 			if (row != NULL) {
356 				RemoveRow(row);
357 				delete row;
358 			}
359 			break;
360 		}
361 
362 		case MSG_TEAM_RENAMED:
363 		{
364 			TeamInfo* info;
365 			team_id team;
366 			if (message->FindInt32("team", &team) != B_OK)
367 				break;
368 
369 			TargetHost* host = fInterface->GetTargetHost();
370 			AutoLocker<TargetHost> hostLocker(host);
371 			info = host->TeamInfoByID(team);
372 			if (info == NULL)
373 				break;
374 
375 			TeamRow* row = FindTeamRow(info->TeamID());
376 			if (row != NULL && row->NeedsUpdate(info))
377 				UpdateRow(row);
378 
379 			break;
380 		}
381 
382 		default:
383 			Inherited::MessageReceived(message);
384 	}
385 }
386 
387 
388 TeamRow*
FindTeamRow(team_id teamId)389 TeamsListView::FindTeamRow(team_id teamId)
390 {
391 	for (int32 i = CountRows(); i-- > 0;) {
392 		TeamRow* row = dynamic_cast<TeamRow*>(RowAt(i));
393 		if (row == NULL)
394 			continue;
395 
396 		if (row->TeamID() == teamId)
397 			return row;
398 	}
399 
400 	return NULL;
401 }
402 
403 
404 void
TeamAdded(TeamInfo * info)405 TeamsListView::TeamAdded(TeamInfo* info)
406 {
407 	BMessage message(MSG_TEAM_ADDED);
408 	message.AddInt32("team", info->TeamID());
409 	BMessenger(this).SendMessage(&message);
410 }
411 
412 
413 void
TeamRemoved(team_id team)414 TeamsListView::TeamRemoved(team_id team)
415 {
416 	BMessage message(MSG_TEAM_REMOVED);
417 	message.AddInt32("team", team);
418 	BMessenger(this).SendMessage(&message);
419 }
420 
421 
422 void
TeamRenamed(TeamInfo * info)423 TeamsListView::TeamRenamed(TeamInfo* info)
424 {
425 	BMessage message(MSG_TEAM_RENAMED);
426 	message.AddInt32("team", info->TeamID());
427 	BMessenger(this).SendMessage(&message);
428 }
429 
430 
431 void
SelectedInterfaceChanged(TargetHostInterface * interface)432 TeamsListView::SelectedInterfaceChanged(TargetHostInterface* interface)
433 {
434 	BMessage message(MSG_SELECTED_INTERFACE_CHANGED);
435 	message.AddPointer("interface", interface);
436 	BMessenger(this).SendMessage(&message);
437 }
438 
439 
440 void
_InitList()441 TeamsListView::_InitList()
442 {
443 	AutoLocker<TargetHost> hostLocker(fHost);
444 	for (int32 i = 0; TeamInfo* info = fHost->TeamInfoAt(i); i++) {
445 		BRow* row = new TeamRow(info);
446 		AddRow(row);
447 	}
448 }
449 
450 
451 void
_SetInterface(TargetHostInterface * interface)452 TeamsListView::_SetInterface(TargetHostInterface* interface)
453 {
454 	if (interface == fInterface)
455 		return;
456 
457 	if (fInterface != NULL) {
458 		Clear();
459 		fHost->RemoveListener(this);
460 		fHost->ReleaseReference();
461 		fHost = NULL;
462 	}
463 
464 	fInterface = interface;
465 	if (fInterface == NULL)
466 		return;
467 
468 	fHost = fInterface->GetTargetHost();
469 	fHost->AcquireReference();
470 	fHost->AddListener(this);
471 	_InitList();
472 }
473