2688 lines
72 KiB
C++
2688 lines
72 KiB
C++
/*
|
||
* 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 "URLInputGroup.h"
|
||
#include "WebPage.h"
|
||
#include "WebView.h"
|
||
#include "WebViewConstants.h"
|
||
#include "WebViewListItem.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',
|
||
};
|
||
|
||
|
||
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 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)
|
||
{
|
||
// Add these items here already, so the shortcuts work even when
|
||
// the menu has never been opened yet.
|
||
_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)
|
||
{
|
||
// Button is 16x16 regardless of font size
|
||
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) {
|
||
// Draw the button frame
|
||
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);
|
||
}
|
||
|
||
// Draw the ×
|
||
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;
|
||
};
|
||
|
||
|
||
// #pragma mark - BrowserWindow
|
||
|
||
|
||
BrowserWindow::BrowserWindow(BRect frame, SettingsMessage* appSettings,
|
||
const BString& url, BPrivate::Network::BUrlContext* context,
|
||
uint32 interfaceElements, BWebView* webView)
|
||
:
|
||
BWebWindow(frame, kApplicationName,
|
||
B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
|
||
B_AUTO_UPDATE_SIZE_LIMITS | B_ASYNCHRONOUS_CONTROLS),
|
||
fIsFullscreen(false),
|
||
fInterfaceVisible(false),
|
||
fMenusRunning(false),
|
||
fPulseRunner(NULL),
|
||
fVisibleInterfaceElements(interfaceElements),
|
||
fContext(context),
|
||
fAppSettings(appSettings),
|
||
fZoomTextOnly(true),
|
||
fShowTabsIfSinglePageOpen(true),
|
||
fAutoHideInterfaceInFullscreenMode(false),
|
||
fAutoHidePointer(false),
|
||
fBookmarkBar(NULL)
|
||
{
|
||
// Begin listening to settings changes and read some current values.
|
||
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);
|
||
|
||
// Create the interface elements
|
||
BMessage* createWebViewMessage = new BMessage(CREATE_VIEW);
|
||
createWebViewMessage->AddString("url", "");
|
||
createWebViewMessage->AddPointer("window", this);
|
||
createWebViewMessage->AddBool("select", true);
|
||
|
||
// Menu
|
||
BMenu* mainMenu = new BMenuBar("Main menu");
|
||
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(*createWebViewMessage), '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_VIEW), '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'));
|
||
// the label will be replaced with the appropriate text later on
|
||
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, "Bookmark bar");
|
||
entry_ref bookmarkBarRef;
|
||
// TODO we could also check if the folder is empty here.
|
||
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);
|
||
|
||
// Back, Forward, Stop & Home buttons
|
||
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();
|
||
|
||
// URL input group
|
||
fURLInputGroup = new URLInputGroup(new BMessage(GOTO_URL));
|
||
|
||
// Status Bar
|
||
fStatusText = new BStringView("status", "");
|
||
fStatusText->SetAlignment(B_ALIGN_LEFT);
|
||
fStatusText->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
|
||
fStatusText->SetExplicitMinSize(BSize(150, 12));
|
||
// Prevent the window from growing to fit a long status message...
|
||
BFont font(be_plain_font);
|
||
font.SetSize(ceilf(font.Size() * 0.8));
|
||
fStatusText->SetFont(&font, B_FONT_SIZE);
|
||
|
||
// Loading progress bar
|
||
fLoadingProgressBar = new BStatusBar("progress");
|
||
fLoadingProgressBar->SetMaxValue(100);
|
||
fLoadingProgressBar->Hide();
|
||
fLoadingProgressBar->SetBarHeight(12);
|
||
|
||
const float kInsetSpacing = 3;
|
||
const float kElementSpacing = 5;
|
||
|
||
// Find group
|
||
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)
|
||
)
|
||
;
|
||
|
||
// Navigation group
|
||
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))
|
||
;
|
||
|
||
// Status bar group
|
||
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);
|
||
|
||
BGroupLayout* menuBarGroup = BLayoutBuilder::Group<>(B_HORIZONTAL, 0.0)
|
||
.Add(mainMenu)
|
||
.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);
|
||
|
||
// Layout
|
||
BGroupView* topView = new BGroupView(B_VERTICAL, 0.0);
|
||
|
||
topView->AddChild(menuBarGroup);
|
||
topView->AddChild(navigationGroup);
|
||
if (fBookmarkBar != NULL)
|
||
topView->AddChild(fBookmarkBar);
|
||
//TODO NEPHELE
|
||
topView->AddChild(findGroup);
|
||
topView->AddChild(statusGroup);
|
||
|
||
AddChild(topView);
|
||
|
||
fURLInputGroup->MakeFocus(true);
|
||
|
||
fMenuGroup = menuBarGroup;
|
||
//fTabGroup = fTabManager->TabGroup()->GetLayout();
|
||
fNavigationGroup = navigationGroup;
|
||
fFindGroup = findGroup;
|
||
fStatusGroup = statusGroup;
|
||
fToggleFullscreenButton = layoutItemFor(toggleFullscreenButton);
|
||
|
||
fFindGroup->SetVisible(false);
|
||
fToggleFullscreenButton->SetVisible(false);
|
||
|
||
CreateWebView(url, true, webView);
|
||
_ShowInterface(true);
|
||
_SetAutoHideInterfaceInFullscreen(fAppSettings->GetValue(
|
||
kSettingsKeyAutoHideInterfaceInFullscreenMode,
|
||
fAutoHideInterfaceInFullscreenMode));
|
||
|
||
AddShortcut('F', B_COMMAND_KEY | B_SHIFT_KEY,
|
||
new BMessage(EDIT_HIDE_FIND_GROUP));
|
||
// TODO: Should be a different shortcut, H is usually for Find selection.
|
||
AddShortcut('H', B_COMMAND_KEY, new BMessage(HOME));
|
||
|
||
// Add shortcuts to select a particular tab
|
||
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);
|
||
}
|
||
|
||
BKeymap keymap;
|
||
keymap.SetToCurrent();
|
||
BObjectList<const char> unmodified(3, true);
|
||
if (keymap.GetModifiedCharacters("+", B_SHIFT_KEY, 0, &unmodified)
|
||
== B_OK) {
|
||
int32 count = unmodified.CountItems();
|
||
for (int32 i = 0; i < count; i++) {
|
||
uint32 key = BUnicodeChar::FromUTF8(unmodified.ItemAt(i));
|
||
if (!HasShortcut(key, 0)) {
|
||
// Add semantic zoom in shortcut, bug #7428
|
||
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) {
|
||
// Some function key Firefox compatibility
|
||
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()) {
|
||
// Handle B_RETURN in the URL text control. This is the easiest
|
||
// way to react *only* when the user presses the return key in the
|
||
// address bar, as opposed to trying to load whatever is in there
|
||
// when the text control just goes out of focus.
|
||
if (bytes[0] == B_RETURN) {
|
||
// Do it in such a way that the user sees the Go-button go down.
|
||
_InvokeButtonVisibly(fURLInputGroup->GoButton());
|
||
return;
|
||
} else if (bytes[0] == B_ESCAPE) {
|
||
// Replace edited text with the current URL.
|
||
fURLInputGroup->LockURLInput(false);
|
||
fURLInputGroup->SetText(CurrentWebView()->MainFrameURL());
|
||
}
|
||
} else if (target == fFindTextControl->TextView()) {
|
||
// Handle B_RETURN when the find text control has focus.
|
||
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 {
|
||
// Default escape key behavior:
|
||
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);
|
||
// Only do this when the mouse is over the web view
|
||
if (CurrentWebView()->Bounds().Contains(where)) {
|
||
// Zoom and unzoom text on Command + mouse wheel.
|
||
// This could of course (and maybe should be) implemented in the
|
||
// WebView, but there would need to be a way for the WebView to
|
||
// know the setting of the fZoomTextOnly member here. Plus other
|
||
// clients of the API may not want this feature.
|
||
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 {
|
||
// Also don't scroll up and down if the mouse is not over the
|
||
// web view
|
||
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:
|
||
{
|
||
// Currently the only source of these messages is the bookmarks
|
||
// menu.
|
||
// Filter refs into URLs, this also gets rid of refs for folders.
|
||
// For clicks on sub-folders in the bookmarks menu, we have Tracker
|
||
// open the corresponding folder.
|
||
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) {
|
||
// Don't know what to do with this entry, just pass it
|
||
// on to the system to handle. Note that this may result
|
||
// in us opening other supported files via the application
|
||
// mechanism.
|
||
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:
|
||
{
|
||
// User possibly dropped files on this window.
|
||
// If there is more than one entry_ref, let the app handle it
|
||
// (open one new page per ref). If there is one ref, open it in
|
||
// this window.
|
||
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);
|
||
// TODO: Would be nice to have an instant update if the page is
|
||
// already zoomed.
|
||
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_VIEW:
|
||
if (fWebViewList->CountItems() > 1) {
|
||
int32 index;
|
||
if (message->FindInt32("tab index", &index) != B_OK)
|
||
_CloseView(index);
|
||
} else
|
||
PostMessage(B_QUIT_REQUESTED);
|
||
break;
|
||
|
||
case SELECT_VIEW:
|
||
void* view;
|
||
if (message->FindPointer("WebView", &view) == B_OK) {
|
||
fWebViewList->Select(fWebViewList->IndexOf((BListItem*)view));
|
||
SetCurrentWebView((BWebView*)view);
|
||
}
|
||
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;
|
||
}
|
||
} 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;
|
||
|
||
default:
|
||
BWebWindow::MessageReceived(message);
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
status_t
|
||
BrowserWindow::Archive(BMessage* archive, bool deep) const
|
||
{
|
||
status_t ret = archive->AddRect("window frame", Frame());
|
||
|
||
for (int i = 0; i < fWebViewList->CountItems(); i++) {
|
||
WebViewListItem* webViewItem = static_cast<WebViewListItem*>(fWebViewList->ItemAt(i));
|
||
BWebView* view = webViewItem->fWebView;
|
||
if (view == NULL) {
|
||
continue;
|
||
}
|
||
|
||
if (ret == B_OK)
|
||
ret = archive->AddString("tab", view->MainFrameURL());
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
|
||
bool
|
||
BrowserWindow::QuitRequested()
|
||
{
|
||
// TODO: Check for modified form data and ask user for confirmation, etc.
|
||
|
||
BMessage message(WINDOW_CLOSED);
|
||
Archive(&message);
|
||
|
||
// Iterate over all tabs to delete all BWebViews.
|
||
// Do this here, so WebKit tear down happens earlier.
|
||
SetCurrentWebView(NULL);
|
||
while (fWebViewList->CountItems() > 0)
|
||
_CloseView(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) {
|
||
// Remember the currently focused view before switching tabs,
|
||
// so that we can revert the focus when switching back to this tab
|
||
// later.
|
||
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());
|
||
|
||
// Restore the previous focus or focus the web view.
|
||
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);
|
||
// Unlock it so the following code can update the URL
|
||
|
||
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);
|
||
// Restore the state
|
||
|
||
// Trigger update of the interface to the new page, by requesting
|
||
// to resend all notifications.
|
||
webView->WebPage()->ResendNotifications();
|
||
} else
|
||
_UpdateTitle("");
|
||
}
|
||
|
||
|
||
bool
|
||
BrowserWindow::IsBlankTab() const
|
||
{
|
||
if (CurrentWebView() == NULL)
|
||
return false;
|
||
BString requestedURL = CurrentWebView()->MainFrameRequestedURL();
|
||
return requestedURL.Length() == 0
|
||
|| requestedURL == _NewTabURL(fWebViewList->CountItems() == 1);
|
||
}
|
||
|
||
|
||
void
|
||
BrowserWindow::CreateWebView(const BString& _url, bool select,
|
||
BWebView* webView)
|
||
{
|
||
bool applyNewPagePolicy = webView == NULL;
|
||
// Executed in app thread (new BWebPage needs to be created in app thread).
|
||
if (webView == NULL)
|
||
webView = new BWebView("web view", fContext);
|
||
|
||
bool isNewWindow = fWebViewList->CountItems() == 0;
|
||
WebViewListItem* newEntry = new WebViewListItem(webView, B_TRANSLATE("New tab"));
|
||
fWebViewList->AddItem(newEntry);
|
||
|
||
BString url(_url);
|
||
if (applyNewPagePolicy && url.Length() == 0)
|
||
url = _NewTabURL(isNewWindow);
|
||
|
||
if (url.Length() > 0)
|
||
webView->LoadURL(url.String());
|
||
|
||
if (select) {
|
||
fWebViewList->Select(fWebViewList->IndexOf(newEntry));
|
||
SetCurrentWebView(webView);
|
||
webView->WebPage()->ResendNotifications();
|
||
fURLInputGroup->SetPageIcon(NULL);
|
||
fURLInputGroup->SetText(url.String());
|
||
fURLInputGroup->MakeFocus(true);
|
||
}
|
||
|
||
_ShowInterface(true);
|
||
}
|
||
|
||
|
||
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);
|
||
}
|
||
|
||
|
||
// #pragma mark - Notification API
|
||
|
||
|
||
void
|
||
BrowserWindow::NavigationRequested(const BString& url, BWebView* view)
|
||
{
|
||
}
|
||
|
||
|
||
void
|
||
BrowserWindow::NewWindowRequested(const BString& url, bool primaryAction)
|
||
{
|
||
// Always open new windows in the application thread, since
|
||
// creating a BWebView will try to grab the application lock.
|
||
// But our own WebPage may already try to lock us from within
|
||
// the application thread -> dead-lock. Thus we can't wait for
|
||
// a reply here.
|
||
BMessage message(CREATE_VIEW);
|
||
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
|
||
CreateWebView(BString(), activate, view);
|
||
}
|
||
|
||
|
||
void
|
||
BrowserWindow::CloseWindowRequested(BWebView* view)
|
||
{
|
||
BMessage message(CLOSE_VIEW);
|
||
message.AddPointer("view pointer", view);
|
||
PostMessage(&message, this);
|
||
}
|
||
|
||
|
||
void
|
||
BrowserWindow::LoadNegotiating(const BString& url, BWebView* view)
|
||
{
|
||
if (view != CurrentWebView()) {
|
||
// Update the userData contents instead so the user sees
|
||
// the correct URL when they switch back to that tab.
|
||
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;
|
||
|
||
// This hook is invoked when the load is committed.
|
||
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);
|
||
|
||
// TODO NEPHELE
|
||
/*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)
|
||
{
|
||
// Make sure we show the page that contains the view.
|
||
if (!_SelectView(view))
|
||
return;
|
||
|
||
// Try delegating the URL to an external app instead.
|
||
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);
|
||
|
||
// TODO: Remove the failing URL from the BrowsingHistory!
|
||
}
|
||
|
||
|
||
void
|
||
BrowserWindow::TitleChanged(const BString& title, BWebView* view)
|
||
{/*
|
||
// TODO NEPHELE
|
||
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)
|
||
{/*
|
||
// TODO NEPHELE
|
||
// The view may already be gone, since this notification arrives
|
||
// asynchronously.
|
||
if (!fTabManager->HasView(view))
|
||
return;
|
||
|
||
_SetPageIcon(view, icon);*/
|
||
}
|
||
|
||
|
||
void
|
||
BrowserWindow::ResizeRequested(float width, float height, BWebView* view)
|
||
{
|
||
if (view != CurrentWebView())
|
||
return;
|
||
|
||
// Ignore request when there is more than one BWebView embedded.
|
||
if (fWebViewList->CountItems() > 1)
|
||
return;
|
||
|
||
// Make sure the new frame is not larger than the screen frame minus
|
||
// window decorator border.
|
||
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;
|
||
|
||
// frame is now not larger than screenFrame, but may still be partly outside
|
||
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)
|
||
{
|
||
// TODO
|
||
// TODO: Ignore request when there is more than one BWebView embedded!
|
||
}
|
||
|
||
|
||
void
|
||
BrowserWindow::SetStatusBarVisible(bool flag, BWebView* view)
|
||
{
|
||
// TODO
|
||
// TODO: Ignore request when there is more than one BWebView embedded!
|
||
}
|
||
|
||
|
||
void
|
||
BrowserWindow::SetMenuBarVisible(bool flag, BWebView* view)
|
||
{
|
||
// TODO
|
||
// TODO: Ignore request when there is more than one BWebView embedded!
|
||
}
|
||
|
||
|
||
void
|
||
BrowserWindow::SetResizable(bool flag, BWebView* view)
|
||
{
|
||
// TODO: Ignore request when there is more than one BWebView embedded!
|
||
|
||
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));
|
||
|
||
fURLInputGroup->SetText(CurrentWebView()->MainFrameURL());
|
||
}
|
||
|
||
|
||
bool
|
||
BrowserWindow::AuthenticationChallenge(BString message, BString& inOutUser,
|
||
BString& inOutPassword, bool& inOutRememberCredentials,
|
||
uint32 failureCount, BWebView* view)
|
||
{
|
||
CredentialsStorage* persistentStorage
|
||
= CredentialsStorage::PersistentInstance();
|
||
CredentialsStorage* sessionStorage
|
||
= CredentialsStorage::SessionInstance();
|
||
|
||
// TODO: Using the message as key here is not so smart.
|
||
HashKeyString 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;
|
||
}
|
||
}
|
||
// Switch to the page for which this authentication is required.
|
||
if (!_SelectView(view))
|
||
return false;
|
||
|
||
AuthenticationPanel* panel = new AuthenticationPanel(Frame());
|
||
// Panel auto-destructs.
|
||
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;
|
||
}
|
||
|
||
|
||
// #pragma mark - private
|
||
|
||
|
||
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::_CloseView(int32 index)
|
||
{/*
|
||
// TODO NEPHELE
|
||
BView* view = fWebViewList->RemoveItem(index);
|
||
BWebView* webView = dynamic_cast<BWebView*>(view);
|
||
if (webView == CurrentWebView())
|
||
SetCurrentWebView(NULL);
|
||
if (webView != NULL)
|
||
webView->Shutdown();
|
||
else
|
||
delete view;*/
|
||
}
|
||
|
||
|
||
|
||
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);
|
||
}
|
||
|
||
|
||
void
|
||
BrowserWindow::_CreateBookmark()
|
||
{
|
||
BPath path;
|
||
status_t status = _BookmarkPath(path);
|
||
if (status != B_OK) {
|
||
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;
|
||
}
|
||
BWebView* webView = CurrentWebView();
|
||
BString url(webView->MainFrameURL());
|
||
// Create a bookmark file
|
||
BFile bookmarkFile;
|
||
BString bookmarkName(webView->MainFrameTitle());
|
||
if (bookmarkName.Length() == 0) {
|
||
bookmarkName = url;
|
||
int32 leafPos = bookmarkName.FindLast('/');
|
||
if (leafPos >= 0)
|
||
bookmarkName.Remove(0, leafPos + 1);
|
||
}
|
||
// Make sure the bookmark title does not contain chars that are not
|
||
// allowed in file names, and is within allowed name length.
|
||
bookmarkName.ReplaceAll('/', '-');
|
||
bookmarkName.Truncate(B_FILE_NAME_LENGTH - 1);
|
||
|
||
// Check that the bookmark exists nowhere in the bookmark hierarchy,
|
||
// though the intended file name must match, we don't search the stored
|
||
// URLs, only for matching file names.
|
||
BDirectory directory(path.Path());
|
||
if (status == B_OK && _CheckBookmarkExists(directory, bookmarkName, url)) {
|
||
BString message(B_TRANSLATE_COMMENT("A bookmark for this page "
|
||
"(%bookmarkName) already exists.", "Don't translate variable "
|
||
"%bookmarkName"));
|
||
message.ReplaceFirst("%bookmarkName", bookmarkName);
|
||
BAlert* alert = new BAlert(B_TRANSLATE("Bookmark info"),
|
||
message.String(), B_TRANSLATE("OK"));
|
||
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
|
||
alert->Go();
|
||
return;
|
||
}
|
||
|
||
BPath entryPath(path);
|
||
status = entryPath.Append(bookmarkName);
|
||
BEntry entry;
|
||
if (status == B_OK)
|
||
status = entry.SetTo(entryPath.Path(), true);
|
||
if (status == B_OK) {
|
||
int32 tries = 1;
|
||
while (entry.Exists()) {
|
||
// Find a unique name for the bookmark, there may still be a
|
||
// file in the way that stores a different URL.
|
||
bookmarkName = webView->MainFrameTitle();
|
||
bookmarkName << " " << tries++;
|
||
entryPath = path;
|
||
status = entryPath.Append(bookmarkName);
|
||
if (status == B_OK)
|
||
status = entry.SetTo(entryPath.Path(), true);
|
||
if (status != B_OK)
|
||
break;
|
||
}
|
||
}
|
||
if (status == B_OK) {
|
||
status = bookmarkFile.SetTo(&entry,
|
||
B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
|
||
}
|
||
|
||
// Write bookmark meta data
|
||
if (status == B_OK)
|
||
status = bookmarkFile.WriteAttrString("META:url", &url);
|
||
if (status == B_OK) {
|
||
BString title = webView->MainFrameTitle();
|
||
bookmarkFile.WriteAttrString("META:title", &title);
|
||
}
|
||
|
||
BNodeInfo nodeInfo(&bookmarkFile);
|
||
if (status == B_OK) {
|
||
status = nodeInfo.SetType("application/x-vnd.Be-bookmark");
|
||
if (status == B_OK) {
|
||
PageUserData* userData = static_cast<PageUserData*>(
|
||
webView->GetUserData());
|
||
if (userData != NULL && userData->PageIcon() != NULL) {
|
||
BBitmap miniIcon(BRect(0, 0, 15, 15), B_BITMAP_NO_SERVER_LINK,
|
||
B_CMAP8);
|
||
status_t ret = miniIcon.ImportBits(userData->PageIcon());
|
||
if (ret == B_OK)
|
||
ret = nodeInfo.SetIcon(&miniIcon, B_MINI_ICON);
|
||
if (ret != B_OK) {
|
||
fprintf(stderr, "Failed to store mini icon for bookmark: "
|
||
"%s\n", strerror(ret));
|
||
}
|
||
BBitmap largeIcon(BRect(0, 0, 31, 31), B_BITMAP_NO_SERVER_LINK,
|
||
B_CMAP8);
|
||
// TODO: Store 32x32 favicon which is often provided by sites.
|
||
const uint8* src = (const uint8*)miniIcon.Bits();
|
||
uint32 srcBPR = miniIcon.BytesPerRow();
|
||
uint8* dst = (uint8*)largeIcon.Bits();
|
||
uint32 dstBPR = largeIcon.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;
|
||
}
|
||
if (ret == B_OK)
|
||
ret = nodeInfo.SetIcon(&largeIcon, B_LARGE_ICON);
|
||
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::_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) {
|
||
if (entry.IsDirectory()) {
|
||
BDirectory subBirectory(&entry);
|
||
// At least preserve the entry file handle when recursing into
|
||
// sub-folders... eventually we will run out, though, with very
|
||
// deep hierarchy.
|
||
entry.Unset();
|
||
if (_CheckBookmarkExists(subBirectory, bookmarkName, url))
|
||
return true;
|
||
} else {
|
||
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)) {
|
||
// Just bail if the bookmark already exists
|
||
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);
|
||
// At least preserve the entry file handle when recursing into
|
||
// sub-folders... eventually we will run out, though, with very
|
||
// deep hierarchy.
|
||
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)
|
||
{/*
|
||
// TODO NEPHELE
|
||
PageUserData* userData = static_cast<PageUserData*>(view->GetUserData());
|
||
if (userData == NULL) {
|
||
userData = new(std::nothrow) PageUserData(NULL);
|
||
if (userData == NULL)
|
||
return;
|
||
view->SetUserData(userData);
|
||
}
|
||
// The PageUserData makes a copy of the icon, which we pass on to
|
||
// the TabManager for display in the respective tab.
|
||
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()) {
|
||
// Submenu was already added in previous iteration.
|
||
item->Submenu()->AddItem(newItem);
|
||
return;
|
||
} else {
|
||
menu->RemoveItem(item);
|
||
BMenu* subMenu = new BMenu(baseURLLabel.String());
|
||
subMenu->AddItem(item);
|
||
subMenu->AddItem(newItem);
|
||
// Add common submenu for this base URL, clickable.
|
||
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;
|
||
// A BTextView has the focus.
|
||
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) {
|
||
// Trigger update of the clipboard items, even if the
|
||
// BWebView doesn't have focus, we'll dispatch these message
|
||
// there anyway. This works so fast that the user can never see
|
||
// the wrong enabled state when the menu opens until the result
|
||
// message arrives. The initial state needs to be enabled, since
|
||
// standard shortcut handling is always wrapped inside MenusBeginning()
|
||
// and MenusEnded(), and since we update items asynchronously, we need
|
||
// to have them enabled to begin with.
|
||
fCutMenuItem->SetEnabled(true);
|
||
fCopyMenuItem->SetEnabled(true);
|
||
fPasteMenuItem->SetEnabled(true);
|
||
|
||
CurrentWebView()->WebPage()->SendEditingCapabilities();
|
||
}
|
||
}
|
||
|
||
|
||
bool
|
||
BrowserWindow::_SelectView(BWebView* view)
|
||
{/*
|
||
// TODO NEPHEL
|
||
if (view != CurrentWebView()) {
|
||
int32 viewIndex = fWebViewList->IndexOf(<BListItem>*view);
|
||
if (viewIndex < 0) {
|
||
// Page seems to be gone already?
|
||
return false;
|
||
}
|
||
fWebViewList->Select(viewIndex);
|
||
SetCurrentWebView(view);
|
||
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) {
|
||
// NOTE: Do not re-use navigationGroupBottom in the above
|
||
// check, since we only want to hide the interface when it is visible.
|
||
_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);
|
||
}
|
||
// TODO: Setting the group visible seems to unhide the status bar.
|
||
// Fix in Haiku?
|
||
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);
|
||
// TODO: This is also used in _ShowInterface. Without it the status bar
|
||
// doesn't always hide again. It may be an Interface Kit bug.
|
||
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;
|
||
// Implement new page policy
|
||
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)
|
||
{
|
||
// We have to take care of some of the escaping before we hand over the
|
||
// search string to WebKit, if we want queries like "4+3" to not be
|
||
// searched as "4 3".
|
||
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)
|
||
{
|
||
// fURLInputGroup->TextView()->SetText(url);
|
||
CurrentWebView()->LoadURL(url.String());
|
||
}
|
||
|
||
|
||
void
|
||
BrowserWindow::_VisitSearchEngine(const BString& search)
|
||
{
|
||
BString searchQuery = search;
|
||
|
||
BString searchPrefix;
|
||
search.CopyCharsInto(searchPrefix, 0, 2);
|
||
|
||
// Default search URL
|
||
BString engine(fSearchPageURL);
|
||
|
||
// Check if the string starts with one of the search engine shortcuts
|
||
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)
|
||
{
|
||
// TODO: Currenlty, only a whitespace character breaks a domain name. It
|
||
// might be a good idea (or a bad one) to make character filtering based on
|
||
// the IDNA 2008 standard.
|
||
|
||
return ch != ' ';
|
||
}
|
||
|
||
|
||
/*! \brief "smart" parser for user-entered URLs
|
||
|
||
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)
|
||
{
|
||
// First test if the URL has a protocol field
|
||
int32 at = url.FindFirst(":");
|
||
|
||
if (at != B_ERROR) {
|
||
// There is a protocol, let's see if we can handle it
|
||
BString proto;
|
||
url.CopyInto(proto, 0, at);
|
||
|
||
bool handled = false;
|
||
|
||
// First try the built-in supported ones
|
||
for (unsigned int i = 0; i < sizeof(kHandledProtocols) / sizeof(char*);
|
||
i++) {
|
||
handled = (proto == kHandledProtocols[i]);
|
||
if (handled)
|
||
break;
|
||
}
|
||
|
||
if (handled) {
|
||
// This is the easy case, a complete and well-formed URL, we can
|
||
// navigate to it without further efforts.
|
||
_VisitURL(url);
|
||
return;
|
||
} else {
|
||
// There is what looks like a protocol, but one we don't know.
|
||
// Ask the BRoster if there is a matching filetype and app which
|
||
// can handle it.
|
||
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;
|
||
}
|
||
}
|
||
|
||
// There is no protocol or only an unsupported one. So let's try harder to
|
||
// guess what the request is.
|
||
|
||
// "localhost" is a special case, it is a valid domain name but has no dots.
|
||
// Handle it separately.
|
||
if (url == "localhost")
|
||
_VisitURL("http://localhost/");
|
||
else {
|
||
// Also handle URLs starting with "localhost" followed by a path.
|
||
const char* localhostPrefix = "localhost/";
|
||
|
||
if (url.Compare(localhostPrefix, strlen(localhostPrefix)) == 0)
|
||
_VisitURL(url);
|
||
else {
|
||
// In all other cases we try to detect a valid domain name. There
|
||
// must be at least one dot and no spaces until the first / in the
|
||
// URL.
|
||
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) {
|
||
// This is apparently an URL missing the protocol part. In that
|
||
// case we default to http.
|
||
BString prefixed = "http://";
|
||
prefixed << url;
|
||
_VisitURL(prefixed);
|
||
return;
|
||
} else {
|
||
// We couldn't find anything that looks like an URL. Let's
|
||
// assume what we have is a search request and go to the search
|
||
// engine.
|
||
_VisitSearchEngine(url);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
void
|
||
BrowserWindow::_HandlePageSourceResult(const BMessage* message)
|
||
{
|
||
// TODO: This should be done in an extra thread perhaps. Doing it in
|
||
// the application thread is not much better, since it actually draws
|
||
// the pages...
|
||
|
||
BPath pathToPageSource;
|
||
|
||
BString url;
|
||
status_t ret = message->FindString("url", &url);
|
||
if (ret == B_OK && url.FindFirst("file://") == 0) {
|
||
// Local file
|
||
url.Remove(0, strlen("file://"));
|
||
pathToPageSource.SetTo(url.String());
|
||
} else {
|
||
// Something else, store it.
|
||
// TODO: What if it isn't HTML, but for example SVG?
|
||
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);
|
||
// If it fails we don't care.
|
||
}
|
||
}
|
||
|
||
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)
|
||
{
|
||
// It is not allowed to show the bookmark bar when it is empty
|
||
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();
|
||
}
|