LCOV - code coverage report
Current view: top level - src - storemodel.cpp (source / functions) Coverage Total Hit
Test: .lcov.total Lines: 38.9 % 113 44
Test Date: 2026-03-23 21:55:57 Functions: 66.7 % 15 10

            Line data    Source code
       1              : // SPDX-FileCopyrightText: 2016 Anne Jan Brouwer
       2              : // SPDX-License-Identifier: GPL-3.0-or-later
       3              : #include "storemodel.h"
       4              : #include "qtpasssettings.h"
       5              : 
       6              : #include "util.h"
       7              : #include <QDebug>
       8              : #include <QFileSystemModel>
       9              : #include <QMessageBox>
      10              : #include <QMimeData>
      11              : #include <QRegularExpression>
      12              : #include <utility>
      13              : 
      14            0 : auto operator<<(
      15              :     QDataStream &out,
      16              :     const dragAndDropInfoPasswordStore &dragAndDropInfoPasswordStore)
      17              :     -> QDataStream & {
      18            0 :   out << dragAndDropInfoPasswordStore.isDir
      19            0 :       << dragAndDropInfoPasswordStore.isFile
      20            0 :       << dragAndDropInfoPasswordStore.path;
      21            0 :   return out;
      22              : }
      23              : 
      24            0 : auto operator>>(QDataStream &in,
      25              :                 dragAndDropInfoPasswordStore &dragAndDropInfoPasswordStore)
      26              :     -> QDataStream & {
      27            0 :   in >> dragAndDropInfoPasswordStore.isDir >>
      28            0 :       dragAndDropInfoPasswordStore.isFile >> dragAndDropInfoPasswordStore.path;
      29            0 :   return in;
      30              : }
      31              : 
      32              : /**
      33              :  * @brief StoreModel::StoreModel
      34              :  * SubClass of QSortFilterProxyModel via
      35              :  * http://www.qtcentre.org/threads/46471-QTreeView-Filter
      36              :  */
      37          265 : StoreModel::StoreModel() { fs = nullptr; }
      38              : 
      39              : /**
      40              :  * @brief StoreModel::filterAcceptsRow should row be shown, wrapper for
      41              :  * StoreModel::ShowThis method.
      42              :  * @param sourceRow
      43              :  * @param sourceParent
      44              :  * @return
      45              :  */
      46           48 : auto StoreModel::filterAcceptsRow(int sourceRow,
      47              :                                   const QModelIndex &sourceParent) const
      48              :     -> bool {
      49           48 :   QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
      50           48 :   return ShowThis(index);
      51              : }
      52              : 
      53              : /**
      54              :  * @brief StoreModel::ShowThis should a row be shown, based on our search
      55              :  * criteria.
      56              :  * @param index
      57              :  * @return
      58              :  */
      59           54 : auto StoreModel::ShowThis(const QModelIndex index) const -> bool {
      60              :   bool retVal = false;
      61           54 :   if (fs == nullptr) {
      62              :     return retVal;
      63              :   }
      64              :   // Gives you the info for number of childs with a parent
      65           54 :   if (sourceModel()->rowCount(index) > 0) {
      66           12 :     for (int nChild = 0; nChild < sourceModel()->rowCount(index); ++nChild) {
      67            6 :       QModelIndex childIndex = sourceModel()->index(nChild, 0, index);
      68              :       if (!childIndex.isValid()) {
      69              :         break;
      70              :       }
      71            6 :       retVal = ShowThis(childIndex);
      72            6 :       if (retVal) {
      73              :         break;
      74              :       }
      75              :     }
      76              :   } else {
      77           48 :     QModelIndex useIndex = sourceModel()->index(index.row(), 0, index.parent());
      78           48 :     QString path = fs->filePath(useIndex);
      79           96 :     path = QDir(store).relativeFilePath(path);
      80           48 :     path.replace(Util::endsWithGpg(), "");
      81           48 :     retVal = path.contains(filterRegularExpression());
      82              :   }
      83              :   return retVal;
      84              : }
      85              : 
      86              : /**
      87              :  * @brief StoreModel::setModelAndStore update the source model and store.
      88              :  * @param sourceModel
      89              :  * @param passStore
      90              :  */
      91          188 : void StoreModel::setModelAndStore(QFileSystemModel *sourceModel,
      92              :                                   QString passStore) {
      93          188 :   setSourceModel(sourceModel);
      94          188 :   fs = sourceModel;
      95              :   store = std::move(passStore);
      96          188 : }
      97              : 
      98              : /**
      99              :  * @brief StoreModel::data don't show the .gpg at the end of a file.
     100              :  * @param index
     101              :  * @param role
     102              :  * @return
     103              :  */
     104           35 : auto StoreModel::data(const QModelIndex &index, int role) const -> QVariant {
     105              :   if (!index.isValid()) {
     106              :     return {};
     107              :   }
     108              : 
     109              :   QVariant initial_value;
     110           35 :   initial_value = QSortFilterProxyModel::data(index, role);
     111              : 
     112           35 :   if (role == Qt::DisplayRole) {
     113           35 :     QString name = initial_value.toString();
     114           35 :     name.replace(Util::endsWithGpg(), "");
     115           35 :     initial_value.setValue(name);
     116              :   }
     117              : 
     118              :   return initial_value;
     119           35 : }
     120              : 
     121              : /**
     122              :  * @brief StoreModel::supportedDropActions enable drop.
     123              :  * @return
     124              :  */
     125           21 : auto StoreModel::supportedDropActions() const -> Qt::DropActions {
     126           21 :   return Qt::CopyAction | Qt::MoveAction;
     127              : }
     128              : 
     129              : /**
     130              :  * @brief StoreModel::supportedDragActions enable drag.
     131              :  * @return
     132              :  */
     133           21 : auto StoreModel::supportedDragActions() const -> Qt::DropActions {
     134           21 :   return Qt::CopyAction | Qt::MoveAction;
     135              : }
     136              : 
     137              : /**
     138              :  * @brief StoreModel::flags
     139              :  * @param index
     140              :  * @return
     141              :  */
     142           70 : auto StoreModel::flags(const QModelIndex &index) const -> Qt::ItemFlags {
     143           70 :   Qt::ItemFlags defaultFlags = QSortFilterProxyModel::flags(index);
     144              : 
     145              :   if (index.isValid()) {
     146              :     return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
     147              :   }
     148           35 :   return Qt::ItemIsDropEnabled | defaultFlags;
     149              : }
     150              : 
     151              : /**
     152              :  * @brief StoreModel::mimeTypes
     153              :  * @return
     154              :  */
     155           35 : auto StoreModel::mimeTypes() const -> QStringList {
     156           35 :   QStringList types;
     157           35 :   types << "application/vnd+qtpass.dragAndDropInfoPasswordStore";
     158           35 :   return types;
     159              : }
     160              : 
     161              : /**
     162              :  * @brief StoreModel::mimeData
     163              :  * @param indexes
     164              :  * @return
     165              :  */
     166            0 : auto StoreModel::mimeData(const QModelIndexList &indexes) const -> QMimeData * {
     167              :   dragAndDropInfoPasswordStore info;
     168              : 
     169            0 :   QByteArray encodedData;
     170              :   // only use the first, otherwise we should enable multiselection
     171            0 :   QModelIndex index = indexes.at(0);
     172              :   if (index.isValid()) {
     173            0 :     QModelIndex useIndex = mapToSource(index);
     174              : 
     175            0 :     info.isDir = fs->fileInfo(useIndex).isDir();
     176            0 :     info.isFile = fs->fileInfo(useIndex).isFile();
     177            0 :     info.path = fs->fileInfo(useIndex).absoluteFilePath();
     178            0 :     QDataStream stream(&encodedData, QIODevice::WriteOnly);
     179            0 :     stream << info;
     180            0 :   }
     181              : 
     182            0 :   auto *mimeData = new QMimeData();
     183            0 :   mimeData->setData("application/vnd+qtpass.dragAndDropInfoPasswordStore",
     184              :                     encodedData);
     185            0 :   return mimeData;
     186              : }
     187              : 
     188              : /**
     189              :  * @brief StoreModel::canDropMimeData
     190              :  * @param data
     191              :  * @param action
     192              :  * @param row
     193              :  * @param column
     194              :  * @param parent
     195              :  * @return
     196              :  */
     197            0 : auto StoreModel::canDropMimeData(const QMimeData *data, Qt::DropAction action,
     198              :                                  int row, int column,
     199              :                                  const QModelIndex &parent) const -> bool {
     200              : #ifdef QT_DEBUG
     201              :   qDebug() << action << row;
     202              : #else
     203              :   Q_UNUSED(action)
     204              :   Q_UNUSED(row)
     205              : #endif
     206              : 
     207              :   QModelIndex useIndex =
     208            0 :       this->index(parent.row(), parent.column(), parent.parent());
     209              :   QByteArray encodedData =
     210            0 :       data->data("application/vnd+qtpass.dragAndDropInfoPasswordStore");
     211            0 :   QDataStream stream(&encodedData, QIODevice::ReadOnly);
     212              :   dragAndDropInfoPasswordStore info;
     213            0 :   stream >> info;
     214            0 :   if (!data->hasFormat("application/vnd+qtpass.dragAndDropInfoPasswordStore")) {
     215              :     return false;
     216              :   }
     217              : 
     218            0 :   if (column > 0) {
     219              :     return false;
     220              :   }
     221              : 
     222              :   // you can drop a folder on a folder
     223            0 :   if (fs->fileInfo(mapToSource(useIndex)).isDir() && info.isDir) {
     224              :     return true;
     225              :   }
     226              :   // you can drop a file on a folder
     227            0 :   if (fs->fileInfo(mapToSource(useIndex)).isDir() && info.isFile) {
     228              :     return true;
     229              :   }
     230              :   // you can drop a file on a file
     231            0 :   if (fs->fileInfo(mapToSource(useIndex)).isFile() && info.isFile) {
     232              :     return true;
     233              :   }
     234              : 
     235              :   return false;
     236            0 : }
     237              : 
     238              : /**
     239              :  * @brief StoreModel::dropMimeData
     240              :  * @param data
     241              :  * @param action
     242              :  * @param row
     243              :  * @param column
     244              :  * @param parent
     245              :  * @return
     246              :  */
     247            0 : auto StoreModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
     248              :                               int row, int column, const QModelIndex &parent)
     249              :     -> bool {
     250            0 :   if (!canDropMimeData(data, action, row, column, parent)) {
     251              :     return false;
     252              :   }
     253              : 
     254            0 :   if (action == Qt::IgnoreAction) {
     255              :     return true;
     256              :   }
     257              :   QByteArray encodedData =
     258            0 :       data->data("application/vnd+qtpass.dragAndDropInfoPasswordStore");
     259              : 
     260            0 :   QDataStream stream(&encodedData, QIODevice::ReadOnly);
     261              :   dragAndDropInfoPasswordStore info;
     262            0 :   stream >> info;
     263              :   QModelIndex destIndex =
     264            0 :       this->index(parent.row(), parent.column(), parent.parent());
     265            0 :   QFileInfo destFileinfo = fs->fileInfo(mapToSource(destIndex));
     266            0 :   QFileInfo srcFileInfo = QFileInfo(info.path);
     267            0 :   QString cleanedSrc = QDir::cleanPath(srcFileInfo.absoluteFilePath());
     268            0 :   QString cleanedDest = QDir::cleanPath(destFileinfo.absoluteFilePath());
     269            0 :   if (info.isDir) {
     270              :     // dropped dir onto dir
     271            0 :     if (destFileinfo.isDir()) {
     272            0 :       QDir destDir = QDir(cleanedDest).filePath(srcFileInfo.fileName());
     273            0 :       QString cleanedDestDir = QDir::cleanPath(destDir.absolutePath());
     274            0 :       if (action == Qt::MoveAction) {
     275            0 :         QtPassSettings::getPass()->Move(cleanedSrc, cleanedDestDir);
     276            0 :       } else if (action == Qt::CopyAction) {
     277            0 :         QtPassSettings::getPass()->Copy(cleanedSrc, cleanedDestDir);
     278              :       }
     279            0 :     }
     280            0 :   } else if (info.isFile) {
     281              :     // dropped file onto a directory
     282            0 :     if (destFileinfo.isDir()) {
     283            0 :       if (action == Qt::MoveAction) {
     284            0 :         QtPassSettings::getPass()->Move(cleanedSrc, cleanedDest);
     285            0 :       } else if (action == Qt::CopyAction) {
     286            0 :         QtPassSettings::getPass()->Copy(cleanedSrc, cleanedDest);
     287              :       }
     288            0 :     } else if (destFileinfo.isFile()) {
     289              :       // dropped file onto a file
     290            0 :       int answer = QMessageBox::question(
     291            0 :           nullptr, tr("force overwrite?"),
     292            0 :           tr("overwrite %1 with %2?").arg(cleanedDest, cleanedSrc),
     293              :           QMessageBox::Yes | QMessageBox::No);
     294            0 :       bool force = answer == QMessageBox::Yes;
     295            0 :       if (action == Qt::MoveAction) {
     296            0 :         QtPassSettings::getPass()->Move(cleanedSrc, cleanedDest, force);
     297            0 :       } else if (action == Qt::CopyAction) {
     298            0 :         QtPassSettings::getPass()->Copy(cleanedSrc, cleanedDest, force);
     299              :       }
     300              :     }
     301              :   }
     302              :   return true;
     303            0 : }
     304              : 
     305              : /**
     306              :  * @brief StoreModel::lessThan
     307              :  * @param source_left
     308              :  * @param source_right
     309              :  * @return
     310              :  */
     311           35 : auto StoreModel::lessThan(const QModelIndex &source_left,
     312              :                           const QModelIndex &source_right) const -> bool {
     313              : /* matches logic in QFileSystemModelSorter::compareNodes() */
     314              : #ifndef Q_OS_MAC
     315           35 :   if (fs && (source_left.column() == 0 || source_left.column() == 1)) {
     316           35 :     bool leftD = fs->isDir(source_left);
     317           35 :     bool rightD = fs->isDir(source_right);
     318              : 
     319           35 :     if (leftD ^ rightD) {
     320              :       return leftD;
     321              :     }
     322              :   }
     323              : #endif
     324              : 
     325           35 :   return QSortFilterProxyModel::lessThan(source_left, source_right);
     326              : }
        

Generated by: LCOV version 2.4-beta