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:
Ryan Leavengood
2007-10-13 04:46:32 +00:00
parent 98148bd6c5
commit 44f919da9a
20 changed files with 4105 additions and 0 deletions
+4
View File
@@ -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
+21
View File
@@ -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
+78
View File
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2007, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Author:
* Łukasz 'Sil2100' Zemczak <[email protected]>
*/
#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;
+697
View File
@@ -0,0 +1,697 @@
/*
* Copyright (c) 2007, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Author:
* Łukasz 'Sil2100' Zemczak <[email protected]>
*/
#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;
}
+114
View File
@@ -0,0 +1,114 @@
/*
* Copyright (c) 2007, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Author:
* Łukasz 'Sil2100' Zemczak <[email protected]>
*/
#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
+169
View File
@@ -0,0 +1,169 @@
/*
* Copyright (c) 2007, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Author:
* Łukasz 'Sil2100' Zemczak <[email protected]>
*/
#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;
}
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2007, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Author:
* Łukasz 'Sil2100' Zemczak <[email protected]>
*/
#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 <[email protected]>
*/
#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 <[email protected]>
*/
#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
+629
View File
@@ -0,0 +1,629 @@
/*
* Copyright (c) 2007, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Author:
* Łukasz 'Sil2100' Zemczak <[email protected]>
*/
#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;
}
+59
View File
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2007, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Author:
* Łukasz 'Sil2100' Zemczak <[email protected]>
*/
#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 <[email protected]>
*/
#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();
}
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2007, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Author:
* Łukasz 'Sil2100' Zemczak <[email protected]>
*/
#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
+163
View File
@@ -0,0 +1,163 @@
/*
* Copyright (c) 2007, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Author:
* Łukasz 'Sil2100' Zemczak <[email protected]>
*/
#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;
}