feat(gui): port CFriendListCtrl to CMuleVirtualDataViewCtrl (#180, #801) - #830
Conversation
…g#180, amule-org#801) Continues the wxListCtrl -> wxDataViewCtrl migration (amule-org#180/amule-org#801) onto the shared base PR amule-org#811 extracted after the Servers port (amule-org#807, now absorbed into amule-org#811). CFriendListCtrl was picked next after reading all the remaining candidates directly rather than going by line count alone: it has no CBarShader rendering (unlike Downloads/SharedFiles/ Sources-Peers, which additionally need a still-nonexistent wxDataViewCustomRenderer), it's already pointer-identity addressed (UpdateFriend(CFriend*)/RemoveFriend(CFriend*) map directly onto AddItemData/RefreshItemData/RemoveItemData), and its blast radius is tiny (ChatWnd.cpp, muuli_wdr.cpp construction only). CFileDetailListCtrl looked smaller by line count but its caller (FileDetailDialog.cpp) drives it with raw position-indexed CRUD (FindItem by name, SetItem by column index, DeleteItem) plus a pre-existing duplicate-type quirk (two unrelated SourcenameItem structs relying on compatible layout) -- porting it cleanly means refactoring the caller too, which is a separate, more invasive piece of work than this one. CServerListCtrl (current, post-amule-org#811) is the template mirrored here: same AppendTextColumn/AppendSpacerColumn/AssociateVirtualModel/ LoadColumnSettings/InitColumnState ctor sequence, same GetItemColumnText/ GetItemAttr/CompareItemData/OnListKey hook shape. Public API (UpdateFriend, RemoveFriend) and the constructor signature are unchanged, so ChatWnd.cpp and muuli_wdr.cpp needed no edits. Notable deltas from the pre-port behaviour: added a real CompareItemData so header-click sort now works (the old list never called SetSortFunc at all); GetItemAttr replaces the old SetItemTextColour call with the same visible result (blue for linked friends, default text colour otherwise). Verified: builds clean; clang-format v18 (pinned Docker image) applied; clang-tidy Tier-1 (whole-tree) and Tier-2 (changed-lines, .clang-tidy-new-code) both clean via the ~/aMuleTest/ci-local replica -- Tier-2 caught one real modernize-use-nullptr hit, fixed. Grepped ChatWnd.cpp/.h and muuli_wdr.cpp to confirm no other call sites exist. Interactive verification (sort, right-click menu states, Delete-key removal, chat-session activation, VoiceOver) left for manual testing per project convention, same as PR amule-org#796/amule-org#807.
|
Verified locally against 1.
So Fix: void CFriendListCtrl::OnItemActivated(wxDataViewEvent &event)
{
// Open a session with the activated row alone, whatever else was selected.
if (event.GetItem().IsOk()) {
UnselectAll();
Select(event.GetItem());
}
const std::vector<wxUIntPtr> selected = GetSelectedItemData();
if (selected.empty()) {
return;
}
theApp->amuledlg->m_chatwnd->StartSession(reinterpret_cast<CFriend *>(selected.front()));
}2. The comment says the refresh is "a repaint (plus a re-sort if the name changed under a name-sorted list)", but Fix: the name is the only sortable column here, so 3. Nit: One behavioural note for the interactive pass: right-clicking empty space used to get |
got3nks's review on amule-org#830 found a real crash: OnItemActivated() cast event.GetItem()'s ID directly to CFriend* on the assumption it was the item's data pointer, but CMuleVirtualDataViewCtrl's row-addressed model returns the row index (+1) as that ID -- the "item identity is not row identity" case MuleVirtualDataViewCtrl.h itself documents. Every double-click/Enter on a friend dereferenced a bogus pointer. Fixed by selecting the activated row and resolving it through GetSelectedItemData(), matching CServerListCtrl::OnItemActivated. Also from the same review: IsLiveSortColumn() now returns true, since the name (the only sortable column) can change after a friend is already listed and the UpdateFriend() comment claimed a re-sort that the base's default-false hook never actually triggered; and dropped a no-op static_cast<int>() around a call that already returns int. Verified: builds clean, clang-format v18 applied, clang-tidy Tier-2 (changed lines, .clang-tidy-new-code) clean via the local CI replica.
The previous run hit a GitHub Actions infrastructure outage (job not acquired by any runner, "Failed to resolve action download info" / "Service Unavailable" on clang-format, Translation checks, mingw-w64 Debug and clang-tidy Tier-1) unrelated to this branch's code -- every job that did run passed. No admin rights to rerun the failed jobs directly, so retriggering with an empty commit instead.
|
Thanks @LSalami - all three review points addressed cleanly, and the double-click fix is exactly right. Verified locally: builds clean with no warnings, and I checked the sort against the base specifically, since #832 landed after this branch was cut. That fix is entirely base-level, and this port inherits it correctly - the ctor sequence matches Merging. |
…#801) (#839) * feat(gui): port CFileDetailListCtrl to CMuleVirtualDataViewCtrl (#180, #801) Continues the wxListCtrl -> wxDataViewCtrl migration (#180/#801) onto the shared base from #811, after Search (#796), Servers (#807/#811) and Friends (#830). CFileDetailListCtrl was next because it has no CBarShader rendering (unlike Downloads/SharedFiles/Sources-Peers, which additionally need a still-nonexistent wxDataViewCustomRenderer). Its caller, CFileDetailDialog::FillSourcenameList(), drove the old list with raw position-indexed CRUD (FindItem by name, SetItemPtrData, SetItem by column index, DeleteItem) rather than the pointer-identity style CServerListCtrl/CFriendListCtrl already use, so porting the control cleanly meant refactoring the caller too: - CFileDetailDialog gained a std::map<wxString, SourcenameItem *> m_sourcenames member, replacing "search the list widget by name" with a map lookup. FillSourcenameList()'s reset/update/prune shape is otherwise unchanged, just re-keyed to the map and driven through the control's new AddSource/RefreshSource/RemoveSource API. - OnBnClickedTakeOver()/OnListClickedTakeOver() resolve the selected row through GetSelectedItemData() (inherited from CMuleVirtualDataViewCtrl) instead of GetNextItem+GetItemText. - The dialog's EVT_LIST_ITEM_ACTIVATED binding on IDC_LISTCTRLFILENAMES becomes EVT_DATAVIEW_ITEM_ACTIVATED; wxDataViewEvent is a wxNotifyEvent/wxCommandEvent descendant so it still propagates from the child control to the dialog-level handler the same way. - Fixed a latent leak: nothing in ~CFileDetailDialog() freed the SourcenameItem objects still referenced by open rows -- only the "not a partfile" and "pruned to zero" paths in FillSourcenameList() ever deleted them. Now freed in the destructor via m_sourcenames. CMuleDataViewCtrl always ORs in wxDV_MULTIPLE (no single-selection mode exists on the shared base), but this list's "take over filename" actions assume exactly one selection, same as the old list did (it never actually requested wxLC_SINGLE_SEL either -- checked muuli_wdr.cpp -- it enforced single-selection itself via OnSelect() deselecting every other row). CFileDetailListCtrl::OnSelectionChanged() does the equivalent: collapses to the just-clicked row whenever more than one ends up selected. Also deleted a vestigial nested SourcenameItem struct in FileDetailListCtrl.h that duplicated (by accident of matching layout) the real one in PartFile.h, and dropped a per-row background-colour set that reproduced the default and carried its own "do we still need this?" comment. Verified: builds clean; clang-format v18 (pinned Docker image) applied; clang-tidy Tier-1 (whole-tree) and Tier-2 (changed-lines, .clang-tidy-new-code) both clean via the ~/aMuleTest/ci-local replica. Grepped for other CFileDetailListCtrl/IDC_LISTCTRLFILENAMES references to confirm muuli_wdr.cpp's construction call needed no changes. Interactive verification (source list populate/re-tally, take-over via button and double-click, single-selection enforcement, sort, VoiceOver) left for manual testing per project convention. * fix(gui): keep the source-name list sorted, and drop rows before freeing them Review follow-up to the port. FillSourcenameList() zeroes every count and then rewrites them in place, so while it runs the list is not ordered by the column it is sorted on -- and AddSource() places a new row with a binary search, which needs that ordering to hold. An insertion therefore leaves rows in arbitrary positions, and the repair has to happen here, exactly as the pre-port code did. Only on insertion, though. A count that merely changed is what the live-sort preference governs: RefreshSource() re-sorts when it is on, and when it is off the row is meant to stay put rather than move under the user. Sorting unconditionally would quietly override that setting for this list. The destructor and the not-a-partfile path also freed the SourcenameItem objects while the list control still held pointers to them. Nothing can paint or sort in either window today -- both dialog call sites are stack temporaries, so destruction is synchronous -- but that rests on wx's teardown order rather than on anything guaranteed, and the base states the rule plainly: it has to be told before the caller frees the item data. Both now clear the rows first, as the prune loop already did. * fix(gui): decide the source list's live re-sort per column IsLiveSortColumn() answered true for every column, so a refresh tick scheduled a re-sort even when the list was sorted by File Name -- a value that never changes, since the name is the key each row was created under. Answer per column instead, the shape CServerListCtrl already uses, so only a sources-sorted list re-sorts on its own. The header comment already described it this way; only the implementation did not. * chore: drop a duplicated paragraph from the file header FileDetailDialog.cpp carried the "Any parts of this program derived from the xMule, lMule or eMule project" paragraph twice. It is the only file in src/ that does, and the file is already being touched here. --------- Co-authored-by: got3nks <[email protected]>
Context
Continues #180/#801's
wxListCtrl->wxDataViewCtrlmigration, on top of the shared baseCMuleDataViewCtrl/CMuleVirtualDataViewCtrlfrom #811. Search (#796) and Servers (#807, absorbed into #811) are done; this portsCFriendListCtrl.Picked after reading all the remaining candidates (Friends, FileDetail, Downloads, SharedFiles, Sources/Peers) directly rather than by line count:
CBarShaderrendering — unlike Downloads/SharedFiles/Sources-Peers, which additionally need awxDataViewCustomRendererthat doesn't exist anywhere in the tree yet (confirmed by grep), so those are correctly a separate, dedicated piece of work.UpdateFriend(CFriend*)/RemoveFriend(CFriend*)map directly ontoAddItemData/RefreshItemData/RemoveItemData, the exact shapeCServerListCtrlalready uses.ChatWnd.cpp(2 call sites) andmuuli_wdr.cpp(construction) reference the class externally.CFileDetailListCtrllooked smaller by line count but its caller (FileDetailDialog.cpp) drives it with raw position-indexed CRUD (FindItemby name,SetItemby column index,DeleteItem) plus a pre-existing duplicate-type quirk (two unrelatedSourcenameItemstructs relying on compatible memory layout) — porting it cleanly means refactoring the caller too, which felt like its own separate pass rather than "the small one to bundle in."What changed
src/ServerListCtrl.h/.cpp(current, post-#811) is the template mirrored here: sameAppendTextColumn/AppendSpacerColumn/AssociateVirtualModel/LoadColumnSettings/InitColumnStatector sequence, sameGetItemColumnText/GetItemAttr/CompareItemData/OnListKeyhook shape, sameEVT_DATAVIEW_ITEM_CONTEXT_MENU/EVT_DATAVIEW_ITEM_ACTIVATEDevent handling usingGetSelectedItemData().Public API (
UpdateFriend,RemoveFriend) and the constructor signature are unchanged, soChatWnd.cppandmuuli_wdr.cppneeded no edits at all.Two small behavioural deltas, both flagged in the commit message:
CompareItemDataso header-click sort now actually works — the old list never calledSetSortFuncat all.GetItemAttrreplaces the oldSetItemTextColourcall with the same visible result (blue for linked friends, default text colour otherwise).Verification
clang-formatv18 (pinned Docker image) applied..clang-tidy-new-code) both clean via a local CI replica — Tier-2 caught one realmodernize-use-nullptrhit, fixed.ChatWnd.cpp/.handmuuli_wdr.cppto confirm no other call sites exist.