<div dir="ltr"><div dir="ltr"><div><span style="font-family:monospace"><p><span><span>Hi everyone,</span></span></p><p><span><span>This past week has been a deep dive into the practical side of the SFX</span><br><span></span><span>framework, marking a significant pivot from data discovery to UI</span><br><span></span><span>implementation. The core directive from our mentor meetings was to build the</span><br><span></span><span>Object Browser shell first and populate it with live data, a decision driven</span><br><span></span><span>by the very promising performance results of our C++ PoCs.</span></span></p><p><span><span>Gerrit PoC Patch: </span><a href="https://www.google.com/url?sa=E&q=https%3A%2F%2Fgerrit.libreoffice.org%2Fc%2Fcore%2F%2B%2F186475" target="_blank"><span><span>https://gerrit.libreoffice.org/c/core/+/186475</span></span></a></span></p><p><span><span><span><span><b><u>The Strategic Pivot: Why Live Data First?</u></b></span></span></span></span></p><p><span><span>Our C++ PoCs answered the critical question of whether live UNO API</span><br><span></span><span>introspection is fast enough for an interactive tool. The results were</span><br><span></span><span>conclusive: listing all services took only milliseconds, and introspecting</span><br><span></span><span>complex UNO types took mere microseconds.</span></span></p><p><span><span>This data gave the mentors confidence that a system built on runtime data</span><br><span></span><span>fetching is a viable starting point. They guided us to prioritize building</span><br><span></span><span>the live UI to get real-world performance metrics, deferring the creation</span><br><span></span><span>of a static offline cache to a later optimization stage if needed.</span></span></p></span><span><span style="font-family:monospace">This data-driven decision process can be visualized as follows:</span></span></div><div><span><div><pre> <code><b><span><</span><span>Initial</span> Question: How <span>to</span> <span>get</span> UNO API data?<span>></span></b>
<span><span class="gmail_default"> </span>|</span>
<span>+</span><span>---------------+------------------+</span>
<span>|</span> <span>|</span>
v v
<span>+</span><span>----------------+ +---------------------+</span>
<span>|</span> <span>Static</span><span>/</span>Offline <span>|</span> <span>|</span> <span>Dynamic</span><span>/</span>Live <span>|</span>
<span>|</span> Approach <span>|</span> <span>|</span> Approach <span>|</span>
<span>+</span><span>----------------+ +---------------------+</span>
<span>|</span> <span>|</span>
<span>|</span> unoidl<span>-</span>read PoC <span>|</span> C<span>+</span><span>+</span> PoCs <span>using</span>
<span>|</span> <span class="gmail_default"> </span> <span>|</span> theCoreReflection
<span>|</span> <span>|</span>
v v
<b> <span><</span><span>Static</span> Dump File<span>></span></b> <b><span><</span>Fast Results: <span>~</span>µs<span>></span></b>
<span>|</span>
v
<span>+</span><span>-------------------------+</span>
<span>|</span> Mentor Feedback: <span>|</span>
<span>|</span> "This is fast enough. |
| Build the live UI." <span>|</span>
<span>+</span><span>-------------------------+</span>
<span>|</span>
v
<span><b>---> Our Current Path: Live Data UI First <---</b></span></code>
<br> </pre></div></span><span style="font-family:monospace"><b><u><span class="gmail_default"></span>T<span class="gmail_default"></span>he Implementation Journey: A Chronicle of Learning</u></b><br><br>Bringing a new UI component to life in LibreOffice was a fantastic lesson<br>in debugging the build system and understanding C++ best practices.<br><br><b>Gerrit UI Patch:</b> <a href="https://gerrit.libreoffice.org/c/core/+/186822" target="_blank">https://gerrit.libreoffice.org/c/core/+/186822</a><br><br><b>1. The .sdi Syntax Puzzle (Build System)</b></span><p><span style="font-family:monospace"><b>Problem:</b><br>
When I first tried to register the new command <code>SID_BASICIDE_OBJECT_BROWSER</code>,<br>
my build failed with a cryptic <code>svidl</code> compiler error and a <code>Not found</code><br>
warning. This wasn't just a typo; it was a fundamental misunderstanding of<br>
how LibreOffice's powerful SFX command framework is designed.</span></p></div><div><span style="font-family:monospace"><b><br></b></span></div><div><span style="font-family:monospace"><b>Investigation & Learning: The Two-Tier Command Architecture</b></span><p><span style="font-family:monospace">
To solve this, I <span class="gmail_default">looked</span> into the history and structure of the SFX<br>
(StarView Framework) dispatch system. By analyzing how existing commands<br>
like <code>SID_BASICIDE_WATCH</code> were implemented (see <span class="gmail_default">Prof</span> Lima’s patch<br></span>
<span style="font-family:monospace"><a href="https://gerrit.libreoffice.org/c/core/+/147305" target="_blank">147305</a>)</span></p>
<p><span style="font-family:monospace">This system is inherited from <b>StarOffice</b> and was carried over into<br></span>
<span style="font-family:monospace"><b>OpenOffice.org</b> and later <b>LibreOffice</b>.</span></p><p><span style="font-family:monospace"><a href="https://wiki.openoffice.org/wiki/Framework/Article/Implementation_of_the_Dispatch_API_In_SFX2" target="_blank">https://wiki.openoffice.org/wiki/Framework/Article/Implementation_of_the_Dispatch_API_In_SFX2</a></span></p>
<p><span style="font-family:monospace">It is also described in TDF's official documentation:<br></span>
<span style="font-family:monospace"><a href="https://wiki.documentfoundation.org/Framework/Article/Implementation_of_the_Dispatch_API_In_SFX2" target="_blank">https://wiki.documentfoundation.org/Framework/Article/Implementation_of_the_Dispatch_API_In_SFX2</a></span></p>
<p><span style="font-family:monospace">Even Andrew Pitonyak’s book points developers toward <code>.sdi</code> files when<br>
working with commands:<br></span>
<span style="font-family:monospace"><a href="http://www.pitonyak.org/OOME_3_0.pdf" target="_blank">http://www.pitonyak.org/OOME_3_0.pdf</a> (Chapter 11, Page 256)</span></p></div><div><span style="font-family:monospace"><b><br></b></span></div><div><span style="font-family:monospace"><b>Why This Design?</b></span>
<p><span style="font-family:monospace">The core challenge in StarOffice was supporting a large, modular,<br>
scriptable office suite with many commands (.uno:Save, .uno:Copy, etc.).<br>
Hardcoding every UI action would be unscalable and inflexible.</span></p>
<p><b style="font-family:monospace">Solution: Separate Global Identity from Local Handling</b></p>
<ul><li>
<p><span style="font-family:monospace"><b>Global SID Registry</b> — defined in <code>sfx2/sdi/sfx.sdi</code></span></p>
<ul><li>
<p><span style="font-family:monospace">Lists all command SIDs known system-wide</span></p>
</li><li>
<p><span style="font-family:monospace">Makes them available for UI configuration (menus, toolbars)</span></p>
</li><li>
<p><span style="font-family:monospace">Enables scripting/macro access via <code>.uno:</code> name</span></p>
</li></ul>
</li><li>
<p><span style="font-family:monospace"><b>Shell-Specific Mapping</b> — defined in <code>basctl/sdi/baside.sdi</code></span></p>
<ul><li>
<p><span style="font-family:monospace">Binds that SID to methods like <code>ExecuteGlobal()</code> and <code>GetState()</code></span></p>
</li><li>
<p><span style="font-family:monospace">Enables context-sensitive behavior depending on the active component</span></p>
</li><li>
<p><span style="font-family:monospace">Keeps each component’s logic self-contained</span></p>
</li></ul>
</li></ul></div><div><span style="font-family:monospace"><b><font size="2"><br></font></b></span></div><div><span style="font-family:monospace"><b><font size="2"><br></font></b></span></div><div><span style="font-family:monospace"><b><font size="2">Flowchart: From User Click to C++ Execution</font></b></span>
<pre>User Clicks Menu Item<br>┌─────────────────────────────────────┐<br>│ <span class="gmail_default"> </span>menubar.xml <span class="gmail_default"> </span><span class="gmail_default"> </span>│ ← [UI XML / .ui file]<br>│ <span class="gmail_default"> </span><menu:menuitem <span class="gmail_default"> </span>│<br>│ command=".uno:ObjectBrowser" /><span class="gmail_default"> </span>│<span class="gmail_default"> </span><br>└───────────────┬─────────────────────┘<br> │<br> ▼<br>UI Command `.uno:ObjectBrowser`<br>┌────────────────────────────────────┐<br>│ GenericCommands.xcu <span class="gmail_default"> </span>│ ← [UI config]<br>│ Maps command → label, helptext <span class="gmail_default"> </span>│<br>│ and shows in customization UI <span class="gmail_default"> </span>│<br>└───────────────┬────────────────────┘<br> │<br> ▼<br> SFX Dispatcher<br> ┌───────────────────────────────────────────────────────┐<br> │ [Runtime Entry Point] │<br> │ Looks up ".uno:ObjectBrowser" in SID map │<br> │ │<br> │ Step 1: Check global registry │<br> │ → sfx2/sdi/sfx.sdi │<br> │ → Finds SID_BASICIDE_OBJECT_BROWSER │<br> │ + GroupId, MenuConfig, etc. │<br> │ │<br> │ Step 2: Determine active component shell │<br> │ → e.g. BasicIDEShell (basctl module) │<br> │ │<br> │ Step 3: Check shell mapping │<br> │ → basctl/sdi/baside.sdi │<br> │ → SID_BASICIDE_OBJECT_BROWSER → │<br> │ ExecMethod = ExecuteGlobal │<br> │ StateMethod = GetState │<br> │ │<br> │ Step 4: Call mapped C++ method │<br> │ → basctl/source/basicide/basides1.cxx │<br> │ → BasicIDEShell::ExecuteGlobal(...) │<br> └───────────────────────────────────────────────────────┘<br><code>
<br><b><br></b></code></pre></div><div><span style="font-family:monospace"><b>How It Works at Build Time
</b></span><p><span style="font-family:monospace">LibreOffice uses a tool called <code>svidl</code> (Slot Interface Definition Language<br>
compiler) to parse <code>.sdi</code> files. It generates <code>.hdl</code> headers containing<br>
the command map, which is included in the build. This system allows<br>
LibreOffice to keep UI and logic declarative, flexible, and modular.</span></p>
<p><span style="font-family:monospace">You can explore the SFX2 build documentation here:<br></span>
<span style="font-family:monospace"><a href="https://git.libreoffice.org/core/+/refs/heads/master/sfx2" target="_blank">https://git.libreoffice.org/core/+/refs/heads/master/sfx2</a></span></p></div><div><span style="font-family:monospace"><br></span></div><div><span style="font-family:monospace"><br></span></div><div><span style="font-family:monospace"><b>Correct Fix: Following the Two-Tier Pattern
</b></span><p><span style="font-family:monospace"><b>Step 1: Global Registration</b> (in <code>sfx2/sdi/sfx.sdi</code>)</span></p>
<pre><code>SfxVoidItem ObjectBrowser SID_BASICIDE_OBJECT_BROWSER
()
[
AutoUpdate = FALSE,
MenuConfig = TRUE,
ToolBoxConfig = TRUE,
AccelConfig = TRUE,
GroupId = SfxGroupId::Macro;
]
</code></pre>
<p><span style="font-family:monospace"><b>Step 2: Local Shell Mapping</b> (in <code>basctl/sdi/baside.sdi</code>)</span></p>
<pre><code>SID_BASICIDE_OBJECT_BROWSER
[
ExecMethod = ExecuteGlobal;
StateMethod = GetState;
]
</code></pre><h3><br></h3><div><span class="gmail-router-outlet-wrapper gmail-ng-tns-c233927227-0"><h4 class="gmail-ng-star-inserted"><strong class="gmail-ng-star-inserted"><span class="gmail-ng-star-inserted"> Runtime Flow Validation</span></strong></h4></span><code>User Clicks <span class="gmail-hljs-selector-tag">Menu</span> Item</code></div><div><span class="gmail-router-outlet-wrapper gmail-ng-tns-c233927227-0"><pre><code> └─> menubar<span class="gmail-hljs-selector-class">.xml</span> calls <span class="gmail-hljs-selector-class">.uno</span>:ObjectBrowser
└─> SFX Dispatcher looks up SID
└─> Finds SID in sfx2/sdi/sfx.sdi
└─> Identifies shell: basctl_Shell
└─> basctl/sdi/baside.sdi mapping
└─> Calls <span class="gmail-hljs-built_in">ExecuteGlobal</span>() in basides1.cxx</code></pre></span><br></div><h3><span style="font-family:monospace">Takeaway</span></h3><p><span style="font-family:monospace">This investigation was a vital learning experience. The SDI/SFX system<br>
is a powerful architectural relic from the StarOffice era that continues<br>
to serve LibreOffice today. Understanding its separation of global vs.<br>
local command handling is essential for anyone building or extending<br>
LibreOffice UI functionality.</span></p>
<p><span class="gmail_default" style="font-family:monospace">We</span><span style="font-family:monospace"> now have a clean, working integration of the Object Browser as a first-<br>
class <code>.uno:</code> command—correctly registered in both global and local layers.</span></p></div><div><br></div><div><h3><span style="font-family:monospace">References</span></h3>
<ul><li>
<p><span style="font-family:monospace">DispatchCommands:<br></span>
<span style="font-family:monospace"><a href="https://wiki.documentfoundation.org/Development/DispatchCommands" target="_blank">https://wiki.documentfoundation.org/Development/DispatchCommands</a></span></p>
</li><li>
<p><span style="font-family:monospace">Dispatch API in SFX2 (TDF article):<br></span>
<span style="font-family:monospace"><a href="https://wiki.documentfoundation.org/Framework/Article/Implementation_of_the_Dispatch_API_In_SFX2" target="_blank">https://wiki.documentfoundation.org/Framework/Article/Implementation_of_the_Dispatch_API_In_SFX2</a></span></p>
</li><li>
<p><span style="font-family:monospace">OpenOffice.org discussion (2004):<br></span>
<span style="font-family:monospace"><a href="https://www.openoffice.org/development/digest/2004_w08.html" target="_blank">https://www.openoffice.org/development/digest/2004_w08.html</a></span></p>
</li><li>
<p><span style="font-family:monospace">Pitonyak, "OpenOffice.org Macros Explained":<br></span>
<span style="font-family:monospace"><a href="http://www.pitonyak.org/OOME_3_0.pdf" target="_blank">http://www.pitonyak.org/OOME_3_0.pdf</a></span></p>
</li><li>
<p><span style="font-family:monospace">SFX2 documentation:<br></span>
<span style="font-family:monospace"><a href="https://git.libreoffice.org/core/+/refs/heads/master/sfx2/doc/sfx2doc.html" target="_blank">https://git.libreoffice.org/core/+/refs/heads/master/sfx2/doc/sfx2doc.html</a></span></p>
</li><li>
<p><span style="font-family:monospace">Gerrit patch showing Watch Window command structure (R. Lima):<br></span>
<span style="font-family:monospace"><a href="https://gerrit.libreoffice.org/c/core/+/147305" target="_blank">https://gerrit.libreoffice.org/c/core/+/147305</a></span></p>
</li></ul></div><div><br></div><div><br></div><div><span style="font-family:monospace"><b><br></b></span></div><div><span style="font-family:monospace"><b>2. C++ Nuances & API Contracts (Compiler Errors)</b><br>This is where the most valuable learning occurred. The loplugin CI checks<br>and C++'s strict typing were invaluable mentors.<br><br><b><u>Problem:</u></b> const-Correctness in weld API.<br>The compiler rejected my OnNodeSelect handler when it was declared<br>with a const weld::TreeView&.<span class="gmail_default"> </span><u>include/vcl/weld.hxx</u><span class="gmail_default" style="font-family:comic sans ms,sans-serif"></span></span><span style="font-family:monospace"><br><br><b>Investigation:</b> I compared the weld API signatures for the two<br>signals we were using, connect_expanding and connect_selection_changed.</span></div><div><span style="font-family:monospace"><br></span></div><div><span style="font-family:monospace"><pre><code><span style="background-color:rgb(217,234,211)"><span style="background-color:rgb(255,255,255)">// Expects a Link that can handle a const iterator</span>
<span><span>void</span> <span>connect_expanding</span><span>(<span>const</span> Link<<span>const</span> TreeIter&, <span>bool</span>>& rLink)</span></span>;
<span style="background-color:rgb(255,255,255)">// Expects a Link that can handle a NON-const TreeView</span>
<span><span>void</span> <span>connect_selection_changed</span><span>(<span>const</span> Link<TreeView&, <span>void</span>>& rLink)</span></span>;</span></code></pre></span></div><div><span style="font-family:monospace"><br></span></div><div><span style="font-family:monospace"><b>Learning:</b> The API's contract is the ultimate authority. The<br>connect_selection_changed method's signature requires a handler that<br>can work with a mutable TreeView&. Even if my code doesn't modify it,<br>I must conform to the API. This is a fundamental lesson in type safety<br>and API design.<br><br><b><u>Problem:</u></b> Template Deduction Failure with std::make_shared.<br>The call std::make_shared<IdeSymbolInfo>(u"...") failed because the<br>template couldn't implicitly convert a string literal (const char16_t*)<br>to the constructor's const OUString& parameter.<br><br><b>Learning:</b> Instead of forcing the conversion at the call site, the<br>more robust and idiomatic C++ solution is to make the class itself<br>smarter.<br><br><b>Solution:</b> <span class="gmail_default">We</span> enhanced the IdeSymbolInfo struct by adding a<br>"convenience constructor" that directly accepts the native literal type:</span></div><div><span style="font-family:monospace"><pre><code style="background-color:rgb(217,234,211)">IdeSymbolInfo(const char16_t* pName, IdeSymbolKind eTheKind)
: <span>sName</span>(<span>OUString</span>(pName)), <span>eKind</span>(eTheKind) {}</code></pre></span><span style="font-family:monospace"> This encapsulates the conversion, keeps the calling code clean, and<br> resolves the template ambiguity<span class="gmail_default">.</span><br><br><b><u>Current Status: A Working but Empty UI Shell</u></b><br><br>The result of this work is a visible, integrated Object Browser window.<br>However, it is currently empty, and the UI has some predictable glitches<br>due to the lack of data.<br><br><span class="gmail_default"> </span><span style="background-color:rgb(207,226,243)">[Image of the Object Browser window in the IDE]</span><br><a href="https://bug-attachments.documentfoundation.org/attachment.cgi?id=201520" target="_blank">https://bug-attachments.documentfoundation.org/attachment.cgi?id=201520</a></span></div><div><span style="font-family:monospace"><br> The UI appears in the "View" menu and can be toggled.<br></span></div><div><br></div><div><span class="gmail_default" style="font-family:monospace"> </span><span style="font-family:monospace">The ObjectBrowser (View) successfully<span class="gmail_default"> </span>calls the IdeDataProvider (Model)<span class="gmail_default"> <br></span></span></div><div><span class="gmail_default" style="font-family:monospace"> </span><span style="font-family:monospace">on initialization to fetch and display the<span class="gmail_default"> </span>top-level nodes.</span></div><div><br><span style="font-family:monospace"></span></div><div><span style="font-family:monospace"><span class="gmail_default"> </span><span class="gmail_default"> </span>The "vanishing arrow" happens because the OnNodeExpand handler is still a <br><span class="gmail_default"> </span>stub. This will be resolved when we populate it with child nodes.<br><br><span class="gmail_default"> </span>The "two-click" focus issue is a minor polishing item we will address as <br><span class="gmail_default"> </span>we build out the interaction logic.</span></div><div><span style="font-family:monospace"><br></span></div><div><span style="font-family:monospace"><b><u>Next Steps: Populating the UI</u></b><br><br>With the shell complete, the immediate next task is to implement the data<br>connection, which will also resolve the current UI glitches.<br><br> <b>Implement Live Data Fetching:</b> The immediate next step is to replace the<br> placeholder logic in IdeDataProvider.cxx. I will port the code from my<br> successful C++ PoCs to fetch live data from theCoreReflection.<br><br> <b>Enable Lazy Loading:</b> The OnNodeExpand handler will be implemented to<br> call the data provider and populate the child nodes on demand. This will<br> make the UI interactive and fix the "vanishing arrow" issue.<br><br> <b>Measure Performance:</b> Every live data call will be wrapped in our<br> IdeTimer utility to gather the real-world performance data the mentors<br> requested.</span><br><span style="font-family:monospace"><br>This phased approach ensures we have a solid foundation. I am now focused<br>on making the browser functional and data-rich.<br><br>Thank you for the guidance that helped me navigate these technical challenges.</span></div><div><span style="font-family:monospace"><br></span></div><div><span style="font-family:monospace"><b>W<span class="gmail_default">eek 1 mail -</span></b></span></div><div><span style="font-family:monospace"><a href="https://lists.freedesktop.org/archives/libreoffice/2025-May/093264.html" target="_blank">https://lists.freedesktop.org/archives/libreoffice/2025-May/093264.html</a></span></div><div><span style="font-family:monospace"><br></span></div><div><div class="gmail_default"><span style="font-family:monospace"><b>Week 2 and 3 mail -</b></span></div><div class="gmail_default"><span style="font-family:monospace"><a href="https://lists.freedesktop.org/archives/libreoffice/2025-June/093362.html" target="_blank">https://lists.freedesktop.org/archives/libreoffice/2025-June/093362.html</a></span></div><div class="gmail_default"><span style="font-family:monospace"><br></span></div><div class="gmail_default"><span style="font-family:monospace"><b>Week 4 mail(Thread) -</b></span></div><span style="font-family:monospace"><a href="https://lists.freedesktop.org/archives/libreoffice/2025-June/093392.html" target="_blank">https://lists.freedesktop.org/archives/libreoffice/2025-June/093392.html</a></span></div><div><span style="font-family:monospace"><br></span></div><span class="gmail_signature_prefix">-- </span><br><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div><span style="font-family:monospace"><b>Regards,</b></span></div><div><span style="font-family:monospace;color:rgb(153,0,255)"><b>Devansh</b></span><br></div></div></div></div>
</div>