QtPass Developer documentation
QtPass test coverage
Current view: top level - src/storemodel.h Coverage Total Hit
Test: QtPass Lines: 50.0 % 2 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 StoreModel, the filtering/sorting proxy over the store's
       6              :  *        QFileSystemModel, and StoreDragItem, the payload of a tree drag.
       7              :  */
       8              : #ifndef SRC_STOREMODEL_H_
       9              : #define SRC_STOREMODEL_H_
      10              : 
      11              : #include <QFileInfo>
      12              : #include <QSortFilterProxyModel>
      13              : #include <optional>
      14              : 
      15              : class Pass;
      16              : class QFileSystemModel;
      17              : 
      18              : /**
      19              :  * @struct StoreDragItem
      20              :  * @ingroup store
      21              :  * @brief What a drag from the store tree carries: the kind of the dragged
      22              :  * item and its path.
      23              :  *
      24              :  * Travels as the `kStoreDragMimeType` payload
      25              :  * (`application/vnd.qtpass.store-item`), serialised by operator<<() and read
      26              :  * back by operator>>().
      27              :  */
      28           61 : struct StoreDragItem {
      29              :   /**
      30              :    * @brief Type of the dragged item.
      31              :    */
      32              :   enum class ItemKind {
      33              :     Unknown,   /**< Item type has not been determined yet */
      34              :     Directory, /**< Dragged item is a directory */
      35              :     File       /**< Dragged item is a file */
      36              :   };
      37              : 
      38              :   ItemKind kind{ItemKind::Unknown}; /**< Type of dragged item */
      39              :   QString path;                     /**< Full path to the dragged item */
      40              : };
      41              : 
      42              : class QDataStream;
      43              : 
      44              : /**
      45              :  * @brief Serialize a StoreDragItem for the QtPass MIME type.
      46              :  * @param out Stream to write to.
      47              :  * @param info Drag/drop info to serialize.
      48              :  * @return The same stream, for chaining.
      49              :  */
      50              : auto operator<<(QDataStream &out, const StoreDragItem &info) -> QDataStream &;
      51              : 
      52              : /**
      53              :  * @brief Deserialize a StoreDragItem from the QtPass MIME type.
      54              :  *
      55              :  * Unrecognised kind bytes resolve to ItemKind::Unknown rather than being
      56              :  * rejected, so a future protocol bump remains decode-safe.
      57              :  *
      58              :  * @param in Stream to read from.
      59              :  * @param info Drag/drop info to populate.
      60              :  * @return The same stream, for chaining.
      61              :  */
      62              : auto operator>>(QDataStream &in, StoreDragItem &info) -> QDataStream &;
      63              : 
      64              : /// @cond DOXYGEN_MISPARSES_CONSTEXPR_INIT
      65              : // The one MIME type the store tree drags: a serialised StoreDragItem (see the
      66              : // struct's documentation). Hidden from Doxygen, which reads the
      67              : // constructor-style initialiser as a function taking a string literal.
      68              : inline constexpr QLatin1StringView
      69              :     kStoreDragMimeType("application/vnd.qtpass.store-item");
      70              : /// @endcond
      71              : 
      72              : /**
      73              :  * @class StoreModel
      74              :  * @ingroup store
      75              :  * @brief QSortFilterProxyModel for filtering and displaying password store.
      76              :  *
      77              :  * StoreModel wraps QFileSystemModel to provide password store-specific
      78              :  * filtering and display functionality. It handles:
      79              :  * - Hiding the `.git` directory from display
      80              :  * - Removing .gpg extension from file names
      81              :  * - Supporting drag and drop operations
      82              :  * - Custom sorting (directories before files)
      83              :  */
      84              : class StoreModel : public QSortFilterProxyModel {
      85            0 :   Q_OBJECT
      86              : 
      87              : private:
      88              :   /**
      89              :    * @brief The wrapped file system model, set by setModelAndStore(); null
      90              :    *        until then, which makes showThis() hide everything.
      91              :    */
      92              :   QFileSystemModel *fs;
      93              :   /**
      94              :    * @brief Store root used to make paths relative for filtering and for the
      95              :    *        drop boundary check.
      96              :    */
      97              :   QString store;
      98              :   /**
      99              :    * @brief Backend that performs drag-and-drop Move/Copy; not owned, null
     100              :    *        until setPass(), in which case drops are refused.
     101              :    */
     102              :   Pass *m_pass{nullptr};
     103              : 
     104              :   /**
     105              :    * @brief Decode the drag payload from @p data.
     106              :    * @param data MIME data of the drop; may be null.
     107              :    * @return The payload, or nothing when @p data is null, carries no payload
     108              :    * of ours, or the payload does not deserialise cleanly.
     109              :    */
     110              :   static auto parseDropData(const QMimeData *data)
     111              :       -> std::optional<StoreDragItem>;
     112              : 
     113              :   /**
     114              :    * @brief Resolve a validated drop into a Move or Copy.
     115              :    *
     116              :    * Both endpoints must resolve inside the store after symlink resolution
     117              :    * (the payload could be crafted). A directory is dropped into the target
     118              :    * folder; a file onto a folder goes into it, a file onto a file asks the
     119              :    * user before overwriting.
     120              :    * @param info The decoded drag payload.
     121              :    * @param action Qt::MoveAction or Qt::CopyAction.
     122              :    * @param parent Proxy index of the drop target.
     123              :    * @return true once the operation has been dispatched to the backend;
     124              :    *         false for an escaping path, an unknown kind or a bad target.
     125              :    */
     126              :   auto executeDropAction(const StoreDragItem &info, Qt::DropAction action,
     127              :                          const QModelIndex &parent) -> bool;
     128              :   /**
     129              :    * @brief Perform the actual Move/Copy for a validated drop.
     130              :    * @param cleanedSrc Canonical source path (inside the store).
     131              :    * @param cleanedDest Canonical destination path (inside the store).
     132              :    * @param action Qt::MoveAction or Qt::CopyAction.
     133              :    * @param force Overwrite an existing destination.
     134              :    * @return true once the operation has been dispatched.
     135              :    */
     136              :   auto performDrop(const QString &cleanedSrc, const QString &cleanedDest,
     137              :                    Qt::DropAction action, bool force) -> bool;
     138              : 
     139              : public:
     140              :   /**
     141              :    * @brief Construct a StoreModel.
     142              :    */
     143              :   StoreModel();
     144              : 
     145              :   /**
     146              :    * @brief Inject the Pass backend for drag-and-drop Move/Copy operations.
     147              :    * @param pass Pass backend instance; must outlive this StoreModel.
     148              :    */
     149              :   void setPass(Pass *pass);
     150              : 
     151              :   /**
     152              :    * @brief Filter whether a row should be displayed.
     153              :    * @param source_row Row index in source model.
     154              :    * @param source_parent Parent index in source model.
     155              :    * @return true if row should be displayed.
     156              :    */
     157              :   [[nodiscard]] auto filterAcceptsRow(int source_row,
     158              :                                       const QModelIndex &source_parent) const
     159              :       -> bool override;
     160              : 
     161              :   /**
     162              :    * @brief Check if a specific index should be shown.
     163              :    * @param index Model index to check.
     164              :    * @return true if index should be visible.
     165              :    */
     166              :   [[nodiscard]] auto showThis(const QModelIndex &index) const -> bool;
     167              : 
     168              :   /**
     169              :    * @brief Initialize model with source model and store path.
     170              :    * @param sourceModel Filesystem model to wrap.
     171              :    * @param passStore Root path of password store.
     172              :    */
     173              :   void setModelAndStore(QFileSystemModel *sourceModel,
     174              :                         const QString &passStore);
     175              : 
     176              :   /**
     177              :    * @brief Set the source filesystem root and map it to a proxy index.
     178              :    *
     179              :    * Wraps the recurring `mapFromSource(fs->setRootPath(path))` dance used to
     180              :    * point the tree view at a directory, so callers don't reach through to the
     181              :    * wrapped QFileSystemModel.
     182              :    * @param path Directory to make the source root.
     183              :    * @return Proxy index for `path`, or an invalid index if no source model is
     184              :    * set.
     185              :    */
     186              :   auto rootIndexFor(const QString &path) -> QModelIndex;
     187              : 
     188              :   /**
     189              :    * @brief Update the store path used for filtering without changing the source
     190              :    * model.
     191              :    * @param passStore New root path of password store.
     192              :    */
     193              :   void setStore(const QString &passStore);
     194              : 
     195              :   /**
     196              :    * @brief Get display data for index.
     197              :    * @param index Model index.
     198              :    * @param role Data role (e.g., Qt::DisplayRole).
     199              :    * @return Display data for the role.
     200              :    */
     201              :   [[nodiscard]] auto data(const QModelIndex &index, int role) const
     202              :       -> QVariant override;
     203              : 
     204              :   /**
     205              :    * @brief Compare two indices for sorting.
     206              :    * @param source_left Left index to compare.
     207              :    * @param source_right Right index to compare.
     208              :    * @return true if left < right.
     209              :    */
     210              :   [[nodiscard]] auto lessThan(const QModelIndex &source_left,
     211              :                               const QModelIndex &source_right) const
     212              :       -> bool override;
     213              : 
     214              :   /**
     215              :    * @brief Get the password store root path.
     216              :    * @return Store path.
     217              :    */
     218              :   [[nodiscard]] auto getStore() const -> QString { return store; }
     219              : 
     220              :   // QAbstractItemModel interface
     221              : public:
     222              :   /**
     223              :    * @brief Get supported drop actions.
     224              :    * @return Supported Qt::DropActions.
     225              :    */
     226              :   [[nodiscard]] auto supportedDropActions() const -> Qt::DropActions override;
     227              : 
     228              :   /**
     229              :    * @brief Get supported drag actions.
     230              :    * @return Supported Qt::DropActions.
     231              :    */
     232              :   [[nodiscard]] auto supportedDragActions() const -> Qt::DropActions override;
     233              : 
     234              :   /**
     235              :    * @brief Get item flags for index.
     236              :    * @param index Model index.
     237              :    * @return Item flags.
     238              :    */
     239              :   [[nodiscard]] auto flags(const QModelIndex &index) const
     240              :       -> Qt::ItemFlags override;
     241              : 
     242              :   /**
     243              :    * @brief Get supported MIME types for drag/drop.
     244              :    * @return List of MIME type strings.
     245              :    */
     246              :   [[nodiscard]] auto mimeTypes() const -> QStringList override;
     247              : 
     248              :   /**
     249              :    * @brief Create MIME data from indexes.
     250              :    * @param indexes List of selected indexes.
     251              :    * @return MIME data object.
     252              :    */
     253              :   [[nodiscard]] auto mimeData(const QModelIndexList &indexes) const
     254              :       -> QMimeData * override;
     255              : 
     256              :   /**
     257              :    * @brief Check if drop is possible.
     258              :    * @param data MIME data to drop.
     259              :    * @param action Drop action.
     260              :    * @param row Target row.
     261              :    * @param column Target column.
     262              :    * @param parent Target parent index.
     263              :    * @return true if drop is possible.
     264              :    */
     265              :   auto canDropMimeData(const QMimeData *data, Qt::DropAction action, int row,
     266              :                        int column, const QModelIndex &parent) const
     267              :       -> bool override;
     268              : 
     269              :   /**
     270              :    * @brief Handle dropped MIME data.
     271              :    * @param data MIME data to drop.
     272              :    * @param action Drop action.
     273              :    * @param row Target row.
     274              :    * @param column Target column.
     275              :    * @param parent Target parent index.
     276              :    * @return true if drop was handled.
     277              :    */
     278              :   auto dropMimeData(const QMimeData *data, Qt::DropAction action, int row,
     279              :                     int column, const QModelIndex &parent) -> bool override;
     280              : };
     281              : 
     282              : #endif // SRC_STOREMODEL_H_
        

Generated by: LCOV version 2.0-1