MailJD nbsp;·nbsp; Test Dashboard nbsp;·nbsp; Coverage
LCOV - code coverage report
Current view: top level - ui - CommandBar.h (source / functions) Coverage Total Hit
Test: MailJD Coverage (Unit + E2E) Lines: 100.0 % 2 2
Test Date: 2026-06-21 21:10:19 Functions: 100.0 % 2 2
Legend: Lines:     hit not hit

            Line data    Source code
       1              : #pragma once
       2              : 
       3              : #include <QWidget>
       4              : 
       5              : class QLabel;
       6              : class QLineEdit;
       7              : class QListWidget;
       8              : class QPropertyAnimation;
       9              : 
      10              : // CommandBar implements a Tridactyl/Vimperator-style command console at the
      11              : // bottom of the main window. It supports multiple input modes:
      12              : //
      13              : //   Command      – ":" prefix, execute named commands with autocomplete
      14              : //   Filter       – "/" prefix, real-time text filter on the mail list
      15              : //   FolderSwitch – "b:" prefix, pick a folder to switch to (with filtering)
      16              : //   MoveToFolder – "s→" prefix, pick a folder to move selected mails into
      17              : //
      18              : // The bar is normally hidden and slides in from the bottom when activated.
      19              : // Escape closes it and returns focus to the previous widget.
      20              : class CommandBar : public QWidget {
      21          330 :   Q_OBJECT
      22              : 
      23              : public:
      24              :   enum Mode { Command, Filter, FolderSwitch, MoveToFolder, Search, AddTask };
      25              : 
      26              :   explicit CommandBar(QWidget *parent = nullptr);
      27              : 
      28              :   // Open the command bar in the given mode.
      29              :   void activate(Mode mode);
      30              : 
      31              :   // Close the command bar and return focus to the previous widget.
      32              :   void deactivate();
      33              : 
      34              :   // Sprint 75: Host the bar as an overlay child of `host` instead of a
      35              :   // layout child. The bar reparents to `host`, installs a Resize event
      36              :   // filter on it, and docks at the bottom (anchored via m_overlayInset).
      37              :   // When the host is nullptr (or never set), activate()/deactivate()
      38              :   // fall back to the legacy layout-driven behaviour so direct unit
      39              :   // tests that do not provide a host stay green.
      40              :   void setOverlayHost(QWidget *host);
      41              : 
      42              :   // Set the list of available folder paths (for FolderSwitch / MoveToFolder).
      43              :   void setFolderList(const QStringList &folders);
      44              : 
      45              :   // Set the list of available commands (for Command mode autocomplete).
      46              :   void setCommandList(const QStringList &commands);
      47              : 
      48              :   // T-180: Set search results for display in the suggestion list.
      49              :   void setSearchResults(const QStringList &results);
      50              : 
      51              :   // T-537: Set calendar list for AddTask mode autocomplete
      52              :   void setCalendarList(const QStringList &calendars);
      53              : 
      54              :   bool isActive() const;
      55           51 :   Mode currentMode() const { return m_mode; }
      56              : 
      57              :   // Sprint 70: layout-driven vertical extent. Returns bar + suggestions
      58              :   // + real layout overhead, capped at 10 visible items. The slide-in
      59              :   // animation reads the same value via computeTargetHeight().
      60              :   QSize sizeHint() const override;
      61              : 
      62              :   // Sprint 59 (U3): set/read the raw input text without changing the mode and
      63              :   // without emitting input signals. Used to keep the search bar in sync with
      64              :   // the SearchPanel (both show the same canonical query). The MainWindow sync
      65              :   // path — not the bar — decides when to refresh suggestions or run a search,
      66              :   // which keeps CommandBar a dumb input widget.
      67              :   void setInputText(const QString &text);
      68              :   QString inputText() const;
      69              : 
      70              : signals:
      71              :   // Emitted when the user presses Enter in Command mode.
      72              :   void commandSubmitted(const QString &cmd);
      73              : 
      74              :   // Emitted on every keystroke in Filter mode (real-time).
      75              :   void filterTextChanged(const QString &text);
      76              : 
      77              :   // Emitted when the user selects a folder (FolderSwitch or MoveToFolder).
      78              :   void folderSelected(CommandBar::Mode mode, const QString &folderPath);
      79              : 
      80              :   // Emitted when the user presses Escape or the bar is deactivated.
      81              :   void cancelled();
      82              : 
      83              :   // Emitted when the bar opens or closes (for shortcut enable/disable).
      84              :   void activeChanged(bool active);
      85              : 
      86              :   // Emitted in Filter mode when arrow keys are pressed (for mail navigation).
      87              :   void navigateMailList(int delta); // +1 = next, -1 = prev
      88              : 
      89              :   // T-180: Emitted on every keystroke in Search mode (debounced).
      90              :   void searchQueryChanged(const QString &query);
      91              : 
      92              :   // T-180: Emitted when the user selects a search result (Enter/click).
      93              :   void searchResultSelected(int index);
      94              : 
      95              :   // Emitted when the user presses Enter in Search mode to confirm the query.
      96              :   void searchSubmitted(const QString &query);
      97              : 
      98              :   // T-537: Emitted when a task is submitted via AddTask mode
      99              :   void taskSubmitted(const QString &title, const QString &calendarPath,
     100              :                      const QDateTime &due, int priority);
     101              : 
     102              : private slots:
     103              :   void onTextChanged(const QString &text);
     104              :   void onReturnPressed();
     105              : 
     106              : protected:
     107              :   bool eventFilter(QObject *obj, QEvent *event) override;
     108              :   void changeEvent(QEvent *event) override;
     109              : 
     110              : private:
     111              :   void setupUi();
     112              :   void updateSuggestions(const QString &text);
     113              :   void selectSuggestion(int delta); // +1 = next, -1 = prev
     114              :   void acceptCurrentSuggestion();
     115              :   QString prefixForMode(Mode mode) const;
     116              :   // T-76.B3: single source for the per-mode input placeholder so both
     117              :   // activate() and retranslateUi() stay in sync.
     118              :   QString placeholderForMode(Mode mode) const;
     119              :   void retranslateUi();
     120              : 
     121              :   // Sprint 70: single source of truth for the CommandBar's vertical
     122              :   // extent. Uses QListWidget::sizeHintForRow(0) (real rendered row
     123              :   // height including QSS padding) plus the actual outer-layout overhead
     124              :   // (contentsMargins + spacing + list frame) and a 10-item ceiling.
     125              :   // Called by both sizeHint() and the slide animation end-value.
     126              :   int computeTargetHeight() const;
     127              : 
     128              :   // Sprint 75: reposition the bar inside m_host and raise it. If the
     129              :   // slide animation is still running (e.g. a live window resize during
     130              :   // slide-in), stop it and snap to the recomputed bottom-anchored
     131              :   // geometry so the running animation cannot overwrite the new geometry
     132              :   // on its next tick. No-op without a host.
     133              :   void positionOverlay();
     134              : 
     135              :   // Sprint 75: apply the current computeTargetHeight() to the bar. With
     136              :   // a host this means setFixedHeight() + positionOverlay(); without a
     137              :   // host it falls back to setMaximumHeight() so the legacy layout-driven
     138              :   // path keeps working. Centralised replacement for every previous
     139              :   // `setMaximumHeight(computeTargetHeight())` site.
     140              :   void adjustOverlayHeight();
     141              : 
     142              :   // UI elements
     143              :   QLabel *m_prefixLabel = nullptr;
     144              :   QLineEdit *m_input = nullptr;
     145              :   QListWidget *m_suggestionList = nullptr;
     146              : 
     147              :   // Animation
     148              :   QPropertyAnimation *m_slideAnim = nullptr;
     149              : 
     150              :   // Sprint 75: overlay host (the central container). When set, the bar
     151              :   // is reparented to it and positioned as an overlay (bottom-anchored,
     152              :   // inset laterally). Nullptr → legacy layout-driven fallback path.
     153              :   QWidget *m_host = nullptr;
     154              :   // Sprint 75: lateral and bottom inset between the bar and the host.
     155              :   // 0 = Tridactyl-style full-width panel flush with the bottom and the
     156              :   // host's lateral edges. The previous Nostalgy-style card design used
     157              :   // 4 (matching outerLayout contentsMargins); the redesign removed the
     158              :   // card chrome so the panel goes edge-to-edge.
     159              :   int m_overlayInset = 0;
     160              : 
     161              :   // State
     162              :   Mode m_mode = Command;
     163              :   bool m_active = false;
     164              :   bool m_showingFilterHelp = false; // True when showing filter prefix suggestions
     165              :   bool m_userNavigated = false;     // True when user explicitly used arrow keys
     166              :   QWidget *m_previousFocus = nullptr;
     167              : 
     168              :   // Data
     169              :   QStringList m_folderPaths;
     170              :   QStringList m_commandNames;
     171              :   QStringList m_calendarPaths; // T-537: for AddTask autocomplete
     172              : };
        

Generated by: LCOV version 2.0-1