Implement incremental search in wxGenericListCtrl.

Mostly copy wxGenericTreeCtrl incremental search implementation to
wxGenericListCtrl (unfortunately there is no simple way to reuse this code
currently), including the recently added EnableBellOnNoMatch() method.

Update the sample to test it, the key event handling in it had to be modified
to allow it.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@72639 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2012-10-07 22:42:27 +00:00
parent 27bc919446
commit d34d31f6d6
8 changed files with 237 additions and 22 deletions

View File

@@ -1371,6 +1371,15 @@ void wxListRenameTimer::Notify()
m_owner->OnRenameTimer();
}
//-----------------------------------------------------------------------------
// wxListFindTimer (internal)
//-----------------------------------------------------------------------------
void wxListFindTimer::Notify()
{
m_owner->OnFindTimer();
}
//-----------------------------------------------------------------------------
// wxListTextCtrlWrapper (internal)
//-----------------------------------------------------------------------------
@@ -1563,6 +1572,8 @@ void wxListMainWindow::Init()
m_lastOnSame = false;
m_renameTimer = new wxListRenameTimer( this );
m_findTimer = NULL;
m_findBell = 0; // default is to not ring bell at all
m_textctrlWrapper = NULL;
m_current =
@@ -1625,6 +1636,7 @@ wxListMainWindow::~wxListMainWindow()
delete m_highlightBrush;
delete m_highlightUnfocusedBrush;
delete m_renameTimer;
delete m_findTimer;
}
void wxListMainWindow::SetReportView(bool inReportView)
@@ -2288,6 +2300,18 @@ void wxListMainWindow::OnRenameCancelled(size_t itemEdit)
GetEventHandler()->ProcessEvent( le );
}
void wxListMainWindow::OnFindTimer()
{
m_findPrefix.clear();
if ( m_findBell )
m_findBell = 1;
}
void wxListMainWindow::EnableBellOnNoMatch( bool on )
{
m_findBell = on;
}
void wxListMainWindow::OnMouse( wxMouseEvent &event )
{
#ifdef __WXMAC__
@@ -2801,7 +2825,8 @@ void wxListMainWindow::OnChar( wxKeyEvent &event )
event.m_keyCode = WXK_RIGHT;
}
switch ( event.GetKeyCode() )
int keyCode = event.GetKeyCode();
switch ( keyCode )
{
case WXK_UP:
if ( m_current > 0 )
@@ -2899,7 +2924,79 @@ void wxListMainWindow::OnChar( wxKeyEvent &event )
break;
default:
event.Skip();
if ( !event.HasModifiers() &&
((keyCode >= '0' && keyCode <= '9') ||
(keyCode >= 'a' && keyCode <= 'z') ||
(keyCode >= 'A' && keyCode <= 'Z') ||
(keyCode == '_') ||
(keyCode == '+') ||
(keyCode == '*') ||
(keyCode == '-')))
{
// find the next item starting with the given prefix
wxChar ch = (wxChar)keyCode;
size_t item;
// if the same character is typed multiple times then go to the
// next entry starting with that character instead of searching
// for an item starting with multiple copies of this character,
// this is more useful and is how it works under Windows.
if ( m_findPrefix.length() == 1 && m_findPrefix[0] == ch )
{
item = PrefixFindItem(m_current, ch);
}
else
{
const wxString newPrefix(m_findPrefix + ch);
item = PrefixFindItem(m_current, newPrefix);
if ( item != (size_t)-1 )
m_findPrefix = newPrefix;
}
// also start the timer to reset the current prefix if the user
// doesn't press any more alnum keys soon -- we wouldn't want
// to use this prefix for a new item search
if ( !m_findTimer )
{
m_findTimer = new wxListFindTimer( this );
}
// Notice that we should start the timer even if we didn't find
// anything to make sure we reset the search state later.
m_findTimer->Start(wxListFindTimer::DELAY, wxTIMER_ONE_SHOT);
// restart timer even when there's no match so bell get's reset
if ( item != (size_t)-1 )
{
// Select the found item and go to it.
HighlightAll(false);
SetItemState(item,
wxLIST_STATE_FOCUSED | wxLIST_STATE_SELECTED,
wxLIST_STATE_FOCUSED | wxLIST_STATE_SELECTED);
// Reset the bell flag if it had been temporarily disabled
// before.
if ( m_findBell )
m_findBell = 1;
}
else // No such item
{
// Signal it with a bell if enabled.
if ( m_findBell == 1 )
{
::wxBell();
// Disable it for the next unsuccessful match, we only
// beep once, this is usually enough and continuing to
// do it would be annoying.
m_findBell = -1;
}
}
}
else
{
event.Skip();
}
}
}
@@ -4321,6 +4418,61 @@ void wxListMainWindow::GetVisibleLinesRange(size_t *from, size_t *to)
*to = m_lineTo;
}
size_t
wxListMainWindow::PrefixFindItem(size_t idParent,
const wxString& prefixOrig) const
{
// if no items then just return
if ( idParent == (size_t)-1 )
return idParent;
// match is case insensitive as this is more convenient to the user: having
// to press Shift-letter to go to the item starting with a capital letter
// would be too bothersome
wxString prefix = prefixOrig.Lower();
// determine the starting point: we shouldn't take the current item (this
// allows to switch between two items starting with the same letter just by
// pressing it) but we shouldn't jump to the next one if the user is
// continuing to type as otherwise he might easily skip the item he wanted
size_t itemid = idParent;
if ( prefix.length() == 1 )
{
itemid += 1;
}
// look for the item starting with the given prefix after it
while ( ( itemid < (size_t)GetItemCount() ) &&
!GetLine(itemid)->GetText(0).Lower().StartsWith(prefix) )
{
itemid += 1;
}
// if we haven't found anything...
if ( !( itemid < (size_t)GetItemCount() ) )
{
// ... wrap to the beginning
itemid = 0;
// and try all the items (stop when we get to the one we started from)
while ( ( itemid < (size_t)GetItemCount() ) && itemid != idParent &&
!GetLine(itemid)->GetText(0).Lower().StartsWith(prefix) )
{
itemid += 1;
}
// If we haven't found the item, id will be (size_t)-1, as per
// documentation
if ( !( itemid < (size_t)GetItemCount() ) ||
( ( itemid == idParent ) &&
!GetLine(itemid)->GetText(0).Lower().StartsWith(prefix) ) )
{
itemid = (size_t)-1;
}
}
return itemid;
}
// -------------------------------------------------------------------------------------
// wxGenericListCtrl
// -------------------------------------------------------------------------------------
@@ -5280,6 +5432,11 @@ void wxGenericListCtrl::RefreshItems(long itemFrom, long itemTo)
m_mainWin->RefreshLines(itemFrom, itemTo);
}
void wxGenericListCtrl::EnableBellOnNoMatch( bool on )
{
m_mainWin->EnableBellOnNoMatch(on);
}
// Generic wxListCtrl is more or less a container for two other
// windows which drawings are done upon. These are namely
// 'm_headerWin' and 'm_mainWin'.