* Renamed TextControlCompleter to TextViewCompleter, since it actually only

works with the BTextView.
* Factored out the URL text handling into a new class URLInputGroup, which is
  used instead of a plain BTextControl, but currently works much the same way.
  It's a BGroupView though and allows easy addition of other controls and items
  into the URL text field.
* Moved baseURL() method into it's own file, since it's used from multiple
  places now.

git-svn-id: http://svn.haiku-os.org/webpositive/webkit/trunk@402 94f232f2-1747-11df-bad5-a5bfde151594
This commit is contained in:
stippi 2010-04-08 12:42:58 +00:00 committed by Alexandre Deckner
parent 406b936322
commit 312655fb6f
8 changed files with 506 additions and 172 deletions

View File

@ -34,13 +34,14 @@
#include "BrowserWindow.h"
#include "AuthenticationPanel.h"
#include "BaseURL.h"
#include "BrowserApp.h"
#include "BrowsingHistory.h"
#include "IconButton.h"
#include "NavMenu.h"
#include "SettingsKeys.h"
#include "SettingsMessage.h"
#include "TextControlCompleter.h"
#include "URLInputGroup.h"
#include "WebPage.h"
#include "WebTabView.h"
#include "WebView.h"
@ -107,112 +108,6 @@ layoutItemFor(BView* view)
}
class URLChoice : public BAutoCompleter::Choice {
public:
URLChoice(const BString& choiceText, const BString& displayText,
int32 matchPos, int32 matchLen, int32 priority)
:
BAutoCompleter::Choice(choiceText, displayText, matchPos, matchLen),
fPriority(priority)
{
}
bool operator<(const URLChoice& other) const
{
if (fPriority > other.fPriority)
return true;
return DisplayText() < other.DisplayText();
}
bool operator==(const URLChoice& other) const
{
return fPriority == other.fPriority
&& DisplayText() < other.DisplayText();
}
private:
int32 fPriority;
};
static BString
baseURL(const BString string)
{
int32 baseURLStart = string.FindFirst("://") + 3;
int32 baseURLEnd = string.FindFirst("/", baseURLStart + 1);
BString result;
result.SetTo(string.String() + baseURLStart, baseURLEnd - baseURLStart);
return result;
}
class BrowsingHistoryChoiceModel : public BAutoCompleter::ChoiceModel {
virtual void FetchChoicesFor(const BString& pattern)
{
int32 count = CountChoices();
for (int32 i = 0; i < count; i++) {
delete reinterpret_cast<BAutoCompleter::Choice*>(
fChoices.ItemAtFast(i));
}
fChoices.MakeEmpty();
// Search through BrowsingHistory for any matches.
BrowsingHistory* history = BrowsingHistory::DefaultInstance();
if (!history->Lock())
return;
BString lastBaseURL;
int32 priority = INT_MAX;
count = history->CountItems();
for (int32 i = 0; i < count; i++) {
BrowsingHistoryItem item = history->HistoryItemAt(i);
const BString& choiceText = item.URL();
int32 matchPos = choiceText.IFindFirst(pattern);
if (matchPos < 0)
continue;
if (lastBaseURL.Length() > 0
&& choiceText.FindFirst(lastBaseURL) >= 0) {
priority--;
} else
priority = INT_MAX;
lastBaseURL = baseURL(choiceText);
fChoices.AddItem(new URLChoice(choiceText,
choiceText, matchPos, pattern.Length(), priority));
}
history->Unlock();
fChoices.SortItems(_CompareChoices);
}
virtual int32 CountChoices() const
{
return fChoices.CountItems();
}
virtual const BAutoCompleter::Choice* ChoiceAt(int32 index) const
{
return reinterpret_cast<BAutoCompleter::Choice*>(
fChoices.ItemAt(index));
}
static int _CompareChoices(const void* a, const void* b)
{
const URLChoice* aChoice = *reinterpret_cast<const URLChoice* const *>(a);
const URLChoice* bChoice = *reinterpret_cast<const URLChoice* const *>(b);
if (*aChoice < *bChoice)
return -1;
else if (*aChoice == *bChoice)
return 0;
return 1;
}
private:
BList fChoices;
};
class BookmarkMenu : public BNavMenu {
public:
BookmarkMenu(const char* title, BHandler* target, const entry_ref* navDir)
@ -349,8 +244,7 @@ BrowserWindow::BrowserWindow(BRect frame, SettingsMessage* appSettings,
fStopButton->TrimIcon();
// URL
fURLTextControl = new BTextControl("url", "", "", NULL);
fURLTextControl->SetDivider(50.0);
fURLInputGroup = new URLInputGroup();
// Go
fGoButton = new BButton("", "Go", new BMessage(GOTO_URL));
@ -396,7 +290,7 @@ BrowserWindow::BrowserWindow(BRect frame, SettingsMessage* appSettings,
.Add(fBackButton, 0, 0)
.Add(fForwardButton, 1, 0)
.Add(fStopButton, 2, 0)
.Add(fURLTextControl, 3, 0)
.Add(fURLInputGroup, 3, 0)
.Add(fGoButton, 4, 0)
.SetInsets(kInsetSpacing, kInsetSpacing, kInsetSpacing, kInsetSpacing)
)
@ -423,10 +317,7 @@ BrowserWindow::BrowserWindow(BRect frame, SettingsMessage* appSettings,
.Add(statusGroup)
);
fURLTextControl->MakeFocus(true);
fURLAutoCompleter = new TextControlCompleter(fURLTextControl,
new BrowsingHistoryChoiceModel());
fURLInputGroup->MakeFocus(true);
fMenuGroup = layoutItemFor(mainMenu);
fTabGroup = layoutItemFor(fTabManager->TabGroup());
@ -471,7 +362,6 @@ BrowserWindow::BrowserWindow(BRect frame, SettingsMessage* appSettings,
BrowserWindow::~BrowserWindow()
{
fAppSettings->RemoveListener(BMessenger(this));
delete fURLAutoCompleter;
delete fTabManager;
}
@ -484,7 +374,7 @@ BrowserWindow::DispatchMessage(BMessage* message, BHandler* target)
if ((message->what == B_KEY_DOWN || message->what == B_UNMAPPED_KEY_DOWN)
&& message->FindString("bytes", &bytes) == B_OK
&& message->FindInt32("modifiers", &modifiers) == B_OK) {
if (fURLTextControl && target == fURLTextControl->TextView()) {
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
@ -512,12 +402,10 @@ BrowserWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case OPEN_LOCATION:
if (fURLTextControl) {
if (fURLTextControl->TextView()->IsFocus())
fURLTextControl->TextView()->SelectAll();
else
fURLTextControl->MakeFocus(true);
}
if (fURLInputGroup->TextView()->IsFocus())
fURLInputGroup->TextView()->SelectAll();
else
fURLInputGroup->MakeFocus(true);
break;
case RELOAD:
CurrentWebView()->Reload();
@ -526,7 +414,7 @@ BrowserWindow::MessageReceived(BMessage* message)
{
BString url;
if (message->FindString("url", &url) != B_OK)
url = fURLTextControl->Text();
url = fURLInputGroup->Text();
fTabManager->SetTabIcon(CurrentWebView(), NULL);
CurrentWebView()->LoadURL(url.String());
break;
@ -889,10 +777,8 @@ BrowserWindow::CreateNewTab(const BString& url, bool select, BWebView* webView)
fTabManager->SelectTab(fTabManager->CountTabs() - 1);
SetCurrentWebView(webView);
webView->WebPage()->ResendNotifications();
if (fURLTextControl) {
fURLTextControl->SetText(url.String());
fURLTextControl->MakeFocus(true);
}
fURLInputGroup->SetText(url.String());
fURLInputGroup->MakeFocus(true);
}
_UpdateTabGroupVisibility();
@ -967,8 +853,7 @@ BrowserWindow::LoadCommitted(const BString& url, BWebView* view)
return;
// This hook is invoked when the load is commited.
if (fURLTextControl)
fURLTextControl->SetText(url.String());
fURLInputGroup->SetText(url.String());
BString status("Loading: ");
status << url;
@ -1170,7 +1055,7 @@ BrowserWindow::AuthenticationChallenge(BString message, BString& inOutUser,
if (view != CurrentWebView()) {
int32 tabIndex = fTabManager->TabForView(view);
if (tabIndex < 0) {
// page seems to be gone already?
// Page seems to be gone already?
return false;
}
fTabManager->SelectTab(tabIndex);
@ -1245,7 +1130,7 @@ BrowserWindow::_TabChanged(int32 index)
else
webView->MakeFocus(true);
fURLTextControl->SetText(webView->MainFrameURL());
fURLInputGroup->SetText(webView->MainFrameURL());
// Trigger update of the interface to the new page, by requesting
// to resend all notifications.
webView->WebPage()->ResendNotifications();

View File

@ -49,7 +49,7 @@ class BWebView;
class IconButton;
class SettingsMessage;
class TabManager;
class TextControlCompleter;
class URLInputGroup;
enum ToolbarPolicy {
HaveToolbar,
@ -150,8 +150,7 @@ private:
IconButton* fForwardButton;
IconButton* fStopButton;
BButton* fGoButton;
BTextControl* fURLTextControl;
TextControlCompleter* fURLAutoCompleter;
URLInputGroup* fURLInputGroup;
BStringView* fStatusText;
BStatusBar* fLoadingProgressBar;

View File

@ -0,0 +1,384 @@
/*
* Copyright 2010 Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "URLInputGroup.h"
#include <ControlLook.h>
#include <GroupLayout.h>
#include <GroupLayoutBuilder.h>
#include <LayoutUtils.h>
#include <MenuItem.h>
#include <PopUpMenu.h>
#include <TextView.h>
#include <Window.h>
#include <stdio.h>
#include <stdlib.h>
#include "BaseURL.h"
#include "BrowsingHistory.h"
#include "IconButton.h"
#include "TextViewCompleter.h"
class URLChoice : public BAutoCompleter::Choice {
public:
URLChoice(const BString& choiceText, const BString& displayText,
int32 matchPos, int32 matchLen, int32 priority)
:
BAutoCompleter::Choice(choiceText, displayText, matchPos, matchLen),
fPriority(priority)
{
}
bool operator<(const URLChoice& other) const
{
if (fPriority > other.fPriority)
return true;
return DisplayText() < other.DisplayText();
}
bool operator==(const URLChoice& other) const
{
return fPriority == other.fPriority
&& DisplayText() < other.DisplayText();
}
private:
int32 fPriority;
};
class BrowsingHistoryChoiceModel : public BAutoCompleter::ChoiceModel {
virtual void FetchChoicesFor(const BString& pattern)
{
int32 count = CountChoices();
for (int32 i = 0; i < count; i++) {
delete reinterpret_cast<BAutoCompleter::Choice*>(
fChoices.ItemAtFast(i));
}
fChoices.MakeEmpty();
// Search through BrowsingHistory for any matches.
BrowsingHistory* history = BrowsingHistory::DefaultInstance();
if (!history->Lock())
return;
BString lastBaseURL;
int32 priority = INT_MAX;
count = history->CountItems();
for (int32 i = 0; i < count; i++) {
BrowsingHistoryItem item = history->HistoryItemAt(i);
const BString& choiceText = item.URL();
int32 matchPos = choiceText.IFindFirst(pattern);
if (matchPos < 0)
continue;
if (lastBaseURL.Length() > 0
&& choiceText.FindFirst(lastBaseURL) >= 0) {
priority--;
} else
priority = INT_MAX;
lastBaseURL = baseURL(choiceText);
fChoices.AddItem(new URLChoice(choiceText,
choiceText, matchPos, pattern.Length(), priority));
}
history->Unlock();
fChoices.SortItems(_CompareChoices);
}
virtual int32 CountChoices() const
{
return fChoices.CountItems();
}
virtual const BAutoCompleter::Choice* ChoiceAt(int32 index) const
{
return reinterpret_cast<BAutoCompleter::Choice*>(
fChoices.ItemAt(index));
}
static int _CompareChoices(const void* a, const void* b)
{
const URLChoice* aChoice
= *reinterpret_cast<const URLChoice* const *>(a);
const URLChoice* bChoice
= *reinterpret_cast<const URLChoice* const *>(b);
if (*aChoice < *bChoice)
return -1;
else if (*aChoice == *bChoice)
return 0;
return 1;
}
private:
BList fChoices;
};
// #pragma mark - URLTextView
static const float kHorizontalTextRectInset = 3.0;
class URLInputGroup::URLTextView : public BTextView {
public:
URLTextView(URLInputGroup* parent);
virtual ~URLTextView();
virtual void FrameResized(float width, float height);
virtual void MouseDown(BPoint where);
virtual void KeyDown(const char* bytes, int32 numBytes);
virtual void MakeFocus(bool focused = true);
virtual BSize MinSize();
virtual BSize MaxSize();
protected:
virtual void InsertText(const char* inText, int32 inLength,
int32 inOffset,
const text_run_array* inRuns);
private:
void _AlignTextRect();
private:
URLInputGroup* fURLInputGroup;
TextViewCompleter* fURLAutoCompleter;
BString fPreviousText;
};
URLInputGroup::URLTextView::URLTextView(URLInputGroup* parent)
:
BTextView("url"),
fURLInputGroup(parent),
fURLAutoCompleter(new TextViewCompleter(this,
new BrowsingHistoryChoiceModel())),
fPreviousText("")
{
MakeResizable(true);
}
URLInputGroup::URLTextView::~URLTextView()
{
delete fURLAutoCompleter;
}
void
URLInputGroup::URLTextView::FrameResized(float width, float height)
{
BTextView::FrameResized(width, height);
_AlignTextRect();
}
void
URLInputGroup::URLTextView::MouseDown(BPoint where)
{
if (!IsFocus()) {
MakeFocus(true);
return;
}
// Only pass through to base class if we already have focus.
BTextView::MouseDown(where);
}
void
URLInputGroup::URLTextView::KeyDown(const char* bytes, int32 numBytes)
{
switch (bytes[0]) {
case B_TAB:
BView::KeyDown(bytes, numBytes);
break;
case B_ESCAPE:
// Revert to text as it was when we received keyboard focus.
SetText(fPreviousText.String());
SelectAll();
break;
default:
BTextView::KeyDown(bytes, numBytes);
break;
}
}
void
URLInputGroup::URLTextView::MakeFocus(bool focus)
{
if (focus == IsFocus())
return;
BTextView::MakeFocus(focus);
if (focus) {
fPreviousText = Text();
SelectAll();
}
fURLInputGroup->Invalidate();
}
BSize
URLInputGroup::URLTextView::MinSize()
{
BSize min;
min.height = ceilf(LineHeight(0) + kHorizontalTextRectInset);
// we always add at least one pixel vertical inset top/bottom for
// the text rect.
min.width = min.height * 3;
return BLayoutUtils::ComposeSize(ExplicitMinSize(), min);
}
BSize
URLInputGroup::URLTextView::MaxSize()
{
BSize max(MinSize());
max.width = B_SIZE_UNLIMITED;
return BLayoutUtils::ComposeSize(ExplicitMaxSize(), max);
}
void
URLInputGroup::URLTextView::InsertText(const char* inText, int32 inLength,
int32 inOffset, const text_run_array* inRuns)
{
char* buffer = NULL;
if (strpbrk(inText, "\r\n") && inLength <= 1024) {
buffer = (char*)malloc(inLength);
if (buffer) {
strcpy(buffer, inText);
for (int32 i = 0; i < inLength; i++) {
if (buffer[i] == '\r' || buffer[i] == '\n')
buffer[i] = ' ';
}
}
}
BTextView::InsertText(buffer ? buffer : inText, inLength, inOffset,
inRuns);
free(buffer);
}
void
URLInputGroup::URLTextView::_AlignTextRect()
{
// Layout the text rect to be in the middle, normally this means there
// is one pixel spacing on each side.
BRect textRect(Bounds());
textRect.left = 0.0;
float vInset = max_c(1,
floorf((textRect.Height() - LineHeight(0)) / 2.0 + 0.5));
float hInset = kHorizontalTextRectInset;
if (be_control_look)
hInset = be_control_look->DefaultLabelSpacing();
textRect.InsetBy(hInset, vInset);
SetTextRect(textRect);
}
// #pragma mark - URLInputGroup
URLInputGroup::URLInputGroup()
:
BGroupView(B_HORIZONTAL),
fWindowActive(false)
{
GroupLayout()->SetInsets(2, 2, 2, 2);
fTextView = new URLTextView(this);
AddChild(fTextView);
SetFlags(Flags() | B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
SetLowColor(ViewColor());
SetViewColor(B_TRANSPARENT_COLOR);
SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH,
B_ALIGN_VERTICAL_CENTER));
}
URLInputGroup::~URLInputGroup()
{
}
void
URLInputGroup::AttachedToWindow()
{
BGroupView::AttachedToWindow();
fWindowActive = Window()->IsActive();
}
void
URLInputGroup::WindowActivated(bool active)
{
BGroupView::WindowActivated(active);
if (fWindowActive != active) {
fWindowActive = active;
Invalidate();
}
}
void
URLInputGroup::Draw(BRect updateRect)
{
BRect bounds(Bounds());
rgb_color base(LowColor());
uint32 flags = 0;
if (fWindowActive && fTextView->IsFocus())
flags |= BControlLook::B_FOCUSED;
be_control_look->DrawTextControlBorder(this, bounds, updateRect, base,
flags);
}
void
URLInputGroup::MakeFocus(bool focus)
{
// Forward this to the text view, we never accept focus ourselves.
fTextView->MakeFocus(focus);
}
BTextView*
URLInputGroup::TextView() const
{
return fTextView;
}
void
URLInputGroup::SetText(const char* text)
{
fTextView->SetText(text);
}
const char*
URLInputGroup::Text() const
{
return fTextView->Text();
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2010 Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef URL_INPUT_GROUP_H
#define URL_INPUT_GROUP_H
#include <GroupView.h>
class BTextView;
class URLInputGroup : public BGroupView {
public:
URLInputGroup();
virtual ~URLInputGroup();
virtual void AttachedToWindow();
virtual void WindowActivated(bool active);
virtual void Draw(BRect updateRect);
virtual void MakeFocus(bool focus = true);
BTextView* TextView() const;
void SetText(const char* text);
const char* Text() const;
private:
class URLTextView;
URLTextView* fTextView;
bool fWindowActive;
};
#endif // URL_INPUT_GROUP_H

View File

@ -6,7 +6,7 @@
* Oliver Tappe <beam@hirschkaefer.de>
*/
#include "TextControlCompleter.h"
#include "TextViewCompleter.h"
#include <Looper.h>
#include <TextControl.h>
@ -15,75 +15,74 @@
#include "AutoCompleterDefaultImpl.h"
// #pragma mark - TextControlWrapper
// #pragma mark - TextViewWrapper
TextControlCompleter::TextControlWrapper::TextControlWrapper(
BTextControl* textControl)
TextViewCompleter::TextViewWrapper::TextViewWrapper(BTextView* textView)
:
fTextControl(textControl)
fTextView(textView)
{
}
void
TextControlCompleter::TextControlWrapper::GetEditViewState(BString& text,
TextViewCompleter::TextViewWrapper::GetEditViewState(BString& text,
int32* caretPos)
{
if (fTextControl && fTextControl->LockLooper()) {
text = fTextControl->Text();
if (fTextView && fTextView->LockLooper()) {
text = fTextView->Text();
if (caretPos) {
int32 end;
fTextControl->TextView()->GetSelection(caretPos, &end);
fTextView->GetSelection(caretPos, &end);
}
fTextControl->UnlockLooper();
fTextView->UnlockLooper();
}
}
void
TextControlCompleter::TextControlWrapper::SetEditViewState(const BString& text,
TextViewCompleter::TextViewWrapper::SetEditViewState(const BString& text,
int32 caretPos, int32 selectionLength)
{
if (fTextControl && fTextControl->LockLooper()) {
fTextControl->TextView()->SetText(text.String(), text.Length());
fTextControl->TextView()->Select(caretPos, caretPos + selectionLength);
fTextControl->TextView()->ScrollToSelection();
fTextControl->UnlockLooper();
if (fTextView && fTextView->LockLooper()) {
fTextView->SetText(text.String(), text.Length());
fTextView->Select(caretPos, caretPos + selectionLength);
fTextView->ScrollToSelection();
fTextView->UnlockLooper();
}
}
BRect
TextControlCompleter::TextControlWrapper::GetAdjustmentFrame()
TextViewCompleter::TextViewWrapper::GetAdjustmentFrame()
{
BRect frame = fTextControl->TextView()->Bounds();
frame = fTextControl->TextView()->ConvertToScreen(frame);
BRect frame = fTextView->Bounds();
frame = fTextView->ConvertToScreen(frame);
frame.InsetBy(0, -3);
return frame;
}
TextControlCompleter::TextControlCompleter(BTextControl* textControl,
ChoiceModel* model, PatternSelector* patternSelector)
TextViewCompleter::TextViewCompleter(BTextView* textView, ChoiceModel* model,
PatternSelector* patternSelector)
:
BAutoCompleter(new TextControlWrapper(textControl), model,
BAutoCompleter(new TextViewWrapper(textView), model,
new BDefaultChoiceView(), patternSelector),
BMessageFilter(B_KEY_DOWN),
fTextControl(textControl)
fTextView(textView)
{
fTextControl->TextView()->AddFilter(this);
fTextView->AddFilter(this);
}
TextControlCompleter::~TextControlCompleter()
TextViewCompleter::~TextViewCompleter()
{
fTextControl->TextView()->RemoveFilter(this);
fTextView->RemoveFilter(this);
}
filter_result
TextControlCompleter::Filter(BMessage* message, BHandler** target)
TextViewCompleter::Filter(BMessage* message, BHandler** target)
{
const char* bytes;
int32 modifiers;
@ -91,7 +90,7 @@ TextControlCompleter::Filter(BMessage* message, BHandler** target)
|| message->FindInt32("modifiers", &modifiers) != B_OK) {
return B_DISPATCH_MESSAGE;
}
switch (bytes[0]) {
case B_UP_ARROW:
SelectPrevious();

View File

@ -13,31 +13,31 @@
#include "AutoCompleter.h"
class BTextControl;
class BTextView;
class TextControlCompleter : protected BAutoCompleter, public BMessageFilter {
class TextViewCompleter : protected BAutoCompleter, public BMessageFilter {
public:
TextControlCompleter(BTextControl* textControl,
TextViewCompleter(BTextView* textView,
ChoiceModel* choiceModel = NULL,
PatternSelector* patternSelector = NULL);
virtual ~TextControlCompleter();
virtual ~TextViewCompleter();
private:
virtual filter_result Filter(BMessage* message, BHandler** target);
class TextControlWrapper : public EditView {
class TextViewWrapper : public EditView {
public:
TextControlWrapper(BTextControl* textControl);
TextViewWrapper(BTextView* textView);
virtual BRect GetAdjustmentFrame();
virtual void GetEditViewState(BString& text,
int32* caretPos);
virtual void SetEditViewState(const BString& text,
int32 caretPos, int32 selectionLength = 0);
private:
BTextControl* fTextControl;
BTextView* fTextView;
};
private:
BTextControl* fTextControl;
BTextView* fTextView;
};
#endif // TEXT_CONTROL_COMPLETER_H

View File

@ -0,0 +1,18 @@
/*
* Copyright 2010 Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "BaseURL.h"
BString
baseURL(const BString string)
{
int32 baseURLStart = string.FindFirst("://") + 3;
int32 baseURLEnd = string.FindFirst("/", baseURLStart + 1);
BString result;
result.SetTo(string.String() + baseURLStart, baseURLEnd - baseURLStart);
return result;
}

View File

@ -0,0 +1,14 @@
/*
* Copyright 2010 Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef BASE_URL_H
#define BASE_URL_H
#include <String.h>
BString baseURL(const BString string);
#endif // BASE_URL_H