root/src/apps/webpositive/SettingsWindow.cpp
/*
 * Copyright 2010 Stephan Aßmus <superstippi@gmx.de>
 * Copyright 2019, Haiku, Inc.
 * All rights reserved. Distributed under the terms of the MIT License.
 */
#include "SettingsWindow.h"

#include <Button.h>
#include <CheckBox.h>
#include <ControlLook.h>
#include <FilePanel.h>
#include <GridLayoutBuilder.h>
#include <GroupLayout.h>
#include <GroupLayoutBuilder.h>
#include <LayoutBuilder.h>
#include <Locale.h>
#include <MenuItem.h>
#include <MenuField.h>
#include <Message.h>
#include <PopUpMenu.h>
#include <ScrollView.h>
#include <SeparatorView.h>
#include <SpaceLayoutItem.h>
#include <Spinner.h>
#include <TabView.h>
#include <TextControl.h>
#include <debugger.h>
#include <SettingsMessage.h>

#include <stdio.h>
#include <stdlib.h>

#include "BrowserApp.h"
#include "BrowsingHistory.h"
#include "BrowserWindow.h"
#include "FontSelectionView.h"
#include "SettingsKeys.h"
#include "WebSettings.h"


#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Settings Window"

enum {
        MSG_APPLY                                                                       = 'aply',
        MSG_CANCEL                                                                      = 'cncl',
        MSG_REVERT                                                                      = 'rvrt',

        MSG_START_PAGE_CHANGED                                          = 'hpch',
        MSG_SEARCH_PAGE_CHANGED                                         = 'spch',
        MSG_SEARCH_PAGE_CHANGED_MENU                            = 'spcm',
        MSG_DOWNLOAD_FOLDER_CHANGED                                     = 'dnfc',
        MSG_NEW_WINDOWS_BEHAVIOR_CHANGED                        = 'nwbc',
        MSG_NEW_TABS_BEHAVIOR_CHANGED                           = 'ntbc',
        MSG_START_UP_BEHAVIOR_CHANGED                           = 'subc',
        MSG_HISTORY_MENU_DAYS_CHANGED                           = 'digm',
        MSG_TAB_DISPLAY_BEHAVIOR_CHANGED                        = 'tdbc',
        MSG_AUTO_HIDE_INTERFACE_BEHAVIOR_CHANGED        = 'ahic',
        MSG_AUTO_HIDE_POINTER_BEHAVIOR_CHANGED          = 'ahpc',
        MSG_SHOW_HOME_BUTTON_CHANGED                            = 'shbc',

        MSG_STANDARD_FONT_CHANGED                                       = 'stfc',
        MSG_SERIF_FONT_CHANGED                                          = 'sefc',
        MSG_SANS_SERIF_FONT_CHANGED                                     = 'ssfc',
        MSG_FIXED_FONT_CHANGED                                          = 'ffch',

        MSG_STANDARD_FONT_SIZE_SELECTED                         = 'sfss',
        MSG_FIXED_FONT_SIZE_SELECTED                            = 'ffss',

        MSG_USE_PROXY_CHANGED                                           = 'upsc',
        MSG_PROXY_ADDRESS_CHANGED                                       = 'psac',
        MSG_PROXY_PORT_CHANGED                                          = 'pspc',
        MSG_USE_PROXY_AUTH_CHANGED                                      = 'upsa',
        MSG_PROXY_USERNAME_CHANGED                                      = 'psuc',
        MSG_PROXY_PASSWORD_CHANGED                                      = 'pswc',

        MSG_CHOOSE_DOWNLOAD_FOLDER                                      = 'swop',
        MSG_HANDLE_DOWNLOAD_FOLDER                                      = 'oprs',
};

static const int32 kDefaultFontSize = 14;


SettingsWindow::SettingsWindow(BRect frame, SettingsMessage* settings)
        :
        BWindow(frame, B_TRANSLATE("Settings"), B_TITLED_WINDOW_LOOK,
                B_NORMAL_WINDOW_FEEL, B_AUTO_UPDATE_SIZE_LIMITS
                        | B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE),
        fSettings(settings)
{
        fApplyButton = new BButton(B_TRANSLATE("Apply"), new BMessage(MSG_APPLY));
        fCancelButton = new BButton(B_TRANSLATE("Cancel"),
                new BMessage(MSG_CANCEL));
        fRevertButton = new BButton(B_TRANSLATE("Revert"),
                new BMessage(MSG_REVERT));

        fOpenFilePanel = NULL;

        float spacing = be_control_look->DefaultItemSpacing();

        BTabView* tabView = new BTabView("settings pages", B_WIDTH_FROM_LABEL);
        tabView->SetBorder(B_NO_BORDER);

        BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
                .SetInsets(0, B_USE_DEFAULT_SPACING, 0, B_USE_WINDOW_SPACING)
                .Add(tabView)
                .Add(new BSeparatorView(B_HORIZONTAL))
                .AddGroup(B_HORIZONTAL)
                        .SetInsets(B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING,
                                B_USE_WINDOW_SPACING, 0)
                        .Add(fRevertButton)
                        .AddGlue()
                        .Add(fCancelButton)
                        .Add(fApplyButton);

        tabView->AddTab(_CreateGeneralPage(spacing));
        tabView->AddTab(_CreateFontsPage(spacing));
        tabView->AddTab(_CreateProxyPage(spacing));

        _SetupFontSelectionView(fStandardFontView,
                new BMessage(MSG_STANDARD_FONT_CHANGED));
        _SetupFontSelectionView(fSerifFontView,
                new BMessage(MSG_SERIF_FONT_CHANGED));
        _SetupFontSelectionView(fSansSerifFontView,
                new BMessage(MSG_SANS_SERIF_FONT_CHANGED));
        _SetupFontSelectionView(fFixedFontView,
                new BMessage(MSG_FIXED_FONT_CHANGED));

        fApplyButton->MakeDefault(true);

        if (!frame.IsValid())
                CenterOnScreen();

        // load settings from disk
        _RevertSettings();
        // apply to WebKit
        _ApplySettings();

        // Start hidden
        Hide();
        Show();
}


SettingsWindow::~SettingsWindow()
{
        RemoveHandler(fStandardFontView);
        delete fStandardFontView;
        RemoveHandler(fSerifFontView);
        delete fSerifFontView;
        RemoveHandler(fSansSerifFontView);
        delete fSansSerifFontView;
        RemoveHandler(fFixedFontView);
        delete fFixedFontView;
        delete fOpenFilePanel;
}


void
SettingsWindow::MessageReceived(BMessage* message)
{
        switch (message->what) {
                case B_COLORS_UPDATED:
                        fStandardFontView->MessageReceived(message);
                        fSerifFontView->MessageReceived(message);
                        fSansSerifFontView->MessageReceived(message);
                        fFixedFontView->MessageReceived(message);
                        break;
                case MSG_APPLY:
                        _ApplySettings();
                        break;
                case MSG_CANCEL:
                        _RevertSettings();
                        PostMessage(B_QUIT_REQUESTED);
                        break;
                case MSG_REVERT:
                        _RevertSettings();
                        break;
                case MSG_CHOOSE_DOWNLOAD_FOLDER:
                        _ChooseDownloadFolder(message);
                        break;
                case MSG_HANDLE_DOWNLOAD_FOLDER:
                        _HandleDownloadPanelResult(fOpenFilePanel, message);
                        break;
                case MSG_STANDARD_FONT_SIZE_SELECTED:
                {
                        int32 size = fStandardSizesSpinner->Value();
                        fStandardFontView->SetSize(size);
                        fSerifFontView->SetSize(size);
                        fSansSerifFontView->SetSize(size);
                        _ValidateControlsEnabledStatus();
                        break;
                }
                case MSG_FIXED_FONT_SIZE_SELECTED:
                {
                        int32 size = fFixedSizesSpinner->Value();
                        fFixedFontView->SetSize(size);
                        _ValidateControlsEnabledStatus();
                        break;
                }

                case MSG_SEARCH_PAGE_CHANGED_MENU:
                {
                        BString searchString;
                        BMenuItem* source;
                        if (message->FindString("searchstring", &searchString) == B_OK) {
                                fSearchPageControl->SetText(searchString);
                                fSearchPageControl->SetEnabled(false);
                        } else
                                fSearchPageControl->SetEnabled(true);

                        if (message->FindPointer("source", (void**)&source) == B_OK)
                                source->SetMarked(true);

                        _ValidateControlsEnabledStatus();
                        break;
                }

                case MSG_START_PAGE_CHANGED:
                case MSG_SEARCH_PAGE_CHANGED:
                case MSG_DOWNLOAD_FOLDER_CHANGED:
                case MSG_START_UP_BEHAVIOR_CHANGED:
                case MSG_NEW_WINDOWS_BEHAVIOR_CHANGED:
                case MSG_NEW_TABS_BEHAVIOR_CHANGED:
                case MSG_HISTORY_MENU_DAYS_CHANGED:
                case MSG_TAB_DISPLAY_BEHAVIOR_CHANGED:
                case MSG_AUTO_HIDE_INTERFACE_BEHAVIOR_CHANGED:
                case MSG_AUTO_HIDE_POINTER_BEHAVIOR_CHANGED:
                case MSG_SHOW_HOME_BUTTON_CHANGED:
                case MSG_STANDARD_FONT_CHANGED:
                case MSG_SERIF_FONT_CHANGED:
                case MSG_SANS_SERIF_FONT_CHANGED:
                case MSG_FIXED_FONT_CHANGED:
                case MSG_USE_PROXY_CHANGED:
                case MSG_PROXY_ADDRESS_CHANGED:
                case MSG_PROXY_PORT_CHANGED:
                case MSG_USE_PROXY_AUTH_CHANGED:
                case MSG_PROXY_USERNAME_CHANGED:
                case MSG_PROXY_PASSWORD_CHANGED:
                        // TODO: Some settings could change live, some others not?
                        _ValidateControlsEnabledStatus();
                        break;

                default:
                        BWindow::MessageReceived(message);
                        break;
        }
}


bool
SettingsWindow::QuitRequested()
{
        if (!IsHidden())
                Hide();
        return false;
}


void
SettingsWindow::Show()
{
        // When showing the window, this is always the
        // point to which we can revert the settings.
        _RevertSettings();
        BWindow::Show();
}


// #pragma mark - private


BView*
SettingsWindow::_CreateGeneralPage(float spacing)
{
        fStartPageControl = new BTextControl("start page",
                B_TRANSLATE("Start page:"), "", new BMessage(MSG_START_PAGE_CHANGED));
        fStartPageControl->SetModificationMessage(
                new BMessage(MSG_START_PAGE_CHANGED));
        fStartPageControl->SetText(
                fSettings->GetValue(kSettingsKeyStartPageURL, kDefaultStartPageURL));

        fSearchPageControl = new BTextControl("search page", "", "",
                new BMessage(MSG_SEARCH_PAGE_CHANGED));
        fSearchPageControl->SetModificationMessage(
                new BMessage(MSG_SEARCH_PAGE_CHANGED));
        BString searchURL = fSettings->GetValue(kSettingsKeySearchPageURL,
                kDefaultSearchPageURL);
        fSearchPageControl->SetText(searchURL);

        fDownloadFolderControl = new BTextControl("download folder",
                B_TRANSLATE("Download folder:"), "",
                new BMessage(MSG_DOWNLOAD_FOLDER_CHANGED));
        fDownloadFolderControl->SetModificationMessage(
                new BMessage(MSG_DOWNLOAD_FOLDER_CHANGED));
        fDownloadFolderControl->SetText(
                fSettings->GetValue(kSettingsKeyDownloadPath, kDefaultDownloadPath));

        fStartUpBehaviorResumePriorSession = new BMenuItem(
                B_TRANSLATE("Resume prior session"),
                new BMessage(MSG_START_UP_BEHAVIOR_CHANGED));
        fStartUpBehaviorStartNewSession = new BMenuItem(
                B_TRANSLATE("Start new session"),
                new BMessage(MSG_START_UP_BEHAVIOR_CHANGED));

        fNewWindowBehaviorOpenHomeItem = new BMenuItem(
                B_TRANSLATE("Open start page"),
                new BMessage(MSG_NEW_WINDOWS_BEHAVIOR_CHANGED));
        fNewWindowBehaviorOpenSearchItem = new BMenuItem(
                B_TRANSLATE("Open search page"),
                new BMessage(MSG_NEW_WINDOWS_BEHAVIOR_CHANGED));
        fNewWindowBehaviorOpenBlankItem = new BMenuItem(
                B_TRANSLATE("Open blank page"),
                new BMessage(MSG_NEW_WINDOWS_BEHAVIOR_CHANGED));

        fNewTabBehaviorCloneCurrentItem = new BMenuItem(
                B_TRANSLATE("Clone current page"),
                new BMessage(MSG_NEW_TABS_BEHAVIOR_CHANGED));
        fNewTabBehaviorOpenHomeItem = new BMenuItem(
                B_TRANSLATE("Open start page"),
                new BMessage(MSG_NEW_TABS_BEHAVIOR_CHANGED));
        fNewTabBehaviorOpenSearchItem = new BMenuItem(
                B_TRANSLATE("Open search page"),
                new BMessage(MSG_NEW_TABS_BEHAVIOR_CHANGED));
        fNewTabBehaviorOpenBlankItem = new BMenuItem(
                B_TRANSLATE("Open blank page"),
                new BMessage(MSG_NEW_TABS_BEHAVIOR_CHANGED));
        fChooseButton = new BButton(B_TRANSLATE("Browse" B_UTF8_ELLIPSIS),
                new BMessage(MSG_CHOOSE_DOWNLOAD_FOLDER));

        fNewWindowBehaviorOpenHomeItem->SetMarked(true);
        fNewTabBehaviorOpenBlankItem->SetMarked(true);
        fStartUpBehaviorResumePriorSession->SetMarked(true);

        BMenuItem* searchPageCustom = new BMenuItem(B_TRANSLATE("Custom"),
                new BMessage(MSG_SEARCH_PAGE_CHANGED_MENU));
        searchPageCustom->SetMarked(true);

        BPopUpMenu* searchPageMenu = new BPopUpMenu("Search page:");
        searchPageMenu->SetRadioMode(true);

        for (int i = 0; kSearchEngines[i].url != NULL; i++) {
                BMessage* message = new BMessage(MSG_SEARCH_PAGE_CHANGED_MENU);
                message->AddString("searchstring", kSearchEngines[i].url);
                searchPageMenu->AddItem(new BMenuItem(kSearchEngines[i].name, message));

        }
        searchPageMenu->AddItem(new BSeparatorItem());
        searchPageMenu->AddItem(searchPageCustom);
        fSearchPageMenu = new BMenuField("search page",
                B_TRANSLATE("Search page:"), searchPageMenu);
        fSearchPageMenu->SetToolTip(B_TRANSLATE("%s - Search term"));

        BPopUpMenu* startUpBehaviorMenu = new BPopUpMenu("Start up");
        startUpBehaviorMenu->AddItem(fStartUpBehaviorResumePriorSession);
        startUpBehaviorMenu->AddItem(fStartUpBehaviorStartNewSession);
        fStartUpBehaviorMenu = new BMenuField("start up behavior",
                B_TRANSLATE("Start up:"), startUpBehaviorMenu);


        BPopUpMenu* newWindowBehaviorMenu = new BPopUpMenu("New windows");
        newWindowBehaviorMenu->AddItem(fNewWindowBehaviorOpenHomeItem);
        newWindowBehaviorMenu->AddItem(fNewWindowBehaviorOpenSearchItem);
        newWindowBehaviorMenu->AddItem(fNewWindowBehaviorOpenBlankItem);
        fNewWindowBehaviorMenu = new BMenuField("new window behavior",
                B_TRANSLATE("New windows:"), newWindowBehaviorMenu);

        BPopUpMenu* newTabBehaviorMenu = new BPopUpMenu("New tabs");
        newTabBehaviorMenu->AddItem(fNewTabBehaviorOpenBlankItem);
        newTabBehaviorMenu->AddItem(fNewTabBehaviorOpenHomeItem);
        newTabBehaviorMenu->AddItem(fNewTabBehaviorOpenSearchItem);
        newTabBehaviorMenu->AddItem(fNewTabBehaviorCloneCurrentItem);
        fNewTabBehaviorMenu = new BMenuField("new tab behavior",
                B_TRANSLATE("New tabs:"), newTabBehaviorMenu);

        fDaysInHistory = new BSpinner("days in history",
                B_TRANSLATE("Number of days to keep links in History menu:"),
                new BMessage(MSG_HISTORY_MENU_DAYS_CHANGED));
        fDaysInHistory->SetRange(1, 35);
        fDaysInHistory->SetValue(
                BrowsingHistory::DefaultInstance()->MaxHistoryItemAge());

        fShowTabsIfOnlyOnePage = new BCheckBox("show tabs if only one page",
                B_TRANSLATE("Show tabs if only one page is open"),
                new BMessage(MSG_TAB_DISPLAY_BEHAVIOR_CHANGED));
        fShowTabsIfOnlyOnePage->SetValue(B_CONTROL_ON);

        fAutoHideInterfaceInFullscreenMode = new BCheckBox("auto-hide interface",
                B_TRANSLATE("Auto-hide interface in full screen mode"),
                new BMessage(MSG_AUTO_HIDE_INTERFACE_BEHAVIOR_CHANGED));
        fAutoHideInterfaceInFullscreenMode->SetValue(B_CONTROL_OFF);

        fAutoHidePointer = new BCheckBox("auto-hide pointer",
                B_TRANSLATE("Auto-hide mouse pointer"),
                new BMessage(MSG_AUTO_HIDE_POINTER_BEHAVIOR_CHANGED));
        fAutoHidePointer->SetValue(B_CONTROL_OFF);

        fShowHomeButton = new BCheckBox("show home button",
                B_TRANSLATE("Show home button"),
                new BMessage(MSG_SHOW_HOME_BUTTON_CHANGED));
        fShowHomeButton->SetValue(B_CONTROL_ON);

        BView* view = BGroupLayoutBuilder(B_VERTICAL, 0)
                .Add(BGridLayoutBuilder(spacing / 2, spacing / 2)
                        .Add(fStartPageControl->CreateLabelLayoutItem(), 0, 0)
                        .Add(fStartPageControl->CreateTextViewLayoutItem(), 1, 0, 4)

                        .Add(fSearchPageMenu->CreateLabelLayoutItem(), 0, 1)
                        .Add(fSearchPageMenu->CreateMenuBarLayoutItem(), 1, 1)

                        .Add(fSearchPageControl->CreateLabelLayoutItem(), 2, 1)
                        .Add(fSearchPageControl->CreateTextViewLayoutItem(), 3, 1, 2)

                        .Add(fStartUpBehaviorMenu->CreateLabelLayoutItem(), 0, 2)
                        .Add(fStartUpBehaviorMenu->CreateMenuBarLayoutItem(), 1, 2, 4)

                        .Add(fNewWindowBehaviorMenu->CreateLabelLayoutItem(), 0, 3)
                        .Add(fNewWindowBehaviorMenu->CreateMenuBarLayoutItem(), 1, 3, 4)

                        .Add(fNewTabBehaviorMenu->CreateLabelLayoutItem(), 0, 4)
                        .Add(fNewTabBehaviorMenu->CreateMenuBarLayoutItem(), 1, 4, 4)

                        .Add(fDownloadFolderControl->CreateLabelLayoutItem(), 0, 5)
                        .Add(fDownloadFolderControl->CreateTextViewLayoutItem(), 1, 5, 3)
                        .Add(fChooseButton, 4, 5)
                )
                .Add(BSpaceLayoutItem::CreateVerticalStrut(spacing))
                .Add(new BSeparatorView(B_HORIZONTAL, B_PLAIN_BORDER))
                .Add(BSpaceLayoutItem::CreateVerticalStrut(spacing))
                .Add(fShowTabsIfOnlyOnePage)
                .Add(fAutoHideInterfaceInFullscreenMode)
                .Add(fAutoHidePointer)
                .Add(fShowHomeButton)
                .Add(BSpaceLayoutItem::CreateVerticalStrut(spacing))

                .AddGroup(B_HORIZONTAL)
                        .Add(fDaysInHistory)
                        .AddGlue()
                        .End()
                .AddGlue()
                .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
                        B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING)
                .TopView()
        ;
        view->SetName(B_TRANSLATE("General"));
        return view;
}


BView*
SettingsWindow::_CreateFontsPage(float spacing)
{
        fStandardFontView = new FontSelectionView("standard",
                B_TRANSLATE("Standard font:"), true, be_plain_font);
        BFont defaultSerifFont = _FindDefaultSerifFont();
        fSerifFontView = new FontSelectionView("serif",
                B_TRANSLATE("Serif font:"), true, &defaultSerifFont);
        fSansSerifFontView = new FontSelectionView("sans serif",
                B_TRANSLATE("Sans serif font:"), true, be_plain_font);
        fFixedFontView = new FontSelectionView("fixed",
                B_TRANSLATE("Fixed font:"), true, be_fixed_font);

        fStandardSizesSpinner = new BSpinner("standard font size",
                B_TRANSLATE("Default standard font size:"),
                new BMessage(MSG_STANDARD_FONT_SIZE_SELECTED));
        fStandardSizesSpinner->SetAlignment(B_ALIGN_RIGHT);

        fFixedSizesSpinner = new BSpinner("fixed font size",
                B_TRANSLATE("Default fixed font size:"),
                new BMessage(MSG_FIXED_FONT_SIZE_SELECTED));
        fFixedSizesSpinner->SetAlignment(B_ALIGN_RIGHT);

        BView* view = BGridLayoutBuilder(spacing / 2, spacing / 2)
                .Add(fStandardFontView->CreateFontsLabelLayoutItem(), 0, 0)
                .Add(fStandardFontView->CreateFontsMenuBarLayoutItem(), 1, 0)
                .Add(fStandardSizesSpinner->CreateLabelLayoutItem(), 2, 0)
                .Add(fStandardSizesSpinner->CreateTextViewLayoutItem(), 3, 0)
                .Add(fStandardFontView->PreviewBox(), 1, 1, 3)
                .Add(fSerifFontView->CreateFontsLabelLayoutItem(), 0, 2)
                .Add(fSerifFontView->CreateFontsMenuBarLayoutItem(), 1, 2)
                .Add(fSerifFontView->PreviewBox(), 1, 3, 3)
                .Add(fSansSerifFontView->CreateFontsLabelLayoutItem(), 0, 4)
                .Add(fSansSerifFontView->CreateFontsMenuBarLayoutItem(), 1, 4)
                .Add(fSansSerifFontView->PreviewBox(), 1, 5, 3)
                .Add(BSpaceLayoutItem::CreateVerticalStrut(spacing / 2), 0, 6, 2)
                .Add(fFixedFontView->CreateFontsLabelLayoutItem(), 0, 7)
                .Add(fFixedFontView->CreateFontsMenuBarLayoutItem(), 1, 7)
                .Add(fFixedSizesSpinner->CreateLabelLayoutItem(), 2, 7)
                .Add(fFixedSizesSpinner->CreateTextViewLayoutItem(), 3, 7)
                .Add(fFixedFontView->PreviewBox(), 1, 8, 3)
                .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
                        B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING)
                .View();

        view->SetName(B_TRANSLATE("Fonts"));
        return view;
}


BView*
SettingsWindow::_CreateProxyPage(float spacing)
{
        fUseProxyCheckBox = new BCheckBox("use proxy",
                B_TRANSLATE("Use proxy server to connect to the internet"),
                new BMessage(MSG_USE_PROXY_CHANGED));
        fUseProxyCheckBox->SetValue(B_CONTROL_ON);

        fProxyAddressControl = new BTextControl("proxy address",
                B_TRANSLATE("Proxy server address:"), "",
                new BMessage(MSG_PROXY_ADDRESS_CHANGED));
        fProxyAddressControl->SetModificationMessage(
                new BMessage(MSG_PROXY_ADDRESS_CHANGED));
        fProxyAddressControl->SetText(
                fSettings->GetValue(kSettingsKeyProxyAddress, ""));

        fProxyPortControl = new BTextControl("proxy port",
                B_TRANSLATE("Proxy server port:"), "",
                new BMessage(MSG_PROXY_PORT_CHANGED));
        fProxyPortControl->SetModificationMessage(
                new BMessage(MSG_PROXY_PORT_CHANGED));
        fProxyPortControl->SetText(
                fSettings->GetValue(kSettingsKeyProxyPort, ""));

        fUseProxyAuthCheckBox = new BCheckBox("use authentication",
                B_TRANSLATE("Proxy server requires authentication"),
                new BMessage(MSG_USE_PROXY_AUTH_CHANGED));
        fUseProxyAuthCheckBox->SetValue(B_CONTROL_ON);

        fProxyUsernameControl = new BTextControl("proxy username",
                B_TRANSLATE("Proxy username:"), "",
                new BMessage(MSG_PROXY_USERNAME_CHANGED));
        fProxyUsernameControl->SetModificationMessage(
                new BMessage(MSG_PROXY_USERNAME_CHANGED));
        fProxyUsernameControl->SetText(
                fSettings->GetValue(kSettingsKeyProxyUsername, ""));

        fProxyPasswordControl = new BTextControl("proxy password",
                B_TRANSLATE("Proxy password:"), "",
                new BMessage(MSG_PROXY_PASSWORD_CHANGED));
        fProxyPasswordControl->SetModificationMessage(
                new BMessage(MSG_PROXY_PASSWORD_CHANGED));
        fProxyPasswordControl->TextView()->HideTyping(true);
        fProxyPasswordControl->SetText(
                fSettings->GetValue(kSettingsKeyProxyPassword, ""));

        BView* view = BGridLayoutBuilder(spacing / 2, spacing / 2)
                .Add(fUseProxyCheckBox, 0, 0, 2)
                .Add(fProxyAddressControl->CreateLabelLayoutItem(), 0, 1)
                .Add(fProxyAddressControl->CreateTextViewLayoutItem(), 1, 1, 2)
                .Add(fProxyPortControl->CreateLabelLayoutItem(), 0, 2)
                .Add(fProxyPortControl->CreateTextViewLayoutItem(), 1, 2, 2)
                .Add(BSpaceLayoutItem::CreateVerticalStrut(spacing), 0, 3)
                .Add(fUseProxyAuthCheckBox, 0, 4, 2)
                .Add(fProxyUsernameControl->CreateLabelLayoutItem(), 0, 5)
                .Add(fProxyUsernameControl->CreateTextViewLayoutItem(), 1, 5, 2)
                .Add(fProxyPasswordControl->CreateLabelLayoutItem(), 0, 6)
                .Add(fProxyPasswordControl->CreateTextViewLayoutItem(), 1, 6, 2)
                .Add(BSpaceLayoutItem::CreateGlue(), 0, 7)
                .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
                        B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING)
                .View();

        view->SetName(B_TRANSLATE("Proxy server"));
        return view;
}


void
SettingsWindow::_SetupFontSelectionView(FontSelectionView* view,
        BMessage* message)
{
        AddHandler(view);
        view->AttachedToLooper();
        view->SetMessage(message);
        view->SetTarget(this);
}


// #pragma mark -


bool
SettingsWindow::_CanApplySettings() const
{
        bool canApply = false;

        // General settings
        canApply = canApply || (strcmp(fStartPageControl->Text(),
                fSettings->GetValue(kSettingsKeyStartPageURL,
                        kDefaultStartPageURL)) != 0);

        canApply = canApply || (strcmp(fSearchPageControl->Text(),
                fSettings->GetValue(kSettingsKeySearchPageURL,
                        kDefaultSearchPageURL)) != 0);

        canApply = canApply || (strcmp(fDownloadFolderControl->Text(),
                fSettings->GetValue(kSettingsKeyDownloadPath,
                        kDefaultDownloadPath)) != 0);

        canApply = canApply || ((fShowTabsIfOnlyOnePage->Value() == B_CONTROL_ON)
                != fSettings->GetValue(kSettingsKeyShowTabsIfSinglePageOpen, true));

        canApply = canApply || (
                (fAutoHideInterfaceInFullscreenMode->Value() == B_CONTROL_ON)
                != fSettings->GetValue(kSettingsKeyAutoHideInterfaceInFullscreenMode,
                        false));

        canApply = canApply || (
                (fAutoHidePointer->Value() == B_CONTROL_ON)
                != fSettings->GetValue(kSettingsKeyAutoHidePointer, false));

        canApply = canApply || ((fShowHomeButton->Value() == B_CONTROL_ON)
                != fSettings->GetValue(kSettingsKeyShowHomeButton, true));

        canApply = canApply || (fDaysInHistory->Value()
                != BrowsingHistory::DefaultInstance()->MaxHistoryItemAge());

        // Start up policy
        canApply = canApply || (_StartUpPolicy()
                != fSettings->GetValue(kSettingsKeyStartUpPolicy,
                        (uint32)ResumePriorSession));

        // New window policy
        canApply = canApply || (_NewWindowPolicy()
                != fSettings->GetValue(kSettingsKeyNewWindowPolicy,
                        (uint32)OpenStartPage));

        // New tab policy
        canApply = canApply || (_NewTabPolicy()
                != fSettings->GetValue(kSettingsKeyNewTabPolicy,
                        (uint32)OpenBlankPage));

        // Font settings
        canApply = canApply || (fStandardFontView->Font()
                != fSettings->GetValue("standard font", *be_plain_font));

        canApply = canApply || (fSerifFontView->Font()
                != fSettings->GetValue("serif font", _FindDefaultSerifFont()));

        canApply = canApply || (fSansSerifFontView->Font()
                != fSettings->GetValue("sans serif font", *be_plain_font));

        canApply = canApply || (fFixedFontView->Font()
                != fSettings->GetValue("fixed font", *be_fixed_font));

        canApply = canApply || (fStandardSizesSpinner->Value()
                != fSettings->GetValue("standard font size", kDefaultFontSize));

        canApply = canApply || (fFixedSizesSpinner->Value()
                != fSettings->GetValue("fixed font size", kDefaultFontSize));

        // Proxy settings
        canApply = canApply || ((fUseProxyCheckBox->Value() == B_CONTROL_ON)
                != fSettings->GetValue(kSettingsKeyUseProxy, false));

        canApply = canApply || (strcmp(fProxyAddressControl->Text(),
                fSettings->GetValue(kSettingsKeyProxyAddress, "")) != 0);

        canApply = canApply || (_ProxyPort()
                != fSettings->GetValue(kSettingsKeyProxyPort, (uint32)0));

        canApply = canApply || ((fUseProxyAuthCheckBox->Value() == B_CONTROL_ON)
                != fSettings->GetValue(kSettingsKeyUseProxyAuth, false));

        canApply = canApply || (strcmp(fProxyUsernameControl->Text(),
                fSettings->GetValue(kSettingsKeyProxyUsername, "")) != 0);

        canApply = canApply || (strcmp(fProxyPasswordControl->Text(),
                fSettings->GetValue(kSettingsKeyProxyPassword, "")) != 0);

        return canApply;
}


void
SettingsWindow::_ApplySettings()
{
        // Store general settings
        BrowsingHistory::DefaultInstance()->SetMaxHistoryItemAge(
                (uint32)fDaysInHistory->Value());
        fSettings->SetValue(kSettingsKeyStartPageURL, fStartPageControl->Text());
        fSettings->SetValue(kSettingsKeySearchPageURL, fSearchPageControl->Text());
        fSettings->SetValue(kSettingsKeyDownloadPath, fDownloadFolderControl->Text());
        fSettings->SetValue(kSettingsKeyShowTabsIfSinglePageOpen,
                fShowTabsIfOnlyOnePage->Value() == B_CONTROL_ON);
        fSettings->SetValue(kSettingsKeyAutoHideInterfaceInFullscreenMode,
                fAutoHideInterfaceInFullscreenMode->Value() == B_CONTROL_ON);
        fSettings->SetValue(kSettingsKeyAutoHidePointer,
                fAutoHidePointer->Value() == B_CONTROL_ON);
        fSettings->SetValue(kSettingsKeyShowHomeButton,
                fShowHomeButton->Value() == B_CONTROL_ON);

        // New page policies
        fSettings->SetValue(kSettingsKeyStartUpPolicy, _StartUpPolicy());
        fSettings->SetValue(kSettingsKeyNewWindowPolicy, _NewWindowPolicy());
        fSettings->SetValue(kSettingsKeyNewTabPolicy, _NewTabPolicy());

        // Store font settings
        fSettings->SetValue("standard font", fStandardFontView->Font());
        fSettings->SetValue("serif font", fSerifFontView->Font());
        fSettings->SetValue("sans serif font", fSansSerifFontView->Font());
        fSettings->SetValue("fixed font", fFixedFontView->Font());
        int32 standardFontSize = fStandardSizesSpinner->Value();
        int32 fixedFontSize = fFixedSizesSpinner->Value();
        fSettings->SetValue("standard font size", standardFontSize);
        fSettings->SetValue("fixed font size", fixedFontSize);

        // Store proxy settings

        fSettings->SetValue(kSettingsKeyUseProxy,
                fUseProxyCheckBox->Value() == B_CONTROL_ON);
        fSettings->SetValue(kSettingsKeyProxyAddress,
                fProxyAddressControl->Text());
        uint32 proxyPort = _ProxyPort();
        fSettings->SetValue(kSettingsKeyProxyPort, proxyPort);
        fSettings->SetValue(kSettingsKeyUseProxyAuth,
                fUseProxyAuthCheckBox->Value() == B_CONTROL_ON);
        fSettings->SetValue(kSettingsKeyProxyUsername,
                fProxyUsernameControl->Text());
        fSettings->SetValue(kSettingsKeyProxyPassword,
                fProxyPasswordControl->Text());

        fSettings->Save();

        // Apply settings to default web page settings.
        BWebSettings::Default()->SetStandardFont(fStandardFontView->Font());
        BWebSettings::Default()->SetSerifFont(fSerifFontView->Font());
        BWebSettings::Default()->SetSansSerifFont(fSansSerifFontView->Font());
        BWebSettings::Default()->SetFixedFont(fFixedFontView->Font());
        BWebSettings::Default()->SetDefaultStandardFontSize(standardFontSize);
        BWebSettings::Default()->SetDefaultFixedFontSize(fixedFontSize);

        if (fUseProxyCheckBox->Value() == B_CONTROL_ON) {
                if (fUseProxyAuthCheckBox->Value() == B_CONTROL_ON) {
                        BWebSettings::Default()->SetProxyInfo(fProxyAddressControl->Text(),
                                proxyPort, B_PROXY_TYPE_HTTP, fProxyUsernameControl->Text(),
                                fProxyPasswordControl->Text());
                } else {
                        BWebSettings::Default()->SetProxyInfo(fProxyAddressControl->Text(),
                                proxyPort, B_PROXY_TYPE_HTTP, "", "");
                }
        } else
                BWebSettings::Default()->SetProxyInfo();

        // This will find all currently instantiated page settings and apply
        // the default values, unless the page settings have local overrides.
        BWebSettings::Default()->Apply();

        _ValidateControlsEnabledStatus();
}


void
SettingsWindow::_RevertSettings()
{
        fStartPageControl->SetText(
                fSettings->GetValue(kSettingsKeyStartPageURL, kDefaultStartPageURL));

        BString searchPage = fSettings->GetValue(kSettingsKeySearchPageURL,
                kDefaultSearchPageURL);
        fSearchPageControl->SetText(searchPage);

        bool found = false;
        BMenu* searchMenu = fSearchPageMenu->Menu();
        int32 itemCount = searchMenu->CountItems() - 2;
                // Ignore the two last items: separator and "custom"
        for (int i = 0; i < itemCount; i++) {
                BMenuItem* item = searchMenu->ItemAt(i);
                BMessage* message = item->Message();
                if (message->FindString("searchstring") == searchPage) {
                        item->SetMarked(true);
                        fSearchPageControl->SetEnabled(false);
                        found = true;
                        break;
                }
        }

        if (!found)
                searchMenu->ItemAt(searchMenu->CountItems() - 1)->SetMarked(true);

        fDownloadFolderControl->SetText(
                fSettings->GetValue(kSettingsKeyDownloadPath, kDefaultDownloadPath));
        fShowTabsIfOnlyOnePage->SetValue(
                fSettings->GetValue(kSettingsKeyShowTabsIfSinglePageOpen, true));
        fAutoHideInterfaceInFullscreenMode->SetValue(
                fSettings->GetValue(kSettingsKeyAutoHideInterfaceInFullscreenMode,
                        false));
        fAutoHidePointer->SetValue(
                fSettings->GetValue(kSettingsKeyAutoHidePointer, false));
        fShowHomeButton->SetValue(
                fSettings->GetValue(kSettingsKeyShowHomeButton, true));

        fDaysInHistory->SetValue(
                BrowsingHistory::DefaultInstance()->MaxHistoryItemAge());

        // Start Up policy
        uint32 startUpPolicy = fSettings->GetValue(kSettingsKeyStartUpPolicy,
                (uint32)ResumePriorSession);
        switch (startUpPolicy) {
                default:
                case ResumePriorSession:
                        fStartUpBehaviorResumePriorSession->SetMarked(true);
                        break;
                case StartNewSession:
                        fStartUpBehaviorStartNewSession->SetMarked(true);
                        break;
        }

        // New window policy
        uint32 newWindowPolicy = fSettings->GetValue(kSettingsKeyNewWindowPolicy,
                (uint32)OpenStartPage);
        switch (newWindowPolicy) {
                default:
                case OpenStartPage:
                        fNewWindowBehaviorOpenHomeItem->SetMarked(true);
                        break;
                case OpenSearchPage:
                        fNewWindowBehaviorOpenSearchItem->SetMarked(true);
                        break;
                case OpenBlankPage:
                        fNewWindowBehaviorOpenBlankItem->SetMarked(true);
                        break;
        }

        // New tab policy
        uint32 newTabPolicy = fSettings->GetValue(kSettingsKeyNewTabPolicy,
                (uint32)OpenBlankPage);
        switch (newTabPolicy) {
                default:
                case OpenBlankPage:
                        fNewTabBehaviorOpenBlankItem->SetMarked(true);
                        break;
                case OpenStartPage:
                        fNewTabBehaviorOpenHomeItem->SetMarked(true);
                        break;
                case OpenSearchPage:
                        fNewTabBehaviorOpenSearchItem->SetMarked(true);
                        break;
                case CloneCurrentPage:
                        fNewTabBehaviorCloneCurrentItem->SetMarked(true);
                        break;
        }

        // Font settings
        int32 defaultFontSize = fSettings->GetValue("standard font size",
                kDefaultFontSize);
        int32 defaultFixedFontSize = fSettings->GetValue("fixed font size",
                kDefaultFontSize);

        fStandardSizesSpinner->SetValue(defaultFontSize);
        fFixedSizesSpinner->SetValue(defaultFixedFontSize);

        fStandardFontView->SetFont(fSettings->GetValue("standard font",
                *be_plain_font), defaultFontSize);
        fSerifFontView->SetFont(fSettings->GetValue("serif font",
                _FindDefaultSerifFont()), defaultFontSize);
        fSansSerifFontView->SetFont(fSettings->GetValue("sans serif font",
                *be_plain_font), defaultFontSize);
        fFixedFontView->SetFont(fSettings->GetValue("fixed font",
                *be_fixed_font), defaultFixedFontSize);

        // Proxy settings
        fUseProxyCheckBox->SetValue(fSettings->GetValue(kSettingsKeyUseProxy,
                false));
        fProxyAddressControl->SetText(fSettings->GetValue(kSettingsKeyProxyAddress,
                ""));
        BString keyProxyPort;
        keyProxyPort << fSettings->GetValue(kSettingsKeyProxyPort, (uint32)0);
        fProxyPortControl->SetText(keyProxyPort.String());
        fUseProxyAuthCheckBox->SetValue(fSettings->GetValue(kSettingsKeyUseProxyAuth,
                false));
        fProxyUsernameControl->SetText(fSettings->GetValue(kSettingsKeyProxyUsername,
                ""));
        fProxyPasswordControl->SetText(fSettings->GetValue(kSettingsKeyProxyPassword,
                ""));

        _ValidateControlsEnabledStatus();
}


void
SettingsWindow::_ChooseDownloadFolder(const BMessage* message)
{
        if (fOpenFilePanel == NULL) {
                BMessenger target(this);
                fOpenFilePanel = new (std::nothrow) BFilePanel(B_OPEN_PANEL,
                        &target, NULL, B_DIRECTORY_NODE);
        }
        BMessage panelMessage(MSG_HANDLE_DOWNLOAD_FOLDER);
        fOpenFilePanel->SetMessage(&panelMessage);
        fOpenFilePanel->Show();
}


void
SettingsWindow:: _HandleDownloadPanelResult(BFilePanel* panel,
        const BMessage* message)
{
        entry_ref ref;
        if (message->FindRef("refs", 0, &ref) == B_OK)
        {
                BPath path(&ref);
                fDownloadFolderControl->SetText(path.Path());
        }
}


void
SettingsWindow::_ValidateControlsEnabledStatus()
{
        bool canApply = _CanApplySettings();
        fApplyButton->SetEnabled(canApply);
        fRevertButton->SetEnabled(canApply);
        // Let the Cancel button be enabled always, as another way to close the
        // window...
        fCancelButton->SetEnabled(true);

        bool useProxy = fUseProxyCheckBox->Value() == B_CONTROL_ON;
        fProxyAddressControl->SetEnabled(useProxy);
        fProxyPortControl->SetEnabled(useProxy);
        fUseProxyAuthCheckBox->SetEnabled(useProxy);
        bool useProxyAuth = useProxy && fUseProxyAuthCheckBox->Value() == B_CONTROL_ON;
        fProxyUsernameControl->SetEnabled(useProxyAuth);
        fProxyPasswordControl->SetEnabled(useProxyAuth);
}


// #pragma mark -


uint32
SettingsWindow::_StartUpPolicy() const
{
        uint32 startUpPolicy = ResumePriorSession;
        BMenuItem* markedItem = fStartUpBehaviorMenu->Menu()->FindMarked();
        if (markedItem == fStartUpBehaviorStartNewSession)
                startUpPolicy = StartNewSession;
        return startUpPolicy;
}

uint32
SettingsWindow::_NewWindowPolicy() const
{
        uint32 newWindowPolicy = OpenStartPage;
        BMenuItem* markedItem = fNewWindowBehaviorMenu->Menu()->FindMarked();
        if (markedItem == fNewWindowBehaviorOpenSearchItem)
                newWindowPolicy = OpenSearchPage;
        else if (markedItem == fNewWindowBehaviorOpenBlankItem)
                newWindowPolicy = OpenBlankPage;
        return newWindowPolicy;
}


uint32
SettingsWindow::_NewTabPolicy() const
{
        uint32 newTabPolicy = OpenBlankPage;
        BMenuItem* markedItem = fNewTabBehaviorMenu->Menu()->FindMarked();
        if (markedItem == fNewTabBehaviorCloneCurrentItem)
                newTabPolicy = CloneCurrentPage;
        else if (markedItem == fNewTabBehaviorOpenHomeItem)
                newTabPolicy = OpenStartPage;
        else if (markedItem == fNewTabBehaviorOpenSearchItem)
                newTabPolicy = OpenSearchPage;
        return newTabPolicy;
}


BFont
SettingsWindow::_FindDefaultSerifFont() const
{
        // Default to the first "serif" font we find.
        BFont serifFont(*be_plain_font);
        font_family family;
        int32 familyCount = count_font_families();
        for (int32 i = 0; i < familyCount; i++) {
                if (get_font_family(i, &family) == B_OK) {
                        BString familyString(family);
                        if (familyString.IFindFirst("sans") >= 0)
                                continue;
                        if (familyString.IFindFirst("serif") >= 0) {
                                serifFont.SetFamilyAndFace(family, B_REGULAR_FACE);
                                break;
                        }
                }
        }
        return serifFont;
}


uint32
SettingsWindow::_ProxyPort() const
{
        return atoul(fProxyPortControl->Text());
}