raven-rhel8/extras/KF6/gear/gwenview/gwenview-24.05.1/app/folderviewcontextmanageritem.cpp

292 lines
8.8 KiB
C++
Raw Normal View History

2024-06-29 11:52:32 +06:00
// vim: set tabstop=4 shiftwidth=4 expandtab:
/*
Gwenview: an image viewer
Copyright 2009 Aurélien Gâteau <agateau@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// Self
#include "folderviewcontextmanageritem.h"
// Qt
#include <QDir>
#include <QDragEnterEvent>
#include <QHeaderView>
#include <QMimeData>
#include <QTreeView>
// KF
#include <KUrlMimeData>
// Local
#include "fileoperations.h"
#include "gwenview_app_debug.h"
#include "lib/touch/touch_helper.h"
#include <lib/contextmanager.h>
#include <lib/eventwatcher.h>
#include <lib/scrollerutils.h>
namespace Gwenview
{
/**
* This treeview accepts url drops
*/
class UrlDropTreeView : public QTreeView
{
public:
explicit UrlDropTreeView(QWidget *parent = nullptr)
: QTreeView(parent)
{
}
protected:
void dragEnterEvent(QDragEnterEvent *event) override
{
QAbstractItemView::dragEnterEvent(event);
setDirtyRegion(mDropRect);
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
}
}
void dragMoveEvent(QDragMoveEvent *event) override
{
QAbstractItemView::dragMoveEvent(event);
const QModelIndex index = indexAt(event->pos());
// This code has been copied from Dolphin
// (panels/folders/paneltreeview.cpp)
setDirtyRegion(mDropRect);
mDropRect = visualRect(index);
setDirtyRegion(mDropRect);
if (index.isValid()) {
event->acceptProposedAction();
} else {
event->ignore();
}
}
void dropEvent(QDropEvent *event) override
{
const QList<QUrl> urlList = KUrlMimeData::urlsFromMimeData(event->mimeData());
const QModelIndex index = indexAt(event->pos());
if (!index.isValid()) {
qCWarning(GWENVIEW_APP_LOG) << "Invalid index!";
return;
}
const QUrl destUrl = static_cast<MODEL_CLASS *>(model())->urlForIndex(index);
FileOperations::showMenuForDroppedUrls(this, urlList, destUrl);
}
bool viewportEvent(QEvent *event) override
{
if (event->type() == QEvent::TouchBegin) {
return true;
}
const QPoint pos = Touch_Helper::simpleTapPosition(event);
if (pos != QPoint(-1, -1)) {
expand(indexAt(pos));
Q_EMIT activated(indexAt(pos));
}
return QTreeView::viewportEvent(event);
}
private:
QRect mDropRect;
};
FolderViewContextManagerItem::FolderViewContextManagerItem(ContextManager *manager)
: AbstractContextManagerItem(manager)
{
mModel = nullptr;
setupView();
connect(contextManager(), &ContextManager::currentDirUrlChanged, this, &FolderViewContextManagerItem::slotCurrentDirUrlChanged);
}
void FolderViewContextManagerItem::slotCurrentDirUrlChanged(const QUrl &url)
{
if (url.isValid() && mUrlToSelect != url) {
mUrlToSelect = url.adjusted(QUrl::StripTrailingSlash | QUrl::NormalizePathSegments);
mExpandingIndex = QModelIndex();
}
if (!mView->isVisible()) {
return;
}
expandToSelectedUrl();
}
void FolderViewContextManagerItem::expandToSelectedUrl()
{
if (!mUrlToSelect.isValid()) {
return;
}
if (!mModel) {
setupModel();
}
const QModelIndex index = findClosestIndex(mExpandingIndex, mUrlToSelect);
if (!index.isValid()) {
return;
}
mExpandingIndex = index;
QUrl url = mModel->urlForIndex(mExpandingIndex);
if (mUrlToSelect == url) {
// We found our url
QItemSelectionModel *selModel = mView->selectionModel();
selModel->setCurrentIndex(mExpandingIndex, QItemSelectionModel::ClearAndSelect);
mView->scrollTo(mExpandingIndex);
mUrlToSelect = QUrl();
mExpandingIndex = QModelIndex();
} else {
// We found a parent of our url
mView->setExpanded(mExpandingIndex, true);
}
}
void FolderViewContextManagerItem::slotRowsInserted(const QModelIndex &parentIndex, int /*start*/, int /*end*/)
{
// Can't trigger the case where parentIndex is invalid, but it most
// probably happen when root items are created. In this case we trigger
// expandToSelectedUrl without checking the url.
// See bug #191771
if (!parentIndex.isValid() || mModel->urlForIndex(parentIndex).isParentOf(mUrlToSelect)) {
mExpandingIndex = parentIndex;
// Hack because otherwise indexes are not in correct order!
QMetaObject::invokeMethod(this, &FolderViewContextManagerItem::expandToSelectedUrl, Qt::QueuedConnection);
}
}
void FolderViewContextManagerItem::slotActivated(const QModelIndex &index)
{
if (!index.isValid()) {
return;
}
QUrl url = mModel->urlForIndex(index);
Q_EMIT urlChanged(url);
}
void FolderViewContextManagerItem::setupModel()
{
mModel = new MODEL_CLASS(this);
mView->setModel(mModel);
#ifndef USE_PLACETREE
for (int col = 1; col <= mModel->columnCount(); ++col) {
mView->header()->setSectionHidden(col, true);
}
mModel->dirLister()->openUrl(QUrl("/"));
#endif
QObject::connect(mModel, &MODEL_CLASS::rowsInserted, this, &FolderViewContextManagerItem::slotRowsInserted);
}
void FolderViewContextManagerItem::setupView()
{
mView = new UrlDropTreeView;
mView->setEditTriggers(QAbstractItemView::NoEditTriggers);
mView->setAcceptDrops(true);
mView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
mView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
// Necessary to get the drop target highlighted
mView->viewport()->setAttribute(Qt::WA_Hover);
mView->setHeaderHidden(true);
// This is tricky: QTreeView header has stretchLastSection set to true.
// In this configuration, the header gets quite wide and cause an
// horizontal scrollbar to appear.
// To avoid this, set stretchLastSection to false and resizeMode to
// Stretch (we still want the column to take the full width of the
// widget).
mView->header()->setStretchLastSection(false);
mView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
ScrollerUtils::setQScroller(mView->viewport());
setWidget(mView);
QObject::connect(mView, &QTreeView::activated, this, &FolderViewContextManagerItem::slotActivated);
EventWatcher::install(mView, QEvent::Show, this, SLOT(expandToSelectedUrl()));
}
QModelIndex FolderViewContextManagerItem::findClosestIndex(const QModelIndex &parent, const QUrl &wantedUrl)
{
Q_ASSERT(mModel);
QModelIndex index = parent;
if (!index.isValid()) {
index = findRootIndex(wantedUrl);
if (!index.isValid()) {
return {};
}
}
QUrl url = mModel->urlForIndex(index);
if (!url.isParentOf(wantedUrl)) {
qCWarning(GWENVIEW_APP_LOG) << url << "is not a parent of" << wantedUrl << "!";
return {};
}
QString relativePath = QDir(url.path()).relativeFilePath(wantedUrl.path());
QModelIndex lastFoundIndex = index;
const QStringList relativePathList = relativePath.split(QDir::separator(), Qt::SkipEmptyParts);
for (const QString &pathPart : relativePathList) {
bool found = false;
for (int row = 0; row < mModel->rowCount(lastFoundIndex); ++row) {
QModelIndex index = mModel->index(row, 0, lastFoundIndex);
if (index.data().toString() == pathPart) {
// FIXME: Check encoding
found = true;
lastFoundIndex = index;
break;
}
}
if (!found) {
break;
}
}
return lastFoundIndex;
}
QModelIndex FolderViewContextManagerItem::findRootIndex(const QUrl &wantedUrl)
{
QModelIndex matchIndex;
int matchUrlLength = 0;
for (int row = 0; row < mModel->rowCount(); ++row) {
QModelIndex index = mModel->index(row, 0);
QUrl url = mModel->urlForIndex(index);
int urlLength = url.url().length();
if (url.isParentOf(wantedUrl) && urlLength > matchUrlLength) {
matchIndex = index;
matchUrlLength = urlLength;
}
}
if (!matchIndex.isValid()) {
qCWarning(GWENVIEW_APP_LOG) << "Found no root index for" << wantedUrl;
}
return matchIndex;
}
} // namespace
#include "moc_folderviewcontextmanageritem.cpp"