text:
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//

#include <assert.h>

#define PROTECTED_THINGS_DISABLE

#include <vgui/Cursor.h>
#include <vgui/IScheme.h>
#include <vgui/IInput.h>
#include <vgui/IPanel.h>
#include <vgui/ISurface.h>
#include <vgui/ISystem.h>
#include <vgui/IVgui.h>
#include <vgui/KeyCode.h>
#include <KeyValues.h>
#include <vgui/MouseCode.h>

#include <vgui_controls/TreeView.h>
#include <vgui_controls/ScrollBar.h>
#include <vgui_controls/TextEntry.h>
#include <vgui_controls/Label.h>
#include <vgui_controls/Button.h>
#include <vgui_controls/TextImage.h>
#include <vgui_controls/ImageList.h>
#include <vgui_controls/ImagePanel.h>

#include "tier1/UtlString.h"

// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>

#ifndef max
#define max(a,b)            (((a) > (b)) ? (a) : (b))
#endif

using namespace vgui;
enum
{
	WINDOW_BORDER_WIDTH=2 // the width of the window's border
};

#define TREE_INDENT_AMOUNT 20

namespace vgui
{

//-----------------------------------------------------------------------------
// Purpose: Displays an editable text field for the text control
//-----------------------------------------------------------------------------
class TreeNodeText : public TextEntry
{
	DECLARE_CLASS_SIMPLE( TreeNodeText, TextEntry );

public:
    TreeNodeText(Panel *parent, const char *panelName, TreeView *tree) : BaseClass(parent, panelName), m_pTree( tree )
    {
		m_bEditingInPlace = false;
		m_bLabelEditingAllowed = false;
		SetDragEnabled( false );
		SetDropEnabled( false );
		AddActionSignalTarget( this );
		m_bArmForEditing = false;
		m_bWaitingForRelease = false;
		m_lArmingTime = 0L;
		SetAllowKeyBindingChainToParent( true );
    }

	MESSAGE_FUNC( OnTextChanged, "TextChanged" )
	{
		GetParent()->InvalidateLayout();
	}

	bool IsKeyRebound( KeyCode code, int modifiers )
	{
		// If in editing mode, don't try and chain keypresses
		if ( m_bEditingInPlace )
		{
			return false;
		}

		return BaseClass::IsKeyRebound( code, modifiers );
	}

	virtual void PaintBackground()
	{
		BaseClass::PaintBackground();

		if ( !m_bLabelEditingAllowed )
			return;

		if ( !m_bEditingInPlace )
			return;

		int w, h;
		GetSize( w, h );
		surface()->DrawSetColor( GetFgColor() );
		surface()->DrawOutlinedRect( 0, 0, w, h );
	}

	virtual void ApplySchemeSettings(IScheme *pScheme)
    {
        TextEntry::ApplySchemeSettings(pScheme);
        SetBorder(NULL);
        SetCursor(dc_arrow);
    }

    virtual void OnKeyCodeTyped(KeyCode code)
    {
		if ( m_bEditingInPlace )
		{
			if ( code == KEY_ENTER )
			{
				FinishEditingInPlace();
			}
			else if ( code == KEY_ESCAPE )
			{
				FinishEditingInPlace( true );
			}
			else
			{
				BaseClass::OnKeyCodeTyped( code );
			}
			return;
		}
		else if ( code == KEY_ENTER && IsLabelEditingAllowed() )
		{
			EnterEditingInPlace();
		}
		else
		{
	        // let parent deal with it (don't chain back to TextEntry)
			CallParentFunction(new KeyValues("KeyCodeTyped", "code", code));
		}
    }

#define CLICK_TO_EDIT_DELAY_MSEC 500

	virtual void OnTick()
	{
		BaseClass::OnTick();
		if ( m_bArmForEditing )
		{
			long msecSinceArming = system()->GetTimeMillis() - m_lArmingTime;

			if ( msecSinceArming > CLICK_TO_EDIT_DELAY_MSEC )
			{
				m_bArmForEditing = false;
				m_bWaitingForRelease = false;
				ivgui()->RemoveTickSignal( GetVPanel() );
				EnterEditingInPlace();
			}
		}
	}

	virtual void OnMouseReleased( MouseCode code )
	{
		if ( m_bEditingInPlace )
		{
			BaseClass::OnMouseReleased( code );
			return;
		}
		else
		{
			if ( m_bWaitingForRelease && !IsBeingDragged() )
			{
				m_bArmForEditing = true;
				m_bWaitingForRelease = false;
				m_lArmingTime = system()->GetTimeMillis();
				ivgui()->AddTickSignal( GetVPanel() );
			}
			else
			{
				m_bWaitingForRelease = false;
			}
		}

        // let parent deal with it
		CallParentFunction(new KeyValues("MouseReleased", "code", code));
	}

	virtual void OnCursorMoved( int x, int y )
	{
		 // let parent deal with it
		CallParentFunction(new KeyValues("OnCursorMoved", "x", x, "y", y));
	}

	virtual void OnMousePressed(MouseCode code)
    {
		if ( m_bEditingInPlace )
		{
			BaseClass::OnMousePressed( code );
			return;
		}
		else
		{
			bool shift = (input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT));
			bool ctrl = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL));

			// make sure there is only one item selected
			// before "WaitingForRelease" which leads to label editing.
			CUtlVector< int > list;
			m_pTree->GetSelectedItems( list );
			bool bIsOnlyOneItemSelected = ( list.Count() == 1 );

			if ( !shift &&
				!ctrl &&
				!m_bArmForEditing &&
				IsLabelEditingAllowed() &&
				bIsOnlyOneItemSelected &&
				IsTextFullySelected() &&
				!IsBeingDragged() )
			{
				m_bWaitingForRelease = true;
			}
		}

        // let parent deal with it
		CallParentFunction(new KeyValues("MousePressed", "code", code));
	}

	void	SetLabelEditingAllowed( bool state )
	{
		m_bLabelEditingAllowed = state;
	}

	bool	IsLabelEditingAllowed()
	{
		return m_bLabelEditingAllowed;
	}

    virtual void OnMouseDoublePressed(MouseCode code)
 	{
		// Once we are editing, double pressing shouldn't chain up
		if ( m_bEditingInPlace )
		{
			BaseClass::OnMouseDoublePressed( code );
			return;
		}

		if ( m_bArmForEditing )
		{
			m_bArmForEditing = false;
			m_bWaitingForRelease = false;
			ivgui()->RemoveTickSignal( GetVPanel() );
		}

		CallParentFunction(new KeyValues("MouseDoublePressed", "code", code));
    }

	void EnterEditingInPlace()
	{
		if ( m_bEditingInPlace )
			return;

		m_bEditingInPlace = true;
		char buf[ 1024 ];
		GetText( buf, sizeof( buf ) );
		m_OriginalText = buf;
		SetCursor(dc_ibeam);
		SetEditable( true );
		SelectNone();
		GotoTextEnd();
		RequestFocus();
		SelectAllText(false);
		m_pTree->SetLabelBeingEdited( true );
	}

	void FinishEditingInPlace( bool revert = false )
	{
		if ( !m_bEditingInPlace )
			return;

		m_pTree->SetLabelBeingEdited( false );
		SetEditable( false );
		SetCursor(dc_arrow);
		m_bEditingInPlace = false;
		char buf[ 1024 ];
		GetText( buf, sizeof( buf ) );

		// Not actually changed...
		if ( !Q_strcmp( buf, m_OriginalText.Get() ) )
			return;

		if ( revert )
		{
			SetText( m_OriginalText.Get() );
			GetParent()->InvalidateLayout();
		}
		else
		{
			KeyValues *kv = new KeyValues( "LabelChanged", "original", m_OriginalText.Get(), "changed", buf );
			PostActionSignal( kv );
		}
	}

	virtual void OnKillFocus()
	{
		BaseClass::OnKillFocus();

		FinishEditingInPlace();
	}

	virtual void OnMouseWheeled(int delta)
    {
		if ( m_bEditingInPlace )
		{
			BaseClass::OnMouseWheeled( delta );
			return;
		}

		CallParentFunction(new KeyValues("MouseWheeled", "delta", delta));
    }
    // editable - cursor normal, and ability to edit text

	bool	IsBeingEdited() const
	{
		return m_bEditingInPlace;
	}

private:

	bool		m_bEditingInPlace;
	CUtlString	m_OriginalText;
	bool		m_bLabelEditingAllowed;

	bool		m_bArmForEditing;
	bool		m_bWaitingForRelease;
	long		m_lArmingTime;
	TreeView	*m_pTree;
};

//-----------------------------------------------------------------------------
// Purpose: icon for the tree node (folder icon, file icon, etc.)
//-----------------------------------------------------------------------------
class TreeNodeImage : public ImagePanel
{
public:
    TreeNodeImage(Panel *parent, const char *name) : ImagePanel(parent, name)
	{
		SetBlockDragChaining( true );
	}

 	//!! this could possibly be changed to just disallow mouse input on the image panel
    virtual void OnMousePressed(MouseCode code)
    {
        // let parent deal with it
		CallParentFunction(new KeyValues("MousePressed", "code", code));
    }

    virtual void OnMouseDoublePressed(MouseCode code)
    {
        // let parent deal with it
		CallParentFunction(new KeyValues("MouseDoublePressed", "code", code));
    }

    virtual void OnMouseWheeled(int delta)
    {
        // let parent deal with it
		CallParentFunction(new KeyValues("MouseWheeled", "delta", delta));
    }

	virtual void OnCursorMoved( int x, int y )
	{
		 // let parent deal with it
		CallParentFunction(new KeyValues("OnCursorMoved", "x", x, "y", y));
	}
};

//-----------------------------------------------------------------------------
// Purpose: Scrollable area of the tree control, holds the tree itself only
//-----------------------------------------------------------------------------
class TreeViewSubPanel : public Panel
{
public:
    TreeViewSubPanel(Panel *parent) : Panel(parent) {}

    virtual void ApplySchemeSettings(IScheme *pScheme)
    {
    	Panel::ApplySchemeSettings(pScheme);

    	SetBorder(NULL);
   }

	virtual void OnMouseWheeled(int delta)
    {
        // let parent deal with it
		CallParentFunction(new KeyValues("MouseWheeled", "delta", delta));
    }
	virtual void OnMousePressed(MouseCode code)
    {
        // let parent deal with it
		CallParentFunction(new KeyValues("MousePressed", "code", code));
    }
    virtual void OnMouseDoublePressed(MouseCode code)
    {
        // let parent deal with it
		CallParentFunction(new KeyValues("MouseDoublePressed", "code", code));
    }

	virtual void OnCursorMoved( int x, int y )
	{
		 // let parent deal with it
		CallParentFunction(new KeyValues("OnCursorMoved", "x", x, "y", y));
	}
};

//-----------------------------------------------------------------------------
// Purpose: A single entry in the tree
//-----------------------------------------------------------------------------
class TreeNode : public Panel
{
	DECLARE_CLASS_SIMPLE( TreeNode, Panel );

public:
    TreeNode(Panel *parent, TreeView *pTreeView);
	~TreeNode();
    void SetText(const char *pszText);
    void SetFont(HFont font);
    void SetKeyValues(KeyValues *data);
    bool IsSelected();
	// currently unused, could be re-used if necessary
//	bool IsInFocus();
	virtual void PaintBackground();
    virtual void PerformLayout();
	TreeNode *GetParentNode();
    int GetChildrenCount();
	void ClearChildren();
	int ComputeInsertionPosition( TreeNode *pChild );
	int FindChild( TreeNode *pChild );
    void AddChild(TreeNode *pChild);
    void SetNodeExpanded(bool bExpanded);
    bool IsExpanded();
    int CountVisibleNodes();
	void CalculateVisibleMaxWidth();
	void OnChildWidthChange();
	int GetMaxChildrenWidth();
    int GetVisibleMaxWidth();
    int GetDepth();
    bool HasParent(TreeNode *pTreeNode);
    bool IsBeingDisplayed();
	virtual void SetVisible(bool state);
    virtual void Paint();
    virtual void ApplySchemeSettings(IScheme *pScheme);
	virtual void SetBgColor( Color color );
	virtual void SetFgColor( Color color );
    virtual void OnSetFocus();
    void SelectPrevChild(TreeNode *pCurrentChild);
    void SelectNextChild(TreeNode *pCurrentChild);

	int GetPrevChildItemIndex( TreeNode *pCurrentChild );
	int GetNextChildItemIndex( TreeNode *pCurrentChild );

	virtual void ClosePreviousParents( TreeNode *pPreviousParent );
	virtual void StepInto( bool bClosePrevious=true );
	virtual void StepOut( bool bClosePrevious=true );
	virtual void StepOver( bool bClosePrevious=true );
    virtual void OnKeyCodeTyped(KeyCode code);
 	virtual void OnMouseWheeled(int delta);
    virtual void OnMousePressed( MouseCode code);
	virtual void OnMouseReleased( MouseCode code);
	virtual void OnCursorMoved( int x, int y );
	virtual bool IsDragEnabled() const;
    void PositionAndSetVisibleNodes(int &nStart, int &nCount, int x, int &y);

    // counts items above this item including itself
    int CountVisibleIndex();

	virtual void OnCreateDragData( KeyValues *msg );
	// For handling multiple selections...
	virtual void OnGetAdditionalDragPanels( CUtlVector< Panel * >& dragabbles );
	virtual void OnMouseDoublePressed( MouseCode code );
	TreeNode *FindItemUnderMouse( int &nStart, int& nCount, int x, int &y, int mx, int my );
	MESSAGE_FUNC_PARAMS( OnLabelChanged, "LabelChanged", data );
	void EditLabel();
	void	SetLabelEditingAllowed( bool state );
	bool	IsLabelEditingAllowed() const;

	virtual bool IsDroppable( CUtlVector< KeyValues * >& msglist );
	virtual void OnPanelDropped( CUtlVector< KeyValues * >& msglist );
	virtual HCursor GetDropCursor( CUtlVector< KeyValues * >& msglist );
	virtual bool GetDropContextMenu( Menu *menu, CUtlVector< KeyValues * >& msglist );

	void				FindNodesInRange( CUtlVector< TreeNode * >& list, int startIndex, int endIndex );

	void				RemoveChildren();

	void SetSelectionTextColor( const Color& clr );
	void SetSelectionBgColor( const Color& clr );
	void SetSelectionUnfocusedBgColor( const Color& clr );
public:
	int                 m_ItemIndex;
	int					m_ParentIndex;
	KeyValues           *m_pData;
    CUtlVector<TreeNode *> m_Children;
    bool                m_bExpand;

private:

	void				FindNodesInRange_R( CUtlVector< TreeNode * >& list, bool& finished, bool& foundStart, int startIndex, int endIndex );

	int					m_iNodeWidth;
	int					m_iMaxVisibleWidth;

    TreeNodeText        *m_pText;
    TextImage           *m_pExpandImage;
    TreeNodeImage       *m_pImagePanel;

	bool				m_bExpandableWithoutChildren;

    TreeView            *m_pTreeView;
	int					m_nClickedItem;
	bool				m_bClickedSelected;
};

TreeNode::TreeNode(Panel *parent, TreeView *pTreeView) :
	BaseClass(parent, "TreeNode" ),
	m_nClickedItem( 0 ),
	m_bClickedSelected( false )
{
    m_pData = NULL;
    m_pTreeView = pTreeView;
    m_ItemIndex = -1;
	m_iNodeWidth = 0;
	m_iMaxVisibleWidth = 0;

    m_pExpandImage = new TextImage("+");
    m_pExpandImage->SetPos(3, 1);

    m_pImagePanel = new TreeNodeImage(this, "TreeImage");
    m_pImagePanel->SetPos(TREE_INDENT_AMOUNT, 3);

    m_pText = new TreeNodeText(this, "TreeNodeText",pTreeView);
    m_pText->SetMultiline(false);
    m_pText->SetEditable(false);
    m_pText->SetPos(TREE_INDENT_AMOUNT*2, 0);
	m_pText->AddActionSignalTarget( this );

    m_bExpand = false;
	m_bExpandableWithoutChildren = false;
}

TreeNode::~TreeNode()
{
	delete m_pExpandImage;
	if ( m_pData )
	{
		m_pData->deleteThis();
	}
}

void TreeNode::SetText(const char *pszText)
{
    m_pText->SetText(pszText);
	InvalidateLayout();
}

void TreeNode::SetLabelEditingAllowed( bool state )
{
	Assert( m_pTreeView->IsLabelEditingAllowed() );
	m_pText->SetLabelEditingAllowed( state );
}

bool TreeNode::IsLabelEditingAllowed() const
{
	return m_pText->IsLabelEditingAllowed();
}

bool TreeNode::GetDropContextMenu( Menu *menu, CUtlVector< KeyValues * >& msglist )
{
	return m_pTreeView->GetItemDropContextMenu( m_ItemIndex, menu, msglist );
}

bool TreeNode::IsDroppable( CUtlVector< KeyValues * >& msglist )
{
	return m_pTreeView->IsItemDroppable( m_ItemIndex, msglist );
}

void TreeNode::OnPanelDropped( CUtlVector< KeyValues * >& msglist )
{
	m_pTreeView->OnItemDropped( m_ItemIndex, msglist );
}

HCursor TreeNode::GetDropCursor( CUtlVector< KeyValues * >& msglist )
{
	return m_pTreeView->GetItemDropCursor( m_ItemIndex, msglist );
}

void TreeNode::OnCreateDragData( KeyValues *msg )
{
	// make sure the dragged item appears selected,
	// on the off chance it appears deselected by a cntl mousedown
	m_pTreeView->AddSelectedItem( m_ItemIndex, false );

	m_pTreeView->GenerateDragDataForItem( m_ItemIndex, msg );
}

// For handling multiple selections...
void TreeNode::OnGetAdditionalDragPanels( CUtlVector< Panel * >& dragabbles )
{
	CUtlVector< int > list;
	m_pTreeView->GetSelectedItems( list );
	int c = list.Count();
	// walk this in reverse order so that panels are in order of selection
	// even though GetSelectedItems returns items in reverse selection order
	for ( int i = c - 1; i >= 0; --i )
	{
		int itemIndex = list[ i ];
		// Skip self
		if ( itemIndex == m_ItemIndex )
			continue;

		dragabbles.AddToTail( ( Panel * )m_pTreeView->GetItem( itemIndex ) );
	}
}

void TreeNode::OnLabelChanged( KeyValues *data )
{
	char const *oldString = data->GetString( "original" );
	char const *newString = data->GetString( "changed" );
	if ( m_pTreeView->IsLabelEditingAllowed() )
	{
		m_pTreeView->OnLabelChanged( m_ItemIndex, oldString, newString );
	}
}

void TreeNode::EditLabel()
{
	if ( m_pText->IsLabelEditingAllowed() &&
		!m_pText->IsBeingEdited() )
	{
		m_pText->EnterEditingInPlace();
	}
}

void TreeNode::SetFont(HFont font)
{
    Assert( font );
    if ( !font )
        return;

    m_pText->SetFont(font);
	m_pExpandImage->SetFont(font);
	InvalidateLayout();
    int i;
    for (i=0;i<GetChildrenCount();i++)
    {
        m_Children[i]->SetFont(font);
    }
}

void TreeNode::SetKeyValues(KeyValues *data)
{
	if ( m_pData != data )
	{
		if (m_pData)
		{
			m_pData->deleteThis();
		}

		m_pData = data->MakeCopy();
	}

    // set text
    m_pText->SetText(data->GetString("Text", ""));
 	m_bExpandableWithoutChildren = data->GetInt("Expand");
    InvalidateLayout();
}

bool TreeNode::IsSelected()
{
	return m_pTreeView->IsItemSelected( m_ItemIndex );
}

void TreeNode::PaintBackground()
{
	if ( !m_pText->IsBeingEdited() )
	{
		// setup panel drawing
		if ( IsSelected() )
		{
			m_pText->SelectAllText(false);
		}
		else
		{
			m_pText->SelectNoText();
		}
	}

	BaseClass::PaintBackground();
}

// currently unused, could be re-used if necessary
/*
bool TreeNode::IsInFocus()
{
    // check if our parent or one of it's children has focus
    VPANEL focus = input()->GetFocus();
    return (HasFocus() || (focus && ipanel()->HasParent(focus, GetVParent())));
}
*/

void TreeNode::PerformLayout()
{
    BaseClass::PerformLayout();

    int width = 0;
	if (m_pData->GetInt("SelectedImage", 0) == 0 &&
		m_pData->GetInt("Image", 0) == 0)
	{
		width = TREE_INDENT_AMOUNT;
	}
	else
	{
		width = TREE_INDENT_AMOUNT * 2;
	}

	m_pText->SetPos(width, 0);

    int contentWide, contentTall;
	m_pText->SetToFullWidth();
    m_pText->GetSize(contentWide, contentTall);
	contentWide += 10;
	m_pText->SetSize( contentWide, m_pTreeView->GetRowHeight() );
    width += contentWide;
    SetSize(width, m_pTreeView->GetRowHeight());

	m_iNodeWidth = width;
	CalculateVisibleMaxWidth();
}

TreeNode *TreeNode::GetParentNode()
{
	if (m_pTreeView->m_NodeList.IsValidIndex(m_ParentIndex))
	{
		return m_pTreeView->m_NodeList[m_ParentIndex];
	}
	return NULL;
}

int TreeNode::GetChildrenCount()
{
    return m_Children.Count();
}

int TreeNode::ComputeInsertionPosition( TreeNode *pChild )
{
	if ( !m_pTreeView->m_pSortFunc )
	{
		return GetChildrenCount() - 1;
	}

	int start = 0, end = GetChildrenCount() - 1;
	while (start <= end)
	{
		int mid = (start + end) >> 1;
		if ( m_pTreeView->m_pSortFunc( m_Children[mid]->m_pData, pChild->m_pData ) )
		{
			start = mid + 1;
		}
		else if ( m_pTreeView->m_pSortFunc( pChild->m_pData, m_Children[mid]->m_pData ) )
		{
			end = mid - 1;
		}
		else
		{
			return mid;
		}
	}
	return end;
}

int TreeNode::FindChild( TreeNode *pChild )
{
	if ( !m_pTreeView->m_pSortFunc )
	{
		for ( int i = 0; i < GetChildrenCount(); --i )
		{
			if ( m_Children[i] == pChild )
				return i;
		}
		return -1;
	}

	// Find the first entry <= to the child
	int start = 0, end = GetChildrenCount() - 1;
	while (start <= end)
	{
		int mid = (start + end) >> 1;

		if ( m_Children[mid] == pChild )
			return mid;

		if ( m_pTreeView->m_pSortFunc( m_Children[mid]->m_pData, pChild->m_pData ) )
		{
			start = mid + 1;
		}
		else
		{
			end = mid - 1;
		}
	}

	int nMax = GetChildrenCount();
	while( end < nMax )
	{
		// Stop when we reach a child that has a different value
		if ( m_pTreeView->m_pSortFunc( pChild->m_pData, m_Children[end]->m_pData ) )
			return -1;

		if ( m_Children[end] == pChild )
			return end;

		++end;
	}

	return -1;
}

void TreeNode::AddChild(TreeNode *pChild)
{
	int i = ComputeInsertionPosition( pChild );
	m_Children.InsertAfter( i, pChild );
}

void TreeNode::SetNodeExpanded(bool bExpanded)
{
    m_bExpand = bExpanded;

    if (m_bExpand)
    {
		// see if we have any child nodes
		if (GetChildrenCount() < 1)
		{
			// we need to get our children from the control
			m_pTreeView->GenerateChildrenOfNode(m_ItemIndex);

			// if we still don't have any children, then hide the expand button
			if (GetChildrenCount() < 1)
			{
				m_bExpand = false;
				m_bExpandableWithoutChildren = false;
				m_pTreeView->InvalidateLayout();
				return;
			}
		}

        m_pExpandImage->SetText("-");
    }
    else
    {
        m_pExpandImage->SetText("+");

		if ( m_bExpandableWithoutChildren && GetChildrenCount() > 0 )
		{
			m_pTreeView->RemoveChildrenOfNode( m_ItemIndex );
		}

        // check if we've closed down on one of our children, if so, we get the focus
        int selectedItem = m_pTreeView->GetFirstSelectedItem();
        if (selectedItem != -1 && m_pTreeView->m_NodeList[selectedItem]->HasParent(this))
        {
            m_pTreeView->AddSelectedItem( m_ItemIndex, true );
        }
    }
	CalculateVisibleMaxWidth();
    m_pTreeView->InvalidateLayout();
}

bool TreeNode::IsExpanded()
{
    return m_bExpand;
}

int TreeNode::CountVisibleNodes()
{
    int count = 1;  // count myself
    if (m_bExpand)
    {
        int i;
        for (i=0;i<m_Children.Count();i++)
        {
            count += m_Children[i]->CountVisibleNodes();
        }
    }
    return count;
}

void TreeNode::CalculateVisibleMaxWidth()
{
	int width;
	if (m_bExpand)
	{
		int childMaxWidth = GetMaxChildrenWidth();
		childMaxWidth += TREE_INDENT_AMOUNT;

		width = max(childMaxWidth, m_iNodeWidth);
	}
	else
	{
		width = m_iNodeWidth;
	}
	if (width != m_iMaxVisibleWidth)
	{
		m_iMaxVisibleWidth = width;
		if (GetParentNode())
		{
			GetParentNode()->OnChildWidthChange();
		}
		else
		{
			m_pTreeView->InvalidateLayout();
		}
	}
}

void TreeNode::OnChildWidthChange()
{
	CalculateVisibleMaxWidth();
}

int TreeNode::GetMaxChildrenWidth()
{
	int maxWidth = 0;
	int i;
    for (i=0;i<GetChildrenCount();i++)
    {
		int childWidth = m_Children[i]->GetVisibleMaxWidth();
		if (childWidth > maxWidth)
		{
			maxWidth = childWidth;
		}
	}
	return maxWidth;
}

int TreeNode::GetVisibleMaxWidth()
{
	return m_iMaxVisibleWidth;
}

int TreeNode::GetDepth()
{
    int depth = 0;
        TreeNode *pParent = GetParentNode();
    while (pParent)
    {
        depth++;
        pParent = pParent->GetParentNode();
    }
    return depth;
}

bool TreeNode::HasParent(TreeNode *pTreeNode)
{
    TreeNode *pParent = GetParentNode();
    while (pParent)
    {
        if (pParent == pTreeNode)
            return true;
		pParent = pParent->GetParentNode();
    }
    return false;
}

bool TreeNode::IsBeingDisplayed()
{
    TreeNode *pParent = GetParentNode();
    while (pParent)
    {
        // our parents aren't showing us
        if (!pParent->m_bExpand)
            return false;

        pParent = pParent->GetParentNode();
    }
    return true;
}

void TreeNode::SetVisible(bool state)
{
    BaseClass::SetVisible(state);

    bool bChildrenVisible = state && m_bExpand;
    int i;
    for (i=0;i<GetChildrenCount();i++)
    {
        m_Children[i]->SetVisible(bChildrenVisible);
    }
}

void TreeNode::Paint()
{
    if (GetChildrenCount() > 0 || m_bExpandableWithoutChildren)
    {
        m_pExpandImage->Paint();
    }

    // set image
    int imageIndex = 0;
    if (IsSelected())
    {
        imageIndex = m_pData->GetInt("SelectedImage", 0);
    }
    else
    {
        imageIndex = m_pData->GetInt("Image", 0);
    }

	if (imageIndex)
	{
		IImage *pImage = m_pTreeView->GetImage(imageIndex);
		if (pImage)
		{
			m_pImagePanel->SetImage(pImage);
		}
		m_pImagePanel->Paint();
	}

    m_pText->Paint();
}

void TreeNode::ApplySchemeSettings(IScheme *pScheme)
{
    BaseClass::ApplySchemeSettings(pScheme);

    SetBorder( NULL );
	SetFgColor( m_pTreeView->GetFgColor() );
	SetBgColor( m_pTreeView->GetBgColor() );
	SetFont( m_pTreeView->GetFont() );
}

void TreeNode::SetSelectionTextColor( const Color& clr )
{
	if ( m_pText )
	{
		m_pText->SetSelectionTextColor( clr );
	}
}

void TreeNode::SetSelectionBgColor( const Color& clr )
{
	if ( m_pText )
	{
		m_pText->SetSelectionBgColor( clr );
	}
}

void TreeNode::SetSelectionUnfocusedBgColor( const Color& clr )
{
	if ( m_pText )
	{
		m_pText->SetSelectionUnfocusedBgColor( clr );
	}
}

void TreeNode::SetBgColor( Color color )
{
	BaseClass::SetBgColor( color );
	if ( m_pText )
	{
		m_pText->SetBgColor( color );
	}

}

void TreeNode::SetFgColor( Color color )
{
	BaseClass::SetFgColor( color );
	if ( m_pText )
	{
		m_pText->SetFgColor( color );
	}
}

void TreeNode::OnSetFocus()
{
    m_pText->RequestFocus();
}

int TreeNode::GetPrevChildItemIndex( TreeNode *pCurrentChild )
{
	int i;
    for (i=0;i<GetChildrenCount();i++)
    {
        if ( m_Children[i] == pCurrentChild )
		{
			if ( i <= 0 )
				return -1;

			TreeNode *pChild = m_Children[i-1];
			return pChild->m_ItemIndex;
		}
    }
	return -1;
}

int TreeNode::GetNextChildItemIndex( TreeNode *pCurrentChild )
{
	int i;
    for (i=0;i<GetChildrenCount();i++)
    {
        if ( m_Children[i] == pCurrentChild )
		{
			if ( i >= GetChildrenCount() - 1 )
				return -1;

			TreeNode *pChild = m_Children[i+1];
			return pChild->m_ItemIndex;
		}
    }
	return -1;
}

void TreeNode::SelectPrevChild(TreeNode *pCurrentChild)
{
    int i;
    for (i=0;i<GetChildrenCount();i++)
    {
        if (m_Children[i] == pCurrentChild)
            break;
    }

    // this shouldn't happen
    if (i == GetChildrenCount())
    {
        Assert(0);
        return;
    }

    // were we on the first child?
    if (i == 0)
    {
        // if so, then we take over!
        m_pTreeView->AddSelectedItem( m_ItemIndex, true );
    }
    else
    {
        // see if we need to find a grandchild of the previous sibling
        TreeNode *pChild = m_Children[i-1];

        // if this child is expanded with children, then we have to find the last child
        while (pChild->m_bExpand && pChild->GetChildrenCount()>0)
        {
            // find the last child
            pChild = pChild->m_Children[pChild->GetChildrenCount()-1];
        }
        m_pTreeView->AddSelectedItem( pChild->m_ItemIndex, true );
    }
}

void TreeNode::SelectNextChild(TreeNode *pCurrentChild)
{
    int i;
    for (i=0;i<GetChildrenCount();i++)
    {
        if (m_Children[i] == pCurrentChild)
            break;
    }

    // this shouldn't happen
    if (i == GetChildrenCount())
    {
        Assert(0);
        return;
    }

    // were we on the last child?
    if (i == GetChildrenCount() - 1)
    {
        // tell our parent to get the next child
		if (GetParentNode())
        {
			GetParentNode()->SelectNextChild(this);
		}
    }
    else
    {
        m_pTreeView->AddSelectedItem( m_Children[i+1]->m_ItemIndex, true );
    }
}

void TreeNode::ClosePreviousParents( TreeNode *pPreviousParent )
{
	// close up all the open nodes we've just stepped out of.
	CUtlVector< int > selected;
	m_pTreeView->GetSelectedItems( selected );
	if ( selected.Count() == 0 )
	{
		Assert( 0 );
		return;
	}

	// Most recently clicked item
	TreeNode *selectedItem = m_pTreeView->GetItem( selected[ 0 ] );
	TreeNode *pNewParent = selectedItem->GetParentNode();
	if ( pPreviousParent && pNewParent )
	{
		while ( pPreviousParent->m_ItemIndex > pNewParent->m_ItemIndex )
		{
			pPreviousParent->SetNodeExpanded(false);
			pPreviousParent = pPreviousParent->GetParentNode();
		}
	}
}

void TreeNode::StepInto( bool bClosePrevious )
{
	if ( !m_bExpand )
    {
        SetNodeExpanded(true);
    }

    if ( ( GetChildrenCount() > 0 ) && m_bExpand )
    {
        m_pTreeView->AddSelectedItem( m_Children[0]->m_ItemIndex, true );
    }
    else if ( GetParentNode() )
    {
		TreeNode *pParent = GetParentNode();
        pParent->SelectNextChild(this);

		if ( bClosePrevious )
		{
			ClosePreviousParents( pParent );
		}
    }
}

void TreeNode::StepOut( bool bClosePrevious )
{
	TreeNode *pParent = GetParentNode();
	if ( pParent )
	{
		m_pTreeView->AddSelectedItem( pParent->m_ItemIndex, true );
		if ( pParent->GetParentNode() )
		{
			pParent->GetParentNode()->SelectNextChild(pParent);
		}
		if ( bClosePrevious )
		{
			ClosePreviousParents( pParent );
		}
		else
		{
			pParent->SetNodeExpanded(true);
		}
	}
}

void TreeNode::StepOver( bool bClosePrevious )
{
	TreeNode *pParent = GetParentNode();
	if ( pParent )
	{
		GetParentNode()->SelectNextChild(this);
		if ( bClosePrevious )
		{
			ClosePreviousParents( pParent );
		}
	}
}

void TreeNode::OnKeyCodeTyped(KeyCode code)
{
    switch (code)
    {
        case KEY_LEFT:
        {
            if (m_bExpand && GetChildrenCount() > 0)
            {
                SetNodeExpanded(false);
            }
            else
            {
                if (GetParentNode())
                {
                    m_pTreeView->AddSelectedItem( GetParentNode()->m_ItemIndex, true );
                }
            }
            break;
        }
        case KEY_RIGHT:
        {
            if (!m_bExpand)
            {
                SetNodeExpanded(true);
            }
            else if (GetChildrenCount() > 0)
            {
				m_pTreeView->AddSelectedItem( m_Children[0]->m_ItemIndex, true );
            }
            break;
        }
        case KEY_UP:
        {
            if (GetParentNode())
            {
                GetParentNode()->SelectPrevChild(this);
            }
            break;
        }
        case KEY_DOWN:
        {
            if (GetChildrenCount() > 0 && m_bExpand)
            {
                m_pTreeView->AddSelectedItem( m_Children[0]->m_ItemIndex, true );
            }
            else if (GetParentNode())
            {
                GetParentNode()->SelectNextChild(this);
            }
            break;
        }
		case KEY_SPACE:
        {
			bool shift = (input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT));
			bool ctrl = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL));
			bool alt = (input()->IsKeyDown(KEY_LALT) || input()->IsKeyDown(KEY_RALT));
			if ( shift )
			{
				StepOut( !ctrl );
			}
			else if ( alt )
			{
				StepOver( !ctrl );
			}
			else
			{
				StepInto( !ctrl );
			}
			break;
        }
		case KEY_I:
		{
			StepInto();
			break;
		}
		case KEY_U:
		{
			StepOut();
			break;
		}
		case KEY_O:
		{
			StepOver();
			break;
		}
		case KEY_ESCAPE:
			{
				if ( m_pTreeView->GetSelectedItemCount() > 0 )
				{
					m_pTreeView->ClearSelection();
				}
				else
				{
					BaseClass::OnKeyCodeTyped(code);
				}
			}
			break;
		case KEY_A:
			{
				bool ctrldown = input()->IsKeyDown( KEY_LCONTROL ) ||  input()->IsKeyDown( KEY_RCONTROL );
				if ( ctrldown )
				{
					m_pTreeView->SelectAll();
				}
				else
				{
					BaseClass::OnKeyCodeTyped(code);
				}
			}
			break;
        default:
            BaseClass::OnKeyCodeTyped(code);
            return;
    }
}

void TreeNode::OnMouseWheeled(int delta)
{
	CallParentFunction(new KeyValues("MouseWheeled", "delta", delta));
}

void TreeNode::OnMouseDoublePressed( MouseCode code )
{
	int x, y;
	input()->GetCursorPos(x, y);

	if (code == MOUSE_LEFT)
	{
		ScreenToLocal(x, y);
		if (x > TREE_INDENT_AMOUNT)
		{
			SetNodeExpanded(!m_bExpand);
		}
	}
}

bool TreeNode::IsDragEnabled() const
{
	int x, y;
	input()->GetCursorPos(x, y);
	((TreeNode *)this)->ScreenToLocal(x, y);
	if ( x < TREE_INDENT_AMOUNT )
		return false;

	return BaseClass::IsDragEnabled();
}

void TreeNode::OnMouseReleased(MouseCode code)
{
	BaseClass::OnMouseReleased( code );

	if ( input()->GetMouseCapture() == GetVPanel() )
	{
		input()->SetMouseCapture( NULL );
		return;
	}
	int x, y;
	input()->GetCursorPos(x, y);
	ScreenToLocal(x, y);

	if ( x < TREE_INDENT_AMOUNT )
		return;

	bool ctrldown = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL));
	bool shiftdown = (input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT));

	if ( !ctrldown && !shiftdown && ( code == MOUSE_LEFT ) )
	{
		m_pTreeView->AddSelectedItem( m_ItemIndex, true );
	}
}

void TreeNode::OnCursorMoved( int x, int y )
{
	if ( input()->GetMouseCapture() != GetVPanel() )
		return;

	LocalToScreen( x, y );
	m_pTreeView->ScreenToLocal( x, y );
	int newItem = m_pTreeView->FindItemUnderMouse( x, y );
	if ( newItem == -1 )
	{
		// Fixme:  Figure out best item
		return;
	}

	int startItem = m_nClickedItem;
	int endItem = newItem;
	if ( startItem > endItem )
	{
		int temp = startItem;
		startItem = endItem;
		endItem = temp;
	}

	CUtlVector< TreeNode * > list;
	m_pTreeView->m_pRootNode->FindNodesInRange( list, startItem, endItem );

	int c = list.Count();
	for ( int i = 0; i < c; ++i )
	{
		TreeNode *item = list[ i ];
		if ( m_bClickedSelected )
		{
			m_pTreeView->AddSelectedItem( item->m_ItemIndex, false );
		}
		else
		{
			m_pTreeView->RemoveSelectedItem( item->m_ItemIndex );
		}
	}
}

void TreeNode::OnMousePressed( MouseCode code)
{
	BaseClass::OnMousePressed( code );

	bool ctrl = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL));
	bool shift = (input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT));
	int x, y;
	input()->GetCursorPos(x, y);

	bool bExpandTree = m_pTreeView->m_bLeftClickExpandsTree;

	if ( code == MOUSE_LEFT )
	{
		ScreenToLocal(x, y);
		if ( x < TREE_INDENT_AMOUNT )
		{
			if ( bExpandTree )
			{
				SetNodeExpanded(!m_bExpand);
			}
			// m_pTreeView->SetSelectedItem(m_ItemIndex);    // explorer doesn't actually select item when it expands an item
			// purposely commented out in case we want to change the behavior
		}
		else
		{
			m_nClickedItem = m_ItemIndex;
			if ( m_pTreeView->IsMultipleItemDragEnabled() )
			{
				input()->SetMouseCapture( GetVPanel() );
			}

			if ( shift )
			{
				m_pTreeView->RangeSelectItems( m_ItemIndex );
			}
			else
			{
				if ( !IsSelected() || ctrl )
				{
					if ( IsSelected() && ctrl )
					{
						m_pTreeView->RemoveSelectedItem( m_ItemIndex );
					}
					else
					{
						m_pTreeView->AddSelectedItem( m_ItemIndex, !ctrl );
					}
				}
				else if ( IsSelected() && m_pTreeView->IsMultipleItemDragEnabled() )
				{
					m_pTreeView->AddSelectedItem( m_ItemIndex, !shift );
				}
			}

			m_bClickedSelected = m_pTreeView->IsItemSelected( m_ItemIndex );
		}
	}
	else if (code == MOUSE_RIGHT)
	{
		// context menu selection
		// If the item was selected, leave selected items alone, otherwise make it the only selected item
		if ( !m_pTreeView->IsItemSelected( m_ItemIndex ) )
		{
			m_pTreeView->AddSelectedItem( m_ItemIndex, true );
		}

		// ask parent to context menu
		m_pTreeView->GenerateContextMenu(m_ItemIndex, x, y);
	}
}

void TreeNode::RemoveChildren()
{
	int c = m_Children.Count();
	for ( int i = c - 1 ; i >= 0 ; --i )
	{
		m_pTreeView->RemoveItem( m_Children[ i ]->m_ItemIndex, false, true );
	}
	m_Children.RemoveAll();
}

void TreeNode::FindNodesInRange( CUtlVector< TreeNode * >& list, int startIndex, int endIndex )
{
	list.RemoveAll();
	bool finished = false;
	bool foundstart = false;
	FindNodesInRange_R( list, finished, foundstart, startIndex, endIndex );
}

void TreeNode::FindNodesInRange_R( CUtlVector< TreeNode * >& list, bool& finished, bool& foundStart, int startIndex, int endIndex )
{
	if ( finished )
		return;
	if ( foundStart == true )
	{
		list.AddToTail( this );

		if ( m_ItemIndex == startIndex || m_ItemIndex == endIndex )
		{
			finished = true;
			return;
		}
	}
	else if ( m_ItemIndex == startIndex || m_ItemIndex == endIndex )
	{
		foundStart = true;
		list.AddToTail( this );
		if ( startIndex == endIndex )
		{
			finished = true;
			return;
		}
	}

	if ( !m_bExpand )
		return;

	int i;
	int c = GetChildrenCount();
    for (i=0;i<c;i++)
    {
		m_Children[i]->FindNodesInRange_R( list, finished, foundStart, startIndex, endIndex );
    }
}

void TreeNode::PositionAndSetVisibleNodes(int &nStart, int &nCount, int x, int &y)
{
    // position ourselves
    if (nStart == 0)
    {
        BaseClass::SetVisible(true);
        SetPos(x, y);
        y += m_pTreeView->GetRowHeight();      // m_nRowHeight
        nCount--;
    }
    else // still looking for first element
    {
        nStart--;
        BaseClass::SetVisible(false);
    }

    x += TREE_INDENT_AMOUNT;
    int i;
    for (i=0;i<GetChildrenCount();i++)
    {
        if (nCount > 0 && m_bExpand)
        {
            m_Children[i]->PositionAndSetVisibleNodes(nStart, nCount, x, y);
        }
        else
        {
            m_Children[i]->SetVisible(false);   // this will make all grand children hidden as well
        }
    }
}

TreeNode *TreeNode::FindItemUnderMouse( int &nStart, int& nCount, int x, int &y, int mx, int my )
{
    // position ourselves
    if (nStart == 0)
    {
		int posx, posy;
        GetPos(posx, posy);
		if ( my >= posy && my < posy + m_pTreeView->GetRowHeight() )
		{
			return this;
		}
		y += m_pTreeView->GetRowHeight();
        nCount--;
    }
    else // still looking for first element
    {
        nStart--;
    }

    x += TREE_INDENT_AMOUNT;
    int i;
    for (i=0;i<GetChildrenCount();i++)
    {
        if (nCount > 0 && m_bExpand)
        {
            TreeNode *child = m_Children[i]->FindItemUnderMouse(nStart, nCount, x, y, mx, my);
			if ( child != NULL )
			{
				return child;
			}
        }
    }

	return NULL;
}

// counts items above this item including itself
int TreeNode::CountVisibleIndex()
{
    int nCount = 1; // myself
    if (GetParentNode())
    {
        int i;
        for (i=0;i<GetParentNode()->GetChildrenCount();i++)
        {
            if (GetParentNode()->m_Children[i] == this)
                break;

            nCount += GetParentNode()->m_Children[i]->CountVisibleNodes();
        }
        return nCount + GetParentNode()->CountVisibleIndex();
    }
    else
        return nCount;
}

}; // namespace vgui

DECLARE_BUILD_FACTORY( TreeView );

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
TreeView::TreeView(Panel *parent, const char *panelName) : Panel(parent, panelName)
{
	m_bScrollbarExternal[ 0 ] = m_bScrollbarExternal[ 1 ] = false;
    m_nRowHeight = 20;
    m_pRootNode = NULL;
    m_pImageList = NULL;
    m_pSortFunc = NULL;
    m_Font = 0;

    m_pSubPanel = new TreeViewSubPanel(this);
    m_pSubPanel->SetVisible(true);
    m_pSubPanel->SetPos(0,0);

	m_pHorzScrollBar = new ScrollBar(this, "HorizScrollBar", false);
	m_pHorzScrollBar->AddActionSignalTarget(this);
	m_pHorzScrollBar->SetVisible(false);

	m_pVertScrollBar = new ScrollBar(this, "VertScrollBar", true);
	m_pVertScrollBar->SetVisible(false);
	m_pVertScrollBar->AddActionSignalTarget(this);

	m_bAllowLabelEditing = false;
	m_bDragEnabledItems = false;
	m_bDeleteImageListWhenDone = false;
	m_bLabelBeingEdited = false;
	m_bMultipleItemDragging = false;
	m_bLeftClickExpandsTree = true;
	m_bAllowMultipleSelections = false;
	m_nMostRecentlySelectedItem = -1;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
TreeView::~TreeView()
{
	CleanUpImageList();
}

//-----------------------------------------------------------------------------
// Clean up the image list
//-----------------------------------------------------------------------------
void TreeView::CleanUpImageList( )
{
    if ( m_pImageList )
    {
        if ( m_bDeleteImageListWhenDone )
        {
            delete m_pImageList;
        }
		m_pImageList = NULL;
    }
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void TreeView::SetSortFunc(TreeViewSortFunc_t pSortFunc)
{
    m_pSortFunc = pSortFunc;
}

HFont TreeView::GetFont()
{
	return m_Font;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void TreeView::SetFont(HFont font)
{
	Assert( font );
	if ( !font )
		return;

    m_Font = font;
	m_nRowHeight = surface()->GetFontTall(font) + 2;

    if (m_pRootNode)
    {
        m_pRootNode->SetFont(font);
    }
	InvalidateLayout();
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int TreeView::GetRowHeight()
{
    return m_nRowHeight;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int TreeView::GetVisibleMaxWidth()
{
    if (m_pRootNode)
    {
        return m_pRootNode->GetVisibleMaxWidth();
    }
	else
	{
		return 0;
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int TreeView::AddItem(KeyValues *data, int parentItemIndex)
{
    Assert(parentItemIndex == -1 || m_NodeList.IsValidIndex(parentItemIndex));

    TreeNode *pTreeNode = new TreeNode(m_pSubPanel, this);
	pTreeNode->SetDragEnabled( m_bDragEnabledItems );
    pTreeNode->m_ItemIndex = m_NodeList.AddToTail(pTreeNode);
    pTreeNode->SetKeyValues(data);

	if ( m_Font != 0 )
	{
		pTreeNode->SetFont( m_Font );
	}
	pTreeNode->SetBgColor( GetBgColor() );

	if ( data->GetInt( "droppable", 0 ) != 0 )
	{
		float flContextDelay = data->GetFloat( "drophoverdelay" );
		if ( flContextDelay )
		{
			pTreeNode->SetDropEnabled( true, flContextDelay );
		}
		else
		{
			pTreeNode->SetDropEnabled( true );
		}
	}

    // there can be only one root
    if (parentItemIndex == -1)
    {
        Assert(m_pRootNode == NULL);
        m_pRootNode = pTreeNode;
        pTreeNode->m_ParentIndex = -1;
    }
    else
    {
        pTreeNode->m_ParentIndex = parentItemIndex;

        // add to parent list
        pTreeNode->GetParentNode()->AddChild(pTreeNode);
    }

	SETUP_PANEL( pTreeNode );

	return pTreeNode->m_ItemIndex;
}

int TreeView::GetRootItemIndex()
{
	if ( m_pRootNode )
		return m_pRootNode->m_ItemIndex;
	else
		return -1;
}

int TreeView::GetNumChildren( int itemIndex )
{
	if ( itemIndex == -1 )
		return 0;

	return m_NodeList[itemIndex]->m_Children.Count();
}

int TreeView::GetChild( int iParentItemIndex, int iChild )
{
	return m_NodeList[iParentItemIndex]->m_Children[iChild]->m_ItemIndex;
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  : itemIndex -
// Output : TreeNode
//-----------------------------------------------------------------------------
TreeNode *TreeView::GetItem( int itemIndex )
{
	if ( !m_NodeList.IsValidIndex( itemIndex ) )
	{
		Assert( 0 );
		return NULL;
	}

	return m_NodeList[ itemIndex ];
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int TreeView::GetItemCount(void)
{
    return m_NodeList.Count();
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
KeyValues* TreeView::GetItemData(int itemIndex)
{
    if (!m_NodeList.IsValidIndex(itemIndex))
        return NULL;
    else
        return m_NodeList[itemIndex]->m_pData;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void TreeView::RemoveItem(int itemIndex, bool bPromoteChildren, bool bFullDelete )
{
	// HACK: there's a bug with RemoveItem where panels are lingering. This gets around it temporarily.

	// FIXME: Negative item indices is a bogus interface method!
	// because what if you want to recursively remove everything under node 0?
	// Use the bFullDelete parameter instead.
	if ( itemIndex < 0 )
	{
		itemIndex = -itemIndex;
		bFullDelete = true;
	}

	if (!m_NodeList.IsValidIndex(itemIndex))
       return;

    TreeNode *pNode = m_NodeList[itemIndex];
    TreeNode *pParent = pNode->GetParentNode();

    // are we promoting the children
    if (bPromoteChildren && pParent)
    {
        int i;
        for (i=0;i<pNode->GetChildrenCount();i++)
        {
            TreeNode *pChild = pNode->m_Children[i];
            pChild->m_ParentIndex = pParent->m_ItemIndex;
        }
    }
    else
    {
        // delete our children
        if ( bFullDelete )
		{
			while ( pNode->GetChildrenCount() )
				RemoveItem( -pNode->m_Children[0]->m_ItemIndex, false );
		}
		else
		{
			int i;
			for (i=0;i<pNode->GetChildrenCount();i++)
			{
				TreeNode *pDeleteChild = pNode->m_Children[i];
				RemoveItem(pDeleteChild->m_ItemIndex, false);
			}
		}
    }

    // remove from our parent's children list
    if (pParent)
    {
        pParent->m_Children.FindAndRemove(pNode);
    }

    // finally get rid of ourselves from the main list
    m_NodeList.Remove(itemIndex);

	if ( bFullDelete )
		delete pNode;
	else
		pNode->MarkForDeletion();

	// Make sure we don't leave ourselves with an invalid selected item.
	m_SelectedItems.FindAndRemove( pNode );
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void TreeView::RemoveAll()
{
    int i;
    for (i=0;i<m_NodeList.MaxElementIndex();i++)
    {
        if (!m_NodeList.IsValidIndex(i))
            continue;

        m_NodeList[i]->MarkForDeletion();
    }
    m_NodeList.RemoveAll();
	m_pRootNode = NULL;
	ClearSelection();
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool TreeView::ModifyItem(int itemIndex, KeyValues *data)
{
    if (!m_NodeList.IsValidIndex(itemIndex))
        return false;

    TreeNode *pNode = m_NodeList[itemIndex];
	TreeNode *pParent = pNode->GetParentNode();
	bool bReSort = ( m_pSortFunc && pParent );
	int nChildIndex = -1;
	if ( bReSort )
	{
		nChildIndex = pParent->FindChild( pNode );
	}

    pNode->SetKeyValues(data);

	// Changing the data can cause it to re-sort
	if ( bReSort )
	{
		int nChildren = pParent->GetChildrenCount();
		bool bLeftBad = (nChildIndex > 0) && m_pSortFunc( pNode->m_pData, pParent->m_Children[nChildIndex-1]->m_pData );
		bool bRightBad = (nChildIndex < nChildren - 1) && m_pSortFunc( pParent->m_Children[nChildIndex+1]->m_pData, pNode->m_pData );
		if ( bLeftBad || bRightBad )
		{
			pParent->m_Children.Remove( nChildIndex );
			pParent->AddChild( pNode );
		}
	}

    InvalidateLayout();

	return true;
}

//-----------------------------------------------------------------------------
// Purpose: set the selection colors of an element in the tree view
//-----------------------------------------------------------------------------

void TreeView::SetItemSelectionTextColor( int itemIndex, const Color& clr )
{
	Assert( m_NodeList.IsValidIndex(itemIndex) );
	if ( !m_NodeList.IsValidIndex(itemIndex) )
		return;

	TreeNode *pNode = m_NodeList[itemIndex];
	pNode->SetSelectionTextColor( clr );
}

void TreeView::SetItemSelectionBgColor( int itemIndex, const Color& clr )
{
	Assert( m_NodeList.IsValidIndex(itemIndex) );
	if ( !m_NodeList.IsValidIndex(itemIndex) )
		return;

	TreeNode *pNode = m_NodeList[itemIndex];
	pNode->SetSelectionBgColor( clr );
}

void TreeView::SetItemSelectionUnfocusedBgColor( int itemIndex, const Color& clr )
{
	Assert( m_NodeList.IsValidIndex(itemIndex) );
	if ( !m_NodeList.IsValidIndex(itemIndex) )
		return;

	TreeNode *pNode = m_NodeList[itemIndex];
	pNode->SetSelectionUnfocusedBgColor( clr );
}

//-----------------------------------------------------------------------------
// Purpose: set the fg color of an element in the tree view
//-----------------------------------------------------------------------------
void TreeView::SetItemFgColor(int itemIndex, const Color& color)
{
	Assert( m_NodeList.IsValidIndex(itemIndex) );
	if ( !m_NodeList.IsValidIndex(itemIndex) )
		return;

	TreeNode *pNode = m_NodeList[itemIndex];
	pNode->SetFgColor( color );
}

//-----------------------------------------------------------------------------
// Purpose: set the bg color of an element in the tree view
//-----------------------------------------------------------------------------
void TreeView::SetItemBgColor(int itemIndex, const Color& color)
{
	Assert( m_NodeList.IsValidIndex(itemIndex) );
	if ( !m_NodeList.IsValidIndex(itemIndex) )
		return;

	TreeNode *pNode = m_NodeList[itemIndex];
	pNode->SetBgColor( color );
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int TreeView::GetItemParent(int itemIndex)
{
	return m_NodeList[itemIndex]->m_ParentIndex;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void TreeView::SetImageList(ImageList *imageList, bool deleteImageListWhenDone)
{
	CleanUpImageList();
    m_pImageList = imageList;
    m_bDeleteImageListWhenDone = deleteImageListWhenDone;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
IImage *TreeView::GetImage(int index)
{
    return m_pImageList->GetImage(index);
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void TreeView::GetSelectedItems( CUtlVector< int >& list )
{
	list.RemoveAll();

	int c = m_SelectedItems.Count();
	for ( int i = 0 ; i < c; ++i )
	{
		list.AddToTail( m_SelectedItems[ i ]->m_ItemIndex );
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void TreeView::GetSelectedItemData( CUtlVector< KeyValues * >& list )
{
	list.RemoveAll();

	int c = m_SelectedItems.Count();
	for ( int i = 0 ; i < c; ++i )
	{
		list.AddToTail( m_SelectedItems[ i ]->m_pData );
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool TreeView::IsItemIDValid(int itemIndex)
{
    return m_NodeList.IsValidIndex(itemIndex);
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int TreeView::GetHighestItemID()
{
    return m_NodeList.MaxElementIndex();
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void TreeView::ExpandItem(int itemIndex, bool bExpand)
{
    if (!m_NodeList.IsValidIndex(itemIndex))
        return;

    m_NodeList[itemIndex]->SetNodeExpanded(bExpand);
    InvalidateLayout();
}

bool TreeView::IsItemExpanded( int itemIndex )
{
    if (!m_NodeList.IsValidIndex(itemIndex))
        return false;

    return m_NodeList[itemIndex]->IsExpanded();
}

//-----------------------------------------------------------------------------
// Purpose: Scrolls the list according to the mouse wheel movement
//-----------------------------------------------------------------------------
void TreeView::OnMouseWheeled(int delta)
{
	if ( !m_pVertScrollBar->IsVisible() )
	{
		return;
	}
	int val = m_pVertScrollBar->GetValue();
	val -= (delta * 3);
	m_pVertScrollBar->SetValue(val);
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void TreeView::OnSizeChanged(int wide, int tall)
{
	BaseClass::OnSizeChanged(wide, tall);
	InvalidateLayout();
	Repaint();
}

void TreeView::GetScrollBarSize( bool vertical, int& w, int& h )
{
	int idx = vertical ? 0 : 1;

	if ( m_bScrollbarExternal[ idx ] )
	{
		w = h = 0;
		return;
	}

	if ( vertical )
	{
		m_pVertScrollBar->GetSize( w, h );
	}
	else
	{
		m_pHorzScrollBar->GetSize( w, h );
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void TreeView::PerformLayout()
{
    int wide, tall;
    GetSize( wide, tall );

    if ( !m_pRootNode )
	{
		m_pSubPanel->SetSize( wide, tall );
        return;
	}

	int sbhw, sbhh;
	GetScrollBarSize( false, sbhw, sbhh );
	int sbvw, sbvh;
	GetScrollBarSize( true, sbvw, sbvh );

    bool vbarNeeded = false;
    bool hbarNeeded = false;

    // okay we have to check if we need either scroll bars, since if we need one
    // it might make it necessary to have the other one
    int nodesVisible = tall / m_nRowHeight;

	// count the number of visible items
	int visibleItemCount = m_pRootNode->CountVisibleNodes();
    int maxWidth = m_pRootNode->GetVisibleMaxWidth() + 10; // 10 pixel buffer

    vbarNeeded = visibleItemCount > nodesVisible;

    if (!vbarNeeded)
    {
        if (maxWidth > wide)
        {
            hbarNeeded = true;

            // recalculate if vbar is needed now
            // double check that we really don't need it
            nodesVisible = (tall - sbhh) / m_nRowHeight;
            vbarNeeded = visibleItemCount > nodesVisible;
        }
    }
    else
    {
        // we've got the vertical bar here, so shrink the width
        hbarNeeded = maxWidth > (wide - (sbvw+2));

        if (hbarNeeded)
        {
            nodesVisible = (tall - sbhh) / m_nRowHeight;
        }
    }

    int subPanelWidth = wide;
    int subPanelHeight = tall;

	int vbarPos = 0;
    if (vbarNeeded)
    {
        subPanelWidth -= (sbvw + 2);
        int barSize = tall;
        if (hbarNeeded)
        {
            barSize -= sbhh;
        }

    	//!! need to make it recalculate scroll positions
    	m_pVertScrollBar->SetVisible(true);
    	m_pVertScrollBar->SetEnabled(false);
    	m_pVertScrollBar->SetRangeWindow( nodesVisible );
    	m_pVertScrollBar->SetRange( 0, visibleItemCount);
    	m_pVertScrollBar->SetButtonPressedScrollValue( 1 );

		if ( !m_bScrollbarExternal[ 0 ] )
		{
    		m_pVertScrollBar->SetPos(wide - (sbvw + WINDOW_BORDER_WIDTH), 0);
    		m_pVertScrollBar->SetSize(sbvw, barSize - 2);
		}

        // need to figure out
        vbarPos = m_pVertScrollBar->GetValue();
    }
    else
    {
    	m_pVertScrollBar->SetVisible(false);
		m_pVertScrollBar->SetValue( 0 );
    }

    int hbarPos = 0;
    if (hbarNeeded)
    {
        subPanelHeight -= (sbhh + 2);
        int barSize = wide;
        if (vbarNeeded)
        {
            barSize -= sbvw;
        }
        m_pHorzScrollBar->SetVisible(true);
        m_pHorzScrollBar->SetEnabled(false);
        m_pHorzScrollBar->SetRangeWindow( barSize );
        m_pHorzScrollBar->SetRange( 0, maxWidth);
        m_pHorzScrollBar->SetButtonPressedScrollValue( 10 );

		if ( !m_bScrollbarExternal[ 1 ] )
		{
			m_pHorzScrollBar->SetPos(0, tall - (sbhh + WINDOW_BORDER_WIDTH));
			m_pHorzScrollBar->SetSize(barSize - 2, sbhh);
		}

        hbarPos = m_pHorzScrollBar->GetValue();
    }
    else
    {
    	m_pHorzScrollBar->SetVisible(false);
		m_pHorzScrollBar->SetValue( 0 );
    }

    m_pSubPanel->SetSize(subPanelWidth, subPanelHeight);

	int y = 0;
    m_pRootNode->PositionAndSetVisibleNodes(vbarPos, visibleItemCount, -hbarPos, y);

    Repaint();
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void TreeView::MakeItemVisible(int itemIndex)
{
    // first make sure that all parents are expanded
    TreeNode *pNode = m_NodeList[itemIndex];
    TreeNode *pParent = pNode->GetParentNode();
    while (pParent)
    {
        if (!pParent->m_bExpand)
        {
            pParent->SetNodeExpanded(true);
        }
        pParent = pParent->GetParentNode();
    }

    // recalculate scroll bar due to possible exapnsion
    PerformLayout();

    if (!m_pVertScrollBar->IsVisible())
        return;

    int visibleIndex = pNode->CountVisibleIndex()-1;
    int range = m_pVertScrollBar->GetRangeWindow();
    int vbarPos = m_pVertScrollBar->GetValue();

    // do we need to scroll up or down?
    if (visibleIndex < vbarPos)
    {
        m_pVertScrollBar->SetValue(visibleIndex);
    }
    else if (visibleIndex+1 > vbarPos+range)
    {
        m_pVertScrollBar->SetValue(visibleIndex+1-range);
    }
    InvalidateLayout();
}

void TreeView::GetVBarInfo( int &top, int &nItemsVisible, bool& hbarVisible )
{
    int wide, tall;
    GetSize( wide, tall );
    nItemsVisible = tall / m_nRowHeight;

    if ( m_pVertScrollBar->IsVisible() )
	{
		top = m_pVertScrollBar->GetValue();
	}
	else
	{
		top = 0;
	}
	hbarVisible = m_pHorzScrollBar->IsVisible();
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void TreeView::ApplySchemeSettings(IScheme *pScheme)
{
	BaseClass::ApplySchemeSettings(pScheme);

	SetBorder(pScheme->GetBorder("ButtonDepressedBorder"));
	SetBgColor(GetSchemeColor("TreeView.BgColor", GetSchemeColor("WindowDisabledBgColor", pScheme), pScheme));
	SetFont( pScheme->GetFont( "Default", IsProportional() ) );
	m_pSubPanel->SetBgColor( GetBgColor() );
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void TreeView::SetBgColor( Color color )
{
	BaseClass::SetBgColor( color );
	m_pSubPanel->SetBgColor( color );
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void TreeView::OnSliderMoved( int position )
{
	InvalidateLayout();
	Repaint();
}

void TreeView::GenerateDragDataForItem( int itemIndex, KeyValues *msg )
{
	// Implemented by subclassed TreeView
}

void TreeView::SetDragEnabledItems( bool state )
{
	m_bDragEnabledItems = state;
}

void TreeView::OnLabelChanged( int itemIndex, char const *oldString, char const *newString )
{
}

bool TreeView::IsLabelEditingAllowed() const
{
	return m_bAllowLabelEditing;
}

void TreeView::SetLabelBeingEdited( bool state )
{
	m_bLabelBeingEdited = state;
}

bool TreeView::IsLabelBeingEdited() const
{
	return m_bLabelBeingEdited;
}

void TreeView::SetAllowLabelEditing( bool state )
{
	m_bAllowLabelEditing = state;
}

void TreeView::EnableExpandTreeOnLeftClick( bool bEnable )
{
	m_bLeftClickExpandsTree = bEnable;
}

int TreeView::FindItemUnderMouse( int mx, int my )
{
	mx = clamp( mx, 0, GetWide() - 1 );
	my = clamp( my, 0, GetTall() - 1 );
	if ( mx >= TREE_INDENT_AMOUNT )
	{
		// Find what's under this position
		// need to figure out
		int vbarPos = m_pVertScrollBar->IsVisible() ? m_pVertScrollBar->GetValue() : 0;
		int hbarPos = m_pHorzScrollBar->IsVisible() ? m_pHorzScrollBar->GetValue() : 0;
		int count = m_pRootNode->CountVisibleNodes();

		int y = 0;
		TreeNode *item = m_pRootNode->FindItemUnderMouse( vbarPos, count, -hbarPos, y, mx, my );
		if ( item  )
		{
			return item->m_ItemIndex;
		}
	}

	return -1;
}

void TreeView::OnMousePressed( MouseCode code )
{
	bool ctrl = (input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL));
	bool shift = (input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT));

	// Try to map mouse position to a row
	if ( code == MOUSE_LEFT && m_pRootNode )
	{
		int mx, my;
		input()->GetCursorPos( mx, my );
		ScreenToLocal( mx, my );
		if ( mx >= TREE_INDENT_AMOUNT )
		{
			// Find what's under this position
			// need to figure out
			int vbarPos = m_pVertScrollBar->IsVisible() ? m_pVertScrollBar->GetValue() : 0;
			int hbarPos = m_pHorzScrollBar->IsVisible() ? m_pHorzScrollBar->GetValue() : 0;
			int count = m_pRootNode->CountVisibleNodes();

			int y = 0;
			TreeNode *item = m_pRootNode->FindItemUnderMouse( vbarPos, count, -hbarPos, y, mx, my );
			if ( item  )
			{
				if ( !item->IsSelected() )
				{
					AddSelectedItem( item->m_ItemIndex, !ctrl && !shift );
				}
				return;
			}
			else
			{
				ClearSelection();
			}
		}
	}

	BaseClass::OnMousePressed( code );
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  : state -
//-----------------------------------------------------------------------------
void TreeView::SetAllowMultipleSelections( bool state )
{
	m_bAllowMultipleSelections = state;
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  :  -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool TreeView::IsMultipleSelectionAllowed() const
{
	return m_bAllowMultipleSelections;
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  :  -
// Output : int
//-----------------------------------------------------------------------------
int TreeView::GetSelectedItemCount() const
{
	return m_SelectedItems.Count();
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  :  -
//-----------------------------------------------------------------------------
void TreeView::ClearSelection()
{
	m_SelectedItems.RemoveAll();
	m_nMostRecentlySelectedItem = -1;
	PostActionSignal( new KeyValues( "TreeViewItemSelectionCleared" ) );
}

void TreeView::RangeSelectItems( int endItem )
{
	int startItem = m_nMostRecentlySelectedItem;
	ClearSelection();
	m_nMostRecentlySelectedItem = startItem;

	if ( !m_NodeList.IsValidIndex( startItem ) )
	{
		AddSelectedItem( endItem, false );
		return;
	}

	Assert( m_NodeList.IsValidIndex( endItem ) );

	if ( !m_pRootNode )
	{
		return;
	}

	CUtlVector< TreeNode * > list;
	m_pRootNode->FindNodesInRange( list, startItem, endItem );

	int c = list.Count();
	for ( int i = 0; i < c; ++i )
	{
		TreeNode *item = list[ i ];
		AddSelectedItem( item->m_ItemIndex, false );
	}
}

void TreeView::FindNodesInRange( int startItem, int endItem, CUtlVector< int >& itemIndices )
{
	CUtlVector< TreeNode * > nodes;
	m_pRootNode->FindNodesInRange( nodes, startItem, endItem );

	int c = nodes.Count();
	for ( int i = 0; i < c; ++i )
	{
		TreeNode *item = nodes[ i ];
		itemIndices.AddToTail( item->m_ItemIndex );
	}
}

void TreeView::RemoveSelectedItem( int itemIndex )
{
	if ( !m_NodeList.IsValidIndex( itemIndex ) )
		return;

	TreeNode *sel = m_NodeList[ itemIndex ];
	Assert( sel );
	int slot = m_SelectedItems.Find( sel );
	if ( slot != m_SelectedItems.InvalidIndex() )
	{
		m_SelectedItems.Remove( slot );
		PostActionSignal( new KeyValues( "TreeViewItemDeselected", "itemIndex", itemIndex ) );

		m_nMostRecentlySelectedItem = itemIndex;
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void TreeView::AddSelectedItem( int itemIndex, bool clearCurrentSelection, bool requestFocus /* = true */, bool bMakeItemVisible /*= true*/ )
{
	if ( clearCurrentSelection )
	{
		ClearSelection();
	}

	// Assume it's bogus
    if ( !m_NodeList.IsValidIndex( itemIndex ) )
        return;

    TreeNode *sel = m_NodeList[ itemIndex ];
	Assert( sel );
	if ( requestFocus )
	{
		sel->RequestFocus();
	}

	// Item 0 is most recently selected!!!
	int slot = m_SelectedItems.Find( sel );
	if ( slot == m_SelectedItems.InvalidIndex() )
	{
		m_SelectedItems.AddToHead( sel );
	}
	else if ( slot != 0 )
	{
		m_SelectedItems.Remove( slot );
		m_SelectedItems.AddToHead( sel );
	}

	if ( bMakeItemVisible )
	{
		MakeItemVisible( itemIndex );
	}

    PostActionSignal( new KeyValues( "TreeViewItemSelected", "itemIndex", itemIndex ) );
    InvalidateLayout();

	if ( clearCurrentSelection )
	{
		m_nMostRecentlySelectedItem = itemIndex;
	}
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  :  -
// Output : int
//-----------------------------------------------------------------------------
int TreeView::GetFirstSelectedItem() const
{
	if ( m_SelectedItems.Count() <= 0 )
		return -1;
	return m_SelectedItems[ 0 ]->m_ItemIndex;
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  : itemIndex -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool TreeView::IsItemSelected( int itemIndex )
{
	// Assume it's bogus
    if ( !m_NodeList.IsValidIndex( itemIndex ) )
        return false;

    TreeNode *sel = m_NodeList[ itemIndex ];
	return m_SelectedItems.Find( sel ) != m_SelectedItems.InvalidIndex();
}

void TreeView::SetLabelEditingAllowed( int itemIndex, bool state )
{
	if ( !m_NodeList.IsValidIndex( itemIndex ) )
		return;

	TreeNode *sel = m_NodeList[ itemIndex ];
	sel->SetLabelEditingAllowed( state );
}

void  TreeView::StartEditingLabel( int itemIndex )
{
	if ( !m_NodeList.IsValidIndex( itemIndex ) )
		return;

	Assert( IsLabelEditingAllowed() );

	TreeNode *sel = m_NodeList[ itemIndex ];
	Assert( sel->IsLabelEditingAllowed() );
	if ( !sel->IsLabelEditingAllowed() )
		return;

	sel->EditLabel();
}

int TreeView::GetPrevChildItemIndex( int itemIndex )
{
	if ( !m_NodeList.IsValidIndex( itemIndex ) )
		return -1;
	TreeNode *sel = m_NodeList[ itemIndex ];
	TreeNode *parent = sel->GetParentNode();
	if ( !parent )
		return -1;

	return parent->GetPrevChildItemIndex( sel );
}

int TreeView::GetNextChildItemIndex( int itemIndex )
{
	if ( !m_NodeList.IsValidIndex( itemIndex ) )
		return -1;
	TreeNode *sel = m_NodeList[ itemIndex ];
	TreeNode *parent = sel->GetParentNode();
	if ( !parent )
		return -1;

	return parent->GetNextChildItemIndex( sel );
}

bool TreeView::IsItemDroppable( int itemIndex, CUtlVector< KeyValues * >& msglist )
{
	// Derived classes should implement
	return false;
}

void TreeView::OnItemDropped( int itemIndex, CUtlVector< KeyValues * >& msglist )
{
}

bool TreeView::GetItemDropContextMenu( int itemIndex, Menu *menu, CUtlVector< KeyValues * >& msglist )
{
	return false;
}

HCursor TreeView::GetItemDropCursor( int itemIndex, CUtlVector< KeyValues * >& msglist )
{
	return dc_arrow;
}

void TreeView::RemoveChildrenOfNode( int itemIndex )
{
	if ( !m_NodeList.IsValidIndex( itemIndex ) )
		return;

	TreeNode *node = m_NodeList[ itemIndex ];
	node->RemoveChildren();
}

ScrollBar *TreeView::SetScrollBarExternal( bool vertical, Panel *newParent )
{
	if ( vertical )
	{
		m_bScrollbarExternal[ 0 ] = true;
		m_pVertScrollBar->SetParent( newParent );
		return m_pVertScrollBar;
	}
	m_bScrollbarExternal[ 1 ] = true;
	m_pHorzScrollBar->SetParent( newParent );
	return m_pHorzScrollBar;
}

// if this is set, then clicking on one row and dragging will select a run or items, etc.
void TreeView::SetMultipleItemDragEnabled( bool state )
{
	m_bMultipleItemDragging = state;
}

bool TreeView::IsMultipleItemDragEnabled() const
{
	return m_bMultipleItemDragging;
}

void TreeView::SelectAll()
{
	m_SelectedItems.RemoveAll();
	FOR_EACH_LL( m_NodeList, i )
	{
		m_SelectedItems.AddToTail( m_NodeList[ i ] );
	}

	PostActionSignal( new KeyValues( "TreeViewItemSelected", "itemIndex", GetRootItemIndex() ) );
	InvalidateLayout();
}


text:
using System;
using NUnit.Framework;
using TagLib;
using System.IO;

namespace TagLib.Tests.FileFormats
{
	[TestFixture]
	public class AudibleFormatTest
	{
		private static string BaseDirectory = "samples/audible";

		[Test]
		public void First ()
		{
			var tag = (Audible.Tag) File.Create(Path.Combine (BaseDirectory, "first.aa")).Tag;
			Assert.AreEqual (tag.Album, "Glyn Hughes"); // This is probably wrong. The publisher is not the album
			Assert.AreEqual (tag.Author, "Ricky Gervais, Steve Merchant, & Karl Pilkington");
			Assert.AreEqual (tag.Copyright, "©2009 Ricky Gervais; (P)2009 Ricky Gervais");
			Assert.IsTrue (tag.Description.StartsWith ("This is the second in a new series of definitive discourses exploring the diversity of human"));
			Assert.AreEqual (tag.Narrator, "Ricky Gervais, Steve Merchant, & Karl Pilkington");
			Assert.AreEqual (tag.Title, "The Ricky Gervais Guide to... NATURAL HISTORY (Unabridged)");
		}

		[Test]
		[Ignore ("Not supported yet")]
		public void Second ()
		{
			var tag = (Audible.Tag) File.Create(Path.Combine (BaseDirectory, "second.aax")).Tag;
			Assert.AreEqual (tag.Album, "Glyn Hughes"); // This is probably wrong. The publisher is not the album
			Assert.AreEqual (tag.Author, "Ricky Gervais, Steve Merchant, & Karl Pilkington");
			Assert.AreEqual (tag.Copyright, "©2009 Ricky Gervais; (P)2009 Ricky Gervais");
			Assert.IsTrue (tag.Description.StartsWith ("This is the second in a new series of definitive discourses exploring the diversity of human"));
			Assert.AreEqual (tag.Narrator, "Ricky Gervais, Steve Merchant, & Karl Pilkington");
			Assert.AreEqual (tag.Title, "The Ricky Gervais Guide to... NATURAL HISTORY (Unabridged)");
		}

		[Test]
		public void Third ()
		{
			var tag = (Audible.Tag) File.Create(Path.Combine (BaseDirectory, "third.aa")).Tag;
			Assert.AreEqual (tag.Album, "Glyn Hughes"); // This is probably wrong. The publisher is not the album
			Assert.AreEqual (tag.Author, "Ricky Gervais, Steve Merchant, & Karl Pilkington");
			Assert.AreEqual (tag.Copyright, "©2009 Ricky Gervais; (P)2009 Ricky Gervais");
			Assert.IsTrue (tag.Description.StartsWith ("This is the second in a new series of definitive discourses exploring the diversity of human"));
			Assert.AreEqual (tag.Narrator, "Ricky Gervais, Steve Merchant, & Karl Pilkington");
			Assert.AreEqual (tag.Title, "The Ricky Gervais Guide to... NATURAL HISTORY (Unabridged)");
		}

		[Test]
		public void Fourth ()
		{
			var tag = (Audible.Tag) File.Create(Path.Combine (BaseDirectory, "fourth.aa")).Tag;
			Assert.AreEqual (tag.Album, "Glyn Hughes"); // This is probably wrong. The publisher is not the album
			Assert.AreEqual (tag.Author, "Ricky Gervais, Steve Merchant & Karl Pilkington");
			Assert.AreEqual (tag.Copyright, "©2010 Ricky Gervais; (P)2010 Ricky Gervais");
			Assert.IsTrue (tag.Description.StartsWith ("The ninth episode in this new series considers the human body, its form, function, and failings"));
			Assert.AreEqual (tag.Narrator, "Ricky Gervais, Steve Merchant & Karl Pilkington");
			Assert.AreEqual (tag.Title, "The Ricky Gervais Guide to... THE HUMAN BODY");
		}
	}
}

redpajama_set_name: RedPajamaGithub


text:
This inspection reports Runnable passed to Cleaner.register() capturing reference that leads to memory leak.
Possible sources of this problem:

Lambda using non static methods, fields or this itself

Non static inner class (anonymous or not) always captures this reference

Instance method reference

Access to outer class non static members from non static inner class

This inspection is available since Java 9 only.

New in 2018.1


text:
import {Component} from 'angular2/core';
import {RouteConfig} from 'angular2/router';
import {TemplateComponent} from '../template/index';
import {LoginComponent} from '../login/index';
import {LoggedInRouterOutlet} from '../loggedin.outlet';

@Component({
  selector: 'sd-app',
  templateUrl: 'app/components/app.component.html',
  directives: [LoggedInRouterOutlet]
})
@RouteConfig([
  {
    path: '/...',
    name: 'App',
    component: TemplateComponent,
    useAsDefault: true
  },
  {
    path: "/login",
    name: "Login",
    component: LoginComponent
  }
])
export class AppComponent {}


text:
import sys
import os
import xml.etree.ElementTree as ET

xmlfile=filename # Take filename as argument before this!

# ACTUAL PARSING BEGINS BELOW :
#num_lines is length of file ie, number of lines in region.xml file.
num_lines = sum(1 for line in open(xmlfile))

#To reach the root of tree

tree = ET.parse(xmlfile)
root = tree.getroot()

#To get the number of "KEYWORD" in the file
from xml.dom.minidom import parseString
file = open(xmlfile,'r')
data = file.read() #open
file.close()
dom = parseString(data)
x = len(dom.getElementsByTagName('KEYWORD')) # get count and saves to variable x

for v in range(len()): # LOOP for number of commandline arugments

        for i in range(x):   # LOOP for number of count of keyword

                if str(''.join(root[i].attrib['KEYWORD_attrib'])) ==  "KEYWORD" :
                        print "Key Name : " + root[i].attrib['KEYWORD_attrib']


text:
#include "elm/encoding/ganglion.h"

#include <opencv2/imgproc/imgproc.hpp>

#include "elm/core/exception.h"

using namespace cv;

base_Ganglion::~base_Ganglion()
{
}

base_Ganglion::base_Ganglion()
{
}

DiffOfGaussians2dSq::DiffOfGaussians2dSq()
    : base_Ganglion()
{
}
#include <iostream>
void DiffOfGaussians2dSq::Init(int radius, float scale, bool center_on)
{
    //sigma = 0.3*((ksize-1)*0.5 - 1) + 0.8
    sigma_center_ = scale*2;
    sigma_surround_ = scale*10;

    if(radius < 1) {

        ELM_THROW_BAD_DIMS("Diff. of Gaussians radius must be > 0.");
    }

    size_ = radius*2+1;
//    Mat center = getGaussianKernel(size_, sigma_center_, CV_32F);
//    Mat surround = getGaussianKernel(size_, sigma_surround_, CV_32F);

    is_center_on_ = center_on;
}

Mat1f DiffOfGaussians2dSq::Kernel() const
{
    Mat1f impulse = Mat1f::zeros(size_, size_);
    impulse(size_/2, size_/2) = 1.f;

    return const_cast<DiffOfGaussians2dSq*>(this)->Compute(impulse);
}

Mat1f DiffOfGaussians2dSq::Compute(InputArray in)
{
    Mat r_surround, r_center, r_diff;
    GaussianBlur(in, r_center,
                 Size2i(size_, size_),
                 sigma_center_, sigma_center_,
                 BORDER_REPLICATE);

    GaussianBlur(in, r_surround,
                 Size2i(size_, size_),
                 sigma_surround_, sigma_surround_,
                 BORDER_REPLICATE);

    r_diff = (is_center_on_)? r_center-r_surround : r_surround-r_center;

    return r_diff;
}


text:
using System.Collections.Generic;
using Xunit;
using Xunit.Abstractions;

namespace System.Linq.Tests
{
    public class SkipTests : EnumerableTests
    {
        private static IEnumerable<T> GuaranteeNotIList<T>(IEnumerable<T> source)
        {
            foreach (T element in source)
                yield return element;
        }

        [Fact]
        public void SkipSome()
        {
            Assert.Equal(Enumerable.Range(10, 10), NumberRangeGuaranteedNotCollectionType(0, 20).Skip(10));
        }

        [Fact]
        public void SkipSomeIList()
        {
            Assert.Equal(Enumerable.Range(10, 10), NumberRangeGuaranteedNotCollectionType(0, 20).ToList().Skip(10));
        }

        [Fact]
        public void SkipNone()
        {
            Assert.Equal(Enumerable.Range(0, 20), NumberRangeGuaranteedNotCollectionType(0, 20).Skip(0));
        }

        [Fact]
        public void SkipNoneIList()
        {
            Assert.Equal(Enumerable.Range(0, 20), NumberRangeGuaranteedNotCollectionType(0, 20).ToList().Skip(0));
        }

        [Fact]
        public void SkipExcessive()
        {
            Assert.Equal(Enumerable.Empty<int>(), NumberRangeGuaranteedNotCollectionType(0, 20).Skip(42));
        }

        [Fact]
        public void SkipExcessiveIList()
        {
            Assert.Equal(Enumerable.Empty<int>(), NumberRangeGuaranteedNotCollectionType(0, 20).ToList().Skip(42));
        }

        [Fact]
        public void SkipAllExactly()
        {
            Assert.False(NumberRangeGuaranteedNotCollectionType(0, 20).Skip(20).Any());
        }

        [Fact]
        public void SkipAllExactlyIList()
        {
            Assert.False(NumberRangeGuaranteedNotCollectionType(0, 20).Skip(20).ToList().Any());
        }

        [Fact]
        public void SkipThrowsOnNull()
        {
            Assert.Throws<ArgumentNullException>("source", () => ((IEnumerable<DateTime>)null).Skip(3));
        }

        [Fact]
        public void SkipThrowsOnNullIList()
        {
            Assert.Throws<ArgumentNullException>("source", () => ((List<DateTime>)null).Skip(3));
            Assert.Throws<ArgumentNullException>("source", () => ((IList<DateTime>)null).Skip(3));
        }

        [Fact]
        public void SkipOnEmpty()
        {
            Assert.Equal(Enumerable.Empty<int>(), GuaranteeNotIList(Enumerable.Empty<int>()).Skip(0));
            Assert.Equal(Enumerable.Empty<string>(), GuaranteeNotIList(Enumerable.Empty<string>()).Skip(-1));
            Assert.Equal(Enumerable.Empty<double>(), GuaranteeNotIList(Enumerable.Empty<double>()).Skip(1));
        }

        [Fact]
        public void SkipOnEmptyIList()
        {
            // Enumerable.Empty does return an IList, but not guaranteed as such
            // by the spec.
            Assert.Equal(Enumerable.Empty<int>(), Enumerable.Empty<int>().ToList().Skip(0));
            Assert.Equal(Enumerable.Empty<string>(), Enumerable.Empty<string>().ToList().Skip(-1));
            Assert.Equal(Enumerable.Empty<double>(), Enumerable.Empty<double>().ToList().Skip(1));
        }

        [Fact]
        public void SkipNegative()
        {
            Assert.Equal(Enumerable.Range(0, 20), NumberRangeGuaranteedNotCollectionType(0, 20).Skip(-42));
        }

        [Fact]
        public void SkipNegativeIList()
        {
            Assert.Equal(Enumerable.Range(0, 20), NumberRangeGuaranteedNotCollectionType(0, 20).ToList().Skip(-42));
        }

        [Fact]
        public void SameResultsRepeatCallsIntQuery()
        {
            var q = GuaranteeNotIList(from x in new[] { 9999, 0, 888, -1, 66, -777, 1, 2, -12345 }
                    where x > Int32.MinValue
                    select x);

            Assert.Equal(q.Skip(0), q.Skip(0));
        }

        [Fact]
        public void SameResultsRepeatCallsIntQueryIList()
        {
            var q = (from x in new[] { 9999, 0, 888, -1, 66, -777, 1, 2, -12345 }
                    where x > Int32.MinValue
                    select x).ToList();

            Assert.Equal(q.Skip(0), q.Skip(0));
        }

        [Fact]
        public void SameResultsRepeatCallsStringQuery()
        {
            var q = GuaranteeNotIList(from x in new[] { "!@#$%^", "C", "AAA", "", "Calling Twice", "SoS", String.Empty }
                    where !String.IsNullOrEmpty(x)
                    select x);

            Assert.Equal(q.Skip(0), q.Skip(0));
        }

        [Fact]
        public void SameResultsRepeatCallsStringQueryIList()
        {
            var q = (from x in new[] { "!@#$%^", "C", "AAA", "", "Calling Twice", "SoS", String.Empty }
                    where !String.IsNullOrEmpty(x)
                    select x).ToList();

            Assert.Equal(q.Skip(0), q.Skip(0));
        }

        [Fact]
        public void SkipOne()
        {
            int?[] source = { 3, 100, 4, null, 10 };
            int?[] expected = { 100, 4, null, 10 };

            Assert.Equal(expected, source.Skip(1));
        }

        [Fact]
        public void SkipOneNotIList()
        {
            int?[] source = { 3, 100, 4, null, 10 };
            int?[] expected = { 100, 4, null, 10 };

            Assert.Equal(expected, GuaranteeNotIList(source).Skip(1));
        }

        [Fact]
        public void SkipAllButOne()
        {
            int?[] source = { 3, 100, null, 4, 10 };
            int?[] expected = { 10 };

            Assert.Equal(expected, source.Skip(source.Length - 1));
        }

        [Fact]
        public void SkipAllButOneNotIList()
        {
            int?[] source = { 3, 100, null, 4, 10 };
            int?[] expected = { 10 };

            Assert.Equal(expected, GuaranteeNotIList(source.Skip(source.Length - 1)));
        }

        [Fact]
        public void SkipOneMoreThanAll()
        {
            int[] source = { 3, 100, 4, 10 };
            Assert.Empty(source.Skip(source.Length + 1));
        }

        [Fact]
        public void SkipOneMoreThanAllNotIList()
        {
            int[] source = { 3, 100, 4, 10 };
            Assert.Empty(GuaranteeNotIList(source).Skip(source.Length + 1));
        }

        [Fact]
        public void ForcedToEnumeratorDoesntEnumerate()
        {
            var iterator = NumberRangeGuaranteedNotCollectionType(0, 3).Skip(2);
            // Don't insist on this behaviour, but check its correct if it happens
            var en = iterator as IEnumerator<int>;
            Assert.False(en != null && en.MoveNext());
        }

        [Fact]
        public void ForcedToEnumeratorDoesntEnumerateIList()
        {
            var iterator = (new[] { 0, 1, 2 }).Skip(2);
            // Don't insist on this behaviour, but check its correct if it happens
            var en = iterator as IEnumerator<int>;
            Assert.False(en != null && en.MoveNext());
        }

        [Fact]
        public void Count()
        {
            Assert.Equal(2, NumberRangeGuaranteedNotCollectionType(0, 3).Skip(1).Count());
            Assert.Equal(2, new[] { 1, 2, 3 }.Skip(1).Count());
        }

        [Fact]
        public void FollowWithTake()
        {
            var source = new[] { 5, 6, 7, 8 };
            var expected = new[] { 6, 7 };
            Assert.Equal(expected, source.Skip(1).Take(2));
        }

        [Fact]
        public void FollowWithTakeNotIList()
        {
            var source = NumberRangeGuaranteedNotCollectionType(5, 4);
            var expected = new[] { 6, 7 };
            Assert.Equal(expected, source.Skip(1).Take(2));
        }

        [Fact]
        public void FollowWithTakeThenMassiveTake()
        {
            var source = new[] { 5, 6, 7, 8 };
            var expected = new[] { 7 };
            Assert.Equal(expected, source.Skip(2).Take(1).Take(int.MaxValue));
        }
        [Fact]
        public void FollowWithTakeThenMassiveTakeNotIList()
        {
            var source = NumberRangeGuaranteedNotCollectionType(5, 4);
            var expected = new[] { 7 };
            Assert.Equal(expected, source.Skip(2).Take(1).Take(int.MaxValue));
        }

        [Fact]
        public void FollowWithSkip()
        {
            var source = new[] { 1, 2, 3, 4, 5, 6 };
            var expected = new[] { 4, 5, 6 };
            Assert.Equal(expected, source.Skip(1).Skip(2).Skip(-4));
        }

        [Fact]
        public void FollowWithSkipNotIList()
        {
            var source = NumberRangeGuaranteedNotCollectionType(1, 6);
            var expected = new[] { 4, 5, 6 };
            Assert.Equal(expected, source.Skip(1).Skip(2).Skip(-4));
        }

        [Fact]
        public void ElementAt()
        {
            var source = new[] { 1, 2, 3, 4, 5, 6 };
            var remaining = source.Skip(2);
            Assert.Equal(3, remaining.ElementAt(0));
            Assert.Equal(4, remaining.ElementAt(1));
            Assert.Equal(6, remaining.ElementAt(3));
            Assert.Throws<ArgumentOutOfRangeException>("index", () => remaining.ElementAt(-1));
            Assert.Throws<ArgumentOutOfRangeException>("index", () => remaining.ElementAt(4));
        }

        [Fact]
        public void ElementAtNotIList()
        {
            var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5, 6 });
            var remaining = source.Skip(2);
            Assert.Equal(3, remaining.ElementAt(0));
            Assert.Equal(4, remaining.ElementAt(1));
            Assert.Equal(6, remaining.ElementAt(3));
            Assert.Throws<ArgumentOutOfRangeException>("index", () => remaining.ElementAt(-1));
            Assert.Throws<ArgumentOutOfRangeException>("index", () => remaining.ElementAt(4));
        }

        [Fact]
        public void ElementAtOrDefault()
        {
            var source = new[] { 1, 2, 3, 4, 5, 6 };
            var remaining = source.Skip(2);
            Assert.Equal(3, remaining.ElementAtOrDefault(0));
            Assert.Equal(4, remaining.ElementAtOrDefault(1));
            Assert.Equal(6, remaining.ElementAtOrDefault(3));
            Assert.Equal(0, remaining.ElementAtOrDefault(-1));
            Assert.Equal(0, remaining.ElementAtOrDefault(4));
        }

        [Fact]
        public void ElementAtOrDefaultNotIList()
        {
            var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5, 6 });
            var remaining = source.Skip(2);
            Assert.Equal(3, remaining.ElementAtOrDefault(0));
            Assert.Equal(4, remaining.ElementAtOrDefault(1));
            Assert.Equal(6, remaining.ElementAtOrDefault(3));
            Assert.Equal(0, remaining.ElementAtOrDefault(-1));
            Assert.Equal(0, remaining.ElementAtOrDefault(4));
        }

        [Fact]
        public void First()
        {
            var source = new[] { 1, 2, 3, 4, 5 };
            Assert.Equal(1, source.Skip(0).First());
            Assert.Equal(3, source.Skip(2).First());
            Assert.Equal(5, source.Skip(4).First());
            Assert.Throws<InvalidOperationException>(() => source.Skip(5).First());
        }

        [Fact]
        public void FirstNotIList()
        {
            var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5 });
            Assert.Equal(1, source.Skip(0).First());
            Assert.Equal(3, source.Skip(2).First());
            Assert.Equal(5, source.Skip(4).First());
            Assert.Throws<InvalidOperationException>(() => source.Skip(5).First());
        }

        [Fact]
        public void FirstOrDefault()
        {
            var source = new[] { 1, 2, 3, 4, 5 };
            Assert.Equal(1, source.Skip(0).FirstOrDefault());
            Assert.Equal(3, source.Skip(2).FirstOrDefault());
            Assert.Equal(5, source.Skip(4).FirstOrDefault());
            Assert.Equal(0, source.Skip(5).FirstOrDefault());
        }

        [Fact]
        public void FirstOrDefaultNotIList()
        {
            var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5 });
            Assert.Equal(1, source.Skip(0).FirstOrDefault());
            Assert.Equal(3, source.Skip(2).FirstOrDefault());
            Assert.Equal(5, source.Skip(4).FirstOrDefault());
            Assert.Equal(0, source.Skip(5).FirstOrDefault());
        }

        [Fact]
        public void Last()
        {
            var source = new[] { 1, 2, 3, 4, 5 };
            Assert.Equal(5, source.Skip(0).Last());
            Assert.Equal(5, source.Skip(1).Last());
            Assert.Equal(5, source.Skip(4).Last());
            Assert.Throws<InvalidOperationException>(() => source.Skip(5).Last());
        }

        [Fact]
        public void LastNotList()
        {
            var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5 });
            Assert.Equal(5, source.Skip(0).Last());
            Assert.Equal(5, source.Skip(1).Last());
            Assert.Equal(5, source.Skip(4).Last());
            Assert.Throws<InvalidOperationException>(() => source.Skip(5).Last());
        }

        [Fact]
        public void LastOrDefault()
        {
            var source = new[] { 1, 2, 3, 4, 5 };
            Assert.Equal(5, source.Skip(0).LastOrDefault());
            Assert.Equal(5, source.Skip(1).LastOrDefault());
            Assert.Equal(5, source.Skip(4).LastOrDefault());
            Assert.Equal(0, source.Skip(5).LastOrDefault());
        }

        [Fact]
        public void LastOrDefaultNotList()
        {
            var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5 });
            Assert.Equal(5, source.Skip(0).LastOrDefault());
            Assert.Equal(5, source.Skip(1).LastOrDefault());
            Assert.Equal(5, source.Skip(4).LastOrDefault());
            Assert.Equal(0, source.Skip(5).LastOrDefault());
        }

        [Fact]
        public void ToArray()
        {
            var source = new[] { 1, 2, 3, 4, 5 };
            Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Skip(0).ToArray());
            Assert.Equal(new[] { 2, 3, 4, 5 }, source.Skip(1).ToArray());
            Assert.Equal(5, source.Skip(4).ToArray().Single());
            Assert.Empty(source.Skip(5).ToArray());
            Assert.Empty(source.Skip(40).ToArray());
        }

        [Fact]
        public void ToArrayNotList()
        {
            var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5 });
            Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Skip(0).ToArray());
            Assert.Equal(new[] { 2, 3, 4, 5 }, source.Skip(1).ToArray());
            Assert.Equal(5, source.Skip(4).ToArray().Single());
            Assert.Empty(source.Skip(5).ToArray());
            Assert.Empty(source.Skip(40).ToArray());
        }

        [Fact]
        public void ToList()
        {
            var source = new[] { 1, 2, 3, 4, 5 };
            Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Skip(0).ToList());
            Assert.Equal(new[] { 2, 3, 4, 5 }, source.Skip(1).ToList());
            Assert.Equal(5, source.Skip(4).ToList().Single());
            Assert.Empty(source.Skip(5).ToList());
            Assert.Empty(source.Skip(40).ToList());
        }

        [Fact]
        public void ToListNotList()
        {
            var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5 });
            Assert.Equal(new[] { 1, 2, 3, 4, 5 }, source.Skip(0).ToList());
            Assert.Equal(new[] { 2, 3, 4, 5 }, source.Skip(1).ToList());
            Assert.Equal(5, source.Skip(4).ToList().Single());
            Assert.Empty(source.Skip(5).ToList());
            Assert.Empty(source.Skip(40).ToList());
        }

        [Fact]
        public void RepeatEnumerating()
        {
            var source = new[] { 1, 2, 3, 4, 5 };
            var remaining = source.Skip(1);
            Assert.Equal(remaining, remaining);
        }

        [Fact]
        public void RepeatEnumeratingNotList()
        {
            var source = GuaranteeNotIList(new[] { 1, 2, 3, 4, 5 });
            var remaining = source.Skip(1);
            Assert.Equal(remaining, remaining);
        }
    }
}


text:
import * as React from 'react'
import { connect } from 'react-redux'
import {
    UncontrolledAlert,
    Col
} from 'reactstrap';

class Messages extends React.Component<any, any> {

	constructor(props) {
		super(props);
	}

	render() {
		const data = this.props.Messages.toObject();

        if (data.success && new Date().getTime() - data.success.time.getTime() < 10000) var success = <UncontrolledAlert
            color="success">{data.success.message}</UncontrolledAlert>
        if (data.warning && new Date().getTime() - data.warning.time.getTime() < 10000) var warning = <UncontrolledAlert
            color="warning">{data.warning.message}</UncontrolledAlert>

		if (!success && !warning) return null;

        return (<Col sm={12}>
            {success}
            {warning}
        </Col>)
	}
}

const mapStateToProps = (state) => {
    const Messages = state.get("Messages");
    const router = state.get("router");
    return {Messages, router};
};
/*
const mapDispatchToProps = (dispatch) => {
  return {
    doLogin:(credentials) => dispatch(doLogin(credentials))
  }
}
*/

const mapDispatchToProps = {};

var VisibleMessages = connect(
	mapStateToProps,
	mapDispatchToProps
)(Messages);

export default VisibleMessages;


text:
package logp

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"runtime"
	"strings"
)

// cmd line flags
var verbose *bool
var toStderr *bool
var debugSelectorsStr *string

type Logging struct {
	Selectors []string
	Files     *FileRotator
	To_syslog *bool
	To_files  *bool
}

func init() {
	// Adds logging specific flags: -v, -e and -d.
	verbose = flag.Bool("v", false, "Log at INFO level")
	toStderr = flag.Bool("e", false, "Output to stdout and disable syslog/file output")
	debugSelectorsStr = flag.String("d", "", "Enable certain debug selectors")
}

// Init combines the configuration from config with the command line
// flags to initialize the Logging systems. After calling this function,
// standard output is always enabled. You can make it respect the command
// line flag with a later SetStderr call.
func Init(name string, config *Logging) error {

	logLevel := LOG_ERR
	if *verbose {
		logLevel = LOG_INFO
	}

	debugSelectors := []string{}
	if len(*debugSelectorsStr) > 0 {
		debugSelectors = strings.Split(*debugSelectorsStr, ",")
		logLevel = LOG_DEBUG
	}

	var defaultToFiles, defaultToSyslog bool
	if runtime.GOOS == "windows" {
		// always disabled on windows
		defaultToSyslog = false
		defaultToFiles = true
	} else {
		defaultToSyslog = true
		defaultToFiles = false
	}

	var toSyslog, toFiles bool
	if config.To_syslog != nil {
		toSyslog = *config.To_syslog
	} else {
		toSyslog = defaultToSyslog
	}
	if config.To_files != nil {
		toFiles = *config.To_files
	} else {
		toFiles = defaultToFiles
	}

	// toStderr disables logging to syslog/files
	toSyslog = toSyslog && !*toStderr
	toFiles = toFiles && !*toStderr

	LogInit(Priority(logLevel), "", toSyslog, true, debugSelectors)
	if len(debugSelectors) > 0 {
		config.Selectors = debugSelectors
	}

	if toFiles {
		if config.Files == nil {
			if runtime.GOOS == "windows" {
				config.Files = &FileRotator{
					Path: fmt.Sprintf("C:\\ProgramData\\%s\\Logs", name),
					Name: name,
				}
			} else {
				config.Files = &FileRotator{
					Path: fmt.Sprintf("/var/log/%s", name),
					Name: name,
				}
			}
		}
		err := SetToFile(true, config.Files)
		if err != nil {
			return err
		}
	}

	if IsDebug("stdlog") {
		// disable standard logging by default (this is sometimes
		// used by libraries and we don't want their logs to spam ours)
		log.SetOutput(ioutil.Discard)
	}

	return nil
}

func SetStderr() {
	if !*toStderr {
		Info("Startup successful, disable stdout logging")
		SetToStderr(false, "")
	}
}