/*
  HTSRTabBarView.m
Author: Hetima Computer

Copyright 2004 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 "SRDefaultsKey.h"
#import "SRContextMenu.h"

#import "SRMainWindowController.h"
#import "SRBookmark.h"
#import "SRBookmarkStorage.h"

#import "SRBookmarkButton.h"
#import "SRBookmarkButtonCell.h"
#import "SRProgressIndicator.h"
#import "SRTabView.h"
#import "HTSRTabBarView.h"
#import "SRTBISafariStyleCell.h"
#import "SRTBIImageFrameStyleCell.h"

#define kHTTabBarLeftMargin 10
#define kHTTabBarRightMargin 24

#define kHTTabBarIndicatorWidth 17
#define kHTTabBarIndicatorYActive   1.5
#define kHTTabBarIndicatorYInactive 1.5
#define kAccordingMaxWidthDefault   320
#define kTabMinWidthDefault 64

#define kDefaultTabBarItemCellClass SRTBISafariStyleCell
//#define   kDefaultTabBarItemCellClass SRTBIImageFrameStyleCell

NSString*   HTSRTabBarViewItemPBType = @"HTSRTabBarViewItemPBType";
static NSMenu*  _tabStyleMenu = nil;

@implementation HTSRTabBarView

- (id)initWithFrame:(NSRect)frame
{
    Class   cellClass=nil;
#if 1
    cellClass=[kDefaultTabBarItemCellClass class];
#else
    NSString*   cellClassName=[[NSUserDefaults standardUserDefaults]stringForKey:SRTabStyleClassName];
    if(cellClassName){
        cellClass=objc_getClass([cellClassName cString]);
        if(![cellClass conformsToProtocol:@protocol(HTSRTabBarItemCellProtocol)]){
            cellClass=nil;
        }
    }
    if(cellClass==nil){
        cellClass=[kDefaultTabBarItemCellClass class];
    }
#endif
    
    float height=[cellClass cellHeight]
                +[cellClass cellTopMargin]
                +[cellClass cellBottomMargin];
    frame.size.height=height;
    frame.origin.y -= height;

    self = [super initWithFrame:frame];
    if (self) {
        NSRect  aRect;
        _cellClass = cellClass;
        _accordingToLabelWidth = NO;
        _accordingMaxWidth = kAccordingMaxWidthDefault;
        _showNewTabButton = YES;
        _hasMenu = YES;
        _tabMinWidth = kTabMinWidthDefault;
        _hasCloseButton = YES;
        _cells = [[NSMutableArray alloc] initWithCapacity:16];
        _indicators = [[NSMutableArray alloc] initWithCapacity:16];
        _srIndicators = [[NSMutableArray alloc] initWithCapacity:16];
        [self registerForDraggedTypes:
                [NSArray arrayWithObjects:
                        SRBookmarkPboardType, NSStringPboardType, HTSRTabBarViewItemPBType, nil]];
        _destIndex=-1;

        //make clip popup
        aRect=NSMakeRect(frame.size.width-kHTTabBarRightMargin+1,0,
                    kHTTabBarRightMargin-1,frame.size.height);
        _clippedPopUpBtn=[[HTSRTabBarClippedPopUpBtn alloc]initWithFrame:aRect pullsDown:YES];
        if(_clippedPopUpBtn){
            [_clippedPopUpBtn setAutoresizingMask:NSViewNotSizable|NSViewMinXMargin];
            [self addSubview:_clippedPopUpBtn];
            if (![_clippedPopUpBtn isHidden]) [_clippedPopUpBtn setHidden:YES];
        }
        //make New Tab button
        aRect.size.height=height+2;
        aRect.origin.y=-1;
        
        _newTabBtn=[[NSButton alloc]initWithFrame:aRect];
        if(_newTabBtn){

            NSImage*    tabNewImage=[NSImage imageNamed:@"TabNew"];
            if(tabNewImage){
                NSSize  aSize=[tabNewImage size];
                aSize.height+=4;
                aSize.width+=4;
                [_newTabBtn setFrameSize:aSize];
                [_newTabBtn setTitle:@""];
                
                [_newTabBtn setImage:tabNewImage];
                tabNewImage=[NSImage imageNamed:@"TabNew_Pressed"];
                if(tabNewImage)[_newTabBtn setAlternateImage:tabNewImage];

                [_newTabBtn setImagePosition:NSImageOnly];
            }else{

                [_newTabBtn setTitle:@"+"];
                [_newTabBtn setFrameSize:NSMakeSize(18,18)];
                NSMutableAttributedString*  attrStr=[[[NSMutableAttributedString alloc]initWithString:
                                                    [_newTabBtn title]]autorelease];
                if (attrStr) {
                    NSRange range=NSMakeRange(0, [attrStr length]);

                    NSMutableParagraphStyle*    paraStyle=[[NSParagraphStyle defaultParagraphStyle]mutableCopy];
                    [paraStyle setAlignment:NSCenterTextAlignment];
                    [attrStr addAttribute:NSParagraphStyleAttributeName value:paraStyle range:range];

                    // Add shadow attribute
                    NSShadow*   shadow;
                    shadow = [[[NSShadow alloc] init] autorelease];
                    float   shadowAlpha=0.5;
                    [shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.0 alpha:shadowAlpha]];
                    [shadow setShadowOffset:NSMakeSize(0, -1)];
                    [shadow setShadowBlurRadius:1.0];
                    [attrStr addAttribute:NSShadowAttributeName value:shadow range:range];
                    
                    [_newTabBtn setAttributedAlternateTitle:attrStr];
                }
            
                [_newTabBtn setImagePosition:NSNoImage];
            }
            //[_newTabBtn setImage:[NSImage imageNamed:@"TabPlus"]];
            //[_newTabBtn setAlternateImage:[NSImage imageNamed:@"TabPlus_Pressed"]];
            [_newTabBtn setBordered:NO];
            [_newTabBtn setAction:@selector(newTabAction:)];
            [_newTabBtn setButtonType:NSMomentaryChangeButton];
            [_newTabBtn setBezelStyle:NSRegularSquareBezelStyle];
            [self addSubview:_newTabBtn];
        }
        
        // Default tab view type
        _tabViewType = HTSRTopTabsBezelBorder;
    }
    return self;
}

- (void)dealloc
{
    [_newTabBtn release];
    [_clippedPopUpBtn release];
    [_indicators release];
    [_srIndicators release];
    [_cells release];
    [_color release];

    [super dealloc];
}

#pragma mark -

-(void)setParentTabView:(SRTabView*)parentTabView
{
    _parentTabView = parentTabView;
}

#pragma mark -
// Custom Appearance support

- (Class)cellClass
{
    return _cellClass;
}

- (void)setCellClass:(Class)aClass;
{
    if(aClass && aClass!=_cellClass && [aClass conformsToProtocol:@protocol(HTSRTabBarItemCellProtocol)]){
        _cellClass=aClass;

        float height=[_cellClass cellHeight]
                +[_cellClass cellTopMargin]
                +[_cellClass cellBottomMargin];
        NSRect  frame=[self frame];
        float   diff=frame.size.height-height;
        frame.size.height=height;
        frame.origin.y += diff;
        [self setFrame:frame];

        [_parentTabView updateAppearance];
        [self _updateMatrixAndMenu];
    }
}

- (void)setCellClassWithName:(NSString*)className
{
    Class   aClass = NSClassFromString(className);
    if (aClass==nil) {
        aClass = [kDefaultTabBarItemCellClass class];
    }
    else {
        if ([aClass respondsToSelector:@selector(supportTabViewType:)]) {
            if (![aClass supportTabViewType:_tabViewType]) {
                // Do not change
                return;
            }
        }
    }
    
    [self setCellClass:aClass];
}



#pragma mark -
#pragma mark ---- access ----

//close button
- (BOOL)hasCloseButton
{
    return _hasCloseButton;
}

- (void)setHasCloseButton:(BOOL)hasClose
{
    if (_hasCloseButton != hasClose) {
        _hasCloseButton = hasClose;
        [self _updateMatrixAndMenu];
    }
}

- (BOOL)accordingToLabelWidth
{
    return _accordingToLabelWidth;
}

- (void)setAccordingToLabelWidth:(BOOL)flag
{
    if (_accordingToLabelWidth != flag) {
        _accordingToLabelWidth = flag;
        [self _updateMatrixAndMenu];
    }
}

-(BOOL)showNewTabButton
{
    return _showNewTabButton;
}

-(void)setShowNewTabuBtton:(BOOL)flag
{
    if (_showNewTabButton != flag) {
        _showNewTabButton = flag;
        if (!_showNewTabButton) {
            [_newTabBtn setHidden:YES];
        }
        
        [self _updateMatrixAndMenu];
    }
}

-(BOOL)hasMenu
{
    return _hasMenu;
}

-(void)setHasMenu:(BOOL)flag
{
    if (_hasMenu != flag) {
        _hasMenu = flag;
    }
}

- (NSColor*)color
{
    return _color;
}

- (void)setColor:(NSColor*)aColor
{
    if(_color != aColor){
        [_color autorelease];
        _color=[aColor retain];
    }
}

- (void)setFont:(NSFont*)font
{
    if(font && (_font != font) ){
        [_font autorelease];
        _font=[font retain];
    }
}


//tab width
- (void)setTabDefaultWidth:(int)width
{
    if(width<1600)
        _tabDefaultWidth=width;
}

- (void)setTabMinWidth:(int)width
{
    if(width>44)
        _tabMinWidth=width;
}

- (float)tabBarViewHeight
{
    float   result;
    result=[_cellClass cellHeight]+[_cellClass cellTopMargin]+[_cellClass cellBottomMargin];
    return result;
}

- (float)leftMargin
{
    return kHTTabBarLeftMargin;
}

- (float)rightMargin
{
    return kHTTabBarRightMargin;
}



- (int)indexOfCell:(id)cell
{
    return [_cells indexOfObject:cell];
}

- (HTSRTabViewType)tabViewType
{
    return _tabViewType;
}

- (void)setTabViewType:(HTSRTabViewType)tabViewType
{
    _tabViewType = tabViewType;
    
    // Check with current cell
    if ([_cellClass respondsToSelector:@selector(supportTabViewType:)]) {
        if (![_cellClass supportTabViewType:tabViewType]) {
            [self setCellClass:[kDefaultTabBarItemCellClass class]];
        }
    }
}


#pragma mark -
#pragma mark ---- action ----
- (IBAction)actAccordingToLabelWidthMenu:(id)sender
{
    int state=[sender state];
    _accordingToLabelWidth=(state!=NSOnState);
    [sender setState:(_accordingToLabelWidth ? NSOnState:NSOffState)];

    [self _updateMatrixAndMenu];
}

- (IBAction)clippedMenuAction:(id)sender
{
    int idx=[sender tag];
    if(idx>=0 && [_parentTabView numberOfItems]>idx){
        [_parentTabView selectItemAtIndex:idx];
    }else{
        [self _updateMatrixAndMenu];
    }
}

- (IBAction)matrixAction:(id)sender
{
    if(self==sender){
        int idx=_selectedCellIndex;
        int currentIdx=[_parentTabView selectedIndex];
        
        if(idx>=0 && [_parentTabView numberOfItems]>idx && idx!=currentIdx){
            //draw temporary
            //until tabView:didSelectTabViewItem: comes
            HTSRTabBarItemCell*  cell;
            int cnt=[_cells count];
            if(cnt>currentIdx){
                cell=[_cells objectAtIndex:currentIdx];
                [cell setState:NSOffState];
            }
            if(cnt>idx){
                cell=[_cells objectAtIndex:idx];
                [cell setState:NSOnState];
            }
            [self display];
            
            [_parentTabView selectItemAtIndex:idx];
        }else{
            [self _updateMatrixAndMenu];
        }
    }
}

- (IBAction)matrixActionCloseBtn:(id)sender
{
    int idx=_selectedCellIndex;
    [_parentTabView removeItemAtIndex:idx];
}

- (IBAction)matrixActionNothing:(id)sender
{
    [self _updateMatrixAndMenu];
}

- (void)setAction:(SEL)action
{
    _action=action;
}

// Action from _tabStyleMenu
- (void)changeTabStyle:(id)sender
{
    NSString*   className=[[sender representedObject]className];
    [[NSUserDefaults standardUserDefaults]setObject:className forKey:SRTabStyleClassName];
}

// NSProgressIndicator
- (void)tabViewItemStartedLoading:(int)idx
{
    [self _updateIndicatorOfIndex:idx active:YES];
}
- (void)tabViewItemFinishedLoading:(int)idx
{
    [self _updateIndicatorOfIndex:idx active:NO];
}
-(void)tabViewItemEstimateChanged:(int)idx progress:(double)progress
{
    int iCnt=[_srIndicators count];
    if(iCnt>idx){
        SRProgressIndicator*    srIndicator=[_srIndicators objectAtIndex:idx];
        [srIndicator setDoubleValue:progress];
    }
    [self setNeedsDisplay:YES];
}

- (void)_updateIndicatorOfIndex:(int)idx active:(BOOL)active
{
    int iCnt=[_indicators count];
    if(iCnt>idx){
        NSProgressIndicator*    indicator=[_indicators objectAtIndex:idx];
        SRProgressIndicator*    srIndicator=[_srIndicators objectAtIndex:idx];
        if(active){
            if ([srIndicator isHidden]) [srIndicator setHidden:NO];
            [srIndicator setDoubleValue:0.0];
            if ([indicator isHidden]) [indicator setHidden:NO];
            [indicator startAnimation:self];
        }else{
            if (![srIndicator isHidden]) [srIndicator setHidden:YES];
            if (![indicator isHidden]) [indicator setHidden:YES];
            [indicator stopAnimation:self];
        }
    }
    int cCnt=[_cells count];
    if(cCnt>idx){
        HTSRTabBarItemCell* cell=[_cells objectAtIndex:idx];
        [cell setIsLoading:active];
    }
    [self setNeedsDisplay:YES];
}

#pragma mark -
#pragma mark ---- tracking ----
- (BOOL)mouseDownCanMoveWindow
{
    return NO;
}
- (void)mouseDown:(NSEvent *)theEvent
{
    NSPoint mousePt=[self convertPoint:[theEvent locationInWindow] fromView:nil];
    NSRect  cellFrame;
    HTSRTabBarItemCell* cell=[self cellForPoint:mousePt cellFrame:&cellFrame];
    
    // For double click
    if ([theEvent clickCount] > 1) {
        if ([theEvent clickCount] == 2) {
            if (cell) {
                int index;
                index = [_cells indexOfObject:cell];
                
				int	doubleClick;
				doubleClick = [[NSUserDefaults standardUserDefaults] integerForKey:SRTabDoubleClick];
				
                switch (doubleClick) {
                case SRTabDoubleClickReload: {
                    // Reaload page
                    WebView*    webView;
                    webView = (WebView*)[_parentTabView viewAtIndex:index];
                    if (webView && [webView respondsToSelector:@selector(reload:)]) {
                        [webView reload:self];
                    }
                    break;
                }
                case SRTabDoubleClickClose: {
                    // Close tab
                    if ([_parentTabView numberOfItems] > 1) {
                        [_parentTabView removeItemAtIndex:index];
                    }
                    else {
                        [[self window] performClose:self];
                    }
                    break;
                }
                }
            }
        }
        
        return;
    }
    
    // Show context menu by mouse press holding
    if (SRShowContextMenuByMousePressHolding(self, theEvent)) {
        return;
    }
    
    _trackingMode=track_normal;
    if(cell){
        _action=nil;
        _selectedCellIndex=[_cells indexOfObject:cell];
        if([cell myTrackMouse:theEvent inRect:cellFrame ofView:self point:mousePt]){
            if(_action && [self respondsToSelector:_action]){
                objc_msgSend(self, _action, self);
            }
        }else{
            _trackingStartPoint=mousePt;
            _trackingMode=track_drag;
        }
    }else{
        _selectedCellIndex=-1;
    }
    _action=nil;
}
- (void)mouseDragged:(NSEvent *)theEvent
{
    if(_trackingMode!=track_drag || _selectedCellIndex<0)   return;
    if ([_cells count] <= 1) return;
    
    NSPoint currentPoint=[self convertPoint:[theEvent locationInWindow] fromView:nil];
    float   dx=fabs(currentPoint.x-_trackingStartPoint.x);
    float   dy=fabs(currentPoint.y-_trackingStartPoint.y);
    float   distance=sqrt(dx*dx+dy*dy);
    if(dy>3 || distance>=10){
        NSRect  cellFrame;
        id cell=[self cellForPoint:_trackingStartPoint cellFrame:&cellFrame];
        _trackingMode=track_normal;
        if(cell==nil)return;

        NSImage*    dragImage=[cell dragImageForRect:cellFrame];
        if([self isFlipped])cellFrame.origin.y+=cellFrame.size.height;
        NSSize  offset=NSZeroSize;
        NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSDragPboard];
        [pb declareTypes:[NSArray arrayWithObjects: /*NSStringPboardType,*/ HTSRTabBarViewItemPBType, nil ] owner: nil];
//      [pb setString:[[NSNumber numberWithInt:[_cells indexOfObject:cell]]stringValue] forType:NSStringPboardType];
        [pb setString:[[NSNumber numberWithInt:[_cells indexOfObject:cell]]stringValue] forType:HTSRTabBarViewItemPBType];

        [self dragImage:dragImage at:cellFrame.origin/*currentPoint*/
                    offset:offset event:theEvent pasteboard:pb source:self slideBack:NO];

        _destIndex=-1;
        [self setNeedsDisplay:YES];
        return;
    }
}

- (void)mouseUp:(NSEvent *)theEvent
{
    NSPoint currentPoint=[self convertPoint:[theEvent locationInWindow] fromView:nil];
    if(_trackingMode==track_drag){
        id cell=[self cellForPoint:_trackingStartPoint cellFrame:nil];
        if([self cellForPoint:currentPoint cellFrame:nil]==cell){
            [self matrixAction:self];
        }else{
            [self matrixActionNothing:self];
        }
    }
}

- (id)cellForPoint:(NSPoint)point cellFrame:(NSRectPointer)outFrame
{
    NSRect  aRect=[self _cellSpaceRect];

    if(!NSPointInRect(point,aRect)) return nil;

    int i,cnt=[_cells count];
    for(i=0;i<cnt;i++){
        HTSRTabBarItemCell*   cell=[_cells objectAtIndex:i];
        switch (_tabViewType) {
        case HTSRTopTabsBezelBorder:
        case HTSRBottomTabsBezelBorder: {
            float   width=[cell width];
            aRect.size.width=width;

            if(NSPointInRect(point,aRect)){
                if(outFrame)    *outFrame=aRect;
                return cell;
            }
            aRect.origin.x+=width;
            break;
        }
        case HTSRLeftTabsBezelBorder:
        case HTSRRightTabsBezelBorder: {
            float   height=[cell height];
            aRect.size.height=height;

            if(NSPointInRect(point,aRect)){
                if(outFrame)    *outFrame=aRect;
                return cell;
            }
            aRect.origin.y+=height;
            break;
        }
        }
    }
    return nil;
}

/*
- (NSRect)_cellFrameForIndex:(int)idx
{
    NSRect  aRect=[self _cellSpaceRect];
        
    int i,cnt=[_cells count];
    if(cnt<idx) return NSZeroRect;
    for(i=0;i<cnt;i++){
        HTSRTabBarItemCell*   cell=[_cells objectAtIndex:i];
        float   width=[cell width];
        aRect.size.width=width;
        if(idx==i){
            return  aRect;
        }
        aRect.origin.x+=width;
    }
    return NSZeroRect;
}
*/
- (float)_cellSpaceWidth
{
    float   width = 0.0f;
    
    switch (_tabViewType) {
    case HTSRTopTabsBezelBorder:
    case HTSRBottomTabsBezelBorder: {
        width=[self frame].size.width;
        width=width-kHTTabBarLeftMargin - kHTTabBarRightMargin;
        break;
    }
    case HTSRLeftTabsBezelBorder:
    case HTSRRightTabsBezelBorder: {
        width=[self frame].size.height;
        width=width-kHTTabBarLeftMargin - kHTTabBarRightMargin;
        break;
    }
    }
    
    return width;
}


- (NSRect)_cellSpaceRect
{
    NSRect  aRect=[self frame];
    
    switch (_tabViewType) {
    case HTSRTopTabsBezelBorder: {
        aRect.origin.x=kHTTabBarLeftMargin;
        aRect.origin.y=[_cellClass cellTopMargin];
        aRect.size.width=[self _cellSpaceWidth];
        aRect.size.height=[_cellClass cellHeight];
        break;
    }
    case HTSRLeftTabsBezelBorder: {
        aRect.origin.x=[_cellClass cellTopMargin];
        aRect.origin.y=kHTTabBarLeftMargin;
        aRect.size.width=[_cellClass cellHeight];
        aRect.size.height=[self _cellSpaceWidth];
        break;
    }
    case HTSRRightTabsBezelBorder: {
        aRect.origin.x=[_cellClass cellTopMargin];
        //aRect.origin.x=[self frame].size.width - [_cellClass cellTopMargin] - [_cellClass cellHeight];
        aRect.origin.y=kHTTabBarLeftMargin;
        aRect.size.width=[_cellClass cellHeight];
        aRect.size.height=[self _cellSpaceWidth];
        break;
    }
    case HTSRBottomTabsBezelBorder: {
        break;
    }
    }
    
    return aRect;
}

#pragma mark ---- drag drop ----

- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
    return  [self _myDraggingEnterdOrUpdated:sender];
}
- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender; 
{
    return  [self _myDraggingEnterdOrUpdated:sender];
}
- (void)draggingExited:(id <NSDraggingInfo>)sender
{
    _destIndex=-1;
    [self setNeedsDisplay:YES];
}

- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
{
    if([sender draggingSource]==self){
        return YES;
    }else{
        NSPasteboard*   pb=[sender draggingPasteboard];

        if([[sender draggingSource] isKindOfClass:[SRBookmarkButton class]]){
            if([[[sender draggingSource] bookmark] type]==SRBookmarkTypeHTML){
                return YES;
            }
        }

        if([pb respondsToSelector:@selector(_web_bestURL)]){
            NSURL*  URL=objc_msgSend(pb,@selector(_web_bestURL));
            if(URL) return YES;
        }
    }
    return NO;
}

- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
    id src=[sender draggingSource];

    if(src==self){
        return YES;
    }else{
        id  winCtl=[[self window]windowController];
        if([src isKindOfClass:[SRBookmarkButton class]] && [[src bookmark] type]==SRBookmarkTypeHTML){
            SRBookmark* bookmark=[src bookmark];
            if(bookmark){
                [winCtl openInNewTabBookmark:bookmark];
                return YES;
            }
        }

        NSPasteboard*   pb=[sender draggingPasteboard];
        if([pb respondsToSelector:@selector(_web_bestURL)]){
            NSURL*  URL=nil;
            URL=objc_msgSend(pb,@selector(_web_bestURL));
            [winCtl openInNewTabURL:URL];
            return YES;
        }
    }
    return NO;
}

- (void)concludeDragOperation:(id <NSDraggingInfo>)sender
{
    NSTabView*  tabView;
    tabView = [_parentTabView tabView];
    
    int destIndex=_destIndex;
    _destIndex=-1;
    if(destIndex==-1)   return;
    id  savedItem=[tabView selectedTabViewItem];

    if([sender draggingSource]==self){
        if(_selectedCellIndex<destIndex)
            destIndex--;
        
        NSTabViewItem*  draggedItem=[tabView tabViewItemAtIndex:_selectedCellIndex];
        [tabView removeTabViewItem:draggedItem];
        [tabView insertTabViewItem:draggedItem atIndex:destIndex];
        if(savedItem)
            [tabView selectTabViewItem:savedItem];
        [self _updateMatrixAndMenu];
    }
}

// draggingEnded: is not yet implemented
/*
- (void)draggingEnded:(id <NSDraggingInfo>)sender
{
    _destIndex=-1;
}
*/

- (NSDragOperation)_myDraggingEnterdOrUpdated:(id <NSDraggingInfo>)info
{
    NSDragOperation result=NSDragOperationGeneric;
    NSRect  cellFrame;
    NSPoint mousePt=[self convertPoint:[info draggingLocation] fromView:nil];
    int     prevIndex=_destIndex;
    id cell=[self cellForPoint:mousePt cellFrame:&cellFrame];
    if(cell){
        _destIndex=[_cells indexOfObject:cell];
        
        switch (_tabViewType) {
        case HTSRTopTabsBezelBorder:
        case HTSRBottomTabsBezelBorder: {
            float   midX=NSMidX(cellFrame);
            if(mousePt.x>midX)_destIndex++;
            break;
        }
        case HTSRLeftTabsBezelBorder:
        case HTSRRightTabsBezelBorder: {
            float   midY=NSMidY(cellFrame);
            if(mousePt.y>midY)_destIndex++;
            break;
        }
        }
    }else{
        switch (_tabViewType) {
        case HTSRTopTabsBezelBorder:
        case HTSRBottomTabsBezelBorder: {
            if(mousePt.x<=kHTTabBarLeftMargin) _destIndex=0;
            else _destIndex=[_cells count];
            break;
        }
        case HTSRLeftTabsBezelBorder:
        case HTSRRightTabsBezelBorder: {
            if(mousePt.y<=kHTTabBarLeftMargin) _destIndex=0;
            else _destIndex=[_cells count];
            break;
        }
        }
    }

    id src=[info draggingSource];
    if(src==self){
        if(_selectedCellIndex==_destIndex ||_selectedCellIndex+1==_destIndex){
            result=NSDragOperationNone;
            _destIndex=-1;
        }
    }else{
        _destIndex=-1;
        result=NSDragOperationNone;
        NSPasteboard*   pb=[info draggingPasteboard];
        
        if([src isKindOfClass:[SRBookmarkButton class]] && [[src bookmark] type]==SRBookmarkTypeHTML){
                return NSDragOperationCopy;
        }

        if([pb respondsToSelector:@selector(_web_bestURL)]){
            NSURL*  URL=objc_msgSend(pb,@selector(_web_bestURL));
            if(URL) return NSDragOperationCopy;
        }
    }
    if(_destIndex!=prevIndex)[self setNeedsDisplay:YES];

    return result;
}

//NSDraggingSource
- (BOOL)ignoreModifierKeysWhileDragging
{
    return YES;
}

- (unsigned int)draggingSourceOperationMaskForLocal:(BOOL)isLocal
{
    return NSDragOperationEvery;
}

- (void)draggedImage:(NSImage*)image endedAt:(NSPoint)point operation:(NSDragOperation)operation
{
    if (operation != NSDragOperationNone) {
        return;
    }
    
#if 0
    // Ignore it if end point is in itself
    NSPoint mouseLoc;
    mouseLoc = [self convertPoint:point fromView:nil];
    if (NSPointInRect(mouseLoc, [self frame])) {
        return;
    }
    
    // Get index of dragged cell
    NSPasteboard*   pboard;
    NSString*       indexString;
    int             index;
    pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
    indexString = [pboard stringForType:HTSRTabBarViewItemPBType];
    if (!indexString) {
        return;
    }
    index = [indexString intValue];
    
    // Get dragged web view
    WebView*    webView;
    webView = (WebView*)[_parentTabView viewAtIndex:index];
    if (!webView) {
        return;
    }
    
    // Create untitled document
    SRMainDocument* document;
    document = [[SRDocumentController sharedDocumentController] 
            openUntitledDocumentOfType:SRHTMLDocumentType display:NO];
    
    // Get tab view
    SRTabView*  tabView;
    tabView = [(SRMainWindowController*)[document mainWindowController] srTabView];
    if (!tabView) {
        return;
    }
    
    // Replace first view of tab view
    [webView retain];
    [_parentTabView removeItemAtIndex:index];
    [webView setHostWindow:[tabView window]];
    [[[tabView tabView] tabViewItemAtIndex:0] setView:webView];
    [webView release];
    
    // Resize subviews
    [[tabView tabView] resizeSubviewsWithOldSize:[tabView frame].size];
    [[tabView window] makeFirstResponder:[tabView viewOfSelectedTabViewItem]];
    
    // Show window
    [document showWindows];
#endif
}

#pragma mark ---- menu ----
- (NSMenu *)menuForEvent:(NSEvent *)theEvent
{
    if (!_hasMenu) {
        return nil;
    }
    
    NSPoint mousePt=[self convertPoint:[theEvent locationInWindow] fromView:nil];
    NSRect  cellFrame;
    HTSRTabBarItemCell *cell=[self cellForPoint:mousePt cellFrame:&cellFrame];
    if(cell){
        return [self _menuForCell:cell event:theEvent];
    }else{
        return [self _backgroundMenuForEvent:theEvent];
    }
}

- (NSMenu *)_backgroundMenuForEvent:(NSEvent*)event
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];

    // Get number of tab items and cell index
    int numberOfTabs;
    numberOfTabs = [_parentTabView numberOfItems];
    
    // Create tag array
    NSMutableArray* tags;
    tags = [NSMutableArray array];

    [tags addObject:[NSNumber numberWithInt:SRTabNewTabTag]];
    if (numberOfTabs > 1) {
        [tags addObject:[NSNumber numberWithInt:SRTabShowAllTabsTag]];
    }
    //[tags addObject:[NSNumber numberWithInt:SRTabBookmarkAllTabTag]];
    [tags addObject:[NSNumber numberWithInt:SRTabAccordingToStringTag]];
    [tags addObject:[NSNumber numberWithInt:SRTabChangeTabStyleTag]];

    // Create menu
    NSMenu* menu = nil;
    if ([tags count] > 0) {
        // Make context menu
        menu = [SRContextMenu copyMenuFrom:[SRContextMenu tabContextMenu] 
                ofTags:tags 
                target:nil];
        
        // Set represented object
        [[menu itemArray] makeObjectsPerformSelector:@selector(setRepresentedObject:) 
                withObject:self];
    }

    // Set menu state
    BOOL            isTabAccordingTo;
    id<NSMenuItem>  tabAccordingToItem;
    isTabAccordingTo = [defaults boolForKey:SRTabAccordingToStringWidth];
    tabAccordingToItem = [menu itemWithTag:SRTabAccordingToStringTag];
    [tabAccordingToItem setState:isTabAccordingTo ? NSOnState : NSOffState];

    id<NSMenuItem>  tabStyleItem;
    tabStyleItem=[menu itemWithTag:SRTabChangeTabStyleTag];
    [tabStyleItem setSubmenu:[self _tabStyleMenu]];

    return menu;
}


- (NSMenu *)_menuForCell:(id)cell event:(NSEvent*)event
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];

    // Get number of tab items and cell index
    int numberOfTabs;
    int tabIndex;
    numberOfTabs = [_parentTabView numberOfItems];
    tabIndex = [_cells indexOfObject:cell];
    if (tabIndex == -1) {
        return nil;
    }

    // Create tag array
    NSMutableArray* tags;
    tags = [NSMutableArray array];

    [tags addObject:[NSNumber numberWithInt:SRTabNewTabTag]];
    [tags addObject:[NSNumber numberWithInt:SRTabCloseTabTag]];
    if (numberOfTabs > 1) {
        [tags addObject:[NSNumber numberWithInt:SRTabShowAllTabsTag]];
    }
    [tags addObject:[NSNumber numberWithInt:SRTabChangeTabStyleTag]];
    if (numberOfTabs > 1 && tabIndex < numberOfTabs - 1) {
        [tags addObject:[NSNumber numberWithInt:SRTabCloseAllRightTag]];
    }
    if (numberOfTabs > 1 && tabIndex > 0) {
        [tags addObject:[NSNumber numberWithInt:SRTabCloseAllLeftTag]];
    }
    if (numberOfTabs > 1) {
        [tags addObject:[NSNumber numberWithInt:SRTabCloseAllOtherTag]];
    }
    [tags addObject:[NSNumber numberWithInt:SRTabReloadTabTag]];
    [tags addObject:[NSNumber numberWithInt:SRTabReloadAllTabsTag]];
    [tags addObject:[NSNumber numberWithInt:SRTabBookmarkAllTabTag]];
    [tags addObject:[NSNumber numberWithInt:SRTabAccordingToStringTag]];

    // Create menu
    NSMenu* menu = nil;
    if ([tags count] > 0) {
        // Make context menu
        menu = [SRContextMenu copyMenuFrom:[SRContextMenu tabContextMenu] 
                ofTags:tags 
                target:nil];
        
        // Set represented object
        [[menu itemArray] makeObjectsPerformSelector:@selector(setRepresentedObject:) 
                withObject:[NSNumber numberWithInt:tabIndex]];
    }

    // Set menu state
    BOOL            isTabAccordingTo;
    id<NSMenuItem>  tabAccordingToItem;
    isTabAccordingTo = [defaults boolForKey:SRTabAccordingToStringWidth];
    tabAccordingToItem = [menu itemWithTag:SRTabAccordingToStringTag];
    [tabAccordingToItem setState:isTabAccordingTo ? NSOnState : NSOffState];

    id<NSMenuItem>  tabStyleItem;
    tabStyleItem=[menu itemWithTag:SRTabChangeTabStyleTag];
    [tabStyleItem setSubmenu:[self _tabStyleMenu]];

    return menu;
}

- (NSMenu*)_tabStyleMenu
{
    NSMenu* tagMenu=[HTSRTabBarView _sharedTabStyleMenu];
    NSArray*    itemArray=[tagMenu itemArray];
    int i, cnt=[itemArray count];
    for(i=0;i<cnt;i++){
        id <NSMenuItem>  aItem=[itemArray objectAtIndex:i];
        if([aItem representedObject]==_cellClass){
            [aItem setState:NSOnState];
            break;
        }
    }
    return _tabStyleMenu;
}

+ (NSMenu*)_sharedTabStyleMenu
{
    if(_tabStyleMenu==nil){
        id <NSMenuItem> aItem;
        _tabStyleMenu=[[NSMenu alloc]initWithTitle:@""];
        aItem=[_tabStyleMenu addItemWithTitle:[SRTBISafariStyleCell name] 
                            action:@selector(changeTabStyle:) keyEquivalent:@""];
        [aItem setRepresentedObject:[SRTBISafariStyleCell class]];
        [aItem setEnabled:YES];

        //[_tabStyleMenu addItem:[NSMenuItem separatorItem]];

        aItem=[_tabStyleMenu addItemWithTitle:[SRTBIImageFrameStyleCell name] 
                            action:@selector(changeTabStyle:) keyEquivalent:@""];
        [aItem setRepresentedObject:[SRTBIImageFrameStyleCell class]];
        [aItem setEnabled:YES];
    
    }

    //NSOffState==(int)0==(id)nil   toriaezu warning denaikedo...
    [[_tabStyleMenu itemArray] makeObjectsPerformSelector:@selector(setState:) 
                withObject:NSOffState];

    return _tabStyleMenu;
}

#pragma mark -
#pragma mark ---- drawing ----

- (void)drawRect:(NSRect)rect
{
    HTSRTabBarItemCell* bgDrawerCell=nil;
    int selectedItemIndex=[_parentTabView selectedIndex];
    if([_cells count]>selectedItemIndex){
        bgDrawerCell=[_cells objectAtIndex:selectedItemIndex];
    }else{
        bgDrawerCell=[_cells lastObject];
    }

    [bgDrawerCell drawBackgroundRect:[self bounds] inView:self];

    // Draw cells
    NSRect  dropHiliteRect=NSZeroRect;

    NSRect  cellFrame=[self _cellSpaceRect];
    NSEnumerator *enumerator;
    if([_cellClass reverseEnumerateWhenDraw]){
        enumerator=[_cells reverseObjectEnumerator];
    }else{
        enumerator=[_cells objectEnumerator];
    }
    HTSRTabBarItemCell* cell;
    while (cell = [enumerator nextObject]){
        int     idx=[_cells indexOfObject:cell];
        
        // Draw cekk
        [cell draw];
        
        // In drop operation
        if(_destIndex==idx){
            dropHiliteRect=[cell frame];
        }
    }
    
    if(_destIndex==[_cells count]){
        dropHiliteRect=[[_cells objectAtIndex:_destIndex-1]frame];
        
        switch (_tabViewType) {
        case HTSRTopTabsBezelBorder:
        case HTSRBottomTabsBezelBorder: {
            dropHiliteRect.origin.x+=dropHiliteRect.size.width;
            break;
        }
        case HTSRLeftTabsBezelBorder:
        case HTSRRightTabsBezelBorder: {
            dropHiliteRect.origin.y+=dropHiliteRect.size.height;
            break;
        }
        }
    }
    if(_destIndex>=0){
        [[NSColor darkGrayColor] set];
        
        switch (_tabViewType) {
        case HTSRTopTabsBezelBorder:
        case HTSRBottomTabsBezelBorder: {
            dropHiliteRect.size.width=4.5;
            cellFrame.origin.x-=2;
            break;
        }
        case HTSRLeftTabsBezelBorder:
        case HTSRRightTabsBezelBorder: {
            dropHiliteRect.size.height=4.5;
            cellFrame.origin.y-=2;
            break;
        }
        }
        
        NSRectFill(dropHiliteRect);
    }
}

- (BOOL)isFlipped
{
    return YES;
}

/*
- (float)marginBottom
{
    return 0;
}
*/
- (void)setFrame:(NSRect)frameRect
{
    [super setFrame:frameRect];
    [self _updateMatrixAndMenu];
}


#pragma mark -
#pragma mark ---- tabView delegate ----



/*
- (void)tabViewDidChangeNumberOfTabViewItems:(NSTabView *)senderTabView
{
    [self _updateMatrixAndMenu];

}
*/
- (void)tabView:(NSTabView *)senderTabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
{
    int selectedItemIndex=[_parentTabView selectedIndex];
    int i,cellCount=[_cells count];

    //clear old selection and select new selection
    NSMenu* clippedMenu=[_clippedPopUpBtn menu];
    if(clippedMenu){
        int i,cnt=[clippedMenu numberOfItems];
        for(i=0;i<cnt;i++){
            SR_VERIFY(i >= 0, @"menu index is less than 0");
            NSMenuItem* menuItem=[clippedMenu itemAtIndex:i];
            [menuItem setState:NSOffState];
        }
    }
    _selectedCellIndex=-1;
    for(i=0;i<cellCount;i++){
        int     tabState=0;
        //NSPoint indicatorPoint=[[_indicators objectAtIndex:i]frame].origin;
        NSCellStateValue    state;
        
        HTSRTabBarItemCell* cell=[_cells objectAtIndex:i];
        
        if(i==selectedItemIndex){
            state=NSOnState;
            tabState |= HTSRTab_SelectedMask;
            //indicatorPoint.y=kHTTabBarIndicatorYActive;
            _selectedCellIndex=i;
        }else{
            state=NSOffState;
            
            if(cellCount!=i+1 && selectedItemIndex==i+1)tabState |= HTSRTab_RightIsSelectedMask;
            else if(selectedItemIndex==i-1)tabState |= HTSRTab_LeftIsSelectedMask;
            //indicatorPoint.y=kHTTabBarIndicatorYInactive;
        }
        [cell setState:state];

        if(cellCount==1)
            tabState |= HTSRTab_PositionLeftMask|HTSRTab_PositionRightMask|HTSRTab_PositionSingleMask;
        else if(i==0)tabState |= HTSRTab_PositionLeftMask;
        else if(i-1==cellCount)tabState |= HTSRTab_PositionRightMask;
        [cell setTabState:tabState];
        //[[_indicators objectAtIndex:i]setFrameOrigin:indicatorPoint];
    }

    if(cellCount<=selectedItemIndex){
        NSMenuItem* targetItem=[clippedMenu itemWithTag:selectedItemIndex];
        if(targetItem)[targetItem setState:NSOnState];
    }

    [self setNeedsDisplay:YES];
}


- (void)_updateMatrixAndMenu
{
    NSTabView*  tabView;
    tabView = [_parentTabView tabView];
    if(tabView==nil) return;

    int i,cellCount=[_cells count];
    NSTabViewItem *selectedItem=[tabView selectedTabViewItem];
    int selectedItemIndex=[tabView indexOfTabViewItem:selectedItem];
    NSMutableArray* widthArray = nil;
    float   cellSpaceWidth=[self _cellSpaceWidth];

    for(i=0;i<cellCount;i++){
        id oldCell=[_cells objectAtIndex:i];
        [[NSNotificationCenter defaultCenter]removeObserver:oldCell];
        if([oldCell closeBtnTrackingTag]!=0)
            [self removeTrackingRect:[oldCell closeBtnTrackingTag]];
    }
    [_cells removeAllObjects];
    _selectedCellIndex=-1;
    //[self removeAllToolTips];

    NSRect  cellRect=[self _cellSpaceRect];
    //cellRect.origin.x+=kHTTabBarLeftMargin;

    cellCount=[tabView numberOfTabViewItems];
    int maxCount;
    float itemWidth = 0.0;
    NSMenu* clippedMenu=nil;

    //calc size
    if(_accordingToLabelWidth){
        float total=0;
        widthArray=[NSMutableArray arrayWithCapacity:cellCount];
        maxCount=1;
        for(i=0;i<cellCount;i++){
            NSString*   label=[[tabView tabViewItemAtIndex:i]label];
            float width=[_cellClass displayWidthOfString:label withCloseButton:_hasCloseButton];
            if(width>_accordingMaxWidth)width=_accordingMaxWidth;
            total+=width;
            if(total>=cellSpaceWidth){
                width=width-(total-cellSpaceWidth);
                [widthArray addObject:[NSNumber numberWithFloat:width]];
                maxCount=i;
                if(width>=_tabMinWidth)maxCount++;
                break;
            }else{
                maxCount=cellCount;
                [widthArray addObject:[NSNumber numberWithFloat:width]];
            }
        }
    }else{
        maxCount=[self _cellSpaceWidth]/_tabMinWidth;
        if(maxCount<1){
            maxCount=1;
            itemWidth=cellSpaceWidth;
        }else{
            if(maxCount>cellCount)maxCount=cellCount;
            itemWidth=(int)(cellSpaceWidth / maxCount)-0.2;
            if(itemWidth>_tabDefaultWidth)itemWidth=_tabDefaultWidth;
            if(itemWidth<_tabMinWidth)itemWidth=_tabMinWidth;
        }
    }

    //main set up loop
    BOOL makeCloseBtn=[self hasCloseButton];
    if(cellCount==1)makeCloseBtn=NO;
    for(i=0;i<cellCount;i++){
        SRTabViewItem* tabViewItem=(SRTabViewItem*)[tabView tabViewItemAtIndex:i];
        if(i<maxCount){
            BOOL    isLoading=NO;
            float   width;
            int     tabState=0;
            HTSRTabBarItemCell* cell =[[[_cellClass alloc]
                        initWithKeeperView:self contentView:[tabViewItem view]]autorelease];
            if (_font) {
                [cell setFont:_font];
            }
            [cell setStringValue:[tabViewItem label]];
            [cell setTag:i];
            [cell setHasCloseButton:makeCloseBtn];
            [cell setColor:_color];
            if(_accordingToLabelWidth){
                width=[[widthArray objectAtIndex:i]floatValue];
            }else{
                width=itemWidth;
            }
            
            switch (_tabViewType) {
            case HTSRTopTabsBezelBorder:
            case HTSRBottomTabsBezelBorder: {
                cellRect.size.width=width;
                break;
            }
            case HTSRLeftTabsBezelBorder:
            case HTSRRightTabsBezelBorder: {
                cellRect.size.height=width;
                break;
            }
            }
            
            [cell setFrame:cellRect];
            
            if([tabViewItem respondsToSelector:@selector(isLoading)])
                isLoading=[tabViewItem isLoading];
            
            [cell setIsLoading:isLoading];

            //[self addToolTipRect:cellRect owner:cell userData:nil];
            //set up close button rollover
            if(makeCloseBtn && [_cellClass canHaveCloseButton]){
                NSTrackingRectTag   tag=[self addTrackingRect:[cell closeBtnRectForFrame:cellRect]
                                    owner:cell userData:nil assumeInside:NO];
                [cell setCloseBtnTrackingTag:tag];
            }

            [cell setEnabled:YES];
            if(selectedItem==tabViewItem){
                _selectedCellIndex=i;
                [cell setState:NSOnState];
                tabState |= HTSRTab_SelectedMask;
            }else{
                [cell setState:NSOffState];
                if(maxCount!=i+1 && selectedItemIndex==i+1)tabState |= HTSRTab_RightIsSelectedMask;
                else if(selectedItemIndex==i-1)tabState |= HTSRTab_LeftIsSelectedMask;
            }
            
            if(cellCount==1)
                tabState |= HTSRTab_PositionLeftMask|HTSRTab_PositionRightMask|HTSRTab_PositionSingleMask;
            else if(i==0)tabState |= HTSRTab_PositionLeftMask;
            else if(i-1==cellCount)tabState |= HTSRTab_PositionRightMask;
            [cell setTabState:tabState];
            
            
            [_cells addObject:cell];

            //setup indicator
            if([_cellClass canHaveIndicator]){
                NSProgressIndicator* indicator;
                SRProgressIndicator* srIndicator;
                int iCount=[_indicators count];
                if(iCount<=i){
                    srIndicator=[[[SRProgressIndicator alloc]initWithFrame:NSZeroRect]autorelease];
                    [self addSubview:srIndicator];
                    if (![srIndicator isHidden]) [srIndicator setHidden:YES];
                    [_srIndicators addObject:srIndicator];
                    
                    indicator=[[[NSProgressIndicator alloc]initWithFrame:NSZeroRect]autorelease];
                    [indicator setStyle:NSProgressIndicatorSpinningStyle];
                    [self addSubview:indicator];
                    if (![indicator isHidden]) [indicator setHidden:YES];
                    [_indicators addObject:indicator];
                }else{
                    indicator=[_indicators objectAtIndex:i];
                    srIndicator=[_srIndicators objectAtIndex:i];
                }

                [indicator setFrame:[cell indicatorRectForFrame:cellRect]];
                [srIndicator setFrame:[cell indicatorRectForFrame:cellRect]];
                if(!isLoading){
                    if (![srIndicator isHidden]) [srIndicator setHidden:YES];
                    if (![indicator isHidden]) [indicator setHidden:YES];
                    [indicator stopAnimation:self];
                }else if([indicator isHidden]){
                    if ([srIndicator isHidden]) [srIndicator setHidden:NO];
                    if ([indicator isHidden]) [indicator setHidden:NO];
                    [indicator startAnimation:self];
                }


            }
            
            switch (_tabViewType) {
            case HTSRTopTabsBezelBorder:
            case HTSRBottomTabsBezelBorder: {
                cellRect.origin.x+=width;
                break;
            }
            case HTSRLeftTabsBezelBorder:
            case HTSRRightTabsBezelBorder: {
                cellRect.origin.y+=width;
                break;
            }
            }
        }else{
            NSMenuItem  *menuItem;
            if(clippedMenu==nil){
                clippedMenu=[[[NSMenu alloc]initWithTitle:@""]autorelease];
                [clippedMenu insertItemWithTitle:@"" action:nil keyEquivalent:@"" atIndex:0];
            }
            menuItem=[[[NSMenuItem alloc]initWithTitle:[tabViewItem label] 
                            action:@selector(clippedMenuAction:) keyEquivalent:@""]autorelease];
            [menuItem setTarget:self];
            [menuItem setTag:i];
            if(selectedItem==tabViewItem)[menuItem setState:NSOnState];
            
            [clippedMenu addItem:menuItem];
        }
    }

    //remove unused indicator
    if([_cellClass canHaveIndicator]){
        cellCount=[_cells count];
        int iCount=[_indicators count];
        if(iCount>cellCount){
            int j=iCount-cellCount;
            for(i=0;i<j;i++){
                NSProgressIndicator* indicator=[_indicators lastObject];
                [indicator removeFromSuperviewWithoutNeedingDisplay];
                [_indicators removeObject:indicator];
                
                SRProgressIndicator* srIndicator=[_srIndicators lastObject];
                [srIndicator removeFromSuperviewWithoutNeedingDisplay];
                [_srIndicators removeObject:srIndicator];
            }
        }

    }

    //clip menu
    cellRect.origin.y=-1;
    cellRect.size.height=[self tabBarViewHeight]+2;
    cellRect.size.width=kHTTabBarRightMargin;
    if(clippedMenu){
        cellRect.origin.x=[self frame].size.width-kHTTabBarRightMargin+1;

        [_clippedPopUpBtn setFrame:cellRect];
        [_clippedPopUpBtn setMenu:clippedMenu];
        if ([_clippedPopUpBtn isHidden]) [_clippedPopUpBtn setHidden:NO];
        if (![_newTabBtn isHidden]) [_newTabBtn setHidden:YES];
    }else{
        if (![_clippedPopUpBtn isHidden]) [_clippedPopUpBtn setHidden:YES];
        if ([_newTabBtn isHidden] && _showNewTabButton) [_newTabBtn setHidden:NO];
        cellRect.size=[_newTabBtn frame].size;
        cellRect.origin.y=(int)([self frame].size.height-cellRect.size.height)/2+1;
        cellRect.origin.x+=4;
        [_newTabBtn setFrame:cellRect];
    }

    [self setNeedsDisplay:YES];
//    [self display];
}


@end

#pragma mark -
NSImage* gHTTabBarGeneralCloseBtn;
NSImage* gHTTabBarGeneralClosePress;
NSImage* gHTTabBarGeneralCloseROver;

NSMutableParagraphStyle*    gTruncatingTailParagraphStyle;

@implementation HTSRTabBarItemCell
+ (void)initialize
{
    //NSBundle* bundle=[NSBundle bundleForClass:[SRTBISafariStyleCell class]];
    gHTTabBarGeneralCloseBtn=[[NSImage imageNamed:@"TabClose_Front"]retain];
    gHTTabBarGeneralClosePress=[[NSImage imageNamed:@"TabClose_Front_Pressed"]retain];
    gHTTabBarGeneralCloseROver=[[NSImage imageNamed:@"TabClose_Front_Rollover"]retain];

    gTruncatingTailParagraphStyle=[[[NSParagraphStyle defaultParagraphStyle]mutableCopy]retain];
    [gTruncatingTailParagraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
    [gTruncatingTailParagraphStyle setAlignment:NSCenterTextAlignment];
}

+(void)myDrawWindowBackgroundRect:(NSRect)rect inView:(NSView*)controlView
{
    //background
    if( [controlView inLiveResize]
     && ([[controlView window]styleMask]&NSTexturedBackgroundWindowMask)
     && [[controlView window] respondsToSelector:@selector(_scaledBackground)]
     && [[controlView window] respondsToSelector:@selector(_texturePattern)] ){

        [objc_msgSend([controlView window],@selector(_scaledBackground)) set];
        NSRectFillUsingOperation(rect, NSCompositeCopy);

        [objc_msgSend([controlView window],@selector(_texturePattern)) set];
        NSRectFillUsingOperation(rect, NSCompositeSourceOver);

    }else{
        NSDrawWindowBackground(rect);
    }
}

+ (NSString*)name
{
    return @"HTSRTabBarItemCell";
}

+ (BOOL)reverseEnumerateWhenDraw
{
    return NO;
}

- (id)initWithKeeperView:(id)keeperView contentView:(id)webView
{
    self = [super init];
    if (self) {
        _keeperView=keeperView;
        _closeBtnTrackingTag=0;
    }
    return self;
}

- (void)dealloc
{
    [_color release];
    [super dealloc];
}


#pragma mark -

- (int)tabState
{
    return _tabState;
}

- (void)setTabState:(int)state
{
    _tabState=state;
}

- (int)tag
{
    return _tag;
}

- (void)setTag:(int)anInt
{
    _tag=anInt;
}

- (void)setIsLoading:(BOOL)flag
{
    _isLoading=flag;
}

- (BOOL)isLoading
{
    return _isLoading;
}

- (NSTrackingRectTag)closeBtnTrackingTag
{
    return _closeBtnTrackingTag;
}

- (void)setCloseBtnTrackingTag:(NSTrackingRectTag)tag
{
    _closeBtnTrackingTag=tag;
}

- (float)width
{
    return _frame.size.width;
}

- (float)height
{
    return _frame.size.height;
}

- (NSRect)frame
{
    return _frame;
}
- (void)setFrame:(NSRect)newRect
{
    _frame=newRect;
}

- (BOOL)hasCloseButton
{
    return _hasCloseButton;
}

- (void)setHasCloseButton:(BOOL)flag
{
    _hasCloseButton=flag;
}

- (NSColor*)color
{
    return _color;
}

- (void)setColor:(NSColor*)aColor
{
    if(aColor && (_color != aColor) ){
        [_color autorelease];
        _color=[aColor retain];
    }
}

+ (BOOL)canHaveCloseButton
{
    return NO;
}
- (NSRect)closeBtnRectForFrame:(NSRect)cellFrame
{
    return NSZeroRect;
}
+ (BOOL)canHaveIndicator
{
    return NO;
}
- (NSRect)indicatorRectForFrame:(NSRect)cellFrame
{
    return NSZeroRect;
}





#pragma mark -
#pragma mark ---- tracking ----

//start
- (BOOL)startTrackingAt:(NSPoint)startPoint inView:(NSView *)controlView
{
    NSRect selfRect=_trackingRect;
    NSRect iconRect=[self closeBtnRectForFrame:selfRect];
    _trackingStartPoint=startPoint;

    if(NSMouseInRect(startPoint, iconRect,[controlView isFlipped])){
        _trackingMode=track_close_btn;
        _trackingHilite=YES;
        [controlView display];
    }else{
        _trackingMode=track_normal;
        _trackingHilite=YES;
        [controlView display];
    }
    return YES;
}


//_trackingMode==track_close_btn only

//drag
- (BOOL)continueTracking:(NSPoint)lastPoint at:(NSPoint)currentPoint inView:(NSView *)controlView
{
    NSRect selfRect=_trackingRect;
    if(_trackingMode==track_close_btn){
        NSRect iconRect=[self closeBtnRectForFrame:selfRect];
        _trackingHilite=NSMouseInRect(currentPoint, iconRect,[controlView isFlipped]);
        [controlView display];
    }else if(_trackingMode==track_normal){
        BOOL    lastHilite=_trackingHilite;
        _trackingHilite=NSMouseInRect(currentPoint, selfRect,[controlView isFlipped]);
        if(lastHilite!=_trackingHilite) [controlView display];

    }
    return YES;
}

//fihish
- (void)stopTracking:(NSPoint)lastPoint at:(NSPoint)stopPoint inView:(NSView *)controlView mouseIsUp:(BOOL)flag
{
    _trackingHilite=NO;
    NSRect selfRect=_trackingRect;
    SEL action = NULL;

    if(flag && _trackingMode==track_close_btn){
        NSRect iconRect=[self closeBtnRectForFrame:selfRect];
        if(NSMouseInRect(stopPoint, iconRect,[controlView isFlipped])){
            action=@selector(matrixActionCloseBtn:);
        }else{
            action=@selector(matrixActionNothing:);
        }
    }else if(_trackingMode==track_normal){
        if(NSMouseInRect(stopPoint, selfRect,[controlView isFlipped])){
            action=@selector(matrixAction:);
            [self setState:NSOnState];
        }else{
            action=@selector(matrixActionNothing:);
        }
    }

    [(NSControl*)controlView setAction:action];
    [controlView display];
}

//prepare
- (BOOL)myTrackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(HTSRTabBarView *)controlView point:(NSPoint)mousePt
{
    //init
    _trackingRect=cellFrame;
    _trackingMode=track_normal;
    [(NSControl*)controlView setAction:@selector(matrixAction:)];

    NSRect iconRect=[self closeBtnRectForFrame:cellFrame];
    if(NSMouseInRect(mousePt, iconRect,[controlView isFlipped])){
        BOOL    result=[super trackMouse:theEvent inRect:cellFrame ofView:controlView untilMouseUp:YES];
        return result;
    }else{
        _trackingMode=track_normal;
        _trackingHilite=YES;
        [controlView display];
        _trackingHilite=NO;
        return NO;
    }
}

- (void)mouseEntered:(NSEvent *)theEvent
{
    _trackingMode=track_ROver_close_btn;
    [_keeperView setNeedsDisplay:YES];
}

- (void)mouseExited:(NSEvent *)theEvent
{
    _trackingMode=track_normal;
    [_keeperView setNeedsDisplay:YES];
}


#pragma mark -

- (void)drawBackgroundRect:(NSRect)rect inView:(HTSRTabBarView *)controlView
{
    NSColor*    lineColor;
    float x=rect.origin.x;
    float y=rect.origin.y;

    if([[controlView window]styleMask]&NSTexturedBackgroundWindowMask){
        lineColor=[NSColor darkGrayColor];
    }else{
        lineColor=[NSColor controlShadowColor];
    }

    //frame
    [lineColor set];
    [NSBezierPath strokeLineFromPoint:NSMakePoint(x,y+0.5) toPoint:NSMakePoint(x+rect.size.width,y+0.5)];
    [NSBezierPath strokeLineFromPoint:NSMakePoint(x,y+rect.size.height-0.5) toPoint:NSMakePoint(x+rect.size.width,y+rect.size.height-0.5)];
}

- (void)draw
{
    [self drawWithFrame:_frame inView:_keeperView];
}

@end


#pragma mark -

@implementation HTSRTabBarClippedPopUpBtn
static NSImage* _HTTabBarClippedPopUpImage;

+ (void)initialize
{
    _HTTabBarClippedPopUpImage=[[NSImage imageNamed:@"ClipIndicator"]retain];
}

- (id)initWithFrame:(NSRect)frameRect pullsDown:(BOOL)flag
{
    self=[super initWithFrame:frameRect pullsDown:YES];
    if (self) {
        [self setBezelStyle:NSRegularSquareBezelStyle];
        [self setBordered:NO];
        [self setTitle:@""];
        [self setPreferredEdge:NSMaxXEdge];
    }
    return self;
}

- (void)drawRect:(NSRect)rect
{
    if(_HTTabBarClippedPopUpImage==nil){
        [super drawRect:rect];
        return;
    }
    rect.origin.x+=4;
    rect.origin.y+=7;
    if([self isFlipped]) {
        rect.origin.y += [_HTTabBarClippedPopUpImage size].height;
    }
    [_HTTabBarClippedPopUpImage compositeToPoint:rect.origin operation:NSCompositeSourceOver];
}

@end


@implementation NSBezierPath(RoundRect)
- (void)appendBezierPathWithRoundedRectangle:(NSRect)aRect withRadius:(float)radius
{
    NSPoint topMid = NSMakePoint(NSMidX(aRect), NSMaxY(aRect));
    NSPoint topLeft = NSMakePoint(NSMinX(aRect), NSMaxY(aRect));
    NSPoint topRight = NSMakePoint(NSMaxX(aRect), NSMaxY(aRect));
    NSPoint bottomRight = NSMakePoint(NSMaxX(aRect), NSMinY(aRect));

    [self moveToPoint:topMid];
    [self appendBezierPathWithArcFromPoint:topLeft 
    toPoint:aRect.origin radius:radius];
    [self appendBezierPathWithArcFromPoint:aRect.origin
    toPoint:bottomRight radius:radius];
    [self appendBezierPathWithArcFromPoint:bottomRight 
    toPoint:topRight radius:radius];
    [self appendBezierPathWithArcFromPoint:topRight toPoint:topLeft radius:radius];
    [self closePath];
}

@end
