⛏️ index : haiku.git

/*
 * Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
 * Copyright 2005, Jérôme DUVAL.
 * All rights reserved. Distributed under the terms of the MIT License.
 */

#include "PackageViews.h"

#include <stdio.h>

#include <Catalog.h>
#include <ControlLook.h>
#include <Directory.h>
#include <Entry.h>
#include <fs_attr.h>
#include <GroupLayout.h>
#include <LayoutUtils.h>
#include <Locale.h>
#include <Messenger.h>
#include <package/PackageInfo.h>
#include <Path.h>
#include <ScrollBar.h>
#include <String.h>
#include <View.h>
#include <Window.h>

#include "InstallerDefs.h"
#include "StringForSize.h"


#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "PackagesView"

#define ICON_ATTRIBUTE "INSTALLER PACKAGE: ICON"


Package::Package(const BPath &path)
	:
	Group(),
	fSize(0),
	fIcon(NULL)
{
	SetPath(path);
}


Package::~Package()
{
	delete fIcon;
}


Package *
Package::PackageFromEntry(BEntry &entry)
{
	BPath path;
	entry.GetPath(&path);

	BPackageKit::BPackageInfo info;
	info.ReadFromPackageFile(path.Path());

	if (info.InitCheck() != B_OK)
		return NULL;

	Package *package = new Package(path);
	package->fName = info.Name();
	package->fDescription = info.Summary();

	bool alwaysOn = false;
	bool onByDefault = true;
	off_t size = 0;
	entry.GetSize(&size);
	char group[64];
	memset(group, 0, 64);

	BNode node(&entry);
	// FIXME enable these when the attributes on the packages are actually
	// populated by the buildsystem. For now, assume everything is
	// on-by-default and optional, and have no groups.
#if 0
	if (node.ReadAttr("INSTALLER PACKAGE: GROUP", B_STRING_TYPE, 0,
		group, 64) < 0) {
		goto err;
	}
	if (node.ReadAttr("INSTALLER PACKAGE: ON_BY_DEFAULT", B_BOOL_TYPE, 0,
		&onByDefault, sizeof(onByDefault)) < 0) {
		goto err;
	}
	if (node.ReadAttr("INSTALLER PACKAGE: ALWAYS_ON", B_BOOL_TYPE, 0,
		&alwaysOn, sizeof(alwaysOn)) < 0) {
		goto err;
	}
#endif
	package->SetGroupName(group);
	package->SetSize(size);
	package->SetAlwaysOn(alwaysOn);
	package->SetOnByDefault(onByDefault);

	attr_info attributes;
	if (node.GetAttrInfo(ICON_ATTRIBUTE, &attributes) == B_OK) {
		char buffer[attributes.size];
		BMessage msg;
		if ((node.ReadAttr(ICON_ATTRIBUTE, attributes.type, 0, buffer,
				attributes.size) == attributes.size)
			&& (msg.Unflatten(buffer) == B_OK)) {
			package->SetIcon(new BBitmap(&msg));
		}
	}
	return package;
#if 0
err:
#endif
	delete package;
	return NULL;
}


void
Package::GetSizeAsString(char* string, size_t stringSize)
{
	string_for_size(fSize, string, stringSize);
}


Group::Group()
{

}

Group::~Group()
{
}


PackageCheckBox::PackageCheckBox(Package *item)
	:
	BCheckBox("pack_cb", item->Name(), NULL),
	fPackage(item)
{
	SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
	SetFlags(Flags() | B_FULL_UPDATE_ON_RESIZE);
	SetIcon(fPackage->Icon());
}


PackageCheckBox::~PackageCheckBox()
{
	delete fPackage;
}


void
PackageCheckBox::Draw(BRect update)
{
	BCheckBox::Draw(update);

	// Draw the label
	char string[15];
	fPackage->GetSizeAsString(string, sizeof(string));
	float width = StringWidth(string);
	BRect sizeRect = Bounds();
	sizeRect.left = sizeRect.right - width;
	rgb_color documentText = ui_color(B_DOCUMENT_TEXT_COLOR);
	be_control_look->DrawLabel(this, string, NULL, sizeRect, update,
		ui_color(B_DOCUMENT_BACKGROUND_COLOR), be_control_look->Flags(this), &documentText);
}


void
PackageCheckBox::MouseMoved(BPoint point, uint32 transit,
	const BMessage* dragMessage)
{
	if (transit == B_ENTERED_VIEW) {
		BMessage msg(MSG_STATUS_MESSAGE);
		msg.AddString("status", fPackage->Description());
		BMessenger(NULL, Window()).SendMessage(&msg);
	} else if (transit == B_EXITED_VIEW) {
		BMessage msg(MSG_STATUS_MESSAGE);
		BMessenger(NULL, Window()).SendMessage(&msg);
	}
}


GroupView::GroupView(Group *group)
	:
	BStringView("group", group->GroupName()),
	fGroup(group)
{
	SetFont(be_bold_font);
}


GroupView::~GroupView()
{
	delete fGroup;
}


// #pragma mark -


PackagesView::PackagesView(const char* name)
	:
	BView(name, B_WILL_DRAW)
{
	BGroupLayout* layout = new BGroupLayout(B_VERTICAL);
	layout->SetSpacing(0);
	layout->SetInsets(B_USE_SMALL_SPACING, 0);
	SetLayout(layout);

	SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR);
	SetExplicitMinSize(BSize(B_SIZE_UNSET, 80));
}


PackagesView::~PackagesView()
{

}


void
PackagesView::Clean()
{
	BView* view;
	while ((view = ChildAt(0))) {
		if (dynamic_cast<GroupView*>(view)
			|| dynamic_cast<PackageCheckBox*>(view)) {
			RemoveChild(view);
			delete view;
		}
	}
	ScrollTo(0, 0);

	BView* parent = Parent();
	BRect r = parent->Bounds();
	parent->FrameResized(r.Width(), r.Height());
}


void
PackagesView::AddPackages(BList& packages, BMessage* msg)
{
	int32 count = packages.CountItems();
	BString lastGroup = "";
	for (int32 i = 0; i < count; i++) {
		void* item = packages.ItemAt(i);
		Package* package = static_cast<Package*>(item);
		if (lastGroup != BString(package->GroupName())) {
			lastGroup = package->GroupName();
			Group* group = new Group();
			group->SetGroupName(package->GroupName());
			GroupView *view = new GroupView(group);
			AddChild(view);
		}
		PackageCheckBox* checkBox = new PackageCheckBox(package);
		checkBox->SetValue(package->OnByDefault()
			? B_CONTROL_ON : B_CONTROL_OFF);
		checkBox->SetEnabled(!package->AlwaysOn());
		checkBox->SetMessage(new BMessage(*msg));
		AddChild(checkBox);
	}
	Invalidate();

	// Force scrollbars to update
	BView* parent = Parent();
	BRect r = parent->Bounds();
	parent->FrameResized(r.Width(), r.Height());
}


void
PackagesView::GetTotalSizeAsString(char* string, size_t stringSize)
{
	int32 count = CountChildren();
	int32 size = 0;
	for (int32 i = 0; i < count; i++) {
		PackageCheckBox* cb = dynamic_cast<PackageCheckBox*>(ChildAt(i));
		if (cb && cb->Value())
			size += cb->GetPackage()->Size();
	}
	string_for_size(size, string, stringSize);
}


void
PackagesView::GetPackagesToInstall(BList* list, int32* size)
{
	int32 count = CountChildren();
	*size = 0;
	for (int32 i = 0; i < count; i++) {
		PackageCheckBox* cb = dynamic_cast<PackageCheckBox*>(ChildAt(i));
		if (cb && cb->Value()) {
			list->AddItem(cb->GetPackage());
			*size += cb->GetPackage()->Size();
		}
	}
}


void
PackagesView::Draw(BRect updateRect)
{
	if (CountChildren() > 0)
		return;
	rgb_color highColor = HighColor();
	be_control_look->DrawLabel(this,
		B_TRANSLATE("No optional packages available."),
		Bounds(), updateRect, ViewColor(), BControlLook::B_DISABLED,
		BAlignment(B_ALIGN_CENTER, B_ALIGN_MIDDLE), &highColor);
}