root/src/apps/bootmanager/FileSelectionPage.cpp
/*
 * Copyright 2008-2010, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *              Michael Pfeiffer <laplace@users.sourceforge.net>
 */


#include "FileSelectionPage.h"

#include <string.h>

#include <Button.h>
#include <Catalog.h>
#include <ControlLook.h>
#include <Path.h>
#include <RadioButton.h>
#include <TextControl.h>
#include <TextView.h>


#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "FileSelectionPage"


const uint32 kMsgOpenFilePanel = 'open';


FileSelectionPage::FileSelectionPage(BMessage* settings, BRect frame,
        const char* name, const char* description, file_panel_mode mode)
        :
        WizardPageView(settings, frame, name, B_FOLLOW_ALL,
                B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE),
        fMode(mode),
        fFilePanel(NULL)
{
        _BuildUI(description);
}


FileSelectionPage::~FileSelectionPage()
{
}


void
FileSelectionPage::FrameResized(float width, float height)
{
        WizardPageView::FrameResized(width, height);
        _Layout();
}


void
FileSelectionPage::AttachedToWindow()
{
        fSelect->SetTarget(this);
}


void
FileSelectionPage::MessageReceived(BMessage* message)
{
        switch (message->what) {
                case kMsgOpenFilePanel:
                        _OpenFilePanel();
                        break;
                case B_REFS_RECEIVED:
                case B_SAVE_REQUESTED:
                        _SetFileFromFilePanelMessage(message);
                        break;
                case B_CANCEL:
                        _FilePanelCanceled();
                        break;
                default:
                        WizardPageView::MessageReceived(message);
        }
}


void
FileSelectionPage::PageCompleted()
{
        fSettings->ReplaceString("file", fFile->Text());
}


const float kFileButtonDistance = 10;

void
FileSelectionPage::_BuildUI(const char* description)
{
        const float kSpacing = be_control_look->DefaultItemSpacing();
        BRect rect(Bounds());

        fDescription = CreateDescription(rect, "description", description);

        MakeHeading(fDescription);
        AddChild(fDescription);

        BString file;
        fSettings->FindString("file", &file);

        fSelect = new BButton(rect, "select",
                B_TRANSLATE_COMMENT("Select", "Button"),
                new BMessage(kMsgOpenFilePanel),
                B_FOLLOW_RIGHT);
        fSelect->ResizeToPreferred();

        float selectLeft = rect.right - fSelect->Bounds().Width();
        rect.right = selectLeft - kSpacing;
        fFile = new BTextControl(rect, "file",
                B_TRANSLATE_COMMENT("File:", "Text control label"),
                file.String(), new BMessage());
        fFile->SetDivider(be_plain_font->StringWidth(fFile->Label()) + 5);
        AddChild(fFile);

        fSelect->MoveTo(selectLeft, 0);
        AddChild(fSelect);

        _Layout();
}


void
FileSelectionPage::_Layout()
{
        const float kSpacing = be_control_look->DefaultItemSpacing();
        LayoutDescriptionVertically(fDescription);

        float left = fFile->Frame().left;
        float top = fDescription->Frame().bottom + kSpacing;

        // center "file" text field and "select" button vertically
        float selectTop = top;
        float fileTop = top;
        float fileHeight = fFile->Bounds().Height();
        float selectHeight = fSelect->Bounds().Height();
        if (fileHeight < selectHeight) {
                int delta = (int)((selectHeight - fileHeight + 1) / 2);
                fileTop += delta;
        } else {
                int delta = (int)((fileHeight - selectHeight + 1) / 2);
                selectTop += delta;
        }

        fFile->MoveTo(left, fileTop);

        float width = fSelect->Frame().left - kSpacing - left;
        fFile->ResizeTo(width, fileHeight);

        left = fSelect->Frame().left;
        fSelect->MoveTo(left, selectTop);
}


void
FileSelectionPage::_OpenFilePanel()
{
        if (fFilePanel != NULL)
                return;

        const entry_ref* directory = NULL;
        entry_ref base;
        BPath file(fFile->Text());
        BPath parent;

        if (file.GetParent(&parent) == B_OK &&
                get_ref_for_path(parent.Path(), &base) == B_OK)
                directory = &base;

        BMessenger messenger(this);
        fFilePanel = new BFilePanel(fMode, &messenger, directory,
                B_FILE_NODE, false, NULL, NULL, true);
        if (fMode == B_SAVE_PANEL && file.Leaf() != NULL)
                fFilePanel->SetSaveText(file.Leaf());
        fFilePanel->Show();
}


void
FileSelectionPage::_SetFileFromFilePanelMessage(BMessage* message)
{
        if (message->what == B_SAVE_REQUESTED) {
                entry_ref directory;
                BString name;
                message->FindRef("directory", &directory);
                message->FindString("name", &name);
                BPath path(&directory);
                if (path.Append(name.String()) == B_OK)
                        fFile->SetText(path.Path());
        } else {
                entry_ref entryRef;
                message->FindRef("refs", &entryRef);
                BEntry entry(&entryRef);
                BPath path;
                if (entry.GetPath(&path) == B_OK)
                        fFile->SetText(path.Path());
        }
}


void
FileSelectionPage::_FilePanelCanceled()
{
        delete fFilePanel;
        fFilePanel = NULL;
}