Advance Wayland and KDE package bring-up
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2008, 2009, 2015 David Faure <faure@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
#include "kfilecopytomenu.h"
|
||||
#include "kfilecopytomenu_p.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QDir>
|
||||
#include <QFileDialog>
|
||||
#include <QIcon>
|
||||
#include <QMimeDatabase>
|
||||
#include <QMimeType>
|
||||
|
||||
#include "../utils_p.h"
|
||||
|
||||
#include <KIO/CopyJob>
|
||||
#include <KIO/FileUndoManager>
|
||||
#include <KIO/JobUiDelegate>
|
||||
|
||||
#include <KJobWidgets>
|
||||
#include <KLocalizedString>
|
||||
#include <KSharedConfig>
|
||||
#include <KStringHandler>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include "windows.h"
|
||||
#endif
|
||||
|
||||
static constexpr int s_maxRecentDirs = 10; // Hardcoded max size
|
||||
|
||||
KFileCopyToMenuPrivate::KFileCopyToMenuPrivate(KFileCopyToMenu *qq, QWidget *parentWidget)
|
||||
: q(qq)
|
||||
, m_urls()
|
||||
, m_parentWidget(parentWidget)
|
||||
, m_readOnly(false)
|
||||
, m_autoErrorHandling(false)
|
||||
{
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
KFileCopyToMenu::KFileCopyToMenu(QWidget *parentWidget)
|
||||
: QObject(parentWidget)
|
||||
, d(new KFileCopyToMenuPrivate(this, parentWidget))
|
||||
{
|
||||
}
|
||||
|
||||
KFileCopyToMenu::~KFileCopyToMenu() = default;
|
||||
|
||||
void KFileCopyToMenu::setUrls(const QList<QUrl> &urls)
|
||||
{
|
||||
d->m_urls = urls;
|
||||
}
|
||||
|
||||
void KFileCopyToMenu::setReadOnly(bool ro)
|
||||
{
|
||||
d->m_readOnly = ro;
|
||||
}
|
||||
|
||||
void KFileCopyToMenu::setAutoErrorHandlingEnabled(bool b)
|
||||
{
|
||||
d->m_autoErrorHandling = b;
|
||||
}
|
||||
|
||||
void KFileCopyToMenu::addActionsTo(QMenu *menu) const
|
||||
{
|
||||
QMenu *mainCopyMenu = new KFileCopyToMainMenu(menu, d.get(), Copy);
|
||||
mainCopyMenu->setTitle(i18nc("@title:menu", "Copy To"));
|
||||
mainCopyMenu->menuAction()->setObjectName(QStringLiteral("copyTo_submenu")); // for the unittest
|
||||
menu->addMenu(mainCopyMenu);
|
||||
|
||||
if (!d->m_readOnly) {
|
||||
QMenu *mainMoveMenu = new KFileCopyToMainMenu(menu, d.get(), Move);
|
||||
mainMoveMenu->setTitle(i18nc("@title:menu", "Move To"));
|
||||
mainMoveMenu->menuAction()->setObjectName(QStringLiteral("moveTo_submenu")); // for the unittest
|
||||
menu->addMenu(mainMoveMenu);
|
||||
}
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
KFileCopyToMainMenu::KFileCopyToMainMenu(QMenu *parent, KFileCopyToMenuPrivate *_d, MenuType menuType)
|
||||
: QMenu(parent)
|
||||
, m_menuType(menuType)
|
||||
, m_actionGroup(static_cast<QWidget *>(nullptr))
|
||||
, d(_d)
|
||||
, m_recentDirsGroup(KSharedConfig::openConfig(), m_menuType == Copy ? QStringLiteral("kuick-copy") : QStringLiteral("kuick-move"))
|
||||
{
|
||||
connect(this, &KFileCopyToMainMenu::aboutToShow, this, &KFileCopyToMainMenu::slotAboutToShow);
|
||||
connect(&m_actionGroup, &QActionGroup::triggered, this, &KFileCopyToMainMenu::slotTriggered);
|
||||
}
|
||||
|
||||
void KFileCopyToMainMenu::slotAboutToShow()
|
||||
{
|
||||
clear();
|
||||
KFileCopyToDirectoryMenu *subMenu;
|
||||
// Home Folder
|
||||
subMenu = new KFileCopyToDirectoryMenu(this, this, QDir::homePath());
|
||||
subMenu->setTitle(i18nc("@title:menu", "Home Folder"));
|
||||
subMenu->setIcon(QIcon::fromTheme(QStringLiteral("go-home")));
|
||||
QAction *act = addMenu(subMenu);
|
||||
act->setObjectName(QStringLiteral("home"));
|
||||
|
||||
// Root Folder
|
||||
#ifndef Q_OS_WIN
|
||||
subMenu = new KFileCopyToDirectoryMenu(this, this, QDir::rootPath());
|
||||
subMenu->setTitle(i18nc("@title:menu", "Root Folder"));
|
||||
subMenu->setIcon(QIcon::fromTheme(QStringLiteral("folder-red")));
|
||||
act = addMenu(subMenu);
|
||||
act->setObjectName(QStringLiteral("root"));
|
||||
#else
|
||||
const QFileInfoList drives = QDir::drives();
|
||||
for (const QFileInfo &info : drives) {
|
||||
QString driveIcon = QStringLiteral("drive-harddisk");
|
||||
const uint type = GetDriveTypeW((wchar_t *)info.absoluteFilePath().utf16());
|
||||
switch (type) {
|
||||
case DRIVE_REMOVABLE:
|
||||
driveIcon = QStringLiteral("drive-removable-media");
|
||||
break;
|
||||
case DRIVE_FIXED:
|
||||
driveIcon = QStringLiteral("drive-harddisk");
|
||||
break;
|
||||
case DRIVE_REMOTE:
|
||||
driveIcon = QStringLiteral("network-server");
|
||||
break;
|
||||
case DRIVE_CDROM:
|
||||
driveIcon = QStringLiteral("drive-optical");
|
||||
break;
|
||||
case DRIVE_RAMDISK:
|
||||
case DRIVE_UNKNOWN:
|
||||
case DRIVE_NO_ROOT_DIR:
|
||||
default:
|
||||
driveIcon = QStringLiteral("drive-harddisk");
|
||||
}
|
||||
subMenu = new KFileCopyToDirectoryMenu(this, this, info.absoluteFilePath());
|
||||
subMenu->setTitle(info.absoluteFilePath());
|
||||
subMenu->setIcon(QIcon::fromTheme(driveIcon));
|
||||
addMenu(subMenu);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Browse... action, shows a file dialog
|
||||
auto *browseAction = new QAction(i18nc("@action:inmenu in Copy To or Move To submenu", "Browse…"), this);
|
||||
browseAction->setObjectName(QStringLiteral("browse"));
|
||||
connect(browseAction, &QAction::triggered, this, &KFileCopyToMainMenu::slotBrowse);
|
||||
addAction(browseAction);
|
||||
|
||||
addSeparator(); // Qt handles removing it automatically if it's last in the menu, nice.
|
||||
|
||||
// Recent Destinations
|
||||
const QStringList recentDirs = m_recentDirsGroup.readPathEntry("Paths", QStringList());
|
||||
for (const QString &recentDir : recentDirs) {
|
||||
const QUrl url = QUrl::fromLocalFile(recentDir);
|
||||
const QString text = KStringHandler::csqueeze(url.toDisplayString(QUrl::PreferLocalFile), 60); // shorten very long paths (#61386)
|
||||
QAction *act = new QAction(text, this);
|
||||
act->setObjectName(recentDir);
|
||||
act->setData(url);
|
||||
m_actionGroup.addAction(act);
|
||||
addAction(act);
|
||||
}
|
||||
}
|
||||
|
||||
void KFileCopyToMainMenu::slotBrowse()
|
||||
{
|
||||
const QUrl dest = QFileDialog::getExistingDirectoryUrl(d->m_parentWidget ? d->m_parentWidget : this);
|
||||
if (!dest.isEmpty()) {
|
||||
copyOrMoveTo(dest);
|
||||
}
|
||||
}
|
||||
|
||||
void KFileCopyToMainMenu::slotTriggered(QAction *action)
|
||||
{
|
||||
const QUrl url = action->data().toUrl();
|
||||
Q_ASSERT(!url.isEmpty());
|
||||
copyOrMoveTo(url);
|
||||
}
|
||||
|
||||
void KFileCopyToMainMenu::copyOrMoveTo(const QUrl &dest)
|
||||
{
|
||||
// Insert into the recent destinations list
|
||||
QStringList recentDirs = m_recentDirsGroup.readPathEntry("Paths", QStringList());
|
||||
const QString niceDest = dest.toDisplayString(QUrl::PreferLocalFile);
|
||||
if (!recentDirs.contains(niceDest)) { // don't change position if already there, moving stuff is bad usability
|
||||
recentDirs.prepend(niceDest);
|
||||
if (recentDirs.size() > s_maxRecentDirs) {
|
||||
recentDirs.erase(recentDirs.begin() + s_maxRecentDirs, recentDirs.end());
|
||||
}
|
||||
m_recentDirsGroup.writePathEntry("Paths", recentDirs);
|
||||
}
|
||||
|
||||
// #199549: add a trailing slash to avoid unexpected results when the
|
||||
// dest doesn't exist anymore: it was creating a file with the name of
|
||||
// the now non-existing dest.
|
||||
QUrl dirDest = dest;
|
||||
Utils::appendSlashToPath(dirDest);
|
||||
|
||||
// And now let's do the copy or move -- with undo/redo support.
|
||||
KIO::CopyJob *job = m_menuType == Copy ? KIO::copy(d->m_urls, dirDest) : KIO::move(d->m_urls, dirDest);
|
||||
KIO::FileUndoManager::self()->recordCopyJob(job);
|
||||
KJobWidgets::setWindow(job, d->m_parentWidget ? d->m_parentWidget : this);
|
||||
if (job->uiDelegate()) {
|
||||
job->uiDelegate()->setAutoErrorHandlingEnabled(d->m_autoErrorHandling);
|
||||
}
|
||||
connect(job, &KIO::CopyJob::result, this, [this](KJob *job) {
|
||||
Q_EMIT d->q->error(job->error(), job->errorString());
|
||||
});
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
KFileCopyToDirectoryMenu::KFileCopyToDirectoryMenu(QMenu *parent, KFileCopyToMainMenu *mainMenu, const QString &path)
|
||||
: QMenu(parent)
|
||||
, m_mainMenu(mainMenu)
|
||||
, m_path(Utils::slashAppended(path))
|
||||
{
|
||||
connect(this, &KFileCopyToDirectoryMenu::aboutToShow, this, &KFileCopyToDirectoryMenu::slotAboutToShow);
|
||||
}
|
||||
|
||||
void KFileCopyToDirectoryMenu::slotAboutToShow()
|
||||
{
|
||||
clear();
|
||||
QAction *act = new QAction(m_mainMenu->menuType() == Copy ? i18nc("@title:menu", "Copy Here") : i18nc("@title:menu", "Move Here"), this);
|
||||
act->setData(QUrl::fromLocalFile(m_path));
|
||||
act->setEnabled(QFileInfo(m_path).isWritable());
|
||||
m_mainMenu->actionGroup().addAction(act);
|
||||
addAction(act);
|
||||
|
||||
addSeparator(); // Qt handles removing it automatically if it's last in the menu, nice.
|
||||
|
||||
// List directory
|
||||
// All we need is sub folder names, their permissions, their icon.
|
||||
// KDirLister or KIO::listDir would fetch much more info, and would be async,
|
||||
// and we only care about local directories so we use QDir directly.
|
||||
QDir dir(m_path);
|
||||
const QStringList entries = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::LocaleAware);
|
||||
const QMimeDatabase db;
|
||||
const QMimeType dirMime = db.mimeTypeForName(QStringLiteral("inode/directory"));
|
||||
for (const QString &subDir : entries) {
|
||||
QString subPath = m_path + subDir;
|
||||
KFileCopyToDirectoryMenu *subMenu = new KFileCopyToDirectoryMenu(this, m_mainMenu, subPath);
|
||||
QString menuTitle(subDir);
|
||||
// Replace '&' by "&&" to make sure that '&' inside the directory name is displayed
|
||||
// correctly and not misinterpreted as an indicator for a keyboard shortcut
|
||||
subMenu->setTitle(menuTitle.replace(QLatin1Char('&'), QLatin1String("&&")));
|
||||
const QString iconName = dirMime.iconName();
|
||||
subMenu->setIcon(QIcon::fromTheme(iconName));
|
||||
if (QFileInfo(subPath).isSymLink()) {
|
||||
QFont font = subMenu->menuAction()->font();
|
||||
font.setItalic(true);
|
||||
subMenu->menuAction()->setFont(font);
|
||||
}
|
||||
addMenu(subMenu);
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_kfilecopytomenu.cpp"
|
||||
#include "moc_kfilecopytomenu_p.cpp"
|
||||
Reference in New Issue
Block a user