Headline titles were rendered as plain text, so an inline org link in a
heading showed its raw [[target][desc]] syntax and could not be followed.
Body text and list items already route links through renderInline and
onLinkActivated; apply the same treatment to the title Label.
The title now renders as StyledText via renderInline, exposes a pointer
cursor over links through a HoverHandler, and dispatches clicks to
openLink (which resolves and navigates via the model). Non-link text
keeps its done-aware color and strike-through.
Clicking an internal org link now navigates the outline to its target.
The GUI resolves the link via /<doc>/resolve and acts on the result:
external targets open in the OS handler; internal targets expand the
target's ancestors, scroll to it, and flash it.
Resolution spans the whole org path rather than a single document:
- file:DOC::TARGET and file:DOC resolve TARGET within the named
document (a file: link to a document not in the path stays external).
- id:uuid links are globally unique and resolve in whichever document
owns the ID.
- #custom-id, *Headline, and bare fuzzy targets resolve in the current
document first, then fall back across every other document.
The resolve result gains a `doc:` field naming the owning document. When
it differs from the current document, DocumentModel::followLink switches
the model to that document before revealing the section.
DocumentModel gains revealSection() and followLink(); OutlineView wires
link clicks to followLink and animates the revealed row via the new
sectionRevealed signal.
Body text and list items now render org links ([[target]] and
[[target][description]]) as clickable hyperlinks via StyledText. Other
text is HTML-escaped and newlines become <br> so formatting is preserved.
Activating a link opens external URL schemes (http(s), mailto, file) in
the system handler; internal links (id:, #custom, *headline) are left for
a future navigation pass. The pointer cursor shows over hovered links.
Scrolling over a checkbox glyph cycles its state
unchecked -> partial -> checked (and back), respecting scroll direction:
wheel up steps forward, wheel down steps in reverse. Left-click still
toggles checked/unchecked.
The shared rewriteCheckbox helper applies a state-mapping function to the
Nth cookie; toggleCheckbox and the new cycleCheckbox are thin callers.
The QML list parser required whitespace after the checkbox bracket
(\]\s+), so a bare cookie with no trailing text (e.g. "- [X]") was not
counted as a checkbox. The model's toggle regex had no such requirement,
so the two disagreed on checkbox ordinals and a click could toggle the
wrong item. Relax the QML regex to \]\s* so both layers count the same
set of checkboxes in the same order.
Clicking a checkbox glyph toggles its state and writes the change back.
DocumentModel::toggleCheckbox(row, ordinal) finds the Nth checkbox cookie
in the section body (document order), flips [ ]/[-] -> [X] and [X] -> [ ],
writes the body via /body, and refreshes the row.
The body parser assigns each checkbox item a stable ordinal across the
whole section, and the list delegate wires a pointer-cursor MouseArea on
the glyph (checkbox items only) to the model toggle.
The body parser now recognizes org list items (- / + / ordered) and
splits them out of text runs into dedicated "list" parts. Each item
captures its indent, bullet, optional checkbox state, and text.
A new list component renders checkbox items with ☐ / ▣ / ☑ glyphs
(unchecked / partial / checked), colored by state, with checked items
dimmed and struck through. Plain list items render with their bullet.
Each executable source block now shows a "Run" button in the outline.
Clicking it runs the block server-side and renders the inserted
#+RESULTS: in place, with an exit-status indicator.
DocumentModel gains executeBlock(row, blockIndex), which runs
/ctl execute <doc> <id> <n>, refreshes the section body, and emits
dataChanged(BodyRole). isLanguageSupported(lang) backs button visibility
via /ctl languages (loaded once, cached).
OutlineView tags each parsed code part with its src-block ordinal so the
GUI index matches the server's block indexing, and the code block header
carries the Run control plus running/ok/error status.
- Store tableData at Rectangle level to avoid scope issues
- Use ColumnLayout + RowLayout instead of GridLayout (cleaner nesting)
- Anchor left instead of center
- 8px margins, 16px column spacing
- Add ?? false fallback for hasHeader to prevent undefined errors
- Parse | delimited rows into cells
- Detect header separator (|---+---|)
- Header row: bold, text color
- Data rows: normal, placeholder color
- Same alternate background as code blocks
TreeView (inherits TableView) is designed for file browsers with fixed row
heights, not structured document editing. ListView gives us:
- Full control over row heights (implicitHeight just works)
- Simpler delegate without TreeViewDelegate quirks
- Manual indentation via leftMargin based on level
- Expansion state tracked in model with hasChildren/expanded roles
- Click-to-expand triangles for sections with children
DocumentModel changed from QAbstractItemModel (tree) to QAbstractListModel
(flat list) with sections ordered depth-first. Tree structure preserved via
level, parentId, childIds fields. Expansion state controls visibility.
TreeView (inherits TableView) defaults to fixed row heights. Setting
rowHeightProvider to return -1 tells it to use each delegate's
implicitHeight, enabling variable-height rows.
ThemeManager now supports:
- fontFamily, fontSize, fontStyle with full QFontDatabase access
- uiScale (0.5x to 4.0x) saved to theme.conf
- resetFont() to return to system defaults
SettingsDialog provides UI for:
- Color scheme selection (all installed KDE schemes)
- Font family/style/size with live preview
- UI scale slider with percentage display
OutlineView uses pointSize (scalable) instead of pixelSize (fixed).
All font sizes derived from theme.fontSize or baseFontSize.
- Replace manual Item+anchoring with ColumnLayout for proper height calc
- Remove redundant bodyMeasure Text and bodyWidth property
- Add proper top/bottom margins using rowPad constant
- Body row now uses RowLayout with Layout.fillWidth
A standalone Qt6/QML app in ui/ that speaks 9P to ork-server; no FFI,
no privileged path. All org logic stays in the server.
- p9client: minimal synchronous 9P2000 client over QTcp/QLocalSocket
- orkclient: QML-facing facade (read/list/listDirs/write/rdwr/docs)
- documentmodel: lazy QAbstractItemModel of the section tree, with a
BodyRole that reads /<doc>/<id>/body (planning line + :PROPERTIES:
drawer stripped, since those are shown as structural objects)
- Main.qml: document sidebar + outline; OutlineView.qml: folding
TreeView rendering keyword/priority/title/tags/timestamps as distinct
objects, with section body shown inline beneath each headline
- main.cpp: --addr/$ORK_ADDR, --selftest (headless outline dump),
--shot (headless window grab for debugging)
- CMake build; binary emitted to bin/ to avoid the QML-module-URI vs
target-name directory clash
Known issue: inline body layout still needs work (row sizing/overlap
when bodies wrap); to be iterated.