* Copyright (C) 2007 Andrea Anzani <andrea.anzani@gmail.com>
* Copyright (C) 2007, 2010 Ryan Leavengood <leavengood@gmail.com>
* Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com>
* Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
* Copyright (C) 2010 Michael Lotz <mmlr@mlotz.ch>
* Copyright (C) 2010 Rene Gollent <rene@gollent.com>
* Copyright 2013-2015 Haiku, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "BrowserWindow.h"
#include <Alert.h>
#include <Application.h>
#include <Bitmap.h>
#include <Button.h>
#include <Catalog.h>
#include <CheckBox.h>
#include <Clipboard.h>
#include <ControlLook.h>
#include <Debug.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <FilePanel.h>
#include <FindDirectory.h>
#include <GridLayoutBuilder.h>
#include <GroupLayout.h>
#include <GroupLayoutBuilder.h>
#include <IconMenuItem.h>
#include <Keymap.h>
#include <LayoutBuilder.h>
#include <Locale.h>
#include <ObjectList.h>
#include <MenuBar.h>
#include <MenuItem.h>
#include <MessageRunner.h>
#include <NodeInfo.h>
#include <NodeMonitor.h>
#include <Path.h>
#include <Roster.h>
#include <Screen.h>
#include <SeparatorView.h>
#include <Size.h>
#include <SpaceLayoutItem.h>
#include <StatusBar.h>
#include <StringView.h>
#include <TextControl.h>
#include <UnicodeChar.h>
#include <Url.h>
#include <map>
#include <stdio.h>
#include "AuthenticationPanel.h"
#include "BaseURL.h"
#include "BitmapButton.h"
#include "BookmarkBar.h"
#include "BrowserApp.h"
#include "BrowsingHistory.h"
#include "CredentialsStorage.h"
#include "IconButton.h"
#include "NavMenu.h"
#include "SettingsKeys.h"
#include "SettingsMessage.h"
#include "TabManager.h"
#include "URLInputGroup.h"
#include "WebPage.h"
#include "WebView.h"
#include "WebViewConstants.h"
#include "WindowIcon.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "WebPositive Window"
enum {
OPEN_LOCATION = 'open',
SAVE_PAGE = 'save',
GO_BACK = 'goba',
GO_FORWARD = 'gofo',
STOP = 'stop',
HOME = 'home',
GOTO_URL = 'goul',
RELOAD = 'reld',
SHOW_HIDE_BOOKMARK_BAR = 'shbb',
CLEAR_HISTORY = 'clhs',
CREATE_BOOKMARK = 'crbm',
SHOW_BOOKMARKS = 'shbm',
ZOOM_FACTOR_INCREASE = 'zfin',
ZOOM_FACTOR_DECREASE = 'zfdc',
ZOOM_FACTOR_RESET = 'zfrs',
ZOOM_TEXT_ONLY = 'zfto',
TOGGLE_FULLSCREEN = 'tgfs',
TOGGLE_AUTO_HIDE_INTERFACE_IN_FULLSCREEN = 'tgah',
CHECK_AUTO_HIDE_INTERFACE = 'cahi',
SHOW_PAGE_SOURCE = 'spgs',
EDIT_SHOW_FIND_GROUP = 'sfnd',
EDIT_HIDE_FIND_GROUP = 'hfnd',
EDIT_FIND_NEXT = 'fndn',
EDIT_FIND_PREVIOUS = 'fndp',
FIND_TEXT_CHANGED = 'ftxt',
SELECT_TAB = 'sltb',
CYCLE_TABS = 'ctab',
};
static const int32 kModifiers = B_SHIFT_KEY | B_COMMAND_KEY
| B_CONTROL_KEY | B_OPTION_KEY | B_MENU_KEY;
static const char* kHandledProtocols[] = {
"http",
"https",
"file",
"about",
"data",
"gopher"
};
static const char* kBookmarkBarSubdir = "Bookmark bar";
static BLayoutItem*
layoutItemFor(BView* view)
{
BLayout* layout = view->Parent()->GetLayout();
int32 index = layout->IndexOfView(view);
return layout->ItemAt(index);
}
class BookmarkMenu : public BNavMenu {
public:
BookmarkMenu(const char* title, BHandler* target, const entry_ref* navDir)
:
BNavMenu(title, B_REFS_RECEIVED, target)
{
_AddStaticItems();
SetNavDir(navDir);
}
virtual void AttachedToWindow()
{
RemoveItems(0, CountItems(), true);
ForceRebuild();
BNavMenu::AttachedToWindow();
if (CountItems() > 0)
AddItem(new BSeparatorItem(), 0);
_AddStaticItems();
DoLayout();
}
private:
void _AddStaticItems()
{
AddItem(new BMenuItem(B_TRANSLATE("Manage bookmarks"),
new BMessage(SHOW_BOOKMARKS), 'M'), 0);
AddItem(new BMenuItem(B_TRANSLATE("Bookmark this page"),
new BMessage(CREATE_BOOKMARK), 'B'), 0);
}
};
class PageUserData : public BWebView::UserData {
public:
PageUserData(BView* focusedView)
:
fFocusedView(focusedView),
fPageIcon(NULL),
fURLInputSelectionStart(-1),
fURLInputSelectionEnd(-1)
{
}
~PageUserData()
{
delete fPageIcon;
}
void SetFocusedView(BView* focusedView)
{
fFocusedView = focusedView;
}
BView* FocusedView() const
{
return fFocusedView;
}
void SetPageIcon(const BBitmap* icon)
{
delete fPageIcon;
if (icon)
fPageIcon = new BBitmap(icon);
else
fPageIcon = NULL;
}
const BBitmap* PageIcon() const
{
return fPageIcon;
}
void SetURLInputContents(const char* text)
{
fURLInputContents = text;
}
const BString& URLInputContents() const
{
return fURLInputContents;
}
void SetURLInputSelection(int32 selectionStart, int32 selectionEnd)
{
fURLInputSelectionStart = selectionStart;
fURLInputSelectionEnd = selectionEnd;
}
int32 URLInputSelectionStart() const
{
return fURLInputSelectionStart;
}
int32 URLInputSelectionEnd() const
{
return fURLInputSelectionEnd;
}
private:
BView* fFocusedView;
BBitmap* fPageIcon;
BString fURLInputContents;
int32 fURLInputSelectionStart;
int32 fURLInputSelectionEnd;
};
class CloseButton : public BButton {
public:
CloseButton(BMessage* message)
:
BButton("close button", NULL, message),
fOverCloseRect(false)
{
SetExplicitMinSize(BSize(15, 15));
SetExplicitMaxSize(BSize(15, 15));
}
virtual void Draw(BRect updateRect)
{
BRect frame = Bounds();
BRect closeRect(frame.InsetByCopy(4, 4));
rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
float tint = B_DARKEN_1_TINT;
if (fOverCloseRect)
tint *= 1.4;
else
tint *= 1.2;
if (Value() == B_CONTROL_ON && fOverCloseRect) {
be_control_look->DrawButtonFrame(this, frame, updateRect,
base, base, BControlLook::B_ACTIVATED
| BControlLook::B_BLEND_FRAME);
be_control_look->DrawButtonBackground(this, frame,
updateRect, base, BControlLook::B_ACTIVATED);
closeRect.OffsetBy(1, 1);
tint *= 1.2;
} else {
SetHighColor(base);
FillRect(updateRect);
}
base = tint_color(base, tint);
SetHighColor(base);
SetPenSize(2);
StrokeLine(closeRect.LeftTop(), closeRect.RightBottom());
StrokeLine(closeRect.LeftBottom(), closeRect.RightTop());
SetPenSize(1);
}
virtual void MouseMoved(BPoint where, uint32 transit,
const BMessage* dragMessage)
{
switch (transit) {
case B_ENTERED_VIEW:
fOverCloseRect = true;
Invalidate();
break;
case B_EXITED_VIEW:
fOverCloseRect = false;
Invalidate();
break;
case B_INSIDE_VIEW:
fOverCloseRect = true;
break;
case B_OUTSIDE_VIEW:
fOverCloseRect = false;
break;
}
BButton::MouseMoved(where, transit, dragMessage);
}
private:
bool fOverCloseRect;
};
BrowserWindow::BrowserWindow(BRect frame, SettingsMessage* appSettings, const BString& url,
BPrivate::Network::BUrlContext* context, uint32 interfaceElements, BWebView* webView,
uint32 workspaces)
:
BWebWindow(frame, kApplicationName, B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
B_AUTO_UPDATE_SIZE_LIMITS | B_ASYNCHRONOUS_CONTROLS, workspaces),
fIsFullscreen(false),
fInterfaceVisible(false),
fMenusRunning(false),
fPulseRunner(NULL),
fVisibleInterfaceElements(interfaceElements),
fContext(context),
fAppSettings(appSettings),
fZoomTextOnly(false),
fShowTabsIfSinglePageOpen(true),
fAutoHideInterfaceInFullscreenMode(false),
fAutoHidePointer(false),
fBookmarkBar(NULL)
{
fAppSettings->AddListener(BMessenger(this));
fZoomTextOnly = fAppSettings->GetValue("zoom text only", fZoomTextOnly);
fShowTabsIfSinglePageOpen = fAppSettings->GetValue(
kSettingsKeyShowTabsIfSinglePageOpen, fShowTabsIfSinglePageOpen);
fAutoHidePointer = fAppSettings->GetValue(kSettingsKeyAutoHidePointer,
fAutoHidePointer);
fNewWindowPolicy = fAppSettings->GetValue(kSettingsKeyNewWindowPolicy,
(uint32)OpenStartPage);
fNewTabPolicy = fAppSettings->GetValue(kSettingsKeyNewTabPolicy,
(uint32)OpenBlankPage);
fStartPageURL = fAppSettings->GetValue(kSettingsKeyStartPageURL,
kDefaultStartPageURL);
fSearchPageURL = fAppSettings->GetValue(kSettingsKeySearchPageURL,
kDefaultSearchPageURL);
BMessage* newTabMessage = new BMessage(NEW_TAB);
newTabMessage->AddString("url", "");
newTabMessage->AddPointer("window", this);
newTabMessage->AddBool("select", true);
fTabManager = new TabManager(BMessenger(this), newTabMessage);
#if INTEGRATE_MENU_INTO_TAB_BAR
BMenu* mainMenu = new BMenu("≡");
#else
BMenu* mainMenu = new BMenuBar("Main menu");
#endif
BMenu* menu = new BMenu(B_TRANSLATE("Window"));
BMessage* newWindowMessage = new BMessage(NEW_WINDOW);
newWindowMessage->AddString("url", "");
BMenuItem* newItem = new BMenuItem(B_TRANSLATE("New window"),
newWindowMessage, 'N');
menu->AddItem(newItem);
newItem->SetTarget(be_app);
newItem = new BMenuItem(B_TRANSLATE("New tab"),
new BMessage(*newTabMessage), 'T');
menu->AddItem(newItem);
newItem->SetTarget(be_app);
menu->AddItem(new BMenuItem(B_TRANSLATE("Open location"),
new BMessage(OPEN_LOCATION), 'L'));
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem(B_TRANSLATE("Close window"),
new BMessage(B_QUIT_REQUESTED), 'W', B_SHIFT_KEY));
menu->AddItem(new BMenuItem(B_TRANSLATE("Close tab"),
new BMessage(CLOSE_TAB), 'W'));
menu->AddItem(new BMenuItem(B_TRANSLATE("Save page as" B_UTF8_ELLIPSIS),
new BMessage(SAVE_PAGE), 'S'));
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem(B_TRANSLATE("Downloads"),
new BMessage(SHOW_DOWNLOAD_WINDOW), 'D'));
menu->AddItem(new BMenuItem(B_TRANSLATE("Settings"),
new BMessage(SHOW_SETTINGS_WINDOW), ','));
menu->AddItem(new BMenuItem(B_TRANSLATE("Cookie manager"),
new BMessage(SHOW_COOKIE_WINDOW)));
menu->AddItem(new BMenuItem(B_TRANSLATE("Script console"),
new BMessage(SHOW_CONSOLE_WINDOW)));
BMenuItem* aboutItem = new BMenuItem(B_TRANSLATE("About"),
new BMessage(B_ABOUT_REQUESTED));
menu->AddItem(aboutItem);
aboutItem->SetTarget(be_app);
menu->AddSeparatorItem();
BMenuItem* quitItem = new BMenuItem(B_TRANSLATE("Quit"),
new BMessage(B_QUIT_REQUESTED), 'Q');
menu->AddItem(quitItem);
quitItem->SetTarget(be_app);
mainMenu->AddItem(menu);
menu = new BMenu(B_TRANSLATE("Edit"));
menu->AddItem(fCutMenuItem = new BMenuItem(B_TRANSLATE("Cut"),
new BMessage(B_CUT), 'X'));
menu->AddItem(fCopyMenuItem = new BMenuItem(B_TRANSLATE("Copy"),
new BMessage(B_COPY), 'C'));
menu->AddItem(fPasteMenuItem = new BMenuItem(B_TRANSLATE("Paste"),
new BMessage(B_PASTE), 'V'));
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem(B_TRANSLATE("Find"),
new BMessage(EDIT_SHOW_FIND_GROUP), 'F'));
menu->AddItem(fFindPreviousMenuItem
= new BMenuItem(B_TRANSLATE("Find previous"),
new BMessage(EDIT_FIND_PREVIOUS), 'G', B_SHIFT_KEY));
menu->AddItem(fFindNextMenuItem = new BMenuItem(B_TRANSLATE("Find next"),
new BMessage(EDIT_FIND_NEXT), 'G'));
mainMenu->AddItem(menu);
fFindPreviousMenuItem->SetEnabled(false);
fFindNextMenuItem->SetEnabled(false);
menu = new BMenu(B_TRANSLATE("View"));
menu->AddItem(new BMenuItem(B_TRANSLATE("Reload"), new BMessage(RELOAD),
'R'));
fBookmarkBarMenuItem = new BMenuItem(B_TRANSLATE("Show bookmark bar"),
new BMessage(SHOW_HIDE_BOOKMARK_BAR));
menu->AddItem(fBookmarkBarMenuItem);
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem(B_TRANSLATE("Increase size"),
new BMessage(ZOOM_FACTOR_INCREASE), '+'));
menu->AddItem(new BMenuItem(B_TRANSLATE("Decrease size"),
new BMessage(ZOOM_FACTOR_DECREASE), '-'));
menu->AddItem(new BMenuItem(B_TRANSLATE("Reset size"),
new BMessage(ZOOM_FACTOR_RESET), '0'));
fZoomTextOnlyMenuItem = new BMenuItem(B_TRANSLATE("Zoom text only"),
new BMessage(ZOOM_TEXT_ONLY));
fZoomTextOnlyMenuItem->SetMarked(fZoomTextOnly);
menu->AddItem(fZoomTextOnlyMenuItem);
menu->AddSeparatorItem();
fFullscreenItem = new BMenuItem(B_TRANSLATE("Full screen"),
new BMessage(TOGGLE_FULLSCREEN), B_RETURN);
menu->AddItem(fFullscreenItem);
menu->AddItem(new BMenuItem(B_TRANSLATE("Page source"),
new BMessage(SHOW_PAGE_SOURCE), 'U'));
mainMenu->AddItem(menu);
fHistoryMenu = new BMenu(B_TRANSLATE("History"));
fHistoryMenu->AddItem(fBackMenuItem = new BMenuItem(B_TRANSLATE("Back"),
new BMessage(GO_BACK), B_LEFT_ARROW));
fHistoryMenu->AddItem(fForwardMenuItem
= new BMenuItem(B_TRANSLATE("Forward"), new BMessage(GO_FORWARD),
B_RIGHT_ARROW));
fHistoryMenu->AddSeparatorItem();
fHistoryMenuFixedItemCount = fHistoryMenu->CountItems();
mainMenu->AddItem(fHistoryMenu);
BPath bookmarkPath;
entry_ref bookmarkRef;
if (_BookmarkPath(bookmarkPath) == B_OK
&& get_ref_for_path(bookmarkPath.Path(), &bookmarkRef) == B_OK) {
BMenu* bookmarkMenu
= new BookmarkMenu(B_TRANSLATE("Bookmarks"), this, &bookmarkRef);
mainMenu->AddItem(bookmarkMenu);
BDirectory barDir(&bookmarkRef);
BEntry bookmarkBar(&barDir, kBookmarkBarSubdir);
entry_ref bookmarkBarRef;
if (bookmarkBar.Exists() && bookmarkBar.GetRef(&bookmarkBarRef)
== B_OK) {
fBookmarkBar = new BookmarkBar("Bookmarks", this, &bookmarkBarRef);
fBookmarkBarMenuItem->SetEnabled(true);
} else
fBookmarkBarMenuItem->SetEnabled(false);
} else
fBookmarkBarMenuItem->SetEnabled(false);
fBackButton = new BIconButton("Back", NULL, new BMessage(GO_BACK));
fBackButton->SetIcon(201);
fBackButton->TrimIcon();
fForwardButton = new BIconButton("Forward", NULL, new BMessage(GO_FORWARD));
fForwardButton->SetIcon(202);
fForwardButton->TrimIcon();
fStopButton = new BIconButton("Stop", NULL, new BMessage(STOP));
fStopButton->SetIcon(204);
fStopButton->TrimIcon();
fHomeButton = new BIconButton("Home", NULL, new BMessage(HOME));
fHomeButton->SetIcon(206);
fHomeButton->TrimIcon();
if (!fAppSettings->GetValue(kSettingsKeyShowHomeButton, true))
fHomeButton->Hide();
fURLInputGroup = new URLInputGroup(new BMessage(GOTO_URL));
fStatusText = new BStringView("status", "");
fStatusText->SetAlignment(B_ALIGN_LEFT);
fStatusText->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
fStatusText->SetExplicitMinSize(BSize(150, 12));
BFont font(be_plain_font);
font.SetSize(ceilf(font.Size() * 0.8));
fStatusText->SetFont(&font, B_FONT_SIZE);
fLoadingProgressBar = new BStatusBar("progress");
fLoadingProgressBar->SetMaxValue(100);
fLoadingProgressBar->Hide();
font_height height;
font.GetHeight(&height);
fLoadingProgressBar->SetBarHeight(height.ascent + height.descent);
const float kInsetSpacing = 3;
const float kElementSpacing = 5;
fFindCloseButton = new CloseButton(new BMessage(EDIT_HIDE_FIND_GROUP));
fFindTextControl = new BTextControl("find", B_TRANSLATE("Find:"), "", NULL);
fFindTextControl->SetModificationMessage(new BMessage(FIND_TEXT_CHANGED));
fFindPreviousButton = new BButton(B_TRANSLATE("Previous"),
new BMessage(EDIT_FIND_PREVIOUS));
fFindPreviousButton->SetToolTip(
B_TRANSLATE_COMMENT("Find previous occurrence of search terms",
"find bar previous button tooltip"));
fFindNextButton = new BButton(B_TRANSLATE("Next"),
new BMessage(EDIT_FIND_NEXT));
fFindNextButton->SetToolTip(
B_TRANSLATE_COMMENT("Find next occurrence of search terms",
"find bar next button tooltip"));
fFindCaseSensitiveCheckBox = new BCheckBox(B_TRANSLATE("Match case"));
BGroupLayout* findGroup = BLayoutBuilder::Group<>(B_VERTICAL, 0.0)
.Add(new BSeparatorView(B_HORIZONTAL, B_PLAIN_BORDER))
.Add(BGroupLayoutBuilder(B_HORIZONTAL, B_USE_SMALL_SPACING)
.Add(fFindCloseButton)
.Add(fFindTextControl)
.Add(fFindPreviousButton)
.Add(fFindNextButton)
.Add(fFindCaseSensitiveCheckBox)
.SetInsets(kInsetSpacing, kInsetSpacing,
kInsetSpacing, kInsetSpacing)
)
;
BGroupLayout* navigationGroup = BLayoutBuilder::Group<>(B_VERTICAL, 0.0)
.Add(BLayoutBuilder::Group<>(B_HORIZONTAL, kElementSpacing)
.Add(fBackButton)
.Add(fForwardButton)
.Add(fStopButton)
.Add(fHomeButton)
.Add(fURLInputGroup)
.SetInsets(kInsetSpacing, kInsetSpacing, kInsetSpacing,
kInsetSpacing)
)
.Add(new BSeparatorView(B_HORIZONTAL, B_PLAIN_BORDER))
;
BGroupLayout* statusGroup = BLayoutBuilder::Group<>(B_VERTICAL, 0.0)
.Add(new BSeparatorView(B_HORIZONTAL, B_PLAIN_BORDER))
.Add(BLayoutBuilder::Group<>(B_HORIZONTAL, kElementSpacing)
.Add(fStatusText)
.Add(fLoadingProgressBar, 0.2)
.AddStrut(12 - kElementSpacing)
.SetInsets(kInsetSpacing, 0, kInsetSpacing, 0)
)
;
BBitmapButton* toggleFullscreenButton = new BBitmapButton(kWindowIconBits,
kWindowIconWidth, kWindowIconHeight, kWindowIconFormat,
new BMessage(TOGGLE_FULLSCREEN));
toggleFullscreenButton->SetBackgroundMode(BBitmapButton::MENUBAR_BACKGROUND);
#if !INTEGRATE_MENU_INTO_TAB_BAR
BMenu* mainMenuItem = mainMenu;
fMenuGroup = (new BGroupView(B_HORIZONTAL, 0))->GroupLayout();
#else
BMenu* mainMenuItem = new BMenuBar("Main menu");
mainMenuItem->AddItem(mainMenu);
fMenuGroup = fTabManager->MenuContainerLayout();
#endif
BLayoutBuilder::Group<>(fMenuGroup)
.Add(mainMenuItem)
.Add(toggleFullscreenButton, 0.0f)
;
if (fAppSettings->GetValue(kSettingsShowBookmarkBar, true))
_ShowBookmarkBar(true);
else
_ShowBookmarkBar(false);
fSavePanel = new BFilePanel(B_SAVE_PANEL, new BMessenger(this), NULL, 0,
false);
BGroupView* topView = new BGroupView(B_VERTICAL, 0.0);
#if !INTEGRATE_MENU_INTO_TAB_BAR
topView->AddChild(fMenuGroup);
#endif
topView->AddChild(fTabManager->TabGroup());
topView->AddChild(navigationGroup);
if (fBookmarkBar != NULL)
topView->AddChild(fBookmarkBar);
topView->AddChild(fTabManager->ContainerView());
topView->AddChild(findGroup);
topView->AddChild(statusGroup);
AddChild(topView);
fURLInputGroup->MakeFocus(true);
fTabGroup = fTabManager->TabGroup()->GetLayout();
fNavigationGroup = navigationGroup;
fFindGroup = findGroup;
fStatusGroup = statusGroup;
fToggleFullscreenButton = layoutItemFor(toggleFullscreenButton);
fFindGroup->SetVisible(false);
fToggleFullscreenButton->SetVisible(false);
CreateNewTab(url, true, webView);
_ShowInterface(true);
_SetAutoHideInterfaceInFullscreen(fAppSettings->GetValue(
kSettingsKeyAutoHideInterfaceInFullscreenMode,
fAutoHideInterfaceInFullscreenMode));
AddShortcut('F', B_COMMAND_KEY | B_SHIFT_KEY,
new BMessage(EDIT_HIDE_FIND_GROUP));
AddShortcut('H', B_COMMAND_KEY, new BMessage(HOME));
for (int32 i = 1; i <= 9; i++) {
BMessage* selectTab = new BMessage(SELECT_TAB);
selectTab->AddInt32("tab index", i - 1);
char numStr[2];
snprintf(numStr, sizeof(numStr), "%d", (int) i);
AddShortcut(numStr[0], B_COMMAND_KEY, selectTab);
}
AddShortcut(B_TAB, B_COMMAND_KEY, new BMessage(CYCLE_TABS));
BKeymap keymap;
keymap.SetToCurrent();
BStringList unmodified(3);
if (keymap.GetModifiedCharacters("+", B_SHIFT_KEY, 0, unmodified)
== B_OK) {
int32 count = unmodified.CountStrings();
for (int32 i = 0; i < count; i++) {
uint32 key = BUnicodeChar::FromUTF8(unmodified.StringAt(i));
if (!HasShortcut(key, 0)) {
AddShortcut(key, B_COMMAND_KEY,
new BMessage(ZOOM_FACTOR_INCREASE));
}
}
}
unmodified.MakeEmpty();
be_app->PostMessage(WINDOW_OPENED);
}
BrowserWindow::~BrowserWindow()
{
fAppSettings->RemoveListener(BMessenger(this));
delete fTabManager;
delete fPulseRunner;
delete fSavePanel;
}
void
BrowserWindow::DispatchMessage(BMessage* message, BHandler* target)
{
const char* bytes;
int32 modifierKeys;
if ((message->what == B_KEY_DOWN || message->what == B_UNMAPPED_KEY_DOWN)
&& message->FindString("bytes", &bytes) == B_OK
&& message->FindInt32("modifiers", &modifierKeys) == B_OK) {
if (bytes[0] == B_FUNCTION_KEY) {
int32 key;
if (message->FindInt32("key", &key) == B_OK) {
switch (key) {
case B_F5_KEY:
PostMessage(RELOAD);
break;
case B_F11_KEY:
PostMessage(TOGGLE_FULLSCREEN);
break;
default:
break;
}
}
} else if (target == fURLInputGroup->TextView()) {
if (bytes[0] == B_RETURN) {
_InvokeButtonVisibly(fURLInputGroup->GoButton());
return;
} else if (bytes[0] == B_ESCAPE) {
fURLInputGroup->LockURLInput(false);
fURLInputGroup->SetText(CurrentWebView()->MainFrameURL());
}
} else if (target == fFindTextControl->TextView()) {
if (bytes[0] == B_RETURN) {
if ((modifierKeys & B_SHIFT_KEY) != 0)
_InvokeButtonVisibly(fFindPreviousButton);
else
_InvokeButtonVisibly(fFindNextButton);
return;
} else if (bytes[0] == B_ESCAPE) {
_InvokeButtonVisibly(fFindCloseButton);
return;
}
} else if (bytes[0] == B_ESCAPE && !fMenusRunning) {
if (modifierKeys == B_COMMAND_KEY)
_ShowInterface(true);
else {
PostMessage(STOP);
return;
}
}
}
if (message->what == B_MOUSE_MOVED || message->what == B_MOUSE_DOWN
|| message->what == B_MOUSE_UP) {
message->FindPoint("where", &fLastMousePos);
if (message->FindInt64("when", &fLastMouseMovedTime) != B_OK)
fLastMouseMovedTime = system_time();
_CheckAutoHideInterface();
}
if (message->what == B_MOUSE_WHEEL_CHANGED) {
BPoint where;
uint32 buttons;
CurrentWebView()->GetMouse(&where, &buttons, false);
if (CurrentWebView()->Bounds().Contains(where)) {
if ((modifiers() & B_COMMAND_KEY) != 0) {
float deltaY;
if (message->FindFloat("be:wheel_delta_y", &deltaY) == B_OK) {
if (deltaY < 0)
CurrentWebView()->IncreaseZoomFactor(fZoomTextOnly);
else
CurrentWebView()->DecreaseZoomFactor(fZoomTextOnly);
return;
}
}
} else {
return;
}
}
BWebWindow::DispatchMessage(message, target);
}
void
BrowserWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case OPEN_LOCATION:
_ShowInterface(true);
if (fURLInputGroup->TextView()->IsFocus())
fURLInputGroup->TextView()->SelectAll();
else
fURLInputGroup->MakeFocus(true);
break;
case RELOAD:
CurrentWebView()->Reload();
break;
case SHOW_HIDE_BOOKMARK_BAR:
_ShowBookmarkBar(fBookmarkBar->IsHidden());
break;
case GOTO_URL:
{
BString url;
if (message->FindString("url", &url) != B_OK)
url = fURLInputGroup->Text();
_SetPageIcon(CurrentWebView(), NULL);
_SmartURLHandler(url);
break;
}
case SAVE_PAGE:
{
fSavePanel->SetSaveText(CurrentWebView()->MainFrameTitle());
fSavePanel->Show();
break;
}
case B_SAVE_REQUESTED:
{
entry_ref ref;
BString name;
if (message->FindRef("directory", &ref) == B_OK
&& message->FindString("name", &name) == B_OK) {
BDirectory dir(&ref);
BFile output(&dir, name,
B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
CurrentWebView()->WebPage()->GetContentsAsMHTML(output);
}
break;
}
case GO_BACK:
CurrentWebView()->GoBack();
break;
case GO_FORWARD:
CurrentWebView()->GoForward();
break;
case STOP:
CurrentWebView()->StopLoading();
break;
case HOME:
CurrentWebView()->LoadURL(fStartPageURL);
break;
case CLEAR_HISTORY: {
BrowsingHistory* history = BrowsingHistory::DefaultInstance();
if (history->CountItems() == 0)
break;
BAlert* alert = new BAlert(B_TRANSLATE("Confirmation"),
B_TRANSLATE("Do you really want to "
"clear the browsing history?"), B_TRANSLATE("Clear"),
B_TRANSLATE("Cancel"));
alert->SetShortcut(1, B_ESCAPE);
if (alert->Go() == 0)
history->Clear();
break;
}
case CREATE_BOOKMARK:
_CreateBookmark();
break;
case SHOW_BOOKMARKS:
_ShowBookmarks();
break;
case B_REFS_RECEIVED:
{
entry_ref ref;
uint32 addedCount = 0;
for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) {
BEntry entry(&ref);
uint32 addedSubCount = 0;
if (entry.IsDirectory()) {
BDirectory directory(&entry);
_AddBookmarkURLsRecursively(directory, message,
addedSubCount);
} else {
BFile file(&ref, B_READ_ONLY);
BString url;
if (_ReadURLAttr(file, url)) {
message->AddString("url", url.String());
addedSubCount++;
}
}
if (addedSubCount == 0) {
be_roster->Launch(&ref);
}
addedCount += addedSubCount;
}
message->RemoveName("refs");
if (addedCount > 10) {
BString string(B_TRANSLATE_COMMENT("Do you want to open "
"%addedCount bookmarks all at once?", "Don't translate "
"variable %addedCount."));
string.ReplaceFirst("%addedCount", BString() << addedCount);
BAlert* alert = new BAlert(
B_TRANSLATE("Open bookmarks confirmation"),
string.String(), B_TRANSLATE("Cancel"),
B_TRANSLATE("Open all"));
alert->SetShortcut(0, B_ESCAPE);
if (alert->Go() == 0)
break;
}
message->AddPointer("window", this);
be_app->PostMessage(message);
break;
}
case B_SIMPLE_DATA:
{
const char* filetype = message->GetString("be:filetypes");
if (filetype != NULL
&& strcmp(filetype, "application/x-vnd.Be-bookmark") == 0
&& LastMouseMovedView() == fBookmarkBar) {
BPath path;
if (_BookmarkPath(path) == B_OK && path.Append(kBookmarkBarSubdir) == B_OK) {
entry_ref ref;
if (BEntry(path.Path()).GetRef(&ref) == B_OK) {
message->AddRef("directory", &ref);
_CreateBookmark(message);
}
}
break;
}
type_code type;
int32 countFound;
if (message->GetInfo("refs", &type, &countFound) != B_OK
|| type != B_REF_TYPE) {
break;
}
if (countFound > 1) {
message->what = B_REFS_RECEIVED;
be_app->PostMessage(message);
break;
}
entry_ref ref;
if (message->FindRef("refs", &ref) != B_OK)
break;
BEntry entry(&ref, true);
BPath path;
if (!entry.Exists() || entry.GetPath(&path) != B_OK)
break;
BUrl url(path);
CurrentWebView()->LoadURL(url);
break;
}
case ZOOM_FACTOR_INCREASE:
CurrentWebView()->IncreaseZoomFactor(fZoomTextOnly);
break;
case ZOOM_FACTOR_DECREASE:
CurrentWebView()->DecreaseZoomFactor(fZoomTextOnly);
break;
case ZOOM_FACTOR_RESET:
CurrentWebView()->ResetZoomFactor();
break;
case ZOOM_TEXT_ONLY:
fZoomTextOnly = !fZoomTextOnly;
fZoomTextOnlyMenuItem->SetMarked(fZoomTextOnly);
break;
case TOGGLE_FULLSCREEN:
ToggleFullscreen();
break;
case TOGGLE_AUTO_HIDE_INTERFACE_IN_FULLSCREEN:
_SetAutoHideInterfaceInFullscreen(
!fAutoHideInterfaceInFullscreenMode);
break;
case CHECK_AUTO_HIDE_INTERFACE:
_CheckAutoHideInterface();
break;
case SHOW_PAGE_SOURCE:
CurrentWebView()->WebPage()->SendPageSource();
break;
case B_PAGE_SOURCE_RESULT:
_HandlePageSourceResult(message);
break;
case EDIT_FIND_NEXT:
CurrentWebView()->FindString(fFindTextControl->Text(), true,
fFindCaseSensitiveCheckBox->Value());
break;
case FIND_TEXT_CHANGED:
{
bool findTextAvailable = strlen(fFindTextControl->Text()) > 0;
fFindPreviousMenuItem->SetEnabled(findTextAvailable);
fFindNextMenuItem->SetEnabled(findTextAvailable);
break;
}
case EDIT_FIND_PREVIOUS:
CurrentWebView()->FindString(fFindTextControl->Text(), false,
fFindCaseSensitiveCheckBox->Value());
break;
case EDIT_SHOW_FIND_GROUP:
if (!fFindGroup->IsVisible())
fFindGroup->SetVisible(true);
fFindTextControl->MakeFocus(true);
break;
case EDIT_HIDE_FIND_GROUP:
if (fFindGroup->IsVisible()) {
fFindGroup->SetVisible(false);
if (CurrentWebView() != NULL)
CurrentWebView()->MakeFocus(true);
}
break;
case B_CUT:
case B_COPY:
case B_PASTE:
{
BTextView* textView = dynamic_cast<BTextView*>(CurrentFocus());
if (textView != NULL)
textView->MessageReceived(message);
else if (CurrentWebView() != NULL)
CurrentWebView()->MessageReceived(message);
break;
}
case B_EDITING_CAPABILITIES_RESULT:
{
BWebView* webView;
if (message->FindPointer("view",
reinterpret_cast<void**>(&webView)) != B_OK
|| webView != CurrentWebView()) {
break;
}
bool canCut;
bool canCopy;
bool canPaste;
if (message->FindBool("can cut", &canCut) != B_OK)
canCut = false;
if (message->FindBool("can copy", &canCopy) != B_OK)
canCopy = false;
if (message->FindBool("can paste", &canPaste) != B_OK)
canPaste = false;
fCutMenuItem->SetEnabled(canCut);
fCopyMenuItem->SetEnabled(canCopy);
fPasteMenuItem->SetEnabled(canPaste);
break;
}
case SHOW_DOWNLOAD_WINDOW:
case SHOW_SETTINGS_WINDOW:
case SHOW_CONSOLE_WINDOW:
case SHOW_COOKIE_WINDOW:
message->AddUInt32("workspaces", Workspaces());
be_app->PostMessage(message);
break;
case CLOSE_TAB:
if (fTabManager->CountTabs() > 1) {
int32 index;
if (message->FindInt32("tab index", &index) != B_OK)
index = fTabManager->SelectedTabIndex();
_ShutdownTab(index);
_UpdateTabGroupVisibility();
} else
PostMessage(B_QUIT_REQUESTED);
break;
case SELECT_TAB:
{
int32 index;
if (message->FindInt32("tab index", &index) == B_OK
&& fTabManager->SelectedTabIndex() != index
&& fTabManager->CountTabs() > index) {
fTabManager->SelectTab(index);
}
break;
}
case CYCLE_TABS:
{
int32 index = fTabManager->SelectedTabIndex() + 1;
if (index >= fTabManager->CountTabs())
index = 0;
fTabManager->SelectTab(index);
break;
}
case TAB_CHANGED:
{
int32 index;
if (message->FindInt32("tab index", &index) != B_OK)
index = -1;
_TabChanged(index);
break;
}
case SETTINGS_VALUE_CHANGED:
{
BString name;
if (message->FindString("name", &name) != B_OK)
break;
bool flag;
BString string;
uint32 value;
if (name == kSettingsKeyShowTabsIfSinglePageOpen
&& message->FindBool("value", &flag) == B_OK) {
if (fShowTabsIfSinglePageOpen != flag) {
fShowTabsIfSinglePageOpen = flag;
_UpdateTabGroupVisibility();
}
} else if (name == kSettingsKeyAutoHidePointer
&& message->FindBool("value", &flag) == B_OK) {
fAutoHidePointer = flag;
if (CurrentWebView())
CurrentWebView()->SetAutoHidePointer(fAutoHidePointer);
} else if (name == kSettingsKeyStartPageURL
&& message->FindString("value", &string) == B_OK) {
fStartPageURL = string;
} else if (name == kSettingsKeySearchPageURL
&& message->FindString("value", &string) == B_OK) {
fSearchPageURL = string;
} else if (name == kSettingsKeyNewWindowPolicy
&& message->FindUInt32("value", &value) == B_OK) {
fNewWindowPolicy = value;
} else if (name == kSettingsKeyNewTabPolicy
&& message->FindUInt32("value", &value) == B_OK) {
fNewTabPolicy = value;
} else if (name == kSettingsKeyAutoHideInterfaceInFullscreenMode
&& message->FindBool("value", &flag) == B_OK) {
_SetAutoHideInterfaceInFullscreen(flag);
} else if (name == kSettingsKeyShowHomeButton
&& message->FindBool("value", &flag) == B_OK) {
if (flag)
fHomeButton->Show();
else
fHomeButton->Hide();
} else if (name == kSettingsShowBookmarkBar
&& message->FindBool("value", &flag) == B_OK) {
_ShowBookmarkBar(flag);
}
break;
}
case ADD_CONSOLE_MESSAGE:
be_app->PostMessage(message);
BWebWindow::MessageReceived(message);
break;
case B_COPY_TARGET:
{
const char* filetype = message->GetString("be:filetypes");
if (filetype != NULL && strcmp(filetype, "application/x-vnd.Be-bookmark") == 0) {
_CreateBookmark(message);
break;
} else {
BWebWindow::MessageReceived(message);
break;
}
}
default:
BWebWindow::MessageReceived(message);
break;
}
}
status_t
BrowserWindow::Archive(BMessage* archive, bool deep) const
{
status_t status = archive->AddRect("window frame", Frame());
if (status == B_OK)
status = archive->AddUInt32("window workspaces", Workspaces());
for (int i = 0; i < fTabManager->CountTabs(); i++) {
BWebView* view = dynamic_cast<BWebView*>(fTabManager->ViewForTab(i));
if (view == NULL) {
continue;
}
if (status == B_OK)
status = archive->AddString("tab", view->MainFrameURL());
}
return status;
}
bool
BrowserWindow::QuitRequested()
{
BMessage message(WINDOW_CLOSED);
Archive(&message);
SetCurrentWebView(NULL);
while (fTabManager->CountTabs() > 0)
_ShutdownTab(0);
message.AddRect("window frame", WindowFrame());
be_app->PostMessage(&message);
return true;
}
void
BrowserWindow::MenusBeginning()
{
_UpdateHistoryMenu();
_UpdateClipboardItems();
fMenusRunning = true;
}
void
BrowserWindow::MenusEnded()
{
fMenusRunning = false;
}
void
BrowserWindow::ScreenChanged(BRect screenSize, color_space format)
{
if (fIsFullscreen)
_ResizeToScreen();
}
void
BrowserWindow::WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces)
{
if (fIsFullscreen)
_ResizeToScreen();
}
static bool
viewIsChild(const BView* parent, const BView* view)
{
if (parent == view)
return true;
int32 count = parent->CountChildren();
for (int32 i = 0; i < count; i++) {
BView* child = parent->ChildAt(i);
if (viewIsChild(child, view))
return true;
}
return false;
}
void
BrowserWindow::SetCurrentWebView(BWebView* webView)
{
if (webView == CurrentWebView())
return;
if (CurrentWebView() != NULL) {
PageUserData* userData = static_cast<PageUserData*>(
CurrentWebView()->GetUserData());
if (userData == NULL) {
userData = new PageUserData(CurrentFocus());
CurrentWebView()->SetUserData(userData);
}
userData->SetFocusedView(CurrentFocus());
userData->SetURLInputContents(fURLInputGroup->Text());
int32 selectionStart;
int32 selectionEnd;
fURLInputGroup->TextView()->GetSelection(&selectionStart,
&selectionEnd);
userData->SetURLInputSelection(selectionStart, selectionEnd);
}
BWebWindow::SetCurrentWebView(webView);
if (webView != NULL) {
webView->SetAutoHidePointer(fAutoHidePointer);
_UpdateTitle(webView->MainFrameTitle());
PageUserData* userData = static_cast<PageUserData*>(
webView->GetUserData());
BView* focusedView = NULL;
if (userData != NULL)
focusedView = userData->FocusedView();
if (focusedView != NULL
&& viewIsChild(GetLayout()->View(), focusedView)) {
focusedView->MakeFocus(true);
} else
webView->MakeFocus(true);
bool state = fURLInputGroup->IsURLInputLocked();
fURLInputGroup->LockURLInput(false);
if (userData != NULL) {
fURLInputGroup->SetPageIcon(userData->PageIcon());
if (userData->URLInputContents().Length())
fURLInputGroup->SetText(userData->URLInputContents());
else
fURLInputGroup->SetText(webView->MainFrameURL());
if (userData->URLInputSelectionStart() >= 0) {
fURLInputGroup->TextView()->Select(
userData->URLInputSelectionStart(),
userData->URLInputSelectionEnd());
}
} else {
fURLInputGroup->SetPageIcon(NULL);
fURLInputGroup->SetText(webView->MainFrameURL());
}
fURLInputGroup->LockURLInput(state);
webView->WebPage()->ResendNotifications();
} else
_UpdateTitle("");
}
bool
BrowserWindow::IsBlankTab() const
{
if (CurrentWebView() == NULL)
return false;
BString requestedURL = CurrentWebView()->MainFrameRequestedURL();
return requestedURL.Length() == 0
|| requestedURL == _NewTabURL(fTabManager->CountTabs() == 1);
}
void
BrowserWindow::CreateNewTab(const BString& _url, bool select,
BWebView* webView)
{
bool applyNewPagePolicy = webView == NULL;
if (webView == NULL)
webView = new BWebView("web view", fContext);
bool isNewWindow = fTabManager->CountTabs() == 0;
fTabManager->AddTab(webView, B_TRANSLATE("New tab"));
BString url(_url);
if (applyNewPagePolicy && url.Length() == 0)
url = _NewTabURL(isNewWindow);
if (url.Length() > 0)
webView->LoadURL(url.String());
if (select) {
fTabManager->SelectTab(fTabManager->CountTabs() - 1);
SetCurrentWebView(webView);
webView->WebPage()->ResendNotifications();
fURLInputGroup->SetPageIcon(NULL);
fURLInputGroup->SetText(url.String());
fURLInputGroup->MakeFocus(true);
}
_ShowInterface(true);
_UpdateTabGroupVisibility();
}
BRect
BrowserWindow::WindowFrame() const
{
if (fIsFullscreen)
return fNonFullscreenWindowFrame;
else
return Frame();
}
void
BrowserWindow::ToggleFullscreen()
{
if (fIsFullscreen) {
MoveTo(fNonFullscreenWindowFrame.LeftTop());
ResizeTo(fNonFullscreenWindowFrame.Width(),
fNonFullscreenWindowFrame.Height());
SetFlags(Flags() & ~(B_NOT_RESIZABLE | B_NOT_MOVABLE));
SetLook(B_DOCUMENT_WINDOW_LOOK);
_ShowInterface(true);
} else {
fNonFullscreenWindowFrame = Frame();
_ResizeToScreen();
SetFlags(Flags() | (B_NOT_RESIZABLE | B_NOT_MOVABLE));
SetLook(B_TITLED_WINDOW_LOOK);
}
fIsFullscreen = !fIsFullscreen;
fFullscreenItem->SetMarked(fIsFullscreen);
fToggleFullscreenButton->SetVisible(fIsFullscreen);
}
void
BrowserWindow::NavigationRequested(const BString& url, BWebView* view)
{
}
void
BrowserWindow::NewWindowRequested(const BString& url, bool primaryAction)
{
BMessage message(NEW_TAB);
message.AddPointer("window", this);
message.AddString("url", url);
message.AddBool("select", primaryAction);
be_app->PostMessage(&message);
}
void
BrowserWindow::NewPageCreated(BWebView* view, BRect windowFrame,
bool modalDialog, bool resizable, bool activate)
{
if (windowFrame.IsValid()) {
BrowserWindow* window = new BrowserWindow(windowFrame, fAppSettings,
BString(), fContext, INTERFACE_ELEMENT_STATUS,
view);
window->Show();
} else
CreateNewTab(BString(), activate, view);
}
void
BrowserWindow::CloseWindowRequested(BWebView* view)
{
int32 index = fTabManager->TabForView(view);
if (index < 0) {
return;
}
BMessage message(CLOSE_TAB);
message.AddInt32("tab index", index);
PostMessage(&message, this);
}
void
BrowserWindow::LoadNegotiating(const BString& url, BWebView* view)
{
if (view != CurrentWebView()) {
PageUserData* userData = static_cast<PageUserData*>(
view->GetUserData());
if (userData != NULL && userData->URLInputContents().Length() == 0) {
userData->SetURLInputContents(url);
}
}
fURLInputGroup->SetText(url.String());
BString status(B_TRANSLATE("Requesting %url"));
status.ReplaceFirst("%url", url);
view->WebPage()->SetStatusMessage(status);
}
void
BrowserWindow::LoadCommitted(const BString& url, BWebView* view)
{
if (view != CurrentWebView())
return;
fURLInputGroup->SetText(url.String());
BString status(B_TRANSLATE("Loading %url"));
status.ReplaceFirst("%url", url);
view->WebPage()->SetStatusMessage(status);
}
void
BrowserWindow::LoadProgress(float progress, BWebView* view)
{
if (view != CurrentWebView())
return;
if (progress < 100 && fLoadingProgressBar->IsHidden())
_ShowProgressBar(true);
else if (progress == 100 && !fLoadingProgressBar->IsHidden())
_ShowProgressBar(false);
fLoadingProgressBar->SetTo(progress);
}
void
BrowserWindow::LoadFailed(const BString& url, BWebView* view)
{
if (view != CurrentWebView())
return;
BString status(B_TRANSLATE_COMMENT("%url failed", "Loading URL failed. "
"Don't translate variable %url."));
status.ReplaceFirst("%url", url);
view->WebPage()->SetStatusMessage(status);
if (!fLoadingProgressBar->IsHidden())
fLoadingProgressBar->Hide();
}
void
BrowserWindow::LoadFinished(const BString& url, BWebView* view)
{
if (view != CurrentWebView())
return;
fURLInputGroup->SetText(url.String());
BString status(B_TRANSLATE_COMMENT("%url finished", "Loading URL "
"finished. Don't translate variable %url."));
status.ReplaceFirst("%url", url);
view->WebPage()->SetStatusMessage(status);
if (!fLoadingProgressBar->IsHidden())
fLoadingProgressBar->Hide();
NavigationCapabilitiesChanged(fBackButton->IsEnabled(),
fForwardButton->IsEnabled(), false, view);
int32 tabIndex = fTabManager->TabForView(view);
if (tabIndex > 0 && strcmp(B_TRANSLATE("New tab"),
fTabManager->TabLabel(tabIndex)) == 0)
fTabManager->SetTabLabel(tabIndex, url);
}
void
BrowserWindow::MainDocumentError(const BString& failingURL,
const BString& localizedDescription, BWebView* view)
{
if (!_ShowPage(view))
return;
int32 at = failingURL.FindFirst(":");
if (at > 0) {
BString proto;
failingURL.CopyInto(proto, 0, at);
bool handled = false;
for (unsigned int i = 0; i < sizeof(kHandledProtocols) / sizeof(char*);
i++) {
handled = (proto == kHandledProtocols[i]);
if (handled)
break;
}
if (!handled) {
_SmartURLHandler(failingURL);
return;
}
}
BWebWindow::MainDocumentError(failingURL, localizedDescription, view);
}
void
BrowserWindow::TitleChanged(const BString& title, BWebView* view)
{
int32 tabIndex = fTabManager->TabForView(view);
if (tabIndex < 0)
return;
fTabManager->SetTabLabel(tabIndex, title);
if (view != CurrentWebView())
return;
_UpdateTitle(title);
}
void
BrowserWindow::IconReceived(const BBitmap* icon, BWebView* view)
{
if (!fTabManager->HasView(view))
return;
_SetPageIcon(view, icon);
}
void
BrowserWindow::ResizeRequested(float width, float height, BWebView* view)
{
if (view != CurrentWebView())
return;
if (fTabManager->CountTabs() > 1)
return;
BScreen screen(this);
BRect screenFrame = screen.Frame();
BRect decoratorFrame = DecoratorFrame();
BRect frame = Frame();
screenFrame.left += decoratorFrame.left - frame.left;
screenFrame.right += decoratorFrame.right - frame.right;
screenFrame.top += decoratorFrame.top - frame.top;
screenFrame.bottom += decoratorFrame.bottom - frame.bottom;
width = min_c(width, screen.Frame().Width());
height = min_c(height, screen.Frame().Height());
frame.right = frame.left + width;
frame.bottom = frame.top + height;
if (!screenFrame.Contains(frame)) {
if (frame.left < screenFrame.left)
frame.OffsetBy(screenFrame.left - frame.left, 0);
else if (frame.right > screenFrame.right)
frame.OffsetBy(screenFrame.right - frame.right, 0);
if (frame.top < screenFrame.top)
frame.OffsetBy(screenFrame.top - frame.top, 0);
else if (frame.bottom > screenFrame.bottom)
frame.OffsetBy(screenFrame.bottom - frame.bottom, 0);
}
MoveTo(frame.left, frame.top);
ResizeTo(width, height);
}
void
BrowserWindow::SetToolBarsVisible(bool flag, BWebView* view)
{
}
void
BrowserWindow::SetStatusBarVisible(bool flag, BWebView* view)
{
}
void
BrowserWindow::SetMenuBarVisible(bool flag, BWebView* view)
{
}
void
BrowserWindow::SetResizable(bool flag, BWebView* view)
{
if (flag)
SetFlags(Flags() & ~B_NOT_RESIZABLE);
else
SetFlags(Flags() | B_NOT_RESIZABLE);
}
void
BrowserWindow::StatusChanged(const BString& statusText, BWebView* view)
{
if (view != CurrentWebView())
return;
if (fStatusText)
fStatusText->SetText(statusText.String());
}
void
BrowserWindow::NavigationCapabilitiesChanged(bool canGoBackward,
bool canGoForward, bool canStop, BWebView* view)
{
if (view != CurrentWebView())
return;
fBackButton->SetEnabled(canGoBackward);
fForwardButton->SetEnabled(canGoForward);
fStopButton->SetEnabled(canStop);
fBackMenuItem->SetEnabled(canGoBackward);
fForwardMenuItem->SetEnabled(canGoForward);
}
void
BrowserWindow::UpdateGlobalHistory(const BString& url)
{
BrowsingHistory::DefaultInstance()->AddItem(BrowsingHistoryItem(url));
BWebView* webView = CurrentWebView();
if (webView != NULL)
fURLInputGroup->SetText(webView->MainFrameURL());
}
bool
BrowserWindow::AuthenticationChallenge(BString message, BString& inOutUser,
BString& inOutPassword, bool& inOutRememberCredentials,
uint32 failureCount, BWebView* view)
{
CredentialsStorage* persistentStorage
= CredentialsStorage::PersistentInstance();
CredentialsStorage* sessionStorage
= CredentialsStorage::SessionInstance();
HashString key(message);
if (failureCount == 0) {
if (persistentStorage->Contains(key)) {
Credentials credentials = persistentStorage->GetCredentials(key);
inOutUser = credentials.Username();
inOutPassword = credentials.Password();
return true;
} else if (sessionStorage->Contains(key)) {
Credentials credentials = sessionStorage->GetCredentials(key);
inOutUser = credentials.Username();
inOutPassword = credentials.Password();
return true;
}
}
if (!_ShowPage(view))
return false;
AuthenticationPanel* panel = new AuthenticationPanel(Frame());
bool success = panel->getAuthentication(message, inOutUser, inOutPassword,
inOutRememberCredentials, failureCount > 0, inOutUser, inOutPassword,
&inOutRememberCredentials);
if (success) {
Credentials credentials(inOutUser, inOutPassword);
if (inOutRememberCredentials)
persistentStorage->PutCredentials(key, credentials);
else
sessionStorage->PutCredentials(key, credentials);
}
return success;
}
void
BrowserWindow::_UpdateTitle(const BString& title)
{
BString windowTitle;
if (title.Length() > 0)
windowTitle = title;
else {
BWebView* webView = CurrentWebView();
if (webView != NULL) {
BString url = webView->MainFrameURL();
int32 leafPos = url.FindLast('/');
url.Remove(0, leafPos + 1);
windowTitle = url;
}
}
if (windowTitle.Length() > 0)
windowTitle << " - ";
windowTitle << kApplicationName;
SetTitle(windowTitle.String());
}
void
BrowserWindow::_UpdateTabGroupVisibility()
{
if (Lock()) {
if (fInterfaceVisible)
fTabGroup->SetVisible(_TabGroupShouldBeVisible());
fTabManager->SetCloseButtonsAvailable(fTabManager->CountTabs() > 1);
Unlock();
}
}
bool
BrowserWindow::_TabGroupShouldBeVisible() const
{
return (fShowTabsIfSinglePageOpen || fTabManager->CountTabs() > 1)
&& (fVisibleInterfaceElements & INTERFACE_ELEMENT_TABS) != 0;
}
void
BrowserWindow::_ShutdownTab(int32 index)
{
BView* view = fTabManager->RemoveTab(index);
BWebView* webView = dynamic_cast<BWebView*>(view);
if (webView == CurrentWebView())
SetCurrentWebView(NULL);
if (webView != NULL)
webView->Shutdown();
else
delete view;
}
void
BrowserWindow::_TabChanged(int32 index)
{
SetCurrentWebView(dynamic_cast<BWebView*>(fTabManager->ViewForTab(index)));
}
status_t
BrowserWindow::_BookmarkPath(BPath& path) const
{
status_t ret = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
if (ret != B_OK)
return ret;
ret = path.Append(kApplicationName);
if (ret != B_OK)
return ret;
ret = path.Append("Bookmarks");
if (ret != B_OK)
return ret;
return create_directory(path.Path(), 0777);
}
miniIcon and largeIcon may be NULL.
*/
void
BrowserWindow::_CreateBookmark(const BPath& path, BString fileName, const BString& title,
const BString& url, const BBitmap* miniIcon, const BBitmap* largeIcon)
{
bool presetFileName = true;
if (fileName.IsEmpty() == true) {
presetFileName = false;
fileName = title;
if (fileName.Length() == 0) {
fileName = url;
int32 leafPos = fileName.FindLast('/');
if (leafPos >= 0)
fileName.Remove(0, leafPos + 1);
}
fileName.ReplaceAll('/', '-');
fileName.Truncate(B_FILE_NAME_LENGTH - 1);
}
BPath entryPath(path);
status_t status = entryPath.Append(fileName);
BEntry entry;
if (status == B_OK)
status = entry.SetTo(entryPath.Path(), true);
if (status == B_OK && entry.Exists() == true) {
off_t size;
entry.GetSize(&size);
char attrName[B_ATTR_NAME_LENGTH];
BNode node(&entry);
status_t attrStatus = node.GetNextAttrName(attrName);
if (strcmp(attrName, "_trk/pinfo_le") == 0)
attrStatus = node.GetNextAttrName(attrName);
if (presetFileName == true && size == 0 && attrStatus == B_ENTRY_NOT_FOUND) {
} else {
BDirectory directory(path.Path());
if (_CheckBookmarkExists(directory, fileName, url) == true) {
return;
} else {
int32 tries = 1;
while (entry.Exists()) {
fileName << " " << tries++;
entryPath = path;
status = entryPath.Append(fileName);
if (status == B_OK)
status = entry.SetTo(entryPath.Path(), true);
if (status != B_OK)
break;
}
}
}
}
BFile bookmarkFile;
if (status == B_OK) {
status = bookmarkFile.SetTo(&entry,
B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
}
if (status == B_OK)
status = bookmarkFile.WriteAttrString("META:url", &url);
if (status == B_OK) {
bookmarkFile.WriteAttrString("META:title", &title);
}
BNodeInfo nodeInfo(&bookmarkFile);
if (status == B_OK) {
status = nodeInfo.SetType("application/x-vnd.Be-bookmark");
if (status == B_OK) {
status_t ret = B_OK;
if (miniIcon != NULL) {
ret = nodeInfo.SetIcon(miniIcon, B_MINI_ICON);
if (ret != B_OK) {
fprintf(stderr, "Failed to store mini icon for bookmark: "
"%s\n", strerror(ret));
}
}
if (largeIcon != NULL && ret == B_OK)
ret = nodeInfo.SetIcon(largeIcon, B_LARGE_ICON);
else if (largeIcon == NULL && miniIcon != NULL && ret == B_OK) {
BBitmap substituteLargeIcon(BRect(0, 0, 31, 31), B_BITMAP_NO_SERVER_LINK,
B_CMAP8);
const uint8* src = (const uint8*)miniIcon->Bits();
uint32 srcBPR = miniIcon->BytesPerRow();
uint8* dst = (uint8*)substituteLargeIcon.Bits();
uint32 dstBPR = substituteLargeIcon.BytesPerRow();
for (uint32 y = 0; y < 16; y++) {
const uint8* s = src;
uint8* d = dst;
for (uint32 x = 0; x < 16; x++) {
*d++ = *s;
*d++ = *s++;
}
dst += dstBPR;
s = src;
for (uint32 x = 0; x < 16; x++) {
*d++ = *s;
*d++ = *s++;
}
dst += dstBPR;
src += srcBPR;
}
ret = nodeInfo.SetIcon(&substituteLargeIcon, B_LARGE_ICON);
} else
ret = B_OK;
if (ret != B_OK) {
fprintf(stderr, "Failed to store large icon for bookmark: "
"%s\n", strerror(ret));
}
}
}
if (status != B_OK) {
BString message(B_TRANSLATE_COMMENT("There was an error creating the "
"bookmark file.\n\nError: %error", "Don't translate variable "
"%error"));
message.ReplaceFirst("%error", strerror(status));
BAlert* alert = new BAlert(B_TRANSLATE("Bookmark error"),
message.String(), B_TRANSLATE("OK"), NULL, NULL,
B_WIDTH_AS_USUAL, B_STOP_ALERT);
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go();
return;
}
}
void
BrowserWindow::_CreateBookmark(BMessage* message)
{
entry_ref ref;
BMessage originatorData;
const char* url;
const char* title;
bool validData = (message->FindRef("directory", &ref) == B_OK
&& message->FindMessage("be:originator-data", &originatorData) == B_OK
&& originatorData.FindString("url", &url) == B_OK
&& originatorData.FindString("title", &title) == B_OK);
const char* fileName;
if (message->FindString("name", &fileName) != B_OK) {
fileName = "";
}
const BBitmap* miniIcon = NULL;
const BBitmap* largeIcon = NULL;
originatorData.FindData("miniIcon", B_COLOR_8_BIT_TYPE,
reinterpret_cast<const void**>(&miniIcon), NULL);
originatorData.FindData("largeIcon", B_COLOR_8_BIT_TYPE,
reinterpret_cast<const void**>(&miniIcon), NULL);
if (validData == true) {
_CreateBookmark(BPath(&ref), BString(fileName), BString(title), BString(url),
miniIcon, largeIcon);
} else {
BString message(B_TRANSLATE("There was an error setting up "
"the bookmark."));
BAlert* alert = new BAlert(B_TRANSLATE("Bookmark error"),
message.String(), B_TRANSLATE("OK"), NULL, NULL,
B_WIDTH_AS_USUAL, B_STOP_ALERT);
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go();
}
return;
}
void
BrowserWindow::_CreateBookmark()
{
BString fileName;
BString title(CurrentWebView()->MainFrameTitle());
BString url(CurrentWebView()->MainFrameURL());
BPath path;
status_t status = _BookmarkPath(path);
BBitmap* miniIcon = NULL;
BBitmap* largeIcon = NULL;
PageUserData* userData = static_cast<PageUserData*>(CurrentWebView()->GetUserData());
if (userData != NULL && userData->PageIcon() != NULL) {
miniIcon = new BBitmap(BRect(0, 0, 15, 15), B_BITMAP_NO_SERVER_LINK, B_CMAP8);
miniIcon->ImportBits(userData->PageIcon());
}
if (status == B_OK)
_CreateBookmark(path, fileName, title, url, miniIcon, largeIcon);
else {
BString message(B_TRANSLATE_COMMENT("There was an error retrieving "
"the bookmark folder.\n\nError: %error", "Don't translate the "
"variable %error"));
message.ReplaceFirst("%error", strerror(status));
BAlert* alert = new BAlert(B_TRANSLATE("Bookmark error"),
message.String(), B_TRANSLATE("OK"), NULL, NULL,
B_WIDTH_AS_USUAL, B_STOP_ALERT);
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go();
}
return;
}
void
BrowserWindow::_ShowBookmarks()
{
BPath path;
entry_ref ref;
status_t status = _BookmarkPath(path);
if (status == B_OK)
status = get_ref_for_path(path.Path(), &ref);
if (status == B_OK)
status = be_roster->Launch(&ref);
if (status != B_OK && status != B_ALREADY_RUNNING) {
BString message(B_TRANSLATE_COMMENT("There was an error trying to "
"show the Bookmarks folder.\n\nError: %error",
"Don't translate variable %error"));
message.ReplaceFirst("%error", strerror(status));
BAlert* alert = new BAlert(B_TRANSLATE("Bookmark error"),
message.String(), B_TRANSLATE("OK"), NULL, NULL,
B_WIDTH_AS_USUAL, B_STOP_ALERT);
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go();
return;
}
}
bool BrowserWindow::_CheckBookmarkExists(BDirectory& directory,
const BString& bookmarkName, const BString& url) const
{
BEntry entry;
while (directory.GetNextEntry(&entry) == B_OK) {
char entryName[B_FILE_NAME_LENGTH];
if (entry.GetName(entryName) != B_OK || bookmarkName != entryName)
continue;
BString storedURL;
BFile file(&entry, B_READ_ONLY);
if (_ReadURLAttr(file, storedURL)) {
if (storedURL == url)
return true;
}
}
return false;
}
bool
BrowserWindow::_ReadURLAttr(BFile& bookmarkFile, BString& url) const
{
return bookmarkFile.InitCheck() == B_OK
&& bookmarkFile.ReadAttrString("META:url", &url) == B_OK;
}
void
BrowserWindow::_AddBookmarkURLsRecursively(BDirectory& directory,
BMessage* message, uint32& addedCount) const
{
BEntry entry;
while (directory.GetNextEntry(&entry) == B_OK) {
if (entry.IsDirectory()) {
BDirectory subBirectory(&entry);
entry.Unset();
_AddBookmarkURLsRecursively(subBirectory, message, addedCount);
} else {
BString storedURL;
BFile file(&entry, B_READ_ONLY);
if (_ReadURLAttr(file, storedURL)) {
message->AddString("url", storedURL.String());
addedCount++;
}
}
}
}
void
BrowserWindow::_SetPageIcon(BWebView* view, const BBitmap* icon)
{
PageUserData* userData = static_cast<PageUserData*>(view->GetUserData());
if (userData == NULL) {
userData = new(std::nothrow) PageUserData(NULL);
if (userData == NULL)
return;
view->SetUserData(userData);
}
userData->SetPageIcon(icon);
fTabManager->SetTabIcon(view, userData->PageIcon());
if (view == CurrentWebView())
fURLInputGroup->SetPageIcon(icon);
}
static void
addItemToMenuOrSubmenu(BMenu* menu, BMenuItem* newItem)
{
BString baseURLLabel = baseURL(BString(newItem->Label()));
for (int32 i = menu->CountItems() - 1; i >= 0; i--) {
BMenuItem* item = menu->ItemAt(i);
BString label = item->Label();
if (label.FindFirst(baseURLLabel) >= 0) {
if (item->Submenu()) {
item->Submenu()->AddItem(newItem);
return;
} else {
menu->RemoveItem(item);
BMenu* subMenu = new BMenu(baseURLLabel.String());
subMenu->AddItem(item);
subMenu->AddItem(newItem);
BMessage* message = new BMessage(GOTO_URL);
message->AddString("url", baseURLLabel.String());
menu->AddItem(new BMenuItem(subMenu, message), i);
return;
}
}
}
menu->AddItem(newItem);
}
static void
addOrDeleteMenu(BMenu* menu, BMenu* toMenu)
{
if (menu->CountItems() > 0)
toMenu->AddItem(menu);
else
delete menu;
}
void
BrowserWindow::_UpdateHistoryMenu()
{
BMenuItem* menuItem;
while ((menuItem = fHistoryMenu->RemoveItem(fHistoryMenuFixedItemCount)))
delete menuItem;
BrowsingHistory* history = BrowsingHistory::DefaultInstance();
if (!history->Lock())
return;
int32 count = history->CountItems();
BMenuItem* clearHistoryItem = new BMenuItem(B_TRANSLATE("Clear history"),
new BMessage(CLEAR_HISTORY));
clearHistoryItem->SetEnabled(count > 0);
fHistoryMenu->AddItem(clearHistoryItem);
if (count == 0) {
history->Unlock();
return;
}
fHistoryMenu->AddSeparatorItem();
BDateTime todayStart = BDateTime::CurrentDateTime(B_LOCAL_TIME);
todayStart.SetTime(BTime(0, 0, 0));
BDateTime oneDayAgoStart = todayStart;
oneDayAgoStart.Date().AddDays(-1);
BDateTime twoDaysAgoStart = oneDayAgoStart;
twoDaysAgoStart.Date().AddDays(-1);
BDateTime threeDaysAgoStart = twoDaysAgoStart;
threeDaysAgoStart.Date().AddDays(-1);
BDateTime fourDaysAgoStart = threeDaysAgoStart;
fourDaysAgoStart.Date().AddDays(-1);
BDateTime fiveDaysAgoStart = fourDaysAgoStart;
fiveDaysAgoStart.Date().AddDays(-1);
BMenu* todayMenu = new BMenu(B_TRANSLATE("Today"));
BMenu* yesterdayMenu = new BMenu(B_TRANSLATE("Yesterday"));
BMenu* twoDaysAgoMenu = new BMenu(
twoDaysAgoStart.Date().LongDayName().String());
BMenu* threeDaysAgoMenu = new BMenu(
threeDaysAgoStart.Date().LongDayName().String());
BMenu* fourDaysAgoMenu = new BMenu(
fourDaysAgoStart.Date().LongDayName().String());
BMenu* fiveDaysAgoMenu = new BMenu(
fiveDaysAgoStart.Date().LongDayName().String());
BMenu* earlierMenu = new BMenu(B_TRANSLATE("Earlier"));
for (int32 i = 0; i < count; i++) {
BrowsingHistoryItem historyItem = history->HistoryItemAt(i);
BMessage* message = new BMessage(GOTO_URL);
message->AddString("url", historyItem.URL().String());
BString truncatedUrl(historyItem.URL());
be_plain_font->TruncateString(&truncatedUrl, B_TRUNCATE_END, 480);
menuItem = new BMenuItem(truncatedUrl, message);
if (historyItem.DateTime() < fiveDaysAgoStart)
addItemToMenuOrSubmenu(earlierMenu, menuItem);
else if (historyItem.DateTime() < fourDaysAgoStart)
addItemToMenuOrSubmenu(fiveDaysAgoMenu, menuItem);
else if (historyItem.DateTime() < threeDaysAgoStart)
addItemToMenuOrSubmenu(fourDaysAgoMenu, menuItem);
else if (historyItem.DateTime() < twoDaysAgoStart)
addItemToMenuOrSubmenu(threeDaysAgoMenu, menuItem);
else if (historyItem.DateTime() < oneDayAgoStart)
addItemToMenuOrSubmenu(twoDaysAgoMenu, menuItem);
else if (historyItem.DateTime() < todayStart)
addItemToMenuOrSubmenu(yesterdayMenu, menuItem);
else
addItemToMenuOrSubmenu(todayMenu, menuItem);
}
history->Unlock();
addOrDeleteMenu(todayMenu, fHistoryMenu);
addOrDeleteMenu(yesterdayMenu, fHistoryMenu);
addOrDeleteMenu(twoDaysAgoMenu, fHistoryMenu);
addOrDeleteMenu(threeDaysAgoMenu, fHistoryMenu);
addOrDeleteMenu(fourDaysAgoMenu, fHistoryMenu);
addOrDeleteMenu(fiveDaysAgoMenu, fHistoryMenu);
addOrDeleteMenu(earlierMenu, fHistoryMenu);
}
void
BrowserWindow::_UpdateClipboardItems()
{
BTextView* focusTextView = dynamic_cast<BTextView*>(CurrentFocus());
if (focusTextView != NULL) {
int32 selectionStart;
int32 selectionEnd;
focusTextView->GetSelection(&selectionStart, &selectionEnd);
bool hasSelection = selectionStart < selectionEnd;
bool canPaste = false;
if (be_clipboard->Lock()) {
BMessage* data = be_clipboard->Data();
if (data != NULL)
canPaste = data->HasData("text/plain", B_MIME_TYPE);
be_clipboard->Unlock();
}
fCutMenuItem->SetEnabled(hasSelection);
fCopyMenuItem->SetEnabled(hasSelection);
fPasteMenuItem->SetEnabled(canPaste);
} else if (CurrentWebView() != NULL) {
fCutMenuItem->SetEnabled(true);
fCopyMenuItem->SetEnabled(true);
fPasteMenuItem->SetEnabled(true);
CurrentWebView()->WebPage()->SendEditingCapabilities();
}
}
bool
BrowserWindow::_ShowPage(BWebView* view)
{
if (view != CurrentWebView()) {
int32 tabIndex = fTabManager->TabForView(view);
if (tabIndex < 0) {
return false;
}
fTabManager->SelectTab(tabIndex);
_TabChanged(tabIndex);
UpdateIfNeeded();
}
return true;
}
void
BrowserWindow::_ResizeToScreen()
{
BScreen screen(this);
MoveTo(0, 0);
ResizeTo(screen.Frame().Width(), screen.Frame().Height());
}
void
BrowserWindow::_SetAutoHideInterfaceInFullscreen(bool doIt)
{
if (fAutoHideInterfaceInFullscreenMode == doIt)
return;
fAutoHideInterfaceInFullscreenMode = doIt;
if (fAppSettings->GetValue(kSettingsKeyAutoHideInterfaceInFullscreenMode,
doIt) != doIt) {
fAppSettings->SetValue(kSettingsKeyAutoHideInterfaceInFullscreenMode,
doIt);
}
if (fAutoHideInterfaceInFullscreenMode) {
BMessage message(CHECK_AUTO_HIDE_INTERFACE);
fPulseRunner = new BMessageRunner(BMessenger(this), &message, 300000);
} else {
delete fPulseRunner;
fPulseRunner = NULL;
_ShowInterface(true);
}
}
void
BrowserWindow::_CheckAutoHideInterface()
{
if (!fIsFullscreen || !fAutoHideInterfaceInFullscreenMode
|| (CurrentWebView() != NULL && !CurrentWebView()->IsFocus())) {
return;
}
if (fLastMousePos.y == 0)
_ShowInterface(true);
else if (fNavigationGroup->IsVisible()
&& fLastMousePos.y > fNavigationGroup->Frame().bottom
&& system_time() - fLastMouseMovedTime > 1000000) {
_ShowInterface(false);
}
}
void
BrowserWindow::_ShowInterface(bool show)
{
if (fInterfaceVisible == show)
return;
fInterfaceVisible = show;
if (show) {
#if !INTEGRATE_MENU_INTO_TAB_BAR
fMenuGroup->SetVisible(
(fVisibleInterfaceElements & INTERFACE_ELEMENT_MENU) != 0);
#endif
fTabGroup->SetVisible(_TabGroupShouldBeVisible());
fNavigationGroup->SetVisible(
(fVisibleInterfaceElements & INTERFACE_ELEMENT_NAVIGATION) != 0);
fStatusGroup->SetVisible(
(fVisibleInterfaceElements & INTERFACE_ELEMENT_STATUS) != 0);
} else {
fMenuGroup->SetVisible(false);
fTabGroup->SetVisible(false);
fNavigationGroup->SetVisible(false);
fStatusGroup->SetVisible(false);
}
while (!fLoadingProgressBar->IsHidden())
fLoadingProgressBar->Hide();
}
void
BrowserWindow::_ShowProgressBar(bool show)
{
if (show) {
if (!fStatusGroup->IsVisible() && (fVisibleInterfaceElements
& INTERFACE_ELEMENT_STATUS) != 0)
fStatusGroup->SetVisible(true);
fLoadingProgressBar->Show();
} else {
if (!fInterfaceVisible)
fStatusGroup->SetVisible(false);
while (!fLoadingProgressBar->IsHidden())
fLoadingProgressBar->Hide();
}
}
void
BrowserWindow::_InvokeButtonVisibly(BButton* button)
{
button->SetValue(B_CONTROL_ON);
UpdateIfNeeded();
button->Invoke();
snooze(1000);
button->SetValue(B_CONTROL_OFF);
}
BString
BrowserWindow::_NewTabURL(bool isNewWindow) const
{
BString url;
uint32 policy = isNewWindow ? fNewWindowPolicy : fNewTabPolicy;
switch (policy) {
case OpenStartPage:
url = fStartPageURL;
break;
case OpenSearchPage:
url.SetTo(fSearchPageURL);
url.ReplaceAll("%s", "");
break;
case CloneCurrentPage:
if (CurrentWebView() != NULL)
url = CurrentWebView()->MainFrameURL();
break;
case OpenBlankPage:
default:
break;
}
return url;
}
BString
BrowserWindow::_EncodeURIComponent(const BString& search)
{
const BString escCharList = " $&`:<>[]{}\"+#%@/;=?\\^|~\',";
BString result = search;
char hexcode[4];
for (int32 i = 0; i < result.Length(); i++) {
if (escCharList.FindFirst(result[i]) != B_ERROR) {
sprintf(hexcode, "%02X", (unsigned int)result[i]);
result.SetByteAt(i, '%');
result.Insert(hexcode, i + 1);
i += 2;
}
}
return result;
}
void
BrowserWindow::_VisitURL(const BString& url)
{
CurrentWebView()->LoadURL(url.String());
}
void
BrowserWindow::_VisitSearchEngine(const BString& search)
{
BString searchQuery = search;
BString searchPrefix;
search.CopyCharsInto(searchPrefix, 0, 2);
BString engine(fSearchPageURL);
for (int i = 0; kSearchEngines[i].url != NULL; i++) {
if (kSearchEngines[i].shortcut == searchPrefix) {
engine = kSearchEngines[i].url;
searchQuery.Remove(0, 2);
break;
}
}
engine.ReplaceAll("%s", _EncodeURIComponent(searchQuery));
_VisitURL(engine);
}
inline bool
BrowserWindow::_IsValidDomainChar(char ch)
{
return ch != ' ';
}
We try to be flexible in what we accept as a valid URL. The protocol may
be missing, or something we can't handle (in that case we run the matching
app). If all attempts to make sense of the input fail, we make a search
engine query for it.
*/
void
BrowserWindow::_SmartURLHandler(const BString& url)
{
int32 at = url.FindFirst(":");
if (at != B_ERROR) {
BString proto;
url.CopyInto(proto, 0, at);
bool handled = false;
for (unsigned int i = 0; i < sizeof(kHandledProtocols) / sizeof(char*);
i++) {
handled = (proto == kHandledProtocols[i]);
if (handled)
break;
}
if (handled) {
_VisitURL(url);
return;
} else {
BString temp;
temp = "application/x-vnd.Be.URL.";
temp += proto;
const char* argv[] = { url.String(), NULL };
if (be_roster->Launch(temp.String(), 1, argv) == B_OK)
return;
}
}
if (url == "localhost")
_VisitURL("http://localhost/");
else {
const char* localhostPrefix = "localhost/";
if (url.Compare(localhostPrefix, strlen(localhostPrefix)) == 0)
_VisitURL(url);
else {
bool isURL = false;
for (int32 i = 0; i < url.CountChars(); i++) {
if (url[i] == '.')
isURL = true;
else if (url[i] == '/')
break;
else if (!_IsValidDomainChar(url[i])) {
isURL = false;
break;
}
}
if (isURL) {
BString prefixed = "http://";
prefixed << url;
_VisitURL(prefixed);
return;
} else {
_VisitSearchEngine(url);
}
}
}
}
void
BrowserWindow::_HandlePageSourceResult(const BMessage* message)
{
BPath pathToPageSource;
BString url;
status_t ret = message->FindString("url", &url);
if (ret == B_OK && url.FindFirst("file://") == 0) {
url.Remove(0, strlen("file://"));
pathToPageSource.SetTo(url.String());
} else {
BString source;
ret = message->FindString("source", &source);
if (ret == B_OK)
ret = find_directory(B_SYSTEM_TEMP_DIRECTORY, &pathToPageSource);
BString tmpFileName("PageSource_");
tmpFileName << system_time() << ".html";
if (ret == B_OK)
ret = pathToPageSource.Append(tmpFileName.String());
BFile pageSourceFile(pathToPageSource.Path(),
B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
if (ret == B_OK)
ret = pageSourceFile.InitCheck();
if (ret == B_OK) {
ssize_t written = pageSourceFile.Write(source.String(),
source.Length());
if (written != source.Length())
ret = (status_t)written;
}
if (ret == B_OK) {
const char* type = "text/html";
size_t size = strlen(type);
pageSourceFile.WriteAttr("BEOS:TYPE", B_STRING_TYPE, 0, type, size);
}
}
entry_ref ref;
if (ret == B_OK)
ret = get_ref_for_path(pathToPageSource.Path(), &ref);
if (ret == B_OK) {
BMessage refsMessage(B_REFS_RECEIVED);
ret = refsMessage.AddRef("refs", &ref);
if (ret == B_OK) {
ret = be_roster->Launch("text/x-source-code", &refsMessage);
if (ret == B_ALREADY_RUNNING)
ret = B_OK;
}
}
if (ret != B_OK) {
char buffer[1024];
snprintf(buffer, sizeof(buffer), "Failed to show the "
"page source: %s\n", strerror(ret));
BAlert* alert = new BAlert(B_TRANSLATE("Page source error"), buffer,
B_TRANSLATE("OK"));
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go(NULL);
}
}
void
BrowserWindow::_ShowBookmarkBar(bool show)
{
if (show && (fBookmarkBar == NULL || fBookmarkBar->CountItems() <= 1))
{
fBookmarkBarMenuItem->SetMarked(false);
return;
}
fBookmarkBarMenuItem->SetMarked(show);
if (fBookmarkBar == NULL || fBookmarkBar->IsHidden() != show)
return;
fAppSettings->SetValue(kSettingsShowBookmarkBar, show);
if (show)
fBookmarkBar->Show();
else
fBookmarkBar->Hide();
}