X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/524a2c6e51b2e14758ee9dcd51fc3922198b5d13..07aaf32633ecf18ec3edfbb41793a112914792d0:/src/generic/listctrl.cpp diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp index e8e6b26b34..b311e031ef 100644 --- a/src/generic/listctrl.cpp +++ b/src/generic/listctrl.cpp @@ -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) @@ -2226,19 +2238,10 @@ wxTextCtrl *wxListMainWindow::EditLabel(long item, wxClassInfo* textControlClass return NULL; } - // We have to call this here because the label in question might just have - // been added and no screen update taken place. if ( m_dirty ) { - // TODO: use wxTheApp->SafeYieldFor(NULL, wxEVT_CATEGORY_UI) instead - // so that no pending events may change the item count (see below) - // IMPORTANT: needs to be tested! - wxSafeYield(); - - // Pending events dispatched by wxSafeYield might have changed the item - // count - if ( (size_t)item >= GetItemCount() ) - return NULL; + // Ensure the display is updated before we start editing. + Update(); } wxTextCtrl * const text = (wxTextCtrl *)textControlClass->CreateObject(); @@ -2288,6 +2291,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__ @@ -2300,7 +2315,10 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) #endif // __WXMAC__ if ( event.LeftDown() ) - SetFocus(); + { + // Ensure we skip the event to let the system set focus to this window. + event.Skip(); + } // Pretend that the event happened in wxListCtrl itself. wxMouseEvent me(event); @@ -2467,9 +2485,10 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) m_renameTimer->Start(dclick > 0 ? dclick : 250, true); } } + + m_lastOnSame = false; } - m_lastOnSame = false; m_lineSelectSingleOnUp = (size_t)-1; } else @@ -2561,8 +2580,16 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) if (m_current != oldCurrent) RefreshLine( oldCurrent ); - // forceClick is only set if the previous click was on another item - m_lastOnSame = !forceClick && (m_current == oldCurrent) && oldWasSelected; + // Set the flag telling us whether the next click on this item should + // start editing its label. This should happen if we clicked on the + // current item and it was already selected, i.e. if this click was not + // done to select it. + // + // It should not happen if this was a double click (forceClick is true) + // nor if we hadn't had the focus before as then this click was used to + // give focus to the control. + m_lastOnSame = (m_current == oldCurrent) && oldWasSelected && + !forceClick && HasFocus(); } } @@ -2789,7 +2816,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 ) @@ -2887,7 +2915,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(); + } } } @@ -4309,6 +4409,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 // ------------------------------------------------------------------------------------- @@ -4457,13 +4612,14 @@ void wxGenericListCtrl::OnScroll(wxScrollWinEvent& event) // the window the next time m_mainWin->ResetVisibleLinesRange(); - HandleOnScroll( event ); - if ( event.GetOrientation() == wxHORIZONTAL && HasHeader() ) { m_headerWin->Refresh(); m_headerWin->Update(); } + + // Let the window be scrolled as usual by the default handler. + event.Skip(); } void wxGenericListCtrl::SetSingleStyle( long style, bool add ) @@ -5241,16 +5397,6 @@ int wxGenericListCtrl::OnGetItemColumnImage(long item, long column) const return -1; } -wxListItemAttr * -wxGenericListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item)) const -{ - wxASSERT_MSG( item >= 0 && item < GetItemCount(), - wxT("invalid item index in OnGetItemAttr()") ); - - // no attributes by default - return NULL; -} - void wxGenericListCtrl::SetItemCount(long count) { wxASSERT_MSG( IsVirtual(), wxT("this is for virtual controls only") ); @@ -5268,6 +5414,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'.