root/src/apps/webpositive/tabview/TabManager.cpp
/*
 * Copyright (C) 2010 Rene Gollent <rene@gollent.com>
 * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
 *
 * All rights reserved. Distributed under the terms of the MIT License.
 */

#include "TabManager.h"

#include <stdio.h>

#include <new>

#include <Application.h>
#include <AbstractLayoutItem.h>
#include <Bitmap.h>
#include <Button.h>
#include <CardLayout.h>
#include <ControlLook.h>
#include <Catalog.h>
#include <GroupView.h>
#include <MenuBar.h>
#include <MenuItem.h>
#include <PopUpMenu.h>
#include <Rect.h>
#include <SpaceLayoutItem.h>
#include <Window.h>

#include "TabContainerView.h"
#include "TabView.h"


#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Tab Manager"


const static BString kEmptyString;


// #pragma mark - Helper classes


class TabButton : public BButton {
public:
        TabButton(BMessage* message)
                : BButton("", message)
        {
        }

        virtual BSize MinSize()
        {
                return BSize(12, 12);
        }

        virtual BSize MaxSize()
        {
                return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
        }

        virtual BSize PreferredSize()
        {
                return MinSize();
        }

        virtual void Draw(BRect updateRect)
        {
                BRect bounds(Bounds());
                rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
                uint32 flags = be_control_look->Flags(this);
                uint32 borders = BControlLook::B_TOP_BORDER
                        | BControlLook::B_BOTTOM_BORDER;
                be_control_look->DrawTabFrame(this, bounds, updateRect, base,
                        0, borders, B_NO_BORDER);
                if (IsEnabled()) {
                        rgb_color button = tint_color(base, 1.07);
                        be_control_look->DrawButtonBackground(this, bounds, updateRect,
                                button, flags, 0);
                }

                BRect symbolRect(bounds);
                symbolRect.left = (symbolRect.left + symbolRect.right) / 2 - 6;
                symbolRect.top = (symbolRect.top + symbolRect.bottom) / 2 - 6;
                symbolRect.right = symbolRect.left + 12;
                symbolRect.bottom = symbolRect.top + 12;
                DrawSymbol(symbolRect, updateRect, base);
        }

        virtual void DrawSymbol(BRect frame, const BRect& updateRect,
                const rgb_color& base)
        {
        }
};


class ScrollLeftTabButton : public TabButton {
public:
        ScrollLeftTabButton(BMessage* message)
                : TabButton(message)
        {
        }

        virtual void DrawSymbol(BRect frame, const BRect& updateRect,
                const rgb_color& base)
        {
                float tint = IsEnabled() ? B_DARKEN_4_TINT : B_DARKEN_1_TINT;
                be_control_look->DrawArrowShape(this, frame, updateRect,
                        base, BControlLook::B_LEFT_ARROW, 0, tint);
        }
};


class ScrollRightTabButton : public TabButton {
public:
        ScrollRightTabButton(BMessage* message)
                : TabButton(message)
        {
        }

        virtual void DrawSymbol(BRect frame, const BRect& updateRect,
                const rgb_color& base)
        {
                frame.OffsetBy(1, 0);
                float tint = IsEnabled() ? B_DARKEN_4_TINT : B_DARKEN_1_TINT;
                be_control_look->DrawArrowShape(this, frame, updateRect,
                        base, BControlLook::B_RIGHT_ARROW, 0, tint);
        }
};


class NewTabButton : public TabButton {
public:
        NewTabButton(BMessage* message)
                : TabButton(message)
        {
                SetToolTip("New tab (Cmd-T)");
        }

        virtual BSize MinSize()
        {
                return BSize(18, 12);
        }

        virtual void DrawSymbol(BRect frame, const BRect& updateRect,
                const rgb_color& base)
        {
                SetHighColor(tint_color(base, B_DARKEN_4_TINT));
                float inset = 3;
                frame.InsetBy(2, 2);
                frame.top++;
                frame.left++;
                FillRoundRect(BRect(frame.left, frame.top + inset,
                        frame.right, frame.bottom - inset), 1, 1);
                FillRoundRect(BRect(frame.left + inset, frame.top,
                        frame.right - inset, frame.bottom), 1, 1);
        }
};


class TabMenuTabButton : public TabButton {
public:
        TabMenuTabButton(BMessage* message)
                : TabButton(message)
                , fCloseTime(0)
        {
        }

        virtual BSize MinSize()
        {
                return BSize(18, 12);
        }

        virtual void DrawSymbol(BRect frame, const BRect& updateRect,
                const rgb_color& base)
        {
                be_control_look->DrawArrowShape(this, frame, updateRect,
                        base, BControlLook::B_DOWN_ARROW, 0, B_DARKEN_4_TINT);
        }

        virtual void MouseDown(BPoint point)
        {
                // Don't reopen the menu if it's already open or freshly closed.
                bigtime_t clickSpeed = 2000000;
                get_click_speed(&clickSpeed);
                bigtime_t clickTime = Window()->CurrentMessage()->FindInt64("when");
                if (!IsEnabled() || (Value() == B_CONTROL_ON)
                        || clickTime < fCloseTime + clickSpeed) {
                        return;
                }

                // Invoke must be called before setting B_CONTROL_ON
                // for the button to stay "down"
                Invoke();
                SetValue(B_CONTROL_ON);
        }

        virtual void MouseUp(BPoint point)
        {
                // Do nothing
        }

        void MenuClosed()
        {
                fCloseTime = system_time();
                SetValue(B_CONTROL_OFF);
        }

private:
        bigtime_t fCloseTime;
};


enum {
        MSG_SCROLL_TABS_LEFT    = 'stlt',
        MSG_SCROLL_TABS_RIGHT   = 'strt',
        MSG_OPEN_TAB_MENU               = 'otmn'
};


class TabContainerGroup : public BGroupView {
public:
        TabContainerGroup(TabContainerView* tabContainerView)
                :
                BGroupView(B_HORIZONTAL, 0.0),
                fTabContainerView(tabContainerView),
                fScrollLeftTabButton(NULL),
                fScrollRightTabButton(NULL),
                fTabMenuButton(NULL)
        {
        }

        virtual void AttachedToWindow()
        {
                if (fScrollLeftTabButton != NULL)
                        fScrollLeftTabButton->SetTarget(this);
                if (fScrollRightTabButton != NULL)
                        fScrollRightTabButton->SetTarget(this);
                if (fTabMenuButton != NULL)
                        fTabMenuButton->SetTarget(this);
        }

        virtual void MessageReceived(BMessage* message)
        {
                if (fTabContainerView == NULL)
                        return BGroupView::MessageReceived(message);

                switch (message->what) {
                        case MSG_SCROLL_TABS_LEFT:
                                fTabContainerView->SetFirstVisibleTabIndex(
                                        fTabContainerView->FirstVisibleTabIndex() - 1);
                                break;

                        case MSG_SCROLL_TABS_RIGHT:
                                fTabContainerView->SetFirstVisibleTabIndex(
                                        fTabContainerView->FirstVisibleTabIndex() + 1);
                                break;

                        case MSG_OPEN_TAB_MENU:
                        {
                                BPopUpMenu* tabMenu = new BPopUpMenu("tab menu", true, false);
                                int tabCount = fTabContainerView->GetLayout()->CountItems();
                                for (int i = 0; i < tabCount; i++) {
                                        TabView* tab = fTabContainerView->TabAt(i);
                                        if (tab != NULL) {
                                                BMenuItem* item = new(std::nothrow)
                                                        BMenuItem(tab->Label(), NULL);
                                                if (item != NULL) {
                                                        tabMenu->AddItem(item);
                                                        if (i == fTabContainerView->SelectedTabIndex())
                                                                item->SetMarked(true);
                                                }
                                        }
                                }

                                // Force layout to get the final menu size. InvalidateLayout()
                                // did not seem to work here.
                                tabMenu->AttachedToWindow();
                                BRect buttonFrame = fTabMenuButton->Frame();
                                BRect menuFrame = tabMenu->Frame();
                                BPoint openPoint = ConvertToScreen(buttonFrame.LeftBottom());
                                // Open with the right side of the menu aligned with the right
                                // side of the button and a little below.
                                openPoint.x -= menuFrame.Width() - buttonFrame.Width();
                                openPoint.y += 2;

                                BMenuItem *selected = tabMenu->Go(openPoint, false, false,
                                        ConvertToScreen(buttonFrame));
                                if (selected) {
                                        selected->SetMarked(true);
                                        int32 index = tabMenu->IndexOf(selected);
                                        if (index != B_ERROR)
                                                fTabContainerView->SelectTab(index);
                                }
                                fTabMenuButton->MenuClosed();
                                delete tabMenu;

                                break;
                        }

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

        void AddScrollLeftButton(TabButton* button)
        {
                fScrollLeftTabButton = button;
                GroupLayout()->AddView(button, 0.0f);
        }

        void AddScrollRightButton(TabButton* button)
        {
                fScrollRightTabButton = button;
                GroupLayout()->AddView(button, 0.0f);
        }

        void AddTabMenuButton(TabMenuTabButton* button)
        {
                fTabMenuButton = button;
                GroupLayout()->AddView(button, 0.0f);
        }

        void EnableScrollButtons(bool canScrollLeft, bool canScrollRight)
        {
                fScrollLeftTabButton->SetEnabled(canScrollLeft);
                fScrollRightTabButton->SetEnabled(canScrollRight);
                if (!canScrollLeft && !canScrollRight) {
                        // hide scroll buttons
                } else {
                        // show scroll buttons
                }
        }

private:
        TabContainerView*       fTabContainerView;
        TabButton*                      fScrollLeftTabButton;
        TabButton*                      fScrollRightTabButton;
        TabMenuTabButton*       fTabMenuButton;
};


class TabButtonContainer : public BGroupView {
public:
        TabButtonContainer()
                :
                BGroupView(B_HORIZONTAL, 0.0)
        {
                SetFlags(Flags() | B_WILL_DRAW);
                SetViewColor(B_TRANSPARENT_COLOR);
                SetLowUIColor(B_PANEL_BACKGROUND_COLOR);
                GroupLayout()->SetInsets(0, 6, 0, 0);
        }

        virtual void Draw(BRect updateRect)
        {
                // draw nothing
        }
};


class TabManagerController : public TabContainerView::Controller {
public:
        TabManagerController(TabManager* manager);

        virtual ~TabManagerController();

        virtual void UpdateSelection(int32 index)
        {
                fManager->SelectTab(index);
        }

        virtual bool HasFrames()
        {
                return false;
        }

        virtual TabView* CreateTabView();

        virtual void DoubleClickOutsideTabs();

        virtual void UpdateTabScrollability(bool canScrollLeft,
                bool canScrollRight)
        {
                fTabContainerGroup->EnableScrollButtons(canScrollLeft, canScrollRight);
        }

        virtual void SetToolTip(const BString& text)
        {
                if (fCurrentToolTip == text)
                        return;

                fCurrentToolTip = text;
                fManager->GetTabContainerView()->HideToolTip();
                fManager->GetTabContainerView()->SetToolTip(
                        reinterpret_cast<BToolTip*>(NULL));
                fManager->GetTabContainerView()->SetToolTip(fCurrentToolTip.String());
        }

        void CloseTab(int32 index);

        void SetDoubleClickOutsideTabsMessage(const BMessage& message,
                const BMessenger& target);

        void SetTabContainerGroup(TabContainerGroup* tabContainerGroup)
        {
                fTabContainerGroup = tabContainerGroup;
        }

private:
        TabManager*                     fManager;
        TabContainerGroup*      fTabContainerGroup;
        BMessage*                       fDoubleClickOutsideTabsMessage;
        BMessenger                      fTarget;
        BString                         fCurrentToolTip;
};


// #pragma mark - WebTabView


class WebTabView : public TabView {
public:
        WebTabView(TabManagerController* controller);
        ~WebTabView();

        virtual BSize MaxSize();

        virtual void DrawContents(BView* owner, BRect frame,
                const BRect& updateRect);

        virtual void MouseDown(BPoint where, uint32 buttons);
        virtual void MouseUp(BPoint where);
        virtual void MouseMoved(BPoint where, uint32 transit,
                const BMessage* dragMessage);

        void SetIcon(const BBitmap* icon);

private:
        void _DrawCloseButton(BView* owner, BRect& frame, const BRect& updateRect);
        BRect _CloseRectFrame(BRect frame) const;

private:
        BBitmap* fIcon;
        TabManagerController* fController;
        bool fOverCloseRect;
        bool fClicked;
};


WebTabView::WebTabView(TabManagerController* controller)
        :
        TabView(),
        fIcon(NULL),
        fController(controller),
        fOverCloseRect(false),
        fClicked(false)
{
}


WebTabView::~WebTabView()
{
        delete fIcon;
}


static const int kIconSize = 18;
static const int kIconInset = 3;


BSize
WebTabView::MaxSize()
{
        // Account for icon.
        BSize size(TabView::MaxSize());
        size.height = max_c(size.height, kIconSize + kIconInset * 2);
        if (fIcon)
                size.width += kIconSize + kIconInset * 2;
        // Account for close button.
        size.width += size.height;
        return size;
}


void
WebTabView::DrawContents(BView* owner, BRect frame, const BRect& updateRect)
{
        _DrawCloseButton(owner, frame, updateRect);

        if (fIcon != NULL) {
                BRect iconBounds(0, 0, kIconSize - 1, kIconSize - 1);
                // clip to icon bounds, if they are smaller
                if (iconBounds.Contains(fIcon->Bounds()))
                        iconBounds = fIcon->Bounds();
                else {
                        // Try to scale down the icon by an even factor so the
                        // final size is between 14 and 18 pixel size. If this fails,
                        // the icon will simply be displayed at 18x18.
                        float scale = 2;
                        while ((fIcon->Bounds().Width() + 1) / scale > kIconSize)
                                scale *= 2;
                        if ((fIcon->Bounds().Width() + 1) / scale >= kIconSize - 4
                                && (fIcon->Bounds().Height() + 1) / scale >= kIconSize - 4
                                && (fIcon->Bounds().Height() + 1) / scale <= kIconSize) {
                                iconBounds.right = (fIcon->Bounds().Width() + 1) / scale - 1;
                                iconBounds.bottom = (fIcon->Bounds().Height() + 1) / scale - 1;
                        }
                }
                // account for borders
                frame.top -= 2.0f;
                BPoint iconPos(frame.left + kIconInset - 1,
                        frame.top + floorf((frame.Height() - iconBounds.Height()) / 2));
                iconBounds.OffsetTo(iconPos);
                owner->SetDrawingMode(B_OP_ALPHA);
                owner->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
                owner->DrawBitmap(fIcon, fIcon->Bounds(), iconBounds,
                        B_FILTER_BITMAP_BILINEAR);
                owner->SetDrawingMode(B_OP_COPY);
                frame.left = frame.left + kIconSize + kIconInset * 2;
        }

        TabView::DrawContents(owner, frame, updateRect);
}


void
WebTabView::MouseDown(BPoint where, uint32 buttons)
{
        if (buttons & B_TERTIARY_MOUSE_BUTTON) {
                // Immediately close tab
                fController->CloseTab(ContainerView()->IndexOf(this));
                return;
        }

        BRect closeRect = _CloseRectFrame(Frame());
        if (!closeRect.Contains(where)) {
                TabView::MouseDown(where, buttons);
                return;
        }

        fClicked = true;
        ContainerView()->Invalidate(closeRect);
}


void
WebTabView::MouseUp(BPoint where)
{
        if (!fClicked) {
                TabView::MouseUp(where);
                return;
        }

        fClicked = false;

        if (_CloseRectFrame(Frame()).Contains(where))
                fController->CloseTab(ContainerView()->IndexOf(this));
}


void
WebTabView::MouseMoved(BPoint where, uint32 transit,
        const BMessage* dragMessage)
{
        BRect closeRect = _CloseRectFrame(Frame());
        bool overCloseRect = closeRect.Contains(where);

        if (overCloseRect != fOverCloseRect) {
                fOverCloseRect = overCloseRect;
                ContainerView()->Invalidate(closeRect);
        }

        // Set the tool tip
        fController->SetToolTip(overCloseRect ? "" : Label());

        TabView::MouseMoved(where, transit, dragMessage);
}


void
WebTabView::SetIcon(const BBitmap* icon)
{
        delete fIcon;
        if (icon)
                fIcon = new BBitmap(icon);
        else
                fIcon = NULL;
        LayoutItem()->InvalidateLayout();
}


BRect
WebTabView::_CloseRectFrame(BRect frame) const
{
        frame.left = frame.right - frame.Height();
        return frame;
}


void
WebTabView::_DrawCloseButton(BView* owner, BRect& frame,
        const BRect& updateRect)
{
        BRect closeRect = _CloseRectFrame(frame);
        frame.right = closeRect.left - be_control_look->DefaultLabelSpacing();

        closeRect.left = (closeRect.left + closeRect.right) / 2 - 3;
        closeRect.right = closeRect.left + 6;
        closeRect.top = (closeRect.top + closeRect.bottom) / 2 - 3;
        closeRect.bottom = closeRect.top + 6;

        rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
        
        float tint;
        if (base.IsLight())
                tint = B_DARKEN_1_TINT;
        else
                tint = 0.50;

        float isFront = ContainerView()->SelectedTab() == static_cast<TabView*>(this);
        
        if (base.IsLight()){
                if (!isFront) {
                        base = tint_color(base, tint);
                        tint *= 1.02;
                }

                if (fOverCloseRect)
                        tint *= 1.4;
                else
                        tint *= 1.2;
        } else {
                if (!isFront) {
                        base = tint_color(base, tint);
                        tint *= 0.80;
                }

                if (fOverCloseRect)
                        tint *= 0.6;
                else
                        tint *= 0.9;
        }

        if (fClicked && fOverCloseRect) {
                // Draw the button frame
                BRect buttonRect(closeRect.InsetByCopy(-4, -4));
                be_control_look->DrawButtonFrame(owner, buttonRect, updateRect,
                        base, base,
                        BControlLook::B_ACTIVATED | BControlLook::B_BLEND_FRAME);
                be_control_look->DrawButtonBackground(owner, buttonRect, updateRect,
                        base, BControlLook::B_ACTIVATED);
                closeRect.OffsetBy(1, 1);
                tint *= 1.2;
        }

        // Draw the ×
        base = tint_color(base, tint);
        owner->SetHighColor(base);
        owner->SetPenSize(2);
        owner->StrokeLine(closeRect.LeftTop(), closeRect.RightBottom());
        owner->StrokeLine(closeRect.LeftBottom(), closeRect.RightTop());
        owner->SetPenSize(1);
}


// #pragma mark - TabManagerController


TabManagerController::TabManagerController(TabManager* manager)
        :
        fManager(manager),
        fTabContainerGroup(NULL),
        fDoubleClickOutsideTabsMessage(NULL)
{
}


TabManagerController::~TabManagerController()
{
        delete fDoubleClickOutsideTabsMessage;
}


TabView*
TabManagerController::CreateTabView()
{
        return new WebTabView(this);
}


void
TabManagerController::DoubleClickOutsideTabs()
{
        fTarget.SendMessage(fDoubleClickOutsideTabsMessage);
}


void
TabManagerController::CloseTab(int32 index)
{
        fManager->CloseTab(index);
}


void
TabManagerController::SetDoubleClickOutsideTabsMessage(const BMessage& message,
        const BMessenger& target)
{
        delete fDoubleClickOutsideTabsMessage;
        fDoubleClickOutsideTabsMessage = new BMessage(message);
        fTarget = target;
}


// #pragma mark - TabManager


TabManager::TabManager(const BMessenger& target, BMessage* newTabMessage)
        :
        fController(new TabManagerController(this)),
        fTarget(target)
{
        fController->SetDoubleClickOutsideTabsMessage(*newTabMessage,
                be_app_messenger);

        fContainerView = new BView("web view container", 0);
        fCardLayout = new BCardLayout();
        fContainerView->SetLayout(fCardLayout);

        fTabContainerView = new TabContainerView(fController);
        fTabContainerGroup = new TabContainerGroup(fTabContainerView);
        fTabContainerGroup->GroupLayout()->SetInsets(0, 3, 0, 0);

        fController->SetTabContainerGroup(fTabContainerGroup);

#if INTEGRATE_MENU_INTO_TAB_BAR
        fMenuContainer = new BGroupView(B_HORIZONTAL, 0);
        fMenuContainer->GroupLayout()->SetInsets(0, -3, 0, -3);
        fTabContainerGroup->GroupLayout()->AddView(fMenuContainer, 0.0f);
#endif

        fTabContainerGroup->GroupLayout()->AddView(fTabContainerView);
        fTabContainerGroup->AddScrollLeftButton(new ScrollLeftTabButton(
                new BMessage(MSG_SCROLL_TABS_LEFT)));
        fTabContainerGroup->AddScrollRightButton(new ScrollRightTabButton(
                new BMessage(MSG_SCROLL_TABS_RIGHT)));
        NewTabButton* newTabButton = new NewTabButton(newTabMessage);
        newTabButton->SetTarget(be_app);
        fTabContainerGroup->GroupLayout()->AddView(newTabButton, 0.0f);
        fTabContainerGroup->AddTabMenuButton(new TabMenuTabButton(
                new BMessage(MSG_OPEN_TAB_MENU)));
}


TabManager::~TabManager()
{
        delete fController;
}


void
TabManager::SetTarget(const BMessenger& target)
{
        fTarget = target;
}


const BMessenger&
TabManager::Target() const
{
        return fTarget;
}


#if INTEGRATE_MENU_INTO_TAB_BAR
BGroupLayout*
TabManager::MenuContainerLayout() const
{
        return fMenuContainer->GroupLayout();
}
#endif


BView*
TabManager::TabGroup() const
{
        return fTabContainerGroup;
}


BView*
TabManager::GetTabContainerView() const
{
        return fTabContainerView;
}


BView*
TabManager::ContainerView() const
{
        return fContainerView;
}


BView*
TabManager::ViewForTab(int32 tabIndex) const
{
        BLayoutItem* item = fCardLayout->ItemAt(tabIndex);
        if (item != NULL)
                return item->View();
        return NULL;
}


int32
TabManager::TabForView(const BView* containedView) const
{
        int32 count = fCardLayout->CountItems();
        for (int32 i = 0; i < count; i++) {
                BLayoutItem* item = fCardLayout->ItemAt(i);
                if (item->View() == containedView)
                        return i;
        }
        return -1;
}


bool
TabManager::HasView(const BView* containedView) const
{
        return TabForView(containedView) >= 0;
}


void
TabManager::SelectTab(int32 tabIndex)
{
        fCardLayout->SetVisibleItem(tabIndex);
        fTabContainerView->SelectTab(tabIndex);

        BMessage message(TAB_CHANGED);
        message.AddInt32("tab index", tabIndex);
        fTarget.SendMessage(&message);
}


void
TabManager::SelectTab(const BView* containedView)
{
        int32 tabIndex = TabForView(containedView);
        if (tabIndex >= 0)
                SelectTab(tabIndex);
}


int32
TabManager::SelectedTabIndex() const
{
        return fCardLayout->VisibleIndex();
}


void
TabManager::CloseTab(int32 tabIndex)
{
        BMessage message(CLOSE_TAB);
        message.AddInt32("tab index", tabIndex);
        fTarget.SendMessage(&message);
}


void
TabManager::AddTab(BView* view, const char* label, int32 index)
{
        fTabContainerView->AddTab(label, index);
        fCardLayout->AddView(index, view);
}


BView*
TabManager::RemoveTab(int32 index)
{
        // It's important to remove the view first, since
        // removing the tab will preliminary mess with the selected tab
        // and then item count of card layout and tab container will not
        // match yet.
        BLayoutItem* item = fCardLayout->RemoveItem(index);
        if (item == NULL)
                return NULL;

        TabView* tab = fTabContainerView->RemoveTab(index);
        delete tab;

        BView* view = item->View();
        delete item;
        return view;
}


int32
TabManager::CountTabs() const
{
        return fCardLayout->CountItems();
}


void
TabManager::SetTabLabel(int32 tabIndex, const char* label)
{
        fTabContainerView->SetTabLabel(tabIndex, label);
}

const BString&
TabManager::TabLabel(int32 tabIndex)
{
        TabView* tab = fTabContainerView->TabAt(tabIndex);
        if (tab)
                return tab->Label();
        else
                return kEmptyString;
}

void
TabManager::SetTabIcon(const BView* containedView, const BBitmap* icon)
{
        WebTabView* tab = dynamic_cast<WebTabView*>(fTabContainerView->TabAt(
                TabForView(containedView)));
        if (tab)
                tab->SetIcon(icon);
}