• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IJHack / QtPass / 24617323889

19 Apr 2026 12:33AM UTC coverage: 22.692% (+0.09%) from 22.607%
24617323889

push

github

web-flow
Merge pull request #1055 from IJHack/fix/refactor-complex-methods

Refactor complex methods to reduce cyclomatic complexity

33 of 84 new or added lines in 2 files covered. (39.29%)

13 existing lines in 3 files now uncovered.

1315 of 5795 relevant lines covered (22.69%)

8.54 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

45.71
/src/storemodel.cpp
1
// SPDX-FileCopyrightText: 2014 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 <QApplication>
8
#include <QDebug>
9
#include <QFileSystemModel>
10
#include <QMessageBox>
11
#include <QMimeData>
12
#include <QRegularExpression>
13
#include <QtGlobal>
14
#include <utility>
15

16
auto operator<<(
1✔
17
    QDataStream &out,
18
    const dragAndDropInfoPasswordStore &dragAndDropInfoPasswordStore)
19
    -> QDataStream & {
20
  out << dragAndDropInfoPasswordStore.isDir
1✔
21
      << dragAndDropInfoPasswordStore.isFile
1✔
22
      << dragAndDropInfoPasswordStore.path;
1✔
23
  return out;
1✔
24
}
25

26
auto operator>>(QDataStream &in,
×
27
                dragAndDropInfoPasswordStore &dragAndDropInfoPasswordStore)
28
    -> QDataStream & {
29
  in >> dragAndDropInfoPasswordStore.isDir >>
×
30
      dragAndDropInfoPasswordStore.isFile >> dragAndDropInfoPasswordStore.path;
×
31
  return in;
×
32
}
33

34
/**
35
 * @brief StoreModel::StoreModel
36
 * SubClass of QSortFilterProxyModel via
37
 * http://www.qtcentre.org/threads/46471-QTreeView-Filter
38
 */
39
StoreModel::StoreModel() { fs = nullptr; }
19✔
40

41
/**
42
 * @brief StoreModel::filterAcceptsRow should row be shown, wrapper for
43
 * StoreModel::showThis method.
44
 * @param sourceRow
45
 * @param sourceParent
46
 * @return
47
 */
48
auto StoreModel::filterAcceptsRow(int sourceRow,
19✔
49
                                  const QModelIndex &sourceParent) const
50
    -> bool {
51
  QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
19✔
52
  return showThis(index);
19✔
53
}
54

55
/**
56
 * @brief StoreModel::showThis should a row be shown, based on our search
57
 * criteria.
58
 * @param index
59
 * @return
60
 */
61
auto StoreModel::showThis(const QModelIndex &index) const -> bool {
44✔
62
  bool retVal = false;
63
  if (fs == nullptr) {
44✔
64
    return retVal;
65
  }
66
  // Gives you the info for number of childs with a parent
67
  if (sourceModel()->rowCount(index) > 0) {
43✔
68
    for (int nChild = 0; nChild < sourceModel()->rowCount(index); ++nChild) {
24✔
69
      QModelIndex childIndex = sourceModel()->index(nChild, 0, index);
24✔
70
      if (!childIndex.isValid()) {
71
        break;
72
      }
73
      retVal = showThis(childIndex);
24✔
74
      if (retVal) {
24✔
75
        break;
76
      }
77
    }
78
  } else {
79
    QModelIndex useIndex = sourceModel()->index(index.row(), 0, index.parent());
19✔
80
    QString path = fs->filePath(useIndex);
19✔
81
    path = QDir(store).relativeFilePath(path);
38✔
82
    if (path.startsWith(".git")) {
38✔
83
      return false;
84
    }
85
    path.replace(Util::endsWithGpg(), "");
18✔
86
    retVal = path.contains(filterRegularExpression());
18✔
87
  }
88
  return retVal;
89
}
90

91
/**
92
 * @brief StoreModel::setModelAndStore update the source model and store.
93
 * @param sourceModel
94
 * @param passStore
95
 */
96
void StoreModel::setModelAndStore(QFileSystemModel *sourceModel,
14✔
97
                                  QString passStore) {
98
  setSourceModel(sourceModel);
14✔
99
  fs = sourceModel;
14✔
100
  store = std::move(passStore);
101
}
14✔
102

103
void StoreModel::setStore(const QString &passStore) {
×
104
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
105
  beginFilterChange();
106
  store = passStore;
107
  endFilterChange(QSortFilterProxyModel::Direction::Rows);
108
#else
109
  store = passStore;
×
110
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
111
  QSortFilterProxyModel::invalidateFilter();
×
112
#else
113
  invalidateFilter();
114
#endif
115
#endif
116
}
×
117

118
/**
119
 * @brief StoreModel::data don't show the .gpg at the end of a file.
120
 * @param index
121
 * @param role
122
 * @return
123
 */
124
auto StoreModel::data(const QModelIndex &index, int role) const -> QVariant {
2✔
125
  if (!index.isValid()) {
126
    return {};
127
  }
128

129
  QVariant initial_value;
130
  initial_value = QSortFilterProxyModel::data(index, role);
1✔
131

132
  if (role == Qt::DisplayRole) {
1✔
133
    QString name = initial_value.toString();
1✔
134
    name.replace(Util::endsWithGpg(), "");
1✔
135
    initial_value.setValue(name);
1✔
136
  }
137

138
  return initial_value;
1✔
139
}
1✔
140

141
/**
142
 * @brief StoreModel::supportedDropActions enable drop.
143
 * @return
144
 */
145
auto StoreModel::supportedDropActions() const -> Qt::DropActions {
1✔
146
  return Qt::CopyAction | Qt::MoveAction;
1✔
147
}
148

149
/**
150
 * @brief StoreModel::supportedDragActions enable drag.
151
 * @return
152
 */
153
auto StoreModel::supportedDragActions() const -> Qt::DropActions {
1✔
154
  return Qt::CopyAction | Qt::MoveAction;
1✔
155
}
156

157
/**
158
 * @brief StoreModel::flags
159
 * @param index
160
 * @return
161
 */
162
auto StoreModel::flags(const QModelIndex &index) const -> Qt::ItemFlags {
2✔
163
  Qt::ItemFlags defaultFlags = QSortFilterProxyModel::flags(index);
2✔
164

165
  if (index.isValid()) {
166
    return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
167
  }
168
  return Qt::ItemIsDropEnabled | defaultFlags;
1✔
169
}
170

171
/**
172
 * @brief StoreModel::mimeTypes
173
 * @return
174
 */
175
auto StoreModel::mimeTypes() const -> QStringList {
1✔
176
  QStringList types;
1✔
177
  types << "application/vnd+qtpass.dragAndDropInfoPasswordStore";
1✔
178
  return types;
1✔
179
}
180

181
/**
182
 * @brief StoreModel::mimeData
183
 * @param indexes
184
 * @return
185
 */
186
auto StoreModel::mimeData(const QModelIndexList &indexes) const -> QMimeData * {
1✔
187
  dragAndDropInfoPasswordStore info;
188

189
  QByteArray encodedData;
1✔
190
  // only use the first, otherwise we should enable multiselection
191
  QModelIndex index = indexes.at(0);
1✔
192
  if (index.isValid()) {
193
    QModelIndex useIndex = mapToSource(index);
1✔
194

195
    info.isDir = fs->fileInfo(useIndex).isDir();
1✔
196
    info.isFile = fs->fileInfo(useIndex).isFile();
1✔
197
    info.path = fs->fileInfo(useIndex).absoluteFilePath();
2✔
198
    QDataStream stream(&encodedData, QIODevice::WriteOnly);
1✔
199
    stream << info;
1✔
200
  }
1✔
201

202
  auto *mimeData = new QMimeData();
1✔
203
  mimeData->setData("application/vnd+qtpass.dragAndDropInfoPasswordStore",
2✔
204
                    encodedData);
205
  return mimeData;
1✔
206
}
207

208
/**
209
 * @brief StoreModel::canDropMimeData
210
 * @param data
211
 * @param action
212
 * @param row
213
 * @param column
214
 * @param parent
215
 * @return
216
 */
217
auto StoreModel::canDropMimeData(const QMimeData *data, Qt::DropAction action,
×
218
                                 int row, int column,
219
                                 const QModelIndex &parent) const -> bool {
220
#ifdef QT_DEBUG
221
  qDebug() << action << row;
222
#else
223
  Q_UNUSED(action)
224
  Q_UNUSED(row)
225
#endif
226

227
  if (data == nullptr ||
×
228
      !data->hasFormat("application/vnd+qtpass.dragAndDropInfoPasswordStore")) {
×
229
    return false;
230
  }
231

232
  QByteArray encodedData =
233
      data->data("application/vnd+qtpass.dragAndDropInfoPasswordStore");
×
234
  if (encodedData.isEmpty()) {
×
235
    return false;
236
  }
237
  QDataStream stream(&encodedData, QIODevice::ReadOnly);
×
238
  dragAndDropInfoPasswordStore info;
239
  stream >> info;
×
240
  if (stream.status() != QDataStream::Ok) {
×
241
    return false;
242
  }
243

244
  QModelIndex useIndex =
245
      this->index(parent.row(), parent.column(), parent.parent());
×
246

247
  if (column > 0) {
×
248
    return false;
249
  }
250

251
  // you can drop a folder on a folder
252
  if (fs->fileInfo(mapToSource(useIndex)).isDir() && info.isDir) {
×
253
    return true;
254
  }
255
  // you can drop a file on a folder
256
  if (fs->fileInfo(mapToSource(useIndex)).isDir() && info.isFile) {
×
257
    return true;
258
  }
259
  // you can drop a file on a file
260
  if (fs->fileInfo(mapToSource(useIndex)).isFile() && info.isFile) {
×
261
    return true;
262
  }
263

264
  return false;
265
}
×
266

267
/**
268
 * @brief StoreModel::dropMimeData
269
 * @param data
270
 * @param action
271
 * @param row
272
 * @param column
273
 * @param parent
274
 * @return
275
 */
276
auto StoreModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
×
277
                              int row, int column, const QModelIndex &parent)
278
    -> bool {
279
  if (!canDropMimeData(data, action, row, column, parent)) {
×
280
    return false;
281
  }
282

283
  if (action == Qt::IgnoreAction) {
×
284
    return true;
285
  }
286

NEW
287
  if (action != Qt::MoveAction && action != Qt::CopyAction) {
×
288
    return false;
289
  }
290

291
  dragAndDropInfoPasswordStore info;
NEW
292
  if (!parseDropData(data, &info)) {
×
293
    return false;
294
  }
295

NEW
296
  return executeDropAction(info, action, parent);
×
297
}
298

NEW
299
auto StoreModel::parseDropData(const QMimeData *data,
×
300
                               dragAndDropInfoPasswordStore *outInfo) -> bool {
301
  QByteArray encodedData =
302
      data->data("application/vnd+qtpass.dragAndDropInfoPasswordStore");
×
303
  if (encodedData.isEmpty()) {
×
304
    return false;
305
  }
306

UNCOV
307
  QDataStream stream(&encodedData, QIODevice::ReadOnly);
×
308
  dragAndDropInfoPasswordStore info;
309
  stream >> info;
×
310
  if (stream.status() != QDataStream::Ok) {
×
311
    return false;
312
  }
313

314
  *outInfo = info;
NEW
315
  return true;
×
NEW
316
}
×
317

NEW
318
auto StoreModel::executeDropAction(const dragAndDropInfoPasswordStore &info,
×
319
                                   Qt::DropAction action,
320
                                   const QModelIndex &parent) -> bool {
321
  QModelIndex destIndex =
322
      this->index(parent.row(), parent.column(), parent.parent());
×
323
  QFileInfo destFileinfo = fs->fileInfo(mapToSource(destIndex));
×
324
  QFileInfo srcFileInfo = QFileInfo(info.path);
×
325

326
  QString cleanedSrc = QDir::cleanPath(srcFileInfo.absoluteFilePath());
×
327
  QString cleanedDest = QDir::cleanPath(destFileinfo.absoluteFilePath());
×
328

UNCOV
329
  if (info.isDir) {
×
NEW
330
    return handleDirDrop(cleanedSrc, destFileinfo, srcFileInfo, action);
×
331
  }
NEW
332
  return handleFileDrop(cleanedSrc, cleanedDest, destFileinfo, action);
×
NEW
333
}
×
334

NEW
335
auto StoreModel::handleDirDrop(const QString &cleanedSrc,
×
336
                               const QFileInfo &destFileinfo,
337
                               const QFileInfo &srcFileInfo,
338
                               Qt::DropAction action) -> bool {
NEW
339
  if (!destFileinfo.isDir()) {
×
340
    return false;
341
  }
342

NEW
343
  QDir destDir = QDir(QDir::cleanPath(destFileinfo.absoluteFilePath()))
×
NEW
344
                     .filePath(srcFileInfo.fileName());
×
NEW
345
  QString cleanedDestDir = QDir::cleanPath(destDir.absolutePath());
×
346

NEW
347
  if (action == Qt::MoveAction) {
×
NEW
348
    QtPassSettings::getPass()->Move(cleanedSrc, cleanedDestDir);
×
NEW
349
  } else if (action == Qt::CopyAction) {
×
NEW
350
    QtPassSettings::getPass()->Copy(cleanedSrc, cleanedDestDir);
×
351
  }
352
  return true;
NEW
353
}
×
354

NEW
355
auto StoreModel::handleFileDrop(const QString &cleanedSrc,
×
356
                                const QString &cleanedDest,
357
                                const QFileInfo &destFileinfo,
358
                                Qt::DropAction action) -> bool {
NEW
359
  if (destFileinfo.isDir()) {
×
NEW
360
    return handleFileToDirDrop(cleanedSrc, cleanedDest, action);
×
361
  }
NEW
362
  return handleFileToFileDrop(cleanedSrc, cleanedDest, action);
×
363
}
364

NEW
365
auto StoreModel::handleFileToDirDrop(const QString &cleanedSrc,
×
366
                                     const QString &cleanedDest,
367
                                     Qt::DropAction action) -> bool {
NEW
368
  if (action == Qt::MoveAction) {
×
NEW
369
    QtPassSettings::getPass()->Move(cleanedSrc, cleanedDest);
×
NEW
370
  } else if (action == Qt::CopyAction) {
×
NEW
371
    QtPassSettings::getPass()->Copy(cleanedSrc, cleanedDest);
×
372
  }
NEW
373
  return true;
×
374
}
375

NEW
376
auto StoreModel::handleFileToFileDrop(const QString &cleanedSrc,
×
377
                                      const QString &cleanedDest,
378
                                      Qt::DropAction action) -> bool {
379
  QWidget *parentWidget = qobject_cast<QWidget *>(parent());
NEW
380
  int answer = QMessageBox::question(
×
NEW
381
      parentWidget, tr("force overwrite?"),
×
NEW
382
      tr("overwrite %1 with %2?").arg(cleanedDest, cleanedSrc),
×
383
      QMessageBox::Yes | QMessageBox::No);
NEW
384
  bool force = answer == QMessageBox::Yes;
×
385

NEW
386
  if (action == Qt::MoveAction) {
×
NEW
387
    QtPassSettings::getPass()->Move(cleanedSrc, cleanedDest, force);
×
NEW
388
  } else if (action == Qt::CopyAction) {
×
NEW
389
    QtPassSettings::getPass()->Copy(cleanedSrc, cleanedDest, force);
×
390
  }
UNCOV
391
  return true;
×
392
}
393

394
/**
395
 * @brief StoreModel::lessThan
396
 * @param source_left
397
 * @param source_right
398
 * @return
399
 */
400
auto StoreModel::lessThan(const QModelIndex &source_left,
2✔
401
                          const QModelIndex &source_right) const -> bool {
402
/* matches logic in QFileSystemModelSorter::compareNodes() */
403
#ifndef Q_OS_MAC
404
  if (fs && (source_left.column() == 0 || source_left.column() == 1)) {
2✔
405
    bool leftD = fs->isDir(source_left);
2✔
406
    bool rightD = fs->isDir(source_right);
2✔
407

408
    if (leftD ^ rightD) {
2✔
409
      return leftD;
410
    }
411
  }
412
#endif
413

414
  return QSortFilterProxyModel::lessThan(source_left, source_right);
1✔
415
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc