QtPass 1.6.0
Multi-platform GUI for pass, the standard unix password manager.
Loading...
Searching...
No Matches
storemodel.cpp
Go to the documentation of this file.
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 <QDebug>
8#include <QFileSystemModel>
9#include <QMessageBox>
10#include <QMimeData>
11#include <QRegularExpression>
12#include <utility>
13
23
31
37StoreModel::StoreModel() { fs = nullptr; }
38
47 const QModelIndex &sourceParent) const
48 -> bool {
49 QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
50 return showThis(index);
51}
52
59auto StoreModel::showThis(const QModelIndex index) const -> bool {
60 bool retVal = false;
61 if (fs == nullptr) {
62 return retVal;
63 }
64 // Gives you the info for number of childs with a parent
65 if (sourceModel()->rowCount(index) > 0) {
66 for (int nChild = 0; nChild < sourceModel()->rowCount(index); ++nChild) {
67 QModelIndex childIndex = sourceModel()->index(nChild, 0, index);
68 if (!childIndex.isValid()) {
69 break;
70 }
71 retVal = showThis(childIndex);
72 if (retVal) {
73 break;
74 }
75 }
76 } else {
77 QModelIndex useIndex = sourceModel()->index(index.row(), 0, index.parent());
78 QString path = fs->filePath(useIndex);
79 path = QDir(store).relativeFilePath(path);
80 if (path.startsWith(".git")) {
81 return false;
82 }
83 path.replace(Util::endsWithGpg(), "");
84 retVal = path.contains(filterRegularExpression());
85 }
86 return retVal;
87}
88
94void StoreModel::setModelAndStore(QFileSystemModel *sourceModel,
95 QString passStore) {
96 setSourceModel(sourceModel);
97 fs = sourceModel;
98 store = std::move(passStore);
99}
100
107auto StoreModel::data(const QModelIndex &index, int role) const -> QVariant {
108 if (!index.isValid()) {
109 return {};
110 }
111
112 QVariant initial_value;
113 initial_value = QSortFilterProxyModel::data(index, role);
114
115 if (role == Qt::DisplayRole) {
116 QString name = initial_value.toString();
117 name.replace(Util::endsWithGpg(), "");
118 initial_value.setValue(name);
119 }
120
121 return initial_value;
122}
123
128auto StoreModel::supportedDropActions() const -> Qt::DropActions {
129 return Qt::CopyAction | Qt::MoveAction;
130}
131
136auto StoreModel::supportedDragActions() const -> Qt::DropActions {
137 return Qt::CopyAction | Qt::MoveAction;
138}
139
145auto StoreModel::flags(const QModelIndex &index) const -> Qt::ItemFlags {
146 Qt::ItemFlags defaultFlags = QSortFilterProxyModel::flags(index);
147
148 if (index.isValid()) {
149 return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
150 }
151 return Qt::ItemIsDropEnabled | defaultFlags;
152}
153
158auto StoreModel::mimeTypes() const -> QStringList {
159 QStringList types;
160 types << "application/vnd+qtpass.dragAndDropInfoPasswordStore";
161 return types;
162}
163
169auto StoreModel::mimeData(const QModelIndexList &indexes) const -> QMimeData * {
171
172 QByteArray encodedData;
173 // only use the first, otherwise we should enable multiselection
174 QModelIndex index = indexes.at(0);
175 if (index.isValid()) {
176 QModelIndex useIndex = mapToSource(index);
177
178 info.isDir = fs->fileInfo(useIndex).isDir();
179 info.isFile = fs->fileInfo(useIndex).isFile();
180 info.path = fs->fileInfo(useIndex).absoluteFilePath();
181 QDataStream stream(&encodedData, QIODevice::WriteOnly);
182 stream << info;
183 }
184
185 auto *mimeData = new QMimeData();
186 mimeData->setData("application/vnd+qtpass.dragAndDropInfoPasswordStore",
187 encodedData);
188 return mimeData;
189}
190
200auto StoreModel::canDropMimeData(const QMimeData *data, Qt::DropAction action,
201 int row, int column,
202 const QModelIndex &parent) const -> bool {
203#ifdef QT_DEBUG
204 qDebug() << action << row;
205#else
206 Q_UNUSED(action)
207 Q_UNUSED(row)
208#endif
209
210 QModelIndex useIndex =
211 this->index(parent.row(), parent.column(), parent.parent());
212 QByteArray encodedData =
213 data->data("application/vnd+qtpass.dragAndDropInfoPasswordStore");
214 QDataStream stream(&encodedData, QIODevice::ReadOnly);
216 stream >> info;
217 if (!data->hasFormat("application/vnd+qtpass.dragAndDropInfoPasswordStore")) {
218 return false;
219 }
220
221 if (column > 0) {
222 return false;
223 }
224
225 // you can drop a folder on a folder
226 if (fs->fileInfo(mapToSource(useIndex)).isDir() && info.isDir) {
227 return true;
228 }
229 // you can drop a file on a folder
230 if (fs->fileInfo(mapToSource(useIndex)).isDir() && info.isFile) {
231 return true;
232 }
233 // you can drop a file on a file
234 if (fs->fileInfo(mapToSource(useIndex)).isFile() && info.isFile) {
235 return true;
236 }
237
238 return false;
239}
240
250auto StoreModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
251 int row, int column, const QModelIndex &parent)
252 -> bool {
253 if (!canDropMimeData(data, action, row, column, parent)) {
254 return false;
255 }
256
257 if (action == Qt::IgnoreAction) {
258 return true;
259 }
260 QByteArray encodedData =
261 data->data("application/vnd+qtpass.dragAndDropInfoPasswordStore");
262
263 QDataStream stream(&encodedData, QIODevice::ReadOnly);
265 stream >> info;
266 QModelIndex destIndex =
267 this->index(parent.row(), parent.column(), parent.parent());
268 QFileInfo destFileinfo = fs->fileInfo(mapToSource(destIndex));
269 QFileInfo srcFileInfo = QFileInfo(info.path);
270 QString cleanedSrc = QDir::cleanPath(srcFileInfo.absoluteFilePath());
271 QString cleanedDest = QDir::cleanPath(destFileinfo.absoluteFilePath());
272 if (info.isDir) {
273 // dropped dir onto dir
274 if (destFileinfo.isDir()) {
275 QDir destDir = QDir(cleanedDest).filePath(srcFileInfo.fileName());
276 QString cleanedDestDir = QDir::cleanPath(destDir.absolutePath());
277 if (action == Qt::MoveAction) {
278 QtPassSettings::getPass()->Move(cleanedSrc, cleanedDestDir);
279 } else if (action == Qt::CopyAction) {
280 QtPassSettings::getPass()->Copy(cleanedSrc, cleanedDestDir);
281 }
282 }
283 } else if (info.isFile) {
284 // dropped file onto a directory
285 if (destFileinfo.isDir()) {
286 if (action == Qt::MoveAction) {
287 QtPassSettings::getPass()->Move(cleanedSrc, cleanedDest);
288 } else if (action == Qt::CopyAction) {
289 QtPassSettings::getPass()->Copy(cleanedSrc, cleanedDest);
290 }
291 } else if (destFileinfo.isFile()) {
292 // dropped file onto a file
293 int answer = QMessageBox::question(
294 nullptr, tr("force overwrite?"),
295 tr("overwrite %1 with %2?").arg(cleanedDest, cleanedSrc),
296 QMessageBox::Yes | QMessageBox::No);
297 bool force = answer == QMessageBox::Yes;
298 if (action == Qt::MoveAction) {
299 QtPassSettings::getPass()->Move(cleanedSrc, cleanedDest, force);
300 } else if (action == Qt::CopyAction) {
301 QtPassSettings::getPass()->Copy(cleanedSrc, cleanedDest, force);
302 }
303 }
304 }
305 return true;
306}
307
314auto StoreModel::lessThan(const QModelIndex &source_left,
315 const QModelIndex &source_right) const -> bool {
316/* matches logic in QFileSystemModelSorter::compareNodes() */
317#ifndef Q_OS_MAC
318 if (fs && (source_left.column() == 0 || source_left.column() == 1)) {
319 bool leftD = fs->isDir(source_left);
320 bool rightD = fs->isDir(source_right);
321
322 if (leftD ^ rightD) {
323 return leftD;
324 }
325 }
326#endif
327
328 return QSortFilterProxyModel::lessThan(source_left, source_right);
329}
static auto getPass() -> Pass *
Get currently active pass backend instance.
auto data(const QModelIndex &index, int role) const -> QVariant override
Get display data for index.
StoreModel()
Construct a StoreModel.
auto mimeTypes() const -> QStringList override
Get supported MIME types for drag/drop.
auto filterAcceptsRow(int, const QModelIndex &) const -> bool override
Filter whether a row should be displayed.
auto dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) -> bool override
Handle dropped MIME data.
auto mimeData(const QModelIndexList &indexes) const -> QMimeData *override
Create MIME data from indexes.
auto supportedDragActions() const -> Qt::DropActions override
Get supported drag actions.
auto showThis(const QModelIndex) const -> bool
Check if a specific index should be shown.
auto flags(const QModelIndex &index) const -> Qt::ItemFlags override
Get item flags for index.
auto canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const -> bool override
Check if drop is possible.
auto lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const -> bool override
Compare two indices for sorting.
void setModelAndStore(QFileSystemModel *sourceModel, QString passStore)
Initialize model with source model and store path.
auto supportedDropActions() const -> Qt::DropActions override
Get supported drop actions.
static auto endsWithGpg() -> const QRegularExpression &
Returns a regex to match .gpg file extensions.
Definition util.cpp:249
auto operator>>(QDataStream &in, dragAndDropInfoPasswordStore &dragAndDropInfoPasswordStore) -> QDataStream &
auto operator<<(QDataStream &out, const dragAndDropInfoPasswordStore &dragAndDropInfoPasswordStore) -> QDataStream &
Holds information for drag and drop operations in the password store.
Definition storemodel.h:25