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

IJHack / QtPass / 24637146628

19 Apr 2026 07:23PM UTC coverage: 27.338%. Remained the same
24637146628

Pull #1078

github

web-flow
Merge aed060a1e into 0cbee1af3
Pull Request #1078: docs: Comments on Qt6.10 specials

0 of 1 new or added line in 1 file covered. (0.0%)

49 existing lines in 1 file now uncovered.

1593 of 5827 relevant lines covered (27.34%)

16.46 hits per line

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

41.61
/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

15
auto operator<<(
1✔
16
    QDataStream &out,
17
    const dragAndDropInfoPasswordStore &dragAndDropInfoPasswordStore)
18
    -> QDataStream & {
19
  out << static_cast<quint8>(dragAndDropInfoPasswordStore.kind)
1✔
20
      << dragAndDropInfoPasswordStore.path;
1✔
21
  return out;
1✔
22
}
23

24
auto operator>>(QDataStream &in,
×
25
                dragAndDropInfoPasswordStore &dragAndDropInfoPasswordStore)
26
    -> QDataStream & {
27
  quint8 k;
28
  in >> k >> dragAndDropInfoPasswordStore.path;
×
29
  switch (k) {
×
30
  case static_cast<quint8>(dragAndDropInfoPasswordStore::ItemKind::Directory):
×
31
    dragAndDropInfoPasswordStore.kind =
×
32
        dragAndDropInfoPasswordStore::ItemKind::Directory;
33
    break;
×
34
  case static_cast<quint8>(dragAndDropInfoPasswordStore::ItemKind::File):
×
35
    dragAndDropInfoPasswordStore.kind =
×
36
        dragAndDropInfoPasswordStore::ItemKind::File;
37
    break;
×
38
  default:
×
39
    dragAndDropInfoPasswordStore.kind =
×
40
        dragAndDropInfoPasswordStore::ItemKind::Unknown;
41
    break;
×
42
  }
43
  return in;
×
44
}
45

46
/**
47
 * @brief StoreModel::StoreModel
48
 * SubClass of QSortFilterProxyModel via
49
 * http://www.qtcentre.org/threads/46471-QTreeView-Filter
50
 */
51
StoreModel::StoreModel() { fs = nullptr; }
19✔
52

53
/**
54
 * @brief StoreModel::filterAcceptsRow should row be shown, wrapper for
55
 * StoreModel::showThis method.
56
 * @param sourceRow
57
 * @param sourceParent
58
 * @return
59
 */
60
auto StoreModel::filterAcceptsRow(int sourceRow,
19✔
61
                                  const QModelIndex &sourceParent) const
62
    -> bool {
63
  QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
19✔
64
  return showThis(index);
19✔
65
}
66

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

103
/**
104
 * @brief StoreModel::setModelAndStore update the source model and store.
105
 * @param sourceModel
106
 * @param passStore
107
 */
108
void StoreModel::setModelAndStore(QFileSystemModel *sourceModel,
14✔
109
                                  const QString &passStore) {
110
  setSourceModel(sourceModel);
14✔
111
  fs = sourceModel;
14✔
112
  store = passStore;
14✔
113
}
14✔
114

115
void StoreModel::setStore(const QString &passStore) {
×
116
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
117
  // Qt 6.10+ provides beginFilterChange()/endFilterChange(), which is the
118
  // preferred API for scoped and more efficient filter updates.
119
  beginFilterChange();
120
  store = passStore;
121
  endFilterChange(QSortFilterProxyModel::Direction::Rows);
122
#else
123
  // Older Qt versions do not provide the begin/end filter change API, so we
124
  // update the store and manually invalidate the filter as a compatibility
125
  // path.
NEW
126
  store = passStore;
×
127
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
UNCOV
128
  QSortFilterProxyModel::invalidateFilter();
×
129
#else
130
  invalidateFilter();
131
#endif
132
#endif
UNCOV
133
}
×
134

135
/**
136
 * @brief StoreModel::data don't show the .gpg at the end of a file.
137
 * @param index
138
 * @param role
139
 * @return
140
 */
141
auto StoreModel::data(const QModelIndex &index, int role) const -> QVariant {
2✔
142
  if (!index.isValid()) {
143
    return {};
144
  }
145

146
  QVariant initial_value;
147
  initial_value = QSortFilterProxyModel::data(index, role);
1✔
148

149
  if (role == Qt::DisplayRole) {
1✔
150
    QString name = initial_value.toString();
1✔
151
    name.replace(Util::endsWithGpg(), "");
1✔
152
    initial_value.setValue(name);
1✔
153
  }
154

155
  return initial_value;
1✔
156
}
1✔
157

158
/**
159
 * @brief StoreModel::supportedDropActions enable drop.
160
 * @return
161
 */
162
auto StoreModel::supportedDropActions() const -> Qt::DropActions {
1✔
163
  return Qt::CopyAction | Qt::MoveAction;
1✔
164
}
165

166
/**
167
 * @brief StoreModel::supportedDragActions enable drag.
168
 * @return
169
 */
170
auto StoreModel::supportedDragActions() const -> Qt::DropActions {
1✔
171
  return Qt::CopyAction | Qt::MoveAction;
1✔
172
}
173

174
/**
175
 * @brief StoreModel::flags
176
 * @param index
177
 * @return
178
 */
179
auto StoreModel::flags(const QModelIndex &index) const -> Qt::ItemFlags {
2✔
180
  Qt::ItemFlags defaultFlags = QSortFilterProxyModel::flags(index);
2✔
181

182
  if (index.isValid()) {
183
    return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
184
  }
185
  return Qt::ItemIsDropEnabled | defaultFlags;
1✔
186
}
187

188
/**
189
 * @brief StoreModel::mimeTypes
190
 * @return
191
 */
192
auto StoreModel::mimeTypes() const -> QStringList {
1✔
193
  QStringList types;
1✔
194
  types << "application/vnd+qtpass.dragAndDropInfoPasswordStore";
1✔
195
  return types;
1✔
196
}
197

198
/**
199
 * @brief StoreModel::mimeData
200
 * @param indexes
201
 * @return
202
 */
203
auto StoreModel::mimeData(const QModelIndexList &indexes) const -> QMimeData * {
1✔
204
  dragAndDropInfoPasswordStore info;
1✔
205

206
  QByteArray encodedData;
1✔
207
  // only use the first, otherwise we should enable multiselection
208
  QModelIndex index = indexes.at(0);
1✔
209
  if (index.isValid()) {
210
    QModelIndex useIndex = mapToSource(index);
1✔
211
    const QFileInfo fileInfo = fs->fileInfo(useIndex);
1✔
212

213
    if (fileInfo.isDir()) {
1✔
UNCOV
214
      info.kind = dragAndDropInfoPasswordStore::ItemKind::Directory;
×
215
    } else if (fileInfo.isFile()) {
1✔
216
      info.kind = dragAndDropInfoPasswordStore::ItemKind::File;
1✔
217
    }
218
    info.path = fileInfo.absoluteFilePath();
2✔
219
    QDataStream stream(&encodedData, QIODevice::WriteOnly);
1✔
220
    stream << info;
1✔
221
  }
1✔
222

223
  auto *mimeData = new QMimeData();
1✔
224
  mimeData->setData("application/vnd+qtpass.dragAndDropInfoPasswordStore",
2✔
225
                    encodedData);
226
  return mimeData;
1✔
227
}
228

229
/**
230
 * @brief StoreModel::canDropMimeData
231
 * @param data
232
 * @param action
233
 * @param row
234
 * @param column
235
 * @param parent
236
 * @return
237
 */
UNCOV
238
auto StoreModel::canDropMimeData(const QMimeData *data, Qt::DropAction action,
×
239
                                 int row, int column,
240
                                 const QModelIndex &parent) const -> bool {
241
#ifdef QT_DEBUG
242
  qDebug() << action << row;
243
#else
244
  Q_UNUSED(action)
245
  Q_UNUSED(row)
246
#endif
247

UNCOV
248
  if (data == nullptr ||
×
UNCOV
249
      !data->hasFormat("application/vnd+qtpass.dragAndDropInfoPasswordStore")) {
×
250
    return false;
251
  }
252

253
  QByteArray encodedData =
UNCOV
254
      data->data("application/vnd+qtpass.dragAndDropInfoPasswordStore");
×
UNCOV
255
  if (encodedData.isEmpty()) {
×
256
    return false;
257
  }
UNCOV
258
  QDataStream stream(&encodedData, QIODevice::ReadOnly);
×
UNCOV
259
  dragAndDropInfoPasswordStore info;
×
260
  stream >> info;
×
261
  if (stream.status() != QDataStream::Ok) {
×
262
    return false;
263
  }
264

265
  QModelIndex useIndex =
UNCOV
266
      this->index(parent.row(), parent.column(), parent.parent());
×
267

268
  if (column > 0) {
×
269
    return false;
270
  }
271

272
  using IK = dragAndDropInfoPasswordStore::ItemKind;
273
  // you can drop a folder on a folder
UNCOV
274
  if (fs->fileInfo(mapToSource(useIndex)).isDir() &&
×
UNCOV
275
      info.kind == IK::Directory) {
×
276
    return true;
277
  }
278
  // you can drop a file on a folder
UNCOV
279
  if (fs->fileInfo(mapToSource(useIndex)).isDir() && info.kind == IK::File) {
×
280
    return true;
281
  }
282
  // you can drop a file on a file
UNCOV
283
  if (fs->fileInfo(mapToSource(useIndex)).isFile() && info.kind == IK::File) {
×
284
    return true;
285
  }
286

287
  return false;
UNCOV
288
}
×
289

290
/**
291
 * @brief StoreModel::dropMimeData
292
 * @param data
293
 * @param action
294
 * @param row
295
 * @param column
296
 * @param parent
297
 * @return
298
 */
UNCOV
299
auto StoreModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
×
300
                              int row, int column, const QModelIndex &parent)
301
    -> bool {
UNCOV
302
  if (!canDropMimeData(data, action, row, column, parent)) {
×
303
    return false;
304
  }
305

UNCOV
306
  if (action == Qt::IgnoreAction) {
×
307
    return true;
308
  }
309

UNCOV
310
  if (action != Qt::MoveAction && action != Qt::CopyAction) {
×
311
    return false;
312
  }
313

UNCOV
314
  dragAndDropInfoPasswordStore info;
×
UNCOV
315
  if (!parseDropData(data, &info)) {
×
316
    return false;
317
  }
318

UNCOV
319
  return executeDropAction(info, action, parent);
×
320
}
321

UNCOV
322
auto StoreModel::parseDropData(const QMimeData *data,
×
323
                               dragAndDropInfoPasswordStore *outInfo) -> bool {
324
  QByteArray encodedData =
UNCOV
325
      data->data("application/vnd+qtpass.dragAndDropInfoPasswordStore");
×
UNCOV
326
  if (encodedData.isEmpty()) {
×
327
    return false;
328
  }
329

UNCOV
330
  QDataStream stream(&encodedData, QIODevice::ReadOnly);
×
UNCOV
331
  dragAndDropInfoPasswordStore info;
×
332
  stream >> info;
×
333
  if (stream.status() != QDataStream::Ok) {
×
334
    return false;
335
  }
336

337
  *outInfo = info;
UNCOV
338
  return true;
×
UNCOV
339
}
×
340

341
auto StoreModel::executeDropAction(const dragAndDropInfoPasswordStore &info,
×
342
                                   Qt::DropAction action,
343
                                   const QModelIndex &parent) -> bool {
344
  QModelIndex destIndex =
UNCOV
345
      this->index(parent.row(), parent.column(), parent.parent());
×
UNCOV
346
  QFileInfo destFileinfo = fs->fileInfo(mapToSource(destIndex));
×
347
  QFileInfo srcFileInfo = QFileInfo(info.path);
×
348

349
  QString cleanedSrc = QDir::cleanPath(srcFileInfo.absoluteFilePath());
×
UNCOV
350
  QString cleanedDest = QDir::cleanPath(destFileinfo.absoluteFilePath());
×
351

352
  switch (info.kind) {
×
UNCOV
353
  case dragAndDropInfoPasswordStore::ItemKind::Directory:
×
354
    return handleDirDrop(cleanedSrc, destFileinfo, srcFileInfo, action);
×
355
  case dragAndDropInfoPasswordStore::ItemKind::File:
×
356
    return handleFileDrop(cleanedSrc, cleanedDest, destFileinfo, action);
×
357
  default:
358
    qWarning() << "executeDropAction: unexpected ItemKind, ignoring drop";
×
UNCOV
359
    return false;
×
360
  }
361
}
×
362

363
auto StoreModel::handleDirDrop(const QString &cleanedSrc,
×
364
                               const QFileInfo &destFileinfo,
365
                               const QFileInfo &srcFileInfo,
366
                               Qt::DropAction action) -> bool {
UNCOV
367
  if (!destFileinfo.isDir()) {
×
368
    return false;
369
  }
370

UNCOV
371
  QDir destDir = QDir(QDir::cleanPath(destFileinfo.absoluteFilePath()))
×
UNCOV
372
                     .filePath(srcFileInfo.fileName());
×
373
  QString cleanedDestDir = QDir::cleanPath(destDir.absolutePath());
×
374

375
  if (action == Qt::MoveAction) {
×
UNCOV
376
    QtPassSettings::getPass()->Move(cleanedSrc, cleanedDestDir);
×
377
  } else if (action == Qt::CopyAction) {
×
378
    QtPassSettings::getPass()->Copy(cleanedSrc, cleanedDestDir);
×
379
  }
380
  return true;
UNCOV
381
}
×
382

383
auto StoreModel::handleFileDrop(const QString &cleanedSrc,
×
384
                                const QString &cleanedDest,
385
                                const QFileInfo &destFileinfo,
386
                                Qt::DropAction action) -> bool {
UNCOV
387
  if (destFileinfo.isDir()) {
×
UNCOV
388
    return handleFileToDirDrop(cleanedSrc, cleanedDest, action);
×
389
  }
390
  return handleFileToFileDrop(cleanedSrc, cleanedDest, action);
×
391
}
392

UNCOV
393
auto StoreModel::handleFileToDirDrop(const QString &cleanedSrc,
×
394
                                     const QString &cleanedDest,
395
                                     Qt::DropAction action) -> bool {
UNCOV
396
  if (action == Qt::MoveAction) {
×
UNCOV
397
    QtPassSettings::getPass()->Move(cleanedSrc, cleanedDest);
×
398
  } else if (action == Qt::CopyAction) {
×
399
    QtPassSettings::getPass()->Copy(cleanedSrc, cleanedDest);
×
400
  }
401
  return true;
×
402
}
403

UNCOV
404
auto StoreModel::handleFileToFileDrop(const QString &cleanedSrc,
×
405
                                      const QString &cleanedDest,
406
                                      Qt::DropAction action) -> bool {
407
  QWidget *parentWidget = qobject_cast<QWidget *>(parent());
UNCOV
408
  int answer = QMessageBox::question(
×
UNCOV
409
      parentWidget, tr("Force overwrite?"),
×
410
      tr("overwrite %1 with %2?").arg(cleanedDest, cleanedSrc),
×
411
      QMessageBox::Yes | QMessageBox::No);
412
  bool force = answer == QMessageBox::Yes;
×
413

414
  if (action == Qt::MoveAction) {
×
UNCOV
415
    QtPassSettings::getPass()->Move(cleanedSrc, cleanedDest, force);
×
416
  } else if (action == Qt::CopyAction) {
×
417
    QtPassSettings::getPass()->Copy(cleanedSrc, cleanedDest, force);
×
418
  }
419
  return true;
×
420
}
421

422
/**
423
 * @brief StoreModel::lessThan
424
 * @param source_left
425
 * @param source_right
426
 * @return
427
 */
428
auto StoreModel::lessThan(const QModelIndex &source_left,
2✔
429
                          const QModelIndex &source_right) const -> bool {
430
/* matches logic in QFileSystemModelSorter::compareNodes() */
431
#ifndef Q_OS_MAC
432
  if (fs && (source_left.column() == 0 || source_left.column() == 1)) {
2✔
433
    bool leftD = fs->isDir(source_left);
2✔
434
    bool rightD = fs->isDir(source_right);
2✔
435

436
    if (leftD ^ rightD) {
2✔
437
      return leftD;
438
    }
439
  }
440
#endif
441

442
  return QSortFilterProxyModel::lessThan(source_left, source_right);
1✔
443
}
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