14#include <QApplication>
16#include <QFileSystemModel>
19#include <QRegularExpression>
23 out << static_cast<quint8>(item.kind) << item.path;
50 const QModelIndex &sourceParent)
const
52 QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
61 if (sourceModel()->rowCount(index) > 0) {
62 for (
int nChild = 0; nChild < sourceModel()->rowCount(index); ++nChild) {
63 QModelIndex childIndex = sourceModel()->index(nChild, 0, index);
64 if (!childIndex.isValid()) {
73 QModelIndex useIndex = sourceModel()->index(index.row(), 0, index.parent());
74 QString path =
fs->filePath(useIndex);
75 path = QDir(
store).relativeFilePath(path);
76 if (path.startsWith(
".git")) {
80 retVal = path.contains(filterRegularExpression());
86 const QString &passStore) {
87 setSourceModel(sourceModel);
96 return mapFromSource(
fs->setRootPath(QDir::cleanPath(path)));
100#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
104 endFilterChange(QSortFilterProxyModel::Direction::Rows);
112 if (!index.isValid()) {
116 QVariant initial_value;
117 initial_value = QSortFilterProxyModel::data(index, role);
119 if (role == Qt::DisplayRole) {
120 QString name = initial_value.toString();
122 initial_value.setValue(name);
125 return initial_value;
129 return Qt::CopyAction | Qt::MoveAction;
133 return Qt::CopyAction | Qt::MoveAction;
137 Qt::ItemFlags defaultFlags = QSortFilterProxyModel::flags(index);
139 if (index.isValid()) {
140 return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
142 return Qt::ItemIsDropEnabled | defaultFlags;
147 types << kStoreDragMimeType;
154 if (indexes.isEmpty())
156 QByteArray encodedData;
158 QModelIndex index = indexes.at(0);
159 if (index.isValid()) {
160 QModelIndex useIndex = mapToSource(index);
161 const QFileInfo fileInfo =
fs->fileInfo(useIndex);
163 if (fileInfo.isDir()) {
165 }
else if (fileInfo.isFile()) {
168 info.
path = fileInfo.absoluteFilePath();
169 QDataStream stream(&encodedData, QIODevice::WriteOnly);
174 mimeData->setData(kStoreDragMimeType, encodedData);
180 const QModelIndex &parent)
const ->
bool {
181 qCDebug(lcQtPass) <<
"canDropMimeData" << action << row;
189 QModelIndex useIndex =
190 this->index(parent.row(), parent.column(), parent.parent());
198 if (
fs->fileInfo(mapToSource(useIndex)).isDir() &&
199 info.
kind == IK::Directory) {
203 if (
fs->fileInfo(mapToSource(useIndex)).isDir() && info.
kind == IK::File) {
207 if (
fs->fileInfo(mapToSource(useIndex)).isFile() && info.
kind == IK::File) {
215 int row,
int column,
const QModelIndex &parent)
221 if (action == Qt::IgnoreAction) {
225 if (action != Qt::MoveAction && action != Qt::CopyAction) {
238 -> std::optional<StoreDragItem> {
239 if (
data ==
nullptr || !
data->hasFormat(kStoreDragMimeType)) {
242 QByteArray encodedData =
data->data(kStoreDragMimeType);
243 if (encodedData.isEmpty()) {
246 QDataStream stream(&encodedData, QIODevice::ReadOnly);
249 if (stream.status() != QDataStream::Ok) {
256 Qt::DropAction action,
257 const QModelIndex &parent) ->
bool {
258 QModelIndex destIndex =
259 this->index(parent.row(), parent.column(), parent.parent());
260 QFileInfo destFileinfo =
fs->fileInfo(mapToSource(destIndex));
261 QFileInfo srcFileInfo = QFileInfo(info.path);
263 QString cleanedSrc = QDir::cleanPath(srcFileInfo.absoluteFilePath());
264 QString cleanedDest = QDir::cleanPath(destFileinfo.absoluteFilePath());
271 <<
"executeDropAction: rejecting drop that escapes the store"
272 <<
"(src=" << cleanedSrc <<
"dest=" << cleanedDest <<
")";
279 if (!destFileinfo.isDir()) {
282 const QString destDir =
283 QDir::cleanPath(QDir(cleanedDest).filePath(srcFileInfo.fileName()));
284 return performDrop(cleanedSrc, destDir, action,
false);
289 if (destFileinfo.isDir()) {
290 return performDrop(cleanedSrc, cleanedDest, action,
false);
293 cleanedSrc, cleanedDest, action,
295 qobject_cast<QWidget *>(QObject::parent()), tr(
"Force overwrite?"),
296 tr(
"overwrite %1 with %2?").arg(cleanedDest, cleanedSrc)));
299 <<
"executeDropAction: unexpected ItemKind, ignoring drop";
305 const QString &cleanedDest, Qt::DropAction action,
306 bool force) ->
bool {
310 if (action == Qt::MoveAction) {
311 m_pass->Move(cleanedSrc, cleanedDest, force);
312 }
else if (action == Qt::CopyAction) {
313 m_pass->Copy(cleanedSrc, cleanedDest, force);
319 const QModelIndex &source_right)
const ->
bool {
322 if (
fs && (source_left.column() == 0 || source_left.column() == 1)) {
323 bool leftD =
fs->isDir(source_left);
324 bool rightD =
fs->isDir(source_right);
326 if (leftD ^ rightD) {
332 return QSortFilterProxyModel::lessThan(source_left, source_right);
Abstract base class for password store operations.
static auto isPathInStore(const QString &storeRoot, const QString &candidate) -> bool
Check that a candidate path resolves inside the password store root, after following symlinks and res...
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.
static auto parseDropData(const QMimeData *data) -> std::optional< StoreDragItem >
Decode the drag payload from data.
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.
Pass * m_pass
Backend that performs drag-and-drop Move/Copy; not owned, null until setPass(), in which case drops a...
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 executeDropAction(const StoreDragItem &info, Qt::DropAction action, const QModelIndex &parent) -> bool
Resolve a validated drop into a Move or Copy.
void setPass(Pass *pass)
Inject the Pass backend for drag-and-drop Move/Copy operations.
auto rootIndexFor(const QString &path) -> QModelIndex
Set the source filesystem root and map it to a proxy index.
QString store
Store root used to make paths relative for filtering and for the drop boundary check.
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 performDrop(const QString &cleanedSrc, const QString &cleanedDest, Qt::DropAction action, bool force) -> bool
Perform the actual Move/Copy for a validated drop.
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.
QFileSystemModel * fs
The wrapped file system model, set by setModelAndStore(); null until then, which makes showThis() hid...
auto supportedDropActions() const -> Qt::DropActions override
Get supported drop actions.
static auto endsWithGpg() -> const QRegularExpression &
Returns a regex to match .gpg file extensions.
auto askYes(QWidget *parent, const QString &title, const QString &text) -> bool
Ask a yes/no question in plain text.
Pass, the abstract password-store backend that RealPass and ImitatePass implement,...
PathValidator: is a path inside the password store, and how is it spelled relative to the store root.
QMessageBox helpers that force Qt::PlainText so store-controlled names can never be read as rich-text...
The "qtpass" logging category.
auto operator>>(QDataStream &in, StoreDragItem &item) -> QDataStream &
Deserialize a StoreDragItem from the QtPass MIME type.
auto operator<<(QDataStream &out, const StoreDragItem &item) -> QDataStream &
Serialize a StoreDragItem for the QtPass MIME type.
StoreModel, the filtering/sorting proxy over the store's QFileSystemModel, and StoreDragItem,...
What a drag from the store tree carries: the kind of the dragged item and its path.
ItemKind
Type of the dragged item.
Util: static helpers for the process environment, binary discovery, store paths, URL safety and the l...