ADD: CSV/TSV Table Grid Lister Plugin with Inline Find & Replace - #37
Open
pplupo wants to merge 236 commits into
Open
ADD: CSV/TSV Table Grid Lister Plugin with Inline Find & Replace#37pplupo wants to merge 236 commits into
pplupo wants to merge 236 commits into
Conversation
This commit introduces the mpv_wayland WLX (Lister) plugin for Double Commander. It enables native video playback in the Quick View panel using the libmpv Render API and QOpenGLWidget. It is specifically designed for seamless integration on Wayland and HiDPI displays. Committed files: - Source code (src/) implementing Qt6/mpv integration - SDK headers (sdk/) for plugin interface - CMakeLists.txt for build configuration - README.md with installation instructions and embedded screenshot - mpv_wayland.png screenshot asset - Integration into root build.sh for automated release packaging
This commit introduces the MDK WLX plugin, a high-performance media viewer powered by the MDK SDK and pure Qt6. It allows instant preview of video and audio files. A key feature is its out-of-process isolation via dlopen, ensuring that MDK's dependencies do not conflict with Double Commander. Committed files: - C++ source (plugin.cpp) and Pascal wrappers (mdk.pas, etc.) - Lazarus project files (.lpi, .lpr) - Makefile for building the C++ shared object - SDK headers (sdk/) - README.md and proposal.md documentation - Integration into root build.sh for automated release packaging
This commit introduces a specialized log viewer WLX plugin built with Qt6 and C++20. It is designed to handle massive log files without freezing Double Commander, utilizing zero-copy file loading (mmap), fast regex searching (RE2), and a robust focus-isolation architecture for Wayland. Committed files: - Source code (src/) for the log model and viewer widget - CMakeLists.txt for build configuration - README.md and detailed design doc (double commander wlx log viewer.md) - logviewer.png screenshot asset - Integration into root build.sh for automated release packaging
This commit introduces the kpart WLX plugin. It acts as a host for KDE KParts, effectively allowing Double Commander to leverage any installed KDE viewer (like Okular for PDFs or LibreOffice for docs) directly within the Quick View panel natively on Wayland/Qt6. Committed files: - Source code (src/) for KPart hosting logic - SDK headers (sdk/) - CMakeLists.txt for build configuration - README.md with screenshots - test.svg and screenshot assets (kpart_md.png, kpart_svg.png) - Integration into root build.sh for automated release packaging
…ete row editing, TSV support, and context menu - Display CSV/TSV files in an interactive QTableWidget grid - Auto-detect separator (comma, semicolon, tab); fall back to file extension - Header Row toggle button: interprets first line as header or data row, reloads file on toggle; controls whether copies include the header line - Ctrl+C: copy selection as TSV (includes header when Header Row is on) - Right-click context menu: Copy as TSV, Copy as CSV, Delete Selected Rows, Insert from Clipboard - Ctrl+V: insert clipboard rows at selected position; validates column count; skips clipboard header line when it matches the current header (Header Row on) - Delete: remove selected rows - Ctrl+S: save file; correctly handles editing vs non-editing state without disturbing Double Commander focus - Inline cell editing with Save / Save As / Reload toolbar actions - Enca encoding auto-detection with Glib conversion fallback - Double-quoted field parsing per CSV RFC - F7 search support - Full README with screenshots, feature docs, and configuration reference - Attribution to original author j2969719
…nd highlighting - Export ListSetDefaultParams to retrieve and bind the host's INI file path. - Add HighlightRule structure and fast RE2-based line matching directly on memory-mapped offsets. - Create Highlighting Rules SettingsDialog modal with an inline-colored rules list. - Enable ExtendedSelection on the rules list to support deleting or moving multiple rules up/down, maintaining selection state using QItemSelectionModel. - Connect double-click on any rule row to open the editing window. - Write Foreground/Background labels above color picker buttons in RuleDialog. - Implement session persistence under [HighlightRules] in the INI file. - Prevent default rules from overriding empty rule configurations on restart. - Add context-aware "Add Default Rules" button to prepend default log levels relative to the current selection. - Create sample.log matching each level for diagnostics.
This commit introduces a premium editor WLX plugin based on Native Qt6 and KDE's KTextEditor framework. It brings full syntax highlighting, code folding, and advanced editing capabilities to Double Commander's viewer panel without LCL compatibility crashes on Wayland. Committed files: - Source code (src/) wrapping KTextEditor - CMakeLists.txt for build configuration - README.md with screenshots - defects.md tracking known issues and resolutions - Screenshot assets (kate_java.png, kate_md.png, kate_py.png) - Integration into root build.sh for automated release packaging
…yles, preserve selection, and fix Proper/Title Case logic
…nd highlighting - Export ListSetDefaultParams to retrieve and bind the host's INI file path. - Add HighlightRule structure and fast RE2-based line matching directly on memory-mapped offsets. - Create Highlighting Rules SettingsDialog modal with an inline-colored rules list. - Enable ExtendedSelection on the rules list to support deleting or moving multiple rules up/down, maintaining selection state using QItemSelectionModel. - Connect double-click on any rule row to open the editing window. - Write Foreground/Background labels above color picker buttons in RuleDialog. - Implement session persistence under [HighlightRules] in the INI file. - Prevent default rules from overriding empty rule configurations on restart. - Add context-aware "Add Default Rules" button to prepend default log levels relative to the current selection. - Create sample.log matching each level for diagnostics.
Manually merged unique changes from all editor-related branches: - editor-features: focus management (NoFocus on menuBar, focus restoration, focus-stealing prevention), Save/Save As/Save Copy As actions with toolbar button, Print action with toolbar button, font zoom controls (Ctrl++/Ctrl+-/ Ctrl+0) with native KTE action fallback, Force RTL Direction toggle, Ctrl+Shift+S Save As shortcut precedence fix, QTimer-based focus restoration - kate-case-conversion: Capitalization submenu replacing flat menu items, improved Title Case with minor-word handling, fixed Proper Case (toLower instead of preserve), renamed snail_case to snake_case, added PascalCase, SCREAMING_SNAKE_CASE, kebab-case, Sentence case, SCREAMING-KEBAB-CASE, dot.case, path/case, replaceSelectionPreservingRange helper to restore selection after text replacement - fix-redo-and-write-lock: Ctrl+Shift+Z redo shortcut (in addition to Ctrl+Y), extracted toggleReadOnly() helper, Alt+Shift+R shortcut for read-only toggle, fixed double-trigger bug by switching QAction::toggled to QAction::triggered, added shortcut labels to read-only menu action
…, and kate-case-conversion into kate base
…agation - Remove non-standard `lc_focus` definition from `sdk/wlxplugin.h` and its handler in `wlx_plugin.cpp`. - Remove custom `hostSetFocus` method from `EditorWidget`. - Set the editor view as the focus proxy for the main widget. - Use native Qt event filtering and focus change listeners to handle active state transitions.
This makes the plugin standalone by compiling and linking libenca statically, removing the need for users to manually install libenca.so.0.
Adds ability to insert empty rows or clipboard rows above/below current selection or clicked row.
De-Qtify: extracted CsvCore (src/core/CsvCore.{h,cpp}) — the CSV/TSV
tokenizer (was a free function `parse_line()` already, just QString-typed)
and the field-escaping logic that was inline in saveFile() — as
std::string-based, toolkit-neutral functions. Rewired plugin.cpp's
parse_line() and saveFile() to call into CsvCore instead of duplicating
the algorithm inline; encoding conversion (EncodingUtils, still Qt-typed)
stays exactly where it was, only the tokenize/escape steps moved.
Preserves an existing quirk exactly: parse_line() still returns an empty
list when the (persisted) gQuoted setting is false, matching prior
behavior bit-for-bit rather than silently changing it.
Verified with a standalone functional test (not just syntax-checked):
simple fields, quoted fields containing the separator, doubled-quote
escaping, CRLF stripping, and a full parse->escape->join round-trip. All
passed. Also rebuilt csvview_qt6.wlx against the rewired plugin.cpp to
confirm the wiring itself compiles and links clean.
GTK3 port (src/gtk3/plugin_gtk3.cpp): deliberately scoped down from full
feature parity. csvview_qt6 is built on EditableGridWidget (QTableView +
QUndoStack), FocusManager, and ScopedFindReplacePanel from wlxbase_wlqt —
there is no wlxbase_gtk yet providing equivalent GTK primitives, and
building one properly (undo stack, focus/shortcut plumbing, a shared
find/replace panel) is a real separate investment, not something to
improvise inline for one plugin. This GTK3 build is a self-contained
GtkTreeView grid: load, inline cell editing, save, separator/header
toggles — but no undo/redo and no find/replace panel. Tracked as
follow-up, not silently dropped.
Verified: both csvview_qt6.wlx and csvview_gtk3.wlx build clean and
export the required WLX ABI symbols. Confirmed via ldd that
csvview_gtk3.wlx has ZERO Qt dependency and csvview_core carries zero Qt
symbols — third plugin in the suite (after mdk, diagramview) to actually
ship a pure-GTK binary.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replaces the self-contained (scoped-down) GTK3 grid from the previous
commit with a full build on wlxbase_gtk, bringing it to parity with the
Qt6 build's use of FocusManager/EditableGridWidget/ScopedFindReplacePanel:
- GtkFocusManager provides Ctrl+Z/Ctrl+Shift+Z/Ctrl+Y undo/redo shortcuts,
Ctrl+F to toggle the find panel, and Ctrl+S to save.
- GtkEditableGridWidget replaces the plain GtkTreeView grid — every cell
edit, row insert, and row delete now goes through the shared undo
stack, and Ctrl+C copies the selection as tab-separated text via
GtkClipboard.
- GtkScopedFindReplacePanel provides Find/Replace/Replace All with a
scope selector ("All Cells" / "Current Column"), matching-case/
entire-cell/regex options (std::regex, ECMAScript syntax) — wired up
in this file's doFind/doReplace/doReplaceAll.
CsvCore (tokenizer/serializer) is unchanged from the previous commit.
Verified: full build (Qt6 + GTK3 + wlxbase_gtk all together) succeeds.
Confirmed via ldd that csvview_gtk3.wlx still has zero Qt dependency
despite the much larger feature set. wlxbase_gtk itself was verified
against a live GTK runtime (see its own commit) — undo/redo, insert
rows, and cell editing all confirmed working before being wired in here.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tainer_add() DC's GTK3 ResizeWindow (uwlxmodule.pas) calls GtkLayout.move() on the widget this plugin returns from ListLoad(), which asserts the widget's parent is exactly that GtkLayout -- a contract only gtk_layout_put() satisfies. gtk_container_add() doesn't register the child that way, so DC's later move/resize calls hit 'gtk_layout_move: assertion gtk_widget_get_parent (child_widget) == GTK_WIDGET (layout) failed' and, in some cases, a real crash further down the paint/layout path. Found via real dcgtk testing against a from-source GTK3 Double Commander build (v1.3.0 alpha, Lazarus 4.99) -- this only ever surfaces against a genuine GtkLayout parent, not the synthetic dlopen/ListLoad test harness used earlier this session, which passes a plain GtkWindow.
…lbar)
The GTK3 UI was written from scratch separately from the Qt6 build and
never reached feature parity with it -- confirmed via a side-by-side
screenshot comparison. Concretely, it was missing a row-number gutter
column entirely, had a manual delimiter dropdown that doesn't exist in
the Qt6 toolbar at all (Qt auto-detects the separator from file
content), and was missing most of the Qt6 toolbar: Save As, Undo,
Redo, Print, Reload, Show Text, Line Wrap, Open Externally (only Save
and Find/Replace existed).
Added:
- Row-number gutter column (leading GtkTreeViewColumn with a cell
data func rendering the model row index -- doesn't touch
GtkEditableGridWidget itself, purely cosmetic in csvview's own
code, since that widget is shared with dbview/structview).
- Separator auto-detection matching the Qt6 build exactly: try ','
';' '\t' on the first line, keep the first yielding >1 columns,
else fall back on the .tsv/.csv extension. Manual delimiter
dropdown removed.
- Separator/extension-mismatch dialog (Ignore / Fix Separator /
Rename Extension), matching the Qt6 build's behavior when e.g. a
.csv file turns out to be tab-separated.
- Save As (GtkFileChooserDialog with CSV/TSV filters).
- Undo/Redo toolbar buttons wired to GtkFocusManager's undo stack
(already existed in GtkFocusManager, just wasn't exposed in the
toolbar), with sensitivity kept in sync via canUndo()/canRedo().
- Print via GtkPrintOperation, paginating a monospace tab-joined
rendering of the visible rows -- simpler than the Qt6 build's HTML
table render, but functionally equivalent (opens the system print
dialog, prints the data).
- Reload button.
- Show Text toggle: a plain GtkTextView shown in place of the grid
(unlike Qt6's colorized-by-column rendering, kept monochrome here
-- scope reduction, not a missing feature parity point that
matters functionally).
- Line Wrap toggle, applied to the Show Text view (GtkEditableGridWidget
doesn't expose a cell-wrap mode, so this doesn't affect the grid
itself, same practical limitation as before).
- Open Externally via g_app_info_launch_default_for_uri.
- Dirty indicator label ("✓"/"●"), matching the Qt6 build's checkmark.
Also: reload now explicitly clears the undo stack (st->fm->clearUndoStack()) --
needed because GtkFocusManager owns the undo stack (not the grid), unlike
Qt6 where EditableGridWidget owns its own per-instance QUndoStack that a
reload implicitly replaces.
Verified: compiles clean in the gtk-dev container; dlopen+ListLoad+
ListSearchText smoke test against a real CSV file loads, finds text,
and closes cleanly (the GTK_LAYOUT cast warning from the synthetic
test harness's plain-GtkWindow parent is expected/unrelated, per the
gtk_layout_put commit on this and other plugin branches). Not yet
retested in the real dcgtk GTK3 Double Commander session.
Follow-up to the earlier toolbar-parity pass -- the GTK3 build still had zero context menu of any kind, unlike the Qt6 build's row/column right-click menus (EditableGridWidget::showRowContextMenu/ showColumnContextMenu in wlxbase_wlqt). Row menu (right-click on the grid body, via a button-press-event handler on the tree view): Copy Row, Copy Selection as TSV/CSV, Delete Row(s) (GtkEditableGridWidget::deleteSelectedRows(), already existed, was just never exposed anywhere in this build), Insert Row Above/Below (insertRows(), same situation). Column menu (right-click on a column header, via a button-press-event handler on each GtkTreeViewColumn's own button widget -- gtk_tree_view_column_get_button()): Insert Column Left/Right, Delete Column. GtkEditableGridWidget has no column insert/delete API at all (fixed column count set at construction, unlike its Qt6 sibling) -- extending the shared widget would be a cross-cutting change affecting dbview/structview too, out of scope for a csvview-only pass. Instead column operations here rebuild the grid in place from the current in-memory row data with the column list mutated (rebuildGridColumns()), the same shape loadFile() already uses when the column count changes on reload, just driven from the live grid's data instead of re-parsing the file. Menu-item callbacks and the column-context closures both hit the same G_CALLBACK()/preprocessor-vs-template-angle-brackets bug fixed earlier in wlx/cuda's case-conversion menu (a raw comma inside std::pair<CsvGtkState*, int> used directly as a macro argument gets misparsed as an extra argument) -- same fix, a local `using ColCtx = ...` alias. Known, disclosed scope reduction vs. the Qt6 build's row menu: no "Copy cell" action (only "Copy Row"), and the "N rows"-aware wording when multiple rows are selected isn't reproduced -- GtkEditableGridWidget doesn't expose the current TreeView selection range as a queryable API, so the row menu currently operates on "the row that was right-clicked" rather than an arbitrary multi-row selection. Not a crash risk, just a narrower interaction than Qt6's. Verified: compiles clean; dlopen+ListLoad+ListSearchText smoke test loads a CSV, finds text, and closes cleanly with the context-menu handlers attached. Right-click interaction itself (the actual menu appearing/functioning) needs real mouse input a headless harness can't provide -- needs retesting in the real dcgtk session.
textScroll had gtk_widget_set_no_show_all(TRUE) so it stays hidden until "Show Text" is toggled on. But the toggle handler only called gtk_widget_show() on the outer scroll container, which does not propagate into its child GtkTextView since show_all was suppressed for the whole subtree — the panel appeared empty every time. Use gtk_widget_show_all() on toggle-on instead, so the text view itself gets shown along with its container.
…all fix was a no-op) Real-world testing confirmed the earlier C1 fix (task doublecmd#4) didn't actually work. Root cause fully understood now: gtk_widget_show_all() skips a widget's ENTIRE subtree when called directly on a widget that itself has no_show_all set -- not just when recursing into it as someone else's descendant. st->textScroll has no_show_all set (so an ancestor's show_all() at ListLoad time doesn't prematurely reveal it), so gtk_widget_show_all(st->textScroll) was a complete no-op: neither textScroll nor the GtkTextView inside it (which, as a result, had never once been individually shown since creation) ever became visible. Fix: use plain gtk_widget_show() on both textScroll and textView explicitly -- gtk_widget_show() ignores no_show_all entirely, unlike gtk_widget_show_all(). Verified with a purpose-built harness that dlopens the plugin, drives the real Show Text toggle button via gtk_toggle_button_set_active() (not just headless load/close), and checks the actual GtkTextView's visible/mapped state plus buffer content: textview visible=1, mapped=1, buffer correctly populated with the CSV data (previously visible=0, mapped=0 despite the buffer being correctly populated all along -- updateTextView() was never broken, only the visibility).
…eader click-to-select Real-world testing reported 'no numbered rows to select or resize them' and 'unable to select columns'. Investigation found a genuine, concrete bug behind the first complaint, not just a missing feature: addRowNumberColumn() inserts a column at treeview position 0 (the '#' gutter). All three call sites called it BEFORE the title-setting loop (setColumnTitle(c, ...) for c in 0..colCount-1), but setColumnTitle addresses columns by raw treeview position via gtk_tree_view_get_column() -- with the gutter already inserted at 0, every title-setting call was off by one: setColumnTitle(0, ...) overwrote the gutter's own '#' title with the first data column's title, and every subsequent title landed one column to the right of where its actual data lived. The '#' column effectively vanished (relabeled as the first data column) and every other header was wrong. Fixed by moving addRowNumberColumn() to run after the title-setting loop at both affected call sites (loadFile, rebuildGridColumns). Once column titles are correctly aligned, clicking the row-number gutter already selects that row via GTK's own default GtkTreeView click handling (confirmed with a real synthetic button-press event, not just a manual selection API call) -- no additional code was needed for that part; the title-misalignment bug was the actual reason it looked broken. Column selection genuinely didn't exist and needed real code: added setupColumnSelection() making every data column header clickable, storing the selected column index in CsvGtkState, and highlighting every cell in that column via a cell-data-func (GtkTreeSelection has no native column-selection concept to build on). Clicking a header toggles that column's selection on/off. Verified: builds cleanly. Confirmed the title fix directly (a widget-driving harness lists all real column titles/positions post-fix: '#', then the actual CSV headers in the correct order and position). Confirmed row-gutter click-to-select via a genuine synthetic GDK_BUTTON_PRESS/RELEASE event dispatched through gtk_widget_event() (not a manual gtk_tree_selection_select_path() call) -- selection count is 1 afterward. Confirmed column-header 'clicked' signal fires and runs the highlight-toggle logic without crashing via g_signal_emit_by_name(); the resulting visual rendering itself can't be asserted headlessly.
…re insert/delete User feedback after the initial single-column click-to-select landed: 1. Couldn't select multiple columns. 2. Selecting a column didn't unselect rows and vice versa (both could be 'selected' at once, an inconsistent state). 3. No N-aware insert/remove rows/columns driven by the actual selection size. Changes: - st->selectedColumn (int) -> st->selectedColumns (std::set<int>) plus columnSelectAnchor, matching how row multi-selection already works. Column headers now support Ctrl-click (toggle a column in/out of the selection) and Shift-click (range from the last-clicked column). Switched from GtkTreeViewColumn's 'clicked' signal (no modifier state available) to 'button-press-event' on the header's own button widget (already reachable via gtk_tree_view_column_get_button(), the same widget attachContextMenus() uses for its right-click handler) so Ctrl/Shift state is available. - Selecting a column now clears row selection (gtk_tree_selection_ unselect_all(), guarded by suppressRowSelectionSync so it doesn't immediately re-trigger the reverse sync) and selecting a row clears column selection (GtkTreeSelection's own 'changed' signal, checked against suppressRowSelectionSync) -- the two selection modes are now mutually exclusive instead of independent. - showRowContextMenu now reads the real multi-row selection directly from GtkTreeSelection (gtk_tree_view_get_selection() on the grid's own treeview is directly reachable even though GtkEditableGridWidget doesn't expose it) instead of falling back to 'just the clicked row' -- 'Insert N Above/Below'/'Delete N Rows' now reflect an actual multi-row selection. insertRows()/deleteSelectedRows() were already N-aware; the previous 'always operates on 1 row' framing was a csvview-side limitation, not a GtkEditableGridWidget one. - Added insertColumnsAt()/deleteColumns() (N-aware) alongside the existing single-column rebuildGridColumns() machinery, and rewired showColumnContextMenu() to operate on the full selectedColumns set when the right-clicked column is part of it (falling back to just the clicked column otherwise). Removed the now-orphaned single- column insertColumn()/deleteColumn() helpers, replaced by the N-aware versions. Bug found and fixed during verification: the column header's cell- data-func and its button-press-event handler were sharing a single heap-allocated ColSelCtx*, each with its own destroy-notify -- GTK invokes both independently during widget teardown, so it double-freed on every ListCloseWindow (reproducibly crashed with 'double free detected in tcache 2' in the plain headless load/close harness, no interaction needed to trigger it). Fixed with two separate allocations, one per destroy-notify site. Verified: builds cleanly. Confirmed via a purpose-built harness (test_csvview_multisel.c) with real synthetic button-press events (including a temporary debug print, since removed, that traced selectedColumns growing correctly across a plain click then a Ctrl-click) that multi-select accumulates as expected. Re-ran the general ListLoad/ResizeWindow/ListCloseWindow harness 3x plus a click-then-reload-then-close harness (test_csvview_reload.c, exercises setupColumnSelection()'s second call site in rebuildGridColumns()) -- all clean after the double-free fix, all crashing before it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR updates the CSV plugin for Double Commander built with Qt6 to visualize, navigate, edit, and export CSV and TSV files in an interactive spreadsheet-like grid (
QTableWidget). It also includes a fully integrated, focus-safe Find & Replace utility panel.Key Features
1. Spreadsheet Grid View & Visuals
2. Auto-Detection & RFC Parsing
3. Edit & Undo/Redo Stack
QUndoStackfor complete Undo (Ctrl+Z) and Redo (Ctrl+shift+ZorCtrl+Y`) capability.✓/*) showing unsaved history changes.4. Inline Find & Replace Panel
Press
Ctrl+F,Ctrl+R, or click the toolbar🔍 Find/Replacebutton in the grid view to open a collapsible search panel at the bottom of the layout:QRegularExpression) patterns.QUndoStackmacro so that they can be undone/redone in a single action.5. Focus & DC Pane Coordination
🛠 Build & Installation
build.shto compile and packagecsvview_qt6.wlxalong with translation files into the release archive underrelease/wlx/csvview/.j2969719.ini.