From 7ff74a7b9b10383fae7023e1871a53f98ded0d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Fri, 24 Apr 2009 12:24:25 +0000 Subject: [PATCH] * Converted to use layout-management. * New logo specific to R1 Alpha/1. * "Setup Partitions" is now always visible, since it will most likely be required to prepare a partition for installation anyways. * The optional packages are still in the GUI, but are collapsed by default as before. As there are currently no optional packages, a message will be displayed if no optional packages are found on the source partition. * The default label for the "Onto" popup is now "Please choose target" instead of the first partition found, even though it is not actually selected yet. * The EULA window is still shown, but it's not based on a BAlert anymore. * Only make main window non-minimizable if the Deskbar is not running (untested). * Style cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30368 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/installer/Installer.rdef | 2 +- src/apps/installer/InstallerApp.cpp | 140 ++++++++---- src/apps/installer/InstallerApp.h | 22 +- src/apps/installer/InstallerWindow.cpp | 289 +++++++++++++++++-------- src/apps/installer/InstallerWindow.h | 86 ++++---- src/apps/installer/Jamfile | 4 +- src/apps/installer/PackageViews.cpp | 83 +++++-- src/apps/installer/PackageViews.h | 3 + src/apps/installer/haikulogo.png | Bin 8860 -> 18441 bytes 9 files changed, 417 insertions(+), 212 deletions(-) diff --git a/src/apps/installer/Installer.rdef b/src/apps/installer/Installer.rdef index 27db254b92..caca6ed83d 100644 --- a/src/apps/installer/Installer.rdef +++ b/src/apps/installer/Installer.rdef @@ -10,7 +10,7 @@ resource app_version { internal = 0, short_info = "Installer", - long_info = "Installer ©2005-2007 Haiku, Inc." + long_info = "Installer ©2005-2009 Haiku, Inc." }; resource app_flags B_EXCLUSIVE_LAUNCH; diff --git a/src/apps/installer/InstallerApp.cpp b/src/apps/installer/InstallerApp.cpp index 3f8ab995d5..133d135b48 100644 --- a/src/apps/installer/InstallerApp.cpp +++ b/src/apps/installer/InstallerApp.cpp @@ -1,22 +1,45 @@ /* - * Copyright 2005, Jérôme DUVAL. All rights reserved. - * Distributed under the terms of the MIT License. + * Copyright 2009, Stephan Aßmus + * Copyright 2005, Jérôme DUVAL. + * All rights reserved. Distributed under the terms of the MIT License. */ +#include "InstallerApp.h" + #include +#include +#include #include #include #include -#include "InstallerApp.h" -const char *APP_SIG = "application/x-vnd.Haiku-Installer"; -#define EULA_TEXT "HAIKU INC - END USER LICENSE AGREEMENT\n\n\ -NOTICE: READ THIS BEFORE INSTALLING OR USING Haiku\n\ -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\ -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\ -THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\ -" +static const uint32 kMsgAgree = 'agre'; + +static const char* kEULAText = +"NOTICE: READ THIS BEFORE INSTALLING OR USING HAIKU\n\n" + +"Copyright " B_UTF8_COPYRIGHT " 2001-2009 The Haiku Project. All rights " +"reserved. The copyright to the Haiku code is property of Haiku, Inc. or of " +"the respective authors where expressly noted in the source.\n\n" + +"Permission is hereby granted, free of charge, to any person obtaining a " +"copy of this software and associated documentation files (the \"Software\"), " +"to deal in the Software without restriction, including without limitation " +"the rights to use, copy, modify, merge, publish, distribute, sublicense, " +"and/or sell copies of the Software, and to permit persons to whom the " +"Software is furnished to do so, subject to the following conditions:\n\n" +"The above copyright notice and this permission notice shall be included in " +"all copies or substantial portions of the Software.\n\n" + +"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS " +"OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, " +"FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE " +"AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER " +"LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING " +"FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS " +"IN THE SOFTWARE."; + int main(int, char **) { @@ -25,42 +48,29 @@ int main(int, char **) return 0; } + InstallerApp::InstallerApp() - : BApplication(APP_SIG) + : BApplication("application/x-vnd.Haiku-Installer") { - BRect frame = BScreen().Frame(); - - // show the EULA - BAlert *alert = new BAlert("", EULA_TEXT, " Disagree ", " Agree ", NULL, - B_WIDTH_FROM_WIDEST, B_EMPTY_ALERT); - BTextView *alertView = alert->TextView(); - alertView->SetViewColor(255, 255, 255); - BView *parent = alertView->Parent(); - alertView->RemoveSelf(); - alertView->MoveBy(3, 7); - alertView->ResizeTo(500, 288); - alertView->SetText(EULA_TEXT); - alertView->SetTextRect(alertView->Bounds().InsetBySelf(2, 2)); - alert->ResizeTo(525, 350); - BBox *box = new BBox(alertView->Frame().InsetBySelf(-2,-2)); - alertView->MoveTo(2, 2); - box->AddChild(alertView); - parent->AddChild(box); - BRect alertFrame = alert->Frame(); - alertFrame.OffsetTo((frame.Width() - alertFrame.Width()) / 2, - (frame.Height() - alertFrame.Height()) / 2); - alert->MoveTo(alertFrame.LeftTop()); - if (alert->Go() != 1) { - PostMessage(B_QUIT_REQUESTED); - return; - } - - BRect windowFrame(0, 0, INSTALLER_RIGHT, 160); - windowFrame.OffsetBy((frame.Width() - windowFrame.Width()) / 2, - frame.Height() / 2 - windowFrame.Height() / 4 - 113); - fWindow = new InstallerWindow(windowFrame); } + +void +InstallerApp::MessageReceived(BMessage* message) +{ + switch (message->what) { + case kMsgAgree: + fEULAWindow->Lock(); + fEULAWindow->Quit(); + new InstallerWindow(); + break; + + default: + BApplication::MessageReceived(message); + } +} + + void InstallerApp::AboutRequested() { @@ -78,13 +88,57 @@ InstallerApp::AboutRequested() view->SetFontAndColor(0, 14, &font); alert->Go(); - } void InstallerApp::ReadyToRun() { +#if 1 + // Show the EULA first. + BTextView* textView = new BTextView("eula", be_plain_font, NULL, + B_WILL_DRAW); + textView->SetInsets(10, 10, 10, 10); + textView->MakeEditable(false); + textView->MakeSelectable(false); + textView->SetText(kEULAText); + BScrollView* scrollView = new BScrollView("eulaScroll", + textView, B_WILL_DRAW, false, true); + + BButton* disagreeButton = new BButton("Disagree", + new BMessage(B_QUIT_REQUESTED)); + disagreeButton->SetTarget(this); + + BButton* agreeButton = new BButton("Agree", + new BMessage(kMsgAgree)); + agreeButton->SetTarget(this); + agreeButton->MakeDefault(true); + + BRect eulaFrame = BRect(0, 0, 600, 450); + fEULAWindow = new BWindow(eulaFrame, "EULA", + B_MODAL_WINDOW, B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE + | B_AUTO_UPDATE_SIZE_LIMITS); + + fEULAWindow->SetLayout(new BGroupLayout(B_HORIZONTAL)); + fEULAWindow->AddChild(BGroupLayoutBuilder(B_VERTICAL, 10) + .Add(scrollView) + .Add(BGroupLayoutBuilder(B_HORIZONTAL, 10) + .AddGlue() + .Add(disagreeButton) + .Add(agreeButton) + ) + .SetInsets(10, 10, 10, 10) + ); + + BRect frame = BScreen().Frame(); + fEULAWindow->MoveTo(frame.left + (frame.Width() - eulaFrame.Width()) / 2, + frame.top + (frame.Height() - eulaFrame.Height()) / 2); + + fEULAWindow->Show(); +#else + // Show the installer window without EULA. + new InstallerWindow(); +#endif } diff --git a/src/apps/installer/InstallerApp.h b/src/apps/installer/InstallerApp.h index 9183bbc5b2..f972dffb30 100644 --- a/src/apps/installer/InstallerApp.h +++ b/src/apps/installer/InstallerApp.h @@ -2,23 +2,23 @@ * Copyright 2005, Jérôme DUVAL. All rights reserved. * Distributed under the terms of the MIT License. */ - -#ifndef _InstallerApp_h -#define _InstallerApp_h +#ifndef INSTALLER_APP_H +#define INSTALLER_APP_H #include #include "InstallerWindow.h" + class InstallerApp : public BApplication { - public: - InstallerApp(); +public: + InstallerApp(); - public: - virtual void AboutRequested(); - virtual void ReadyToRun(); + virtual void MessageReceived(BMessage* message); + virtual void AboutRequested(); + virtual void ReadyToRun(); - private: - InstallerWindow *fWindow; +private: + BWindow* fEULAWindow; }; -#endif /* _InstallerApp_h */ +#endif // INSTALLER_APP_H diff --git a/src/apps/installer/InstallerWindow.cpp b/src/apps/installer/InstallerWindow.cpp index fae7c46367..0d4fa0bde8 100644 --- a/src/apps/installer/InstallerWindow.cpp +++ b/src/apps/installer/InstallerWindow.cpp @@ -1,6 +1,7 @@ /* - * Copyright 2005-2008, Jérôme DUVAL. All rights reserved. - * Distributed under the terms of the MIT License. + * Copyright 2009, Stephan Aßmus + * Copyright 2005-2008, Jérôme DUVAL. + * All rights reserved. Distributed under the terms of the MIT License. */ #include "InstallerWindow.h" @@ -14,13 +15,21 @@ #include #include #include +#include +#include +#include +#include #include #include #include +#include +#include #include #include #include +#include "tracker_private.h" + #include "DialogPane.h" #include "PartitionMenuItem.h" @@ -52,7 +61,8 @@ private: LogoView::LogoView(const BRect& frame) : - BView(frame, "logoview", B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW) + BView(frame, "logoview", B_FOLLOW_LEFT | B_FOLLOW_TOP, + B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE) { _Init(); } @@ -60,7 +70,7 @@ LogoView::LogoView(const BRect& frame) LogoView::LogoView() : - BView("logoview", B_WILL_DRAW) + BView("logoview", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE) { _Init(); } @@ -113,119 +123,220 @@ LogoView::_Init() // #pragma mark - -InstallerWindow::InstallerWindow(BRect frame_rect) - : BWindow(frame_rect, "Installer", B_TITLED_WINDOW, - B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_NOT_RESIZABLE), +class SeparatorView : public BView { +public: + SeparatorView(enum orientation orientation); + virtual ~SeparatorView(); + + virtual BSize MinSize(); + virtual BSize PreferredSize(); + virtual BSize MaxSize(); +private: + enum orientation fOrientation; +}; + + +SeparatorView::SeparatorView(enum orientation orientation) + : + BView("separator", 0), + fOrientation(orientation) +{ + SetViewColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), + B_DARKEN_2_TINT)); +} + + +SeparatorView::~SeparatorView() +{ +} + + +BSize +SeparatorView::MinSize() +{ + return BLayoutUtils::ComposeSize(ExplicitMinSize(), BSize(0, 0)); +} + + +BSize +SeparatorView::MaxSize() +{ + BSize size(0, 0); + if (fOrientation == B_VERTICAL) + size.height = B_SIZE_UNLIMITED; + else + size.width = B_SIZE_UNLIMITED; + + return BLayoutUtils::ComposeSize(ExplicitMaxSize(), size); +} + + +BSize +SeparatorView::PreferredSize() +{ + BSize size(0, 0); + if (fOrientation == B_VERTICAL) + size.height = 10; + else + size.width = 10; + + return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), size); +} + + +// #pragma mark - + + +InstallerWindow::InstallerWindow() + : BWindow(BRect(-2000, -2000, -1800, -1800), "Installer", B_TITLED_WINDOW, + B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS), + fNeedsToCenterOnScreen(true), + fDriveSetupLaunched(false), fInstallStatus(kReadyForInstall), + + fPackagesLayoutItem(NULL), + fSizeViewLayoutItem(NULL), + fLastSrcItem(NULL), fLastTargetItem(NULL) { fCopyEngine = new CopyEngine(this); - BRect bounds = Bounds(); - fBackBox = new BBox(bounds, NULL, B_FOLLOW_ALL, - B_WILL_DRAW | B_FRAME_EVENTS, B_NO_BORDER); - AddChild(fBackBox); + LogoView* logoView = new LogoView(); - BRect logoRect = fBackBox->Bounds(); - logoRect.left += 12; - logoRect.top += 12; - LogoView *logoView = new LogoView(logoRect); - logoView->ResizeToPreferred(); - fBackBox->AddChild(logoView); - - BRect statusRect(logoView->Frame().right + 14, logoRect.top + 2, - bounds.right - 14, logoView->Frame().bottom - 2); - BRect textRect(statusRect); - textRect.OffsetTo(B_ORIGIN); - textRect.InsetBy(2, 2); - fStatusView = new BTextView(statusRect, "statusView", textRect, - be_plain_font, NULL, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW); + fStatusView = new BTextView("statusView", be_plain_font, NULL, B_WILL_DRAW); + fStatusView->SetInsets(10, 10, 10, 10); fStatusView->MakeEditable(false); fStatusView->MakeSelectable(false); - BScrollView *scroll = new BScrollView("statusScroll", fStatusView, - B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS); - fBackBox->AddChild(scroll); + BSize logoSize = logoView->MinSize(); + fStatusView->SetExplicitMinSize(BSize(logoSize.width * 0.66, B_SIZE_UNSET)); - fBeginButton = new BButton(BRect(bounds.right - 90, bounds.bottom - 35, - bounds.right - 11, bounds.bottom - 11), - "begin_button", "Begin", new BMessage(BEGIN_MESSAGE), - B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + fBeginButton = new BButton("begin_button", "Begin", + new BMessage(BEGIN_MESSAGE)); fBeginButton->MakeDefault(true); fBeginButton->SetEnabled(false); - fBackBox->AddChild(fBeginButton); - fSetupButton = new BButton(BRect(bounds.left + 11, bounds.bottom - 35, - bounds.left + be_plain_font->StringWidth("Setup partitions") + 36, - bounds.bottom - 22), "setup_button", "Setup partitions" B_UTF8_ELLIPSIS, - new BMessage(SETUP_MESSAGE), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM); - fBackBox->AddChild(fSetupButton); - fSetupButton->Hide(); + fSetupButton = new BButton("setup_button", + "Setup partitions" B_UTF8_ELLIPSIS, new BMessage(SETUP_MESSAGE)); - fPackagesView = new PackagesView(BRect(bounds.left + 12, bounds.top + 4, - bounds.right - 15 - B_V_SCROLL_BAR_WIDTH, bounds.bottom - 61), - "packages_view"); - fPackagesScrollView = new BScrollView("packagesScroll", fPackagesView, - B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, B_WILL_DRAW, false, true); - fBackBox->AddChild(fPackagesScrollView); - fPackagesScrollView->Hide(); + fPackagesView = new PackagesView("packages_view"); + BScrollView* packagesScrollView = new BScrollView("packagesScroll", + fPackagesView, B_WILL_DRAW, false, true); - fDrawButton = new PaneSwitch(BRect(bounds.left + 12, bounds.bottom - 33, - bounds.left + 120, bounds.bottom - 20), "options_button"); - - fDrawButton->SetLabels("Fewer options", "More options"); + fDrawButton = new PaneSwitch("options_button"); + fDrawButton->SetLabels("Hide Optional Packages", "Show Optional Packages"); fDrawButton->SetMessage(new BMessage(SHOW_BOTTOM_MESSAGE)); - - fBackBox->AddChild(fDrawButton); + fDrawButton->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); + fDrawButton->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP)); fDestMenu = new BPopUpMenu("scanning" B_UTF8_ELLIPSIS, true, false); fSrcMenu = new BPopUpMenu("scanning" B_UTF8_ELLIPSIS, true, false); - BRect fieldRect(bounds.left + 13, bounds.top + 70, bounds.right - 13, - bounds.top + 90); - fSrcMenuField = new BMenuField(fieldRect, "srcMenuField", - "Install from: ", fSrcMenu); - fSrcMenuField->SetDivider(bounds.right - 300); + fSrcMenuField = new BMenuField("srcMenuField", "Install from: ", fSrcMenu, + NULL); fSrcMenuField->SetAlignment(B_ALIGN_RIGHT); - fBackBox->AddChild(fSrcMenuField); - fieldRect.OffsetBy(0, 23); - fDestMenuField = new BMenuField(fieldRect, "destMenuField", - "Onto: ", fDestMenu); - fDestMenuField->SetDivider(bounds.right - 300); + fDestMenuField = new BMenuField("destMenuField", "Onto: ", fDestMenu, + NULL); fDestMenuField->SetAlignment(B_ALIGN_RIGHT); - fBackBox->AddChild(fDestMenuField); - BRect sizeRect = fBackBox->Bounds(); - sizeRect.top = 105; - sizeRect.bottom = sizeRect.top + 15; - sizeRect.right -= 12; - const char* requiredDiskSpaceString = "Disk space required: 0.0 KB"; - sizeRect.left = sizeRect.right - be_plain_font->StringWidth( - requiredDiskSpaceString) - 40; - fSizeView = new BStringView(sizeRect, "size_view", - requiredDiskSpaceString, B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + const char* requiredDiskSpaceString + = "Additional disk space required: 0.0 KB"; + fSizeView = new BStringView("size_view", requiredDiskSpaceString); fSizeView->SetAlignment(B_ALIGN_RIGHT); - fBackBox->AddChild(fSizeView); - fSizeView->Hide(); + fSizeView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); + fSizeView->SetExplicitAlignment( + BAlignment(B_ALIGN_RIGHT, B_ALIGN_MIDDLE)); + + SetLayout(new BGroupLayout(B_HORIZONTAL)); + AddChild(BGroupLayoutBuilder(B_VERTICAL) + .Add(BGroupLayoutBuilder(B_HORIZONTAL) + .Add(logoView) + .Add(fStatusView) + ) + .Add(new SeparatorView(B_HORIZONTAL)) + .Add(BGroupLayoutBuilder(B_VERTICAL, 10) + .Add(BGridLayoutBuilder(0, 10) + .Add(fSrcMenuField->CreateLabelLayoutItem(), 0, 0) + .Add(fSrcMenuField->CreateMenuBarLayoutItem(), 1, 0) + .Add(fDestMenuField->CreateLabelLayoutItem(), 0, 1) + .Add(fDestMenuField->CreateMenuBarLayoutItem(), 1, 1) + + .Add(BSpaceLayoutItem::CreateVerticalStrut(5), 0, 2, 2) + + .Add(fDrawButton, 0, 3, 2) + .Add(packagesScrollView, 0, 4, 2) + .Add(fSizeView, 0, 5, 2) + ) + + .AddStrut(5) + + .Add(BGroupLayoutBuilder(B_HORIZONTAL) + .Add(fSetupButton) + .AddGlue() + .Add(fBeginButton) + ) + .SetInsets(10, 10, 10, 10) + ) + ); + + // Make the optional packages invisible on start + BLayout* layout = packagesScrollView->Parent()->GetLayout(); + int32 index = layout->IndexOfView(packagesScrollView); + fPackagesLayoutItem = layout->ItemAt(index); + + layout = fSizeView->Parent()->GetLayout(); + index = layout->IndexOfView(fSizeView); + fSizeViewLayoutItem = layout->ItemAt(index); + + fPackagesLayoutItem->SetVisible(false); + fSizeViewLayoutItem->SetVisible(false); // finish creating window + if (!be_roster->IsRunning(kDeskbarSignature)) + SetFlags(Flags() | B_NOT_MINIMIZABLE); + Show(); fDriveSetupLaunched = be_roster->IsRunning(DRIVESETUP_SIG); + + if (Lock()) { + fSetupButton->SetEnabled(!fDriveSetupLaunched); + Unlock(); + } + be_roster->StartWatching(this); PostMessage(START_SCAN); } + InstallerWindow::~InstallerWindow() { be_roster->StopWatching(this); } +void +InstallerWindow::FrameResized(float width, float height) +{ + BWindow::FrameResized(width, height); + + if (fNeedsToCenterOnScreen) { + // We have created ourselves off-screen, since the size adoption + // because of the layout management may happen after Show(). We + // assume that the first frame event is because of this adoption and + // move ourselves to the screen center... + fNeedsToCenterOnScreen = false; + BRect frame = BScreen(this).Frame(); + MoveTo(frame.left + (frame.Width() - Frame().Width()) / 2, + frame.top + (frame.Height() - Frame().Height()) / 2); + } +} + + void InstallerWindow::MessageReceived(BMessage *msg) { @@ -290,7 +401,7 @@ InstallerWindow::MessageReceived(BMessage *msg) char buffer[15]; fPackagesView->GetTotalSizeAsString(buffer); char string[255]; - sprintf(string, "Disk space required: %s", buffer); + sprintf(string, "Additional disk space required: %s", buffer); fSizeView->SetText(string); break; } @@ -335,6 +446,7 @@ InstallerWindow::MessageReceived(BMessage *msg) } } + bool InstallerWindow::QuitRequested() { @@ -353,22 +465,9 @@ InstallerWindow::QuitRequested() void InstallerWindow::ShowBottom() { - if (fDrawButton->Value()) { - ResizeTo(INSTALLER_RIGHT, 306); - if (fSetupButton->IsHidden()) - fSetupButton->Show(); - if (fPackagesScrollView->IsHidden()) - fPackagesScrollView->Show(); - if (fSizeView->IsHidden()) - fSizeView->Show(); - } else { - if (!fSetupButton->IsHidden()) - fSetupButton->Hide(); - if (!fPackagesScrollView->IsHidden()) - fPackagesScrollView->Hide(); - if (!fSizeView->IsHidden()) - fSizeView->Hide(); - ResizeTo(INSTALLER_RIGHT, 160); + if (fPackagesLayoutItem && fSizeViewLayoutItem) { + fPackagesLayoutItem->SetVisible(fDrawButton->Value()); + fSizeViewLayoutItem->SetVisible(fDrawButton->Value()); } } @@ -438,9 +537,8 @@ InstallerWindow::AdjustMenus() } else { if (fSrcMenu->CountItems() == 0) label = ""; - else { + else label = ((PartitionMenuItem *)fSrcMenu->ItemAt(0))->MenuLabel(); - } } fSrcMenuField->TruncateString(&label, B_TRUNCATE_END, 260); fSrcMenuField->MenuItem()->SetLabel(label.String()); @@ -451,9 +549,8 @@ InstallerWindow::AdjustMenus() } else { if (fDestMenu->CountItems() == 0) label = ""; - else { - label = ((PartitionMenuItem *)fDestMenu->ItemAt(0))->MenuLabel(); - } + else + label = "Please Choose Target"; } fDestMenuField->TruncateString(&label, B_TRUNCATE_END, 260); fDestMenuField->MenuItem()->SetLabel(label.String()); diff --git a/src/apps/installer/InstallerWindow.h b/src/apps/installer/InstallerWindow.h index 3ab3c77a19..322936bcc2 100644 --- a/src/apps/installer/InstallerWindow.h +++ b/src/apps/installer/InstallerWindow.h @@ -2,8 +2,8 @@ * Copyright 2005, Jérôme DUVAL. All rights reserved. * Distributed under the terms of the MIT License. */ -#ifndef _InstallerWindow_h -#define _InstallerWindow_h +#ifndef INSTALLER_WINDOW_H +#define INSTALLER_WINDOW_H #include #include @@ -17,12 +17,12 @@ #include "CopyEngine.h" #include "PackageViews.h" -#define INSTALLER_RIGHT 402 - namespace BPrivate { class PaneSwitch; }; +class BLayoutItem; + enum InstallStatus { kReadyForInstall, kInstalling, @@ -37,40 +37,52 @@ const char PACKAGES_DIRECTORY[] = "_packages_"; const char VAR_DIRECTORY[] = "var"; class InstallerWindow : public BWindow { - public: - InstallerWindow(BRect frameRect); - virtual ~InstallerWindow(); +public: + InstallerWindow(); + virtual ~InstallerWindow(); - virtual void MessageReceived(BMessage *msg); - virtual bool QuitRequested(); - BMenu *GetSourceMenu() { return fSrcMenu; }; - BMenu *GetTargetMenu() { return fDestMenu; }; - private: - void DisableInterface(bool disable); - void LaunchDriveSetup(); - void PublishPackages(); - void ShowBottom(); - void StartScan(); - void AdjustMenus(); - void SetStatusMessage(const char *text); - static int ComparePackages(const void *firstArg, const void *secondArg); - BBox *fBackBox; - BButton *fBeginButton, *fSetupButton; - PaneSwitch *fDrawButton; - bool fDriveSetupLaunched; - InstallStatus fInstallStatus; - BTextView *fStatusView; - BMenu* fSrcMenu, *fDestMenu; - BMenuField* fSrcMenuField, *fDestMenuField; - PackagesView *fPackagesView; - BScrollView *fPackagesScrollView; - BStringView *fSizeView; + virtual void FrameResized(float width, float height); + virtual void MessageReceived(BMessage* message); + virtual bool QuitRequested(); - BBitmap *fLogo; - BPoint fDrawPoint; - CopyEngine *fCopyEngine; - BString fLastStatus; - BMenuItem *fLastSrcItem, *fLastTargetItem; + BMenu* GetSourceMenu() { return fSrcMenu; }; + BMenu* GetTargetMenu() { return fDestMenu; }; +private: + void DisableInterface(bool disable); + void LaunchDriveSetup(); + void PublishPackages(); + void ShowBottom(); + void StartScan(); + void AdjustMenus(); + void SetStatusMessage(const char* text); + static int ComparePackages(const void* firstArg, + const void* secondArg); + + BButton* fBeginButton; + BButton* fSetupButton; + PaneSwitch* fDrawButton; + + bool fNeedsToCenterOnScreen; + + bool fDriveSetupLaunched; + InstallStatus fInstallStatus; + + BTextView* fStatusView; + BMenu* fSrcMenu; + BMenu* fDestMenu; + BMenuField* fSrcMenuField; + BMenuField* fDestMenuField; + PackagesView* fPackagesView; + BStringView* fSizeView; + + BLayoutItem* fPackagesLayoutItem; + BLayoutItem* fSizeViewLayoutItem; + + CopyEngine* fCopyEngine; + BString fLastStatus; + + BMenuItem* fLastSrcItem; + BMenuItem* fLastTargetItem; }; -#endif /* _InstallerWindow_h */ +#endif // INSTALLER_WINDOW_H diff --git a/src/apps/installer/Jamfile b/src/apps/installer/Jamfile index a10e64686d..3d9f2c1125 100644 --- a/src/apps/installer/Jamfile +++ b/src/apps/installer/Jamfile @@ -1,8 +1,6 @@ SubDir HAIKU_TOP src apps installer ; -UsePrivateHeaders shared ; -UsePrivateHeaders storage ; -UsePrivateHeaders tracker ; +UsePrivateHeaders shared storage tracker ; SubDirHdrs [ FDirName $(HAIKU_TOP) src kits tracker ] ; Application Installer : diff --git a/src/apps/installer/PackageViews.cpp b/src/apps/installer/PackageViews.cpp index fcac3b0f8c..12762e70c8 100644 --- a/src/apps/installer/PackageViews.cpp +++ b/src/apps/installer/PackageViews.cpp @@ -1,23 +1,31 @@ /* - * Copyright 2005, Jérôme DUVAL. All rights reserved. - * Distributed under the terms of the MIT License. + * Copyright 2009, Stephan Aßmus + * Copyright 2005, Jérôme DUVAL. + * All rights reserved. Distributed under the terms of the MIT License. */ -#include +#include "PackageViews.h" + +#include + +#include #include #include +#include +#include #include #include #include -#include #include -#include "PackageViews.h" + #include "InstallerWindow.h" + #define ICON_ATTRIBUTE "INSTALLER PACKAGE: ICON" void SizeAsString(off_t size, char *string); + void SizeAsString(off_t size, char *string) { @@ -261,20 +269,6 @@ PackagesView::AddPackages(BList &packages, BMessage *msg) rect.OffsetBy(0, 20); } ResizeTo(bounds.Width(), rect.top); - - BScrollBar *vertScroller = ScrollBar(B_VERTICAL); - - if (vertScroller->Bounds().Height() > rect.top) { - vertScroller->SetRange(0.0f, 0.0f); - vertScroller->SetValue(0.0f); - } else { - vertScroller->SetRange(0.0f, rect.top - - vertScroller->Bounds().Height()); - vertScroller->SetProportion(vertScroller->Bounds().Height() / rect.top); - } - - vertScroller->SetSteps(15, vertScroller->Bounds().Height()); - Invalidate(); } @@ -308,15 +302,62 @@ PackagesView::GetPackagesToInstall(BList *list, int32 *size) } +void +PackagesView::FrameResized(float width, float height) +{ + BScrollBar* scrollBar = ScrollBar(B_VERTICAL); + if (scrollBar == NULL) + return; + + float virtualHeight = 0.0; + + int32 count = CountChildren(); + if (count > 0) { + BView* child = ChildAt(count - 1); + virtualHeight = child->Frame().bottom; + } + + if (height > virtualHeight) { + scrollBar->SetRange(0.0f, 0.0f); + scrollBar->SetValue(0.0f); + } else { + scrollBar->SetRange(0.0f, virtualHeight - height); + scrollBar->SetProportion(height / virtualHeight); + } + + scrollBar->SetSteps(15, height); +} + + +void +PackagesView::Draw(BRect updateRect) +{ + if (CountChildren() > 0) + return; + + be_control_look->DrawLabel(this, "No optional packages available.", + Bounds(), updateRect, ViewColor(), BControlLook::B_DISABLED, + BAlignment(B_ALIGN_CENTER, B_ALIGN_MIDDLE)); +} + + void PackagesView::GetPreferredSize(float* _width, float* _height) { // TODO: Something more nice as default? I need to see how this looks // when there are actually any packages... if (_width != NULL) - *_width = 200.0; + *_width = 400.0; if (_height != NULL) - *_height = 150.0; + *_height = 80.0; +} + + +BSize +PackagesView::MaxSize() +{ + return BLayoutUtils::ComposeSize(ExplicitMaxSize(), + BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); } diff --git a/src/apps/installer/PackageViews.h b/src/apps/installer/PackageViews.h index 356cc9e054..8cc5cfdfa0 100644 --- a/src/apps/installer/PackageViews.h +++ b/src/apps/installer/PackageViews.h @@ -113,7 +113,10 @@ public: void GetTotalSizeAsString(char* string); void GetPackagesToInstall(BList* list, int32* size); + virtual void FrameResized(float width, float height); + virtual void Draw(BRect updateRect); virtual void GetPreferredSize(float* _width, float* _height); + virtual BSize MaxSize(); private: BList fViews; diff --git a/src/apps/installer/haikulogo.png b/src/apps/installer/haikulogo.png index baff8282572dd80be615e1589359853b3d51d61e..b59fa2d7c5a39726ab2acc19db1cff2ce235d256 100644 GIT binary patch literal 18441 zcmXt=Wl)>l7KO1=9Euc&Qrs!-?ry=|-Q6ix+@ZL;ySuv+++B(U*PHLhoylbKBQtq( zvd`ITul2kMSCp4PM!-XWfPg@jk`z^jfPmxyzqWvb1wY5ssnb9}{D6=W6;k!cyv*|a zO8{v56aXxp-`!ovFsEJc7{=4X>6rW){eZ^o4EVhRz|<7IQ$o`b6zs%atc6qmeIjOh z|GO7}8He^zOGy@JLzZZgu*#xc)AaVisk^kqw#2u|$Cn6sM??cHqOwa!J3 z8*0cTguyB_pj=iGK_*2$W&hhL(OiLrNhn9w32H<`;qB%+h8P}ob&Xa#+jzBmKkzH? zc0{Y5*3>bCU5~`{>NLi&AeQ;FfNv5Z>kXsv*s^lu=}A<~_)`*^lRORNZ?w4Ar}W_GSD zUbGtx^@=Y6tT%~j1PXQWloOu{k^*Vfh(z7?2>uMQ1R5)nvFJUGYeo{%1;SMEB1W?! zP0>iHh99D3gHd}KTK8~1%5x#{R5!6bggVusRff-bbIE$k?5)h$)t|oV#h|W5GO77e zXt7_Xpk2#KLd=5G&5u&(DVXH!TSEIHsLo%|9kFKy#K@->t<5-7&3G{*%1e2(F5c-6 zCK>+omaKY%)t*r>7sFcItBI=REsE6-Q~>W7m+K^9UA(LJ4@U<$-%JZSh#HI9^~CwH z?85i}y*fb-y!eNqjaN>HO^;pM%8U7Za`8sh{{BA%L+2J9Z2Pe2)uc8| zb5FF}-5M279obMdW9!|Hk}1zNgj^@s^M!VlSZYnX0a@v5>JiBsKGKVKA786T(cnx7?B4DC{Wz(o zFWW|lyeDa9s;1TTJjv%Q8p-ZuDH6ZLo+~G6rgUY2sQu~4c7FF(qnQn_g)6~Dr+n-9 z>xJx2pD~UVJJR<4uny^QUe)69e3;r$ZbnKiubZ3tBe);Cux9<)QYe=FzIHfS^PlG=v zoo%xyRd2irs3)VTsVOy1dz7Y36q2Gp*%d$kXGw!H+Ena8HSAzQy}A?O3%Pf8da>gS z-=oQf|3%%1$K$5E?gTNzl@4(7{8^G~Xahe+d@X0__l4x}B5h4)zvBpDYExz;WB1?l z>W&x#CJmSMC@hcI?^xV=PSM9cWrYUn<&Xk;+>V9!)Gqm^JnlzzUiVf+KG%IDo*Vw3 z?_3kaDA%{URkN?&`P-4ceOQU9pbu^PuA$WKyQ0cxU6(nrw+nLtQcMKoF;abgryFJ+ zq5`SsWs;n`f#R9< zLwC;Aoe_CH5Q|Jm{7*a3(|nIQ%{Hrh>HnTk z+NKz=qsb#O4zbp$jfW}-cj`A=N<6`f?{wt81W=#b+TuUZG{;>Xr!U-k?uHp|-)^{3 z8f6)1%6k8t%HRMc*Z71yZu@Vu^&m2|2IPFc9S0BW{`MRT1IGSLR@RzIy@lfs zQ@K6#FGSyW2r$WRX=-wuVgn*+PdCi)XSip#J&lVMCAmqw=rngCRH=6>XJ%<>X+6b$ zKA}!<9Te919MW#MEXb*h~4w_ zB{@0yOR_Fqv^%_)0`y&JSskg+<(v)L0M%v!RZHWueB*8*_iTz*|MOm76#y_j zEYTQ$@ae`M`JNwc!gISzxy|f!s3J{=qmq#&6;diS(4~t=&yi!V9HlBYAwe^mT;r^W z7upA!5y)AhI1rymp%(!FfNz<{cAx7tsrB!mJfBx8{aJ?K+q9j{%}t+Up6y-mmUEig zuWXp!OVPF)gJ@TlTT_mj(z!gZv~O;nb=~Ba)(o5TaZ_C${?1b7bVx6ytY=@f8)GEU z&7zfH#(-9@FGGgD0p3{Eo|#VL)YU*@|F;_?9_8wm7Yo@z^BcA?l~GuLj=U z-fg$zw4Qf!61oeSj>EVcKA%E{S4O0() zOu$_b+Jqu4YnOM@=ayauc%LAJ7{Y(m`FU1RQ*Shc0Bi*6I3uU(d6k`aeI@e9E%d>X z8IlftNX=rY5nf}$p2Zf1hKAO0o?_G7C+N8jVZ5%;e~(B{Pyd$8^8J9KZ1pqMTd#lp z9xb%GP1=R@o6!SiG|kFoI4mv-5(sk2ggLytytG`JIjs>zZef;{-q;{2cxJa6H#D%k ze8c;ytJ>4&c|zZ8w?8D)^C+$Q@v3z{ChEt&O;1s-j{R}n2b?>*o_N0mE8b!IdG*8^ zc1gAuP0!mQqXgE;u(C1?qXk}R5ZAGC-CMNUnhvX(wechCZH7I$+yb4p8heE3Pb3r+ zW=>8?GIWyfk(yzIaL!WxZBL_*-DFagdR^&ZL|&t8m!8L2VRRE0;1f2}=XR{x61>&J zJ1L$eA!-$+Tv@4sPZMDZEu`NgZ$LSpnLJmW3-@g*@?0TBGO5by>ZyRp+Q&YR^{y4< z-o{>+SvJWB6iDu4&oWOOdKwSVv{9PV+Jtz6)3kgYae8sQBpLHO$27oV3n-!4^gC~$ zy8F9{rcgXD3|zRg7y*9{YV3$HAw)eLHeY~qQ;;E!CScAuhAR{rl^1P*Nf9&Tzl~3s znO=o4}qCY`7??y#y~vyaG^jVN|MV`mOp3a<+FAG#rWgx8QcuMip=waCRs9_r@2Ht>SRcUP_~rQ zX~en3>zmB$o+%Qg?0Vka?AlK$fUhIO{=71&3`Kc)hKm$_40u&srtq+RU5c$K@###=K@=hxYVN~<%|o;8c**(_Dmb!qI)qCbUL@yOA`XR%LBMLsjYMZm@rNCp`jN`g(%iPLJ>jM41$(`cfBg542>qOC^L>H5nG=J8Pj{S9n9#IXlk9|O`d{i~zsG!^ zT;7!NXo|IB5X`eep;21eJ9O8Ztksu`47WcXT6BS$eh&>fu5vwAOEh|Z&!#ba4;sMN z)vaMWAjr25Ih9?VC`4MkZJge012?qK_i=M1SzYhc%YQ6^e8cbcQZ}8H`W$3TvWbN+ z%|@UJC7SzflS%}4BTDVLEQceMr4c8;dW^x;Y1I#-OCGwo zg~51LKG~0JR$-?vdNtTJz{rvPIs%NLm6m#Bv;nlh3UIx;PVKK**GzHE)!TmgI7n2u zeOR~0o;2@HVsuDJ52Y=bEeed~f1%ob8s^ZsB6b}7wgEnXSlQSP0dC!ow}-Z^)uya`e~>%F#oAshYCINzyh7yGHjk5hs6mS&1ZCUdxwsc4pSsGr#%u z9A*(BpOORTYZDdtxz2MF$ihPqv7MGR&D*>juX;ZHP`FQW6TD49fT@vmgsO$@&ky%$ zflnWxcNnoBr~9TWwo0)qE_=?+ze|Q-$|>~_ycJaaM{BZ)VzUkB@|yjwt%CgFm_`0$ zvse|tlCq}v3yz?9EvS2FDnB8Vw?mNI7oZ4UmN_20)AoKKd|>m_3$SPU zVzq((weX#39bUAyF5}D-sOw(mxIawNc{re6-QG4Q3Hu^B;U<%)pj9%mR%p3U>)vl z1MhbJb?YExlu&dfpg1w%D7dj0-?D7#j_@xET!9adh4AkQacTjW1hQ#l{owI(>GFz- zvdT&_0u~5!vH}1{LMAhQRXM-0 zX{1vb-g$M~;_;`H?Njg5^=wrh=@^XqI0Hx!#I zV{*u@=lX1{U)X9n`kKv8a{OYFn^&$2`NTW}vlf297kzrQXBpLL4C9LeU7L~ZcJBK| zEar$60yBcEOCaSr0%stQW|1>WmVT6sEWvQxppGU4lJ!MhmM9Tt%ZiDG6!oVI4cVdV zk|cz#v&k(yZC?4Azxx}I`WWkTmgAZMLKO8r)4jc?IwArGx&`yA!wp{9%lSQ`_1|9| zH)cQZJ|7Lu)~u`BLjP-EtnBQ?XZ)RKN+$-JDnZ_?6J00ykse^3lg45mbN()D8)V!S zY*%P1MoFk(F%a$HjY^^Pi*jGD+wGhW*=yi;mTp#KP`0iDBZcY@?V*8a=5;swe2Mjt zO7Fj9Q)bRaSTn;l{Y-)jrbtg1;;)PY8`F$M(MD?62QZb)@PjY`+D;)qEg^iRT>GlnfN> zc{pMCxO;NH3w%B+OmiI*m}oZt&L3%jVJ0dqDhj#s|9qv>Zk}{~Kle!8GcYkIfVGlZ zBvA02uveV;j$Xt2M|4RTiCi%bLRH$ZOfeyffZiarIzbCcWPn*RJ&eonVkdP1#pI~P zV(w?N-6leBX93iOuhE~EHb0sY4<#SwbcSD~o+zM1iQA-GmOXLWbn3BFVW)+A))lU$ z6&>`f)#;SA^ma3%!*>u@>nDg+&MrSMFYxTlYJ6hi=Joyi3YLhSt>H(08Sl-$OsU;F z#*9s%_Ev!J`A#flAHVB#6v5~Eu-wc?Pe1-;-doVQG8P8VU2MmHD~Omb%=ck63@pha z95`*bG&3Ri(apu0pBMpv20u;2!RnvImbn^IB*2vgR@=c2*#9Ol9sl=x7%0f|^z}#q zAltDge^Tr*TfF4K#)q$g!H@IEwX&|&5PWN74`$)}wX2}Q0J?$+l0AR~dKn+m0ES=! z+1XiU5L<&!hYF*52dC%cvKzTBgPGa`x!)MUJ!}8im>Nj}nPxMsIZmjj-4&)TkmdW_ z)n^FWYYtJdV;<^QLGC$vI_yobqEg3K9*wdO;viF=p{}GmibC!T1Z!yC3Gw5*W<1L{ z8IB})m(VXR;eN?Od?U&{nw(_9d1!%xxhCkkp&)YZKer$F9vodUZ+)bhggRducAqpI zhKxKsc{Z+THk{Y`f*XNhW=H+f_Z{0Lnh&du=hR<368o>;MRr?PuM@G=8o=6{A1n_EDz}KGlOZzl7>+jgQE=o!PY(#|u9Q+#>Zt_zi zF^_>MFq&UQgxF!>AKsw#Kk<C+2F zl&hwDN#UEOVR(3UxPZ~=TNx(IQmjO~EBJ=<{7pDi7VW{=gHWux*ySe-#)MM#*jmct z5S+RS>j%u_Jc(C}HHdgCO8_Y-O(-OIO(^=jo9Ry%$K_|a#l=NMB_+eM8Z*MkqNtX_ zbWzV^uD6*_Y^OWsqgD}(`D#GS&`+*A&c9OR44r3B`gt~&FufGp1o4qQKfnztiH z_g@YxhQY!lyhIA2NqT<>hc!p$BF-2?5wcW4$1}%A8TMvtjh2lqEza-vz>eY$@F0}N zCoQ_QDa1v!|zn>nY`bXOF0CSs50z`gxM51-Ymd`qurnMg2uxQ+mLd~8WIh2 zjo`~rf@dvlG-i^Ze&4Z5@(!8&9Z5uZ*-QmPAYA-j5HHH}si+>Qw?PK+h)f-jtQ-G5 zJ9bMftQ$%$b(R%UPfNO-rEe0&tKATqC*!P~r;uxbOX!7CS7|-`BJRWl-UVmlZV?GK)c2^@MM16GdCdA6VB zLy?!H7`yJ!U;lN~-1mUK82aC2e6E)%mWWq>lK8W+XW`#PI*4J#DfLGUgR92#P^eW z*>5FLNgh1&v2|~-_WI}}4gJ=YXInNARl?*YLWQ))MPAb>H)i?ERU7=*@mojN`iV08 zEJcqjzCvLyBYB;r;oA!VlsI&{Rjtaa`b#$QBCA|LD)p)*d-ybpN4kh<)B15H3Vbcs z4vRgJdvC8&-L{0@#WFHf&ffbW(-W^XGfFPl3MdN* zbS$BefyXRfmImV}CI9%nReFMVLyIFGJm2__ z4qT@86BcgV*^WP_-;CBE%D)$>@ujG}i?Nc%6vMw}!rNF%O~VL%UD5oJYFXk8YA*Iv zfXpPp&=3emu*b?1{F5s%8cEDA)JQtECeVoL$)Nr>e4*E>IsTo$kSAqY4T>?F0*5US zMY^J!d!`{U^F3Wwx@cQ^KSQ8^+yiluwYZ^fiFzCGvnXE}_SIqjKr(vw^{PkUam$+# zTgM^r{2gor{8?=<2L%zo^{!32(v{+@msX$SGJ;zfE)I@?yEgs;k!SGi6i4FQ`_-?9 z?d|(RyB~qoP@%Sys~(C5=H5v?J>8K54|Y3oUHEP1b8MY;YLma@7MNcKeA3pI%)K`w zl6UIoY7??f9oZ05O;@$@O}qf~S$dC3#bISE=`1?HV&k91Ln~+k0obj`OOl1QuI%?q z341m_%ztNFrcOAB|7a`sP#)(aQB}(tys)Ejn=%OHPsP(mma*@qweAAlcXJC(*Snr@ zX9E;SA6veq`6F$GBHp-tEEDcz?x<0jwMw}h*%QqZqI*PR|9zXzvf(-KR_h{@swco+ zT^3k7@1`8%y2<)Hp2*RLf&4RtRo(q!W!Jh33q1Dw0Ohb)FVju)zg`$lIQ+JwCQsYF z4IkO};3aa=r6h`700P6>&5)fx?ET&qT zLz};Jr!`Eks;Vb$6!Hu(&9Wi8*$wtM;Yz>S8U&bc3cJi;k{qE@P9d9@U|>0a`okE6 z!I;i@m#wu5bb(^=_cYzPGloeIp*nvfug2UF#fJT7GTxs9LDvJQ9sHpC8viU@7Bg_u z3d2frrykqCsRh>(Xv_PmZR_g%92_#Bg^R9iZpz&+D5!Xk5TYRjmJ5r0nNOkDgw(hP zz>mp8F%6nDKqv%cvE?em-k!yUf#fqs$|R=5@HHgpScwOi=oWAai+D%3Vv8(VIuGn# z16qP|+CrC*4>BWz0f44v@$@RXovKd)ldaUCC+kk!A0=r&QuDf{PYS!LzUy%!xuEA? zhOnl}TQ~bE*6hN}q*_#tcVTOi+_;1q3hMLRzF>K@@JDyPqUO(HwvJVbEH4-JO&@r3 z<~nyA4J&sybC2T17;V*9cSL80`i76GgnBH={Mxzo^dmDpfa;9@?LvjQ2e#z)gHZWL z&uUx$lk8w4`!AQX*|Lu`{TSDIhsTYPdMyi5(DbzYo1eftvEOLa>(xk)Og1&g1R?RXrUCzljIh2Y%t?4B!=wUU$fmm z4JZ%wS@#5hv1xgEz%WcV64o?RsHB@)P0Y;k!1+CM?e`S@hG?;44#frqI1#nbfXq$) zlKp>w;*|XhqYzJ>8*IxHrwAzh<1GOT&R&%l_Y?mrV8z11qKfG6 zeSoRa?a2bTx6HNh#gqq@2bIf|iEz@Wio98&G_lw6Acbb`md4d0GQl!4dk=j?Cl)a- z=kMiqADBM=X8JF&fvd_c(z!Ik>7Ua=}ep9 z1l5j@y8Yv|c~cwo3+mbTHLAn8@z{8ADRibxpUa)A)otU7%{+$aGl;8>#>e$|cfG^b zA8axDlC3d0KEV5**HF0~^Tp$=tfcj37(dLX&yJG@(7~Wl+sn3{7SX@=dS(97c5DWb zmCQf@D+ZZ^T2?~2@9Et$LWA-}|L>9}lLH{7`N-fpoQ}ZcWlehxyu{f7j0%g;cWaNEGMXrr0_Gce`OYh~Et+)5Uxq zY*?|SPVW{J%m+e|H$3*Et4+7Tal&LaUxvNUKE5U)caa58%b2~i+k^G??dx-V{_Imf zVw%s2{>##mq8e=9kNJO_IAtqBl*r2$3Z7x<2~>qiFXd~h>RiZPM{V&4ZE?282{97H zxfBl^Ki9VIzG4@g`^mJkypA#`Myn>%<6PW2-kT%dvGR4SQj9l`bgVphV1K?2e%9xG zLN5;kYgaWCMBViL=CztaLQK7#OCKHboIEgDSxuz+OP+4Ly1=uba9*4%Oi*8x0$Mt6 zZ1BbXFQlNram&UlSFY|DjIv9Qac%K2am!r*ZDH4f<5r4=Jo=L6^vYmU8A80-QEgt(=(= zpPrnqd?gu0ilXUVP~dj#;^rlSY(&1pX;Esu-@6x)=fO8%eNF2gg4uND7}#>jNtAe% z$he?!u46SGMnd6#GEl4538$NQVD18Wl82`h?zo$;7b3;Y(n=t+c!;I_Krq63VgCi^?cQ#Vt~%#~$KyKHupjCc|7xBCyu zc6e!@83m=9a>Kn%qitlkTu;(dl<|)^l^RaHjP)k0Ic`D^^GEW|wNc zaMm?zOE93`VsZYu=)(^ZN{?}r*-1iT86FEItnK6FT(iZF(0aMjk^U82$;Z(gTLyFa zVz|5+RvEr3NSY~CFX=}=TD*`X_;X@G(>$@swCYYh+cUUhWO#eNcwZ{FDyl=vY2aXB zRy=uesCN?A*TWXqw|e*zXL23SrGrgM3<9%Bf~o_IOe7tk7L}VRMcmsc_u1T3i2SpN zV)~hwL%wx1n#YdOVqS}5T_F7WzFt;b9C~}}1fC0SJThNIeM9w7H3E#F{`xirZ6==F zcwBq%itr~G-zrHG)|ZjR>DlhwdxhB~5_ zfGx23RG5`(_oG~x45fp#HV;|NE||X0_i0b_Q`}RND=Ru|zBEftM0V@-^%v|{LkBcZ=YM{Gxm{^mw*9=-!a@vjbpA``cTxRw^YZ$vYCL%5T^1;Q zXK<*@&Hr`>G8Aecx#sx(naYs(+-M6vI}d~K?G7;aQ}O6M4zfrh4DDlNjYd40InI^K z$gM`9#zYr92Em8Rro^)%i!8*o*td*3Ka|l;AT2WF=U-a1CTmzz&-&#V0EJo!tt zMk_?(1@W9_AW8i~?B}u&S$mqt`~-n1yOm48zdpZ@)rAS~_1zVg8Ut`rIT{glfnlm% zs0U@{eK+28$87&c^kyY7)>NsFXlF1{A+Nq3T`J*(Hb=hm!HA}yM5*guPxxHEcl#Fb z6OmDD8-%_I`i=UmOeI2DnT@;TE%hlm!z(4N`xtaH{DH!ee-SIXZwAS)T&;s z{8}N^KPXTPp=2J~_;@l^s%}cdCpM$re1*Q)ie@%NNT6OSE01eTklKyjtR)e7bxPcFm*Y#d z#NYnH+u6i5-REoq>9Qh-g1@p_#Qn;qYhKch9pr@T`Tbo z*}s*Gk0v22!;w>6Ym^|jxY6u!^6#;{_HSKRm&CQqGXQ_6tGUQg;<9BdtI+KE{odm% zc-ZI!qc9h>q=Zl>fO{5;O;FRP(R<%hg|zmzL8=5W1?Wc`ty&=aEb)WxY*U-x9sgm2~m zS&6a9^)_MKyXx#yDca9T`%cd3IL$*yiZIKg?RW{)2q$EFKL9MOb6$m_Xm zL}VY4F}L#uRyIreu+wv}x;s7VICJ2@0`qiE;>%9jVdy}uD{Z&EKmL99>nx=l9u)5Y zJUBCO-VMQa8W#8*Yl!@=gbh~EWow}!eL^8`TH|gB_E#Br z$;QuCG~K^JTYrvvYd1SxUr7DH#YJC7TUxs0W=@`WD}Dk-0Im7N_FH2O4l(d=h3PNuTmmE z1>wUpy9)gqd0;dyiI#?j^Z6jr^LC6f>>4ym8td?KT7rQD%OVR6JInLT1Z(}6X9mil zUcWWv-P|^Fm>ViRbXDu%;8v=?Kd3ZO@nqNkVa>WVXd)CL|C9GXIhMTZJa?vs?3 zOHPL;KtY&3+M(+)zHe@xWN_>g5)77<57N>|E-&WFri+57ncE4*WAHSyGbcg(CAjMb zHZ}}T4r3zD_}5)FQK9JXUfUKW&;aqgZt17ZUU}U2=$KsME zgwa=SF(n)voSkF;C+u!Q+S3b`r}4S_QDp?WDfK^u2N$2(*_x1EhuI8FyzFQ&NI^{Y z@set}c!{A=gbU5ua68d>D~AdH5aLrV7|chj@}n>hZVwsNy^Pv2O3|#Web9vpIfyX7!Vgj}DrB!=0E`z4`#0I@PMG zbp%^K{)G}DGm%^PuZ(s3?7&L1QnMkHTqeZ?qBt$~3~`}*N4UIshIH{(ght;xB=8v+ zZ^KQsUtv8Rc(QBjZrwAmxvZgq^f$j z!T4*U-@7#q4q6x;qC;s7rP~k|)$6|rIgZW2cGq(autsS40<}1@pXTG@lH1b!Gc|eF z`;0oFBqzr4qE7O0BT*hR9Bu@>sxI5UROZ>?@yyf*DwMD9{}F5dIq5D%WJm6!nb*TR zKZZN5j96KJuyK%jcKuwIPlg2%vlDDBZ-9gFN{zbyacddxOwGi1I7Jp_ zf4STSi8XEXoGKLYBbIs-#R1yJ3K_+sJ7EZ(r*=p^b{d3>jb2)OxWkHR6!q-&XO9A# z+^-JXzK?DE4Gz1)F4#820I?`&Q7EMGQ~}EoBqIej|2< zCE){8J?4_l(*RVrvFWzLD=<5;KP!TI2#)4)`+;EU%RGkXALqo!iH{!8)s2H#uJcVn z)&7YZ>pX^X*%KoOu_t&JwJo%aQwjj^diSG24<{)vTq-6cJaIm1edx%d?BH8YGPq>K z=com9F^!&GtR!xf2^0$AYi%l}38todD_!^lOgKnkUs}_6#?vF$TI|Rj`o55TJaD9E zWVC_lKhE1x(zK&nNLQ%@gH7%`MY!j-W4Ih|h8t*#pNaVaS|OpyBMshEwe7e zI2XURUtLoZOUUC^>$opYcBWPCanjw(|hljTEv%`Dk~t1`V$Qhl%o}3v8By86tm2Iqy}| zR8vV;aL8Z|W*&50mjJRE?9l>Mx)a#t6`ln>#I9?sMD17n-{~}VtXSR3?xUWyhO-&tCruw`HM9ftIK)M_rj`HzA)zZ>1`S2HN$V&RUot+A4b`#uRG;kfn ziL`=$qglVF0g^;C!FkrjChK_qcT3FJFi91Rz;ryr0#<6GFbyPh_(G2D!KVvz-4Xff z2ewm{oEJ=RSh>yh@wBf5NVe%xY|Swzd|wwkLwG3kuFl-y~|mFbVgimD~6B z=Nj7!4$?_33Az4fyK`CA{l`K0*RML+tdMiOBNUtA#69y;ikrf$Tm$6|84#?QVa+C1 zHvIFt)h?^IbmUlx`pxFI(Kk>YJAq&8i~svr`qQyv(9KQ|s+Oldxa9r=#4wgpNF@9Wh;)nJnkjq$DS>-o1xx(3_@<06md$<Mk)QjMYpf#`3ZG2#gtV7gT2SW5Ui3oau2?gI1B;a|@0KRZLwS*l z2;+db4NNgfJ3j&O9|1{gy1@M#1KEtwyN}nO(WiZjtc4$bNge-$U*3-U_ILl|1ySvL zqO-NsC~#rxsSTmU{RQab;qok!ENto7?(cCnH!V-?&eft`y#5TuW&7bBj?;#9b~3M7 z{N-{3=i;EfNJgi=FW9qN>l2HZ#O;?5%&O03Qa{sV(NV%cP&@$@#B#GPy<-G=kNkda zMs7C32n~)7L^%&VMk;`@q>BqdbGJWo+?6+#X5RIXatt#szh|(1!jeLC_(T=1Rv%k8 z;M0$nyeZ$bg4Kmx*S(thbsN}@v9z+P|7bb3#(@Q+Gc*1lAfF?a9Nhe26PCAQX2QP# z#yx8K`ZJH+k9^gwdl4j^;InU2$8FVgGDpCFlmhjrJ2b@wtF+L$#+qvT14-#^v<|1d zJc6(q8WPA30AMX}*apNE6Oa|DzJQ62q;)$HuPZ*1dz($Gz@Rz@5>^gUS2v^Jfk7*4 z_%BeibC5jldu^u_!V4uB={%`LM5qGNzKZ4s1_3FmPvJvpKw81cV`woUE88Y0-zCe1 z>#k2filB4~viZlYfeuH~7r)nUa4?+jXBD3Bo9z4#A&ezJ@9YGPvZg17l@kstjh*%fWp5i79g)Wlq!wdO=7DvMsg0O)N&u{Z z0kFDLSRdlQ5V!lj%3f({wzngEMiFaORM&|R%Z8%zu0Ha86*p__V3wU(RXY;?l@0%? z=p)%QnZ}ck@2nelEt2r$qVBI9$XOI05>wcFe7U*A*5|*}Pq#)UVGxX*TDhiVI2*3k zoAQFC#`2?8R@gd=nV;S9bp52c0{3ZQCC!cg=L;~(=VE3Jlt>o-M_FEG)BN=8EZ_QE z%}c$;%;DaOdu{Cm>{EY_ME1n>I{}&gj*gCUz}fP{uL08bx(*|qoCh^Gv(APL2v^-b z$9Z|jo2F?1k|8RR7EKp{k*xIeK6M=#>sneCc6P)2H`fVtsPx(?Vx5{lA%lX{d=s0R zxL&o^+LzKTz!7M0D*gV@uy{fY@f4%~vy7haJs@gWd^d1v9#+}iefgK_ z=x2l3l+hLOCyw#9@0<_6wP}b652j!|8E?X1Uk1CW4>2(MXewib(0!xtKUpxD#xkUF z|9lERWoml@qxayO743rub_VcV1<>2OvP1W=zrvaQHd<*wmWoBGseova@Gz;pGokd^DVWw%ez`qsb}~kRx4`uG<%5Lu0s2S zN~^^MK(hHcuLNLF>RX1yzwg8xUSHPnf%|=b`3Y@k2m=VB5o*(Tabt^%iipt4%{9{? zT4GQNPZy-X&SD;^xNnyR9u|_8e2B4W8i>PY2Y7#P!-lj+gzCq#JV`)Xjt~?i83-}I z^CN-mTTS`TLd(-u*2I28q#j~0+k~X>23C6(ukTk}FA=nyRV~=`Xt}2IWW_WHl#R`| z6CRnwpHCy1K6~M3 zGYIQwOg8GNstFt(PeQQ8k*pWju*}ofkArlv`-V^Ir1%#(wWi97v*jtB&APt4vjAB> zBAE|Es>$(|H|b1PlKHmg4i>pgS=^i9db+qr*FyG0JoH#ZRS#G&xx#Fj<;hCl>G zn$1y--<|F}g1Q#u_pMX)r+0RKe3(vL^FQj~o%BNSfSYnN`#~t|-mU|;K8r2WUo}r{ zEoO}c*66Ostqkwa>#xEU>I>Ir6;DLIm`5`soI4NXNYfuYX)K@rPUrCzymQX``X-O?|CE3m`usCthNhtphgsp0WPynpJmclqu}4)WLJCo8$!AdbX;^Dqx+_c#$(o;>UJS!+CZZk3mQrGv0V7ECd5d^ zR+*8kas@RtsGpIH%!j*SLkA~k!k!PBG++@w4ko*7&2yq3&-E#>v$-#ky8fZjT~xGF-cPkDFE=TrcyS{=dY>?>7u+`5Hfz{l;J&> za~y{qrX|>T*u6OYmPfcyLMre|mkdU>wUh$cU1{`Mu5kcZ^1qkW3Wvq_jvfvv(tI-# z=!#GU8Vhv*fK%`(_q?n<`MOjSXS+^|>+36-ocy%s2u`G|*zY;fziAg;t^6X(o{SDn zyq(12ds!?SwFVaJqw^Ch%gK2iCnk+NCxK(G)}4Vm1U4Ao2?-bZAO1qbe)vuJnFS9}J#Gvnxt^bJ9>iUw-QAP$eQ;WhYgbSq zjHR)Bu>eo{r01Zb0iKta+$KP2{NZ74InFMVxG&!@|7-6?+w3BlU|!Qwy{VN-iLg6I zW6MCbZmqL<@yq%B&k{8rFg(RP!72q9nlHOtAA+eYM+d4P9z#NU5XCB%KtmoR4Wq@5 zgjZ=xfZTgBAYC9t3ud?NrMkx)G<2Mm>0otrCC`D!>tccrt*R_XiW$sbyu8Ie$rJa) z@~HArl9Ojw;8aQ?4h;UbvCjIaaPtLcXP84 zi4@^dtFu31l62)G#N$mhML!=OBMS;hS^OBkSj{6cDypf8R~Cy)n(NhYikc3^Oa8Fk zvXQee{_u%k-j@o>rbF~2hcD|`N3bsQ-$yP)6(CrH_4S4N(_)M9Lr;yJ>;N{Hm9D9| zKLU&D3qzO-RJJEo#BVKq#=>Dy;k!J~zq#s4BzpYKaTpxA&fJw32IfTa1}w1#Op;7E zlMuWhVB6AC96%_6w=jmOlQFk&Vo3Tlb2NEG(xMV7QbM@k#)(So75Zrs9?B?zgB5N^ zriv+U%P+%$Q`V;s>LQR#oD(ULvP8&oiRMlOMJUDeXHyf@iL5JYJQ_NYfvW0%Uk2I7 z_{OLZsIMTSO2IT<&t&B8N}>*kFD)ZE_gkDREe$e6!yy3Yk#tHQ^Al_5`u0e1;`a@1zn z>Yp`Boy;Y)1n(n%O>DOnHQszNz(x7vu@GNQiYZ4ZAu?>E+PhmI_| zxlSfo-){l$K9}#uf%j@9S$0@wUhmWHQT6HoyLJ#?B49z>iSJ? z2#_!WM5v-ap#;k-LVOwV?;jBzlF4oy(;^V^`pMBP?-yZsb+J)WOq4ya@$s&U-Iyte zS_BuoATQQJnhhY8c~NX_nT%lv_kRj<6^U!_GSkyTQPI#ap>V^UMsw(_vYnmhRnS6T zFlX>RX4cP0#g2#+)+tF2)&1Sk1`c`hGOTT0jr?Vk@fdD6IHcf82Tt`mV=P|u9yg;? zYClP`Q_tgCB{S|Mo7mdqJ%$-uRhHrqiI2OJ^eq+0*;xrPWP^_^U&QZlxhMbR*FE4bo;-~s5Tj?uZ=O>MbZxp#$nL8dP|n7k--dlpQXM-PQJyWwB z{o-k|`7aQHr>#vBVzp4J|6z3&qNxc705Hir*CQel|?1O`FBoQ ztZ#B`hB*-V?)FP(LUpc#bzJQ4HO>@Ox?U`hPM)oR4sJv~T6q<@<7LxRH;6EASnQ_} zGxRX7dGDOWez>S)anuGZoM42g=tfqxHiRXL8W_%3(v5EP^~O6<_LTPZ{Tch?erZ&6QA?u{XMkAOx`7H}XX_#?n=!;xx+kMfCzQK9CYEwHlai-J{hIJ+(0 z?cJ#`6bkGDd!GT?Z=tBbK*PT2t+3UXt@C^I>N25@f82-~%oiP8&NE~@0uKPB2Q)Mu zfz{rr%MCfFM(AvKFE=pUwjC`^q$oWB<3%U+yI>^YPvQh%Qm#!G#dv+4V>rJqC)`N=*+f?FB0n z=B|H&XXh9O3$ucq`9D=cf@7_R0$pIMGs(@={m7tA06jWMlOzE2BO{P)M4$ z{XAOiij4Nf-@t=)OMChtt~nfpb}L#@m7MHdJu@UjIZZ#232u9PoXR$uynJ@l2-575 zYaY!y2c?Cz$dj?AQ#p*CJqyK#lYf7iaAfShFmH2lB>Xxy8(1)@igMj$j z`rrQo04+L(&fB1x7xQBFl!JVOT6Rao04e?&v2t@(3mL+&3VuM=Oqoal`?!0H$6%(Gv|^c$Rp zKDG#O!ENl{zq@~w4d$d=0>k@{hylu&C+8U3iPz7H*bKqic0zu;Ukcf*4c@&-Hj4`R z2AIH1%1PvRLogXESnj8)-cg=rN3-SN%eA(a%;#TnW;FuaqOY>o03=c8yXC5%E49C2 z-C*%fzuh(Dz2?$Vwb)D;BLm-fxybj%WXjlswB8J#OUsCzpl#16`txUYMJItiYx)QK z{{oZ-Yx$|1`hKY2FFdDPx1t|*7>c40F(p43vP#0JuZJyLtk47F@WYXwdMa)3hqPKL zNn&|fO^pChQ*CtSH+L?ac%rqOslTGa+MO7mPvm150{F_ykvco^`FuiRoj)H>S65n6 zm1S%HJ0uZnXEZgX?U5A~s3)9&as2V=STS4sdqH?d8yhqF!@2q<9|wh*u9*8HB`0XP zNm)*yv!``}p&L2#bOX9<(p|~p?1p1@fl1*pVS^QZqRyIyHylpi2O%jA4hku( zy&b8xmRNbYP(RHyfYHC~WGf)@5UwB~m+6&bT*+_w+(bNR{?u+r0pTMF;)`XK~ z8Gm`X2zu`55apRMcQa;S%$*C(%>V-IjyMA2GoNvd2{X?Np<DQM1|Q!^{Nm6-K2R_@%Tz>bi~^iQw73U8sDfohlj?s$(jq&e*;k>5xNE ztE-V(TZP(KQ6Y@NilR_nUXF3`#R8D4sw{qWo5xiq{pCBiwzaqM zcrkqxGY3b?dp@dmJ`!OuK%MK}n0-pI&_*Ba!7|>!cdRDINMAsTt_x7Hhi5p;`0zs^ z=~Pu=9B_b;?mQlm-ZcK3l2j~ag`cPk7T_Hi5P7Ed!808ZMl6QZ(SaNe6REBiVC3}5 z#^ZvwwQKSF{i3d4{31-728SLBscngz>Y^lxkQ!sZ{e~F1i`lhiG{M4+3I(yz82g2) z*!et{j~}3rw%Q}#jU5kfz45@qo~A7)ZLQd9$&~!c%SCW-s(hop9clJ# z;?>o{TU%WX<_e88lknbqcw`wR7{vJQcP&*_cG%GhZHv+NW|rdlVg!j|>QxNSWA#in z8aE%wo}lqhilR_fR)&7cDab$ik#J6!>pko1VagN%P~F{lQ}I;l^yzq4u1qhRQq}a% z!DVF_U0pDFvQT5IsstFCyKkg6^5nn+Vc|lks}l>tyfLT%ksc^66(U^hW|lO##_{eA|PETQ6We?xlYk<0{vfB+|5hrT`(pAT)) zB)sO%B++R4Gli)wm86|JG4|eD>|8u^CdS!kBUM$UR~&>w8EU6TRYf>QVF6X z;jk#%=MxfSXD3E|{kWQJV@-R~Ww`B3Ns+s>xHhaapfr3(^N`FRX+KTN16b;2`ZSpUN2gGJ;|T`6z@eBVQkwbLN+=( zg&JE`B^KEGd}9B(`|r25^06=NaZ*0c0Bfu7`g+XNh8Yl?+MWo%AG*8q+RFTsN*@Jq zDm6`j-2@dyCg>Q=%@|XrWJn4opm`kWOGUCQlc=e|Utce_B(i@O!s`_(a!RtBpb0W* z0_-MeL^Rxb#L*yGmWftX5jI0lB9ZhrB>a8>cDr^>NOcpGK@(s%K_59%6a~#(apCm} zTb&u;91aVx>+BrYUv`_Iv8M^Jo1l*zDT+d1$`r9f$liOy%$d;CgfVFn(xge^dTO`b zPoiyVg4{_mCJY-B^bsS&5FhI{ze8$*ntch_1Wk~WCctijCTM~_5j0`JouCPtpicx% zfZYU5&;)%VXaejeXo4o_6G0PTH$f9LL7xbk0J{mApb7d!&;-~`&;(7;CxRxxZh|Ig df<6)S{{d`>(oa-wj7tCj002ovPDHLkV1lf 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 eyj=c^m;VjA;|;qm*)c!>0000