Adding Łukasz Zemczak's package installer to our tree. This was his Google
Summer of Code project. Thanks for your work Łukasz and I hope we can see more work from you. Still to do: - Create an icon. - Add pkg files to the MIME database with PackageInstaller as the default handler. The rdef here has the MIME type name for the pkg format should anyone else choose to add it :) - Support for running scripts included with packages. - Testing various different packages. - Fixing problems in the Haiku GUI layout system which affect the code used for various parts of the installer GUI (please bear with the commented out code for now.) - Adding this to the image. Tomorrow I will add Łukasz's InstalledPackages utility which can be used to view installed packages and uninstall them. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22525 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -12,6 +12,7 @@ SubInclude HAIKU_TOP src apps expander ;
|
||||
SubInclude HAIKU_TOP src apps fontdemo ;
|
||||
SubInclude HAIKU_TOP src apps glteapot ;
|
||||
SubInclude HAIKU_TOP src apps icon-o-matic ;
|
||||
SubInclude HAIKU_TOP src apps installedpackages ;
|
||||
SubInclude HAIKU_TOP src apps installer ;
|
||||
SubInclude HAIKU_TOP src apps launchbox ;
|
||||
SubInclude HAIKU_TOP src apps magnify ;
|
||||
@@ -21,6 +22,7 @@ SubInclude HAIKU_TOP src apps mediaconverter ;
|
||||
SubInclude HAIKU_TOP src apps mediaplayer ;
|
||||
SubInclude HAIKU_TOP src apps midiplayer ;
|
||||
SubInclude HAIKU_TOP src apps networkstatus ;
|
||||
SubInclude HAIKU_TOP src apps packageinstaller ;
|
||||
SubInclude HAIKU_TOP src apps people ;
|
||||
SubInclude HAIKU_TOP src apps poorman ;
|
||||
SubInclude HAIKU_TOP src apps powerstatus ;
|
||||
@@ -35,3 +37,5 @@ SubInclude HAIKU_TOP src apps terminal ;
|
||||
SubInclude HAIKU_TOP src apps tracker ;
|
||||
SubInclude HAIKU_TOP src apps tv ;
|
||||
SubInclude HAIKU_TOP src apps workspaces ;
|
||||
|
||||
SubInclude HAIKU_TOP src apps test_app ;
|
||||
|
||||
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
* Łukasz 'Sil2100' Zemczak <[email protected]>
|
||||
*/
|
||||
|
||||
|
||||
#include "InstalledPackageInfo.h"
|
||||
#include <Directory.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <Entry.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <posix/string.h>
|
||||
|
||||
|
||||
const char * kPackagesDir = "packages";
|
||||
|
||||
|
||||
static status_t
|
||||
info_prepare(const char *filename, BFile *file, BMessage *info)
|
||||
{
|
||||
if (!filename)
|
||||
return B_ERROR;
|
||||
|
||||
BPath path;
|
||||
if (find_directory(B_USER_CONFIG_DIRECTORY, &path) != B_OK
|
||||
|| path.Append(kPackagesDir) != B_OK
|
||||
|| path.Append(filename) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
file->SetTo(path.Path(), B_READ_ONLY);
|
||||
if (file->InitCheck() != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
status_t ret = info->Unflatten(file);
|
||||
if (ret != B_OK || info->what != P_PACKAGE_INFO)
|
||||
return B_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
info_get_package_name(const char *filename)
|
||||
{
|
||||
BFile file;
|
||||
BMessage info;
|
||||
if (info_prepare(filename, &file, &info) != B_OK)
|
||||
return NULL;
|
||||
BString name;
|
||||
info.FindString("package_name", &name);
|
||||
return name.String();
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
info_get_package_version(const char *filename)
|
||||
{
|
||||
BFile file;
|
||||
BMessage info;
|
||||
if (info_prepare(filename, &file, &info) != B_OK)
|
||||
return NULL;
|
||||
BString version;
|
||||
info.FindString("package_version", &version);
|
||||
return version.String();
|
||||
}
|
||||
|
||||
|
||||
InstalledPackageInfo::InstalledPackageInfo()
|
||||
:
|
||||
fStatus(B_NO_INIT),
|
||||
fIsUpToDate(false),
|
||||
fCreate(false),
|
||||
fInstalledItems(10)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
InstalledPackageInfo::InstalledPackageInfo(const char *packageName,
|
||||
const char *version, bool create)
|
||||
:
|
||||
fStatus(B_NO_INIT),
|
||||
fIsUpToDate(false),
|
||||
fInstalledItems(10)
|
||||
{
|
||||
SetTo(packageName, version, create);
|
||||
}
|
||||
|
||||
|
||||
InstalledPackageInfo::~InstalledPackageInfo()
|
||||
{
|
||||
_ClearItemList();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
InstalledPackageInfo::InitCheck()
|
||||
{
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
InstalledPackageInfo::SetTo(const char *packageName, const char *version,
|
||||
bool create)
|
||||
{
|
||||
_ClearItemList();
|
||||
fCreate = create;
|
||||
fStatus = B_NO_INIT;
|
||||
fVersion = version;
|
||||
|
||||
if (!packageName)
|
||||
return fStatus;
|
||||
|
||||
BPath configPath;
|
||||
if (find_directory(B_USER_CONFIG_DIRECTORY, &configPath) != B_OK) {
|
||||
fStatus = B_ERROR;
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
if (fPathToInfo.SetTo(configPath.Path(), kPackagesDir) != B_OK) {
|
||||
fStatus = B_ERROR;
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
// Check whether the directory exists
|
||||
BDirectory packageDir(fPathToInfo.Path());
|
||||
fStatus = packageDir.InitCheck();
|
||||
if (fStatus == B_ENTRY_NOT_FOUND) {
|
||||
// If not, create it
|
||||
packageDir.SetTo(configPath.Path());
|
||||
if (packageDir.CreateDirectory(kPackagesDir, &packageDir) != B_OK) {
|
||||
fStatus = B_ERROR;
|
||||
return fStatus;
|
||||
}
|
||||
}
|
||||
|
||||
BString filename = packageName;
|
||||
filename << version << ".pdb";
|
||||
if (fPathToInfo.Append(filename.String()) != B_OK) {
|
||||
fStatus = B_ERROR;
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
BFile package(fPathToInfo.Path(), B_READ_ONLY);
|
||||
fStatus = package.InitCheck();
|
||||
if (fStatus == B_OK) {
|
||||
// The given package exists, so we can unflatten the data to a message
|
||||
// and then pass it further
|
||||
BMessage info;
|
||||
if (info.Unflatten(&package) != B_OK || info.what != P_PACKAGE_INFO) {
|
||||
fStatus = B_ERROR;
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
int32 count;
|
||||
fStatus = info.FindString("package_name", &fName);
|
||||
fStatus |= info.FindString("package_desc", &fDescription);
|
||||
fStatus |= info.FindString("package_version", &fVersion);
|
||||
int64 spaceNeeded = 0;
|
||||
fStatus |= info.FindInt64("package_size", &spaceNeeded);
|
||||
fSpaceNeeded = static_cast<uint64>(spaceNeeded);
|
||||
fStatus |= info.FindInt32("file_count", &count);
|
||||
if (fStatus != B_OK) {
|
||||
fStatus = B_ERROR;
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
int32 i;
|
||||
BString itemPath;
|
||||
for (i = 0; i < count; i++) {
|
||||
if (info.FindString("items", i, &itemPath) != B_OK) {
|
||||
fStatus = B_ERROR;
|
||||
return fStatus;
|
||||
}
|
||||
fInstalledItems.AddItem(new BString(itemPath)); // Or maybe BPath better?
|
||||
}
|
||||
fIsUpToDate = true;
|
||||
}
|
||||
else if (fStatus == B_ENTRY_NOT_FOUND) {
|
||||
if (create) {
|
||||
fStatus = B_OK;
|
||||
fIsUpToDate = false;
|
||||
}
|
||||
}
|
||||
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
InstalledPackageInfo::AddItem(const char *itemName)
|
||||
{
|
||||
if (!itemName)
|
||||
return B_ERROR;
|
||||
|
||||
return fInstalledItems.AddItem(new BString(itemName));
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
InstalledPackageInfo::Uninstall()
|
||||
{
|
||||
if (fStatus != B_OK)
|
||||
return fStatus;
|
||||
|
||||
BString *iter;
|
||||
uint32 i, count = fInstalledItems.CountItems();
|
||||
BEntry entry;
|
||||
status_t ret;
|
||||
|
||||
// Try to remove all entries that are present in the list
|
||||
for (i = 0; i < count; i++) {
|
||||
iter = static_cast<BString *>(fInstalledItems.ItemAt(count - i - 1));
|
||||
fprintf(stderr, "Removing: %s (%d/%d)\n", iter->String(), i, count);
|
||||
ret = entry.SetTo(iter->String());
|
||||
if (ret == B_BUSY) {
|
||||
// The entry's directory is locked - wait a few cycles for it to
|
||||
// unlock itself
|
||||
int32 tries = 0;
|
||||
for (tries = 0; tries < P_BUSY_TRIES; tries++) {
|
||||
ret = entry.SetTo(iter->String());
|
||||
if (ret != B_BUSY)
|
||||
break;
|
||||
// Wait a moment
|
||||
usleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == B_ENTRY_NOT_FOUND)
|
||||
continue;
|
||||
else if (ret != B_OK) {
|
||||
fStatus = B_ERROR;
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
fprintf(stderr, "...we continue\n");
|
||||
|
||||
if (entry.Exists() && entry.Remove() != B_OK) {
|
||||
fprintf(stderr, "\n%s\n", strerror(ret));
|
||||
fStatus = B_ERROR;
|
||||
return fStatus;
|
||||
}
|
||||
fInstalledItems.RemoveItem(count - i - 1);
|
||||
}
|
||||
|
||||
if (entry.SetTo(fPathToInfo.Path()) != B_OK) {
|
||||
fStatus = B_ERROR;
|
||||
return fStatus;
|
||||
}
|
||||
if (entry.Exists() && entry.Remove() != B_OK) {
|
||||
fStatus = B_ERROR;
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
InstalledPackageInfo::Save()
|
||||
{
|
||||
// If the package info is not up to date and everything till now was
|
||||
// done correctly, we will save all data as a flattened BMessage to the
|
||||
// package info file
|
||||
if (fIsUpToDate || fStatus != B_OK)
|
||||
return fStatus;
|
||||
|
||||
BFile package;
|
||||
if (fCreate) {
|
||||
fStatus = package.SetTo(fPathToInfo.Path(), B_WRITE_ONLY | B_CREATE_FILE
|
||||
| B_ERASE_FILE);
|
||||
}
|
||||
else {
|
||||
fStatus = package.SetTo(fPathToInfo.Path(), B_WRITE_ONLY | B_ERASE_FILE);
|
||||
}
|
||||
|
||||
if (fStatus != B_OK)
|
||||
return fStatus;
|
||||
|
||||
status_t ret;
|
||||
int32 i, count = fInstalledItems.CountItems();
|
||||
BMessage info(P_PACKAGE_INFO);
|
||||
ret = info.AddString("package_name", fName);
|
||||
ret |= info.AddString("package_desc", fDescription);
|
||||
ret |= info.AddString("package_version", fVersion);
|
||||
ret |= info.AddInt64("package_size", fSpaceNeeded);
|
||||
ret |= info.AddInt32("file_count", count);
|
||||
if (ret != B_OK) {
|
||||
fStatus = B_ERROR;
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
BString *iter;
|
||||
for (i = 0; i < count; i++) {
|
||||
iter = static_cast<BString *>(fInstalledItems.ItemAt(i));
|
||||
if (info.AddString("items", *iter) != B_OK) {
|
||||
fStatus = B_ERROR;
|
||||
return fStatus;
|
||||
}
|
||||
}
|
||||
|
||||
if (info.Flatten(&package) != B_OK) {
|
||||
fStatus = B_ERROR;
|
||||
return fStatus;
|
||||
}
|
||||
fIsUpToDate = true;
|
||||
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
void
|
||||
InstalledPackageInfo::_ClearItemList()
|
||||
{
|
||||
// Clear the items list
|
||||
BString *iter;
|
||||
uint32 i, count = fInstalledItems.CountItems();
|
||||
for (i = 0; i < count; i++) {
|
||||
iter = static_cast<BString *>(fInstalledItems.ItemAt(0));
|
||||
fInstalledItems.RemoveItem((int32)0);
|
||||
delete iter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
* Łukasz 'Sil2100' Zemczak <[email protected]>
|
||||
*/
|
||||
#ifndef INSTALLEDPACKAGEINFO_H
|
||||
#define INSTALLEDPACKAGEINFO_H
|
||||
|
||||
#include <File.h>
|
||||
#include <String.h>
|
||||
#include <List.h>
|
||||
#include <Path.h>
|
||||
|
||||
|
||||
#define P_BUSY_TRIES 10
|
||||
|
||||
enum {
|
||||
P_PACKAGE_INFO = 'ppki'
|
||||
};
|
||||
|
||||
extern const char * kPackagesDir;
|
||||
|
||||
|
||||
// Useful function for fetching the package name and version without parsing all
|
||||
// other data
|
||||
const char * info_get_package_name(const char *filename);
|
||||
const char * info_get_package_version(const char *filename);
|
||||
|
||||
|
||||
class InstalledPackageInfo {
|
||||
public:
|
||||
InstalledPackageInfo();
|
||||
InstalledPackageInfo(const char *packageName, const char *version = NULL,
|
||||
bool create = false);
|
||||
~InstalledPackageInfo();
|
||||
|
||||
status_t InitCheck();
|
||||
status_t SetTo(const char *packageName, const char *version = NULL,
|
||||
bool create = false);
|
||||
|
||||
void SetName(const char *name) { fName = name; }
|
||||
const char *GetName() { return fName.String(); }
|
||||
void SetDescription(const char *description) { fDescription = description; }
|
||||
const char *GetDescription() { return fDescription.String(); }
|
||||
//void SetVersion(const char *version) { fVersion = version; }
|
||||
const char *GetVersion() { return fVersion.String(); }
|
||||
void SetSpaceNeeded(uint64 size) { fSpaceNeeded = size; }
|
||||
uint64 GetSpaceNeeded() { return fSpaceNeeded; }
|
||||
|
||||
status_t AddItem(const char *itemName);
|
||||
|
||||
status_t Uninstall();
|
||||
status_t Save();
|
||||
|
||||
private:
|
||||
void _ClearItemList();
|
||||
|
||||
status_t fStatus;
|
||||
bool fIsUpToDate;
|
||||
bool fCreate;
|
||||
|
||||
BString fName;
|
||||
BString fDescription;
|
||||
BString fVersion;
|
||||
uint64 fSpaceNeeded;
|
||||
BList fInstalledItems;
|
||||
|
||||
BPath fPathToInfo;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
SubDir HAIKU_TOP src apps packageinstaller ;
|
||||
|
||||
UsePrivateHeaders shared interface ;
|
||||
SubDirHdrs $(HAIKU_TOP) headers libs zlib ;
|
||||
|
||||
#SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits interface ] ;
|
||||
|
||||
Application PackageInstaller :
|
||||
main.cpp
|
||||
PackageWindow.cpp
|
||||
PackageView.cpp
|
||||
PackageInfo.cpp
|
||||
PackageItem.cpp
|
||||
PackageStatus.cpp
|
||||
PackageTextViewer.cpp
|
||||
PackageImageViewer.cpp
|
||||
InstalledPackageInfo.cpp
|
||||
: be tracker translation z
|
||||
: PackageInstaller.rdef
|
||||
;
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
* Łukasz 'Sil2100' Zemczak <[email protected]>
|
||||
*/
|
||||
|
||||
|
||||
#include "PackageImageViewer.h"
|
||||
|
||||
#include <BitmapStream.h>
|
||||
#include <Message.h>
|
||||
#include <Screen.h>
|
||||
#include <TranslatorRoster.h>
|
||||
|
||||
|
||||
// Reserved
|
||||
#define T(x) x
|
||||
|
||||
|
||||
enum {
|
||||
P_MSG_CLOSE = 'pmic'
|
||||
};
|
||||
|
||||
|
||||
|
||||
ImageView::ImageView(BPositionIO *image)
|
||||
: BView(BRect(0, 0, 1, 1), "image_view", B_FOLLOW_NONE, B_WILL_DRAW),
|
||||
fSuccess(true)
|
||||
{
|
||||
if (!image) {
|
||||
fSuccess = false;
|
||||
return;
|
||||
}
|
||||
// Initialize and translate the image
|
||||
BTranslatorRoster *roster = BTranslatorRoster::Default();
|
||||
BBitmapStream stream;
|
||||
if (roster->Translate(image, NULL, NULL, &stream, B_TRANSLATOR_BITMAP)
|
||||
< B_OK) {
|
||||
fSuccess = false;
|
||||
return;
|
||||
}
|
||||
stream.DetachBitmap(&fImage);
|
||||
}
|
||||
|
||||
|
||||
ImageView::~ImageView()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ImageView::AttachedToWindow()
|
||||
{
|
||||
if (!fSuccess) {
|
||||
ResizeTo(75, 75);
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to resize the view depending on what size has the screen and
|
||||
// the image we will be viewing
|
||||
BScreen screen(Window());
|
||||
BRect frame = screen.Frame();
|
||||
BRect image = fImage->Bounds();
|
||||
|
||||
if (image.Width() > (frame.Width() - 100.0f)) {
|
||||
image.right = frame.Width() - 100.0f;
|
||||
}
|
||||
if (image.Height() > (frame.Height() - 100.0f)) {
|
||||
image.bottom = frame.Height() - 100.f;
|
||||
}
|
||||
|
||||
ResizeTo(image.Width(), image.Height());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ImageView::Draw(BRect updateRect)
|
||||
{
|
||||
if (fSuccess)
|
||||
DrawBitmapAsync(fImage, Bounds());
|
||||
else {
|
||||
float length = StringWidth(T("Image not loaded correctly"));
|
||||
DrawString(T("Image not loaded correctly"),
|
||||
BPoint((Bounds().Width() - length) / 2.0f, 30.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ImageView::MouseUp(BPoint point)
|
||||
{
|
||||
BWindow *parent = Window();
|
||||
if (parent)
|
||||
parent->PostMessage(P_MSG_CLOSE);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
PackageImageViewer::PackageImageViewer(BPositionIO *image)
|
||||
: BWindow(BRect(100, 100, 100, 100), "", B_MODAL_WINDOW,
|
||||
B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_NOT_CLOSABLE)
|
||||
{
|
||||
fBackground = new ImageView(image);
|
||||
AddChild(fBackground);
|
||||
|
||||
ResizeTo(fBackground->Bounds().Width(), fBackground->Bounds().Height());
|
||||
|
||||
BScreen screen(this);
|
||||
BRect frame = screen.Frame();
|
||||
MoveTo((frame.Width() - Bounds().Width()) / 2.0f,
|
||||
(frame.Height() - Bounds().Height()) / 2.0f);
|
||||
}
|
||||
|
||||
|
||||
PackageImageViewer::~PackageImageViewer()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageImageViewer::Go()
|
||||
{
|
||||
// Since this class can be thought of as a modified BAlert window, no use
|
||||
// to reinvent a well fledged wheel. This concept has been borrowed from
|
||||
// the current BAlert implementation
|
||||
fSemaphore = create_sem(0, "ImageViewer");
|
||||
if (fSemaphore < B_OK) {
|
||||
Quit();
|
||||
return;
|
||||
}
|
||||
|
||||
BWindow *parent =
|
||||
dynamic_cast<BWindow *>(BLooper::LooperForThread(find_thread(NULL)));
|
||||
Show();
|
||||
|
||||
if (parent) {
|
||||
status_t ret;
|
||||
for (;;) {
|
||||
do {
|
||||
ret = acquire_sem_etc(fSemaphore, 1, B_RELATIVE_TIMEOUT, 50000);
|
||||
} while (ret == B_INTERRUPTED);
|
||||
|
||||
if (ret == B_BAD_SEM_ID)
|
||||
break;
|
||||
parent->UpdateIfNeeded();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Since there are no spinlocks, wait until the semaphore is free
|
||||
while (acquire_sem(fSemaphore) == B_INTERRUPTED) {
|
||||
}
|
||||
}
|
||||
|
||||
if (Lock())
|
||||
Quit();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageImageViewer::MessageReceived(BMessage *msg)
|
||||
{
|
||||
if (msg->what == P_MSG_CLOSE) {
|
||||
if (fSemaphore >= B_OK) {
|
||||
delete_sem(fSemaphore);
|
||||
fSemaphore = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
BWindow::MessageReceived(msg);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
* Łukasz 'Sil2100' Zemczak <[email protected]>
|
||||
*/
|
||||
#ifndef PACKAGEIMAGEVIEWER_H
|
||||
#define PACKAGEIMAGEVIEWER_H
|
||||
|
||||
#include <Window.h>
|
||||
#include <View.h>
|
||||
#include <Bitmap.h>
|
||||
#include <DataIO.h>
|
||||
|
||||
|
||||
|
||||
class ImageView : public BView {
|
||||
public:
|
||||
ImageView(BPositionIO *image);
|
||||
~ImageView();
|
||||
|
||||
void AttachedToWindow();
|
||||
void Draw(BRect updateRect);
|
||||
void MouseUp(BPoint point);
|
||||
|
||||
private:
|
||||
BBitmap *fImage;
|
||||
bool fSuccess;
|
||||
};
|
||||
|
||||
|
||||
class PackageImageViewer : public BWindow {
|
||||
public:
|
||||
PackageImageViewer(BPositionIO *image);
|
||||
~PackageImageViewer();
|
||||
|
||||
void Go();
|
||||
|
||||
void MessageReceived(BMessage *msg);
|
||||
|
||||
private:
|
||||
ImageView *fBackground;
|
||||
|
||||
sem_id fSemaphore;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
* Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
|
||||
*/
|
||||
#ifndef PACKAGEINFO_H
|
||||
#define PACKAGEINFO_H
|
||||
|
||||
#include "PackageItem.h"
|
||||
#include <List.h>
|
||||
#include <String.h>
|
||||
#include <File.h>
|
||||
#include <DataIO.h>
|
||||
#include <Path.h>
|
||||
|
||||
|
||||
struct pkg_profile;
|
||||
|
||||
|
||||
class PackageInfo {
|
||||
public:
|
||||
PackageInfo();
|
||||
PackageInfo(const entry_ref *ref);
|
||||
~PackageInfo();
|
||||
|
||||
const char *GetName() { return fName.String(); }
|
||||
const char *GetDescription() { return fDescription.String(); }
|
||||
const char *GetShortDescription() { return fShortDesc.String(); }
|
||||
const char *GetVersion() { return fVersion.String(); }
|
||||
const char *GetDisclaimer() { return fDisclaimer.String(); }
|
||||
BMallocIO *GetSplashScreen() { return fHasImage ? &fImage : NULL; }
|
||||
int32 GetProfileCount() { return fProfiles.CountItems(); }
|
||||
pkg_profile *GetProfile(int32 num) { return static_cast<pkg_profile *>(fProfiles.ItemAt(num)); }
|
||||
|
||||
status_t Parse();
|
||||
status_t InitCheck() { return fStatus; }
|
||||
|
||||
private:
|
||||
void _AddItem(PkgItem *item, uint64 size, uint32 groups, uint32 path,
|
||||
uint32 cust);
|
||||
|
||||
status_t fStatus;
|
||||
|
||||
BFile *fPackageFile;
|
||||
BString fName;
|
||||
BString fDescription;
|
||||
BList fProfiles;
|
||||
|
||||
BString fShortDesc;
|
||||
BString fDeveloper;
|
||||
BString fVersion;
|
||||
BString fDisclaimer;
|
||||
BMallocIO fImage;
|
||||
bool fHasImage;
|
||||
|
||||
BList fFiles; // Holds all files in the package
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
struct pkg_profile {
|
||||
pkg_profile() : items(10), space_needed(0), path_type(P_SYSTEM_PATH) {}
|
||||
~pkg_profile();
|
||||
|
||||
BString name;
|
||||
BString description;
|
||||
BList items;
|
||||
uint64 space_needed;
|
||||
|
||||
uint8 path_type;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
resource app_signature "application/x-vnd.Haiku-PackageInstaller";
|
||||
|
||||
resource file_types message {
|
||||
"types" = "application/x-scode-UPkg"
|
||||
};
|
||||
|
||||
resource app_version {
|
||||
major = 0,
|
||||
middle = 2,
|
||||
minor = 0,
|
||||
|
||||
variety = B_APPV_ALPHA,
|
||||
|
||||
internal = 0,
|
||||
|
||||
short_info = "Package Installer",
|
||||
long_info = "Package Installer ©2007 Haiku, Inc."
|
||||
};
|
||||
|
||||
resource app_flags B_SINGLE_LAUNCH;
|
||||
|
||||
@@ -0,0 +1,697 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
* Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
|
||||
*/
|
||||
|
||||
|
||||
#include "PackageItem.h"
|
||||
|
||||
#include <Alert.h>
|
||||
#include <ByteOrder.h>
|
||||
#include <Directory.h>
|
||||
#include <NodeInfo.h>
|
||||
#include <SymLink.h>
|
||||
#include <Volume.h>
|
||||
|
||||
#include <fs_info.h>
|
||||
#include "zlib.h"
|
||||
|
||||
// Macro reserved for later localization
|
||||
#define T(x) x
|
||||
|
||||
enum {
|
||||
P_CHUNK_SIZE = 256
|
||||
};
|
||||
|
||||
static const uint32 kDefaultMode = 0777;
|
||||
static const uint8 padding[7] = { 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
enum {
|
||||
P_DATA = 0,
|
||||
P_ATTRIBUTE
|
||||
};
|
||||
|
||||
|
||||
status_t
|
||||
inflate_data(uint8 *in, uint32 in_size, uint8 *out, uint32 out_size)
|
||||
{
|
||||
z_stream stream;
|
||||
stream.zalloc = Z_NULL;
|
||||
stream.zfree = Z_NULL;
|
||||
stream.opaque = Z_NULL;
|
||||
stream.avail_in = in_size;
|
||||
stream.next_in = in;
|
||||
status_t ret;
|
||||
|
||||
ret = inflateInit(&stream);
|
||||
if (ret != Z_OK)
|
||||
return B_ERROR;
|
||||
|
||||
stream.avail_out = out_size;
|
||||
stream.next_out = out;
|
||||
|
||||
ret = inflate(&stream, Z_NO_FLUSH);
|
||||
if (ret != Z_STREAM_END) {
|
||||
parser_debug("Left: %d\n", stream.avail_out);
|
||||
return B_ERROR; // Uncompressed file size in package info corrupted
|
||||
}
|
||||
|
||||
(void)inflateEnd(&stream);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static inline int
|
||||
inflate_file_to_file(BFile *in, uint64 in_size, BFile *out, uint64 out_size)
|
||||
{
|
||||
z_stream stream;
|
||||
stream.zalloc = Z_NULL;
|
||||
stream.zfree = Z_NULL;
|
||||
stream.opaque = Z_NULL;
|
||||
stream.avail_in = 0;
|
||||
stream.next_in = Z_NULL;
|
||||
status_t ret;
|
||||
|
||||
uint8 buffer_out[P_CHUNK_SIZE], buffer_in[P_CHUNK_SIZE];
|
||||
uint64 bytes_read = 0, read = P_CHUNK_SIZE, write = 0;
|
||||
|
||||
ret = inflateInit(&stream);
|
||||
if (ret != Z_OK)
|
||||
return B_ERROR;
|
||||
|
||||
do {
|
||||
bytes_read += P_CHUNK_SIZE;
|
||||
if (bytes_read > in_size) {
|
||||
read = in_size - (bytes_read - P_CHUNK_SIZE);
|
||||
bytes_read = in_size;
|
||||
}
|
||||
|
||||
stream.avail_in = in->Read(buffer_in, read);
|
||||
if (stream.avail_in != read) {
|
||||
(void)inflateEnd(&stream);
|
||||
return B_ERROR;
|
||||
}
|
||||
stream.next_in = buffer_in;
|
||||
|
||||
do {
|
||||
stream.avail_out = P_CHUNK_SIZE;
|
||||
stream.next_out = buffer_out;
|
||||
|
||||
ret = inflate(&stream, Z_NO_FLUSH);
|
||||
if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) {
|
||||
(void)inflateEnd(&stream);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
write = P_CHUNK_SIZE - stream.avail_out;
|
||||
if (static_cast<uint64>(out->Write(buffer_out, write)) != write) {
|
||||
(void)inflateEnd(&stream);
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
while (stream.avail_out == 0);
|
||||
}
|
||||
while (bytes_read != in_size);
|
||||
|
||||
(void)inflateEnd(&stream);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
PkgDirectory::PkgDirectory(BFile *parent, BString path, uint8 type, uint32 ctime,
|
||||
uint32 mtime, uint64 offset, uint64 size)
|
||||
:
|
||||
fPath(path),
|
||||
fOffset(offset),
|
||||
fSize(size),
|
||||
fPathType(type),
|
||||
fCreationTime(ctime),
|
||||
fModificationTime(mtime),
|
||||
fPackage(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PkgDirectory::SetTo(BFile *parent, BString path, uint8 type, uint32 ctime,
|
||||
uint32 mtime, uint64 offset, uint64 size)
|
||||
{
|
||||
fPackage = parent;
|
||||
fPath = path;
|
||||
|
||||
fOffset = offset;
|
||||
fSize = size;
|
||||
fPathType = type;
|
||||
fCreationTime = ctime;
|
||||
fModificationTime = mtime;
|
||||
}
|
||||
|
||||
|
||||
PkgDirectory::~PkgDirectory()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PkgDirectory::WriteToPath(const char *path, BPath *final)
|
||||
{
|
||||
BPath destination;
|
||||
status_t ret;
|
||||
parser_debug("Directory: %s WriteToPath() called!\n", fPath.String());
|
||||
|
||||
ret = _InitPath(path, &destination);
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
|
||||
// Since Haiku is single-user right now, we give the newly
|
||||
// created directory default permissions
|
||||
ret = create_directory(destination.Path(), kDefaultMode);
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
BDirectory dir(destination.Path());
|
||||
parser_debug("Directory created!\n");
|
||||
|
||||
if (fCreationTime)
|
||||
dir.SetCreationTime(static_cast<time_t>(fCreationTime));
|
||||
|
||||
if (fModificationTime)
|
||||
dir.SetModificationTime(static_cast<time_t>(fModificationTime));
|
||||
|
||||
// Since directories can only have attributes in the offset section,
|
||||
// we can check here whether it is necessary to continue
|
||||
if (fOffset) {
|
||||
ret = _HandleAttributes(&destination, &dir, "FoDa");
|
||||
}
|
||||
|
||||
if (final) {
|
||||
*final = destination;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
PkgDirectory::_ItemExists(const char *name)
|
||||
{
|
||||
BString alertString = T("The file named");
|
||||
alertString << " \'" << name << "\' ";
|
||||
alertString << T("already exists in the given path. Should I replace "
|
||||
"the existing file with the one from this package?");
|
||||
|
||||
BAlert *alert = new BAlert(T("file_exists"), alertString.String(),
|
||||
T("Yes"), T("No"), T("Abort"));
|
||||
|
||||
return alert->Go();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PkgDirectory::_InitPath(const char *path, BPath *destination)
|
||||
{
|
||||
status_t ret = B_OK;
|
||||
|
||||
if (fPathType == P_INSTALL_PATH) {
|
||||
if (!path)
|
||||
return B_ERROR;
|
||||
ret = destination->SetTo(path, fPath.String());
|
||||
}
|
||||
else if (fPathType == P_SYSTEM_PATH)
|
||||
ret = destination->SetTo(fPath.String());
|
||||
else {
|
||||
if (!path)
|
||||
return B_ERROR;
|
||||
|
||||
BVolume volume(dev_for_path(path));
|
||||
ret = volume.InitCheck();
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
|
||||
BDirectory temp;
|
||||
ret = volume.GetRootDirectory(&temp);
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
|
||||
BPath mountPoint(&temp, NULL);
|
||||
ret = destination->SetTo(mountPoint.Path(), fPath.String());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PkgDirectory::_HandleAttributes(BPath *destination, BNode *node,
|
||||
const char *header)
|
||||
{
|
||||
status_t ret = B_OK;
|
||||
|
||||
BVolume volume(dev_for_path(destination->Path()));
|
||||
if (volume.KnowsAttr()) {
|
||||
parser_debug("We have an offset\n");
|
||||
if (!fPackage)
|
||||
return B_ERROR;
|
||||
|
||||
ret = fPackage->InitCheck();
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
|
||||
// We need to parse the data section now
|
||||
fPackage->Seek(fOffset, SEEK_SET);
|
||||
uint8 buffer[7];
|
||||
if (fPackage->Read(buffer, 7) != 7 || memcmp(buffer, header, 5))
|
||||
return B_ERROR;
|
||||
parser_debug("Header validated!\n");
|
||||
|
||||
char *attrName = 0;
|
||||
uint32 nameSize = 0;
|
||||
uint8 *attrData = new uint8[P_CHUNK_SIZE];
|
||||
uint64 dataSize = P_CHUNK_SIZE;
|
||||
uint8 *temp = new uint8[P_CHUNK_SIZE];
|
||||
uint64 tempSize = P_CHUNK_SIZE;
|
||||
|
||||
uint64 attrCSize = 0, attrOSize = 0;
|
||||
uint32 attrType = 0; // type_code type
|
||||
bool attrStarted = false, done = false;
|
||||
|
||||
while (fPackage->Read(buffer, 7) == 7) {
|
||||
if (!memcmp(buffer, "FBeA", 5))
|
||||
continue;
|
||||
|
||||
ret = _ParseAttribute(buffer, node, &attrName, &nameSize, &attrType,
|
||||
&attrData, &dataSize, &temp, &tempSize, &attrCSize, &attrOSize,
|
||||
&attrStarted, &done);
|
||||
if (ret != B_OK || done)
|
||||
break;
|
||||
}
|
||||
|
||||
if (attrData)
|
||||
delete attrData;
|
||||
if (temp)
|
||||
delete temp;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
PkgDirectory::_ParseAttribute(uint8 *buffer, BNode *node, char **attrName,
|
||||
uint32 *nameSize, uint32 *attrType, uint8 **attrData, uint64 *dataSize,
|
||||
uint8 **temp, uint64 *tempSize, uint64 *attrCSize, uint64 *attrOSize,
|
||||
bool *attrStarted, bool *done)
|
||||
{
|
||||
status_t ret = B_OK;
|
||||
uint32 length;
|
||||
|
||||
if (!memcmp(buffer, "BeAI", 5)) {
|
||||
parser_debug(" Attribute started.\n");
|
||||
if (*attrName)
|
||||
*attrName[0] = 0;
|
||||
*attrCSize = 0;
|
||||
*attrOSize = 0;
|
||||
|
||||
*attrStarted = true;
|
||||
}
|
||||
else if (!memcmp(buffer, "BeAN", 5)) {
|
||||
if (!*attrStarted) {
|
||||
ret = B_ERROR;
|
||||
return ret;
|
||||
}
|
||||
|
||||
parser_debug(" BeAN.\n");
|
||||
fPackage->Read(&length, 4);
|
||||
swap_data(B_UINT32_TYPE, &length, sizeof(uint32), B_SWAP_BENDIAN_TO_HOST);
|
||||
|
||||
if (*nameSize < (length + 1)) {
|
||||
delete *attrName;
|
||||
*nameSize = length + 1;
|
||||
*attrName = new char[*nameSize];
|
||||
}
|
||||
fPackage->Read(*attrName, length);
|
||||
(*attrName)[length] = 0;
|
||||
|
||||
parser_debug(" (%d) = %s\n", length, *attrName);
|
||||
}
|
||||
else if (!memcmp(buffer, "BeAT", 5)) {
|
||||
if (!*attrStarted) {
|
||||
ret = B_ERROR;
|
||||
return ret;
|
||||
}
|
||||
|
||||
parser_debug(" BeAT.\n");
|
||||
fPackage->Read(attrType, 4);
|
||||
swap_data(B_UINT32_TYPE, attrType, sizeof(*attrType),
|
||||
B_SWAP_BENDIAN_TO_HOST);
|
||||
}
|
||||
else if (!memcmp(buffer, "BeAD", 5)) {
|
||||
if (!*attrStarted) {
|
||||
ret = B_ERROR;
|
||||
return ret;
|
||||
}
|
||||
|
||||
parser_debug(" BeAD.\n");
|
||||
fPackage->Read(attrCSize, 8);
|
||||
swap_data(B_UINT64_TYPE, attrCSize, sizeof(*attrCSize),
|
||||
B_SWAP_BENDIAN_TO_HOST);
|
||||
|
||||
fPackage->Read(attrOSize, 8);
|
||||
swap_data(B_UINT64_TYPE, attrOSize, sizeof(*attrOSize),
|
||||
B_SWAP_BENDIAN_TO_HOST);
|
||||
|
||||
fPackage->Seek(4, SEEK_CUR); // TODO: Check what this means
|
||||
|
||||
if (*tempSize < *attrCSize) {
|
||||
delete *temp;
|
||||
*tempSize = *attrCSize;
|
||||
*temp = new uint8[*tempSize];
|
||||
}
|
||||
if (*dataSize < *attrOSize) {
|
||||
delete *attrData;
|
||||
*dataSize = *attrOSize;
|
||||
*attrData = new uint8[*dataSize];
|
||||
}
|
||||
|
||||
if (fPackage->Read(*temp, *attrCSize)
|
||||
!= static_cast<ssize_t>(*attrCSize)) {
|
||||
ret = B_ERROR;
|
||||
return ret;
|
||||
}
|
||||
|
||||
parser_debug(" Data read successfuly. Inflating!\n");
|
||||
ret = inflate_data(*temp, *tempSize, *attrData, *dataSize);
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
}
|
||||
else if (!memcmp(buffer, padding, 7)) {
|
||||
if (!*attrStarted) {
|
||||
*done = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
parser_debug(" Padding.\n");
|
||||
ssize_t wrote = node->WriteAttr(*attrName, *attrType, 0, *attrData,
|
||||
*attrOSize);
|
||||
if(wrote != static_cast<ssize_t>(*attrOSize)) {
|
||||
ret = B_ERROR;
|
||||
return ret;
|
||||
}
|
||||
|
||||
*attrStarted = false;
|
||||
if (*attrName)
|
||||
*attrName[0] = 0;
|
||||
*attrCSize = 0;
|
||||
*attrOSize = 0;
|
||||
|
||||
parser_debug(" > Attribute added.\n");
|
||||
}
|
||||
else {
|
||||
ret = B_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
PkgDirectory::_ParseData(uint8 *buffer, BFile *file, uint64 originalSize,
|
||||
bool *done)
|
||||
{
|
||||
status_t ret = B_OK;
|
||||
|
||||
if (!memcmp(buffer, "FiMF", 5)) {
|
||||
parser_debug(" Found file data.\n");
|
||||
uint64 compressed, original;
|
||||
fPackage->Read(&compressed, 8);
|
||||
swap_data(B_UINT64_TYPE, &compressed, sizeof(uint64),
|
||||
B_SWAP_BENDIAN_TO_HOST);
|
||||
|
||||
fPackage->Read(&original, 8);
|
||||
swap_data(B_UINT64_TYPE, &original, sizeof(uint64),
|
||||
B_SWAP_BENDIAN_TO_HOST);
|
||||
parser_debug(" Still good... (%llu : %llu)\n", original,
|
||||
originalSize);
|
||||
|
||||
if (original != originalSize) {
|
||||
ret = B_ERROR; // File size missmatch
|
||||
return ret;
|
||||
}
|
||||
parser_debug(" Still good...\n");
|
||||
|
||||
if (fPackage->Read(buffer, 4) != 4) {
|
||||
ret = B_ERROR;
|
||||
return ret;
|
||||
}
|
||||
parser_debug(" Still good...\n");
|
||||
|
||||
ret = inflate_file_to_file(fPackage, compressed, file, original);
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
parser_debug(" File data inflation complete!\n");
|
||||
}
|
||||
else if (!memcmp(buffer, padding, 7)) {
|
||||
*done = true;
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
ret = B_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PkgFile::PkgFile(BFile *parent, BString path, uint8 type, uint32 ctime,
|
||||
uint32 mtime, uint64 offset, uint64 size, uint64 originalSize,
|
||||
uint32 platform, BString mime, BString signature, uint32 mode)
|
||||
: PkgItem(parent, path, type, ctime, mtime, offset, size),
|
||||
fOriginalSize(originalSize),
|
||||
fPlatform(platform),
|
||||
fMode(mode),
|
||||
fMimeType(mime),
|
||||
fSignature(signature)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PkgFile::~PkgFile()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PkgFile::WriteToPath(const char *path, BPath *final)
|
||||
{
|
||||
BPath destination;
|
||||
status_t ret;
|
||||
parser_debug("File: %s WriteToPath() called!\n", fPath.String());
|
||||
|
||||
ret = _InitPath(path, &destination);
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
|
||||
BFile file(destination.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_FAIL_IF_EXISTS);
|
||||
ret = file.InitCheck();
|
||||
if (ret == B_FILE_EXISTS) {
|
||||
int32 selection = _ItemExists(destination.Leaf());
|
||||
switch (selection) {
|
||||
case 0:
|
||||
ret = file.SetTo(destination.Path(), B_WRITE_ONLY | B_ERASE_FILE);
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
break;
|
||||
case 1:
|
||||
return B_OK;
|
||||
default:
|
||||
return B_FILE_EXISTS;
|
||||
}
|
||||
}
|
||||
else if (ret == B_ENTRY_NOT_FOUND) {
|
||||
BPath directory;
|
||||
destination.GetParent(&directory);
|
||||
if (create_directory(directory.Path(), kDefaultMode) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
ret = file.SetTo(destination.Path(), B_WRITE_ONLY | B_CREATE_FILE);
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
}
|
||||
else if (ret != B_OK)
|
||||
return ret;
|
||||
|
||||
parser_debug(" File created!\n");
|
||||
|
||||
// Set the file permissions, creation and modification times
|
||||
ret = file.SetPermissions(static_cast<mode_t>(fMode));
|
||||
if (fCreationTime)
|
||||
ret |= file.SetCreationTime(static_cast<time_t>(fCreationTime));
|
||||
if (fModificationTime)
|
||||
ret |= file.SetModificationTime(static_cast<time_t>(fModificationTime));
|
||||
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
|
||||
// Set the mimetype and application signature if present
|
||||
BNodeInfo info(&file);
|
||||
if (fMimeType.Length() > 0) {
|
||||
ret = info.SetType(fMimeType.String());
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
}
|
||||
if (fSignature.Length() > 0) {
|
||||
ret = info.SetPreferredApp(fSignature.String());
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (fOffset) {
|
||||
parser_debug("We have an offset\n");
|
||||
if (!fPackage)
|
||||
return B_ERROR;
|
||||
|
||||
ret = fPackage->InitCheck();
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
|
||||
// We need to parse the data section now
|
||||
fPackage->Seek(fOffset, SEEK_SET);
|
||||
uint8 buffer[7];
|
||||
|
||||
char *attrName = 0;
|
||||
uint32 nameSize = 0;
|
||||
uint8 *attrData = new uint8[P_CHUNK_SIZE];
|
||||
uint64 dataSize = P_CHUNK_SIZE;
|
||||
uint8 *temp = new uint8[P_CHUNK_SIZE];
|
||||
uint64 tempSize = P_CHUNK_SIZE;
|
||||
|
||||
uint64 attrCSize = 0, attrOSize = 0;
|
||||
uint32 attrType = 0; // type_code type
|
||||
bool attrStarted = false, done = false;
|
||||
|
||||
uint8 section = P_ATTRIBUTE;
|
||||
|
||||
while (fPackage->Read(buffer, 7) == 7) {
|
||||
if (!memcmp(buffer, "FBeA", 5)) {
|
||||
parser_debug("-> Attribute\n");
|
||||
section = P_ATTRIBUTE;
|
||||
continue;
|
||||
}
|
||||
else if (!memcmp(buffer, "FiDa", 5)) {
|
||||
parser_debug("-> File data\n");
|
||||
section = P_DATA;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (section) {
|
||||
case P_ATTRIBUTE:
|
||||
{
|
||||
ret = _ParseAttribute(buffer, &file, &attrName, &nameSize, &attrType,
|
||||
&attrData, &dataSize, &temp, &tempSize, &attrCSize, &attrOSize,
|
||||
&attrStarted, &done);
|
||||
break;
|
||||
}
|
||||
case P_DATA:
|
||||
{
|
||||
ret = _ParseData(buffer, &file, fOriginalSize, &done);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (ret != B_OK || done)
|
||||
break;
|
||||
}
|
||||
|
||||
if (attrData)
|
||||
delete attrData;
|
||||
if (temp)
|
||||
delete temp;
|
||||
}
|
||||
|
||||
if (final) {
|
||||
*final = destination;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PkgLink::PkgLink(BFile *parent, BString path, BString link, uint8 type,
|
||||
uint32 ctime, uint32 mtime, uint32 mode, uint64 offset, uint64 size)
|
||||
: PkgItem(parent, path, type, ctime, mtime, offset, size),
|
||||
fMode(mode),
|
||||
fLink(link)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PkgLink::~PkgLink()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PkgLink::WriteToPath(const char *path, BPath *final)
|
||||
{
|
||||
BPath destination;
|
||||
status_t ret;
|
||||
parser_debug("Symlink: %s WriteToPath() called!\n", fPath.String());
|
||||
|
||||
ret = _InitPath(path, &destination);
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
|
||||
BString linkName(destination.Leaf());
|
||||
parser_debug("%s:%s:%s\n", fPath.String(), destination.Path(), linkName.String());
|
||||
BPath dirPath;
|
||||
ret = destination.GetParent(&dirPath);
|
||||
BDirectory dir(dirPath.Path());
|
||||
|
||||
ret = dir.InitCheck();
|
||||
if (ret == B_ENTRY_NOT_FOUND) {
|
||||
if (create_directory(destination.Path(), kDefaultMode) != B_OK)
|
||||
return B_ERROR;
|
||||
}
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
|
||||
BSymLink symlink;
|
||||
ret = dir.CreateSymLink(linkName.String(), fLink.String(), &symlink);
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
|
||||
parser_debug(" Symlink created!\n");
|
||||
|
||||
ret = symlink.SetPermissions(static_cast<mode_t>(fMode));
|
||||
|
||||
if (fCreationTime)
|
||||
ret |= symlink.SetCreationTime(static_cast<time_t>(fCreationTime));
|
||||
|
||||
if (fModificationTime)
|
||||
ret |= symlink.SetModificationTime(static_cast<time_t>(fModificationTime));
|
||||
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
|
||||
if (fOffset) {
|
||||
// Simlinks also seem to have attributes - so parse them
|
||||
ret = _HandleAttributes(&destination, &dir, "LnDa");
|
||||
}
|
||||
|
||||
if (final) {
|
||||
*final = destination;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
* Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
|
||||
*/
|
||||
#ifndef PACKAGEITEM_H
|
||||
#define PACKAGEITEM_H
|
||||
|
||||
#include <String.h>
|
||||
#include <Entry.h>
|
||||
#include <File.h>
|
||||
#include <Path.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//#define DEBUG_PARSER
|
||||
|
||||
// Local macro for the parser debug output
|
||||
#ifdef DEBUG_PARSER
|
||||
#define parser_debug(format, args...) fprintf(stderr, format, ##args)
|
||||
#else
|
||||
#define parser_debug(format, args...)
|
||||
#endif
|
||||
|
||||
|
||||
class PkgDirectory;
|
||||
|
||||
// Since files are derive from directories, which is not too obvious,
|
||||
// we define a type PkgItem to use for base type iterations
|
||||
typedef PkgDirectory PkgItem;
|
||||
|
||||
|
||||
enum {
|
||||
P_INSTALL_PATH = 0,
|
||||
P_SYSTEM_PATH,
|
||||
P_USER_PATH
|
||||
};
|
||||
|
||||
|
||||
status_t inflate_data(uint8 *in, uint32 in_size, uint8 *out, uint32 out_size);
|
||||
|
||||
|
||||
class PkgDirectory {
|
||||
public:
|
||||
PkgDirectory(BFile *parent, BString path, uint8 type, uint32 ctime,
|
||||
uint32 mtime, uint64 offset = 0, uint64 size = 0);
|
||||
virtual ~PkgDirectory();
|
||||
|
||||
virtual status_t WriteToPath(const char *path = NULL, BPath *final = NULL);
|
||||
virtual void SetTo(BFile *parent, BString path, uint8 type,
|
||||
uint32 ctime, uint32 mtime, uint64 offset = 0, uint64 size = 0);
|
||||
|
||||
protected:
|
||||
int32 _ItemExists(const char *name);
|
||||
status_t _InitPath(const char *path, BPath *destination);
|
||||
status_t _HandleAttributes(BPath *destination, BNode *node,
|
||||
const char *header);
|
||||
|
||||
inline status_t _ParseAttribute(uint8 *buffer, BNode *node, char **attrName,
|
||||
uint32 *nameSize, uint32 *attrType, uint8 **attrData, uint64 *dataSize,
|
||||
uint8 **temp, uint64 *tempSize, uint64 *attrCSize, uint64 *attrOSize,
|
||||
bool *attrStarted, bool *done);
|
||||
inline status_t _ParseData(uint8 *buffer, BFile *file, uint64 originalSize,
|
||||
bool *done);
|
||||
|
||||
BString fPath;
|
||||
uint64 fOffset;
|
||||
uint64 fSize;
|
||||
uint8 fPathType;
|
||||
uint32 fCreationTime;
|
||||
uint32 fModificationTime;
|
||||
|
||||
BFile *fPackage;
|
||||
};
|
||||
|
||||
|
||||
class PkgFile : public PkgItem {
|
||||
public:
|
||||
PkgFile(BFile *parent, BString path, uint8 type, uint32 ctime,
|
||||
uint32 mtime, uint64 offset, uint64 size, uint64 originalSize,
|
||||
uint32 platform, BString mime, BString signature, uint32 mode);
|
||||
~PkgFile();
|
||||
|
||||
status_t WriteToPath(const char *path = NULL, BPath *final = NULL);
|
||||
|
||||
private:
|
||||
uint64 fOriginalSize;
|
||||
uint32 fPlatform;
|
||||
uint32 fMode;
|
||||
|
||||
BString fMimeType;
|
||||
BString fSignature;
|
||||
};
|
||||
|
||||
|
||||
class PkgLink : public PkgItem {
|
||||
public:
|
||||
PkgLink(BFile *parent, BString path, BString link, uint8 type,
|
||||
uint32 ctime, uint32 mtime, uint32 mode, uint64 offset = 0,
|
||||
uint64 size = 0);
|
||||
~PkgLink();
|
||||
|
||||
status_t WriteToPath(const char *path = NULL, BPath *final = NULL);
|
||||
|
||||
private:
|
||||
uint32 fMode;
|
||||
|
||||
BString fLink;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
* Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
|
||||
*/
|
||||
|
||||
|
||||
#include "PackageStatus.h"
|
||||
|
||||
#include <Autolock.h>
|
||||
|
||||
#include <GroupLayoutBuilder.h>
|
||||
#include <GroupLayout.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// Macro reserved for later localization
|
||||
#define T(x) x
|
||||
|
||||
|
||||
StopButton::StopButton()
|
||||
: BButton(BRect(0, 0, 22, 18), "stop", "", new BMessage(P_MSG_STOP))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StopButton::Draw(BRect updateRect)
|
||||
{
|
||||
BButton::Draw(updateRect);
|
||||
|
||||
updateRect = Bounds();
|
||||
updateRect.InsetBy((updateRect.Width() - 4) / 2, (updateRect.Height() - 4) / 2);
|
||||
//updateRect.InsetBy(9, 7);
|
||||
SetHighColor(0, 0, 0);
|
||||
FillRect(updateRect);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
/*PackageStatus::PackageStatus(BHandler *parent, const char *title,
|
||||
const char *label, const char *trailing)
|
||||
: BWindow(BRect(200, 200, 550, 275), title, B_TITLED_WINDOW,
|
||||
B_NOT_CLOSABLE | B_NOT_RESIZABLE | B_NOT_ZOOMABLE, 0)
|
||||
{
|
||||
SetSizeLimits(0, 100000, 0, 100000);
|
||||
fBackground = new BView(Bounds(), "background", B_FOLLOW_NONE, B_WILL_DRAW);
|
||||
fBackground->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
BRect rect(Bounds());
|
||||
float width, height;
|
||||
rect.left += 6;
|
||||
rect.right -= 40;
|
||||
rect.top += 6;
|
||||
rect.bottom = rect.top + 15;
|
||||
fStatus = new BStatusBar(rect, "status_bar", T("Installing package"));
|
||||
fStatus->SetBarHeight(12);
|
||||
fStatus->GetPreferredSize(&width, &height);
|
||||
fStatus->ResizeTo(fStatus->Frame().Width(), height);
|
||||
fBackground->AddChild(fStatus);
|
||||
|
||||
font_height fontHeight;
|
||||
fBackground->GetFontHeight(&fontHeight);
|
||||
BRect frame = fStatus->Frame();
|
||||
fBackground->ResizeTo(Bounds().Width(), (2 * frame.top) + frame.Height() +
|
||||
fontHeight.leading + fontHeight.ascent + fontHeight.descent);
|
||||
|
||||
rect = Bounds();
|
||||
rect.left = rect.right - 32;
|
||||
//rect.right = rect.left + 17;
|
||||
rect.top += 18;
|
||||
//rect.bottom = rect.top + 10;
|
||||
fButton = new StopButton();
|
||||
fButton->MoveTo(BPoint(rect.left, rect.top));
|
||||
fButton->ResizeTo(22, 18);
|
||||
fBackground->AddChild(fButton);
|
||||
|
||||
AddChild(fBackground);
|
||||
fButton->SetTarget(parent);
|
||||
|
||||
ResizeTo(Bounds().Width(), fBackground->Bounds().Height());
|
||||
Run();
|
||||
}*/
|
||||
|
||||
|
||||
PackageStatus::PackageStatus(const char *title, const char *label,
|
||||
const char *trailing)
|
||||
: BWindow(BRect(200, 200, 550, 255), title, B_TITLED_WINDOW,
|
||||
B_NOT_CLOSABLE | B_NOT_RESIZABLE | B_NOT_ZOOMABLE, 0),
|
||||
fIsStopped(false)
|
||||
{
|
||||
SetLayout(new BGroupLayout(B_VERTICAL));
|
||||
|
||||
fStatus = new BStatusBar("status_bar", T("Installing package"));
|
||||
fStatus->SetBarHeight(12);
|
||||
|
||||
fButton = new StopButton();
|
||||
fButton->SetExplicitMaxSize(BSize(22, 18));
|
||||
|
||||
fBackground = BGroupLayoutBuilder(B_HORIZONTAL)
|
||||
.AddStrut(5.0f)
|
||||
.Add(fStatus)
|
||||
.Add(fButton);
|
||||
fBackground->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
AddChild(fBackground);
|
||||
|
||||
fButton->SetTarget(this);
|
||||
Run();
|
||||
}
|
||||
|
||||
|
||||
PackageStatus::~PackageStatus()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageStatus::MessageReceived(BMessage *msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
case P_MSG_STOP:
|
||||
fIsStopped = true;
|
||||
break;
|
||||
default:
|
||||
BWindow::MessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageStatus::Reset(uint32 stages, const char *label, const char *trailing)
|
||||
{
|
||||
BAutolock lock(this);
|
||||
|
||||
if (lock.IsLocked()) {
|
||||
fStatus->Reset(label, trailing);
|
||||
fStatus->SetMaxValue(stages);
|
||||
fIsStopped = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageStatus::StageStep(uint32 count, const char *text, const char *trailing)
|
||||
{
|
||||
BAutolock lock(this);
|
||||
|
||||
if (lock.IsLocked()) {
|
||||
fStatus->Update(count, text, trailing);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PackageStatus::Stopped()
|
||||
{
|
||||
BAutolock lock(this);
|
||||
return fIsStopped;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
* Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
|
||||
*/
|
||||
#ifndef PACKAGESTATUS_H
|
||||
#define PACKAGESTATUS_H
|
||||
|
||||
#include <Window.h>
|
||||
#include <View.h>
|
||||
#include <Button.h>
|
||||
#include <StatusBar.h>
|
||||
|
||||
|
||||
enum {
|
||||
P_MSG_NEXT_STAGE = 'psne',
|
||||
P_MSG_STOP,
|
||||
P_MSG_RESET
|
||||
};
|
||||
|
||||
|
||||
class StopButton : public BButton {
|
||||
public:
|
||||
StopButton();
|
||||
virtual void Draw(BRect);
|
||||
};
|
||||
|
||||
|
||||
class PackageStatus : public BWindow {
|
||||
public:
|
||||
PackageStatus(const char *title, const char *label = NULL,
|
||||
const char *trailing = NULL);
|
||||
~PackageStatus();
|
||||
|
||||
void MessageReceived(BMessage *msg);
|
||||
void Reset(uint32 stages, const char *label = NULL,
|
||||
const char *trailing = NULL);
|
||||
void StageStep(uint32 count, const char *text = NULL,
|
||||
const char *trailing = NULL);
|
||||
bool Stopped();
|
||||
|
||||
private:
|
||||
BView *fBackground;
|
||||
BStatusBar *fStatus;
|
||||
StopButton *fButton;
|
||||
bool fIsStopped;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
* Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
|
||||
*/
|
||||
|
||||
|
||||
#include "PackageTextViewer.h"
|
||||
|
||||
#include <Button.h>
|
||||
#include <ScrollView.h>
|
||||
|
||||
#include <GroupLayout.h>
|
||||
#include <GroupLayoutBuilder.h>
|
||||
|
||||
|
||||
enum {
|
||||
P_MSG_ACCEPT = 'pmac',
|
||||
P_MSG_DECLINE
|
||||
};
|
||||
|
||||
// Reserved
|
||||
#define T(x) x
|
||||
|
||||
|
||||
PackageTextViewer::PackageTextViewer(const char *text, bool disclaimer)
|
||||
: BWindow(BRect(125, 125, 675, 475), T("Disclaimer"), B_MODAL_WINDOW,
|
||||
B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_NOT_CLOSABLE),
|
||||
fValue(0)
|
||||
{
|
||||
_InitView(text, disclaimer);
|
||||
}
|
||||
|
||||
|
||||
PackageTextViewer::~PackageTextViewer()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
PackageTextViewer::Go()
|
||||
{
|
||||
// Since this class can be thought of as a modified BAlert window, no use
|
||||
// to reinvent a well fledged wheel. This concept has been borrowed from
|
||||
// the current BAlert implementation
|
||||
fSemaphore = create_sem(0, "TextViewer");
|
||||
if (fSemaphore < B_OK) {
|
||||
Quit();
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
BWindow *parent =
|
||||
dynamic_cast<BWindow *>(BLooper::LooperForThread(find_thread(NULL)));
|
||||
Show();
|
||||
|
||||
if (parent) {
|
||||
status_t ret;
|
||||
for (;;) {
|
||||
do {
|
||||
ret = acquire_sem_etc(fSemaphore, 1, B_RELATIVE_TIMEOUT, 50000);
|
||||
} while (ret == B_INTERRUPTED);
|
||||
|
||||
if (ret == B_BAD_SEM_ID)
|
||||
break;
|
||||
parent->UpdateIfNeeded();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Since there are no spinlocks, wait until the semaphore is free
|
||||
while (acquire_sem(fSemaphore) == B_INTERRUPTED) {
|
||||
}
|
||||
}
|
||||
|
||||
int32 value = fValue;
|
||||
if (Lock())
|
||||
Quit();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageTextViewer::MessageReceived(BMessage *msg)
|
||||
{
|
||||
if (msg->what == P_MSG_ACCEPT) {
|
||||
if (fSemaphore >= B_OK) {
|
||||
fValue = 1;
|
||||
delete_sem(fSemaphore);
|
||||
fSemaphore = -1;
|
||||
}
|
||||
}
|
||||
else if (msg->what == P_MSG_DECLINE) {
|
||||
if (fSemaphore >= B_OK) {
|
||||
fValue = 0;
|
||||
delete_sem(fSemaphore);
|
||||
fSemaphore = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
BWindow::MessageReceived(msg);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
void
|
||||
PackageTextViewer::_InitView(const char *text, bool disclaimer)
|
||||
{
|
||||
fBackground = new BView(Bounds(), "background_view", 0, 0);
|
||||
fBackground->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
BRect bounds;
|
||||
BRect rect = Bounds();
|
||||
if (disclaimer) {
|
||||
BButton *button = new BButton(BRect(0, 0, 1, 1), "accept", T("Accept"),
|
||||
new BMessage(P_MSG_ACCEPT));
|
||||
button->ResizeToPreferred();
|
||||
|
||||
bounds = button->Bounds();
|
||||
rect.top = rect.bottom - bounds.bottom - 5.0f;
|
||||
rect.left = rect.right - bounds.right - 5.0f;
|
||||
rect.bottom = bounds.bottom;
|
||||
rect.right = bounds.right;
|
||||
button->MoveTo(rect.LeftTop());
|
||||
button->MakeDefault(true);
|
||||
fBackground->AddChild(button);
|
||||
|
||||
button = new BButton(BRect(0, 0, 1, 1), "decline", T("Decline"),
|
||||
new BMessage(P_MSG_DECLINE));
|
||||
button->ResizeToPreferred();
|
||||
|
||||
bounds = button->Bounds();
|
||||
rect.left -= bounds.right + 7.0f;
|
||||
button->MoveTo(rect.LeftTop());
|
||||
fBackground->AddChild(button);
|
||||
}
|
||||
else {
|
||||
BButton *button = new BButton(BRect(0, 0, 1, 1), "accept", T("Continue"),
|
||||
new BMessage(P_MSG_ACCEPT));
|
||||
button->ResizeToPreferred();
|
||||
|
||||
bounds = button->Bounds();
|
||||
rect.top = rect.bottom - bounds.bottom - 5.0f;
|
||||
rect.left = rect.right - bounds.right - 5.0f;
|
||||
rect.bottom = bounds.bottom;
|
||||
rect.right = bounds.right;
|
||||
button->MoveTo(rect.LeftTop());
|
||||
button->MakeDefault(true);
|
||||
fBackground->AddChild(button);
|
||||
}
|
||||
|
||||
bounds = Bounds().InsetBySelf(5.0f, 5.0f);
|
||||
bounds.bottom = rect.top - 6.0f;
|
||||
bounds.right -= B_V_SCROLL_BAR_WIDTH;
|
||||
|
||||
fText = new BTextView(bounds, "text_view", BRect(0, 0, bounds.Width(),
|
||||
bounds.Height()), B_FOLLOW_NONE, B_WILL_DRAW);
|
||||
fText->MakeEditable(false);
|
||||
fText->MakeSelectable(true);
|
||||
fText->SetText(text);
|
||||
|
||||
BScrollView *scroll = new BScrollView("scroll_view", fText,
|
||||
B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true);
|
||||
|
||||
fBackground->AddChild(scroll);
|
||||
|
||||
AddChild(fBackground);
|
||||
}
|
||||
|
||||
|
||||
/*void
|
||||
PackageTextViewer::_InitView(const char *text, bool disclaimer)
|
||||
{
|
||||
SetLayout(new BGroupLayout(B_HORIZONTAL));
|
||||
|
||||
fText = new BTextView(BRect(0, 0, 1, 1), "text_view", BRect(0, 0, 1, 1),
|
||||
B_FOLLOW_NONE, B_WILL_DRAW | B_SUPPORTS_LAYOUT);
|
||||
fText->MakeEditable(false);
|
||||
fText->MakeSelectable(true);
|
||||
BScrollView *scroll = new BScrollView("scroll_view", fText,
|
||||
B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true);
|
||||
|
||||
if (disclaimer) {
|
||||
BButton *accept = new BButton("accept", T("Accept"),
|
||||
new BMessage(P_MSG_ACCEPT));
|
||||
|
||||
BButton *decline = new BButton("decline", T("Decline"),
|
||||
new BMessage(P_MSG_DECLINE));
|
||||
|
||||
fBackground = BGroupLayoutBuilder(B_VERTICAL)
|
||||
.Add(scroll)
|
||||
.AddGroup(B_HORIZONTAL, 5.0f)
|
||||
.AddGlue()
|
||||
.Add(accept)
|
||||
.Add(decline)
|
||||
.End();
|
||||
}
|
||||
else {
|
||||
BButton *button = new BButton("accept", T("Continue"),
|
||||
new BMessage(P_MSG_ACCEPT));
|
||||
|
||||
fBackground = BGroupLayoutBuilder(B_VERTICAL)
|
||||
.Add(scroll)
|
||||
.AddGroup(B_HORIZONTAL, 5.0f)
|
||||
.AddGlue()
|
||||
.Add(button)
|
||||
.End();
|
||||
}
|
||||
|
||||
AddChild(fBackground);
|
||||
|
||||
fBackground->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
fText->SetText(text);
|
||||
}*/
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
* Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
|
||||
*/
|
||||
#ifndef PACKAGETEXTVIEWER_H
|
||||
#define PACKAGETEXTVIEWER_H
|
||||
|
||||
#include <Window.h>
|
||||
#include <View.h>
|
||||
#include <TextView.h>
|
||||
|
||||
|
||||
class PackageTextViewer : public BWindow {
|
||||
public:
|
||||
PackageTextViewer(const char *text, bool disclaimer = false);
|
||||
~PackageTextViewer();
|
||||
|
||||
int32 Go();
|
||||
|
||||
void MessageReceived(BMessage *msg);
|
||||
|
||||
private:
|
||||
void _InitView(const char *text, bool disclaimer);
|
||||
|
||||
BView *fBackground;
|
||||
BTextView *fText;
|
||||
|
||||
sem_id fSemaphore;
|
||||
int32 fValue;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,629 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
* Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
|
||||
*/
|
||||
|
||||
|
||||
#include "InstalledPackageInfo.h"
|
||||
#include "PackageImageViewer.h"
|
||||
#include "PackageTextViewer.h"
|
||||
#include "PackageView.h"
|
||||
|
||||
#include <Alert.h>
|
||||
#include <Button.h>
|
||||
#include <Directory.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <MenuItem.h>
|
||||
#include <Path.h>
|
||||
#include <PopUpMenu.h>
|
||||
#include <ScrollView.h>
|
||||
#include <TextView.h>
|
||||
#include <Volume.h>
|
||||
#include <VolumeRoster.h>
|
||||
#include <Window.h>
|
||||
|
||||
#include <GroupLayout.h>
|
||||
#include <GroupLayoutBuilder.h>
|
||||
#include <GroupView.h>
|
||||
|
||||
#include <fs_info.h>
|
||||
#include <stdio.h> // For debugging
|
||||
|
||||
// Macro reserved for later localization
|
||||
#define T(x) x
|
||||
|
||||
const float kMaxDescHeight = 125.0f;
|
||||
const uint32 kSeparatorIndex = 3;
|
||||
|
||||
|
||||
|
||||
static void
|
||||
convert_size(uint64 size, char *buffer, uint32 n)
|
||||
{
|
||||
if (size < 1024)
|
||||
snprintf(buffer, n, "%llu bytes", size);
|
||||
else if (size < 1024 * 1024)
|
||||
snprintf(buffer, n, "%.1f KiB", size / 1024.0f);
|
||||
else if (size < 1024 * 1024 * 1024)
|
||||
snprintf(buffer, n, "%.1f MiB", size / (1024.0f*1024.0f));
|
||||
else
|
||||
snprintf(buffer, n, "%.1f GiB", size / (1024.0f*1024.0f*1024.0f));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
PackageView::PackageView(BRect frame, const entry_ref *ref)
|
||||
: BView(frame, "package_view", B_FOLLOW_NONE, 0),
|
||||
//BView("package_view", B_WILL_DRAW, new BGroupLayout(B_HORIZONTAL)),
|
||||
fOpenPanel(new BFilePanel(B_OPEN_PANEL, NULL, NULL,
|
||||
B_DIRECTORY_NODE, false)),
|
||||
fInfo(ref)
|
||||
{
|
||||
_InitView();
|
||||
|
||||
// Check whether the package has been successfuly parsed
|
||||
status_t ret = fInfo.InitCheck();
|
||||
if (ret == B_OK)
|
||||
_InitProfiles();
|
||||
else if (ret != B_NO_INIT) {
|
||||
BAlert *warning = new BAlert(T("parsing_failed"),
|
||||
T("I was unable to read the given package file.\nOne of the possible "
|
||||
"reasons for this might be that the requested file is not a valid "
|
||||
"BeOS .pkg package."), T("OK"), NULL, NULL, B_WIDTH_AS_USUAL,
|
||||
B_WARNING_ALERT);
|
||||
warning->Go();
|
||||
|
||||
BWindow *parent = Window();
|
||||
if (parent && parent->Lock())
|
||||
parent->Quit();
|
||||
}
|
||||
|
||||
ResizeTo(Bounds().Width(), fInstall->Frame().bottom + 4);
|
||||
}
|
||||
|
||||
|
||||
PackageView::~PackageView()
|
||||
{
|
||||
delete fOpenPanel;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageView::AttachedToWindow()
|
||||
{
|
||||
// Set the window title
|
||||
BWindow *parent = Window();
|
||||
BString title;
|
||||
BString name = fInfo.GetName();
|
||||
if (name.CountChars() == 0) {
|
||||
title = T("Package installer");
|
||||
}
|
||||
else {
|
||||
title = T("Install ");
|
||||
title += name;
|
||||
}
|
||||
parent->SetTitle(title.String());
|
||||
fInstall->SetTarget(this);
|
||||
|
||||
fOpenPanel->SetTarget(BMessenger(this));
|
||||
fInstallTypes->SetTargetForItems(this);
|
||||
|
||||
if (fInfo.InitCheck() == B_OK) {
|
||||
// If the package is valid, we can set up the default group and all
|
||||
// other things. If not, then the application will close just after
|
||||
// attaching the view to the window
|
||||
_GroupChanged(0);
|
||||
|
||||
fStatusWindow = new PackageStatus(T("Installation progress"));
|
||||
|
||||
// Show the splash screen, if present
|
||||
BMallocIO *image = fInfo.GetSplashScreen();
|
||||
if (image) {
|
||||
PackageImageViewer *imageViewer = new PackageImageViewer(image);
|
||||
imageViewer->Go();
|
||||
}
|
||||
|
||||
// Show the disclaimer/info text popup, if present
|
||||
BString disclaimer = fInfo.GetDisclaimer();
|
||||
if (disclaimer.Length() != 0) {
|
||||
PackageTextViewer *text = new PackageTextViewer(disclaimer.String());
|
||||
int32 selection = text->Go();
|
||||
// The user didn't accept our disclaimer, this means we cannot continue.
|
||||
if (selection == 0) {
|
||||
BWindow *parent = Window();
|
||||
if (parent && parent->Lock())
|
||||
parent->Quit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageView::MessageReceived(BMessage *msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
case P_MSG_INSTALL:
|
||||
{
|
||||
fInstall->SetEnabled(false);
|
||||
fStatusWindow->Show();
|
||||
BAlert *notify;
|
||||
status_t ret = Install();
|
||||
if (ret == B_OK) {
|
||||
notify = new BAlert("installation_success",
|
||||
T("The package you requested has been successfully installed "
|
||||
"on your system."), T("OK"));
|
||||
|
||||
notify->Go();
|
||||
fStatusWindow->Hide();
|
||||
|
||||
BWindow *parent = Window();
|
||||
if (parent && parent->Lock())
|
||||
parent->Quit();
|
||||
}
|
||||
else if (ret == B_FILE_EXISTS)
|
||||
notify = new BAlert("installation_aborted",
|
||||
T("The installation of the package has been aborted."), T("OK"));
|
||||
else
|
||||
notify = new BAlert("installation_failed", // TODO: Review this
|
||||
T("The requested package failed to install on your system. This "
|
||||
"might be a problem with the target package file. Please consult "
|
||||
"this issue with the package distributor."), T("OK"), NULL,
|
||||
NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
|
||||
notify->Go();
|
||||
fStatusWindow->Hide();
|
||||
fInstall->SetEnabled(true);
|
||||
|
||||
break;
|
||||
}
|
||||
case P_MSG_PATH_CHANGED:
|
||||
{
|
||||
BString path;
|
||||
if (msg->FindString("path", &path) == B_OK) {
|
||||
fCurrentPath.SetTo(path.String());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case P_MSG_OPEN_PANEL:
|
||||
fOpenPanel->Show();
|
||||
break;
|
||||
case P_MSG_GROUP_CHANGED:
|
||||
{
|
||||
int32 index;
|
||||
if (msg->FindInt32("index", &index) == B_OK) {
|
||||
_GroupChanged(index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case B_REFS_RECEIVED:
|
||||
{
|
||||
entry_ref ref;
|
||||
if (msg->FindRef("refs", &ref) == B_OK) {
|
||||
BPath path(&ref);
|
||||
|
||||
BMenuItem * item = fDestField->MenuItem();
|
||||
dev_t device = dev_for_path(path.Path());
|
||||
BVolume volume(device);
|
||||
if (volume.InitCheck() != B_OK)
|
||||
break;
|
||||
|
||||
BString name = path.Path();
|
||||
char sizeString[32];
|
||||
|
||||
convert_size(volume.FreeBytes(), sizeString, 32);
|
||||
name << " (" << sizeString << " free)";
|
||||
|
||||
item->SetLabel(name.String());
|
||||
fCurrentPath.SetTo(path.Path());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case B_SIMPLE_DATA:
|
||||
if (msg->WasDropped()) {
|
||||
uint32 type;
|
||||
int32 count;
|
||||
status_t ret = msg->GetInfo("refs", &type, &count);
|
||||
// Check whether the message means someone dropped a file
|
||||
// to our view
|
||||
if (ret == B_OK && type == B_REF_TYPE) {
|
||||
// If it is, send it along with the refs to the application
|
||||
msg->what = B_REFS_RECEIVED;
|
||||
be_app->PostMessage(msg);
|
||||
}
|
||||
}
|
||||
default:
|
||||
BView::MessageReceived(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageView::Install()
|
||||
{
|
||||
pkg_profile *type = static_cast<pkg_profile *>(fInfo.GetProfile(fCurrentType));
|
||||
uint32 n = type->items.CountItems();
|
||||
|
||||
fStatusWindow->Reset(n + 4);
|
||||
|
||||
fStatusWindow->StageStep(1, "Preparing package");
|
||||
|
||||
InstalledPackageInfo packageInfo(fInfo.GetName(), fInfo.GetVersion());
|
||||
|
||||
status_t err = packageInfo.InitCheck();
|
||||
if (err == B_OK) {
|
||||
// The package is already installed, inform the user
|
||||
BAlert *reinstall = new BAlert("reinstall",
|
||||
T("The given package seems to be already installed on your system. "
|
||||
"Would you like to uninstall the existing one and continue the "
|
||||
"installation?"), T("Yes"), T("No"));
|
||||
|
||||
if (reinstall->Go() == 0) {
|
||||
// Uninstall the package
|
||||
err = packageInfo.Uninstall();
|
||||
if (err != B_OK)
|
||||
return err;
|
||||
|
||||
err = packageInfo.SetTo(fInfo.GetName(), fInfo.GetVersion(), true);
|
||||
if (err != B_OK)
|
||||
return err;
|
||||
}
|
||||
else {
|
||||
// Abort the installation
|
||||
return B_FILE_EXISTS;
|
||||
}
|
||||
}
|
||||
else if (err == B_ENTRY_NOT_FOUND) {
|
||||
err = packageInfo.SetTo(fInfo.GetName(), fInfo.GetVersion(), true);
|
||||
if (err != B_OK)
|
||||
return err;
|
||||
}
|
||||
else if (fStatusWindow->Stopped())
|
||||
return B_FILE_EXISTS;
|
||||
else
|
||||
return err;
|
||||
|
||||
fStatusWindow->StageStep(1, "Installing files and directories");
|
||||
|
||||
// Install files and directories
|
||||
PkgItem *iter;
|
||||
BPath installedTo;
|
||||
uint32 i;
|
||||
BString label;
|
||||
|
||||
packageInfo.SetName(fInfo.GetName());
|
||||
// TODO: Here's a small problem, since right now it's not quite sure
|
||||
// which description is really used as such. The one displayed on
|
||||
// the installer is mostly package installation description, but
|
||||
// most people use it for describing the application in more detail
|
||||
// then in the short description.
|
||||
// For now, we'll use the short description if possible.
|
||||
BString description = fInfo.GetShortDescription();
|
||||
if (description.Length() <= 0)
|
||||
description = fInfo.GetDescription();
|
||||
packageInfo.SetDescription(description.String());
|
||||
packageInfo.SetSpaceNeeded(type->space_needed);
|
||||
|
||||
for (i = 0;i < n;i++) {
|
||||
iter = static_cast<PkgItem *>(type->items.ItemAt(i));
|
||||
err = iter->WriteToPath(fCurrentPath.Path(), &installedTo);
|
||||
if (err != B_OK)
|
||||
return err;
|
||||
if (fStatusWindow->Stopped())
|
||||
return B_FILE_EXISTS;
|
||||
label = "";
|
||||
label << (uint32)(i + 1) << " of " << (uint32)n;
|
||||
fStatusWindow->StageStep(1, NULL, label.String());
|
||||
|
||||
packageInfo.AddItem(installedTo.Path());
|
||||
}
|
||||
|
||||
fStatusWindow->StageStep(1, "Finishing installation", "");
|
||||
|
||||
err = packageInfo.Save();
|
||||
if (err != B_OK)
|
||||
return err;
|
||||
|
||||
fStatusWindow->StageStep(1, "Done");
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void
|
||||
PackageView::_InitView()
|
||||
{
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
BTextView *description = new BTextView(BRect(0, 0, 20, 20), "description",
|
||||
BRect(4, 4, 16, 16), B_FOLLOW_NONE, B_WILL_DRAW);
|
||||
description->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
description->SetText(fInfo.GetDescription());
|
||||
description->MakeEditable(false);
|
||||
description->MakeSelectable(false);
|
||||
|
||||
fInstallTypes = new BPopUpMenu("none");
|
||||
|
||||
BMenuField *installType = new BMenuField("install_type",
|
||||
T("Installation type:"), fInstallTypes, 0);
|
||||
installType->SetAlignment(B_ALIGN_RIGHT);
|
||||
installType->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_MIDDLE));
|
||||
|
||||
fInstallDesc = new BTextView(BRect(0, 0, 10, 10), "install_desc",
|
||||
BRect(2, 2, 8, 8), B_FOLLOW_NONE, B_WILL_DRAW);
|
||||
fInstallDesc->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
fInstallDesc->MakeEditable(false);
|
||||
fInstallDesc->MakeSelectable(false);
|
||||
fInstallDesc->SetText(T("No installation type selected"));
|
||||
fInstallDesc->TextHeight(0, fInstallDesc->TextLength());
|
||||
|
||||
fInstall = new BButton("install_button", T("Install"),
|
||||
new BMessage(P_MSG_INSTALL));
|
||||
|
||||
BView *installField = BGroupLayoutBuilder(B_VERTICAL, 5.0f)
|
||||
.AddGroup(B_HORIZONTAL)
|
||||
.Add(installType)
|
||||
.AddGlue()
|
||||
.End()
|
||||
.Add(fInstallDesc);
|
||||
|
||||
BBox *installBox = new BBox("install_box");
|
||||
installBox->AddChild(installField);
|
||||
|
||||
BView *root = BGroupLayoutBuilder(B_VERTICAL, 3.0f)
|
||||
.Add(description)
|
||||
.Add(installBox)
|
||||
.AddGroup(B_HORIZONTAL)
|
||||
.AddGlue()
|
||||
.Add(fInstall)
|
||||
.End();
|
||||
|
||||
AddChild(root);
|
||||
|
||||
fInstall->MakeDefault(true);
|
||||
}*/
|
||||
|
||||
|
||||
void
|
||||
PackageView::_InitView()
|
||||
{
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
BRect rect = Bounds();
|
||||
BTextView *description = new BTextView(rect, "description",
|
||||
rect.InsetByCopy(5, 5), B_FOLLOW_NONE, B_WILL_DRAW);
|
||||
description->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
description->SetText(fInfo.GetDescription());
|
||||
description->MakeEditable(false);
|
||||
description->MakeSelectable(false);
|
||||
|
||||
float length = description->TextHeight(0, description->TextLength()) + 5;
|
||||
if (length > kMaxDescHeight) {
|
||||
// Set a scroller for the description.
|
||||
description->ResizeTo(rect.Width() - B_V_SCROLL_BAR_WIDTH, kMaxDescHeight);
|
||||
BScrollView *scroller = new BScrollView("desciption_view", description,
|
||||
B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS, false, true, B_NO_BORDER);
|
||||
|
||||
AddChild(scroller);
|
||||
rect = scroller->Frame();
|
||||
}
|
||||
else {
|
||||
description->ResizeTo(rect.Width(), length);
|
||||
AddChild(description);
|
||||
rect = description->Frame();
|
||||
}
|
||||
|
||||
rect.top = rect.bottom + 2;
|
||||
rect.bottom += 100;
|
||||
BBox *installBox = new BBox(rect.InsetByCopy(2, 2), "install_box");
|
||||
|
||||
fInstallTypes = new BPopUpMenu("none");
|
||||
|
||||
BMenuField *installType = new BMenuField(BRect(2, 2, 100, 50), "install_type",
|
||||
T("Installation type:"), fInstallTypes, false);
|
||||
installType->SetDivider(installType->StringWidth(installType->Label()) + 8);
|
||||
installType->SetAlignment(B_ALIGN_RIGHT);
|
||||
installType->ResizeToPreferred();
|
||||
|
||||
installBox->AddChild(installType);
|
||||
|
||||
rect = installBox->Bounds().InsetBySelf(4, 4);
|
||||
rect.top = installType->Frame().bottom;
|
||||
fInstallDesc = new BTextView(rect, "install_desc",
|
||||
BRect(2, 2, rect.Width() - 2, rect.Height() - 2), B_FOLLOW_NONE,
|
||||
B_WILL_DRAW);
|
||||
fInstallDesc->MakeEditable(false);
|
||||
fInstallDesc->MakeSelectable(false);
|
||||
fInstallDesc->SetText(T("No installation type selected"));
|
||||
fInstallDesc->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
fInstallDesc->ResizeTo(rect.Width() - B_V_SCROLL_BAR_WIDTH, 60);
|
||||
BScrollView *scroller = new BScrollView("desciption_view", fInstallDesc,
|
||||
B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS, false, true, B_NO_BORDER);
|
||||
|
||||
installBox->ResizeTo(installBox->Bounds().Width(),
|
||||
scroller->Frame().bottom + 10);
|
||||
|
||||
installBox->AddChild(scroller);
|
||||
|
||||
AddChild(installBox);
|
||||
|
||||
fDestination = new BPopUpMenu("none");
|
||||
|
||||
rect = installBox->Frame();
|
||||
rect.top = rect.bottom + 5;
|
||||
rect.bottom += 35;
|
||||
fDestField = new BMenuField(rect, "install_to", T("Install to:"),
|
||||
fDestination, false);
|
||||
fDestField->SetDivider(fDestField->StringWidth(fDestField->Label()) + 8);
|
||||
fDestField->SetAlignment(B_ALIGN_RIGHT);
|
||||
fDestField->ResizeToPreferred();
|
||||
|
||||
AddChild(fDestField);
|
||||
|
||||
fInstall = new BButton(rect, "install_button", T("Install"),
|
||||
new BMessage(P_MSG_INSTALL));
|
||||
fInstall->ResizeToPreferred();
|
||||
AddChild(fInstall);
|
||||
fInstall->MoveTo(Bounds().Width() - fInstall->Bounds().Width() - 10, rect.top + 2);
|
||||
fInstall->MakeDefault(true);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageView::_InitProfiles()
|
||||
{
|
||||
// Set all profiles
|
||||
int i = 0, num = fInfo.GetProfileCount();
|
||||
pkg_profile *prof;
|
||||
BMenuItem *item = 0;
|
||||
char sizeString[32];
|
||||
BString name = "";
|
||||
BMessage *message;
|
||||
|
||||
if (num > 0) { // Add the default item
|
||||
prof = fInfo.GetProfile(0);
|
||||
convert_size(prof->space_needed, sizeString, 32);
|
||||
name << prof->name << " (" << sizeString << ")";
|
||||
|
||||
message = new BMessage(P_MSG_GROUP_CHANGED);
|
||||
message->AddInt32("index", 0);
|
||||
item = new BMenuItem(name.String(), message);
|
||||
fInstallTypes->AddItem(item);
|
||||
item->SetMarked(true);
|
||||
fCurrentType = 0;
|
||||
}
|
||||
|
||||
for (i = 1; i < num; i++) {
|
||||
prof = fInfo.GetProfile(i);
|
||||
|
||||
if (prof) {
|
||||
convert_size(prof->space_needed, sizeString, 32);
|
||||
name = prof->name;
|
||||
name << " (" << sizeString << ")";
|
||||
|
||||
message = new BMessage(P_MSG_GROUP_CHANGED);
|
||||
message->AddInt32("index", i);
|
||||
item = new BMenuItem(name.String(), message);
|
||||
fInstallTypes->AddItem(item);
|
||||
}
|
||||
else
|
||||
fInstallTypes->AddSeparatorItem();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageView::_GroupChanged(int32 index)
|
||||
{
|
||||
if (index < 0)
|
||||
return B_ERROR;
|
||||
|
||||
BMenuItem *iter;
|
||||
int32 i, num = fDestination->CountItems();
|
||||
|
||||
// Clear the choice list
|
||||
for (i = 0;i < num;i++) {
|
||||
iter = fDestination->RemoveItem((int32)0);
|
||||
delete iter;
|
||||
}
|
||||
|
||||
fCurrentType = index;
|
||||
pkg_profile *prof = fInfo.GetProfile(index);
|
||||
BString test;
|
||||
fInstallDesc->SetText(prof->description.String());
|
||||
|
||||
if (prof) {
|
||||
BMenuItem *item = 0;
|
||||
BPath path;
|
||||
BMessage *temp;
|
||||
BVolume volume;
|
||||
|
||||
if (prof->path_type == P_INSTALL_PATH) {
|
||||
dev_t device;
|
||||
BString name;
|
||||
char sizeString[32];
|
||||
|
||||
if (find_directory(B_BEOS_APPS_DIRECTORY, &path) == B_OK) {
|
||||
device = dev_for_path(path.Path());
|
||||
if (volume.SetTo(device) == B_OK && !volume.IsReadOnly()) {
|
||||
temp = new BMessage(P_MSG_PATH_CHANGED);
|
||||
temp->AddString("path", BString(path.Path()));
|
||||
|
||||
convert_size(volume.FreeBytes(), sizeString, 32);
|
||||
name = path.Path();
|
||||
name << " (" << sizeString << " free)";
|
||||
item = new BMenuItem(name.String(), temp);
|
||||
item->SetTarget(this);
|
||||
fDestination->AddItem(item);
|
||||
}
|
||||
}
|
||||
if (find_directory(B_APPS_DIRECTORY, &path) == B_OK) {
|
||||
device = dev_for_path(path.Path());
|
||||
if (volume.SetTo(device) == B_OK && !volume.IsReadOnly()) {
|
||||
temp = new BMessage(P_MSG_PATH_CHANGED);
|
||||
temp->AddString("path", BString(path.Path()));
|
||||
|
||||
convert_size(volume.FreeBytes(), sizeString, 32);
|
||||
name = path.Path();
|
||||
name << " (" << sizeString << " free)";
|
||||
item = new BMenuItem(name.String(), temp);
|
||||
item->SetTarget(this);
|
||||
fDestination->AddItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (item) {
|
||||
item->SetMarked(true);
|
||||
fCurrentPath.SetTo(path.Path());
|
||||
}
|
||||
fDestination->AddSeparatorItem();
|
||||
|
||||
item = new BMenuItem("Other...", new BMessage(P_MSG_OPEN_PANEL));
|
||||
item->SetTarget(this);
|
||||
fDestination->AddItem(item);
|
||||
|
||||
fDestField->SetEnabled(true);
|
||||
}
|
||||
else if (prof->path_type == P_USER_PATH) {
|
||||
BString name;
|
||||
char sizeString[32], volumeName[B_FILE_NAME_LENGTH];
|
||||
BVolumeRoster roster;
|
||||
BDirectory mountPoint;
|
||||
|
||||
while (roster.GetNextVolume(&volume) != B_BAD_VALUE) {
|
||||
if (volume.IsReadOnly() ||
|
||||
volume.GetRootDirectory(&mountPoint) != B_OK)
|
||||
continue;
|
||||
|
||||
if (path.SetTo(&mountPoint, NULL) != B_OK)
|
||||
continue;
|
||||
|
||||
temp = new BMessage(P_MSG_PATH_CHANGED);
|
||||
temp->AddString("path", BString(path.Path()));
|
||||
|
||||
convert_size(volume.FreeBytes(), sizeString, 32);
|
||||
volume.GetName(volumeName);
|
||||
name = volumeName;
|
||||
name << " (" << sizeString << " free)";
|
||||
item = new BMenuItem(name.String(), temp);
|
||||
item->SetTarget(this);
|
||||
fDestination->AddItem(item);
|
||||
}
|
||||
|
||||
fDestField->SetEnabled(true);
|
||||
}
|
||||
else
|
||||
fDestField->SetEnabled(false);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
* Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
|
||||
*/
|
||||
#ifndef PACKAGEVIEW_H
|
||||
#define PACKAGEVIEW_H
|
||||
|
||||
#include "PackageInfo.h"
|
||||
#include "PackageStatus.h"
|
||||
#include <View.h>
|
||||
#include <Box.h>
|
||||
#include <Button.h>
|
||||
#include <MenuField.h>
|
||||
#include <FilePanel.h>
|
||||
|
||||
enum {
|
||||
P_MSG_GROUP_CHANGED = 'gpch',
|
||||
P_MSG_PATH_CHANGED,
|
||||
P_MSG_OPEN_PANEL,
|
||||
P_MSG_INSTALL
|
||||
};
|
||||
|
||||
|
||||
class PackageView : public BView {
|
||||
public:
|
||||
PackageView(BRect frame, const entry_ref *ref);
|
||||
~PackageView();
|
||||
|
||||
void AttachedToWindow();
|
||||
void MessageReceived(BMessage *msg);
|
||||
|
||||
status_t Install();
|
||||
|
||||
private:
|
||||
void _InitView();
|
||||
void _InitProfiles();
|
||||
|
||||
status_t _GroupChanged(int32 index);
|
||||
|
||||
BPopUpMenu *fInstallTypes;
|
||||
BTextView *fInstallDesc;
|
||||
BPopUpMenu *fDestination;
|
||||
BMenuField *fDestField;
|
||||
BButton *fInstall;
|
||||
|
||||
BFilePanel *fOpenPanel;
|
||||
BPath fCurrentPath;
|
||||
uint32 fCurrentType;
|
||||
|
||||
PackageInfo fInfo;
|
||||
PackageStatus *fStatusWindow;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
* Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
|
||||
*/
|
||||
|
||||
|
||||
#include "PackageWindow.h"
|
||||
|
||||
#include <Application.h>
|
||||
|
||||
#include <GroupLayout.h>
|
||||
|
||||
// Macro reserved for later localization
|
||||
#define T(x) x
|
||||
|
||||
|
||||
PackageWindow::PackageWindow(const entry_ref *ref)
|
||||
: BWindow(BRect(100, 100, 600, 300), T("Package Installer"), B_TITLED_WINDOW,
|
||||
B_NOT_ZOOMABLE | B_NOT_RESIZABLE)
|
||||
{
|
||||
//SetLayout(new BGroupLayout(B_HORIZONTAL));
|
||||
|
||||
fBackground = new PackageView(Bounds(), ref);
|
||||
AddChild(fBackground);
|
||||
|
||||
ResizeTo(Bounds().Width(), fBackground->Bounds().Height());
|
||||
}
|
||||
|
||||
|
||||
PackageWindow::~PackageWindow()
|
||||
{
|
||||
RemoveChild(fBackground);
|
||||
|
||||
delete fBackground;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageWindow::Quit()
|
||||
{
|
||||
be_app->PostMessage(P_WINDOW_QUIT);
|
||||
BWindow::Quit();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
* Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
|
||||
*/
|
||||
#ifndef PACKAGEWINDOW_H
|
||||
#define PACKAGEWINDOW_H
|
||||
|
||||
#include "PackageView.h"
|
||||
#include <Window.h>
|
||||
#include <Entry.h>
|
||||
|
||||
|
||||
const uint32 P_WINDOW_QUIT = 'PiWq';
|
||||
|
||||
|
||||
class PackageWindow : public BWindow {
|
||||
public:
|
||||
PackageWindow(const entry_ref *refs);
|
||||
virtual ~PackageWindow();
|
||||
|
||||
virtual void Quit();
|
||||
|
||||
private:
|
||||
PackageView *fBackground;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
* Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
|
||||
*/
|
||||
|
||||
|
||||
#include "PackageWindow.h"
|
||||
|
||||
#include <Application.h>
|
||||
#include <FilePanel.h>
|
||||
#include <List.h>
|
||||
#include <Alert.h>
|
||||
#include <TextView.h>
|
||||
#include <Entry.h>
|
||||
#include <Autolock.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
class PackageInstaller : public BApplication {
|
||||
public:
|
||||
PackageInstaller();
|
||||
~PackageInstaller();
|
||||
|
||||
void RefsReceived(BMessage *msg);
|
||||
void ArgvReceived(int32 argc, char **argv);
|
||||
void ReadyToRun();
|
||||
|
||||
void MessageReceived(BMessage *msg);
|
||||
|
||||
void AboutRequested();
|
||||
|
||||
private:
|
||||
BFilePanel *fOpen;
|
||||
uint32 fWindowCount;
|
||||
};
|
||||
|
||||
|
||||
PackageInstaller::PackageInstaller()
|
||||
: BApplication("application/x-vnd.Haiku-PackageInstaller"),
|
||||
fWindowCount(0)
|
||||
{
|
||||
fOpen = new BFilePanel(B_OPEN_PANEL);
|
||||
}
|
||||
|
||||
|
||||
PackageInstaller::~PackageInstaller()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageInstaller::ReadyToRun()
|
||||
{
|
||||
// We're ready to run - if no windows are yet visible, this means that
|
||||
// we should show a open panel
|
||||
if (fWindowCount == 0) {
|
||||
fOpen->Show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageInstaller::RefsReceived(BMessage *msg)
|
||||
{
|
||||
uint32 type;
|
||||
int32 i, count;
|
||||
status_t ret = msg->GetInfo("refs", &type, &count);
|
||||
if (ret != B_OK || type != B_REF_TYPE)
|
||||
return;
|
||||
|
||||
entry_ref ref;
|
||||
PackageWindow *iter;
|
||||
for (i = 0; i < count; i++) {
|
||||
if (msg->FindRef("refs", i, &ref) == B_OK) {
|
||||
iter = new PackageWindow(&ref);
|
||||
fWindowCount++;
|
||||
iter->Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageInstaller::ArgvReceived(int32 argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
BPath path;
|
||||
entry_ref ref;
|
||||
status_t ret = B_OK;
|
||||
PackageWindow *iter = 0;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (path.SetTo(argv[i]) != B_OK) {
|
||||
fprintf(stderr, "Error! \"%s\" is not a valid path.\n", argv[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = get_ref_for_path(path.Path(), &ref);
|
||||
if (ret != B_OK) {
|
||||
fprintf(stderr, "Error (%s)! Could not open \"%s\".\n", strerror(ret),
|
||||
argv[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
iter = new PackageWindow(&ref);
|
||||
fWindowCount++;
|
||||
iter->Show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageInstaller::MessageReceived(BMessage *msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
case P_WINDOW_QUIT:
|
||||
fWindowCount--;
|
||||
if (fWindowCount == 0) {
|
||||
BAutolock lock(this);
|
||||
if (lock.IsLocked())
|
||||
Quit();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BApplication::MessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageInstaller::AboutRequested()
|
||||
{
|
||||
BAlert *about = new BAlert("about",
|
||||
"PackageInstaller\n"
|
||||
"BeOS legacy .pkg file installer for Haiku.\n\n"
|
||||
"Copyright 2007,\nŁukasz 'Sil2100' Zemczak\n\n"
|
||||
"Copyright (c) 2007 Haiku, Inc. \n",
|
||||
"Close");
|
||||
|
||||
BTextView *view = about->TextView();
|
||||
BFont font;
|
||||
view->SetStylable(true);
|
||||
view->GetFont(&font);
|
||||
font.SetFace(B_BOLD_FACE);
|
||||
font.SetSize(font.Size() * 1.5);
|
||||
view->SetFontAndColor(0, 17, &font);
|
||||
|
||||
about->Go();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
PackageInstaller app;
|
||||
app.Run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user