+ return true;
+ }
+
+ // else translate it into wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK event
+ LV_HITTESTINFO lvhti;
+ wxZeroMemory(lvhti);
+
+#if defined(__WXWINCE__) && !defined(__HANDHELDPC__) && _WIN32_WCE < 400
+ if ( nmhdr->code == GN_CONTEXTMENU )
+ {
+ lvhti.pt = ((NMRGINFO*)nmhdr)->ptAction;
+ }
+ else
+#endif //__WXWINCE__
+ {
+ ::GetCursorPos(&(lvhti.pt));
+ }
+
+ ::ScreenToClient(GetHwnd(), &lvhti.pt);
+ if ( ListView_HitTest(GetHwnd(), &lvhti) != -1 )
+ {
+ if ( lvhti.flags & LVHT_ONITEM )
+ {
+ eventType = wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK;
+ event.m_itemIndex = lvhti.iItem;
+ event.m_pointDrag.x = lvhti.pt.x;
+ event.m_pointDrag.y = lvhti.pt.y;
+ }
+ }
+ break;
+
+#ifdef NM_CUSTOMDRAW
+ case NM_CUSTOMDRAW:
+ *result = OnCustomDraw(lParam);
+
+ return *result != CDRF_DODEFAULT;
+#endif // _WIN32_IE >= 0x300
+
+ case LVN_ODCACHEHINT:
+ {
+ const NM_CACHEHINT *cacheHint = (NM_CACHEHINT *)lParam;
+
+ eventType = wxEVT_COMMAND_LIST_CACHE_HINT;
+
+ // we get some really stupid cache hints like ones for
+ // items in range 0..0 for an empty control or, after
+ // deleting an item, for items in invalid range -- filter
+ // this garbage out
+ if ( cacheHint->iFrom > cacheHint->iTo )
+ return false;
+
+ event.m_oldItemIndex = cacheHint->iFrom;
+
+ const long iMax = GetItemCount();
+ event.m_itemIndex = cacheHint->iTo < iMax ? cacheHint->iTo
+ : iMax - 1;
+ }
+ break;
+
+#ifdef HAVE_NMLVFINDITEM
+ case LVN_ODFINDITEM:
+ // Find an item in a (necessarily virtual) list control.
+ if ( IsVirtual() )
+ {
+ NMLVFINDITEM* pFindInfo = (NMLVFINDITEM*)lParam;
+
+ // no match by default
+ *result = -1;
+
+ // we only handle string-based searches here
+ //
+ // TODO: what about LVFI_PARTIAL, should we handle this?
+ if ( !(pFindInfo->lvfi.flags & LVFI_STRING) )
+ {
+ return false;
+ }
+
+ const wxChar * const searchstr = pFindInfo->lvfi.psz;
+ const size_t len = wxStrlen(searchstr);
+
+ // this is the first item we should examine, search from it
+ // wrapping if necessary
+ int startPos = pFindInfo->iStart;
+ const int maxPos = GetItemCount();
+
+ // Check that the index is valid to ensure that our loop
+ // below always terminates.
+ if ( startPos < 0 || startPos >= maxPos )
+ {
+ // When the last item in the control is selected,
+ // iStart is really set to (invalid) maxPos index so
+ // accept this silently.
+ if ( startPos != maxPos )
+ {
+ wxLogDebug(wxT("Ignoring invalid search start ")
+ wxT("position %d in list control with ")
+ wxT("%d items."), startPos, maxPos);
+ }
+
+ startPos = 0;
+ }
+
+ // Linear search in a control with a lot of items can take
+ // a long time so we limit the total time of the search to
+ // ensure that the program doesn't appear to hang.
+#if wxUSE_STOPWATCH
+ wxStopWatch sw;
+#endif // wxUSE_STOPWATCH
+ for ( int currentPos = startPos; ; )
+ {
+ // does this item begin with searchstr?
+ if ( wxStrnicmp(searchstr,
+ GetItemText(currentPos), len) == 0 )
+ {
+ *result = currentPos;
+ break;
+ }
+
+ // Go to next item with wrapping if necessary.
+ if ( ++currentPos == maxPos )
+ {
+ // Surprisingly, LVFI_WRAP seems to be never set in
+ // the flags so wrap regardless of it.
+ currentPos = 0;
+ }
+
+ if ( currentPos == startPos )
+ {
+ // We examined all items without finding anything.
+ //
+ // Notice that we still return true as we did
+ // perform the search, if we didn't do this the
+ // message would have been considered unhandled and
+ // the control seems to always select the first
+ // item by default in this case.
+ return true;
+ }
+
+#if wxUSE_STOPWATCH
+ // Check the time elapsed only every thousand
+ // iterations for performance reasons: if we did it
+ // more often calling wxStopWatch::Time() could take
+ // noticeable time on its own.
+ if ( !((currentPos - startPos)%1000) )
+ {
+ // We use half a second to limit the search time
+ // which is about as long as we can take without
+ // annoying the user.
+ if ( sw.Time() > 500 )
+ {
+ // As above, return true to prevent the control
+ // from selecting the first item by default.
+ return true;
+ }
+ }
+#endif // wxUSE_STOPWATCH
+
+ }
+
+ SetItemState(*result,
+ wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED,
+ wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
+ EnsureVisible(*result);
+ return true;
+ }
+ else
+ {
+ processed = false;
+ }
+ break;
+#endif // HAVE_NMLVFINDITEM
+
+ case LVN_GETDISPINFO:
+ if ( IsVirtual() )
+ {
+ LV_DISPINFO *info = (LV_DISPINFO *)lParam;
+
+ LV_ITEM& lvi = info->item;
+ long item = lvi.iItem;
+
+ if ( lvi.mask & LVIF_TEXT )
+ {
+ wxString text = OnGetItemText(item, lvi.iSubItem);
+ wxStrlcpy(lvi.pszText, text.c_str(), lvi.cchTextMax);
+ }
+
+ // see comment at the end of wxListCtrl::GetColumn()
+#ifdef NM_CUSTOMDRAW
+ if ( lvi.mask & LVIF_IMAGE )
+ {
+ lvi.iImage = OnGetItemColumnImage(item, lvi.iSubItem);
+ }
+#endif // NM_CUSTOMDRAW
+
+ // even though we never use LVM_SETCALLBACKMASK, we still
+ // can get messages with LVIF_STATE in lvi.mask under Vista
+ if ( lvi.mask & LVIF_STATE )
+ {
+ // we don't have anything to return from here...
+ lvi.stateMask = 0;
+ }
+
+ return true;