9#include <QFileSystemModel>
12#include <QRegularExpression>
61 const QModelIndex &sourceParent)
const
63 QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
79 if (sourceModel()->rowCount(index) > 0) {
80 for (
int nChild = 0; nChild < sourceModel()->rowCount(index); ++nChild) {
81 QModelIndex childIndex = sourceModel()->index(nChild, 0, index);
82 if (!childIndex.isValid()) {
91 QModelIndex useIndex = sourceModel()->index(index.row(), 0, index.parent());
92 QString path = fs->filePath(useIndex);
93 path = QDir(store).relativeFilePath(path);
94 if (path.startsWith(
".git")) {
98 retVal = path.contains(filterRegularExpression());
109 const QString &passStore) {
110 setSourceModel(sourceModel);
116#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
123 endFilterChange(QSortFilterProxyModel::Direction::Rows);
129#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
130 QSortFilterProxyModel::invalidateFilter();
144 if (!index.isValid()) {
148 QVariant initial_value;
149 initial_value = QSortFilterProxyModel::data(index, role);
151 if (role == Qt::DisplayRole) {
152 QString name = initial_value.toString();
154 initial_value.setValue(name);
157 return initial_value;
165 return Qt::CopyAction | Qt::MoveAction;
173 return Qt::CopyAction | Qt::MoveAction;
182 Qt::ItemFlags defaultFlags = QSortFilterProxyModel::flags(index);
184 if (index.isValid()) {
185 return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
187 return Qt::ItemIsDropEnabled | defaultFlags;
196 types <<
"application/vnd+qtpass.dragAndDropInfoPasswordStore";
208 QByteArray encodedData;
210 QModelIndex index = indexes.at(0);
211 if (index.isValid()) {
212 QModelIndex useIndex = mapToSource(index);
213 const QFileInfo fileInfo = fs->fileInfo(useIndex);
215 if (fileInfo.isDir()) {
217 }
else if (fileInfo.isFile()) {
220 info.
path = fileInfo.absoluteFilePath();
221 QDataStream stream(&encodedData, QIODevice::WriteOnly);
226 mimeData->setData(
"application/vnd+qtpass.dragAndDropInfoPasswordStore",
242 const QModelIndex &parent)
const ->
bool {
244 qDebug() << action << row;
250 if (
data ==
nullptr ||
251 !
data->hasFormat(
"application/vnd+qtpass.dragAndDropInfoPasswordStore")) {
255 QByteArray encodedData =
256 data->data(
"application/vnd+qtpass.dragAndDropInfoPasswordStore");
257 if (encodedData.isEmpty()) {
260 QDataStream stream(&encodedData, QIODevice::ReadOnly);
263 if (stream.status() != QDataStream::Ok) {
267 QModelIndex useIndex =
268 this->index(parent.row(), parent.column(), parent.parent());
276 if (fs->fileInfo(mapToSource(useIndex)).isDir() &&
277 info.
kind == IK::Directory) {
281 if (fs->fileInfo(mapToSource(useIndex)).isDir() && info.
kind == IK::File) {
285 if (fs->fileInfo(mapToSource(useIndex)).isFile() && info.
kind == IK::File) {
302 int row,
int column,
const QModelIndex &parent)
308 if (action == Qt::IgnoreAction) {
312 if (action != Qt::MoveAction && action != Qt::CopyAction) {
317 if (!parseDropData(
data, &info)) {
321 return executeDropAction(info, action, parent);
324auto StoreModel::parseDropData(
const QMimeData *data,
326 QByteArray encodedData =
327 data->data(
"application/vnd+qtpass.dragAndDropInfoPasswordStore");
328 if (encodedData.isEmpty()) {
332 QDataStream stream(&encodedData, QIODevice::ReadOnly);
335 if (stream.status() != QDataStream::Ok) {
344 Qt::DropAction action,
345 const QModelIndex &parent) ->
bool {
346 QModelIndex destIndex =
347 this->index(parent.row(), parent.column(), parent.parent());
348 QFileInfo destFileinfo = fs->fileInfo(mapToSource(destIndex));
349 QFileInfo srcFileInfo = QFileInfo(info.
path);
351 QString cleanedSrc = QDir::cleanPath(srcFileInfo.absoluteFilePath());
352 QString cleanedDest = QDir::cleanPath(destFileinfo.absoluteFilePath());
356 return handleDirDrop(cleanedSrc, destFileinfo, srcFileInfo, action);
358 return handleFileDrop(cleanedSrc, cleanedDest, destFileinfo, action);
360 qWarning() <<
"executeDropAction: unexpected ItemKind, ignoring drop";
365auto StoreModel::handleDirDrop(
const QString &cleanedSrc,
366 const QFileInfo &destFileinfo,
367 const QFileInfo &srcFileInfo,
368 Qt::DropAction action) ->
bool {
369 if (!destFileinfo.isDir()) {
373 QDir destDir = QDir(QDir::cleanPath(destFileinfo.absoluteFilePath()))
374 .filePath(srcFileInfo.fileName());
375 QString cleanedDestDir = QDir::cleanPath(destDir.absolutePath());
377 if (action == Qt::MoveAction) {
379 }
else if (action == Qt::CopyAction) {
385auto StoreModel::handleFileDrop(
const QString &cleanedSrc,
386 const QString &cleanedDest,
387 const QFileInfo &destFileinfo,
388 Qt::DropAction action) ->
bool {
389 if (destFileinfo.isDir()) {
390 return handleFileToDirDrop(cleanedSrc, cleanedDest, action);
392 return handleFileToFileDrop(cleanedSrc, cleanedDest, action);
395auto StoreModel::handleFileToDirDrop(
const QString &cleanedSrc,
396 const QString &cleanedDest,
397 Qt::DropAction action) ->
bool {
398 if (action == Qt::MoveAction) {
400 }
else if (action == Qt::CopyAction) {
406auto StoreModel::handleFileToFileDrop(
const QString &cleanedSrc,
407 const QString &cleanedDest,
408 Qt::DropAction action) ->
bool {
409 QWidget *parentWidget = qobject_cast<QWidget *>(parent());
410 int answer = QMessageBox::question(
411 parentWidget, tr(
"Force overwrite?"),
412 tr(
"overwrite %1 with %2?").arg(cleanedDest, cleanedSrc),
413 QMessageBox::Yes | QMessageBox::No);
414 bool force = answer == QMessageBox::Yes;
416 if (action == Qt::MoveAction) {
418 }
else if (action == Qt::CopyAction) {
431 const QModelIndex &source_right)
const ->
bool {
434 if (fs && (source_left.column() == 0 || source_left.column() == 1)) {
435 bool leftD = fs->isDir(source_left);
436 bool rightD = fs->isDir(source_right);
438 if (leftD ^ rightD) {
444 return QSortFilterProxyModel::lessThan(source_left, source_right);
static auto getPass() -> Pass *
Get currently active pass backend instance.
auto filterAcceptsRow(int source_row, const QModelIndex &source_parent) const -> bool override
Filter whether a row should be displayed.
auto data(const QModelIndex &index, int role) const -> QVariant override
Get display data for index.
StoreModel()
Construct a StoreModel.
auto showThis(const QModelIndex &index) const -> bool
Check if a specific index should be shown.
auto mimeTypes() const -> QStringList override
Get supported MIME types for drag/drop.
void setModelAndStore(QFileSystemModel *sourceModel, const QString &passStore)
Initialize model with source model and store path.
auto dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) -> bool override
Handle dropped MIME data.
void setStore(const QString &passStore)
Update the store path used for filtering without changing the source model.
auto mimeData(const QModelIndexList &indexes) const -> QMimeData *override
Create MIME data from indexes.
auto supportedDragActions() const -> Qt::DropActions override
Get supported drag actions.
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.
auto supportedDropActions() const -> Qt::DropActions override
Get supported drop actions.
static auto endsWithGpg() -> const QRegularExpression &
Returns a regex to match .gpg file extensions.
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.