/*
SRBrowserController.m

Author: Makoto Kinoshita

Copyright 2004-2006 The Shiira Project. 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 THE SHIIRA PROJECT ``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 THE SHIIRA PROJECT 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.
*/

#import "SRConstants.h"

#import "SRBookmark.h"

#import "SRAppController.h"
#import "SRBookmarkController.h"
#import "SRBrowserController.h"
#import "SRBrowserDocument.h"
#import "SRDefaultKeys.h"
#import "SRDocumentController.h"
#import "SRFullScreenController.h"
#import "SRPageController.h"
#import "SRSearchFieldController.h"
#import "SRIconManager.h"
#import "SRURLCompleteDataSource.h"

#import "SRTabContextMenu.h"

#import "SRMenu.h"
#import "SRBookmarkBar.h"
#import "SRSearchField.h"
#import "SRStatusBar.h"
#import "SRToolbarItem.h"
#import "SREncodings.h"

#import "SRPrefDefaultKeys.h"

#import "SRPlugInController.h"

#import "SRWebView.h"

// URL location
int         SRURLMinWidth = 48;
int         SRURLMaxWidth = 1024;

// Search field
int         SRSearchFieldMinWidth = 96;
int         SRSearchFieldMaxWidth = 256;

@implementation SRBrowserController (delegate)

//--------------------------------------------------------------//
#pragma mark -- Window appearance --
//--------------------------------------------------------------//

- (void)_setTitle:(NSString*)title
{
    // Check title
    if (!title || [title length] == 0) {
        title = NSLocalizedString(@"Untitled", nil);
    }
    
    // Set title
    [_browserContent setValue:title forKey:@"title"];
}

- (void)_setURLString:(NSString*)URLString
{
    // Check URL string
    if (!URLString) {
        URLString = @"";
    }
    
    // Set URL String
    [_browserContent setValue:URLString forKey:@"URLString"];
}

- (void)_setIconWithURLString:(NSString*)URLString
{
    // Set icon
    NSImage*    icon;
    icon = [[WebIconDatabase sharedIconDatabase] 
            iconForURL:URLString withSize:NSMakeSize(16, 16)];
    if (icon) {
        [[self URLComboBox] setImage:icon];
    }
}

- (void)_setStatusMessage:(NSString*)message
{
    // Set message
    if (!message) {
        message = @"";
    }
    [_browserContent setValue:message forKey:@"status"];
}

- (void)_setFeedStatus:(BOOL)flag selected:(BOOL)selected
{
    // Set image
    if (selected) {
        [_feedButton setImage:[NSImage imageNamed:@"statusFeedSelected"]];
    }
    else {
        [_feedButton setImage:[NSImage imageNamed:@"statusFeed"]];
    }
    
    // Add status icon button
    if (flag) {
        [_statusBar addStatusIconButton:_feedButton];
    }
    // Remove status icon button
    else {
        [_statusBar removeStatusIconButton:_feedButton];
    }
}

- (void)_setIDNStatus:(BOOL)flag
{
    // Add status icon button
    if (flag) {
        [_statusBar addStatusIconButton:_IDNButton];
    }
    // Remove status icon button
    else {
        [_statusBar removeStatusIconButton:_IDNButton];
    }
}

- (void)_setLockedStatus:(BOOL)flag
{
    // Add status icon button
    if (flag) {
        [_statusBar addStatusIconButton:_lockedButton];
    }
    // Remove status icon button
    else {
        [_statusBar removeStatusIconButton:_lockedButton];
    }
}

- (void)_setCookieStatus:(BOOL)flag
{
    // Add status icon button
    if (flag) {
        [_statusBar addStatusIconButton:_cookieButton];
    }
    // Remove status icon button
    else {
        [_statusBar removeStatusIconButton:_cookieButton];
    }
}

//--------------------------------------------------------------//
#pragma mark -- NSToolbar delegate --
//--------------------------------------------------------------//

- (NSArray*)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar
{
    return [[self class] toolbarItemIdentifiers];
}

- (NSArray*)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
{
    return [[self class] defaultToolbarItemIdentifiers];
}

- (NSToolbarItem*)toolbar:(NSToolbar*)toolbar 
        itemForItemIdentifier:(NSString*)itemIdentifier 
        willBeInsertedIntoToolbar:(BOOL)flag
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Create toolbar item
    id  item;
    if ([itemIdentifier isEqualToString:SRBrowserURLItem]) {
        item = [[SRURLToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
    }
    else {
        item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
    }
    [item autorelease];
    [item setTarget:self];
    
    // Get label
    NSString*   label;
    NSString*   paletteLabel = nil;
    label = NSLocalizedStringFromTable(itemIdentifier, SRBrowserToolbarLabelTable, nil);
    
    // Get icon
    NSImage*    iconImage = nil;
    if ([(HMWindow*)[self window] isMetal]) {
        iconImage = [SRMetalIconImageDict objectForKey:itemIdentifier];
    }
    else {
        iconImage = [SRAquaIconImageDict objectForKey:itemIdentifier];
    }
    
    // For action
    SEL action = NULL;
    
    // Go back
    if ([itemIdentifier isEqualToString:SRBrowserGoBackItem]) {
        action = @selector(goBackAction:);
    }
    // Go forward
    else if ([itemIdentifier isEqualToString:SRBrowserGoForwardItem]) {
        action = @selector(goForwardAction:);
    }
    // Reload page
    else if ([itemIdentifier isEqualToString:SRBrowserReloadPageItem]) {
        action = @selector(reloadPageAction:);
    }
    // Stop loading
    else if ([itemIdentifier isEqualToString:SRBrowserStopLoadingItem]) {
        action = @selector(stopLoadingAction:);
    }
    // Go home
    else if ([itemIdentifier isEqualToString:SRBrowserGoHomeItem]) {
        action = @selector(goHomeAction:);
    }
    // URL
    else if ([itemIdentifier isEqualToString:SRBrowserURLItem]) {
        // Create URL combo box
        HMImageComboBox*    URLComboBox;
        URLComboBox = [[HMImageComboBox alloc] initWithFrame:NSZeroRect];
        [URLComboBox autorelease];
        [URLComboBox sizeToFit];
        [URLComboBox setImage:[[WebIconDatabase sharedIconDatabase] 
                defaultIconWithSize:NSMakeSize(16, 16)]];
        [URLComboBox setDelegate:self];
        
        // Set data source
        [URLComboBox setUsesDataSource:YES];
        _URLDataSource = [[SRURLCompleteDataSource alloc] init];
        [URLComboBox setDataSource:_URLDataSource];
        
        // Set action
        if (flag) {
            [URLComboBox setTarget:self];
            [URLComboBox setAction:@selector(URLComboBoxAction:)];
            [[URLComboBox cell] setSendsActionOnEndEditing:NO];
            [URLComboBox setCompletes:YES];
            [URLComboBox setDelegate:self];
            [URLComboBox bind:@"value" 
                    toObject:_browserController withKeyPath:@"selection.URLString" options:nil];
        }
        
        // Set view
        [item setView:URLComboBox];
        [item setMinSize:NSMakeSize(SRURLMinWidth, [URLComboBox frame].size.height)];
        [item setMaxSize:NSMakeSize(SRURLMaxWidth, [URLComboBox frame].size.height)];
        
        // Set menu representation
        NSMenuItem* menuItem;
        menuItem = [[NSMenuItem alloc] initWithTitle:label 
                action:@selector(openLocationAction:) 
                keyEquivalent:@""];
        [menuItem autorelease];
        [item setMenuFormRepresentation:menuItem];
    }
    // Search
    else if ([itemIdentifier isEqualToString:SRBrowserSearchItem]) {
        SRSearchField*  searchField;
        searchField = [[SRSearchField alloc] initWithFrame:NSZeroRect];
        [searchField autorelease];
        [searchField setTarget:_searchFieldController];
        [searchField setAction:@selector(searchAction:)];
        [searchField sizeToFit];
        [[searchField cell] setWraps:NO];
        [[searchField cell] setScrollable:YES];
        [[searchField cell] setSendsWholeSearchString:YES];
        [searchField setFlexible:YES];
        [searchField setMinWidth:SRSearchFieldMinWidth];
        [searchField setMaxWidth:SRSearchFieldMaxWidth];
        [searchField setDelegate:self];
        
        [item setView:searchField];
        
        int width;
        width = [defaults integerForKey:SRSearchFieldWidth];
        if (width < SRSearchFieldMinWidth) {
            width = SRSearchFieldMinWidth;
        }
        if (width > SRSearchFieldMaxWidth) {
            width = SRSearchFieldMaxWidth;
        }
        [item setMinSize:NSMakeSize(width, [searchField frame].size.height)];
        [item setMaxSize:NSMakeSize(width, [searchField frame].size.height)];
        
        NSMenuItem* menuItem;
        menuItem = [[NSMenuItem alloc] initWithTitle:label 
                action:@selector(findByToolbarAction:) 
                keyEquivalent:@""];
        [menuItem autorelease];
        [item setMenuFormRepresentation:menuItem];
    }
    // New tab
    else if ([itemIdentifier isEqualToString:SRBrowserNewTabItem]) {
        // Check tab style
        SRTabStyleType  tabStyle;
        tabStyle = [self tabStyle];
        
        if (tabStyle == SRTabStylePageDock) {
            iconImage = [NSImage imageNamed:@"NewPageDock"];
            label = NSLocalizedStringFromTable(@"SRNewPageDock", SRBrowserToolbarLabelTable, nil);
        }
        if (tabStyle == SRTabStyleTab) {
            iconImage = [NSImage imageNamed:@"NewTab"];
            label = NSLocalizedStringFromTable(@"SRNewTab", SRBrowserToolbarLabelTable, nil);
        }
        
        paletteLabel = NSLocalizedStringFromTable(@"SRNewTabPageDock", SRBrowserToolbarLabelTable, nil);
        action = @selector(newTabAction:);
    }
    // Close tab
    else if ([itemIdentifier isEqualToString:SRBrowserCloseTabItem]) {
        // Check tab style
        SRTabStyleType  tabStyle;
        tabStyle = [self tabStyle];
        
        if (tabStyle == SRTabStylePageDock) {
            iconImage = [NSImage imageNamed:@"ClosePageDock"];
            label = NSLocalizedStringFromTable(@"SRClosePageDock", SRBrowserToolbarLabelTable, nil);
        }
        if (tabStyle == SRTabStyleTab) {
            iconImage = [NSImage imageNamed:@"CloseTab"];
            label = NSLocalizedStringFromTable(@"SRCloseTab", SRBrowserToolbarLabelTable, nil);
        }
        
        paletteLabel = NSLocalizedStringFromTable(@"SRCloseTabPageDock", SRBrowserToolbarLabelTable, nil);
        action = @selector(closeTabAction:);
    }
    // Bookmark page
    else if ([itemIdentifier isEqualToString:SRBrowserAddBookmarkItem]) {
        action = @selector(addToBookmarkAction:);
    }
    // Bigger Text
    else if ([itemIdentifier isEqualToString:SRBrowserBiggerTextItem]) {
        action = @selector(biggerTextAction:);
    }
    // Smaller Text
    else if ([itemIdentifier isEqualToString:SRBrowserSmallerTextItem]) {
        action = @selector(smallerTextAction:);
    }
    // Shelf
    else if ([itemIdentifier isEqualToString:SRBrowserShelfItem]) {
        action = @selector(showShelfAction:);
    }
    // Full screen
    else if ([itemIdentifier isEqualToString:SRBrowserFullScreenItem]) {
        action = @selector(switchToFullScreenWithMenuAction:);
    }
    // Print page
    else if ([itemIdentifier isEqualToString:SRBrowserPrintPageItem]) {
        action = @selector(printPageAction:);
    }
    // Bookmark panel
    else if ([itemIdentifier isEqualToString:SRBrowserBookmarkPanelItem]) {
        [item setTarget:[SRAppController sharedInstance]];
        action = @selector(toggleBookmarkPanelAction:);
    }
    // History panel
    else if ([itemIdentifier isEqualToString:SRBrowserHistoryPanelItem]) {
        [item setTarget:[SRAppController sharedInstance]];
        action = @selector(toggleHistoryPanelAction:);
    }
    // Page info panel
    else if ([itemIdentifier isEqualToString:SRBrowserPageInfoPanelItem]) {
        action = @selector(showPageInfoAction:);
    }
    // Find panel
    else if ([itemIdentifier isEqualToString:SRBrowserFindPanelItem]) {
        [item setTarget:[SRAppController sharedInstance]];
        action = @selector(findAction:);
    }
    // Download panel
    else if ([itemIdentifier isEqualToString:SRBrowserDownloadPanelItem]) {
        [item setTarget:[SRAppController sharedInstance]];
        action = @selector(toggleDownloadPanelAction:);
    }
    // RSS panel
    else if ([itemIdentifier isEqualToString:SRBrowserRSSPanelItem]) {
        [item setTarget:[SRAppController sharedInstance]];
        action = @selector(toggleRSSPanelAction:);
    }
    // Plug-in
    else {
        // Get info dicts
        NSArray*        plugInInfoDicts;
        NSEnumerator*   enumerator;
        NSDictionary*   infoDict;
        plugInInfoDicts = [[SRPlugInController sharedInstance] plugInInfoDicts];
        enumerator = [plugInInfoDicts objectEnumerator];
        while (infoDict = [enumerator nextObject]) {
            if ([itemIdentifier isEqualToString:[infoDict objectForKey:@"CFBundleIdentifier"]]) {
                // Get title
                label = [infoDict objectForKey:@"SRPlugInTitle"];
                
                // Get bundle
                NSBundle*   bundle;
                bundle = [NSBundle bundleForClass:
                        NSClassFromString([infoDict objectForKey:@"NSPrincipalClass"])];
                if (bundle) {
                    NSString*   path;
                    path = [bundle pathForImageResource:[infoDict objectForKey:@"SRToolbarIconFile"]];
                    if (path) {
                        iconImage = [[NSImage alloc] initWithContentsOfFile:path];
                        [iconImage autorelease];
                    }
                }
                
                // Set action
                action = @selector(openPlugInAction:);
            }
        }
    }
    
    // Set item properties
    if (label) {
        [item setLabel:label];
    }
    if (iconImage) {
        [item setImage:iconImage];
    }
    if (action) {
        [item setAction:action];
    }
    
    if (paletteLabel) {
        [item setPaletteLabel:paletteLabel];
    }
    else if (label) {
        [item setPaletteLabel:label];
    }
    
    return item;
}

//--------------------------------------------------------------//
#pragma mark -- NSToolbarItemValidation informal protocol --
//--------------------------------------------------------------//

- (BOOL)validateToolbarItem:(NSToolbarItem*)item
{
    // Get item identifier
    id  identifier;
    identifier = [item itemIdentifier];
    
    // User defaults
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Get selected web view
    WebView*    webView;
    webView = [[self selectedPageController] webView];
    
    // Go Back
    if ([identifier isEqualToString:SRBrowserGoBackItem]) {
        if (!webView) {
            return NO;
        }
        return [webView canGoBack];
    }
    // Go Forward
    if ([identifier isEqualToString:SRBrowserGoForwardItem]) {
        if (!webView) {
            return NO;
        }
        return [webView canGoForward];
    }
    // Reload Page
    if ([identifier isEqualToString:SRBrowserReloadPageItem]) {
        if (!webView) {
            return NO;
        }
        
        // Get data source
        WebDataSource*  provisionalDataSource;
        WebDataSource*  dataSource;
        provisionalDataSource = [[webView mainFrame] provisionalDataSource];
        dataSource = [[webView mainFrame] dataSource];
        
        if (provisionalDataSource) {
            return ![provisionalDataSource isLoading];
        }
        if (dataSource) {
            if (![dataSource request]) {
                return NO;
            }
            return ![dataSource isLoading];
        }
        return NO;
    }
    // Stop Loading
    if ([identifier isEqualToString:SRBrowserStopLoadingItem]) {
        if (!webView) {
            return NO;
        }
        
        // Get data source
        WebDataSource*  provisionalDataSource;
        WebDataSource*  dataSource;
        provisionalDataSource = [[webView mainFrame] provisionalDataSource];
        dataSource = [[webView mainFrame] dataSource];
        
        if (provisionalDataSource) {
            return [provisionalDataSource isLoading];
        }
        if (dataSource) {
            if (![dataSource request]) {
                return NO;
            }
            return [dataSource isLoading];
        }
        return NO;
    }
    // Go Home
    if ([identifier isEqualToString:SRBrowserGoHomeItem]) {
        // Get home page URL
        NSString*   URLString;
        URLString = [defaults stringForKey:SRGeneralHomePage];
        return URLString && [URLString length] > 0;
    }
    // New tab
    if ([identifier isEqualToString:SRBrowserNewTabItem]) {
        // Check tab style
        SRTabStyleType  tabStyle;
        tabStyle = [self tabStyle];
        
        if (tabStyle == SRTabStylePageDock && [item image] != [NSImage imageNamed:@"NewPageDock"]) {
            [item setImage:[NSImage imageNamed:@"NewPageDock"]];
            [item setLabel:NSLocalizedStringFromTable(@"SRNewPageDock", SRBrowserToolbarLabelTable, nil)];
        }
        if (tabStyle == SRTabStyleTab && [item image] != [NSImage imageNamed:@"NewTab"]) {
            [item setImage:[NSImage imageNamed:@"NewTab"]];
            [item setLabel:NSLocalizedStringFromTable(@"SRNewTab", SRBrowserToolbarLabelTable, nil)];
        }
        
        return YES;
    }
    // Close tab
    if ([identifier isEqualToString:SRBrowserCloseTabItem]) {
        // Check tab style
        SRTabStyleType  tabStyle;
        tabStyle = [self tabStyle];
        
        if (tabStyle == SRTabStylePageDock && [item image] != [NSImage imageNamed:@"ClosePageDock"]) {
            [item setImage:[NSImage imageNamed:@"ClosePageDock"]];
            [item setLabel:NSLocalizedStringFromTable(@"SRClosePageDock", SRBrowserToolbarLabelTable, nil)];
        }
        if (tabStyle == SRTabStyleTab && [item image] != [NSImage imageNamed:@"CloseTab"]) {
            [item setImage:[NSImage imageNamed:@"CloseTab"]];
            [item setLabel:NSLocalizedStringFromTable(@"SRCloseTab", SRBrowserToolbarLabelTable, nil)];
        }
        
        return [_tabView numberOfTabViewItems] > 1;
    }
    // Add bookmark
    if ([identifier isEqualToString:SRBrowserAddBookmarkItem]) {
        if (!webView) {
            return NO;
        }
        return [[[webView mainFrame] dataSource] request] != nil;
    }
    // Bigger Text
    if ([identifier isEqualToString:SRBrowserBiggerTextItem]) {
        if (!webView) {
            return NO;
        }
        return [webView canMakeTextLarger];
    }
    // Smaller Text
    if ([identifier isEqualToString:SRBrowserSmallerTextItem]) {
        if (!webView) {
            return NO;
        }
        return [webView canMakeTextSmaller];
    }
    // Shelf
    if ([identifier isEqualToString:SRBrowserShelfItem]) {
        // Always YES
        return YES;
    }
    // Full screen
    if ([identifier isEqualToString:SRBrowserFullScreenItem]) {
        // Always YES
        return YES;
    }
    // Page info
    if ([identifier isEqualToString:SRBrowserPageInfoPanelItem]) {
        // Get data source
        WebDataSource*  dataSource;
        dataSource = [[webView mainFrame] dataSource];
        if (!dataSource) {
            return NO;
        }
        
        // Check error URL
        if ([[[[dataSource request] URL] absoluteString] hasSuffix:@"Shiira/template/tmpError.html"]) {
            return NO;
        }

        return YES;
    }
    // Plug-in
    if ([item action] == @selector(openPlugInAction:)) {
        return YES;
    }
    
    return NO;
}

//--------------------------------------------------------------//
#pragma mark -- NSWindow delegate --
//--------------------------------------------------------------//

- (void)windowDidBecomeKey:(NSNotification*)notification
{
    // Make itself file menu delegate
    NSMenu* fileMenu;
    fileMenu = SRFileMenu();
    [fileMenu setDelegate:self];
    
    // Validate menu item by hand
    NSMenuItem* menuItem;
    menuItem = [fileMenu itemWithTag:SRCloseWindowTag];
    [self validateMenuItem:menuItem];
    menuItem = [fileMenu itemWithTag:SRCloseTabTag];
    [self validateMenuItem:menuItem];
    
    // Update appearance
    [_tabView setNeedsDisplay:YES];
}

- (void)windowDidResignKey:(NSNotification*)notification
{
    // Make clear file menu delegate
    NSMenu* fileMenu;
    fileMenu = SRFileMenu();
    if ([fileMenu delegate] == self) {
        [fileMenu setDelegate:[SRAppController sharedInstance]];
    }
    
    // Update appearance
    [_tabView setNeedsDisplay:YES];
}

- (void)windowDidBecomeMain:(NSNotification*)notification
{
    // Get window
    NSWindow*   window;
    window = [self window];
    
    // Change first responder
    WebView*        webView;
    WebDataSource*  dataSource;
    webView = [[self selectedPageController] webView];
    dataSource = [[webView mainFrame] dataSource];
    if (!dataSource) {
        [window makeFirstResponder:[self URLComboBox]];
    }
    
    // Set Web inspector
    WebInspector*   inspector;
    inspector = [NSClassFromString(@"WebInspector") sharedWebInspector];
    if (inspector && [[inspector window] isVisible]) {
        [inspector setWebFrame:[[[self selectedPageController] webView] mainFrame]];
    }
    
    // Notify change
    [[NSNotificationCenter defaultCenter] 
            postNotificationName:SRBrowserDidBecomeMain object:self];
    
    // Validate menu item by hand
    NSMenu*     fileMenu;
    NSMenuItem* menuItem;
    fileMenu = SRFileMenu();
    menuItem = [fileMenu itemWithTag:SRCloseWindowTag];
    [self validateMenuItem:menuItem];
    menuItem = [fileMenu itemWithTag:SRCloseTabTag];
    [self validateMenuItem:menuItem];
    
    // Update appearance
    [_tabView setNeedsDisplay:YES];
}

- (void)windowDidResignMain:(NSNotification*)notification
{
    // Notify change
    [[NSNotificationCenter defaultCenter] 
            postNotificationName:SRBrowserDidResignMain object:self];
    
    // Update appearance
    [_tabView setNeedsDisplay:YES];
}

- (void)windowDidMove:(NSNotification*)notification
{
    // Check flag
    if (_isResizedByJavaScript) {
        return;
    }
    
    // Get origin
    NSWindow*   window;
    NSPoint     origin;
    window = [notification object];
    origin = [window frame].origin;
    origin.y += [window frame].size.height;
    
    // Save to defaults database
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:NSStringFromPoint(origin) 
            forKey:SRBrowserWindowFrameOrigin];
}

- (void)windowDidResize:(NSNotification*)notification
{
    // Check flag
    if (_isResizedByJavaScript) {
        return;
    }
    
    // Get size
    NSWindow*   window;
    NSSize      size;
    window = [notification object];
    size = [[window contentView] frame].size;
    
    // Save to defaults database
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:NSStringFromSize(size) 
            forKey:SRBrowserWindowContentSize];
}

- (NSRect)windowWillUseStandardFrame:(NSWindow*)window defaultFrame:(NSRect)defaultFrame
{
    // Get selected web view
    WebView*    webView;
    webView = [[self selectedPageController] webView];
    if (!webView) {
        return defaultFrame;
    }
    
    // Get document view
    id  documentView;
    documentView = [[[webView mainFrame] frameView] documentView];
    if (!documentView) {
        return defaultFrame;
    }
    
    // Get current window frame
    NSRect  windowFrame;
    windowFrame = [[self window] frame];
    
    // Decide new frame
    NSSize  size;
    NSRect  frame = defaultFrame;
    size = [documentView frame].size;
    frame.origin.x = windowFrame.origin.x;
    frame.size.width = size.width;
    
    // When frame view has scroll bars
    NSArray*    subviews;
    subviews = [[[webView mainFrame] frameView] subviews];
    if ([subviews count] > 0) {
        id  subview;
        subview = [subviews objectAtIndex:0];
        if ([subview isKindOfClass:[NSScrollView class]]) {
            if ([subview hasVerticalScroller]) {
                frame.size.width += [NSScroller scrollerWidth];
            }
        }
    }
    
    return frame;
}

//--------------------------------------------------------------//
#pragma mark -- Menu item validation --
//--------------------------------------------------------------//

- (BOOL)validateMenuItem:(id<NSMenuItem>)menuItem
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Get tag
    int tag;
    tag = [menuItem tag];
    
    // For full screen mode
    if ([self isFullScreenMode]) {
        switch (tag) {
        case SRNewTabTag:
        case SROpenLocationTag:
        case SRCloseWindowTag:
        case SRCloseTabTag:
        case SRPrintAPDFTag:
        
        case SRFindTag:
        case SRFindNextTag:
        case SRFindPreviousTag:
        case SRUseSelectionForFindTag:
        case SRJumpToSelectionTag:
        case SRFindByToolbarTag:
        case SRSpecialCharactersTag:
        
        case SRToolbarTag:
        case SRBookmarksBarTag:
        case SRStatusBarTag:
        case SRCustomizeToolbarTag:
        case SRViewPageSourceTag:
        
        case SRZoomTag:
        case SRMinimizeTag:
        case SRPreviousTabTag:
        case SRNextTabTag:
        case SRShowAllTabsTag:
        case SRCacheTag:
        case SRDownloadsPanelTag:
        case SRBringAllToFronTag:
        {
            return NO;
        }
        
        // Force single widnow mode
        case SRDefaultBrowsingTag:
        case SRSmartBrowseModeTag:
        {
            [menuItem setState:NSOffState];
            return NO;
        }
        case SRSingleWindowModeTag:
        {
            [menuItem setState:NSOnState];
            return NO;
        }
        }
    }
    
    // Get web view
    WebView*    webView;
    webView = [[self selectedPageController] webView];
    
    switch (tag) {
    // File menu
    case SRNewTabTag: {
        return YES;
    }
    case SRCloseWindowTag: {
        // Check number of tab
        if (![[self window] isKeyWindow] || [_tabView numberOfTabViewItems] < 2) {
            [menuItem setKeyEquivalent:@"w"];
            [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
        }
        else {
            [menuItem setKeyEquivalent:@"W"];
            [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
        }
        
        // Always YES
        return YES;
    }
    case SRCloseTabTag: {
        // Check number of tab
        if (![[self window] isKeyWindow] || [_tabView numberOfTabViewItems] < 2) {
            [menuItem setKeyEquivalent:@""];
            return NO;
        }
        else {
            [menuItem setKeyEquivalent:@"w"];
            [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
            return YES;
        }
    }
    
    // View menu
    case SRToolbarTag: {
        // Set menu status
        BOOL    isToolbarVisible;
        isToolbarVisible = [[[self window] toolbar] isVisible];
        [menuItem setState:isToolbarVisible ? NSOnState : NSOffState];
        
        // Always YES
        return YES;
    }
    case SRBookmarksBarTag: {
        // Set menu status
        BOOL    isBookmarkBarVisible;
        isBookmarkBarVisible = [self isBookmarkBarVisible];
        [menuItem setState:isBookmarkBarVisible ? NSOnState : NSOffState];
        
        // Always YES
        return YES;
    }
    case SRPageDockTag: {
        // Set menu status
        BOOL    isPageDockVisible;
        isPageDockVisible = [self isPageDockVisible];
        [menuItem setState:isPageDockVisible ? NSOnState : NSOffState];
        
        // Always YES
        return YES;
    }
    case SRShowShelfTag: {
        // Always YES
        return YES;
    }
    case SRStopLoadingTag: {
        if (!webView) {
            return NO;
        }
        
        // Get data source
        WebDataSource*  provisionalDataSource;
        WebDataSource*  dataSource;
        provisionalDataSource = [[webView mainFrame] provisionalDataSource];
        dataSource = [[webView mainFrame] dataSource];
        
        if (provisionalDataSource) {
            return [provisionalDataSource isLoading];
        }
        if (dataSource) {
            if (![dataSource request]) {
                return NO;
            }
            return [dataSource isLoading];
        }
        return NO;
    }
    case SRReloadPageTag: {
        if (!webView) {
            return NO;
        }
        
        // Get data source
        WebDataSource*  provisionalDataSource;
        WebDataSource*  dataSource;
        provisionalDataSource = [[webView mainFrame] provisionalDataSource];
        dataSource = [[webView mainFrame] dataSource];
        
        if (provisionalDataSource) {
            return ![provisionalDataSource isLoading];
        }
        if (dataSource) {
            if (![dataSource request]) {
                return NO;
            }
            return ![dataSource isLoading];
        }
        return NO;
    }
    case SRBiggerTextTag: {
        if (!webView) {
            return NO;
        }
        
        return [webView canMakeTextLarger];
    }
    case SRSmallerTextTag: {
        if (!webView) {
            return NO;
        }
        
        return [webView canMakeTextSmaller];
    }
    case SRDefaultBrowsingTag: {
        // Set state
        [menuItem setState:[defaults integerForKey:SRBrowseMode] == SRDefaultBrowseMode ? 
                NSOnState : NSOffState];
        return YES;
    }
    case SRSingleWindowModeTag: {
        // Set state
        [menuItem setState:[defaults integerForKey:SRBrowseMode] == SRSingleWindowMode ? 
                NSOnState : NSOffState];
        return YES;
    }
    case SRSmartBrowseModeTag: {
        // Set state
        [menuItem setState:[defaults integerForKey:SRBrowseMode] == SRSmartBrowseMode ? 
                NSOnState : NSOffState];
        return YES;
    }
    case SRViewPageSourceTag: {
        // Get data source
        WebDataSource*  dataSource;
        dataSource = [[webView mainFrame] dataSource];
        if (!dataSource) {
            return NO;
        }
        
        // Check error URL
        if ([[[[dataSource request] URL] absoluteString] hasSuffix:@"Shiira/template/tmpError.html"]) {
            return NO;
        }
        
        return [[dataSource representation] canProvideDocumentSource];
    }
    case SROpenURLWithBrowserItemTag: {
        NSURL*  url;
        url = [[[[webView mainFrame] dataSource] request] URL];
        return url != nil;
    }
    case SRTextEncodingDefaultTag: {
        // Update submenu
        NSMenu*             textEncodingMenu;
        NSString*           encodingName;
        NSStringEncoding    encoding;
        textEncodingMenu = [menuItem menu];
        encodingName = [webView customTextEncodingName];
        if (!encodingName) {
            encoding = SRTextEncodingDefaultTag;
        }
        else {
            // Get text encoding
            encoding = [[[NSValueTransformer valueTransformerForName:SREncodingToIANATransformerName] 
                    reverseTransformedValue:encodingName] intValue];
        }
        
        // Get correspond menu item
        id<NSMenuItem>  encodingMenuItem;
        encodingMenuItem = [textEncodingMenu itemWithTag:encoding];
        
        // Set state
        NSEnumerator*   enumerator;
        id<NSMenuItem>  item;
        enumerator = [[textEncodingMenu itemArray] objectEnumerator];
        while (item = [enumerator nextObject]) {
            [item setState:item == encodingMenuItem ? NSOnState : NSOffState];
        }
        
        return YES;
    }
    
    // History menu
    case SRBackTag: {
        if (!webView) {
            return NO;
        }
        
        return [webView canGoBack];
    }
    case SRForwardTag: {
        if (!webView) {
            return NO;
        }
        
        return [webView canGoForward];
    }
    case SRHomeTag: {
        // Get home page URL
        NSString*   URLString;
        URLString = [defaults stringForKey:SRGeneralHomePage];
        return URLString && [URLString length] > 0;
    }
    
    // Bookmark menu
    case SRAddToBookmarkTag: {
        // Get selected web view
        if (![[[webView mainFrame] dataSource] request]) {
            return NO;
        }
        return YES;
    }
    
    // Window menu
    case SRPreviousTabTag: {
        // Get selected index
        int numberOfItems;
        int selectedIndex;
        numberOfItems = [_tabView numberOfTabViewItems];
        selectedIndex = [_tabView indexOfSelectedTabViewItem];
        if (selectedIndex == -1) {
            return NO;
        }
        
        return numberOfItems > 1;
    }
    case SRNextTabTag: {
        // Get item number and selected index
        int numberOfItems;
        int selectedIndex;
        numberOfItems = [_tabView numberOfTabViewItems];
        selectedIndex = [_tabView indexOfSelectedTabViewItem];
        if (selectedIndex == -1) {
            return NO;
        }
        
        return numberOfItems > 1;
    }
    case SRShowAllTabsTag: {
        return [_tabView numberOfTabViewItems] > 1;
    }
    case SRWebInspectorTag: {
        return NSClassFromString(@"WebInspector") != nil;
    }
    }
    
    return YES;
}

//--------------------------------------------------------------//
#pragma mark -- SRPageController notification --
//--------------------------------------------------------------//

- (void)_updateBrowserContentWithPageControllerNotification:(NSNotification*)notification
{
#if 0
   // Set status message
    NSString*   status;
    status = NSLocalizedStringFromTable(UTF8STR("Connecting “%@”"), nil, nil);
    if (status) {
        [self setValue:[NSString stringWithFormat:status, URLString]
                forKey:SRMainWebViewStatus];
    }
#endif
}

- (void)pageDidStartProvisionalLoad:(NSNotification*)notification
{
    // Check page controller
    SRPageController*   pageController;
    pageController = [notification object];
    if (pageController != [self selectedPageController]) {
        return;
    }
    
    // Get web view and data source
    WebView*        webView;
    WebDataSource*  dataSource;
    webView = [pageController webView];
    dataSource = [[webView mainFrame] provisionalDataSource];
    
    // Get URL string
    NSString*   URLString;
    NSString*   visibleURLString;
    URLString = [[[dataSource request] URL] absoluteString];
    visibleURLString = [[[dataSource request] URL] _web_userVisibleString];
    
    // Set window appearance
    [self _setTitle:visibleURLString];
    [self _setURLString:visibleURLString];
    [self _setIconWithURLString:URLString];
    
    [self _setFeedStatus:NO selected:NO];
    [self _setIDNStatus:NO];
    [self _setLockedStatus:NO];
    [self _setCookieStatus:NO];
}

- (void)pageDidCommitLoad:(NSNotification*)notification
{
    // Check page controller
    SRPageController*   pageController;
    pageController = [notification object];
    if (pageController != [self selectedPageController]) {
        return;
    }
    
    // Get web view and data source
    WebView*        webView;
    WebDataSource*  dataSource;
    webView = [pageController webView];
    dataSource = [[webView mainFrame] dataSource];
    
    // Get URL string
    NSURL*      URL;
    NSString*   URLString;
    NSString*   visibleURLString;
    URL = [[dataSource request] URL];
    URLString = [URL absoluteString];
    visibleURLString = [URL _web_userVisibleString];
    
    // Set window appearance
    [self _setTitle:visibleURLString];
    [self _setURLString:visibleURLString];
    [self _setIconWithURLString:URLString];
    
    [self _setLockedStatus:[[URL scheme] isEqualToString:@"https"]];
    [self _setIDNStatus:[[URL host] rangeOfString:@"xn--"].location != NSNotFound];
    
    // Notify it
    if ([notification object] == [self selectedPageController]) {
        [[NSNotificationCenter defaultCenter] 
                postNotificationName:SRBrowserDidCommitLoad object:self];
    }
}

- (void)pageDidFinishLoad:(NSNotification*)notification
{
    // Check page controller
    SRPageController*   pageController;
    pageController = [notification object];
    if (pageController != [self selectedPageController]) {
        return;
    }
    
    // Get web view and data source
    WebView*        webView;
    WebDataSource*  dataSource;
    webView = [pageController webView];
    dataSource = [[webView mainFrame] dataSource];
    
    // Get representation
    id<WebDocumentRepresentation>   representation;
    representation = [dataSource representation];
    
    // Set feed status
    if ([representation isKindOfClass:NSClassFromString(@"RSSRepresentation")]) {
        [self _setFeedStatus:YES selected:YES];
    }
    else {
        [self _setFeedStatus:[webView hasRSSLink] selected:NO];
    }
    
    // Set cookie status
    int             cookieCount = 0;
    NSEnumerator*   enumerator;
    WebFrame*       frame;
    enumerator = [[webView webFrames] objectEnumerator];
    while (frame = [enumerator nextObject]) {
        NSURL*  url;
        url = [[[frame dataSource] request] URL];
        if (url) {
            NSArray*    cookies;
            cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] 
                    cookiesForURL:url];
            cookieCount += [cookies count];
        }
    }
    
    if (cookieCount > 0) {
        [self _setCookieStatus:YES];
    }
    else {
        [self _setCookieStatus:NO];
    }
    
    // Set Web inspector
    WebInspector*   inspector;
    inspector = [NSClassFromString(@"WebInspector") sharedWebInspector];
    if (inspector && [[inspector window] isVisible]) {
        [inspector setWebFrame:[webView mainFrame]];
    }
    
    // For error
    NSString*   URLString;
    URLString = [[[dataSource request] URL] absoluteString];
    if ([URLString hasSuffix:@"Shiira/template/tmpError.html"]) {
        // Get error URL
        NSString*   errorURLString;
        errorURLString = SRErrorURLWithWebView(webView);
        if (errorURLString) {
            [self _setURLString:errorURLString];
        }
    }
}

- (void)pageDidReceiveServerRedirect:(NSNotification*)notification
{
    // Notify it
    if ([notification object] == [self selectedPageController]) {
        [[NSNotificationCenter defaultCenter] 
                postNotificationName:SRBrowserDidReceiveServerRedirect object:self];
    }
}

- (void)pageTitleReceived:(NSNotification*)notification
{
    // Check page controller
    SRPageController*   pageController;
    pageController = [notification object];
    if (pageController != [self selectedPageController]) {
        return;
    }
    
    // Get web view and data source
    WebView*        webView;
    WebDataSource*  dataSource;
    webView = [pageController webView];
    dataSource = [[webView mainFrame] dataSource];
    
    // Get title
    NSString*   title;
    title = [dataSource pageTitle];
    
    // Set window appearance
    [self _setTitle:title];
}

- (void)pageIconReceived:(NSNotification*)notification
{
    // Check page controller
    SRPageController*   pageController;
    pageController = [notification object];
    if (pageController != [self selectedPageController]) {
        return;
    }
    
    // Get web view and data source
    WebView*        webView;
    WebDataSource*  dataSource;
    webView = [pageController webView];
    dataSource = [[webView mainFrame] dataSource];
    
    // Get URL string
    NSString*   URLString;
    URLString = [[[dataSource request] URL] absoluteString];
    
    // Set window appearance
    [self _setIconWithURLString:URLString];
}

- (void)pageProgressStart:(NSNotification*)notification
{
    // Notify it
    if ([notification object] == [self selectedPageController]) {
        [[NSNotificationCenter defaultCenter] 
                postNotificationName:SRBrowserProgressStart object:self];
    }
}

- (void)pageProgressEstimateChanged:(NSNotification*)notification
{
}

- (void)pageProgressFinish:(NSNotification*)notification
{
    // Notify it
    if ([notification object] == [self selectedPageController]) {
        [[NSNotificationCenter defaultCenter] 
                postNotificationName:SRBrowserProgressFinish object:self];
    }
}

//--------------------------------------------------------------//
#pragma mark -- SRBookmarkBar notification --
//--------------------------------------------------------------//

- (void)bookmarkBarHeightChanged:(NSNotification*)notification
{
    // When bookmark bar is hidden
    if ([_bookmarkBar isHidden]) {
        return;
    }
    
    // Get frames
    NSRect  barFrame, tabFrame;
    barFrame = [_bookmarkBar frame];
    tabFrame = [_tabView frame];
    
    // When bottom of bar dose not touch at top of tab
    if (barFrame.origin.y != tabFrame.origin.y + tabFrame.size.height) {
        tabFrame.size.height = barFrame.origin.y - tabFrame.origin.y;
        [_tabView setFrame:tabFrame];
        [[_tabView superview] setNeedsDisplay:YES];
    }
}

//--------------------------------------------------------------//
#pragma mark -- HMTabView delegate --
//--------------------------------------------------------------//

- (void)hmTabView:(HMTabView*)tabView didSelectTabViewItem:(HMTabViewItem*)tabViewItem
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Get web view, data source and request
    WebView*        webView;
    WebDataSource*  dataSource;
    BOOL            isIndeterminate = NO;
    NSURLRequest*   request;
    webView = (WebView*)[tabViewItem view];
    dataSource = [[webView mainFrame] dataSource];
    if (!dataSource) {
        dataSource = [[webView mainFrame] provisionalDataSource];
        
        // If there is provisional data source, isIndeterminate is true
        isIndeterminate = dataSource != nil;
    }
    request = [dataSource request];
    
    // Get URL string
    NSString*   URLString;
    NSString*   visibleURLString;
    URLString = [[request URL] absoluteString];
    visibleURLString = [[request URL] _web_userVisibleString];
    
    // For error
    if ([URLString hasSuffix:@"Shiira/template/tmpError.html"]) {
        // Get error URL
        NSString*   errorURLString;
        errorURLString = SRErrorURLWithWebView(webView);
        if (errorURLString) {
            URLString = errorURLString;
            visibleURLString = errorURLString;
        }
    }
    
    // Get representation
    id<WebDocumentRepresentation>   representation;
    representation = [dataSource representation];
    
    // Set window appearance
    [self _setTitle:[tabViewItem label]];
    [self _setURLString:visibleURLString];
    [self _setIconWithURLString:URLString];
    [self _setStatusMessage:@""];
    
    if ([representation isKindOfClass:NSClassFromString(@"RSSRepresentation")]) {
        [self _setFeedStatus:YES selected:YES];
    }
    else {
        [self _setFeedStatus:[webView hasRSSLink] selected:NO];
    }
    [self _setIDNStatus:NO];
    [self _setLockedStatus:NO];
    
    // Set cookie status
    int             cookieCount = 0;
    NSEnumerator*   enumerator;
    WebFrame*       frame;
    enumerator = [[webView webFrames] objectEnumerator];
    while (frame = [enumerator nextObject]) {
        NSURL*  url;
        url = [[[frame dataSource] request] URL];
        if (url) {
            NSArray*    cookies;
            cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] 
                    cookiesForURL:url];
            cookieCount += [cookies count];
        }
    }
    
    if (cookieCount > 0) {
        [self _setCookieStatus:YES];
    }
    else {
        [self _setCookieStatus:NO];
    }
    
    // Set Web inspector
    WebInspector*   inspector;
    inspector = [NSClassFromString(@"WebInspector") sharedWebInspector];
    if (inspector && [[inspector window] isVisible]) {
        [inspector setWebFrame:[webView mainFrame]];
    }
    
    // Change first responder
    NSWindow*   window;
    window = [self window];
    if (!dataSource) {
        [window makeFirstResponder:[self URLComboBox]];
    }
    else {
        [window makeFirstResponder:webView];
    }
    
#if 0
    // Check error
    NSDictionary*   errorInfo;
    errorInfo = [tabViewItem userInfo];
    if (errorInfo) {
        // Show error dialog
        NSError*    error;
        WebFrame*   frame;
        error = [errorInfo objectForKey:@"error"];
        frame = [errorInfo objectForKey:@"frame"];
        if (error && frame) {
            [self showAlertWithError:error forFrame:frame];
        }
        
        // Clear user info
        [tabViewItem setUserInfo:nil];
    }
#endif
    
    // Notify change
    [[NSNotificationCenter defaultCenter] 
            postNotificationName:SRBrowserSelectedTabChanged object:self];
}

- (void)hmTabViewDidChangeNumberOfTabViewItems:(HMTabView*)tabView
{
    // Enable or disable tab expose button
    [_tabExposeButton setEnabled:[_tabView numberOfTabViewItems] > 1];
    
    // Update file menu
    [SRFileMenu() update];
}

- (void)hmTabView:(HMTabView*)tabView didEndAddTabViewItems:(NSArray*)tabViewItems
{
    // Select tab view item
    if (_willSelectTabViewItem && [tabViewItems containsObject:_willSelectTabViewItem]) {
        [_tabView selectTabViewItem:_willSelectTabViewItem];
    }
    _willSelectTabViewItem = nil;
}

- (void)hmTabView:(HMTabView*)tabView didEndRemoveTabViewItems:(NSArray*)tabViewItems
{
    // Stop loading
    NSMutableArray* webViews;
    NSEnumerator*   enumerator;
    HMTabViewItem*  tabViewItem;
    webViews = [[NSMutableArray alloc] init];
    enumerator = [tabViewItems objectEnumerator];
    while (tabViewItem = [enumerator nextObject]) {
        id  view;
        view = [tabViewItem view];
        if ([view isKindOfClass:[WebView class]]) {
            // Stop loading
            [view stopLoading:self];
            [view setHostWindow:nil];
            
            // Keep web views
            [webViews addObject:view];
        }
    }
    
    // Remove page controllers
    NSMutableArray*     pageControllers;
    SRPageController*   pageController;
    pageControllers = [[NSMutableArray alloc] init];
    enumerator = [_pageControllers objectEnumerator];
    while (pageController = [enumerator nextObject]) {
        if ([webViews containsObject:[pageController webView]]) {
            [pageControllers addObject:pageController];
        }
    }
    
    [_pageControllers removeObjectsInArray:pageControllers];
    [webViews release];
    [pageControllers release];
}

- (void)hmTabViewDidMoveTabViewItems:(HMTabView*)tabView
{
    // Re-order page controllers
    NSMutableArray* pageControllers;
    pageControllers = [NSMutableArray arrayWithArray:_pageControllers];
    [_pageControllers removeAllObjects];
    
    NSEnumerator*   enumerator;
    HMTabViewItem*  tabViewItem;
    enumerator = [[_tabView tabViewItems] objectEnumerator];
    while (tabViewItem = [enumerator nextObject]) {
        NSEnumerator*       pageEnum;
        SRPageController*   pageController;
        pageEnum = [pageControllers objectEnumerator];
        while (pageController = [pageEnum nextObject]) {
            if ([pageController tabViewItem] == tabViewItem) {
                [_pageControllers addObject:pageController];
                [pageControllers removeObjectIdenticalTo:pageController];
                break;
            }
        }
    }
}

- (void)hmTabViewEndDragging:(HMTabView*)tabView
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Get page dock height
    int pageDockHeight;
    pageDockHeight = [_tabView tabItemViewHigh];
    if (pageDockHeight > 0) {
        [defaults setInteger:pageDockHeight forKey:SRPageDockHeight];
    }
}

- (void)hmTabView:(HMTabView*)tabView insertPboard:(NSPasteboard*)pboard atTabIndex:(int)index
{
    // Get types
    NSArray*    draggedTypes;
    draggedTypes = [pboard types];
    
    // For Web URLs
    if ([draggedTypes containsObject:WebURLsWithTitlesPboardType]) {
        // Get URLs and titles
        NSArray*    URLs;
        NSArray*    titles;
        URLs = [WebURLsWithTitles URLsFromPasteboard:pboard];
        titles = [WebURLsWithTitles titlesFromPasteboard:pboard];
        
        // Open URL strings
        int i;
        for (i = 0; i < [URLs count]; i++) {
            // Get URL and title
            NSURL*      url;
            NSString*   title;
            url = [URLs objectAtIndex:i];
            title = [titles objectAtIndex:i];
            
            // Create page controller
            [self insertNewTabWithLabel:title frameName:nil groupName:nil atIndex:index + i select:YES];
            
            // Open URL
            [self openURL:url atIndex:index + i];
        }
        
        return;
    }
}

//--------------------------------------------------------------//
#pragma mark -- HMTabView notification --
//--------------------------------------------------------------//

- (void)hmTabItemAdded:(NSNotification*)notification
{
#if 0
    // Get tab view item
    HMTabViewItem*  tabViewItem;
    tabViewItem = (HMTabViewItem*)[[[notification userInfo] objectForKey:@"tabViewItem"] unsignedIntValue];
    
    // Select it
    if (_willSelectTabViewItem && _willSelectTabViewItem == tabViewItem) {
        [_tabView selectTabViewItem:_willSelectTabViewItem];
        _willSelectTabViewItem = nil;
    }
#endif
}

//--------------------------------------------------------------//
#pragma mark -- HMTabItemGroupView delegate --
//--------------------------------------------------------------//

- (NSMenu*)tabItemGroupView:(HMTabItemGroupView*)view menuForEvent:(NSEvent*)event
{
    // Create menu for context
    NSMenu* menu;
    menu = [[NSMenu alloc] initWithTitle:@"Tab"];
    [menu autorelease];
     
    // Get tab context menu
    NSMenu* tabMenu;
    tabMenu = [SRTabContextMenu contextMenu];
    
    NSMenuItem* menuItem;
    
    // 'New Tab'
    menuItem = HMCopyMenuItemWithTag(tabMenu, SRTabNewTabTag, nil);
    [menu addItem:menuItem];
    
    // 'Show All Tabs'
    menuItem = HMCopyMenuItemWithTag(tabMenu, SRTabShowAllTabsTag, nil);
    [menu addItem:menuItem];
    
    // Separator
    [menu addItem:[NSMenuItem separatorItem]];
    
    // 'Reload All Tabs'
    menuItem = HMCopyMenuItemWithTag(tabMenu, SRTabReloadAllTabsTag, nil);
    [menu addItem:menuItem];
    
    // 'Bookmark All Tabs'
    menuItem = HMCopyMenuItemWithTag(tabMenu, SRTabBookmarkAllTabTag, nil);
    [menu addItem:menuItem];
    
    return menu;
}

//--------------------------------------------------------------//
#pragma mark -- HMTabItemView delegate --
//--------------------------------------------------------------//

- (NSMenu*)tabItemView:(HMTabItemView*)view menuForEvent:(NSEvent*)event
{
    // Get tab view item
    HMTabViewItem*  tabViewItem;
    tabViewItem = [view tabViewItem];
    
    // Create menu for context
    NSMenu* menu;
    menu = [[NSMenu alloc] initWithTitle:@"Tab"];
    [menu autorelease];
     
    // Get tab context menu
    NSMenu* tabMenu;
    tabMenu = [SRTabContextMenu contextMenu];
    
    // Get index and count of tab items
    int index, count;
    index = [_tabView indexOfTabViewItem:tabViewItem];
    count = [_tabView numberOfTabViewItems];
    
    NSMenuItem* menuItem;
    
    // 'New Tab'
    menuItem = HMCopyMenuItemWithTag(tabMenu, SRTabNewTabTag, nil);
    [menu addItem:menuItem];
    
    // 'Close Tab'
    if (count > 1) {
        menuItem = HMCopyMenuItemWithTag(tabMenu, SRTabCloseTabTag, nil);
        [menuItem setRepresentedObject:tabViewItem];
        [menu addItem:menuItem];
    }
    
    // 'Show All Tabs'
    menuItem = HMCopyMenuItemWithTag(tabMenu, SRTabShowAllTabsTag, nil);
    [menu addItem:menuItem];
    
    // Separator
    [menu addItem:[NSMenuItem separatorItem]];
    
    if (count > 1) {
        // 'Close All Tabs on Right'
        if (index != count - 1) {
            menuItem = HMCopyMenuItemWithTag(tabMenu, SRTabCloseAllRightTag, nil);
            [menuItem setRepresentedObject:tabViewItem];
            [menu addItem:menuItem];
        }
        
        // 'Close All Tabs on Left'
        if (index != 0) {
            menuItem = HMCopyMenuItemWithTag(tabMenu, SRTabCloseAllLeftTag, nil);
            [menuItem setRepresentedObject:tabViewItem];
            [menu addItem:menuItem];
        }
        
        // 'Close Other Tabs'
        menuItem = HMCopyMenuItemWithTag(tabMenu, SRTabCloseAllOtherTag, nil);
        [menuItem setRepresentedObject:tabViewItem];
        [menu addItem:menuItem];
        
        // Separator
        [menu addItem:[NSMenuItem separatorItem]];
    }
    
    // 'Reload Tab'
    menuItem = HMCopyMenuItemWithTag(tabMenu, SRTabReloadTabTag, nil);
    [menuItem setRepresentedObject:tabViewItem];
    [menu addItem:menuItem];
    
    // 'Reload All Tabs'
    menuItem = HMCopyMenuItemWithTag(tabMenu, SRTabReloadAllTabsTag, nil);
    [menu addItem:menuItem];
    
    // 'Bookmark All Tabs'
    menuItem = HMCopyMenuItemWithTag(tabMenu, SRTabBookmarkAllTabTag, nil);
    [menu addItem:menuItem];
    
    return menu;
}

- (void)tabItemViewDoubleClicked:(HMTabItemView*)view
{
    // Get tab view item
    HMTabViewItem*  tabViewItem;
    tabViewItem = [view tabViewItem];
    
    // Get index and count of tab items
    int index, count;
    index = [_tabView indexOfTabViewItem:tabViewItem];
    count = [_tabView numberOfTabViewItems];
    
    // Get double click action
    int doubleClickAction;
    doubleClickAction = [[NSUserDefaults standardUserDefaults] integerForKey:SRTabDoubleClick];
    switch (doubleClickAction) {
    case SRTabDoubleClickReload: {
        // Reload it
        [[[_pageControllers objectAtIndex:index] webView] reload:self];
        break;
    }
    case SRTabDoubleClickClose: {
        // Close it
        if (count > 1) {
            [self removeTabAtIndex:index];
        }
        else {
            [NSApp sendAction:@selector(closeWindowAction:) to:nil from:self];
        }
        break;
    }
    }
}

//--------------------------------------------------------------//
#pragma mark -- NSComboBox delegate --
//--------------------------------------------------------------//

- (void)comboBoxWillDismiss:(NSNotification*)notification
{
    // Get combo box
    NSComboBox* combo;
    combo = [notification object];
    
    // Select text
    [combo selectText:self];
    
    // For enter key pressing event
    NSEvent*    event;
    event = [NSApp currentEvent];
    if ([event type] == NSKeyDown) {
        // Send action only enter key is pressed
        [[combo target] performSelector:[combo action] withObject:combo];
    }
}

- (void)comboBoxWillPopUp:(NSNotification*)notification
{
    // Get combo box
    NSComboBox* combo;
    combo = [notification object];
    
    // Select first one
    if ([combo numberOfItems] > 0) {
        [combo selectItemAtIndex:0];
    }
}

//- (void)comboBoxSelectionIsChanging:(NSNotification*)notification

- (void)comboBoxSelectionDidChange:(NSNotification*)notification
{
    // Get combo box
    NSComboBox* combo;
    combo = [notification object];
    
    // Get selected index
    int selectedIndex;
    selectedIndex = [combo indexOfSelectedItem];
    
    // Select item again. It changes string value of combo box
    [combo selectItemAtIndex:selectedIndex];
}

//--------------------------------------------------------------//
#pragma mark -- NSControl delegate --
//--------------------------------------------------------------//

- (void)controlTextDidChange:(NSNotification*)notification
{
    id  control;
    control = [notification object];
    
    // For SRURLComboBox
    if ([control isKindOfClass:[HMImageComboBox class]]) {
        // Get string
        NSString*   string;
        string = [control stringValue];
        
        // Remove new line characters
        NSCharacterSet* newLineCharacterSet;
        newLineCharacterSet = [NSCharacterSet newLineCharacterSet];
        if ([string rangeOfCharacterFromSet:newLineCharacterSet 
                options:NSLiteralSearch].location != NSNotFound)
        {
            string = [string stringByTrimmingCharactersInSet:newLineCharacterSet];
            
            [control setStringValue:string];
        }
        
        // Clear image
        [control setImage:[[WebIconDatabase sharedIconDatabase] defaultIconWithSize:NSMakeSize(16, 16)]];
    }
}

//--------------------------------------------------------------//
#pragma mark -- HMImageComboBox delegate --
//--------------------------------------------------------------//

- (BOOL)hmComboBox:(HMImageComboBox*)comboBox writeDataToPasteboard:(NSPasteboard*)pboard
{
    // Check string
    NSString*   string;
    string = [comboBox stringValue];
    if ([string length] == 0) {
        return NO;
    }
    
    // Page data
    NSMutableDictionary*    pageInfo;
    pageInfo = [NSMutableDictionary dictionary];
    [pageInfo setObject:string forKey:@"urlString"];
    
    // Get selected web view
    WebView*        webView;
    WebDataSource*  dataSource;
    NSString*       URLString;
    webView = [[self selectedPageController] webView];
    dataSource = [[webView mainFrame] dataSource];
    URLString = [[[dataSource request] URL] absoluteString];
    if ([URLString isEqualToString:string]) {
        // Get title
        NSString*   title;
        title = [dataSource pageTitle];
        if (title) {
            [pageInfo setObject:title forKey:@"title"];
        }
        
        // Get MIME type
        NSString*   mimeType;
        mimeType = [[dataSource response] MIMEType];
        if (mimeType) {
            [pageInfo setObject:mimeType forKey:@"mime"];
        }
    }
    
    // Write data to pasteboard
    [pboard declareTypes:[NSArray arrayWithObject:SRPageInfoPboardType] owner:nil];
    [pboard setPropertyList:pageInfo forType:SRPageInfoPboardType];
    
    return YES;
}

//--------------------------------------------------------------//
#pragma mark -- SRSearchField delegate --
//--------------------------------------------------------------//

- (void)searchField:(SRSearchField*)searchField resizeToNewSize:(NSSize)size
{
    // Get toolbar item
    NSEnumerator*   enumerator;
    NSToolbarItem*  toolbarItem;
    enumerator = [[[[self window] toolbar] visibleItems] objectEnumerator];
    while (toolbarItem = [enumerator nextObject]) {
        if ([[toolbarItem itemIdentifier] isEqualToString:SRBrowserSearchItem]) {
            // Set new size
            [toolbarItem setMinSize:size];
            [toolbarItem setMaxSize:size];
            
            // Set it default
            [[NSUserDefaults standardUserDefaults] 
                    setInteger:size.width forKey:SRSearchFieldWidth];
        }
    }
}

//--------------------------------------------------------------//
#pragma mark -- Key value observation --
//--------------------------------------------------------------//

- (void)observeValueForKeyPath:(NSString*)keyPath 
        ofObject:(id)object 
        change:(NSDictionary*)change 
        context:(void*)context
{
    // For preference
    if ([object isKindOfClass:[NSUserDefaults class]]) {
        // Bookmark preference
        if ([keyPath isEqualToString:SRBookmarkBarType]) {
            // Get selected browser
            NSString*   browser;
            browser = [object objectForKey:SRBookmarkBarType];
            if (!browser || ![browser isKindOfClass:[NSString class]]) {
                browser = SRBrowserShiira;
            }
            
            // Get bookmark for bookmark bar
            SRBookmark* bookmark;
            bookmark = [[SRAppController sharedInstance] 
                    bookmarkForBookmarkBarOfBrowser:browser];
            if (bookmark) {
                // Set bookmark
                [_bookmarkBar setBookmarks:[bookmark sortedChildren]];
            }
            return;
        }
        if ([keyPath isEqualToString:SRBookmarkBarUseMultiLine]) {
            // Set bookmark wrapping
            [_bookmarkBar setWrap:[object boolForKey:SRBookmarkBarUseMultiLine]];
            [_bookmarkBar sizeToFit];
            
            return;
        }
        
        // Tab preference
        if ([keyPath isEqualToString:SRTabStyle]) {
            // Set tab style
            SRTabStyleType  tabStyle;
            tabStyle = [object integerForKey:SRTabStyle];
            [self setTabStyle:tabStyle];
            
            return;
        }
        if ([keyPath isEqualToString:SRPageDockStyle]) {
            // Set tab style
            SRTabStyleType  tabStyle;
            tabStyle = [object integerForKey:SRTabStyle];
            [self setTabStyle:tabStyle];
            
            return;
        }
    }
}

@end
