/* * Copyright 2009-2010, Philippe Houdoin, phoudoin@haiku-os.org. All rights reserved. * Copyright 2013-2018, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ #include "TeamsListView.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "TargetHostInterface.h" enum { MSG_SELECTED_INTERFACE_CHANGED = 'seic', MSG_TEAM_ADDED = 'tead', MSG_TEAM_REMOVED = 'tere', MSG_TEAM_RENAMED = 'tern' }; // #pragma mark - BitmapStringField BBitmapStringField::BBitmapStringField(BBitmap* bitmap, const char* string) : Inherited(string), fBitmap(bitmap) { } BBitmapStringField::~BBitmapStringField() { delete fBitmap; } void BBitmapStringField::SetBitmap(BBitmap* bitmap) { delete fBitmap; fBitmap = bitmap; // TODO: cause a redraw? } // #pragma mark - TeamsColumn float TeamsColumn::sTextMargin = 0.0; TeamsColumn::TeamsColumn(const char* title, float width, float minWidth, float maxWidth, uint32 truncateMode, alignment align) : Inherited(title, width, minWidth, maxWidth, align), fTruncateMode(truncateMode) { SetWantsEvents(true); } void TeamsColumn::DrawField(BField* field, BRect rect, BView* parent) { BBitmapStringField* bitmapField = dynamic_cast(field); BStringField* stringField = dynamic_cast(field); if (bitmapField) { const BBitmap* bitmap = bitmapField->Bitmap(); // figure out the placement float x = 0.0; BRect r = bitmap ? bitmap->Bounds() : BRect(0, 0, 15, 15); float y = rect.top + ((rect.Height() - r.Height()) / 2); float width = 0.0; switch (Alignment()) { default: case B_ALIGN_LEFT: case B_ALIGN_CENTER: x = rect.left + sTextMargin; width = rect.right - (x + r.Width()) - (2 * sTextMargin); r.Set(x + r.Width(), rect.top, rect.right - width, rect.bottom); break; case B_ALIGN_RIGHT: x = rect.right - sTextMargin - r.Width(); width = (x - rect.left - (2 * sTextMargin)); r.Set(rect.left, rect.top, rect.left + width, rect.bottom); break; } if (width != bitmapField->Width()) { BString truncatedString(bitmapField->String()); parent->TruncateString(&truncatedString, fTruncateMode, width + 2); bitmapField->SetClippedString(truncatedString.String()); bitmapField->SetWidth(width); } // draw the bitmap if (bitmap) { parent->SetDrawingMode(B_OP_ALPHA); parent->DrawBitmap(bitmap, BPoint(x, y)); parent->SetDrawingMode(B_OP_OVER); } // draw the string DrawString(bitmapField->ClippedString(), parent, r); } else if (stringField) { float width = rect.Width() - (2 * sTextMargin); if (width != stringField->Width()) { BString truncatedString(stringField->String()); parent->TruncateString(&truncatedString, fTruncateMode, width + 2); stringField->SetClippedString(truncatedString.String()); stringField->SetWidth(width); } DrawString(stringField->ClippedString(), parent, rect); } } float TeamsColumn::GetPreferredWidth(BField *_field, BView* parent) const { BBitmapStringField* bitmapField = dynamic_cast(_field); BStringField* stringField = dynamic_cast(_field); float parentWidth = Inherited::GetPreferredWidth(_field, parent); float width = 0.0; if (bitmapField) { const BBitmap* bitmap = bitmapField->Bitmap(); BFont font; parent->GetFont(&font); width = font.StringWidth(bitmapField->String()) + 3 * sTextMargin; if (bitmap) width += bitmap->Bounds().Width(); else width += 16; } else if (stringField) { BFont font; parent->GetFont(&font); width = font.StringWidth(stringField->String()) + 2 * sTextMargin; } return max_c(width, parentWidth); } bool TeamsColumn::AcceptsField(const BField* field) const { return dynamic_cast(field) != NULL; } void TeamsColumn::InitTextMargin(BView* parent) { BFont font; parent->GetFont(&font); sTextMargin = ceilf(font.Size() * 0.8); } // #pragma mark - TeamRow enum { kNameColumn, kIDColumn }; TeamRow::TeamRow(TeamInfo* info) : BRow(ceilf(be_control_look->DefaultLabelSpacing() * 3.3f)) { _SetTo(info); } bool TeamRow::NeedsUpdate(TeamInfo* info) { // Check if we need to rebuilt the row's fields because the team critical // info (basically, app image running under that team ID) has changed if (info->Arguments() != fTeamInfo.Arguments()) { _SetTo(info); return true; } return false; } status_t TeamRow::_SetTo(TeamInfo* info) { fTeamInfo = *info; app_info appInfo; status_t status = be_roster->GetRunningAppInfo(fTeamInfo.TeamID(), &appInfo); if (status != B_OK) { // Not an application known to be_roster if (fTeamInfo.TeamID() == B_SYSTEM_TEAM) { // Get icon and name from kernel image system_info systemInfo; get_system_info(&systemInfo); BPath kernelPath; find_directory(B_BEOS_SYSTEM_DIRECTORY, &kernelPath); kernelPath.Append(systemInfo.kernel_name); get_ref_for_path(kernelPath.Path(), &appInfo.ref); } else BPrivate::get_app_ref(fTeamInfo.TeamID(), &appInfo.ref); } BBitmap* icon = new BBitmap(BRect(BPoint(0, 0), be_control_look->ComposeIconSize(B_MINI_ICON)), B_RGBA32); icon_size iconSize = (icon_size)(icon->Bounds().Width() + 1); status = BNodeInfo::GetTrackerIcon(&appInfo.ref, icon, iconSize); if (status != B_OK) { BMimeType genericAppType(B_APP_MIME_TYPE); status = genericAppType.GetIcon(icon, iconSize); } if (status != B_OK) { delete icon; icon = NULL; } BString tmp; tmp << fTeamInfo.TeamID(); SetField(new BBitmapStringField(icon, fTeamInfo.Arguments()), kNameColumn); SetField(new BStringField(tmp), kIDColumn); return status; } // #pragma mark - TeamsListView TeamsListView::TeamsListView(const char* name) : Inherited(name, B_NAVIGABLE, B_PLAIN_BORDER), TargetHost::Listener(), TeamsWindow::Listener(), fInterface(NULL), fHost(NULL) { AddColumn(new TeamsColumn("Name", 400, 100, 600, B_TRUNCATE_BEGINNING), kNameColumn); AddColumn(new TeamsColumn("ID", 80, 40, 100, B_TRUNCATE_MIDDLE, B_ALIGN_RIGHT), kIDColumn); SetSortingEnabled(false); } TeamsListView::~TeamsListView() { if (fHost != NULL) fHost->ReleaseReference(); } void TeamsListView::AttachedToWindow() { Inherited::AttachedToWindow(); TeamsColumn::InitTextMargin(ScrollView()); } void TeamsListView::DetachedFromWindow() { Inherited::DetachedFromWindow(); _SetInterface(NULL); } void TeamsListView::MessageReceived(BMessage* message) { switch (message->what) { case MSG_SELECTED_INTERFACE_CHANGED: { TargetHostInterface* interface; if (message->FindPointer("interface", reinterpret_cast( &interface)) == B_OK) { _SetInterface(interface); } break; } case MSG_TEAM_ADDED: { TeamInfo* info; team_id team; if (message->FindInt32("team", &team) != B_OK) break; TargetHost* host = fInterface->GetTargetHost(); AutoLocker hostLocker(host); info = host->TeamInfoByID(team); if (info == NULL) break; TeamRow* row = new TeamRow(info); AddRow(row); break; } case MSG_TEAM_REMOVED: { team_id team; if (message->FindInt32("team", &team) != B_OK) break; TeamRow* row = FindTeamRow(team); if (row != NULL) { RemoveRow(row); delete row; } break; } case MSG_TEAM_RENAMED: { TeamInfo* info; team_id team; if (message->FindInt32("team", &team) != B_OK) break; TargetHost* host = fInterface->GetTargetHost(); AutoLocker hostLocker(host); info = host->TeamInfoByID(team); if (info == NULL) break; TeamRow* row = FindTeamRow(info->TeamID()); if (row != NULL && row->NeedsUpdate(info)) UpdateRow(row); break; } default: Inherited::MessageReceived(message); } } TeamRow* TeamsListView::FindTeamRow(team_id teamId) { for (int32 i = CountRows(); i-- > 0;) { TeamRow* row = dynamic_cast(RowAt(i)); if (row == NULL) continue; if (row->TeamID() == teamId) return row; } return NULL; } void TeamsListView::TeamAdded(TeamInfo* info) { BMessage message(MSG_TEAM_ADDED); message.AddInt32("team", info->TeamID()); BMessenger(this).SendMessage(&message); } void TeamsListView::TeamRemoved(team_id team) { BMessage message(MSG_TEAM_REMOVED); message.AddInt32("team", team); BMessenger(this).SendMessage(&message); } void TeamsListView::TeamRenamed(TeamInfo* info) { BMessage message(MSG_TEAM_RENAMED); message.AddInt32("team", info->TeamID()); BMessenger(this).SendMessage(&message); } void TeamsListView::SelectedInterfaceChanged(TargetHostInterface* interface) { BMessage message(MSG_SELECTED_INTERFACE_CHANGED); message.AddPointer("interface", interface); BMessenger(this).SendMessage(&message); } void TeamsListView::_InitList() { AutoLocker hostLocker(fHost); for (int32 i = 0; TeamInfo* info = fHost->TeamInfoAt(i); i++) { BRow* row = new TeamRow(info); AddRow(row); } } void TeamsListView::_SetInterface(TargetHostInterface* interface) { if (interface == fInterface) return; if (fInterface != NULL) { Clear(); fHost->RemoveListener(this); fHost->ReleaseReference(); fHost = NULL; } fInterface = interface; if (fInterface == NULL) return; fHost = fInterface->GetTargetHost(); fHost->AcquireReference(); fHost->AddListener(this); _InitList(); }