From fc11b80c6c3a2d9f1a52014ab1341a9923d74e8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 6 Aug 2009 15:00:52 +0000 Subject: [PATCH] * Applied patch by sil2100 that basically adds a "Yes to all" button, see ticket #4059. I fixed a few style violations, though. Thanks! * Automatic whitespace cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32161 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/packageinstaller/PackageItem.cpp | 295 +++++++++++----------- src/apps/packageinstaller/PackageItem.h | 54 ++-- src/apps/packageinstaller/PackageView.cpp | 150 ++++++++--- src/apps/packageinstaller/PackageView.h | 6 +- 4 files changed, 307 insertions(+), 198 deletions(-) diff --git a/src/apps/packageinstaller/PackageItem.cpp b/src/apps/packageinstaller/PackageItem.cpp index 98f32f87dd..7217d385e8 100644 --- a/src/apps/packageinstaller/PackageItem.cpp +++ b/src/apps/packageinstaller/PackageItem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2009, Haiku, Inc. + * Copyright 2007-2009, Haiku, Inc. * Distributed under the terms of the MIT license. * * Author: @@ -9,16 +9,19 @@ #include "PackageItem.h" +#include + #include #include #include +#include #include #include #include -#include #include "zlib.h" + // Macro reserved for later localization #define T(x) x @@ -37,7 +40,7 @@ enum { status_t inflate_data(uint8 *in, uint32 inSize, uint8 *out, uint32 outSize) -{ +{ z_stream stream; stream.zalloc = Z_NULL; stream.zfree = Z_NULL; @@ -146,7 +149,7 @@ PackageItem::~PackageItem() void -PackageItem::SetTo(BFile *parent, const BString &path, uint8 type, uint32 ctime, +PackageItem::SetTo(BFile *parent, const BString &path, uint8 type, uint32 ctime, uint32 mtime, uint64 offset, uint64 size) { fPackage = parent; @@ -160,25 +163,6 @@ PackageItem::SetTo(BFile *parent, const BString &path, uint8 type, uint32 ctime, } -int32 -PackageItem::ItemExists(const char *name) -{ - // TODO: this function doesn't really fit in, the GUI should be separated - // from the package engine completely - - BString alertString = "The "; - - alertString << ItemKind() << " named \'" << 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 PackageItem::InitPath(const char *path, BPath *destination) { @@ -218,7 +202,7 @@ PackageItem::InitPath(const char *path, BPath *destination) status_t -PackageItem::HandleAttributes(BPath *destination, BNode *node, +PackageItem::HandleAttributes(BPath *destination, BNode *node, const char *header) { status_t ret = B_OK; @@ -256,7 +240,7 @@ PackageItem::HandleAttributes(BPath *destination, BNode *node, continue; ret = ParseAttribute(buffer, node, &attrName, &nameSize, &attrType, - &attrData, &dataSize, &temp, &tempSize, &attrCSize, &attrOSize, + &attrData, &dataSize, &temp, &tempSize, &attrCSize, &attrOSize, &attrStarted, &done); if (ret != B_OK || done) { if (ret != B_OK) { @@ -276,9 +260,9 @@ PackageItem::HandleAttributes(BPath *destination, BNode *node, status_t -PackageItem::ParseAttribute(uint8 *buffer, BNode *node, char **attrName, - uint32 *nameSize, uint32 *attrType, uint8 **attrData, uint64 *dataSize, - uint8 **temp, uint64 *tempSize, uint64 *attrCSize, uint64 *attrOSize, +PackageItem::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; @@ -320,7 +304,7 @@ PackageItem::ParseAttribute(uint8 *buffer, BNode *node, char **attrName, parser_debug(" BeAT.\n"); fPackage->Read(attrType, 4); - swap_data(B_UINT32_TYPE, attrType, sizeof(*attrType), + swap_data(B_UINT32_TYPE, attrType, sizeof(*attrType), B_SWAP_BENDIAN_TO_HOST); } else if (!memcmp(buffer, "BeAD", 5)) { if (!*attrStarted) { @@ -330,11 +314,11 @@ PackageItem::ParseAttribute(uint8 *buffer, BNode *node, char **attrName, parser_debug(" BeAD.\n"); fPackage->Read(attrCSize, 8); - swap_data(B_UINT64_TYPE, attrCSize, sizeof(*attrCSize), + 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), + swap_data(B_UINT64_TYPE, attrOSize, sizeof(*attrOSize), B_SWAP_BENDIAN_TO_HOST); fPackage->Seek(4, SEEK_CUR); // TODO: Check what this means @@ -350,7 +334,7 @@ PackageItem::ParseAttribute(uint8 *buffer, BNode *node, char **attrName, *attrData = new uint8[*dataSize]; } - if (fPackage->Read(*temp, *attrCSize) + if (fPackage->Read(*temp, *attrCSize) != static_cast(*attrCSize)) { ret = B_ERROR; return ret; @@ -367,7 +351,7 @@ PackageItem::ParseAttribute(uint8 *buffer, BNode *node, char **attrName, } parser_debug(" Padding.\n"); - ssize_t wrote = node->WriteAttr(*attrName, *attrType, 0, *attrData, + ssize_t wrote = node->WriteAttr(*attrName, *attrType, 0, *attrData, *attrOSize); if (wrote != static_cast(*attrOSize)) { parser_debug("Failed to write attribute %s %s\n", *attrName, strerror(wrote)); @@ -391,7 +375,7 @@ PackageItem::ParseAttribute(uint8 *buffer, BNode *node, char **attrName, status_t -PackageItem::ParseData(uint8 *buffer, BFile *file, uint64 originalSize, +PackageItem::ParseData(uint8 *buffer, BFile *file, uint64 originalSize, bool *done) { status_t ret = B_OK; @@ -400,11 +384,11 @@ PackageItem::ParseData(uint8 *buffer, BFile *file, uint64 originalSize, parser_debug(" Found file data.\n"); uint64 compressed, original; fPackage->Read(&compressed, 8); - swap_data(B_UINT64_TYPE, &compressed, sizeof(uint64), + 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), + swap_data(B_UINT64_TYPE, &original, sizeof(uint64), B_SWAP_BENDIAN_TO_HOST); parser_debug(" Still good... (%llu : %llu)\n", original, originalSize); @@ -446,25 +430,28 @@ PackageItem::ParseData(uint8 *buffer, BFile *file, uint64 originalSize, PackageDirectory::PackageDirectory(BFile *parent, const BString &path, uint8 type, uint32 ctime, uint32 mtime, uint64 offset, uint64 size) - : PackageItem(parent, path, type, ctime, mtime, offset, size) + : + PackageItem(parent, path, type, ctime, mtime, offset, size) { } status_t -PackageDirectory::WriteToPath(const char *path, BPath *final) +PackageDirectory::WriteToPath(const char *path, ItemState *state) { - BPath destination; + BPath &destination = state->destination; status_t ret; parser_debug("Directory: %s WriteToPath() called!\n", fPath.String()); ret = InitPath(path, &destination); + parser_debug("Ret: %d %s\n", ret, strerror(ret)); 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); + parser_debug("Create dir ret: %d %s\n", ret, strerror(ret)); if (ret != B_OK) return ret; BDirectory dir(destination.Path()); @@ -472,7 +459,7 @@ PackageDirectory::WriteToPath(const char *path, BPath *final) if (fCreationTime) dir.SetCreationTime(static_cast(fCreationTime)); - + if (fModificationTime) dir.SetModificationTime(static_cast(fModificationTime)); @@ -480,10 +467,8 @@ PackageDirectory::WriteToPath(const char *path, BPath *final) // we can check here whether it is necessary to continue if (fOffset) ret = HandleAttributes(&destination, &dir, "FoDa"); - - if (final) - *final = destination; + parser_debug("Ret: %d %s\n", ret, strerror(ret)); return ret; } @@ -502,7 +487,8 @@ PackageFile::PackageFile(BFile *parent, const BString &path, uint8 type, uint32 ctime, uint32 mtime, uint64 offset, uint64 size, uint64 originalSize, uint32 platform, const BString &mime, const BString &signature, uint32 mode) - : PackageItem(parent, path, type, ctime, mtime, offset, size), + : + PackageItem(parent, path, type, ctime, mtime, offset, size), fOriginalSize(originalSize), fPlatform(platform), fMode(mode), @@ -513,43 +499,55 @@ PackageFile::PackageFile(BFile *parent, const BString &path, uint8 type, status_t -PackageFile::WriteToPath(const char *path, BPath *final) +PackageFile::WriteToPath(const char *path, ItemState *state) { - BPath destination; - status_t ret; + if (state == NULL) + return B_ERROR; + + BPath &destination = state->destination; + status_t ret = B_OK; 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); + BFile file; + if (state->status == B_NO_INIT || destination.InitCheck() != B_OK) { + ret = InitPath(path, &destination); if (ret != B_OK) return ret; - } else if (ret != B_OK) + + ret = file.SetTo(destination.Path(), + B_WRITE_ONLY | B_CREATE_FILE | B_FAIL_IF_EXISTS); + 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); + } else if (ret == B_FILE_EXISTS) + state->status = B_FILE_EXISTS; + + if (ret != B_OK) + return ret; + } + + if (state->status == B_FILE_EXISTS) { + switch (state->policy) { + case P_EXISTS_OVERWRITE: + ret = file.SetTo(destination.Path(), + B_WRITE_ONLY | B_ERASE_FILE); + break; + + case P_EXISTS_NONE: + case P_EXISTS_ASK: + ret = B_FILE_EXISTS; + break; + + case P_EXISTS_SKIP: + return B_OK; + } + } + + if (ret != B_OK) return ret; parser_debug(" File created!\n"); @@ -563,7 +561,7 @@ PackageFile::WriteToPath(const char *path, BPath *final) if (ret != B_OK) return ret; - + // Set the mimetype and application signature if present BNodeInfo info(&file); if (fMimeType.Length() > 0) { @@ -600,7 +598,7 @@ PackageFile::WriteToPath(const char *path, BPath *final) 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) { @@ -637,9 +635,6 @@ PackageFile::WriteToPath(const char *path, BPath *final) delete[] temp; } - if (final) - *final = destination; - return ret; } @@ -657,7 +652,8 @@ PackageFile::ItemKind() PackageLink::PackageLink(BFile *parent, const BString &path, const BString &link, uint8 type, uint32 ctime, uint32 mtime, uint32 mode, uint64 offset, uint64 size) - : PackageItem(parent, path, type, ctime, mtime, offset, size), + : + PackageItem(parent, path, type, ctime, mtime, offset, size), fMode(mode), fLink(link) { @@ -665,73 +661,88 @@ PackageLink::PackageLink(BFile *parent, const BString &path, status_t -PackageLink::WriteToPath(const char *path, BPath *final) +PackageLink::WriteToPath(const char *path, ItemState *state) { + if (state == NULL) + return B_ERROR; + + status_t ret = B_OK; + BSymLink symlink; parser_debug("Symlink: %s WriteToPath() called!\n", fPath.String()); - BPath destination; - status_t ret = InitPath(path, &destination); - if (ret != B_OK) - return ret; + BPath &destination = state->destination; + BDirectory *dir = &state->parent; - BString linkName(destination.Leaf()); - parser_debug("%s:%s:%s\n", fPath.String(), destination.Path(), - linkName.String()); + if (state->status == B_NO_INIT || destination.InitCheck() != B_OK + || dir->InitCheck() != B_OK) { + // Not yet initialized + ret = InitPath(path, &destination); + if (ret != B_OK) + return ret; - BPath dirPath; - ret = destination.GetParent(&dirPath); - BDirectory dir(dirPath.Path()); + BString linkName(destination.Leaf()); + parser_debug("%s:%s:%s\n", fPath.String(), destination.Path(), + linkName.String()); - ret = dir.InitCheck(); - if (ret == B_ENTRY_NOT_FOUND) { - if ((ret = create_directory(dirPath.Path(), kDefaultMode)) != B_OK) { - parser_debug("create_directory()) failed\n"); - return B_ERROR; - } - } - if (ret != B_OK) { - parser_debug("destination InitCheck failed %s for %s\n", strerror(ret), dirPath.Path()); - return ret; - } + BPath dirPath; + ret = destination.GetParent(&dirPath); + ret = dir->SetTo(dirPath.Path()); - BSymLink symlink; - ret = dir.CreateSymLink(destination.Path(), fLink.String(), &symlink); - if (ret == B_FILE_EXISTS) { - // We need to check if the existing symlink is pointing at the same path - // as our new one - if not, let's prompt the user - symlink.SetTo(destination.Path()); - BPath oldLink; - - ret = symlink.MakeLinkedPath(&dir, &oldLink); - chdir(dirPath.Path()); - - if (ret == B_BAD_VALUE || oldLink != fLink.String()) { - // The old symlink is different (or not a symlink) - ask the user - int32 selection = ItemExists(destination.Leaf()); - switch (selection) { - case 0: - { - symlink.Unset(); - BEntry entry; - ret = entry.SetTo(destination.Path()); - if (ret != B_OK) - return ret; - - entry.Remove(); - ret = dir.CreateSymLink(destination.Path(), fLink.String(), - &symlink); - break; - } - case 1: - parser_debug("Skipping already existent SymLink\n"); - return B_OK; - default: - ret = B_FILE_EXISTS; + if (ret == B_ENTRY_NOT_FOUND) { + ret = create_directory(dirPath.Path(), kDefaultMode); + if (ret != B_OK) { + parser_debug("create_directory()) failed\n"); + return B_ERROR; } - } else { - ret = B_OK; + } + if (ret != B_OK) { + parser_debug("destination InitCheck failed %s for %s\n", + strerror(ret), dirPath.Path()); + return ret; + } + + ret = dir->CreateSymLink(destination.Path(), fLink.String(), &symlink); + if (ret == B_FILE_EXISTS) { + // We need to check if the existing symlink is pointing at the same path + // as our new one - if not, let's prompt the user + symlink.SetTo(destination.Path()); + BPath oldLink; + + ret = symlink.MakeLinkedPath(dir, &oldLink); + chdir(dirPath.Path()); + + if (ret == B_BAD_VALUE || oldLink != fLink.String()) + state->status = ret = B_FILE_EXISTS; + else + ret = B_OK; } } + + if (state->status == B_FILE_EXISTS) { + switch (state->policy) { + case P_EXISTS_OVERWRITE: + { + BEntry entry; + ret = entry.SetTo(destination.Path()); + if (ret != B_OK) + return ret; + + entry.Remove(); + ret = dir->CreateSymLink(destination.Path(), fLink.String(), + &symlink); + break; + } + + case P_EXISTS_NONE: + case P_EXISTS_ASK: + ret = B_FILE_EXISTS; + break; + + case P_EXISTS_SKIP: + return B_OK; + } + } + if (ret != B_OK) { parser_debug("CreateSymLink failed\n"); return ret; @@ -743,7 +754,7 @@ PackageLink::WriteToPath(const char *path, BPath *final) if (fCreationTime && ret == B_OK) ret = symlink.SetCreationTime(static_cast(fCreationTime)); - + if (fModificationTime && ret == B_OK) { ret = symlink.SetModificationTime(static_cast( fModificationTime)); @@ -759,10 +770,6 @@ PackageLink::WriteToPath(const char *path, BPath *final) ret = HandleAttributes(&destination, &symlink, "LnDa"); } - if (final) { - *final = destination; - } - return ret; } diff --git a/src/apps/packageinstaller/PackageItem.h b/src/apps/packageinstaller/PackageItem.h index c57c342f08..114b279133 100644 --- a/src/apps/packageinstaller/PackageItem.h +++ b/src/apps/packageinstaller/PackageItem.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Haiku, Inc. + * Copyright 2007-2009, Haiku, Inc. * Distributed under the terms of the MIT license. * * Author: @@ -11,6 +11,7 @@ #include +#include #include #include #include @@ -32,10 +33,38 @@ enum { P_USER_PATH }; +// Existing item overwriting policy of a single file +enum { + P_EXISTS_ASK = 0, + P_EXISTS_OVERWRITE, + P_EXISTS_SKIP, + P_EXISTS_ABORT, + P_EXISTS_NONE +}; + extern status_t inflate_data(uint8* in, uint32 inSize, uint8* out, uint32 outSize); +struct ItemState { + ItemState() : policy(P_EXISTS_NONE), status(B_NO_INIT) {} + ~ItemState() {} + + inline void Reset(int32 currentPolicy) + { + destination.Unset(); + parent.Unset(); + status = B_NO_INIT; + policy = currentPolicy; + } + + BPath destination; + BDirectory parent; + uint8 policy; + status_t status; +}; + + class PackageItem { public: PackageItem(BFile* parent, const BString& path, @@ -44,16 +73,15 @@ public: virtual ~PackageItem(); virtual status_t WriteToPath(const char* path = NULL, - BPath* final = NULL) = 0; + ItemState *state = NULL) = 0; virtual void SetTo(BFile* parent, const BString& path, uint8 type, uint32 ctime, uint32 mtime, uint64 offset = 0, uint64 size = 0); + virtual const char* ItemKind() = 0; protected: - virtual const char* ItemKind() = 0; - int32 ItemExists(const char* name); status_t InitPath(const char* path, BPath* destination); - status_t HandleAttributes(BPath* destination, BNode* node, + status_t HandleAttributes(BPath* destination, BNode* node, const char* header); status_t ParseAttribute(uint8* buffer, BNode* node, @@ -84,9 +112,7 @@ public: uint64 offset = 0, uint64 size = 0); virtual status_t WriteToPath(const char* path = NULL, - BPath* final = NULL); - -protected: + ItemState *state = NULL); virtual const char* ItemKind(); }; @@ -100,16 +126,14 @@ public: const BString& signature, uint32 mode); virtual status_t WriteToPath(const char* path = NULL, - BPath* final = NULL); - -protected: + ItemState *state = NULL); virtual const char* ItemKind(); private: uint64 fOriginalSize; uint32 fPlatform; uint32 fMode; - + BString fMimeType; BString fSignature; }; @@ -119,13 +143,11 @@ class PackageLink : public PackageItem { public: PackageLink(BFile* parent, const BString& path, const BString& link, uint8 type, uint32 ctime, - uint32 mtime, uint32 mode, uint64 offset = 0, + uint32 mtime, uint32 mode, uint64 offset = 0, uint64 size = 0); virtual status_t WriteToPath(const char* path = NULL, - BPath* final = NULL); - -protected: + ItemState *state = NULL); virtual const char* ItemKind(); private: diff --git a/src/apps/packageinstaller/PackageView.cpp b/src/apps/packageinstaller/PackageView.cpp index 14a9734b90..d7ab1e1732 100644 --- a/src/apps/packageinstaller/PackageView.cpp +++ b/src/apps/packageinstaller/PackageView.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Haiku, Inc. + * Copyright 2007-2009, Haiku, Inc. * Distributed under the terms of the MIT license. * * Author: @@ -69,7 +69,7 @@ PackageView::PackageView(BRect frame, const entry_ref *ref) // Check whether the package has been successfuly parsed status_t ret = fInfo.InitCheck(); - if (ret == B_OK) + if (ret == B_OK) _InitProfiles(); ResizeTo(Bounds().Width(), fInstall->Frame().bottom + 4); @@ -129,7 +129,7 @@ PackageView::AttachedToWindow() PackageImageViewer *imageViewer = new PackageImageViewer(image); imageViewer->Go(); } - + // Show the disclaimer/info text popup, if present BString disclaimer = fInfo.GetDisclaimer(); if (disclaimer.Length() != 0) { @@ -175,14 +175,14 @@ PackageView::MessageReceived(BMessage *msg) 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, + "this issue with the package distributor."), T("OK"), NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); fprintf(stderr, "Error while installing the package : %s\n", strerror(ret)); } notify->Go(); fStatusWindow->Hide(); fInstall->SetEnabled(true); - + break; } case P_MSG_PATH_CHANGED: @@ -196,7 +196,7 @@ PackageView::MessageReceived(BMessage *msg) case P_MSG_OPEN_PANEL: fOpenPanel->Show(); break; - case P_MSG_GROUP_CHANGED: + case P_MSG_GROUP_CHANGED: { int32 index; if (msg->FindInt32("index", &index) == B_OK) { @@ -267,7 +267,7 @@ PackageView::Install() 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(); @@ -305,10 +305,11 @@ PackageView::Install() // Install files and directories PackageItem *iter; - BPath installedTo; + ItemState state; uint32 i; + int32 choice; 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 @@ -322,20 +323,35 @@ PackageView::Install() packageInfo.SetDescription(description.String()); packageInfo.SetSpaceNeeded(type->space_needed); + fItemExistsPolicy = P_EXISTS_NONE; + for (i = 0; i < n; i++) { + state.Reset(fItemExistsPolicy); // Reset the current item state iter = static_cast(type->items.ItemAt(i)); - err = iter->WriteToPath(fCurrentPath.Path(), &installedTo); + + err = iter->WriteToPath(fCurrentPath.Path(), &state); + if (err == B_FILE_EXISTS) { + // Writing to path failed because path already exists - ask the user + // what to do and retry the writing process + choice = _ItemExists(*iter, state.destination); + if (choice != P_EXISTS_ABORT) { + state.policy = choice; + err = iter->WriteToPath(fCurrentPath.Path(), &state); + } + } + if (err != B_OK) { fprintf(stderr, "Error while writing path %s\n", fCurrentPath.Path()); 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()); + packageInfo.AddItem(state.destination.Path()); } fStatusWindow->StageStep(1, "Finishing installation", ""); @@ -355,7 +371,7 @@ 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)); @@ -370,15 +386,15 @@ PackageView::_InitView() installType->SetAlignment(B_ALIGN_RIGHT); installType->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_MIDDLE)); - fInstallDesc = new BTextView(BRect(0, 0, 10, 10), "install_desc", + 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"), + + fInstall = new BButton("install_button", T("Install"), new BMessage(P_MSG_INSTALL)); BView *installField = BGroupLayoutBuilder(B_VERTICAL, 5.0f) @@ -400,7 +416,7 @@ PackageView::_InitView() .End(); AddChild(root); - + fInstall->MakeDefault(true); }*/ @@ -409,7 +425,7 @@ 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); @@ -424,7 +440,7 @@ PackageView::_InitView() 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(); } @@ -433,24 +449,24 @@ PackageView::_InitView() 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", + fInstallDesc = new BTextView(rect, "install_desc", BRect(2, 2, rect.Width() - 2, rect.Height() - 2), B_FOLLOW_NONE, B_WILL_DRAW); fInstallDesc->MakeEditable(false); @@ -461,28 +477,28 @@ PackageView::_InitView() 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:"), + 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"), + + fInstall = new BButton(rect, "install_button", T("Install"), new BMessage(P_MSG_INSTALL)); fInstall->ResizeToPreferred(); AddChild(fInstall); @@ -506,7 +522,7 @@ PackageView::_InitProfiles() 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); @@ -517,12 +533,12 @@ PackageView::_InitProfiles() 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); @@ -534,6 +550,68 @@ PackageView::_InitProfiles() } +int32 +PackageView::_ItemExists(PackageItem &item, BPath &path) +{ + int32 choice = P_EXISTS_NONE; + + switch (fItemExistsPolicy) { + case P_EXISTS_OVERWRITE: + choice = P_EXISTS_OVERWRITE; + break; + + case P_EXISTS_SKIP: + choice = P_EXISTS_SKIP; + break; + + case P_EXISTS_ASK: + case P_EXISTS_NONE: + { + BString alertString = T("The "); + + alertString << item.ItemKind() << T(" named \'") << path.Leaf() << "\' "; + alertString << T("already exists in the given path. Should the " + "existing file be replaced with the one from this package?"); + + BAlert *alert = new BAlert(T("file_exists"), alertString.String(), + T("Yes"), T("No"), T("Abort")); + + choice = alert->Go(); + switch (choice) { + case 0: + choice = P_EXISTS_OVERWRITE; + break; + case 1: + choice = P_EXISTS_SKIP; + break; + default: + return P_EXISTS_ABORT; + } + + if (fItemExistsPolicy == P_EXISTS_NONE) { + // TODO: Maybe add 'No, but ask again' type of choice as well? + alertString = T("Should this decision be remembered and all " + "existing files encountered in the future be "); + alertString << ((choice == P_EXISTS_OVERWRITE) + ? T("replaced?") : T("skipped?")); + + alert = new BAlert(T("policy_decision"), alertString.String(), + T("Yes"), T("No")); + + int32 decision = alert->Go(); + if (decision == 0) + fItemExistsPolicy = choice; + else + fItemExistsPolicy = P_EXISTS_ASK; + } + break; + } + } + + return choice; +} + + status_t PackageView::_GroupChanged(int32 index) { @@ -559,7 +637,7 @@ PackageView::_GroupChanged(int32 index) BPath path; BMessage *temp; BVolume volume; - + if (prof->path_type == P_INSTALL_PATH) { dev_t device; BString name; @@ -570,7 +648,7 @@ PackageView::_GroupChanged(int32 index) 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)"; diff --git a/src/apps/packageinstaller/PackageView.h b/src/apps/packageinstaller/PackageView.h index 88e738bed6..1471502500 100644 --- a/src/apps/packageinstaller/PackageView.h +++ b/src/apps/packageinstaller/PackageView.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Haiku, Inc. + * Copyright 2007-2009, Haiku, Inc. * Distributed under the terms of the MIT license. * * Author: @@ -36,12 +36,13 @@ class PackageView : public BView { void AttachedToWindow(); void MessageReceived(BMessage *msg); - + status_t Install(); private: void _InitView(); void _InitProfiles(); + int32 _ItemExists(PackageItem &item, BPath &path); status_t _GroupChanged(int32 index); @@ -54,6 +55,7 @@ class PackageView : public BView { BFilePanel *fOpenPanel; BPath fCurrentPath; uint32 fCurrentType; + int32 fItemExistsPolicy; PackageInfo fInfo; PackageStatus *fStatusWindow;