QtPass Developer documentation
QtPass test coverage
Current view: top level - src/mainwindow.h Coverage Total Hit
Test: QtPass Lines: 100.0 % 1 1
Test Date: 2026-11-14 13:19:18 Functions: - 0 0

            Line data    Source code
       1              : // SPDX-FileCopyrightText: 2014 Anne Jan Brouwer
       2              : // SPDX-License-Identifier: GPL-3.0-or-later
       3              : /**
       4              :  * @file
       5              :  * @brief MainWindow: the main application window (tree, toolbar, search,
       6              :  *        status bar, process output dock) and the glue between the password
       7              :  *        store backends and the widgets.
       8              :  */
       9              : #ifndef SRC_MAINWINDOW_H_
      10              : #define SRC_MAINWINDOW_H_
      11              : 
      12              : #include "appsettings.h"
      13              : #include "enums.h"
      14              : #include "grepsearchcontroller.h"
      15              : #include "storetree.h"
      16              : 
      17              : #include <QDialog>
      18              : #include <QMainWindow>
      19              : #include <QPointer>
      20              : #include <QProcess>
      21              : #include <QTimer>
      22              : 
      23              : #ifdef __APPLE__
      24              : /**
      25              :  * @brief Qt-internal switch, declared here because Qt does not export it in
      26              :  *        a header: enables the automatic `&` mnemonics in menu titles that
      27              :  *        are off by default on macOS. Called once in the constructor.
      28              :  * @param b true to enable auto-mnemonics.
      29              :  * @see https://doc.qt.io/qt-6/qkeysequence.html#qt_set_sequence_auto_mnemonic
      30              :  */
      31              : void qt_set_sequence_auto_mnemonic(bool b);
      32              : #endif
      33              : 
      34              : namespace Ui {
      35              : class MainWindow;
      36              : class Pass;
      37              : } // namespace Ui
      38              : 
      39              : class Pass;
      40              : class ProcessOutputPanel;
      41              : class QProgressDialog;
      42              : class QTreeWidgetItem;
      43              : class QtPass;
      44              : class PasswordDisplayPanel;
      45              : class TrayIcon;
      46              : 
      47              : /**
      48              :  * @class MainWindow
      49              :  * @ingroup ui
      50              :  * @brief Main application window orchestrating UI, user interactions, and
      51              :  * external process handlers.
      52              :  *
      53              :  * Provides the central interface for managing items, folders, passwords, and
      54              :  * OTPs; coordinates UI components (toolbars, panels, dialogs, status/tray),
      55              :  * selection and navigation in the underlying file/store models, and lifecycle
      56              :  * interactions with external handlers (e.g., pass, Git, GPG key generation,
      57              :  * OTP).
      58              :  */
      59              : class MainWindow : public QMainWindow {
      60          341 :   Q_OBJECT
      61              : 
      62              : public:
      63              :   /**
      64              :    * @brief Construct the main window.
      65              :    * @param searchText Initial search text to populate the search field.
      66              :    * @param parent Optional parent widget.
      67              :    */
      68              :   explicit MainWindow(const QString &searchText = QString(),
      69              :                       QWidget *parent = nullptr);
      70              :   /**
      71              :    * @brief Save the window state (a quit from the tray menu or a SIGTERM
      72              :    *        never delivers closeEvent()) and delete the QtPass glue.
      73              :    */
      74              :   ~MainWindow() override;
      75              : 
      76              :   /**
      77              :    * @brief Restore window geometry and state from saved settings.
      78              :    */
      79              :   void restoreWindow();
      80              : 
      81              :   /**
      82              :    * @brief Open the configuration dialog.
      83              :    *
      84              :    * On a fresh start the first-run wizard runs before the dialog is shown.
      85              :    * Accepting the dialog does not guarantee a usable configuration: the OK
      86              :    * button is not gated on Util::configIsValid(), so QtPass::init() uses the
      87              :    * return value to decide whether to ask again or to give up.
      88              :    * @return true when the dialog was accepted, false when it was cancelled.
      89              :    */
      90              :   auto config() -> bool;
      91              : 
      92              :   /**
      93              :    * @brief Enable or disable the main UI elements.
      94              :    * @param state true to enable, false to disable.
      95              :    */
      96              :   void setUiElementsEnabled(bool state);
      97              : 
      98              :   /**
      99              :    * @brief Display a transient message in the text panel.
     100              :    * @param text Message text to display.
     101              :    * @param isError true to style the message as an error.
     102              :    * @param isHtml true if text contains HTML markup.
     103              :    */
     104              :   void flashText(const QString &text, const bool isError,
     105              :                  const bool isHtml = false);
     106              : 
     107              :   /**
     108              :    * @brief Return the currently selected index in the tree view.
     109              :    * @return Current QModelIndex.
     110              :    */
     111              :   auto getCurrentTreeViewIndex() -> QModelIndex;
     112              : 
     113              :   /**
     114              :    * @brief Return whether startup configuration succeeded.
     115              :    *
     116              :    * Reflects the result of the initial configuration check performed in the
     117              :    * constructor (QtPass::init()). When it is false the application cannot be
     118              :    * used (e.g. the user cancelled the first-run wizard), and main() should
     119              :    * exit before ever showing the window.
     120              :    * @return true when QtPass::init() reported a working configuration.
     121              :    */
     122              :   auto initSucceeded() const -> bool { return m_initSucceeded; }
     123              : 
     124              : protected:
     125              :   /**
     126              :    * @brief Save window state and geometry on close.
     127              :    * @param event The close event.
     128              :    */
     129              :   void closeEvent(QCloseEvent *event) override;
     130              :   /**
     131              :    * @brief Handle keyboard shortcuts.
     132              :    * @param event The key press event.
     133              :    */
     134              :   void keyPressEvent(QKeyEvent *event) override;
     135              :   /**
     136              :    * @brief React to language or window state changes.
     137              :    * @param event The change event.
     138              :    */
     139              :   void changeEvent(QEvent *event) override;
     140              :   /**
     141              :    * @brief Notice an application palette change, the theme switch that
     142              :    *        makes a style-imposed bar palette suspect; see
     143              :    *        dropStaleToolsAreaPalettes().
     144              :    * @param event The event.
     145              :    * @return true if the event was consumed.
     146              :    */
     147              :   auto event(QEvent *event) -> bool override;
     148              :   /**
     149              :    * @brief First-show hook used to focus the search input once the window
     150              :    *        is actually mapped (avoids races with timers fired before show).
     151              :    * @param event The show event.
     152              :    */
     153              :   void showEvent(QShowEvent *event) override;
     154              :   /**
     155              :    * @brief Filter events from watched objects.
     156              :    * @param obj The object that received the event.
     157              :    * @param event The event to filter.
     158              :    * @return true if the event was consumed.
     159              :    */
     160              :   auto eventFilter(QObject *obj, QEvent *event) -> bool override;
     161              : 
     162              : public slots:
     163              :   /**
     164              :    * @brief Clear the current tree view selection.
     165              :    */
     166              :   void deselect();
     167              : 
     168              :   /**
     169              :    * @brief Handle an incoming inter-process message (single-instance mode).
     170              :    * @param message Message string received from another instance.
     171              :    */
     172              :   void messageAvailable(const QString &message);
     173              : 
     174              :   /**
     175              :    * @brief Handle generic process output for display in output panel.
     176              :    * @param output Process output text.
     177              :    * @param isError true if output should be styled as error (red).
     178              :    * @param pid Identifier of the originating subprocess (for the label
     179              :    *            prefix); defaults to Enums::INVALID for unlabelled output.
     180              :    */
     181              :   void onProcessOutput(const QString &output, bool isError,
     182              :                        Enums::PROCESS pid = Enums::INVALID);
     183              : 
     184              :   /**
     185              :    * @brief Display a critical error dialog.
     186              :    * @param title Dialog title.
     187              :    * @param msg Error message body.
     188              :    */
     189              :   void critical(const QString &title, const QString &msg);
     190              : 
     191              :   /**
     192              :    * @brief Slot called when an external process wrapper has started.
     193              :    */
     194              :   void executeWrapperStarted();
     195              : 
     196              :   /**
     197              :    * @brief Show a message in the status bar for the given duration.
     198              :    * @param msg Message to display.
     199              :    * @param timeout Duration in milliseconds (default 2000).
     200              :    */
     201              :   void showStatusMessage(const QString &msg, int timeout = 2000);
     202              : 
     203              :   /**
     204              :    * @brief Render a decrypted entry: fields into the display panel, the rest
     205              :    *        into the text browser, and the password onto the clipboard when
     206              :    *        "Always copy" is set. Decrypts of any entry but the one the panel
     207              :    *        last asked to show (m_shownFile) are dropped.
     208              :    * @param output Decrypted password file content.
     209              :    * @param file Entry the content belongs to; empty for legacy callers that
     210              :    *        do not name it, which always repaints.
     211              :    */
     212              :   void passShowHandler(const QString &output, const QString &file = QString());
     213              : 
     214              :   /**
     215              :    * @brief Generate a one-time password from decrypted content and copy it.
     216              :    *        Ignores decrypts of anything but the entry onOtp() asked for.
     217              :    * @param output Decrypted entry content.
     218              :    * @param file Entry the content belongs to.
     219              :    */
     220              :   void otpFromFileToClipboard(const QString &output, const QString &file);
     221              : 
     222              :   /**
     223              :    * @brief Copy the first line of a decrypted entry (Ctrl+C). Ignores
     224              :    *        decrypts of anything but the entry copyPasswordFromTreeview()
     225              :    *        asked for; an otpauth:// first line is refused.
     226              :    * @param text Decrypted entry content.
     227              :    * @param file Entry the content belongs to.
     228              :    */
     229              :   void passwordFromFileToClipboard(const QString &text, const QString &file);
     230              : 
     231              :   /**
     232              :    * @brief Forget the pending OTP and copy requests.
     233              :    *
     234              :    * A failed decrypt never emits Pass::finishedShow; without this a later
     235              :    * decrypt of the same entry (the user retrying) would be taken as the
     236              :    * answer to a request the user has long given up on.
     237              :    */
     238              :   void cancelOtpRequest();
     239              :   /**
     240              :    * @brief An operation ended in an error before or instead of a result:
     241              :    * forget the pending requests and what the panel was about to show.
     242              :    *
     243              :    * Connected to Pass::processErrorExit. A Show that never ran (a linked
     244              :    * entry refused at the store boundary) leaves the previous entry's fields
     245              :    * on the panel under the new name otherwise, and onOtp()'s fast path would
     246              :    * take that entry's code for the refused one.
     247              :    */
     248              :   void onOperationError();
     249              : 
     250              :   /**
     251              :    * @brief Drop a style-imposed menu bar or toolbar palette that belongs to
     252              :    * the other theme (Breeze header palette after a light/dark switch).
     253              :    */
     254              :   void dropStaleToolsAreaPalettes();
     255              : 
     256              :   /**
     257              :    * @brief Handle results from a completed grep search.
     258              :    * @param results List of file/match pairs from the grep operation.
     259              :    */
     260              :   void onGrepFinished(const QList<QPair<QString, QStringList>> &results);
     261              : 
     262              :   /**
     263              :    * @brief Trigger a git push operation.
     264              :    */
     265              :   void onPush();
     266              : 
     267              :   /**
     268              :    * @brief Handle a click on an item in the tree view.
     269              :    * @param index The model index that was clicked.
     270              :    */
     271              :   void on_treeView_clicked(const QModelIndex &index);
     272              : 
     273              :   /**
     274              :    * @brief Begin a re-encryption pass on the current path.
     275              :    *
     276              :    * Disables the UI, shows a cancellable progress dialog and keeps both in
     277              :    * place until endReencryptPath(): while the worker runs, unrelated
     278              :    * completions must not re-enable the interface (see setUiElementsEnabled).
     279              :    */
     280              :   void startReencryptPath();
     281              : 
     282              :   /**
     283              :    * @brief Update the re-encryption progress dialog.
     284              :    * @param current Files checked so far.
     285              :    * @param total Files found under the re-encrypted folder.
     286              :    */
     287              :   void reencryptProgress(int current, int total);
     288              : 
     289              :   /**
     290              :    * @brief Finish a re-encryption pass on the current path.
     291              :    */
     292              :   void endReencryptPath();
     293              : 
     294              : private slots:
     295              :   /**
     296              :    * @brief Fill the profile box from the settings, the active profile
     297              :    * selected, without switching profiles while doing so.
     298              :    */
     299              :   void updateProfileBox();
     300              :   /**
     301              :    * @brief Enable the profile box only when there is more than one profile,
     302              :    * the interface is enabled and the backend is idle.
     303              :    */
     304              :   void updateProfileBoxEnabled();
     305              :   /**
     306              :    * @brief The content-search toggle changed: switch the search box between
     307              :    *        name filtering and regex content search, clearing the query, the
     308              :    *        tree filter and any results; leaving while a search runs cancels
     309              :    *        it.
     310              :    * @param checked true when content search was switched on.
     311              :    */
     312              :   void on_grepButton_toggled(bool checked);
     313              :   /**
     314              :    * @brief A content-search result was clicked: select the entry in the
     315              :    *        tree, show it, and go back to the tree (clearing the results when
     316              :    *        content is hidden or the panel autoclears).
     317              :    * @param item The clicked entry or match line; its UserRole holds the
     318              :    *        entry name.
     319              :    * @param column Unused.
     320              :    */
     321              :   void on_grepResultsList_itemClicked(QTreeWidgetItem *item, int column);
     322              :   /** @brief Toolbar/context-menu "Add password": open PasswordDialog for a
     323              :    *         new entry in the current folder. */
     324              :   void addPassword();
     325              :   /**
     326              :    * @brief Toolbar/context-menu "Add folder": ask for a name, create the
     327              :    *        folder under the current one (refusing paths that escape the
     328              :    *        store) and seed its `.gpg-id` from the parent when configured.
     329              :    */
     330              :   void addFolder();
     331              :   /** @brief Toolbar "Edit" or a double-click: editPassword() on the current
     332              :    *         entry. */
     333              :   void onEdit();
     334              :   /**
     335              :    * @brief Toolbar "Delete" or the Delete key: confirm, then remove the
     336              :    *        current entry or folder. Nothing selected is a no-op (#556); a
     337              :    *        linked folder only loses its link, a folder behind a link is
     338              :    *        refused.
     339              :    */
     340              :   void onDelete();
     341              :   /**
     342              :    * @brief Toolbar "OTP": copy the current entry's one-time code. Uses the
     343              :    *        code the panel already shows for this entry; otherwise decrypts
     344              :    *        once and lets otpFromFileToClipboard() finish.
     345              :    */
     346              :   void onOtp();
     347              :   /**
     348              :    * @brief Toolbar "Update": git pull.
     349              :    * @param block true to pull synchronously (before opening an edit dialog
     350              :    *        with auto-pull on).
     351              :    */
     352              :   void onUpdate(bool block = false);
     353              :   /**
     354              :    * @brief Toolbar/context-menu "Users": open UsersDialog for the current
     355              :    *        folder, unless it lies behind a link.
     356              :    */
     357              :   void onUsers();
     358              :   /** @brief Toolbar "Config": config(), ignoring its result. */
     359              :   void onConfig();
     360              :   /**
     361              :    * @brief Show the About box: version, project link, licence.
     362              :    */
     363              :   void showAbout();
     364              :   /**
     365              :    * @brief A double-click on a tree entry opens it for editing; folders are
     366              :    *        left to the view.
     367              :    * @param index The double-clicked proxy index.
     368              :    */
     369              :   void on_treeView_doubleClicked(const QModelIndex &index);
     370              :   /**
     371              :    * @brief Empty the display panel and the text browser, and leave content
     372              :    *        search if its results were showing. Runs on the autoclear timer.
     373              :    * @param notify true to show "Password and content hidden" in the browser,
     374              :    *        false to leave it blank.
     375              :    */
     376              :   void clearPanel(bool notify = true);
     377              :   /**
     378              :    * @brief The search box changed (name filtering only): drop the pending
     379              :    *        decrypt and the panel, expand the tree and restart searchTimer.
     380              :    * @param arg1 The new text.
     381              :    */
     382              :   void on_lineEdit_textChanged(const QString &arg1);
     383              :   /**
     384              :    * @brief Enter in the search box: in content-search mode start (or, for an
     385              :    *        empty query, cancel) the grep; otherwise select and show the first
     386              :    *        matching entry.
     387              :    */
     388              :   void on_lineEdit_returnPressed();
     389              :   /**
     390              :    * @brief The user picked another profile: save its store, key and Git
     391              :    *        flags as the active settings, re-root the tree and clear the
     392              :    *        selection. Ignored during the fresh start and reverted while an
     393              :    *        operation runs.
     394              :    * @param name The chosen profile name.
     395              :    */
     396              :   void on_profileBox_currentTextChanged(const QString &name);
     397              :   /**
     398              :    * @brief Build and show the tree's context menu for the item under the
     399              :    *        cursor: folder actions (open, add, users, rename, Share) or entry
     400              :    *        actions (edit, rename), plus Delete.
     401              :    * @param pos Viewport position of the right-click.
     402              :    */
     403              :   void showContextMenu(const QPoint &pos);
     404              :   /**
     405              :    * @brief Add the Share submenu for the folder under the cursor: the
     406              :    * entries are enabled only where a recipient list and a usable gpg or
     407              :    * pass make them work.
     408              :    * @param contextMenu The menu being built, which owns the submenu.
     409              :    * @param s The settings the executables and the store come from.
     410              :    */
     411              :   void addShareMenu(QMenu &contextMenu, const AppSettings &s);
     412              :   /**
     413              :    * @brief Ask before deleting an entry or a folder, naming what goes and
     414              :    * warning when the folder holds anything but entries.
     415              :    * @param file Store-relative path being deleted.
     416              :    * @param isDir Whether it is a folder.
     417              :    * @return Whether the user said yes.
     418              :    */
     419              :   auto confirmDeletion(const QString &file, bool isDir) -> bool;
     420              :   /**
     421              :    * @brief Ask before removing a folder that is a link, which takes the link
     422              :    * and leaves what it points to.
     423              :    * @param file Store-relative path of the link.
     424              :    * @return Whether the user said yes.
     425              :    */
     426              :   auto confirmLinkRemoval(const QString &file) -> bool;
     427              :   /**
     428              :    * @brief Show the text browser's standard context menu, reparented to the
     429              :    *        window so the browser's stylesheet does not bleed into it.
     430              :    * @param pos Viewport position of the right-click.
     431              :    */
     432              :   void showBrowserContextMenu(const QPoint &pos);
     433              :   /** @brief Context menu "Open folder with file manager" on the current
     434              :    *         folder. */
     435              :   void openFolder();
     436              :   /**
     437              :    * @brief Context menu "Rename folder": ask for a new name and Move the
     438              :    *        current folder, refusing a target outside the store.
     439              :    */
     440              :   void renameFolder();
     441              :   /**
     442              :    * @brief Open PasswordDialog on an existing entry, after a blocking pull
     443              :    *        when auto-pull is on. Releases the panel's claim on the next
     444              :    *        decrypt so the dialog's own Show does not repaint or copy.
     445              :    * @param file Store-relative entry name; empty is a no-op.
     446              :    */
     447              :   void editPassword(const QString &file);
     448              :   /**
     449              :    * @brief Context menu "Rename password": ask for a new name and Move the
     450              :    *        current entry within its folder, refusing a target outside the
     451              :    *        store.
     452              :    */
     453              :   void renamePassword();
     454              :   /**
     455              :    * @brief Select-all and focus the search box once the window is visible;
     456              :    *        sets m_firstShowCompleted only on success so showEvent() retries.
     457              :    *        Looks the widget up by name because setWindowFlags() can rebuild
     458              :    *        it under `ui->lineEdit` (Qt 6.11).
     459              :    */
     460              :   void focusInput();
     461              :   /**
     462              :    * @brief Ctrl+C on the tree: decrypt the current entry and let
     463              :    *        passwordFromFileToClipboard() copy its first line. The newest
     464              :    *        request wins (m_copyRequestFile).
     465              :    */
     466              :   void copyPasswordFromTreeview();
     467              :   /**
     468              :    * @brief searchTimer fired: filter the tree on the typed words (matched
     469              :    *        literally, in order, case-insensitively) and select the first
     470              :    *        match; an empty query collapses the tree and deselects.
     471              :    */
     472              :   void onTimeoutSearch();
     473              : 
     474              : private:
     475              :   /**
     476              :    * @brief The UI-neutral glue to the backends (output, status, clipboard,
     477              :    *        QR codes); created in the constructor, deleted in the destructor.
     478              :    */
     479              :   QtPass *m_qtPass;
     480              :   /** @brief The widgets generated from mainwindow.ui. */
     481              :   QScopedPointer<Ui::MainWindow> ui;
     482              :   /** @brief Mode/busy/cancelled state of the content search. */
     483              :   GrepSearchController m_grep;
     484              :   /**
     485              :    * @brief Renders decrypted fields into the grid; created in
     486              :    *        initDisplayPanel(), parented to this window.
     487              :    */
     488              :   PasswordDisplayPanel *m_displayPanel = nullptr;
     489              :   /**
     490              :    * @brief Set once focusInput() has actually focused the search box, so
     491              :    *        later show events leave the focus alone.
     492              :    */
     493              :   bool m_firstShowCompleted = false;
     494              :   /// Whether the application palette changed in this window's lifetime. A
     495              :   /// header palette a style stamps on the bars is only suspect after that:
     496              :   /// at startup the style's colours are fresh, however far from the window
     497              :   /// colour a scheme puts its header.
     498              :   bool m_themeSwitched = false;
     499              :   /// Entry the display panel is currently rendering. The tree's currentIndex
     500              :   /// can move without a repaint (arrow keys and right-click do not emit
     501              :   /// QTreeView::clicked), so onOtp() must not assume the visible code belongs
     502              :   /// to the selected entry.
     503              :   QString m_shownFile;
     504              :   /// Entry the in-flight OTP request asked for; empty when none. finishedShow
     505              :   /// names its file, so otpFromFileToClipboard() simply ignores everything
     506              :   /// else and passShowHandler() skips the password copy for this one.
     507              :   QString m_otpRequestFile;
     508              :   /// Entry the in-flight Ctrl+C request asked for; empty when none. Each
     509              :   /// finishedShow is matched to it by file, so a second Ctrl+C on another
     510              :   /// entry just replaces the request instead of racing it.
     511              :   QString m_copyRequestFile;
     512              :   /// The process output console, a QDockWidget at the bottom dock area
     513              :   /// created in initProcessOutput(). It isn't part of the .ui because uic
     514              :   /// places its QMainWindow children in centralWidget / statusBar / menuBar /
     515              :   /// toolBars / dock-widget slots only — a sibling widget at the QMainWindow
     516              :   /// level isn't laid out and ends up obscuring the centralWidget. See #1192
     517              :   /// for the symptom.
     518              :   ProcessOutputPanel *m_processOutput = nullptr;
     519              :   /// The store as shown in the tree: models, view setup, path mapping.
     520              :   StoreTree *m_tree = nullptr;
     521              :   /// Single-shot timer that runs clearPanel() "Autoclear panel" seconds
     522              :   /// after an entry was shown.
     523              :   QTimer clearPanelTimer, searchTimer; ///< searchTimer: single-shot 350 ms
     524              :                                        ///< debounce between typing in the
     525              :                                        ///< search box and onTimeoutSearch().
     526              :   /// Re-enables the UI if a backend operation disables it but never reports
     527              :   /// completion (see setUiElementsEnabled); armed whenever the UI is
     528              :   /// disabled, stopped when it is enabled again.
     529              :   QTimer m_uiWatchdog;
     530              :   /// Interval of m_uiWatchdog in milliseconds.
     531              :   static constexpr int UiWatchdogMs = 30000;
     532              :   /// Progress/cancel dialog shown between startReencryptPath() and
     533              :   /// endReencryptPath(); QPointer so a closed dialog reads back as null.
     534              :   QPointer<QProgressDialog> m_reencryptProgress;
     535              :   /// True between startReencryptPath() and endReencryptPath(). While set,
     536              :   /// setUiElementsEnabled(true) is ignored so the git completions queued by
     537              :   /// Init/Move/Copy (or the UI watchdog) cannot re-enable the interface
     538              :   /// while the re-encryption worker is still rewriting files.
     539              :   bool m_reencryptRunning = false;
     540              :   /// What setUiElementsEnabled() last set: updateProfileBox() keeps the
     541              :   /// profile box disabled while an operation runs.
     542              :   bool m_uiEnabled = true;
     543              :   /// The system tray icon; null until initTrayIcon() creates it when the
     544              :   /// setting is on, deleted again by destroyTrayIcon() when it is turned off
     545              :   /// or no tray is available.
     546              :   TrayIcon *m_tray{};
     547              :   /// Whether the constructor ended with a usable configuration; main()
     548              :   /// consults it via initSucceeded() to decide whether the application should
     549              :   /// start at all.
     550              :   bool m_initSucceeded = false;
     551              :   /// No usable configuration has been accepted yet: config() runs the
     552              :   /// first-run wizard and defaults to pass when it is installed.
     553              :   bool m_freshStart = true;
     554              : 
     555              :   /// Wire the toolbar and menu actions to their slots, set their icons, and
     556              :   /// set up the "Show menu bar" toggle with its MenuBarPeek (not on macOS).
     557              :   void initToolBarButtons();
     558              :   /// Welcome message and the permanent logo in the status bar.
     559              :   void initStatusBar();
     560              :   /// Connect QtPass's and both backends' signals (the active backend can
     561              :   /// change through the configuration dialog without a restart).
     562              :   void connectBackends();
     563              :   /// Font, wrapping and link handling of the text browser, per the settings.
     564              :   void initTextBrowser();
     565              :   /// The grid of decrypted fields and what its buttons ask for.
     566              :   void initDisplayPanel();
     567              :   /// The panel-clear and search timers, and the watchdog that re-enables
     568              :   /// the UI when an operation never signals its end.
     569              :   void initTimers();
     570              :   /// The Process Output dock, its Settings-menu toggle, and the feed of
     571              :   /// non-secret process output into it.
     572              :   void initProcessOutput();
     573              :   /**
     574              :    * @brief Connect the signals of one backend that the window answers
     575              :    *        itself: errors, critical messages, wrapper start, idle, status,
     576              :    *        finishedShow (panel, OTP and Ctrl+C handlers) and finishedGrep.
     577              :    * @param pass The backend; both are connected, see connectBackends().
     578              :    */
     579              :   void connectPassSignals(Pass *pass);
     580              : 
     581              :   /// Make the first entry (depth first) under the store root current.
     582              :   void selectFirstFile();
     583              :   /**
     584              :    * @brief Depth-first search for the first entry under a folder.
     585              :    * @param parentIndex Proxy index of the folder to search.
     586              :    * @return Proxy index of the first file, or invalid when there is none.
     587              :    */
     588              :   auto firstFile(QModelIndex parentIndex) -> QModelIndex;
     589              :   /**
     590              :    * @brief StoreTree::fileFor() on the tree.
     591              :    * @param index Proxy index.
     592              :    * @param forPass true for the store-relative entry name, false for the
     593              :    *        absolute .gpg path.
     594              :    * @return Entry name or path; empty for a folder or invalid index.
     595              :    */
     596              :   auto getFile(const QModelIndex &index, bool forPass) -> QString;
     597              :   /**
     598              :    * @brief Run PasswordDialog for a new or existing entry. For a new one the
     599              :    *        dialog gets the store's real folders (current one preselected) and
     600              :    *        the `.templates`, if any.
     601              :    * @param file Store-relative entry name; empty when creating.
     602              :    * @param isNew true to create, false to edit @p file.
     603              :    */
     604              :   void setPassword(const QString &file, bool isNew = true);
     605              :   /**
     606              :    * @brief Guard the input dialogs (create, move, rename) against names like
     607              :    *        `../../etc/passwd` or absolute paths escaping the store root; warns
     608              :    *        the user when refusing.
     609              :    * @param candidate Path the user asked for.
     610              :    * @return true when it resolves inside the store.
     611              :    */
     612              :   auto confirmPathInStore(const QString &candidate) -> bool;
     613              : 
     614              :   /**
     615              :    * @brief Create m_tray and add the menu bar toggle to its menu; gives up
     616              :    *        (m_tray stays null) when no system tray is available.
     617              :    */
     618              :   void initTrayIcon();
     619              :   /// Delete m_tray and reset it to null.
     620              :   void destroyTrayIcon();
     621              :   /**
     622              :    * @brief Share menu "Re-encrypt all passwords": confirm, lock the UI via
     623              :    *        startReencryptPath() and have ImitatePass rewrite every entry
     624              :    *        under @p dir for the recipients in its `.gpg-id`.
     625              :    * @param dir Absolute folder; refused when missing or behind a link.
     626              :    */
     627              :   void reencryptPath(const QString &dir);
     628              :   /**
     629              :    * @brief Share menu "Export my public key": run `gpg --armor --export` for
     630              :    *        the configured signing key and show the result in
     631              :    *        ExportPublicKeyDialog; explains what to do when no key is set.
     632              :    */
     633              :   void exportPublicKey();
     634              :   /**
     635              :    * @brief Share menu "Add recipient": open UsersDialog for @p dir (keys
     636              :    *        already in the keyring only).
     637              :    * @param dir Absolute folder; refused when behind a link.
     638              :    */
     639              :   void addRecipient(const QString &dir);
     640              :   /**
     641              :    * @brief Refuse, with a message, a tree-picked folder that is or lies
     642              :    *        behind a symlink or junction: what it points to is not part of the
     643              :    *        store. The store root itself may be a link.
     644              :    * @param dir Absolute folder path.
     645              :    * @return true when the folder was refused and the caller must stop.
     646              :    */
     647              :   auto refuseLinkedFolder(const QString &dir) -> bool;
     648              :   /// Share menu "What is this?": the explanation of sharing with GPG.
     649              :   void showShareHelp();
     650              : 
     651              :   /// Re-apply the monospace and line-wrapping settings to the text browser
     652              :   /// after the configuration dialog.
     653              :   void applyTextBrowserSettings();
     654              :   /// Toggle Qt::WindowStaysOnTopHint to match the "always on top" setting,
     655              :   /// skipping the native-window rebuild when nothing changes.
     656              :   void applyWindowFlagsSettings();
     657              :   /// Store geometry and dock/toolbar state in the settings; idempotent,
     658              :   /// called from closeEvent() and the destructor.
     659              :   void saveWindowState();
     660              : 
     661              :   /**
     662              :    * @brief Show Push and Pull only when Git is in use; enable them only while
     663              :    *        the interface is.
     664              :    * @param uiEnabled false while an operation runs
     665              :    */
     666              :   void updateGitButtonVisibility(bool uiEnabled = true);
     667              :   /**
     668              :    * @brief Refresh the OTP toolbar action from settings.
     669              :    * @param uiEnabled false while a backend operation is in flight, so the
     670              :    *        action is disabled along with the rest of the UI.
     671              :    */
     672              :   void updateOtpButtonVisibility(bool uiEnabled = true);
     673              :   /// Show the content-search buttons only when the setting is on; turning
     674              :   /// it off while in content-search mode leaves that mode.
     675              :   void updateGrepButtonVisibility();
     676              :   /**
     677              :    * @brief Enable or disable the Push and Pull actions together.
     678              :    * @param state true to enable.
     679              :    */
     680              :   void enableGitButtons(const bool &state);
     681              : 
     682              :   /// Sync the Process Output dock and its menu toggle with the setting
     683              :   /// after the configuration dialog.
     684              :   void updateProcessOutputVisibility();
     685              : };
     686              : 
     687              : #endif // SRC_MAINWINDOW_H_
        

Generated by: LCOV version 2.0-1