Skip to content

Officeview#46

Open
pplupo wants to merge 29 commits into
doublecmd:masterfrom
pplupo:officeview
Open

Officeview#46
pplupo wants to merge 29 commits into
doublecmd:masterfrom
pplupo:officeview

Conversation

@pplupo

@pplupo pplupo commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

A Double Commander WLX lister plugin that previews Microsoft Office and OpenDocument files (Word/Excel/PowerPoint and their legacy/macro-enabled variants, plus ODT/ODS/ODP) directly in Double Commander's Quick View panel and file lister, without opening a separate editor.

It depends on LibreOffice, Euro-Office, or OnlyOffice. It looks for them in the first execution and uses what it found. If it can't be found, the path can be provided in a config file. If multiple are found, it tries to open ODF with LibreOffice and OOXML+MS Legacy with Euro-Office or OnlyOffice (Euro-Office takes precedence). All that can be changed in the config file (users can have multiple, but use only one to visualize all formats).

pplupo and others added 29 commits May 12, 2026 10:15
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
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move action configuration into completed handler so connections
  are established after the KPart is fully loaded
- Use dynamic property guard (_kpw_connected) to prevent duplicate
  lambda connections (Qt::UniqueConnection doesn't work with lambdas)
- Persist checkable action states to QSettings INI file
- Restore settings using trigger() to change Gwenview's internal
  zoom state, not just checkbox visual state
- Handle zoom radio pair specially during restore to avoid Gwenview
  fighting back when we manipulate checkbox states directly
- Add Ctrl+Shift+S shortcut routing for Save As
- Remove aggressive uncheck→check-other radio logic that conflicted
  with manual zoom in/out (custom zoom is a valid state)
Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Focus/input:
- Add lc_focus (5) to the shared wlxplugin.h SDK header, previously missing
  entirely on this branch, so ListSendCommand could handle DC's focus
  hand-off signal at all.
- Port QtWlPlugin::FocusManager (from wayland_qt_base) into officeview for
  both the x2t/PdfViewerWidget and LibreOfficeKit/LOKContainerWidget paths,
  replacing ad-hoc focus handling that left keyboard shortcuts and panel
  switching unreliable.
- Fix a click-activation bug where the ancestry check used the wrong
  QObject in the propagation chain (QWidgetWindow isn't a QWidget), causing
  some documents to require two clicks before Ctrl+C worked.
- Add a grace-period guard (setActiveFromHost) so DC's own lc_focus(0)
  can't immediately undo a legitimate click-based activation.
- Retry LOK's getTextSelection after SelectAll instead of a single fixed
  wait, fixing intermittent empty-clipboard copies.
- Scope LOK copy/context-menu actions to the specific sheet/slide clicked
  or currently visible, instead of whatever part LOK's internal cursor
  last happened to be on.

Rendering:
- Give ODF documents their own LibreOfficeKit-side zoom, copy, and context
  menu instead of silently borrowing x2t's, since ODF stays on LibreOffice
  deliberately (better fidelity than x2t for this format family).
- Fix spreadsheet sheet-tab extraction to exclude hidden sheets, which
  otherwise mismatched x2t's actual visible-sheet PDF output and silently
  hid the tab bar.
- Add per-sheet pagination for xlsx/xlsm: convert each sheet separately
  (patching its own temp copy's activeTab so x2t paginates it fully,
  instead of squeezing every sheet onto a single page via printPages:all)
  and merge with qpdf, tracking real per-sheet start pages instead of
  assuming one page per sheet.
- Switch the PDF view to always use MultiPage mode; SinglePage mode hid a
  sheet's later pages behind the tab bar with no obvious way to reach them.
- Apply 2x supersampled LOK tile rendering to reduce font aliasing.

Config:
- Add a per-extension file size limit (officeview.conf), skipping
  conversion entirely for files over the limit; 0 disables an extension.
- Restructure officeview.conf into [Paths]/[Engines]/[FileSizeLimits]
  sections (previously a flat list that only grew entries lazily, so it
  never had all supported extensions) with paths first and a comment
  explaining the size-limit semantics.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
QPdfView's page-layout/coordinate-mapping internals are private API with
no public hook to map a click to a page + point-within-page, which meant
copy was limited to whole-page/whole-selection text with no way to
highlight or select an arbitrary run of text. MuPDF's structured-text API
(fz_highlight_selection / fz_copy_selection) exposes that directly.

- Add MuPdfWidget/MuPdfContainerWidget, mirroring LOKWidget/
  LOKContainerWidget's structure (continuous page stacking, only visible
  pages rendered, same FocusManager/zoom/wheel-event wiring) so all three
  rendering paths share one interface for ListSendCommand.
- Remove PdfViewerWidget and the Qt6::Pdf/PdfWidgets dependency entirely;
  replace the one QPdfDocument use (page counting for the per-sheet merge
  pipeline) with a small MuPDF-based helper.
- Fix tab-bar desync: sheetStartPages holds page *indices*, but three
  places compared it directly against the scrollbar's pixel position, so
  a few pixels of scroll could exceed a page-index number like 14 or 15
  and snap the active tab to the last sheet. Convert through
  pageYOffset()/pageAtY() so both sides of every comparison share units.
- Fix font aliasing on fractional-scaling displays: page rendering had no
  devicePixelRatio handling, so Qt stretched the under-resolution image up
  to fill the widget's real physical pixels. Render at
  zoom*devicePixelRatioF() and mark the QImage's devicePixelRatio so Qt
  draws it 1:1 instead of scaling it.

Links dynamically against the system libmupdf for now; static linking is
a separate follow-up.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Also update the compiled binary to match the current MuPDF-based build.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
rclone's Google Drive VFS mount leaves native Google Docs/Sheets/Slides
as 0-byte stub files on disk, since it can't materialize their content
transparently on read like a regular file. When ListLoad hits a 0-byte
file for a supported extension, it now checks /proc/mounts for a
covering fuse.rclone mount, and if found runs `rclone copyto` to export
the real content before handing it to the usual OOXML/ODF rendering
path. If the file isn't under an rclone mount, it fails gracefully
with a short message instead of trying to render nothing.

Google Drive exports get their own independently configurable engine
preference (EngineForGDrive), and any of the four Engines keys can now
be set to Disabled to skip that format family entirely.

The file-size-limit disable sentinel changes from 0 to -1, since 0 is
now a legitimate size for an unmaterialized rclone stub rather than
something to reject outright.

README updated to document all of the above.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant