///
/// Copyright © 2003-2008 JetBrains s.r.o.
/// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder).
///
using System;
using System.Collections;
using System.Windows.Forms;
using JetBrains.UI.Interop;
namespace JetBrains.JetListViewLibrary
{
///
/// Manages incremental search in a JetListView.
///
internal class IncrementalSearcher
{
private JetListViewNodeCollection _nodeCollection;
private RowListRenderer _rowListRenderer;
private IRowRenderer _rowRenderer;
private SelectionModel _selection;
private string _incSearchBuffer = "";
private bool _incSearching;
public IncrementalSearcher( JetListViewNodeCollection nodeCollection,
RowListRenderer rowListRenderer, SelectionModel selection )
{
_nodeCollection = nodeCollection;
_rowListRenderer = rowListRenderer;
SelectionModel = selection;
}
public IRowRenderer RowRenderer
{
get { return _rowRenderer; }
set { _rowRenderer = value; }
}
public SelectionModel SelectionModel
{
get { return _selection; }
set
{
if ( _selection != null )
{
_selection.FocusStateChanged -= new ViewNodeStateChangeEventHandler( HandleFocusStateChanged );
}
_selection = value;
_selection.FocusStateChanged += new ViewNodeStateChangeEventHandler( HandleFocusStateChanged );
}
}
public bool IncrementalSearch( string text )
{
if ( _nodeCollection.Nodes.Count == 0 )
{
return false;
}
JetListViewNode startNode = _selection.ActiveNode;
if ( startNode == null )
{
startNode = _nodeCollection.Nodes [0];
}
lock( _nodeCollection )
{
if ( SearchEnumerator( text, _nodeCollection.EnumerateVisibleNodesForward( startNode ), null ) )
{
return true;
}
if ( startNode != _nodeCollection.Nodes [0] )
{
return SearchEnumerator( text,
_nodeCollection.EnumerateVisibleNodesForward( _nodeCollection.Nodes [0] ), startNode );
}
}
return false;
}
private bool SearchEnumerator( string text, IEnumerator searchEnumerator,
JetListViewNode stopNode )
{
while( searchEnumerator.MoveNext() )
{
JetListViewNode curNode = (JetListViewNode) searchEnumerator.Current;
if ( curNode == stopNode )
{
return false;
}
if ( _rowRenderer.MatchIncrementalSearch( curNode, text ) )
{
_incSearching = true;
_rowRenderer.SearchHighlightText = text;
_nodeCollection.ExpandParents( curNode );
_rowListRenderer.InvalidateRow( curNode );
_selection.SelectAndFocusNode( curNode );
_incSearching = false;
return true;
}
}
return false;
}
public void ClearIncrementalSearch()
{
_incSearchBuffer = "";
if ( _rowRenderer != null && _rowRenderer.SearchHighlightText != null )
{
_rowRenderer.SearchHighlightText = null;
if ( _selection.ActiveNode != null )
{
_rowListRenderer.InvalidateRow( _selection.ActiveNode );
}
}
}
public bool IncrementalSearchNext( string text, MoveDirection dir )
{
JetListViewNode curNode = _selection.ActiveNode;
IEnumerator enumerator = (dir == MoveDirection.Down )
? _nodeCollection.EnumerateNodesForward( curNode )
: _nodeCollection.EnumerateNodesBackward( curNode );
enumerator.MoveNext();
if ( SearchEnumerator( text, enumerator, null ) )
{
return true;
}
JetListViewNode startNode = (dir == MoveDirection.Down)
? _nodeCollection.Nodes [0]
: _nodeCollection.LastNode;
if ( curNode == startNode )
{
return false;
}
enumerator = _nodeCollection.GetDirectionalEnumerator( startNode, dir );
return SearchEnumerator( text, enumerator, curNode );
}
public bool HandleKeyDown( Keys keyData )
{
if ( keyData == Keys.Space && _incSearchBuffer.Length > 0 )
{
return true; // Space should not toggle selection if we're in inc. search
}
else if ( keyData == Keys.Escape && _incSearchBuffer.Length > 0 )
{
ClearIncrementalSearch();
}
else if ( ( keyData == Keys.F3 || keyData == ( Keys.Shift | Keys.F3 ) ) &&
_incSearchBuffer.Length > 0 )
{
if ( !IncrementalSearchNext( _incSearchBuffer,
(keyData == Keys.F3) ? MoveDirection.Down : MoveDirection.Up ) )
{
Win32Declarations.MessageBeep( -1 );
}
}
else if ( keyData == Keys.Back && _incSearchBuffer.Length > 0 )
{
if ( _incSearchBuffer.Length > 1 )
{
_incSearchBuffer = _incSearchBuffer.Substring( 0, _incSearchBuffer.Length - 1 );
IncrementalSearch( _incSearchBuffer );
}
else
{
ClearIncrementalSearch();
}
}
else
{
return false;
}
return true;
}
public void HandleKeyPress( char keyChar )
{
if ( Char.IsLetterOrDigit( keyChar ) || Char.IsPunctuation( keyChar ) ||
( _incSearchBuffer.Length > 0 && Char.IsWhiteSpace( keyChar ) ) )
{
if ( IncrementalSearch( _incSearchBuffer + keyChar ) )
{
_incSearchBuffer = _incSearchBuffer + keyChar;
}
else
{
Win32Declarations.MessageBeep( -1 );
}
}
}
private void HandleFocusStateChanged( object sender, ViewNodeStateChangeEventArgs e )
{
if ( !_incSearching )
{
ClearIncrementalSearch();
}
}
}
}