diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..a71b4bd --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,39 @@ +name: Build + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + debian: + name: Debian + runs-on: ubuntu-latest + container: docker.io/library/debian:sid + steps: + - name: Checkout Source + uses: actions/checkout@v2 + - name: Update repository + run: apt-get update -y + - name: Install the basic dev packages + run: apt-get install -y equivs curl git devscripts lintian build-essential automake autotools-dev cmake g++ + - name: Install build dependencies + run: mk-build-deps -i -t "apt-get --yes" -r + - name: Build Package + run: dpkg-buildpackage -b -uc -us -j$(nproc) + + ubuntu: + name: Ubuntu + runs-on: ubuntu-latest + steps: + - name: Checkout Source + uses: actions/checkout@v2 + - name: Update repository + run: sudo apt-get update -y + - name: Install the basic dev packages + run: sudo apt-get install -y equivs curl git devscripts lintian build-essential automake autotools-dev cmake g++ + - name: Install build dependencies + run: sudo mk-build-deps -i -t "apt-get --yes" -r + - name: Build Package + run: dpkg-buildpackage -b -uc -us -j$(nproc) diff --git a/.gitignore b/.gitignore index 0b823ea..4e47391 100644 --- a/.gitignore +++ b/.gitignore @@ -52,4 +52,5 @@ compile_commands.json *creator.user* /build/* -.vscode \ No newline at end of file +.vscode +tags diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c01c45..fee3c2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,13 +12,27 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt5 COMPONENTS Core DBus Quick LinguistTools REQUIRED) -find_package(FishUI REQUIRED) +# find_package(FishUI REQUIRED) find_package(KF5KIO) find_package(KF5Solid) +find_package(KF5WindowSystem) +find_package(KF5Config) + +qt5_add_dbus_adaptor(DBUS_SOURCES + com.cutefish.FileManager.xml + application.h Application) add_executable(cutefish-filemanager main.cpp + application.cpp + window.cpp + dbusinterface.cpp + + draganddrop/declarativedroparea.cpp + draganddrop/declarativedragdropevent.cpp + draganddrop/declarativemimedata.cpp + model/foldermodel.cpp model/placesmodel.cpp model/placesitem.cpp @@ -26,24 +40,38 @@ add_executable(cutefish-filemanager model/dirlister.cpp model/positioner.cpp - dialogs/propertiesdialog.cpp + cio/cfilejob.cpp + cio/cfilesizejob.cpp + dialogs/createfolderdialog.cpp + dialogs/filepropertiesdialog.cpp + dialogs/openwithdialog.cpp widgets/rubberband.cpp widgets/itemviewadapter.cpp + desktop/desktop.cpp desktop/desktopview.cpp desktop/desktopsettings.cpp + desktop/dockdbusinterface.cpp helper/datehelper.cpp - helper/thumbnailer.cpp helper/pathhistory.cpp helper/fm.cpp helper/shortcut.cpp - helper/thumbnailerjob.cpp + helper/filelauncher.cpp + helper/keyboardsearchmanager.cpp + + mimetype/mimeappmanager.cpp + mimetype/xdgdesktopfile.cpp + + thumbnailer/thumbnailprovider.cpp + thumbnailer/thumbnailcache.cpp desktopiconprovider.cpp qml.qrc + + ${DBUS_SOURCES} ) target_link_libraries(cutefish-filemanager @@ -56,8 +84,10 @@ target_link_libraries(cutefish-filemanager KF5::KIOFileWidgets KF5::KIOWidgets KF5::Solid + KF5::WindowSystem + KF5::ConfigCore - FishUI + # FishUI ) file(GLOB TS_FILES translations/*.ts) @@ -65,6 +95,6 @@ qt5_create_translation(QM_FILES ${TS_FILES}) add_custom_target(translations DEPENDS ${QM_FILES} SOURCES ${TS_FILES}) add_dependencies(cutefish-filemanager translations) -install(TARGETS cutefish-filemanager RUNTIME DESTINATION /usr/bin) +install(TARGETS cutefish-filemanager RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES cutefish-filemanager.desktop DESTINATION "/usr/share/applications") install(FILES ${QM_FILES} DESTINATION /usr/share/cutefish-filemanager/translations) diff --git a/README.md b/README.md index 5c9009f..4284429 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,25 @@ -# File Manager +# File Manager Vi version -Cutefish File Manager, simple to use, beautiful, and retain the classic PC interactive design. +Cutefish File Manager, simple to use, beautiful, and retain the classic PC interactive design. + +On this branch, the Cutefish File Manager has an even easier way to browse your files thanks to the vi mode. Instead of the classical shortcuts, vim fans will be pleased to use some of the vim shortcuts to browse their files. + +![screenshot](screenshots/Screenshot_20211025_151224.png) ## Dependencies ### Ubuntu ``` -sudo apt install libkf5solid-dev libkf5kio-dev -y +sudo apt install equivs curl git devscripts lintian build-essential automake autotools-dev --no-install-recommends + +sudo mk-build-deps -i -t "apt-get --yes" -r +``` + +### Debian + +``` +sudo apt install build-essential cmake extra-cmake-modules libkf5kio-dev libkf5solid-dev libkf5windowsystem-dev libkf5config-dev qtbase5-dev qtbase5-private-dev qtdeclarative5-dev qtquickcontrols2-5-dev qttools5-dev qttools5-dev-tools ``` ### ArchLinux @@ -19,9 +31,10 @@ sudo pacman -S extra-cmake-modules qt5-base qt5-quickcontrols2 taglib kio ## Build ```shell +git checkout vi-mode mkdir build cd build -cmake .. +cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr .. make ``` @@ -31,6 +44,26 @@ make sudo make install ``` +## Keybindings + +Most of those keybindings are coming from Vim, but not all of them. Here is a list of them : +- h,j,k,l : directions, +- y : (yank) copy, +- p : paste here, +- r : rename, +- Return/Enter : open/launch, +- % : display hidden files, +- u : undo last change, +- d : cut, +- x : delete, +- q : close the window, +- a : refresh, +- colon (:) : focus path input, +- v : select all files, +- backspace : go back + +> Developper info : all of these shortcuts are noted in `helper/shortcut.h` + ## License This project has been licensed by GPLv3. diff --git a/application.cpp b/application.cpp new file mode 100644 index 0000000..9adb65b --- /dev/null +++ b/application.cpp @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#include "application.h" +#include "dbusinterface.h" +#include "window.h" +#include "desktop/desktop.h" +#include "thumbnailer/thumbnailprovider.h" +#include "filemanageradaptor.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +// KIO +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Application::Application(int& argc, char** argv) + : QApplication(argc, argv) + , m_instance(false) +{ + if (QDBusConnection::sessionBus().registerService("com.cutefish.FileManager")) { + setOrganizationName("cutefishos"); + setWindowIcon(QIcon::fromTheme("file-manager")); + + new FileManagerAdaptor(this); + new DBusInterface; + QDBusConnection::sessionBus().registerObject("/FileManager", this); + + // Translations + QLocale locale; + QString qmFilePath = QString("%1/%2.qm").arg("/usr/share/cutefish-filemanager/translations/").arg(locale.name()); + if (QFile::exists(qmFilePath)) { + QTranslator *translator = new QTranslator(this); + if (translator->load(qmFilePath)) { + installTranslator(translator); + } else { + translator->deleteLater(); + } + } + + m_instance = true; + } +} + +int Application::run() +{ + if (!parseCommandLineArgs()) + return 0; + + return QApplication::exec(); +} + +void Application::openFiles(const QStringList &paths) +{ + for (const QString &path : paths) { + openWindow(path); + } +} + +void Application::moveToTrash(const QStringList &paths) +{ + if (paths.isEmpty()) + return; + + QList urls; + + for (const QString &path : paths) { + urls.append(QUrl::fromLocalFile(path)); + } + + KIO::Job *job = KIO::trash(urls); + job->uiDelegate()->setAutoErrorHandlingEnabled(true); + KIO::FileUndoManager::self()->recordJob(KIO::FileUndoManager::Trash, urls, QUrl(QStringLiteral("trash:/")), job); +} + +void Application::emptyTrash() +{ + Window *w = new Window; + w->load(QUrl("qrc:/qml/Dialogs/EmptyTrashDialog.qml")); +} + +void Application::openWindow(const QString &path) +{ + Window *w = new Window; + w->rootContext()->setContextProperty("arg", path); + w->addImageProvider("thumbnailer", new ThumbnailProvider()); + w->load(QUrl("qrc:/qml/main.qml")); +} + +QStringList Application::formatUriList(const QStringList &list) +{ + QStringList val; + + for (const QString &path : list) { + val.append(path == "." ? QDir::currentPath() : path); + } + + if (val.isEmpty()) { + val.append(QDir::currentPath()); + } + + return val; +} + +bool Application::parseCommandLineArgs() +{ + QCommandLineParser parser; + parser.setApplicationDescription(QStringLiteral("File Manager")); + parser.addHelpOption(); + + parser.addPositionalArgument("files", "Files", "[FILE1, FILE2,...]"); + + QCommandLineOption desktopOption(QStringList() << "d" << "desktop" << "Desktop Mode"); + parser.addOption(desktopOption); + + QCommandLineOption emptyTrashOption(QStringList() << "e" << "empty-trash" << "Empty Trash"); + parser.addOption(emptyTrashOption); + + QCommandLineOption moveToTrashOption(QStringList() << "mtr" << "move-to-trash" << "Move To Trash"); + parser.addOption(moveToTrashOption); + + parser.process(arguments()); + + if (m_instance) { + QPixmapCache::setCacheLimit(2048); + + if (parser.isSet(desktopOption)) { + Desktop desktop; + } else { + openFiles(formatUriList(parser.positionalArguments())); + } + } else { + QDBusInterface iface("com.cutefish.FileManager", + "/FileManager", + "com.cutefish.FileManager", + QDBusConnection::sessionBus(), this); + + if (parser.isSet(emptyTrashOption)) { + // Empty Dialog + iface.call("emptyTrash"); + } else if (parser.isSet(moveToTrashOption)) { + iface.call("moveToTrash", parser.positionalArguments()); + } else { + iface.call("openFiles", formatUriList(parser.positionalArguments())); + } + } + + return m_instance; +} diff --git a/application.h b/application.h new file mode 100644 index 0000000..b87df0f --- /dev/null +++ b/application.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#ifndef APPLICATION_H +#define APPLICATION_H + +#include + +class Application : public QApplication +{ + Q_OBJECT + +public: + explicit Application(int& argc, char** argv); + + int run(); + + // DBus + void openFiles(const QStringList &paths); + void moveToTrash(const QStringList &paths); + void emptyTrash(); + +private: + void openWindow(const QString &path); + QStringList formatUriList(const QStringList &list); + +private: + bool parseCommandLineArgs(); + +private: + bool m_instance; +}; + +#endif // APPLICATION_H diff --git a/cio/cfilejob.cpp b/cio/cfilejob.cpp new file mode 100644 index 0000000..0ab6694 --- /dev/null +++ b/cio/cfilejob.cpp @@ -0,0 +1,7 @@ +#include "cfilejob.h" + +CFileJob::CFileJob(QObject *parent) + : QThread(parent) +{ + +} diff --git a/cio/cfilejob.h b/cio/cfilejob.h new file mode 100644 index 0000000..1481a98 --- /dev/null +++ b/cio/cfilejob.h @@ -0,0 +1,17 @@ +#ifndef CFILEJOB_H +#define CFILEJOB_H + +#include + +class CFileJob : public QThread +{ + Q_OBJECT + +public: + explicit CFileJob(QObject *parent = nullptr); + +signals: + +}; + +#endif // CFILEJOB_H diff --git a/cio/cfilesizejob.cpp b/cio/cfilesizejob.cpp new file mode 100644 index 0000000..be2c5bd --- /dev/null +++ b/cio/cfilesizejob.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#include "cfilesizejob.h" +#include +#include +#include +#include +#include +#include + +CFileSizeJob::CFileSizeJob(QObject *parent) + : QThread(parent) +{ + +} + +CFileSizeJob::~CFileSizeJob() +{ +} + +qint64 CFileSizeJob::totalSize() const +{ + return m_totalSize; +} + +void CFileSizeJob::start(const QList &urls) +{ + if (urls.isEmpty()) + return; + + m_urls = urls; + m_running = true; + + QThread::start(); +} + +void CFileSizeJob::stop() +{ + m_running = false; + + QThread::wait(); +} + +void CFileSizeJob::run() +{ + m_totalSize = 0; + m_filesCount = 0; + m_directoryCount = 0; + + for (QUrl &url : m_urls) { + if (!m_running) + return; + + QFileInfo i(url.toLocalFile()); + + if (i.filePath() == "/proc/kcore" || i.filePath() == "/dev/core") + continue; + + if (i.isSymLink() && i.symLinkTarget() == "/proc/kcore") + continue; + + if (i.isFile()) { + m_totalSize += i.size(); + m_filesCount++; + emit sizeChanged(); + } else if (i.isDir()) { + m_directoryCount++; + + QDirIterator it(url.toLocalFile(), QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + + while (it.hasNext()) { + if (!m_running) + return; + + QFileInfo info(it.next()); + + if (info.filePath() == "/proc/kcore" || info.filePath() == "/dev/core") + continue; + + if (info.isSymLink()) + continue; + + if (info.isFile()) + m_filesCount++; + else if (info.isDir()) + m_directoryCount++; + + m_totalSize += info.size(); + + emit sizeChanged(); + } + } + } + + emit result(); +} diff --git a/cio/cfilesizejob.h b/cio/cfilesizejob.h new file mode 100644 index 0000000..73d1295 --- /dev/null +++ b/cio/cfilesizejob.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#ifndef CFILESIZEJOB_H +#define CFILESIZEJOB_H + +#include +#include +#include + +class CFileSizeJob : public QThread +{ + Q_OBJECT + +public: + explicit CFileSizeJob(QObject *parent = nullptr); + ~CFileSizeJob(); + + qint64 totalSize() const; + + void start(const QList &urls); + void stop(); + +signals: + void sizeChanged(); + void result(); + +protected: + void run() override; + +private: + bool m_running; + QList m_urls; + qint64 m_totalSize; + int m_filesCount; + int m_directoryCount; +}; + +#endif // CFILESIZEJOB_H diff --git a/com.cutefish.FileManager.xml b/com.cutefish.FileManager.xml new file mode 100644 index 0000000..fef4ce0 --- /dev/null +++ b/com.cutefish.FileManager.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/dbusinterface.cpp b/dbusinterface.cpp new file mode 100644 index 0000000..6153f34 --- /dev/null +++ b/dbusinterface.cpp @@ -0,0 +1,39 @@ +#include "dbusinterface.h" + +#include +#include +#include +#include + +DBusInterface::DBusInterface() +{ + QDBusConnection::sessionBus().registerObject("/org/freedesktop/FileManager1", this, + QDBusConnection::ExportScriptableContents | QDBusConnection::ExportAdaptors); + QDBusConnectionInterface *sessionInterface = QDBusConnection::sessionBus().interface(); + + if (sessionInterface) { + sessionInterface->registerService(QStringLiteral("org.freedesktop.FileManager1"), QDBusConnectionInterface::QueueService); + } +} + +void DBusInterface::ShowFolders(const QStringList &uriList, const QString &startUpId) +{ + Q_UNUSED(startUpId); + + QProcess::startDetached("cutefish-filemanager", uriList); +} + +void DBusInterface::ShowItems(const QStringList &uriList, const QString &startUpId) +{ + Q_UNUSED(startUpId); + + QProcess::startDetached("cutefish-filemanager", uriList); +} + +void DBusInterface::ShowItemProperties(const QStringList &uriList, const QString &startUpId) +{ + Q_UNUSED(uriList); + Q_UNUSED(startUpId); + + // TODO +} diff --git a/dbusinterface.h b/dbusinterface.h new file mode 100644 index 0000000..d9951ad --- /dev/null +++ b/dbusinterface.h @@ -0,0 +1,19 @@ +#ifndef DBUSINTERFACE_H +#define DBUSINTERFACE_H + +#include + +class DBusInterface : QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.freedesktop.FileManager1") + +public: + explicit DBusInterface(); + + Q_SCRIPTABLE void ShowFolders(const QStringList& uriList, const QString& startUpId); + Q_SCRIPTABLE void ShowItems(const QStringList& uriList, const QString& startUpId); + Q_SCRIPTABLE void ShowItemProperties(const QStringList& uriList, const QString& startUpId); +}; + +#endif // DBUSINTERFACE_H diff --git a/debian/changelog b/debian/changelog index 0f58ee7..f091f72 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,5 @@ -cutefish-filemanager (0.1) UNRELEASED; urgency=low +cutefish-filemanager (0.8) UNRELEASED; urgency=high - * Initial release (CutefishOS) + * Initial release (CutefishOS) - -- CutefishOS Thu, 16 Oct 2014 17:22:15 +0200 + -- CutefishOS Packaging Team Sat, 29 Jan 2022 03:21:19 +0800 \ No newline at end of file diff --git a/debian/control b/debian/control index ac2c8d4..7c8e87f 100644 --- a/debian/control +++ b/debian/control @@ -1,12 +1,14 @@ Source: cutefish-filemanager Section: devel Priority: optional -Maintainer: CutefishOS +Maintainer: CutefishOS Build-Depends: cmake, debhelper (>= 9), extra-cmake-modules, libkf5kio-dev, libkf5solid-dev, + libkf5windowsystem-dev, + libkf5config-dev, qtbase5-dev, qtbase5-private-dev, qtdeclarative5-dev, @@ -14,7 +16,7 @@ Build-Depends: cmake, qttools5-dev, qttools5-dev-tools Standards-Version: 4.5.0 -Homepage: https://github.com/cutefishos/terminal +Homepage: https://cutefishos.com Package: cutefish-filemanager Architecture: any diff --git a/debian/copyright b/debian/copyright index 716fe64..662fea8 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,3 +1,3 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: calamares -Source: +Upstream-Name: cutefish-filemanager +Source: cutefishos.com diff --git a/debian/rules b/debian/rules index ab2f7c3..4fe3ea4 100755 --- a/debian/rules +++ b/debian/rules @@ -3,7 +3,7 @@ export QT_SELECT=5 %: - dh $@ + dh $@ --parallel override_dh_auto_configure: dh_auto_configure -- -DEMBED_TRANSLATIONS=ON -DBUILD_TESTING=ON diff --git a/desktop/desktop.cpp b/desktop/desktop.cpp new file mode 100644 index 0000000..403d00b --- /dev/null +++ b/desktop/desktop.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#include "desktop.h" +#include +#include + +#include +#include + +Desktop::Desktop(QObject *parent) + : QObject(parent) +{ + for (QScreen *screen : QGuiApplication::screens()) { + screenAdded(screen); + } + + connect(qApp, &QGuiApplication::screenAdded, this, &Desktop::screenAdded); + connect(qApp, &QGuiApplication::screenRemoved, this, &Desktop::screenRemoved); +} + +void Desktop::screenAdded(QScreen *screen) +{ + if (!m_list.contains(screen)) { + DesktopView *view = new DesktopView(screen); + view->show(); + m_list.insert(screen, view); + } +} + +void Desktop::screenRemoved(QScreen *screen) +{ + if (m_list.contains(screen)) { + DesktopView *view = m_list.find(screen).value(); + view->setVisible(false); + view->deleteLater(); + m_list.remove(screen); + } +} diff --git a/desktop/desktop.h b/desktop/desktop.h new file mode 100644 index 0000000..87e4f19 --- /dev/null +++ b/desktop/desktop.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#ifndef DESKTOP_H +#define DESKTOP_H + +#include +#include +#include + +#include "desktopview.h" + +class Desktop : public QObject +{ + Q_OBJECT + +public: + explicit Desktop(QObject *parent = nullptr); + +private slots: + void screenAdded(QScreen *qscreen); + void screenRemoved(QScreen *qscreen); + +private: + QMap m_list; +}; + +#endif // DESKTOP_H diff --git a/desktop/desktopsettings.cpp b/desktop/desktopsettings.cpp index 3298c39..3b560ff 100644 --- a/desktop/desktopsettings.cpp +++ b/desktop/desktopsettings.cpp @@ -24,13 +24,13 @@ DesktopSettings::DesktopSettings(QObject *parent) : QObject(parent) - , m_interface("org.cutefish.Settings", - "/Theme", "org.cutefish.Theme", + , m_interface("com.cutefish.Settings", + "/Theme", "com.cutefish.Theme", QDBusConnection::sessionBus(), this) { QDBusServiceWatcher *watcher = new QDBusServiceWatcher(this); watcher->setConnection(QDBusConnection::sessionBus()); - watcher->addWatchedService("org.cutefish.Settings"); + watcher->addWatchedService("com.cutefish.Settings"); connect(watcher, &QDBusServiceWatcher::serviceRegistered, this, &DesktopSettings::init); init(); diff --git a/desktop/desktopview.cpp b/desktop/desktopview.cpp index 58f6d14..83a1456 100644 --- a/desktop/desktopview.cpp +++ b/desktop/desktopview.cpp @@ -18,40 +18,43 @@ */ #include "desktopview.h" -#include "helper/thumbnailer.h" +#include "dockdbusinterface.h" +#include "thumbnailer/thumbnailprovider.h" #include #include #include -#include +#include #include #include -DesktopView::DesktopView(QQuickView *parent) +DesktopView::DesktopView(QScreen *screen, QQuickView *parent) : QQuickView(parent) + , m_screen(screen) { - m_screenRect = qApp->primaryScreen()->geometry(); - m_screenAvailableRect = qApp->primaryScreen()->availableVirtualGeometry(); + m_screenRect = m_screen->geometry(); KWindowSystem::setType(winId(), NET::Desktop); KWindowSystem::setState(winId(), NET::KeepBelow); engine()->rootContext()->setContextProperty("desktopView", this); - engine()->addImageProvider("thumbnailer", new Thumbnailer()); + engine()->rootContext()->setContextProperty("Dock", DockDBusInterface::self()); + engine()->addImageProvider("thumbnailer", new ThumbnailProvider()); setTitle(tr("Desktop")); - setScreen(qApp->primaryScreen()); + setScreen(m_screen); setResizeMode(QQuickView::SizeRootObjectToView); - setSource(QStringLiteral("qrc:/qml/Desktop/Main.qml")); onGeometryChanged(); + onPrimaryScreenChanged(QGuiApplication::primaryScreen()); - connect(qApp->primaryScreen(), &QScreen::virtualGeometryChanged, this, &DesktopView::onGeometryChanged); - connect(qApp->primaryScreen(), &QScreen::geometryChanged, this, &DesktopView::onGeometryChanged); - connect(qApp->primaryScreen(), &QScreen::availableGeometryChanged, this, &DesktopView::onAvailableGeometryChanged); - connect(qApp->primaryScreen(), &QScreen::virtualGeometryChanged, this, &DesktopView::onAvailableGeometryChanged); + // 主屏改变 + connect(qGuiApp, &QGuiApplication::primaryScreenChanged, this, &DesktopView::onPrimaryScreenChanged); + + connect(m_screen, &QScreen::virtualGeometryChanged, this, &DesktopView::onGeometryChanged); + connect(m_screen, &QScreen::geometryChanged, this, &DesktopView::onGeometryChanged); } QRect DesktopView::screenRect() @@ -59,22 +62,19 @@ QRect DesktopView::screenRect() return m_screenRect; } -QRect DesktopView::screenAvailableRect() +void DesktopView::onPrimaryScreenChanged(QScreen *screen) { - return m_screenAvailableRect; + bool isPrimaryScreen = m_screen->name() == screen->name(); + + onGeometryChanged(); + + setSource(isPrimaryScreen ? QStringLiteral("qrc:/qml/Desktop/Main.qml") + : QStringLiteral("qrc:/qml/Desktop/Wallpaper.qml")); } void DesktopView::onGeometryChanged() { - m_screenRect = qApp->primaryScreen()->geometry(); + m_screenRect = m_screen->geometry().adjusted(0, 0, 1, 1); setGeometry(m_screenRect); emit screenRectChanged(); } - -void DesktopView::onAvailableGeometryChanged(const QRect &geometry) -{ - Q_UNUSED(geometry); - - m_screenAvailableRect = qApp->primaryScreen()->availableVirtualGeometry(); - emit screenAvailableGeometryChanged(); -} diff --git a/desktop/desktopview.h b/desktop/desktopview.h index ee6ba55..6bbc98d 100644 --- a/desktop/desktopview.h +++ b/desktop/desktopview.h @@ -21,30 +21,29 @@ #define DESKTOPVIEW_H #include +#include +class Desktop; class DesktopView : public QQuickView { Q_OBJECT Q_PROPERTY(QRect screenRect READ screenRect NOTIFY screenRectChanged) - Q_PROPERTY(QRect screenAvailableRect READ screenAvailableRect NOTIFY screenAvailableGeometryChanged) public: - explicit DesktopView(QQuickView *parent = nullptr); + explicit DesktopView(QScreen *screen = nullptr, QQuickView *parent = nullptr); QRect screenRect(); - QRect screenAvailableRect(); signals: void screenRectChanged(); - void screenAvailableGeometryChanged(); private slots: + void onPrimaryScreenChanged(QScreen *screen); void onGeometryChanged(); - void onAvailableGeometryChanged(const QRect &geometry); private: + QScreen *m_screen; QRect m_screenRect; - QRect m_screenAvailableRect; }; #endif // DESKTOPVIEW_H diff --git a/desktop/dockdbusinterface.cpp b/desktop/dockdbusinterface.cpp new file mode 100644 index 0000000..10a0a13 --- /dev/null +++ b/desktop/dockdbusinterface.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#include "dockdbusinterface.h" +#include +#include + +static DockDBusInterface *DOCKDBUS_SELF = nullptr; + +DockDBusInterface *DockDBusInterface::self() +{ + if (!DOCKDBUS_SELF) + DOCKDBUS_SELF = new DockDBusInterface; + + return DOCKDBUS_SELF; +} + +DockDBusInterface::DockDBusInterface(QObject *parent) + : QObject(parent) + , m_dockInterface("com.cutefish.Dock", + "/Dock", + "com.cutefish.Dock", QDBusConnection::sessionBus()) + , m_leftMargin(0) + , m_rightMargin(0) + , m_bottomMargin(0) +{ + if (m_dockInterface.isValid()) { + updateMargins(); + connect(&m_dockInterface, SIGNAL(primaryGeometryChanged()), this, SLOT(updateMargins())); + connect(&m_dockInterface, SIGNAL(directionChanged()), this, SLOT(updateMargins())); + connect(&m_dockInterface, SIGNAL(visibilityChanged()), this, SLOT(updateMargins())); + } else { + QDBusServiceWatcher *watcher = new QDBusServiceWatcher("com.cutefish.Dock", + QDBusConnection::sessionBus(), + QDBusServiceWatcher::WatchForUnregistration, + this); + connect(watcher, &QDBusServiceWatcher::serviceUnregistered, this, [=] { + updateMargins(); + connect(&m_dockInterface, SIGNAL(primaryGeometryChanged()), this, SLOT(updateMargins())); + connect(&m_dockInterface, SIGNAL(directionChanged()), this, SLOT(updateMargins())); + connect(&m_dockInterface, SIGNAL(visibilityChanged()), this, SLOT(updateMargins())); + }); + } +} + +int DockDBusInterface::leftMargin() const +{ + return m_leftMargin; +} + +int DockDBusInterface::rightMargin() const +{ + return m_rightMargin; +} + +int DockDBusInterface::bottomMargin() const +{ + return m_bottomMargin; +} + +void DockDBusInterface::updateMargins() +{ + QRect dockGeometry = m_dockInterface.property("primaryGeometry").toRect(); + int dockDirection = m_dockInterface.property("direction").toInt(); + int visibility = m_dockInterface.property("visibility").toInt(); + + m_leftMargin = 0; + m_rightMargin = 0; + m_bottomMargin = 0; + + // AlwaysHide + if (visibility == 1) { + emit marginsChanged(); + return; + } + + if (dockDirection == 0) { + m_leftMargin = dockGeometry.width(); + } else if (dockDirection == 1) { + m_bottomMargin = dockGeometry.height(); + } else if (dockDirection == 2) { + m_rightMargin = dockGeometry.width(); + } + + emit marginsChanged(); +} diff --git a/desktop/dockdbusinterface.h b/desktop/dockdbusinterface.h new file mode 100644 index 0000000..515998c --- /dev/null +++ b/desktop/dockdbusinterface.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#ifndef DOCKDBUSINTERFACE_H +#define DOCKDBUSINTERFACE_H + +#include +#include + +class DockDBusInterface : public QObject +{ + Q_OBJECT + Q_PROPERTY(int leftMargin READ leftMargin NOTIFY marginsChanged) + Q_PROPERTY(int rightMargin READ rightMargin NOTIFY marginsChanged) + Q_PROPERTY(int bottomMargin READ bottomMargin NOTIFY marginsChanged) + +public: + static DockDBusInterface *self(); + explicit DockDBusInterface(QObject *parent = nullptr); + + int leftMargin() const; + int rightMargin() const; + int bottomMargin() const; + +signals: + void marginsChanged(); + +private slots: + void updateMargins(); + +private: + QDBusInterface m_dockInterface; + + int m_leftMargin; + int m_rightMargin; + int m_bottomMargin; +}; + +#endif // DOCKDBUSINTERFACE_H diff --git a/dialogs/filepropertiesdialog.cpp b/dialogs/filepropertiesdialog.cpp new file mode 100644 index 0000000..cdf3db4 --- /dev/null +++ b/dialogs/filepropertiesdialog.cpp @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#include "filepropertiesdialog.h" +#include "../desktopiconprovider.h" +#include "../helper/fm.h" + +#include +#include +#include +#include + +#include + +inline QString concatPaths(const QString &path1, const QString &path2) +{ + Q_ASSERT(!path2.startsWith(QLatin1Char('/'))); + + if (path1.isEmpty()) { + return path2; + } else if (!path1.endsWith(QLatin1Char('/'))) { + return path1 + QLatin1Char('/') + path2; + } else { + return path1 + path2; + } +} + +FilePropertiesDialog::FilePropertiesDialog(const KFileItem &item, QQuickView *parent) + : QQuickView(parent) +{ + m_items.append(item); + init(); +} + +FilePropertiesDialog::FilePropertiesDialog(const KFileItemList &items, QQuickView *parent) + : QQuickView(parent) + , m_items(items) +{ + init(); +} + +FilePropertiesDialog::FilePropertiesDialog(const QUrl &url, QQuickView *parent) + : QQuickView(parent) +{ + m_items.append(KFileItem(url)); + + init(); +} + +FilePropertiesDialog::~FilePropertiesDialog() +{ + if (m_sizeJob) { + m_sizeJob->stop(); + m_sizeJob->deleteLater(); + m_sizeJob = nullptr; + } +} + +void FilePropertiesDialog::updateSize(int width, int height) +{ + resize(QSize(width, height)); + setMinimumSize(QSize(width, height)); + setMaximumSize(QSize(width, height)); +} + +void FilePropertiesDialog::accept(const QString &text) +{ + KFileItemList list = m_items; + + if (list.size() == 1) { + KFileItem item = list.first(); + + QString n = text; + while (!n.isEmpty() && n[n.length() - 1].isSpace()) + n.chop(1); + + if (n.isEmpty()) + return; + + QString newFileName = KIO::encodeFileName(n); + + if (fileName() != newFileName) { + QUrl newUrl; + + if (!location().isEmpty() && !Fm::isFixedFolder(m_items.first().url())) { + newUrl = location(); + newUrl.setPath(concatPaths(newUrl.path(), newFileName)); + newUrl.setScheme(item.url().scheme()); + + auto job = KIO::move(item.url(), newUrl, KIO::HideProgressInfo); + job->start(); + } + } + } + + this->destroy(); + this->deleteLater(); +} + +void FilePropertiesDialog::reject() +{ + if (m_sizeJob) { + m_sizeJob->stop(); + m_sizeJob->deleteLater(); + m_sizeJob = nullptr; + } + + this->destroy(); + this->deleteLater(); +} + +bool FilePropertiesDialog::multiple() const +{ + return m_multiple; +} + +bool FilePropertiesDialog::isWritable() const +{ + return m_isWritable; +} + +QString FilePropertiesDialog::location() const +{ + return m_location; +} + +QString FilePropertiesDialog::fileName() const +{ + return m_fileName; +} + +QString FilePropertiesDialog::iconName() const +{ + return m_iconName; +} + +QString FilePropertiesDialog::mimeType() const +{ + return m_mimeType; +} + +QString FilePropertiesDialog::fileSize() const +{ + return m_size; +} + +QString FilePropertiesDialog::creationTime() const +{ + return m_creationTime; +} + +QString FilePropertiesDialog::modifiedTime() const +{ + return m_modifiedTime; +} + +QString FilePropertiesDialog::accessedTime() const +{ + return m_accessedTime; +} + +bool FilePropertiesDialog::event(QEvent *e) +{ + if (e->type() == QEvent::Close) { + this->deleteLater(); + } + + return QQuickView::event(e); +} + +void FilePropertiesDialog::init() +{ + engine()->rootContext()->setContextProperty("main", this); + // engine()->addImageProvider(QStringLiteral("icontheme"), new DesktopIconProvider()); + + setFlag(Qt::Dialog); + setTitle(tr("Properties")); + setResizeMode(QQuickView::SizeViewToRootObject); + setSource(QUrl("qrc:/qml/Dialogs/PropertiesDialog.qml")); + + m_multiple = m_items.count() > 1; + + QList list; + for (KFileItem item : m_items) { + list.append(item.url()); + } + + m_sizeJob = std::shared_ptr(new CFileSizeJob); + m_sizeJob->start(list); + + connect(m_sizeJob.get(), &CFileSizeJob::sizeChanged, this, &FilePropertiesDialog::updateTotalSize); + connect(m_sizeJob.get(), &CFileSizeJob::result, this, &FilePropertiesDialog::updateTotalSize); + + if (!m_multiple) { + KFileItem item = m_items.first(); + QFileInfo info(item.url().toLocalFile()); + + QString path; + m_fileName = m_items.first().name(); + + if (item.isDir()) + m_iconName = "folder"; + else + m_iconName = m_items.first().iconName(); + + m_mimeType = m_items.first().mimetype(); + m_size = KIO::convertSize(m_items.first().size()); + m_location = info.dir().path(); + + m_creationTime = info.birthTime().toString(Qt::SystemLocaleLongDate); + m_modifiedTime = info.lastModified().toString(Qt::SystemLocaleLongDate); + m_accessedTime = info.lastRead().toString(Qt::SystemLocaleLongDate); + +// m_creationTime = item.time(KFileItem::CreationTime).toString(); +// m_modifiedTime = item.time(KFileItem::ModificationTime).toString(); +// m_accessedTime = item.time(KFileItem::AccessTime).toString(); + + m_isWritable = m_items.first().isWritable(); + + emit fileNameChanged(); + emit iconNameChanged(); + emit mimeTypeChanged(); + emit fileSizeChanged(); + emit locationChanged(); + emit creationTimeChanged(); + emit modifiedTimeChanged(); + emit accessedTimeChanged(); + } else { + m_isWritable = false; + m_fileName = tr("%1 files").arg(m_items.count()); + m_location = QFileInfo(m_items.first().localPath()).dir().path(); + m_iconName = "unknown"; + + emit fileNameChanged(); + emit locationChanged(); + emit iconNameChanged(); + } + + emit isWritableChanged(); +} + +void FilePropertiesDialog::updateTotalSize() +{ + if (!m_sizeJob) + return; + + m_size = KIO::convertSize(m_sizeJob->totalSize()); + emit fileSizeChanged(); +} diff --git a/dialogs/propertiesdialog.h b/dialogs/filepropertiesdialog.h similarity index 52% rename from dialogs/propertiesdialog.h rename to dialogs/filepropertiesdialog.h index 9cdc65c..a87bf5f 100644 --- a/dialogs/propertiesdialog.h +++ b/dialogs/filepropertiesdialog.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2021 CutefishOS Team. * - * Author: revenmartin + * Author: Reion Wong * * 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 @@ -17,37 +17,43 @@ * along with this program. If not, see . */ -#ifndef PROPERTIESDIALOG_H -#define PROPERTIESDIALOG_H +#ifndef FILEPROPERTIESDIALOG_H +#define FILEPROPERTIESDIALOG_H -#include +#include +#include #include +#include #include #include -class PropertiesDialog : public QObject +#include "cio/cfilesizejob.h" + +class FilePropertiesDialog : public QQuickView { Q_OBJECT - Q_PROPERTY(QString location READ location CONSTANT) + Q_PROPERTY(QString location READ location NOTIFY locationChanged) Q_PROPERTY(QString fileName READ fileName NOTIFY fileNameChanged) Q_PROPERTY(QString iconName READ iconName NOTIFY iconNameChanged) - Q_PROPERTY(QString mimeType READ mimeType CONSTANT) - Q_PROPERTY(QString size READ size NOTIFY sizeChanged) - Q_PROPERTY(QString creationTime READ creationTime CONSTANT) - Q_PROPERTY(QString modifiedTime READ modifiedTime CONSTANT) - Q_PROPERTY(QString accessedTime READ accessedTime CONSTANT) + Q_PROPERTY(QString mimeType READ mimeType NOTIFY mimeTypeChanged) + Q_PROPERTY(QString fileSize READ fileSize NOTIFY fileSizeChanged) + Q_PROPERTY(QString creationTime READ creationTime NOTIFY creationTimeChanged) + Q_PROPERTY(QString modifiedTime READ modifiedTime NOTIFY modifiedTimeChanged) + Q_PROPERTY(QString accessedTime READ accessedTime NOTIFY accessedTimeChanged) Q_PROPERTY(bool multiple READ multiple CONSTANT) - Q_PROPERTY(bool isWritable READ isWritable CONSTANT) + Q_PROPERTY(bool isWritable READ isWritable NOTIFY isWritableChanged) public: - explicit PropertiesDialog(const KFileItem &item, QObject *parent = nullptr); - explicit PropertiesDialog(const KFileItemList &items, QObject *parent = nullptr); - explicit PropertiesDialog(const QUrl &url, QObject *parent = nullptr); - ~PropertiesDialog(); + explicit FilePropertiesDialog(const KFileItem &item, QQuickView *parent = nullptr); + explicit FilePropertiesDialog(const KFileItemList &items, QQuickView *parent = nullptr); + explicit FilePropertiesDialog(const QUrl &url, QQuickView *parent = nullptr); + ~FilePropertiesDialog(); - static void showDialog(const KFileItem &item); - static void showDialog(const KFileItemList &items); + Q_INVOKABLE void updateSize(int width, int height); + + Q_INVOKABLE void accept(const QString &text); + Q_INVOKABLE void reject(); bool multiple() const; bool isWritable() const; @@ -56,27 +62,32 @@ class PropertiesDialog : public QObject QString fileName() const; QString iconName() const; QString mimeType() const; - QString size() const; + QString fileSize() const; QString creationTime() const; QString modifiedTime() const; QString accessedTime() const; - KFileItemList items() const; - - Q_INVOKABLE void accept(const QString &text); - Q_INVOKABLE void reject(); - signals: + void locationChanged(); void fileNameChanged(); void iconNameChanged(); - void sizeChanged(); + void mimeTypeChanged(); + void fileSizeChanged(); + + void creationTimeChanged(); + void modifiedTimeChanged(); + void accessedTimeChanged(); + void isWritableChanged(); + +protected: + bool event(QEvent *e) override; private: void init(); private slots: - void slotDirSizeFinished(KJob *job); + void updateTotalSize(); private: KFileItemList m_items; @@ -89,9 +100,10 @@ private slots: QString m_modifiedTime; QString m_accessedTime; - KIO::DirectorySizeJob *m_dirSizeJob; + std::shared_ptr m_sizeJob; bool m_multiple; + bool m_isWritable; }; -#endif // PROPERTIESDIALOG_H +#endif // FILEPROPERTIESDIALOG_H diff --git a/dialogs/openwithdialog.cpp b/dialogs/openwithdialog.cpp new file mode 100644 index 0000000..1231de3 --- /dev/null +++ b/dialogs/openwithdialog.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#include "openwithdialog.h" +#include "../mimetype/mimeappmanager.h" +#include "../helper/filelauncher.h" + +#include +#include + +OpenWithDialog::OpenWithDialog(const QUrl &url, QQuickView *parent) + : QQuickView(parent) + , m_url(url.toLocalFile()) +{ + setFlag(Qt::Dialog); + setTitle(tr("Open With")); + setResizeMode(QQuickView::SizeViewToRootObject); + + engine()->rootContext()->setContextProperty("main", this); + engine()->rootContext()->setContextProperty("mimeAppManager", MimeAppManager::self()); + engine()->rootContext()->setContextProperty("launcher", FileLauncher::self()); + + setSource(QUrl("qrc:/qml/Dialogs/OpenWithDialog.qml")); + + QRect rect = geometry(); + setMinimumSize(rect.size()); + setMaximumSize(rect.size()); + + connect(this, &QQuickView::visibleChanged, this, [=] { + if (!this->isVisible()) + this->deleteLater(); + }); +} + +QString OpenWithDialog::url() const +{ + return m_url; +} diff --git a/dialogs/openwithdialog.h b/dialogs/openwithdialog.h new file mode 100644 index 0000000..7c1d464 --- /dev/null +++ b/dialogs/openwithdialog.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#ifndef OPENWITHDIALOG_H +#define OPENWITHDIALOG_H + +#include + +class OpenWithDialog : public QQuickView +{ + Q_OBJECT + Q_PROPERTY(QString url READ url CONSTANT) + +public: + explicit OpenWithDialog(const QUrl &url, QQuickView *parent = nullptr); + + QString url() const; + +private: + QString m_url; +}; + +#endif // OPENWITHDIALOG_H diff --git a/dialogs/propertiesdialog.cpp b/dialogs/propertiesdialog.cpp deleted file mode 100644 index 1a8b656..0000000 --- a/dialogs/propertiesdialog.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2021 CutefishOS Team. - * - * Author: revenmartin - * - * 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 3 of the License, or - * 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, see . - */ - -#include "propertiesdialog.h" -#include "../desktopiconprovider.h" - -#include -#include - -#include -#include - -#include -#include -#include -#include - -inline QString concatPaths(const QString &path1, const QString &path2) -{ - Q_ASSERT(!path2.startsWith(QLatin1Char('/'))); - - if (path1.isEmpty()) { - return path2; - } else if (!path1.endsWith(QLatin1Char('/'))) { - return path1 + QLatin1Char('/') + path2; - } else { - return path1 + path2; - } -} - -PropertiesDialog::PropertiesDialog(const KFileItem &item, QObject *parent) - : QObject(parent) -{ - m_items.append(item); - init(); -} - -PropertiesDialog::PropertiesDialog(const KFileItemList &items, QObject *parent) - : QObject(parent) -{ - m_items = items; - init(); -} - -PropertiesDialog::PropertiesDialog(const QUrl &url, QObject *parent) - : QObject(parent) -{ - m_items.append(KFileItem(url)); - init(); -} - -PropertiesDialog::~PropertiesDialog() -{ - if (m_dirSizeJob) - m_dirSizeJob->kill(); -} - -void PropertiesDialog::showDialog(const KFileItem &item) -{ - PropertiesDialog *dlg = new PropertiesDialog(item); - QQmlApplicationEngine *engine = new QQmlApplicationEngine; - engine->addImageProvider(QStringLiteral("icontheme"), new DesktopIconProvider()); - engine->rootContext()->setContextProperty("main", dlg); - engine->load(QUrl("qrc:/qml/Dialogs/PropertiesDialog.qml")); -} - -void PropertiesDialog::showDialog(const KFileItemList &items) -{ - PropertiesDialog *dlg = new PropertiesDialog(items); - QQmlApplicationEngine *engine = new QQmlApplicationEngine; - engine->addImageProvider(QStringLiteral("icontheme"), new DesktopIconProvider()); - engine->rootContext()->setContextProperty("main", dlg); - engine->load(QUrl("qrc:/qml/Dialogs/PropertiesDialog.qml")); -} - -bool PropertiesDialog::multiple() const -{ - return m_multiple; -} - -bool PropertiesDialog::isWritable() const -{ - return m_items.first().isWritable(); -} - -QString PropertiesDialog::location() const -{ - return m_location; -} - -QString PropertiesDialog::fileName() const -{ - return m_fileName; -} - -QString PropertiesDialog::iconName() const -{ - return m_iconName; -} - -QString PropertiesDialog::mimeType() const -{ - return m_mimeType; -} - -QString PropertiesDialog::size() const -{ - return m_size; -} - -QString PropertiesDialog::creationTime() const -{ - return m_creationTime; -} - -QString PropertiesDialog::modifiedTime() const -{ - return m_modifiedTime; -} - -QString PropertiesDialog::accessedTime() const -{ - return m_accessedTime; -} - -KFileItemList PropertiesDialog::items() const -{ - return m_items; -} - -void PropertiesDialog::accept(const QString &text) -{ - KFileItemList list = items(); - - if (list.size() == 1) { - KFileItem item = list.first(); - - QString n = text; - while (!n.isEmpty() && n[n.length() - 1].isSpace()) - n.chop(1); - - if (n.isEmpty()) - return; - - QString newFileName = KIO::encodeFileName(n); - - if (fileName() != newFileName) { - QUrl newUrl; - - if (!location().isEmpty()) { - newUrl = location(); - newUrl.setPath(concatPaths(newUrl.path(), newFileName)); - newUrl.setScheme(item.url().scheme()); - - auto job = KIO::move(item.url(), newUrl, KIO::HideProgressInfo); - job->start(); - } - } - } -} - -void PropertiesDialog::reject() -{ -} - -void PropertiesDialog::init() -{ - m_multiple = m_items.count() > 1; - - m_dirSizeJob = KIO::directorySize(m_items); - - connect(m_dirSizeJob, &KIO::DirectorySizeJob::result, this, &PropertiesDialog::slotDirSizeFinished); - - if (!m_multiple) { - KFileItem item = m_items.first(); - - QString path; - m_fileName = m_items.first().name(); - - if (item.isDir()) - m_iconName = "folder"; - else - m_iconName = m_items.first().iconName(); - - m_mimeType = m_items.first().mimetype(); - m_size = KIO::convertSize(m_items.first().size()); - m_location = QFileInfo(m_items.first().localPath()).dir().path(); - - m_creationTime = item.time(KFileItem::CreationTime).toString(); - m_modifiedTime = item.time(KFileItem::ModificationTime).toString(); - m_accessedTime = item.time(KFileItem::AccessTime).toString(); - } else { - m_fileName = tr("%1 files").arg(m_items.count()); - m_location = QFileInfo(m_items.first().localPath()).dir().path(); - } -} - -void PropertiesDialog::slotDirSizeFinished(KJob *job) -{ - if (job->error()) - return; - - m_size = KIO::convertSize(m_dirSizeJob->totalSize()); - - m_dirSizeJob = 0; - - emit sizeChanged(); -} diff --git a/draganddrop/declarativedragdropevent.cpp b/draganddrop/declarativedragdropevent.cpp new file mode 100644 index 0000000..ef0d398 --- /dev/null +++ b/draganddrop/declarativedragdropevent.cpp @@ -0,0 +1,55 @@ +/* + SPDX-FileCopyrightText: 2010 BetterInbox + SPDX-FileContributor: Gregory Schlomoff + SPDX-FileCopyrightText: 2013 Sebastian Kügler + + SPDX-License-Identifier: MIT +*/ + +#include "declarativedragdropevent.h" + +DeclarativeDragDropEvent::DeclarativeDragDropEvent(QDropEvent *e, DeclarativeDropArea *parent) + : QObject(parent) + , m_x(e->pos().x()) + , m_y(e->pos().y()) + , m_buttons(e->mouseButtons()) + , m_modifiers(e->keyboardModifiers()) + , m_data(nullptr) + , m_event(e) +{ +} + +DeclarativeDragDropEvent::DeclarativeDragDropEvent(QDragLeaveEvent *e, DeclarativeDropArea *parent) + : QObject(parent) + , m_x(0) + , m_y(0) + , m_buttons(Qt::NoButton) + , m_modifiers(Qt::NoModifier) + , m_data(nullptr) + , m_event(nullptr) +{ + Q_UNUSED(e); +} + +void DeclarativeDragDropEvent::accept(int action) +{ + m_event->setDropAction(static_cast(action)); + // qDebug() << "-----> Accepting event: " << this << m_data.urls() << m_data.text() << m_data.html() << ( m_data.hasColor() ? m_data.color().name() : " + // no color"); + m_event->accept(); +} + +void DeclarativeDragDropEvent::ignore() +{ + m_event->ignore(); +} + +DeclarativeMimeData *DeclarativeDragDropEvent::mimeData() +{ + if (!m_data && m_event) { + // TODO This should be using MimeDataWrapper eventually, although this is an API break, + // so will need to be done carefully. + m_data.reset(new DeclarativeMimeData(m_event->mimeData())); + } + return m_data.data(); +} diff --git a/draganddrop/declarativedragdropevent.h b/draganddrop/declarativedragdropevent.h new file mode 100644 index 0000000..c453f3c --- /dev/null +++ b/draganddrop/declarativedragdropevent.h @@ -0,0 +1,121 @@ +/* + SPDX-FileCopyrightText: 2010 BetterInbox + SPDX-FileContributor: Gregory Schlomoff + + SPDX-License-Identifier: MIT +*/ + +#ifndef DECLARATIVEDRAGDROPEVENT_H +#define DECLARATIVEDRAGDROPEVENT_H + +#include "declarativedroparea.h" +#include "declarativemimedata.h" +#include + +class DeclarativeDragDropEvent : public QObject +{ + Q_OBJECT + + /** + * The mouse X position of the event relative to the DropArea that is receiving the event. + */ + Q_PROPERTY(int x READ x) + + /** + * The mouse Y position of the event relative to the DropArea that is receiving the event. + */ + Q_PROPERTY(int y READ y) + + /** + * The pressed mouse buttons. + * A combination of: + * Qt.NoButton The button state does not refer to any button (see QMouseEvent::button()). + * Qt.LeftButton The left button is pressed, or an event refers to the left button. (The left button may be the right button on left-handed mice.) + * Qt.RightButton The right button. + * Qt.MidButton The middle button. + * Qt.MiddleButton MidButton The middle button. + * Qt.XButton1 The first X button. + * Qt.XButton2 The second X button. + */ + Q_PROPERTY(int buttons READ buttons) + + /** + * Pressed keyboard modifiers, a combination of: + * Qt.NoModifier No modifier key is pressed. + * Qt.ShiftModifier A Shift key on the keyboard is pressed. + * Qt.ControlModifier A Ctrl key on the keyboard is pressed. + * Qt.AltModifier An Alt key on the keyboard is pressed. + * Qt.MetaModifier A Meta key on the keyboard is pressed. + * Qt.KeypadModifier A keypad button is pressed. + * Qt.GroupSwitchModifier X11 only. A Mode_switch key on the keyboard is pressed. + */ + Q_PROPERTY(int modifiers READ modifiers) + + /** + * The mime data of this operation + * @see DeclarativeMimeData + */ + Q_PROPERTY(DeclarativeMimeData *mimeData READ mimeData) + + /** + * The possible different kind of action that can be done in the drop, is a combination of: + * Qt.CopyAction 0x1 Copy the data to the target. + * Qt.MoveAction 0x2 Move the data from the source to the target. + * Qt.LinkAction 0x4 Create a link from the source to the target. + * Qt.ActionMask 0xff + * Qt.IgnoreAction 0x0 Ignore the action (do nothing with the data). + * Qt.TargetMoveAction 0x8002 On Windows, this value is used when the ownership of the D&D data should be taken over by the target application, i.e., the + * source application should not delete the data. On X11 this value is used to do a move. TargetMoveAction is not used on the Mac. + */ + Q_PROPERTY(Qt::DropActions possibleActions READ possibleActions) + + /** + * Default action + * @see possibleActions + */ + Q_PROPERTY(Qt::DropAction proposedAction READ proposedAction) + +public: + DeclarativeDragDropEvent(QDropEvent *e, DeclarativeDropArea *parent = nullptr); + DeclarativeDragDropEvent(QDragLeaveEvent *e, DeclarativeDropArea *parent = nullptr); + + int x() const + { + return m_x; + } + int y() const + { + return m_y; + } + int buttons() const + { + return m_buttons; + } + int modifiers() const + { + return m_modifiers; + } + DeclarativeMimeData *mimeData(); + Qt::DropAction proposedAction() const + { + return m_event->proposedAction(); + } + Qt::DropActions possibleActions() const + { + return m_event->possibleActions(); + } + +public Q_SLOTS: + void accept(int action); + void ignore(); + +private: + int m_x; + int m_y; + Qt::MouseButtons m_buttons; + Qt::KeyboardModifiers m_modifiers; + QScopedPointer m_data; + QDropEvent *m_event; +}; + +#endif // DECLARATIVEDRAGDROPEVENT_H diff --git a/draganddrop/declarativedroparea.cpp b/draganddrop/declarativedroparea.cpp new file mode 100644 index 0000000..7bab563 --- /dev/null +++ b/draganddrop/declarativedroparea.cpp @@ -0,0 +1,148 @@ +/* + SPDX-FileCopyrightText: 2010 BetterInbox + SPDX-FileContributor: Gregory Schlomoff + + SPDX-License-Identifier: MIT +*/ + +#include "declarativedroparea.h" +#include "declarativedragdropevent.h" + +DeclarativeDropArea::DeclarativeDropArea(QQuickItem *parent) + : QQuickItem(parent) + , m_enabled(true) + , m_preventStealing(false) + , m_temporaryInhibition(false) + , m_containsDrag(false) +{ + setFlag(ItemAcceptsDrops, m_enabled); +} + +void DeclarativeDropArea::temporaryInhibitParent(bool inhibit) +{ + QQuickItem *candidate = parentItem(); + + while (candidate) { + if (DeclarativeDropArea *da = qobject_cast(candidate)) { + da->m_temporaryInhibition = inhibit; + if (inhibit) { + Q_EMIT da->dragLeaveEvent(nullptr); + } + } + candidate = candidate->parentItem(); + } +} + +void DeclarativeDropArea::dragEnterEvent(QDragEnterEvent *event) +{ + if (!m_enabled || m_temporaryInhibition) { + return; + } + + DeclarativeDragDropEvent dde(event, this); + event->accept(); + + Q_EMIT dragEnter(&dde); + + if (!event->isAccepted()) { + return; + } + + if (m_preventStealing) { + temporaryInhibitParent(true); + } + + m_oldDragMovePos = event->pos(); + setContainsDrag(true); +} + +void DeclarativeDropArea::dragLeaveEvent(QDragLeaveEvent *event) +{ + // do it anyways, in the unlikely case m_preventStealing + // was changed while drag + temporaryInhibitParent(false); + + m_oldDragMovePos = QPoint(-1, -1); + DeclarativeDragDropEvent dde(event, this); + Q_EMIT dragLeave(&dde); + setContainsDrag(false); +} + +void DeclarativeDropArea::dragMoveEvent(QDragMoveEvent *event) +{ + if (!m_enabled || m_temporaryInhibition) { + event->ignore(); + return; + } + event->accept(); + // if the position we export didn't change, don't generate the move event + if (event->pos() == m_oldDragMovePos) { + return; + } + + m_oldDragMovePos = event->pos(); + DeclarativeDragDropEvent dde(event, this); + Q_EMIT dragMove(&dde); +} + +void DeclarativeDropArea::dropEvent(QDropEvent *event) +{ + // do it anyways, in the unlikely case m_preventStealing + // was changed while drag, do it after a loop, + // so the parent dropevent doesn't get delivered + metaObject()->invokeMethod(this, "temporaryInhibitParent", Qt::QueuedConnection, Q_ARG(bool, false)); + + m_oldDragMovePos = QPoint(-1, -1); + + if (!m_enabled || m_temporaryInhibition) { + return; + } + + DeclarativeDragDropEvent dde(event, this); + Q_EMIT drop(&dde); + setContainsDrag(false); +} + +bool DeclarativeDropArea::isEnabled() const +{ + return m_enabled; +} + +void DeclarativeDropArea::setEnabled(bool enabled) +{ + if (enabled == m_enabled) { + return; + } + + m_enabled = enabled; + setFlag(ItemAcceptsDrops, m_enabled); + Q_EMIT enabledChanged(); +} + +bool DeclarativeDropArea::preventStealing() const +{ + return m_preventStealing; +} + +void DeclarativeDropArea::setPreventStealing(bool prevent) +{ + if (prevent == m_preventStealing) { + return; + } + + m_preventStealing = prevent; + Q_EMIT preventStealingChanged(); +} + +void DeclarativeDropArea::setContainsDrag(bool dragging) +{ + if (m_containsDrag != dragging) { + m_containsDrag = dragging; + Q_EMIT containsDragChanged(m_containsDrag); + } +} + +bool DeclarativeDropArea::containsDrag() const +{ + return m_containsDrag; +} diff --git a/draganddrop/declarativedroparea.h b/draganddrop/declarativedroparea.h new file mode 100644 index 0000000..265c893 --- /dev/null +++ b/draganddrop/declarativedroparea.h @@ -0,0 +1,95 @@ +/* + SPDX-FileCopyrightText: 2010 BetterInbox + SPDX-FileContributor: Gregory Schlomoff + + SPDX-License-Identifier: MIT +*/ + +#ifndef DECLARATIVEDROPAREA_H +#define DECLARATIVEDROPAREA_H + +#include + +class DeclarativeDragDropEvent; + +class DeclarativeDropArea : public QQuickItem +{ + Q_OBJECT + + /** + * If false the area will receive no drop events + */ + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) + + /** + * + */ + Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged) + + Q_PROPERTY(bool containsDrag READ containsDrag NOTIFY containsDragChanged) + +public: + DeclarativeDropArea(QQuickItem *parent = nullptr); + bool isEnabled() const; + void setEnabled(bool enabled); + + bool preventStealing() const; + void setPreventStealing(bool prevent); + bool containsDrag() const; + +Q_SIGNALS: + /** + * Emitted when the mouse cursor dragging something enters in the drag area + * @param event description of the dragged content + * @see DeclarativeDragDropEvent + */ + void dragEnter(DeclarativeDragDropEvent *event); + + /** + * Emitted when the mouse cursor dragging something leaves the drag area + * @param event description of the dragged content + * @see DeclarativeDragDropEvent + */ + void dragLeave(DeclarativeDragDropEvent *event); + + /** + * Emitted when the mouse cursor dragging something moves over the drag area + * @param event description of the dragged content + * @see DeclarativeDragDropEvent + */ + void dragMove(DeclarativeDragDropEvent *event); + + /** + * Emitted when the user drops something in the area + * @param event description of the dragged content + * @see DeclarativeDragDropEvent + */ + void drop(DeclarativeDragDropEvent *event); + + // Notifiers + void enabledChanged(); + + void preventStealingChanged(); + + void containsDragChanged(bool contained); + +protected: + void dragEnterEvent(QDragEnterEvent *event) override; + void dragLeaveEvent(QDragLeaveEvent *event) override; + void dragMoveEvent(QDragMoveEvent *event) override; + void dropEvent(QDropEvent *event) override; + +private Q_SLOTS: + void temporaryInhibitParent(bool inhibit); + +private: + void setContainsDrag(bool dragging); + + bool m_enabled : 1; + bool m_preventStealing : 1; + bool m_temporaryInhibition : 1; + bool m_containsDrag : 1; + QPoint m_oldDragMovePos; +}; + +#endif diff --git a/draganddrop/declarativemimedata.cpp b/draganddrop/declarativemimedata.cpp new file mode 100644 index 0000000..138b156 --- /dev/null +++ b/draganddrop/declarativemimedata.cpp @@ -0,0 +1,153 @@ +/* + SPDX-FileCopyrightText: 2010 BetterInbox + SPDX-FileContributor: Gregory Schlomoff + + SPDX-License-Identifier: MIT +*/ + +#include "declarativemimedata.h" + +/*! + \qmlclass MimeData DeclarativeMimeData + + This is a wrapper class around QMimeData, with a few extensions to provide better support for in-qml drag & drops. +*/ + +DeclarativeMimeData::DeclarativeMimeData() + : QMimeData() + , m_source(nullptr) +{ +} + +/*! + \internal + \class DeclarativeMimeData + + Creates a new DeclarativeMimeData by cloning the QMimeData passed as parameter. + This is useful for two reasons : + - In DragArea, we want to clone our "working copy" of the DeclarativeMimeData instance, as Qt will automatically + delete it after the drag and drop operation. + - In the drop events, the QMimeData is const, and we have troubles passing const to QML. So we clone it to + remove the "constness" + + This method will try to cast the QMimeData to DeclarativeMimeData, and will clone our extensions to QMimeData as well +*/ +DeclarativeMimeData::DeclarativeMimeData(const QMimeData *copy) + : QMimeData() + , m_source(nullptr) +{ + // Copy the standard MIME data + const auto formats = copy->formats(); + for (const QString &format : formats) { + QMimeData::setData(format, copy->data(format)); + } + + // If the object we are copying actually is a DeclarativeMimeData, copy our extended properties as well + const DeclarativeMimeData *declarativeMimeData = qobject_cast(copy); + if (declarativeMimeData) { + this->setSource(declarativeMimeData->source()); + } +} + +/*! + \qmlproperty url MimeData::url + + Returns the first URL from the urls property of QMimeData + TODO: We should use QDeclarativeListProperty to return the whole list instead of only the first element. +*/ +QUrl DeclarativeMimeData::url() const +{ + if (this->hasUrls() && !this->urls().isEmpty()) { + return QMimeData::urls().first(); + } + return QUrl(); +} +void DeclarativeMimeData::setUrl(const QUrl &url) +{ + if (this->url() == url) + return; + + QList urlList; + urlList.append(url); + QMimeData::setUrls(urlList); + Q_EMIT urlChanged(); +} + +QJsonArray DeclarativeMimeData::urls() const +{ + QJsonArray varUrls; + const auto lstUrls = QMimeData::urls(); + for (const QUrl &url : lstUrls) { + varUrls.append(url.toString()); + } + return varUrls; +} + +void DeclarativeMimeData::setUrls(const QJsonArray &urls) +{ + QList urlList; + urlList.reserve(urls.size()); + for (const QVariant &varUrl : urls) { + urlList << varUrl.toUrl(); + } + QMimeData::setUrls(urlList); + Q_EMIT urlsChanged(); +} + +// color +QColor DeclarativeMimeData::color() const +{ + if (this->hasColor()) { + return qvariant_cast(this->colorData()); + } + return QColor(); +} + +bool DeclarativeMimeData::hasColor() const +{ + // qDebug() << " hasColor " << (QMimeData::hasColor() ? color().name() : "false"); + return QMimeData::hasColor(); +} + +void DeclarativeMimeData::setColor(const QColor &color) +{ + if (this->color() != color) { + this->setColorData(color); + Q_EMIT colorChanged(); + } +} + +void DeclarativeMimeData::setData(const QString &mimeType, const QVariant &data) +{ + if (data.type() == QVariant::ByteArray) { + QMimeData::setData(mimeType, data.toByteArray()); + } else if (data.canConvert(QVariant::String)) { + QMimeData::setData(mimeType, data.toString().toLatin1()); + } +} + +/*! + \qmlproperty item MimeData::source + + Setting source to any existing qml item will enable the receiver of the drag and drop operation to know in which item + the operation originated. + + In the case of inter-application drag and drop operations, the source will not be available, and will be 0. + Be sure to test it in your QML code, before using it, or it will generate errors in the console. +*/ +QQuickItem *DeclarativeMimeData::source() const +{ + return m_source; +} +void DeclarativeMimeData::setSource(QQuickItem *source) +{ + if (m_source != source) { + m_source = source; + Q_EMIT sourceChanged(); + } +} + +QByteArray DeclarativeMimeData::getDataAsByteArray(const QString &format) +{ + return data(format); +} diff --git a/draganddrop/declarativemimedata.h b/draganddrop/declarativemimedata.h new file mode 100644 index 0000000..09e6800 --- /dev/null +++ b/draganddrop/declarativemimedata.h @@ -0,0 +1,100 @@ +/* + SPDX-FileCopyrightText: 2010 BetterInbox + SPDX-FileContributor: Gregory Schlomoff + + SPDX-License-Identifier: MIT +*/ + +#ifndef DECLARATIVEMIMEDATA_H +#define DECLARATIVEMIMEDATA_H + +#include +#include +#include +#include +#include + +class DeclarativeMimeData : public QMimeData +{ + Q_OBJECT + + /** + * A plain text (MIME type text/plain) representation of the data. + */ + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) + + /** + * A string if the data stored in the object is HTML (MIME type text/html); otherwise returns an empty string. + */ + Q_PROPERTY(QString html READ html WRITE setHtml NOTIFY htmlChanged) + + /** + * Url contained in the mimedata + */ + Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged) + + /** + * A list of URLs contained within the MIME data object. + * URLs correspond to the MIME type text/uri-list. + */ + Q_PROPERTY(QJsonArray urls READ urls WRITE setUrls NOTIFY urlsChanged) + + /** + * A color if the data stored in the object represents a color (MIME type application/x-color); otherwise QColor(). + */ + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) + + /** + * The graphical item on the scene that started the drag event. It may be null. + */ + Q_PROPERTY(QQuickItem *source READ source WRITE setSource NOTIFY sourceChanged) + + /** @see QMimeData::hasUrls */ + Q_PROPERTY(bool hasUrls READ hasUrls NOTIFY urlsChanged) + // TODO: Image property + + /** + * @sa QMimeData::formats + */ + Q_PROPERTY(QStringList formats READ formats) +public: + DeclarativeMimeData(); + DeclarativeMimeData(const QMimeData *copy); + + QUrl url() const; + void setUrl(const QUrl &url); + + QJsonArray urls() const; + void setUrls(const QJsonArray &urls); + + QColor color() const; + void setColor(const QColor &color); + Q_INVOKABLE bool hasColor() const; + + Q_INVOKABLE void setData(const QString &mimeType, const QVariant &data); + + QQuickItem *source() const; + void setSource(QQuickItem *source); + + Q_INVOKABLE QByteArray getDataAsByteArray(const QString &format); + + /* + QString text() const; //TODO: Reimplement this to issue the onChanged signals + void setText(const QString &text); + QString html() const; + void setHtml(const QString &html); + */ + +Q_SIGNALS: + void textChanged(); // FIXME not being used + void htmlChanged(); // FIXME not being used + void urlChanged(); + void urlsChanged(); + void colorChanged(); + void sourceChanged(); + +private: + QQuickItem *m_source; +}; + +#endif // DECLARATIVEMIMEDATA_H diff --git a/helper/filelauncher.cpp b/helper/filelauncher.cpp new file mode 100644 index 0000000..2124788 --- /dev/null +++ b/helper/filelauncher.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#include "filelauncher.h" + +#include +#include +#include +#include +#include +#include +#include + +FileLauncher *SELF = nullptr; + +FileLauncher *FileLauncher::self() +{ + if (SELF == nullptr) + SELF = new FileLauncher; + + return SELF; +} + +FileLauncher::FileLauncher(QObject *parent) + : QObject(parent) +{ + +} + +bool FileLauncher::launchApp(const QString &desktopFile, const QString &fileName) +{ + QSettings settings(desktopFile, QSettings::IniFormat); + settings.beginGroup("Desktop Entry"); + + QStringList list = settings.value("Exec").toString().split(' '); + QStringList args; + + if (list.isEmpty() || list.size() < 0) + return false; + + QString exec = list.first(); + list.removeOne(exec); + + for (const QString &arg : list) { + QString newArg = arg; + + if (newArg.startsWith("%F", Qt::CaseInsensitive)) + newArg.replace("%F", fileName, Qt::CaseInsensitive); + + if (newArg.startsWith("%U", Qt::CaseInsensitive)) + newArg.replace("%U", fileName, Qt::CaseInsensitive); + + args.append(newArg); + } + + qDebug() << "launchApp()" << exec << args; + + return startDetached(exec, args); +} + +bool FileLauncher::launchExecutable(const QString &fileName) +{ + return startDetached(fileName); +} + +bool FileLauncher::startDetached(const QString &exec, QStringList args) +{ + QDBusInterface iface("com.cutefish.Session", + "/Session", + "com.cutefish.Session", QDBusConnection::sessionBus()); + + if (iface.isValid()) { + iface.asyncCall("launch", exec, args).waitForFinished(); + } else { + QProcess::startDetached(exec, args); + } + + return true; +} + +bool FileLauncher::startDetached(const QString &exec, const QString &workingDir, QStringList args) +{ + QDBusInterface iface("com.cutefish.Session", + "/Session", + "com.cutefish.Session", QDBusConnection::sessionBus()); + + if (iface.isValid()) { + iface.asyncCall("launch", exec, workingDir, args).waitForFinished(); + } + + return true; +} diff --git a/helper/filelauncher.h b/helper/filelauncher.h new file mode 100644 index 0000000..1728005 --- /dev/null +++ b/helper/filelauncher.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#ifndef FILELAUNCHER_H +#define FILELAUNCHER_H + +#include + +class FileLauncher : public QObject +{ + Q_OBJECT + +public: + static FileLauncher *self(); + explicit FileLauncher(QObject *parent = nullptr); + + Q_INVOKABLE bool launchApp(const QString &desktopFile, const QString &fileName); + Q_INVOKABLE bool launchExecutable(const QString &fileName); + + static bool startDetached(const QString &exec, QStringList args = QStringList()); + static bool startDetached(const QString &exec, const QString &workingDir, QStringList args = QStringList()); +}; + +#endif // FILELAUNCHER_H diff --git a/helper/fm.cpp b/helper/fm.cpp index 7c4b533..d222764 100644 --- a/helper/fm.cpp +++ b/helper/fm.cpp @@ -18,6 +18,10 @@ */ #include "fm.h" +#include +#include +#include + #include Fm::Fm(QObject *parent) : QObject(parent) @@ -25,8 +29,26 @@ Fm::Fm(QObject *parent) : QObject(parent) } +QString Fm::rootPath() +{ + return QDir::rootPath(); +} + void Fm::emptyTrash() { KIO::Job *job = KIO::emptyTrash(); job->start(); } + +bool Fm::isFixedFolder(const QUrl &folderUrl) +{ + const QString folder = folderUrl.toLocalFile(); + + return folder == QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first() || + folder == QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).first() || + folder == QStandardPaths::standardLocations(QStandardPaths::MusicLocation).first() || + folder == QStandardPaths::standardLocations(QStandardPaths::MoviesLocation).first() || + folder == QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).first() || + folder == QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first() || + folder == QStandardPaths::standardLocations(QStandardPaths::DownloadLocation).first(); +} diff --git a/helper/fm.h b/helper/fm.h index 1c7e7f9..7da7049 100644 --- a/helper/fm.h +++ b/helper/fm.h @@ -29,7 +29,9 @@ class Fm : public QObject public: explicit Fm(QObject *parent = nullptr); + Q_INVOKABLE QString rootPath(); Q_INVOKABLE static void emptyTrash(); + static bool isFixedFolder(const QUrl &folderUrl); }; #endif // FM_H diff --git a/helper/keyboardsearchmanager.cpp b/helper/keyboardsearchmanager.cpp new file mode 100644 index 0000000..09b3b11 --- /dev/null +++ b/helper/keyboardsearchmanager.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#include "keyboardsearchmanager.h" + +KeyboardSearchManager *KEYBORDSRARCH_MANAGER_SELF = nullptr; + +KeyboardSearchManager *KeyboardSearchManager::self() +{ + if (!KEYBORDSRARCH_MANAGER_SELF) + KEYBORDSRARCH_MANAGER_SELF = new KeyboardSearchManager; + + return KEYBORDSRARCH_MANAGER_SELF; +} + +KeyboardSearchManager::KeyboardSearchManager(QObject *parent) + : QObject(parent) + , m_timeout(500) +{ + // m_timer.setInterval(m_timeout); + // connect(&m_timer, &QTimer::timeout, this, [=] { + // m_searchText.clear(); + // }); +} + +void KeyboardSearchManager::addKeys(const QString &keys) +{ + if (!keys.isEmpty()) { + // m_timer.stop(); + // m_searchText.append(keys); + + // const QChar firstKey = m_searchText.length() > 0 ? m_searchText.at(0) : QChar(); + // const bool sameKey = m_searchText.length() > 1 && m_searchText.count(firstKey) == m_searchText.length(); + + // emit searchTextChanged(sameKey ? firstKey : m_searchText, false); + emit searchTextChanged(keys, false); + + // m_timer.start(); + } +} diff --git a/helper/keyboardsearchmanager.h b/helper/keyboardsearchmanager.h new file mode 100644 index 0000000..c14699d --- /dev/null +++ b/helper/keyboardsearchmanager.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + + +#ifndef KEYBOARDSEARCHMANAGER_H +#define KEYBOARDSEARCHMANAGER_H + +#include +#include + +class KeyboardSearchManager : public QObject +{ + Q_OBJECT + +public: + static KeyboardSearchManager *self(); + explicit KeyboardSearchManager(QObject *parent = nullptr); + + void addKeys(const QString &keys); + +signals: + void searchTextChanged(const QString &string, bool searchFromNextItem); + +private: + QString m_searchText; + qint64 m_timeout; + // QTimer m_timer; +}; + +#endif // KEYBOARDSEARCHMANAGER_H diff --git a/helper/pathhistory.cpp b/helper/pathhistory.cpp index d4801e8..fdc34cc 100644 --- a/helper/pathhistory.cpp +++ b/helper/pathhistory.cpp @@ -31,6 +31,31 @@ void PathHistory::append(const QUrl &path) m_prevHistory.append(path); } +QUrl PathHistory::first() +{ + return m_prevHistory.first(); +} + +QUrl PathHistory::last() +{ + return m_prevHistory.last(); +} + +QUrl PathHistory::at(int i) +{ + return m_prevHistory.at(i); +} + +int PathHistory::count() +{ + return m_prevHistory.count(); +} + +bool PathHistory::isEmpty() +{ + return m_prevHistory.isEmpty(); +} + QUrl PathHistory::posteriorPath() { if (m_postHistory.isEmpty()) diff --git a/helper/pathhistory.h b/helper/pathhistory.h index a129bdb..78fa3c4 100644 --- a/helper/pathhistory.h +++ b/helper/pathhistory.h @@ -21,6 +21,7 @@ #define PATHHISTORY_H #include +#include class PathHistory : public QObject { @@ -31,6 +32,14 @@ class PathHistory : public QObject void append(const QUrl &path); + QUrl first(); + QUrl last(); + + QUrl at(int i); + int count(); + + bool isEmpty(); + QUrl posteriorPath(); QUrl previousPath(); diff --git a/helper/shortcut.cpp b/helper/shortcut.cpp index 66de69e..597a41d 100644 --- a/helper/shortcut.cpp +++ b/helper/shortcut.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright 2021 Reion Wong * + * Copyright 2021 Reion Wong * * Copyright Ken * * Copyright 2016 Leslie Zhai * * * @@ -20,6 +20,7 @@ ***************************************************************************/ #include "shortcut.h" +#include "keyboardsearchmanager.h" #include @@ -31,40 +32,29 @@ ShortCut::ShortCut(QObject *parent) void ShortCut::install(QObject *target) { - if (m_object) { - m_object->removeEventFilter(this); - } + // No need to remove, because memory space is automatically freed in qml. + // if (m_object) { + // m_object->removeEventFilter(this); + // } if (target) { target->installEventFilter(this); - m_object = target; + // m_object = target; } } bool ShortCut::eventFilter(QObject *obj, QEvent *e) { - if (e->type() == QEvent::KeyPress) { - QKeyEvent *keyEvent = static_cast(e); - // int keyInt = keyEvent->modifiers() + keyEvent->key(); + if (e->type() != QEvent::KeyPress) { + return QObject::eventFilter(obj, e); + } + + QKeyEvent *keyEvent = static_cast(e); + int key = keyEvent->key(); - if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return) { - emit open(); - } else if (keyEvent->key() == Qt::Key_C && keyEvent->modifiers() & Qt::ControlModifier) { - emit copy(); - } else if (keyEvent->key() == Qt::Key_X && keyEvent->modifiers() & Qt::ControlModifier) { - emit cut(); - } else if (keyEvent->key() == Qt::Key_V && keyEvent->modifiers() & Qt::ControlModifier) { - emit paste(); - } else if (keyEvent->key() == Qt::Key_F2) { - emit rename(); - } else if (keyEvent->key() == Qt::Key_L && keyEvent->modifiers() & Qt::ControlModifier) { - emit openPathEditor(); - } else if (keyEvent->key() == Qt::Key_A && keyEvent->modifiers() & Qt::ControlModifier) { - emit selectAll(); - } else if (keyEvent->key() == Qt::Key_Backspace) { - emit backspace(); - } else if (keyEvent->key() == Qt::Key_Delete) { - emit deleteFile(); + for (const fun_shortcut &shortcut: Normal_Shortcuts) { + if (key == shortcut.key) { + shortcut.action(); } } diff --git a/helper/shortcut.h b/helper/shortcut.h index d4c9c80..fb5c7f0 100644 --- a/helper/shortcut.h +++ b/helper/shortcut.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright 2021 Reion Wong * + * Copyright 2021 Reion Wong * * Copyright Ken * * Copyright 2016 Leslie Zhai * * * @@ -19,47 +19,66 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ -#ifndef SHORTCUT_H -#define SHORTCUT_H +#pragma once #include -/** - * TODO: ShortCut is a stopgap solution and should be dropped when Qt's StandardKey - * gains support for these actions. QTBUG-54926 https://bugreports.qt.io/browse/QTBUG-54926 - * And it is *NOT* encouraged registering C++ types with the QML by using EventFilter - * but for special case QTBUG-40327 https://bugreports.qt.io/browse/QTBUG-40327 - * - * ShortCut was copied from Ken's answer. - * https://stackoverflow.com/questions/12192780/assigning-keyboard-shortcuts-to-qml-components - * it uses cc by-sa 3.0 license by default compatible with GPL. - * https://www.gnu.org/licenses/license-list.en.html#ccbysa - */ class ShortCut : public QObject { Q_OBJECT -public: - explicit ShortCut(QObject *parent = nullptr); + public: + explicit ShortCut(QObject *parent = nullptr); - Q_INVOKABLE void install(QObject *target = nullptr); + Q_INVOKABLE void install(QObject *target = nullptr); -signals: - void open(); - void copy(); - void cut(); - void paste(); - void rename(); - void openPathEditor(); - void selectAll(); - void backspace(); - void deleteFile(); + signals: + void open(); + void copy(); + void cut(); + void paste(); + void rename(); + void refresh(); + void openPathEditor(); + void selectAll(); + void backspace(); + void deleteFile(); + void showHidden(); + void keyPressed(const QString &text); + void close(); + void undo(); -protected: - bool eventFilter(QObject *obj, QEvent *e) override; + protected: + bool eventFilter(QObject *obj, QEvent *e) override; -private: - QObject *m_object; -}; + private: + QObject *m_object; + + // This is a structure composed of : + // - a key (the shortcut) + // - an action (the function pointer) + typedef struct { + Qt::Key key; + std::function action; + } fun_shortcut; -#endif // SHORTCUT_H + // This array contains structures where keys are associated + // with an action. You only have to loop on this array, compare + // its key with the one you received, and execute its action + const fun_shortcut Normal_Shortcuts[14] = { + { Qt::Key_Y, [&]() { return copy(); } }, + { Qt::Key_P, [&]() { return paste(); } }, + { Qt::Key_R, [&]() { return rename(); } }, + { Qt::Key_Return, [&]() { return open(); } }, + { Qt::Key_Enter, [&]() { return open(); } }, + { Qt::Key_Percent, [&]() { return showHidden(); } }, + { Qt::Key_U, [&]() { return undo(); } }, + { Qt::Key_D, [&]() { return cut(); } }, + { Qt::Key_X, [&]() { return deleteFile(); } }, + { Qt::Key_Q, [&]() { return close(); } }, + { Qt::Key_A, [&]() { return refresh(); } }, + { Qt::Key_Colon, [&]() { return openPathEditor(); } }, + { Qt::Key_V, [&]() { return selectAll(); } }, + { Qt::Key_Backspace, [&]() { return backspace(); } } + }; +}; diff --git a/helper/thumbnailer.cpp b/helper/thumbnailer.cpp deleted file mode 100644 index ba7c2b2..0000000 --- a/helper/thumbnailer.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2021 CutefishOS Team. - * - * Author: revenmartin - * - * 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 3 of the License, or - * 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, see . - */ - -#include "thumbnailer.h" - -#include - -#include "thumbnailerjob.h" - -#include -#include - -QQuickImageResponse *Thumbnailer::requestImageResponse(const QString &id, const QSize &requestedSize) -{ - AsyncImageResponse *response = new AsyncImageResponse(id, requestedSize); - return response; -} - -AsyncImageResponse::AsyncImageResponse(const QString &id, const QSize &requestedSize) - : m_id(id) - , m_requestedSize(requestedSize) -{ - auto job_ = new ThumbnailerJob(QUrl::fromUserInput(id).toLocalFile(), requestedSize); - connect(job_, &ThumbnailerJob::gotPreview, [this] (QPixmap pixmap) { - m_image = pixmap.toImage(); - emit this->finished(); - }); - - connect(job_, &ThumbnailerJob::failed, [this] { - emit this->cancel(); - emit this->finished(); - }); - - job_->start(); - - - -// QStringList plugins = KIO::PreviewJob::defaultPlugins(); -// auto job = new KIO::PreviewJob(KFileItemList() << KFileItem(QUrl::fromUserInput(id)), requestedSize, &plugins); - -// connect(job, &KIO::PreviewJob::gotPreview, [this](KFileItem, QPixmap pixmap) { -// m_image = pixmap.toImage(); -// emit this->finished(); -// }); - -// connect(job, &KIO::PreviewJob::failed, [this](KFileItem) { -// emit this->cancel(); -// emit this->finished(); -// }); - -// job->start(); -} - -QQuickTextureFactory *AsyncImageResponse::textureFactory() const -{ - return QQuickTextureFactory::textureFactoryForImage(m_image); -} diff --git a/helper/thumbnailerjob.cpp b/helper/thumbnailerjob.cpp deleted file mode 100644 index 3c1c011..0000000 --- a/helper/thumbnailerjob.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2021 CutefishOS Team. - * - * Author: Reion Wong - * - * 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 3 of the License, or - * 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, see . - */ - -#include "thumbnailerjob.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -ThumbnailerJob::ThumbnailerJob(const QString &fileName, const QSize &size, QObject *parent) - : QThread(parent) - , m_url(QUrl::fromUserInput(fileName)) - , m_size(size) - , shmaddr(nullptr) - , shmid(-1) -{ - // http://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html#DIRECTORY - m_thumbnailsDir = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1String("/thumbnails/"); -} - -ThumbnailerJob::~ThumbnailerJob() -{ - if (shmaddr) { - shmdt((char *)shmaddr); - shmctl(shmid, IPC_RMID, nullptr); - } -} - -void ThumbnailerJob::run() -{ - if (!QFile::exists(m_url.toLocalFile())) { - emit failed(); - return; - } - - int width = m_size.width(); - int height = m_size.height(); - int cacheSize = 0; - bool needCache = false; - - // 首先需要找到目录 - if (width <= 128 && height <= 128) - cacheSize = 128; - else if (width <= 256 && height <= 256) - cacheSize = 256; - else - cacheSize = 512; - - struct CachePool { - QString path; - int minSize; - }; - - const static auto pools = { - CachePool{QStringLiteral("/normal/"), 128}, - CachePool{QStringLiteral("/large/"), 256}, - CachePool{QStringLiteral("/x-large/"), 512}, - CachePool{QStringLiteral("/xx-large/"), 1024}, - }; - - QString thumbDir; - int wants = /*devicePixelRatio **/ cacheSize; - for (const auto &p : pools) { - if (p.minSize < wants) { - continue; - } else { - thumbDir = p.path; - break; - } - } - - m_thumbnailsPath = m_thumbnailsDir + thumbDir; - - // 不存在需要创建路径 - if (!QDir(m_thumbnailsPath).exists()) { - if (QDir().mkpath(m_thumbnailsPath)) { - QFile f(m_thumbnailsPath); - f.setPermissions(QFile::ReadUser | QFile::WriteUser | QFile::ExeUser); // 0700 - } - } - - // 求出文件的 md5 - QByteArray origName; - const QFileInfo info(m_url.toLocalFile()); - const QString canonicalPath = info.canonicalFilePath(); - origName = QUrl::fromLocalFile(canonicalPath).toEncoded(QUrl::RemovePassword | QUrl::FullyEncoded); - - if (origName.isEmpty()) { - emit failed(); - return; - } - - QCryptographicHash md5(QCryptographicHash::Md5); - md5.addData(origName); - m_thumbnailsName = QString::fromLatin1(md5.result().toHex()) + QLatin1String(".png"); - - // 是否需要生成缓存 - needCache = !QFile::exists(m_thumbnailsPath + m_thumbnailsName); - - if (needCache) { - QFile f(m_url.toLocalFile()); - if (f.open(QIODevice::ReadOnly)) { - QByteArray data = f.readAll(); - QImage thumb; - thumb.loadFromData(data); - thumb = thumb.scaled(m_size, Qt::KeepAspectRatio, Qt::SmoothTransformation); - - // 保存 cache 文件 - QSaveFile saveFile(m_thumbnailsPath + m_thumbnailsName); - if (saveFile.open(QIODevice::WriteOnly)) { - if (thumb.save(&saveFile, "PNG")) { - saveFile.commit(); - } - } - - emitPreview(thumb); - } - } else { - QFile f(m_thumbnailsPath + m_thumbnailsName); - if (f.open(QIODevice::ReadOnly)) { - QByteArray data = f.readAll(); - QImage thumb; - thumb.loadFromData(data); - emitPreview(thumb); - } - } -} - -void ThumbnailerJob::emitPreview(const QImage &image) -{ - QPixmap pixmap; - - if (image.width() > m_size.width() || image.height() > m_size.height()) { - pixmap = QPixmap::fromImage(image.scaled(m_size, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - } else { - pixmap = QPixmap::fromImage(image); - } - - emit gotPreview(pixmap); -} diff --git a/images/dark/add.svg b/images/dark/add.svg new file mode 100644 index 0000000..3bcd12d --- /dev/null +++ b/images/dark/add.svg @@ -0,0 +1,66 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/images/dark/grid.svg b/images/dark/grid.svg index 16cf854..6e1c792 100644 --- a/images/dark/grid.svg +++ b/images/dark/grid.svg @@ -1,11 +1,21 @@ - + + + + + + image/svg+xml + + + + + - - + + diff --git a/images/dark/list.svg b/images/dark/list.svg index 5517525..18c4eea 100644 --- a/images/dark/list.svg +++ b/images/dark/list.svg @@ -1,105 +1,27 @@ - - - - - - image/svg+xml - - - - - - - + + + + + + + + + + diff --git a/images/drive-harddisk-root.svg b/images/drive-harddisk-root.svg new file mode 100755 index 0000000..2489006 --- /dev/null +++ b/images/drive-harddisk-root.svg @@ -0,0 +1,21 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/images/drive-harddisk.svg b/images/drive-harddisk.svg new file mode 100755 index 0000000..2489006 --- /dev/null +++ b/images/drive-harddisk.svg @@ -0,0 +1,21 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/images/drive-optical.svg b/images/drive-optical.svg new file mode 100755 index 0000000..0a31fff --- /dev/null +++ b/images/drive-optical.svg @@ -0,0 +1,18 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/images/drive-removable-media-usb.svg b/images/drive-removable-media-usb.svg new file mode 100755 index 0000000..c5cc0ef --- /dev/null +++ b/images/drive-removable-media-usb.svg @@ -0,0 +1,21 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/images/folder-desktop.svg b/images/folder-desktop.svg new file mode 100755 index 0000000..0009563 --- /dev/null +++ b/images/folder-desktop.svg @@ -0,0 +1,16 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/images/folder-document.svg b/images/folder-document.svg new file mode 100755 index 0000000..809cf9c --- /dev/null +++ b/images/folder-document.svg @@ -0,0 +1,21 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/images/folder-download.svg b/images/folder-download.svg new file mode 100755 index 0000000..b7c8ae5 --- /dev/null +++ b/images/folder-download.svg @@ -0,0 +1,16 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/images/folder-home.svg b/images/folder-home.svg new file mode 100755 index 0000000..88a7042 --- /dev/null +++ b/images/folder-home.svg @@ -0,0 +1,16 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/images/folder-music.svg b/images/folder-music.svg new file mode 100755 index 0000000..f2d0256 --- /dev/null +++ b/images/folder-music.svg @@ -0,0 +1,16 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/images/folder-picture.svg b/images/folder-picture.svg new file mode 100755 index 0000000..9488b22 --- /dev/null +++ b/images/folder-picture.svg @@ -0,0 +1,16 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/images/folder-video.svg b/images/folder-video.svg new file mode 100755 index 0000000..283795c --- /dev/null +++ b/images/folder-video.svg @@ -0,0 +1,16 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/images/light/add.svg b/images/light/add.svg new file mode 100644 index 0000000..def3824 --- /dev/null +++ b/images/light/add.svg @@ -0,0 +1,66 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/images/light/grid.svg b/images/light/grid.svg index e035d6c..f119f5d 100644 --- a/images/light/grid.svg +++ b/images/light/grid.svg @@ -1,11 +1,21 @@ - + + + + + + image/svg+xml + + + + + - - + + diff --git a/images/light/list.svg b/images/light/list.svg index 603a6d1..5633041 100644 --- a/images/light/list.svg +++ b/images/light/list.svg @@ -1,105 +1,29 @@ - - - - - - image/svg+xml - - - - - - - + + + + + + + + + + + + diff --git a/images/media-optical-data.svg b/images/media-optical-data.svg new file mode 100755 index 0000000..f983c9b --- /dev/null +++ b/images/media-optical-data.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/images/media-optical-mixed-cd.svg b/images/media-optical-mixed-cd.svg new file mode 100755 index 0000000..a3978bf --- /dev/null +++ b/images/media-optical-mixed-cd.svg @@ -0,0 +1,22 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/images/media-optical.svg b/images/media-optical.svg new file mode 100755 index 0000000..68ce9f0 --- /dev/null +++ b/images/media-optical.svg @@ -0,0 +1,17 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/images/user-trash.svg b/images/user-trash.svg new file mode 100755 index 0000000..7b0c00a --- /dev/null +++ b/images/user-trash.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/main.cpp b/main.cpp index e5da074..23faa0f 100644 --- a/main.cpp +++ b/main.cpp @@ -17,48 +17,35 @@ * along with this program. If not, see . */ -#include -#include -#include -#include - -#include -#include - +#include "application.h" #include "model/placesmodel.h" #include "model/foldermodel.h" #include "model/pathbarmodel.h" #include "model/positioner.h" #include "widgets/rubberband.h" #include "widgets/itemviewadapter.h" +#include "desktop/desktop.h" #include "desktop/desktopsettings.h" #include "desktop/desktopview.h" -#include "helper/thumbnailer.h" #include "helper/datehelper.h" #include "helper/fm.h" #include "helper/shortcut.h" -int main(int argc, char *argv[]) -{ - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#include "draganddrop/declarativedragdropevent.h" +#include "draganddrop/declarativedroparea.h" +#include "draganddrop/declarativemimedata.h" - QApplication app(argc, argv); - app.setOrganizationName("cutefishos"); +#include - // Translations - QLocale locale; - QString qmFilePath = QString("%1/%2.qm").arg("/usr/share/cutefish-filemanager/translations/").arg(locale.name()); - if (QFile::exists(qmFilePath)) { - QTranslator *translator = new QTranslator(app.instance()); - if (translator->load(qmFilePath)) { - app.installTranslator(translator); - } else { - translator->deleteLater(); - } - } +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true); // Register QML Type. const char *uri = "Cutefish.FileManager"; + const char *dragandrop_uri = "Cutefish.DragDrop"; + qmlRegisterType(uri, 1, 0, "PlacesModel"); qmlRegisterType(uri, 1, 0, "FolderModel"); qmlRegisterType(uri, 1, 0, "PathBarModel"); @@ -68,60 +55,19 @@ int main(int argc, char *argv[]) qmlRegisterType(uri, 1, 0, "DesktopSettings"); qmlRegisterType(uri, 1, 0, "Fm"); qmlRegisterType(uri, 1, 0, "ShortCut"); - qmlRegisterAnonymousType(uri, 1); - - QCommandLineParser parser; - parser.setApplicationDescription(QStringLiteral("File Manager")); - parser.addHelpOption(); - parser.addPositionalArgument("files", "Files", "[FILE1, FILE2,...]"); - - QCommandLineOption desktopOption(QStringList() << "d" << "desktop" << "Desktop Mode"); - parser.addOption(desktopOption); - - QCommandLineOption emptyTrashOption(QStringList() << "e" << "empty-trash" << "Empty Trash"); - parser.addOption(emptyTrashOption); - - parser.process(app); - - if (parser.isSet(desktopOption)) { - app.setApplicationName("cutefish-desktop"); - DesktopView view; - view.show(); - return app.exec(); - } else if (parser.isSet(emptyTrashOption)) { - // Empty Dialog - QQmlApplicationEngine engine; - const QUrl url(QStringLiteral("qrc:/qml/Dialogs/EmptyTrashDialog.qml")); - engine.load(url); - return app.exec(); - } - - QQmlApplicationEngine engine; - const QUrl url(QStringLiteral("qrc:/qml/main.qml")); - QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, - &app, [url](QObject *obj, const QUrl &objUrl) { - if (!obj && url == objUrl) - QCoreApplication::exit(-1); - }, Qt::QueuedConnection); - - // Handle urls - if (!parser.positionalArguments().isEmpty()) { - QStringList arguments = parser.positionalArguments(); - QUrl url(arguments.first()); - if (!url.isValid()) - url = QUrl::fromLocalFile(arguments.first()); - - if (url.isValid()) - engine.rootContext()->setContextProperty("arg", arguments.first()); - else - engine.rootContext()->setContextProperty("arg", ""); - } else { - engine.rootContext()->setContextProperty("arg", ""); - } +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) + qmlRegisterType(); + qmlRegisterType(); +#else + qmlRegisterAnonymousType(uri, 1); + qmlRegisterAnonymousType(dragandrop_uri, 1); +#endif - engine.load(url); - engine.addImageProvider("thumbnailer", new Thumbnailer()); + qmlRegisterType(dragandrop_uri, 1, 0, "DropArea"); + qmlRegisterUncreatableType(dragandrop_uri, 1, 0, "MimeData", QStringLiteral("MimeData cannot be created from QML.")); + qmlRegisterUncreatableType(dragandrop_uri, 2, 0, "DragDropEvent", QStringLiteral("DragDropEvent cannot be created from QML.")); - return app.exec(); + Application app(argc, argv); + return app.run(); } diff --git a/mimetype/mimeappmanager.cpp b/mimetype/mimeappmanager.cpp new file mode 100644 index 0000000..9505f69 --- /dev/null +++ b/mimetype/mimeappmanager.cpp @@ -0,0 +1,476 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#include "mimeappmanager.h" +#include "helper/filelauncher.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static MimeAppManager *SELF = nullptr; + +MimeAppManager *MimeAppManager::self() +{ + if (!SELF) + SELF = new MimeAppManager; + + return SELF; +} + +MimeAppManager::MimeAppManager(QObject *parent) + : QObject(parent), + m_fileSystemWatcher(new QFileSystemWatcher), + m_updateTimer(new QTimer(this)) +{ + m_updateTimer->setInterval(100); + m_updateTimer->setSingleShot(true); + + m_fileSystemWatcher->addPaths(desktopPaths()); + + connect(m_fileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, &MimeAppManager::onFileChanged); + connect(m_fileSystemWatcher, &QFileSystemWatcher::fileChanged, this, &MimeAppManager::onFileChanged); + connect(m_updateTimer, &QTimer::timeout, this, &MimeAppManager::initApplications); + + m_updateTimer->start(); +} + +QStringList MimeAppManager::desktopPaths() +{ + QStringList folders; + folders << QString("/usr/share/applications") + << QString("/usr/local/share/applications/") + << QDir::homePath() + QString("/.local/share/applications"); + + return folders; +} + +QString MimeAppManager::mimeAppsListFilePath() +{ + // return QString("%1/.config/mimeapps.list").arg(QDir::homePath()); + + return QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QLatin1String("/mimeapps.list"); +} + +void MimeAppManager::initApplications() +{ + m_desktopFiles.clear(); + m_desktopObjects.clear(); + + QMap> mimeAppsSet; + + for (const QString &folder : desktopPaths()) { + QDirIterator itor(folder, QStringList("*.desktop"), QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + while (itor.hasNext()) { + itor.next(); + QString filePath = itor.filePath(); + XdgDesktopFile desktopFile(filePath); + + if (!desktopFile.valid()) + continue; + + if (desktopFile.value("Terminal").toBool()) + continue; + + m_desktopFiles.append(filePath); + m_desktopObjects.insert(filePath, desktopFile); + + // Load terminal + QStringList categories = desktopFile.value("Categories").toString().split(";"); + if (categories.contains("TerminalEmulator")) { + m_terminalApps.append(desktopFile); + } + + QStringList mimeTypes = desktopFile.value("MimeType").toString().trimmed().split(";"); + for (const QString &mimeType : mimeTypes) { + if (!mimeType.isEmpty()) { + QSet apps; + if (mimeAppsSet.contains(mimeType)) { + apps = mimeAppsSet.value(mimeType); + apps.insert(filePath); + } else { + apps.insert(filePath); + } + + mimeAppsSet.insert(mimeType, apps); + } + } + } + } + + for (const QString &key : mimeAppsSet.keys()) { + QSet apps = mimeAppsSet.value(key); + QStringList orderApps; + + if (apps.count() > 1) { + QFileInfoList fileInfos; + for (const QString &app : apps) { + QFileInfo info(app); + fileInfos.append(info); + } + + std::sort(fileInfos.begin(), fileInfos.end(), [=] (const QFileInfo &f1, const QFileInfo &f2) { + return f1.birthTime() < f2.birthTime(); + }); + + for (QFileInfo info : fileInfos) { + orderApps.append(info.absoluteFilePath()); + } + } else { + orderApps.append(apps.values()); + } + + m_mimeApps.insert(key, orderApps); + } + + // Check from cache. + // ref: https://specifications.freedesktop.org/desktop-entry-spec/0.9.5/ar01s07.html + + QFile file("/usr/share/applications/mimeinfo.cache"); + if (!file.open(QIODevice::ReadOnly)) + return; + + QStringList audioDesktopList; + QStringList imageDeksopList; + QStringList textDekstopList; + QStringList videoDesktopList; + + while (!file.atEnd()) { + QString line = file.readLine(); + QString mimeType = line.split("=").first(); + QString _desktops = line.split("=").last(); + QStringList desktops = _desktops.split(";"); + + for (const QString &desktop : desktops) { + if (desktop.isEmpty() || audioDesktopList.contains(desktop)) + continue; + + if (mimeType.startsWith("audio")) { + if (!audioDesktopList.contains(desktop)) + audioDesktopList.append(desktop); + } else if (mimeType.startsWith("image")) { + if (!imageDeksopList.contains(desktop)) + imageDeksopList.append(desktop); + } else if (mimeType.startsWith("text")) { + if (!textDekstopList.contains(desktop)) + textDekstopList.append(desktop); + } else if (mimeType.startsWith("video")) { + if (!videoDesktopList.contains(desktop)) + videoDesktopList.append(desktop); + } + } + } + + file.close(); + + const QString mimeInfoCacheRootPath = "/usr/share/applications"; + for (const QString &desktop : audioDesktopList) { + const QString &path = QString("%1/%2").arg(mimeInfoCacheRootPath, desktop); + if (!QFile::exists(path)) + continue; + + XdgDesktopFile desktopFile(path); + if (desktopFile.valid()) + m_audioMimeApps.insert(path, desktopFile); + } + + for (const QString &desktop : imageDeksopList) { + const QString &path = QString("%1/%2").arg(mimeInfoCacheRootPath, desktop); + if (!QFile::exists(path)) + continue; + + XdgDesktopFile desktopFile(path); + if (desktopFile.valid()) + m_imageMimeApps.insert(path, desktopFile); + } + + for (const QString &desktop : textDekstopList) { + const QString &path = QString("%1/%2").arg(mimeInfoCacheRootPath, desktop); + if (!QFile::exists(path)) + continue; + + XdgDesktopFile desktopFile(path); + if (desktopFile.valid()) + m_textMimeApps.insert(path, desktopFile); + } + + for (const QString &desktop : videoDesktopList) { + const QString &path = QString("%1/%2").arg(mimeInfoCacheRootPath, desktop); + if (!QFile::exists(path)) + continue; + + XdgDesktopFile desktopFile(path); + if (desktopFile.valid()) + m_videoMimeApps.insert(path, desktopFile); + } +} + +QString MimeAppManager::getDefaultAppByFilePath(const QString &filePath) +{ + return getDefaultAppByMimeType(QMimeDatabase().mimeTypeForFile(filePath)); +} + +QString MimeAppManager::getDefaultAppByMimeType(const QMimeType &mimeType) +{ + QString mimeappsFile = mimeAppsListFilePath(); + + if (!QFile::exists(mimeappsFile)) + return QString(); + + QSettings settings(mimeappsFile, QSettings::IniFormat); + + // for (const QString group : settings.childGroups()) { + // settings.beginGroup(group); + // for (const QString &key : settings.allKeys()) { + // if (key == mimeType.name()) + // return settings.value(key).toString(); + // } + // settings.endGroup(); + // } + + settings.beginGroup("Default Applications"); + // TODO: User applications directory? + if (settings.contains(mimeType.name())) { + const QString desktopFile = QString("/usr/share/applications/%1").arg(settings.value(mimeType.name()).toString()); + if (QFile::exists(desktopFile)) { + return desktopFile; + } + } + + settings.endGroup(); + + settings.beginGroup("Added Associations"); + if (settings.contains(mimeType.name())) { + QString desktopFile = QString("/usr/share/applications/%1").arg(settings.value(mimeType.name()).toString()); + if (QFile::exists(desktopFile)) { + return desktopFile; + } + } + + return QString(); +} + +QString MimeAppManager::getDefaultAppDesktopByMimeType(const QString &mimeType) +{ + return getDefaultAppByMimeType(QMimeDatabase().mimeTypeForName(mimeType)); +} + +bool MimeAppManager::setDefaultAppForType(const QString &mimeType, const QString &app) +{ + Q_UNUSED(mimeType); + + // ref: https://specifications.freedesktop.org/mime-apps-spec/1.0.1/ar01s03.html + + QString mimeappsFile = mimeAppsListFilePath(); + QString desktop = app; + + if (QFile::exists(desktop)) { + QFileInfo info(desktop); + desktop = info.completeBaseName(); + } else { + return false; + } + + KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), + KConfig::NoGlobals, + QStandardPaths::GenericConfigLocation); + KConfigGroup defaultApp(profile, "Default Applications"); + defaultApp.writeXdgListEntry(mimeType, {desktop}); + + KConfigGroup addedApps(profile, "Added Associations"); + QStringList apps = addedApps.readXdgListEntry(mimeType); + apps.removeAll(desktop); + apps.prepend(desktop); // make it the preferred app + addedApps.writeXdgListEntry(mimeType, apps); + + profile->sync(); + + return true; +} + +bool MimeAppManager::setDefaultAppForFile(const QString &filePath, const QString &desktop) +{ + // ref: https://specifications.freedesktop.org/mime-apps-spec/1.0.1/ar01s03.html + + QMimeType mimeType; + QString value = desktop; + + if (!QFile::exists(filePath)) + return false; + else + mimeType = QMimeDatabase().mimeTypeForFile(filePath); + + if (QFile::exists(value)) { + QFileInfo info(value); + value = info.fileName(); + } else { + return false; + } + + KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), + KConfig::NoGlobals, + QStandardPaths::GenericConfigLocation); + KConfigGroup defaultApp(profile, "Default Applications"); + defaultApp.writeXdgListEntry(mimeType.name(), {value}); + + KConfigGroup addedApps(profile, "Added Associations"); + QStringList apps = addedApps.readXdgListEntry(mimeType.name()); + apps.removeAll(value); + apps.prepend(value); // make it the preferred app + addedApps.writeXdgListEntry(mimeType.name(), apps); + + profile->sync(); + + return true; +} + +QStringList MimeAppManager::getRecommendedAppsByFilePath(const QString &filePath) +{ + return getRecommendedAppsByMimeType(QMimeDatabase().mimeTypeForFile(filePath)); +} + +QStringList MimeAppManager::getRecommendedAppsByMimeType(const QMimeType &mimeType) +{ + QStringList recommendApps; + QList mimeTypeList; + QMimeDatabase mimeDatabase; + + mimeTypeList.append(mimeType); + + while (recommendApps.isEmpty()) { + for (const QMimeType &type : mimeTypeList) { + QStringList typeNameList; + + typeNameList.append(type.name()); + typeNameList.append(type.aliases()); + + for (const QString &name : typeNameList) { + for (const QString &app : m_mimeApps.value(name)) { + bool exists = false; + + for (const QString &other : recommendApps) { + const XdgDesktopFile &appDesktop = m_desktopObjects.value(app); + const XdgDesktopFile &otherDesktop = m_desktopObjects.value(other); + + if (appDesktop.value("Exec").toString() == otherDesktop.value("Exec").toString() && + appDesktop.localeName() == otherDesktop.localeName()) { + exists = true; + break; + } + } + + // if desktop file was not existed do not recommend!! + if (!QFileInfo::exists(app)) { + qWarning() << app << "not exist anymore"; + continue; + } + + if (!exists) + recommendApps.append(app); + } + } + } + + if (!recommendApps.isEmpty()) + break; + + QList newMimeTypeList; + for (const QMimeType &type : mimeTypeList) { + for (const QString &name : type.parentMimeTypes()) + newMimeTypeList.append(mimeDatabase.mimeTypeForName(name)); + } + + mimeTypeList = newMimeTypeList; + + if (mimeTypeList.isEmpty()) + break; + } + + return recommendApps; +} + +QVariantList MimeAppManager::recommendedApps(const QUrl &url) +{ + QVariantList list; + + if (url.isValid()) { + const QString &filePath = url.toString(); + + for (const QString &path : getRecommendedAppsByFilePath(filePath)) { + XdgDesktopFile desktop(path); + + if (!desktop.valid()) + continue; + + QVariantMap item; + item["icon"] = desktop.value("Icon").toString(); + item["name"] = desktop.localeName(); + item["desktopFile"] = path; + + list << item; + } + } + + return list; +} + +void MimeAppManager::launchTerminal(const QString &path) +{ + if (m_terminalApps.isEmpty()) + return; + + QSettings settings("cutefishos", "defaultApps"); + QString defaultTerminal = settings.value("terminal").toString(); + QString command; + + if (!defaultTerminal.isEmpty()) { + for (const XdgDesktopFile &f : m_terminalApps) { + if (f.fileName().contains(defaultTerminal)) { + command = f.value("Exec").toString(); + break; + } + } + } + + if (command.isEmpty()) { + command = m_terminalApps.first().value("Exec").toString(); + } + + FileLauncher::startDetached(command, path, QStringList()); +} + +void MimeAppManager::onFileChanged(const QString &path) +{ + Q_UNUSED(path); + + m_updateTimer->start(); +} diff --git a/mimetype/mimeappmanager.h b/mimetype/mimeappmanager.h new file mode 100644 index 0000000..5311fd9 --- /dev/null +++ b/mimetype/mimeappmanager.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#ifndef MIMEAPPMANAGER_H +#define MIMEAPPMANAGER_H + +#include +#include +#include +#include +#include + +#include "xdgdesktopfile.h" + +class QMimeType; +class MimeAppManager : public QObject +{ + Q_OBJECT + +public: + static MimeAppManager *self(); + explicit MimeAppManager(QObject *parent = nullptr); + + QStringList desktopPaths(); + QString mimeAppsListFilePath(); + void initApplications(); + + QString getDefaultAppByFilePath(const QString &filePath); + QString getDefaultAppByMimeType(const QMimeType &mimeType); + QString getDefaultAppDesktopByMimeType(const QString &mimeType); + Q_INVOKABLE bool setDefaultAppForType(const QString &mimeType, const QString &app); + Q_INVOKABLE bool setDefaultAppForFile(const QString &filePath, const QString &desktop); + + QStringList getRecommendedAppsByFilePath(const QString &filePath); + QStringList getRecommendedAppsByMimeType(const QMimeType &mimeType); + + Q_INVOKABLE QVariantList recommendedApps(const QUrl &url); + + Q_INVOKABLE void launchTerminal(const QString &path); + +private slots: + void onFileChanged(const QString &path); + +private: + QStringList m_desktopFiles; + QMap m_mimeApps; + + QMap m_videoMimeApps; + QMap m_imageMimeApps; + QMap m_textMimeApps; + QMap m_audioMimeApps; + QMap m_desktopObjects; + + QList m_terminalApps; + + QFileSystemWatcher *m_fileSystemWatcher; + QTimer *m_updateTimer; +}; + +#endif // MIMEAPPMANAGER_H diff --git a/mimetype/xdgdesktopfile.cpp b/mimetype/xdgdesktopfile.cpp new file mode 100644 index 0000000..de7e7ea --- /dev/null +++ b/mimetype/xdgdesktopfile.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#include "xdgdesktopfile.h" +#include +#include +#include +#include + +XdgDesktopFile::XdgDesktopFile(const QString &fileName) + : m_isValid(false) + , m_fileName(fileName) +{ + if (!m_fileName.isEmpty()) + load(); +} + +bool XdgDesktopFile::valid() const +{ + return m_isValid; +} + +QVariant XdgDesktopFile::value(const QString &key, const QVariant &defaultValue) const +{ + QString path = (!prefix().isEmpty()) ? prefix() + QLatin1Char('/') + key : key; + QVariant res = m_items.value(path, defaultValue); + return res; +} + +void XdgDesktopFile::setValue(const QString &key, const QVariant &value) +{ + QString path = (!prefix().isEmpty()) ? prefix() + QLatin1Char('/') + key : key; + + if (value.type() == QVariant::String) { + QString s = value.toString(); + m_items[path] = QVariant(s); + } else { + m_items[path] = value; + } +} + +bool XdgDesktopFile::load() +{ + if (!QFile::exists(m_fileName)) + return false; + + m_items.clear(); + + read("Desktop Entry"); + + return m_isValid; +} + +bool XdgDesktopFile::save() +{ + QFile file(m_fileName); + + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) + return false; + + QTextStream stream(&file); + QMap::const_iterator i = m_items.constBegin(); + QString section; + + while (i != m_items.constBegin()) { + QString path = i.key(); + QString sect = path.section(QChar('/'), 0, 0); + + if (sect != section) { + section = sect; +#if QT_VERSION >= 0x050e00 + stream << QLatin1Char('[') << section << QChar(']') << Qt::endl; +#else + stream << QLatin1Char('[') << section << QChar(']') << endl; +#endif + } + + QString key = path.section(QChar('/'), 1); +#if QT_VERSION >= 0x050e00 + stream << key << QLatin1Char('=') << i.value().toString() << Qt::endl; +#else + stream << key << QLatin1Char('=') << i.value().toString() << endl; +#endif + ++i; + } + + return true; +} + +QStringList XdgDesktopFile::keys() const +{ + return m_items.keys(); +} + +QString XdgDesktopFile::localeName() const +{ + QString localeKey = QString("Name[%1]").arg(QLocale::system().name()); + + if (XdgDesktopFile::value(localeKey).toString().isEmpty()) + return XdgDesktopFile::value("Name").toString();; + + return XdgDesktopFile::value(localeKey).toString(); +} + +QString XdgDesktopFile::prefix() const +{ + return QLatin1String("Desktop Entry"); +} + +QString XdgDesktopFile::fileName() const +{ + return m_fileName; +} + +bool XdgDesktopFile::read(const QString &prefix) +{ + QFile file(m_fileName); + + // Can't open file. + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return false; + + QTextStream stream(&file); + QString section; + bool prefixExists = false; + + while (!stream.atEnd()) { + QString line = stream.readLine().trimmed(); + + // Skip comments. + if (line.startsWith("#")) + continue; + + // Find the prefix string. + if (line.startsWith(QChar('[')) && line.endsWith(QChar(']'))) { + section = line.mid(1, line.length() - 2); + + if (section == prefix) + prefixExists = true; + + continue; + } + + QString key = line.section(QLatin1Char('='), 0, 0).trimmed(); + QString value = line.section(QLatin1Char('='), 1).trimmed(); + + if (key.isEmpty()) + continue; + + m_items[section + QLatin1Char('/') + key] = QVariant(value); + } + + m_isValid = (prefix.isEmpty()) || prefixExists; + return m_isValid; +} diff --git a/mimetype/xdgdesktopfile.h b/mimetype/xdgdesktopfile.h new file mode 100644 index 0000000..ae65bfa --- /dev/null +++ b/mimetype/xdgdesktopfile.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#ifndef XDGDESKTOPFILE_H +#define XDGDESKTOPFILE_H + +#include +#include +#include + +class XdgDesktopFile +{ +public: + explicit XdgDesktopFile(const QString &fileName = QString()); + + bool valid() const; + + QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const; + void setValue(const QString &key, const QVariant &value); + + bool load(); + bool save(); + + QStringList keys() const; + + QString localeName() const; + QString prefix() const; + + QString fileName() const; + +private: + bool read(const QString &prefix); + +private: + bool m_isValid; + QString m_fileName; + QMap m_items; +}; + +#endif // XDGDESKTOPFILE_H diff --git a/model/foldermodel.cpp b/model/foldermodel.cpp index 91ff07f..fd060a3 100644 --- a/model/foldermodel.cpp +++ b/model/foldermodel.cpp @@ -5,6 +5,7 @@ * Copyright (C) 2011 Marco Martin * * Copyright (C) 2014 by Eike Hein * * Copyright (C) 2021 Reven Martin * + * Copyright (C) 2021 Reion Wong * * * * 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 * @@ -24,13 +25,20 @@ #include "foldermodel.h" #include "dirlister.h" +#include "window.h" -#include "../dialogs/propertiesdialog.h" +#include "../dialogs/filepropertiesdialog.h" #include "../dialogs/createfolderdialog.h" +#include "../dialogs/openwithdialog.h" #include "../helper/datehelper.h" +#include "../helper/filelauncher.h" +#include "../helper/fm.h" + +#include "../cio/cfilesizejob.h" // Qt +#include #include #include #include @@ -40,14 +48,19 @@ #include #include #include +#include #include #include #include #include #include +#include +#include +#include // Qt Quick #include +#include // KIO #include @@ -63,30 +76,101 @@ #include #include #include -#include -#include + +static bool isDropBetweenSharedViews(const QList &urls, const QUrl &folderUrl) +{ + for (const auto &url : urls) { + if (folderUrl.adjusted(QUrl::StripTrailingSlash) != url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash)) { + return false; + } + } + return true; +} FolderModel::FolderModel(QObject *parent) : QSortFilterProxyModel(parent) , m_dirWatch(nullptr) + , m_status(None) , m_sortMode(0) , m_sortDesc(false) , m_sortDirsFirst(true) + , m_showHiddenFiles(false) + , m_filterMode(NoFilter) + , m_filterPatternMatchAll(true) , m_complete(false) , m_isDesktop(false) + , m_selectedItemSize("") , m_actionCollection(this) , m_dragInProgress(false) + , m_dropTargetPositionsCleanup(new QTimer(this)) , m_viewAdapter(nullptr) -{ - DirLister *dirLister = new DirLister(this); - dirLister->setDelayedMimeTypes(true); - dirLister->setAutoErrorHandlingEnabled(false, nullptr); + , m_mimeAppManager(MimeAppManager::self()) + , m_sizeJob(nullptr) + , m_currentIndex(-1) + , m_updateNeedSelectTimer(new QTimer(this)) +{ + QSettings settings("cutefishos", qApp->applicationName()); + m_showHiddenFiles = settings.value("showHiddenFiles", false).toBool(); + + m_updateNeedSelectTimer->setSingleShot(true); + m_updateNeedSelectTimer->setInterval(50); + connect(m_updateNeedSelectTimer, &QTimer::timeout, this, &FolderModel::updateNeedSelectUrls); + + m_dirLister = new DirLister(this); + m_dirLister->setDelayedMimeTypes(true); + m_dirLister->setAutoErrorHandlingEnabled(false, nullptr); + m_dirLister->setAutoUpdate(true); + m_dirLister->setShowingDotFiles(m_showHiddenFiles); + // connect(dirLister, &DirLister::error, this, &FolderModel::notification); + + connect(m_dirLister, &KCoreDirLister::started, this, std::bind(&FolderModel::setStatus, this, Status::Listing)); + + void (KCoreDirLister::*myCompletedSignal)() = &KCoreDirLister::completed; + QObject::connect(m_dirLister, myCompletedSignal, this, [this] { + setStatus(Status::Ready); + emit listingCompleted(); + }); + + void (KCoreDirLister::*myCanceledSignal)() = &KCoreDirLister::canceled; + QObject::connect(m_dirLister, myCanceledSignal, this, [this] { + setStatus(Status::Canceled); + emit listingCanceled(); + }); m_dirModel = new KDirModel(this); - m_dirModel->setDirLister(dirLister); + m_dirModel->setDirLister(m_dirLister); m_dirModel->setDropsAllowed(KDirModel::DropOnDirectory | KDirModel::DropOnLocalExecutable); m_dirModel->moveToThread(qApp->thread()); + // If we have dropped items queued for moving, go unsorted now. + connect(this, &QAbstractItemModel::rowsAboutToBeInserted, this, [this]() { + if (!m_dropTargetPositions.isEmpty()) { + setSortMode(-1); + } + }); + + // Position dropped items at the desired target position. + connect(this, &QAbstractItemModel::rowsInserted, this, &FolderModel::onRowsInserted); + + /* + * Dropped files may not actually show up as new files, e.g. when we overwrite + * an existing file. Or files that fail to be listed by the dirLister, or... + * To ensure we don't grow the map indefinitely, clean it up periodically. + * The cleanup timer is (re)started whenever we modify the map. We use a quite + * high interval of 10s. This should ensure, that we don't accidentally wipe + * the mapping when we actually still want to use it. Since the time between + * adding an entry in the map and it showing up in the model should be + * small, this should rarely, if ever happen. + */ + m_dropTargetPositionsCleanup->setInterval(10000); + m_dropTargetPositionsCleanup->setSingleShot(true); + connect(m_dropTargetPositionsCleanup, &QTimer::timeout, this, [this]() { + if (!m_dropTargetPositions.isEmpty()) { + qDebug() << "clearing drop target positions after timeout:" << m_dropTargetPositions; + m_dropTargetPositions.clear(); + } + }); + m_selectionModel = new QItemSelectionModel(this, this); connect(m_selectionModel, &QItemSelectionModel::selectionChanged, this, &FolderModel::selectionChanged); @@ -132,12 +216,16 @@ QHash FolderModel::staticRoleNames() roleNames[BlankRole] = "blank"; roleNames[SelectedRole] = "selected"; roleNames[IsDirRole] = "isDir"; + roleNames[IsHiddenRole] = "isHidden"; + roleNames[IsLinkRole] = "isLink"; roleNames[UrlRole] = "url"; + roleNames[DisplayNameRole] = "displayName"; roleNames[FileNameRole] = "fileName"; roleNames[FileSizeRole] = "fileSize"; roleNames[IconNameRole] = "iconName"; roleNames[ThumbnailRole] = "thumbnail"; roleNames[ModifiedRole] = "modified"; + roleNames[IsDesktopFileRole] = "desktopFile"; return roleNames; } @@ -155,9 +243,31 @@ QVariant FolderModel::data(const QModelIndex &index, int role) const return m_selectionModel->isSelected(index); case UrlRole: return item.url(); + case DisplayNameRole: { + if (item.isDesktopFile()) { + KDesktopFile dfile(item.localPath()); + + if (!dfile.readName().isEmpty()) + return dfile.readName(); + } + + return item.url().fileName(); + } case FileNameRole: { return item.url().fileName(); } + case IsDesktopFileRole: { + return item.isDesktopFile(); + } + case IsDirRole: { + return item.isDir(); + } + case IsHiddenRole: { + return item.isHidden(); + } + case IsLinkRole: { + return item.isLink(); + } case FileSizeRole: { if (item.isDir()) { QDir dir(item.url().toLocalFile()); @@ -196,11 +306,44 @@ QVariant FolderModel::data(const QModelIndex &index, int role) const return QSortFilterProxyModel::data(index, role); } +int FolderModel::indexForKeyboardSearch(const QString &text, int startFromIndex) const +{ + startFromIndex = qMax(0, startFromIndex); + + for (int i = startFromIndex; i < rowCount(); ++i) { + if (fileItem(i).text().startsWith(text, Qt::CaseInsensitive)) { + return i; + } + } + + for (int i = 0; i < startFromIndex; ++i) { + if (fileItem(i).text().startsWith(text, Qt::CaseInsensitive)) { + return i; + } + } + + return -1; +} + KFileItem FolderModel::itemForIndex(const QModelIndex &index) const { return m_dirModel->itemForIndex(mapToSource(index)); } +QModelIndex FolderModel::indexForUrl(const QUrl &url) const +{ + return m_dirModel->indexForUrl(url); +} + +KFileItem FolderModel::fileItem(int index) const +{ + if (index >= 0 && index < count()) { + return itemForIndex(FolderModel::index(index, 0)); + } + + return KFileItem(); +} + QList FolderModel::selectedUrls() const { const auto indexes = m_selectionModel->selectedIndexes(); @@ -215,6 +358,11 @@ QList FolderModel::selectedUrls() const return urls; } +int FolderModel::currentIndex() const +{ + return m_currentIndex; +} + QString FolderModel::url() const { return m_url; @@ -225,35 +373,44 @@ void FolderModel::setUrl(const QString &url) if (url.isEmpty()) return; - const QUrl &resolvedNewUrl = resolve(url); + bool isTrash = url.startsWith("trash:/"); + QUrl resolvedNewUrl = resolve(url); + QFileInfo info(resolvedNewUrl.toLocalFile()); + + if (!QFile::exists(resolvedNewUrl.toLocalFile()) && !isTrash) { + emit notification(tr("The file or folder %1 does not exist.").arg(url)); + return; + } + + // TODO: selected ? + if (info.isFile() && !isTrash) { + resolvedNewUrl = QUrl::fromLocalFile(info.dir().path()); + } // Refresh this directory. if (url == m_url) { - m_dirModel->dirLister()->updateDirectory(resolvedNewUrl); + refresh(); return; } - m_pathHistory.append(resolvedNewUrl); + setStatus(Status::Listing); + + if (m_pathHistory.isEmpty() || m_pathHistory.last() != resolvedNewUrl) + m_pathHistory.append(resolvedNewUrl); beginResetModel(); - m_url = url; - m_dirModel->dirLister()->openUrl(resolvedNewUrl); + m_url = resolvedNewUrl.toString(QUrl::PreferLocalFile); + m_dirModel->dirLister()->openUrl(isTrash ? QUrl(QStringLiteral("trash:/")) : resolvedNewUrl); clearDragImages(); m_dragIndexes.clear(); endResetModel(); - emit urlChanged(); - emit resolvedUrlChanged(); - - if (m_dirWatch) { - delete m_dirWatch; - m_dirWatch = nullptr; + if (isTrash) { + refresh(); } - if (resolvedNewUrl.isValid()) { - m_dirWatch = new KDirWatch(this); - m_dirWatch->addFile(resolvedNewUrl.toLocalFile() + QLatin1String("/.directory")); - } + emit urlChanged(); + emit resolvedUrlChanged(); } QUrl FolderModel::resolvedUrl() const @@ -328,6 +485,74 @@ void FolderModel::setSortDirsFirst(bool enable) } } +int FolderModel::filterMode() const +{ + return m_filterMode; +} + +void FolderModel::setFilterMode(int filterMode) +{ + if (m_filterMode != (FilterMode)filterMode) { + m_filterMode = (FilterMode)filterMode; + + invalidateFilterIfComplete(); + + emit filterModeChanged(); + } +} + +QStringList FolderModel::filterMimeTypes() const +{ + return m_mimeSet.values(); +} + +void FolderModel::setFilterMimeTypes(const QStringList &mimeList) +{ +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) + const QSet &set = QSet::fromList(mimeList); +#else + const QSet set(mimeList.constBegin(), mimeList.constEnd()); +#endif + + if (m_mimeSet != set) { + m_mimeSet = set; + + invalidateFilterIfComplete(); + + emit filterMimeTypesChanged(); + } +} + +QString FolderModel::filterPattern() const +{ + return m_filterPattern; +} + +void FolderModel::setFilterPattern(const QString &pattern) +{ + if (m_filterPattern == pattern) { + return; + } + + m_filterPattern = pattern; + m_filterPatternMatchAll = (pattern == QLatin1String("*")); + + const QStringList patterns = pattern.split(QLatin1Char(' ')); + m_regExps.clear(); + m_regExps.reserve(patterns.count()); + + foreach (const QString &pattern, patterns) { + QRegExp rx(pattern); + rx.setPatternSyntax(QRegExp::Wildcard); + rx.setCaseSensitivity(Qt::CaseInsensitive); + m_regExps.append(rx); + } + + invalidateFilterIfComplete(); + + emit filterPatternChanged(); +} + QObject *FolderModel::viewAdapter() const { return m_viewAdapter; @@ -504,6 +729,18 @@ void FolderModel::goForward() setUrl(url.toString()); } +void FolderModel::refresh() +{ + m_dirModel->dirLister()->updateDirectory(m_dirModel->dirLister()->url()); +} + +void FolderModel::undo() +{ + if (KIO::FileUndoManager::self()->undoAvailable()) { + KIO::FileUndoManager::self()->undo(); + } +} + bool FolderModel::supportSetAsWallpaper(const QString &mimeType) { if (mimeType == "image/jpeg" || mimeType == "image/png") @@ -567,6 +804,9 @@ void FolderModel::setSelected(int row) return; m_selectionModel->select(index(row, 0), QItemSelectionModel::Select); + m_currentIndex = row; + + emit currentIndexChanged(); } void FolderModel::selectAll() @@ -636,9 +876,51 @@ void FolderModel::unpinSelection() void FolderModel::newFolder() { - CreateFolderDialog *dlg = new CreateFolderDialog; - dlg->setPath(rootItem().url().toString()); - dlg->show(); + QString rootPath = rootItem().url().toString(); + QString baseName = tr("New Folder"); + QString newName = baseName; + + int i = 0; + while (true) { + if (QFile::exists(rootItem().url().toLocalFile() + "/" + newName)) { + ++i; + newName = QString("%1%2").arg(baseName).arg(QString::number(i)); + } else { + break; + } + } + + m_newDocumentUrl = QUrl(rootItem().url().toString() + "/" + newName); + + auto job = KIO::mkdir(QUrl(rootItem().url().toString() + "/" + newName)); + job->start(); +} + +void FolderModel::newTextFile() +{ + QString rootPath = rootItem().url().toString(); + QString baseName = tr("New Text"); + QString newName = baseName; + + int i = 0; + while (true) { + if (QFile::exists(rootItem().url().toLocalFile() + "/" + newName)) { + ++i; + newName = QString("%1%2").arg(baseName).arg(QString::number(i)); + } else { + break; + } + } + + m_newDocumentUrl = QUrl(rootItem().url().toString() + "/" + newName); + + QFile file(m_newDocumentUrl.toLocalFile()); + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QTextStream stream(&file); + stream << "\n"; + ::chmod(m_newDocumentUrl.toLocalFile().toStdString().c_str(), 0700); + file.close(); + } } void FolderModel::rename(int row, const QString &name) @@ -671,6 +953,7 @@ void FolderModel::paste() // Update paste action if (QAction *paste = m_actionCollection.action(QStringLiteral("paste"))) { QList urls = KUrlMimeData::urlsFromMimeData(mimeData); + const QString ¤tUrl = rootItem().url().toLocalFile(); if (!urls.isEmpty()) { if (!rootItem().isNull()) { @@ -678,11 +961,31 @@ void FolderModel::paste() } } + if (enable && !urls.isEmpty()) { + for (QUrl url : urls) { + m_needSelectUrls.append(QUrl::fromLocalFile(QString("%1/%2").arg(currentUrl) + .arg(url.fileName()))); + } + } + paste->setEnabled(enable); } if (enable) { - KIO::paste(mimeData, m_dirModel->dirLister()->url()); + // Copy a new MimeData. + QMimeData *data = new QMimeData; + for (QString mimetype : mimeData->formats()) { + data->setData(mimetype, mimeData->data(mimetype)); + } + + KIO::Job *job = KIO::paste(data, m_dirModel->dirLister()->url()); + // connect(job, &KIO::Job::finished, this, &FolderModel::delayUpdateNeedSelectUrls); + job->start(); + + // Clear system clipboard. + if (mimeData->hasFormat("application/x-cutefish-cutselection")) { + QApplication::clipboard()->clear(); + } } } @@ -696,7 +999,10 @@ void FolderModel::cut() return; QMimeData *mimeData = QSortFilterProxyModel::mimeData(m_selectionModel->selectedIndexes()); - KIO::setClipboardDataCut(mimeData, true); + + mimeData->setData("application/x-kde-cutselection", QByteArray("1")); + mimeData->setData("application/x-cutefish-cutselection", QByteArray("1")); + QApplication::clipboard()->setMimeData(mimeData); } @@ -705,6 +1011,9 @@ void FolderModel::openSelected() if (!m_selectionModel->hasSelection()) return; + if (resolvedUrl().scheme() == QLatin1String("trash")) + return; + const QList urls = selectedUrls(); if (!m_isDesktop) { if (urls.size() == 1 && KFileItem(urls.first()).isDir()) { @@ -714,10 +1023,62 @@ void FolderModel::openSelected() } for (const QUrl &url : urls) { - (void)new KRun(url, nullptr); + KFileItem item(url); + QString mimeType = item.mimetype(); + + // Desktop file. + if (mimeType == "application/x-desktop") { + FileLauncher::self()->launchApp(url.toLocalFile(), ""); + continue; + } + + // runnable + if (mimeType == "application/x-executable" || + mimeType == "application/x-sharedlib" || + mimeType == "application/x-iso9660-appimage" || + mimeType == "application/vnd.appimage") { + QFileInfo fileInfo(url.toLocalFile()); + if (!fileInfo.isExecutable()) { + QFile file(url.toLocalFile()); + file.setPermissions(file.permissions() | QFile::ExeOwner | QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther); + } + + FileLauncher::self()->launchExecutable(url.toLocalFile()); + + continue; + } + + QString defaultAppDesktopFile = m_mimeAppManager->getDefaultAppByMimeType(item.currentMimeType()); + + // If no default application is found, + // look for the first one of the frequently used applications. + if (defaultAppDesktopFile.isEmpty()) { + QStringList recommendApps = m_mimeAppManager->getRecommendedAppsByMimeType(item.currentMimeType()); + if (recommendApps.count() > 0) { + defaultAppDesktopFile = recommendApps.first(); + } + } + + if (!defaultAppDesktopFile.isEmpty()) { + FileLauncher::self()->launchApp(defaultAppDesktopFile, url.toLocalFile()); + continue; + } + + QDesktopServices::openUrl(url); } } +void FolderModel::showOpenWithDialog() +{ + if (!m_selectionModel->hasSelection()) + return; + + const QList urls = selectedUrls(); + + OpenWithDialog *dlg = new OpenWithDialog(urls.first()); + dlg->show(); +} + void FolderModel::deleteSelected() { if (!m_selectionModel->hasSelection()) { @@ -730,13 +1091,8 @@ void FolderModel::deleteSelected() } } - const QList urls = selectedUrls(); - KIO::JobUiDelegate uiDelegate; - - if (uiDelegate.askDeleteConfirmation(urls, KIO::JobUiDelegate::Delete, KIO::JobUiDelegate::DefaultConfirmation)) { - KIO::Job *job = KIO::del(urls); - job->uiDelegate()->setAutoErrorHandlingEnabled(true); - } + KIO::DeleteJob *job = KIO::del(selectedUrls()); + job->start(); } void FolderModel::moveSelectedToTrash() @@ -771,7 +1127,7 @@ void FolderModel::keyDeletePress() if (!m_selectionModel->hasSelection()) return; - resolvedUrl().scheme() == "trash" ? deleteSelected() : moveSelectedToTrash(); + resolvedUrl().scheme() == "trash" ? openDeleteDialog() : moveSelectedToTrash(); } void FolderModel::setDragHotSpotScrollOffset(int x, int y) @@ -813,6 +1169,77 @@ void FolderModel::dragSelected(int x, int y) QMetaObject::invokeMethod(this, "dragSelectedInternal", Qt::QueuedConnection, Q_ARG(int, x), Q_ARG(int, y)); } +void FolderModel::drop(QQuickItem *target, QObject *dropEvent, int row) +{ + QMimeData *mimeData = qobject_cast(dropEvent->property("mimeData").value()); + + if (!mimeData) { + return; + } + + QModelIndex idx; + KFileItem item; + + if (row > -1 && row < rowCount()) { + idx = index(row, 0); + item = itemForIndex(idx); + } + + QUrl dropTargetUrl; + + // So we get to run mostLocalUrl() over the current URL. + if (item.isNull()) { + item = rootItem(); + } + + if (item.isNull()) { + dropTargetUrl = m_dirModel->dirLister()->url(); + } else { + dropTargetUrl = item.mostLocalUrl(); + } + + auto dropTargetFolderUrl = dropTargetUrl; + if (dropTargetFolderUrl.fileName() == QLatin1Char('.')) { + // the target URL for desktop:/ is e.g. 'file://home/user/Desktop/.' + dropTargetFolderUrl = dropTargetFolderUrl.adjusted(QUrl::RemoveFilename); + } + + const int x = dropEvent->property("x").toInt(); + const int y = dropEvent->property("y").toInt(); + const QPoint dropPos = {x, y}; + + if (m_dragInProgress && row == -1) { + if (mimeData->urls().isEmpty()) + return; + + setSortMode(-1); + + for (const auto &url : mimeData->urls()) { + m_dropTargetPositions.insert(url.fileName(), dropPos); + } + + emit move(x, y, mimeData->urls()); + + return; + } + + + if (idx.isValid() && !(flags(idx) & Qt::ItemIsDropEnabled)) { + return; + } + + if (!isDropBetweenSharedViews(mimeData->urls(), dropTargetFolderUrl)) { + KIO::Job *job = KIO::move(mimeData->urls(), dropTargetUrl, KIO::HideProgressInfo); + job->start(); + + // Add select + for (QUrl url : mimeData->urls()) { + m_needSelectUrls.append(QUrl::fromLocalFile(QString("%1/%2").arg(rootItem().url().toLocalFile()) + .arg(url.fileName()))); + } + } +} + void FolderModel::setWallpaperSelected() { if (!m_selectionModel) @@ -823,8 +1250,8 @@ void FolderModel::setWallpaperSelected() if (!url.isLocalFile()) return; - QDBusInterface iface("org.cutefish.Settings", "/Theme", - "org.cutefish.Theme", + QDBusInterface iface("com.cutefish.Settings", "/Theme", + "com.cutefish.Theme", QDBusConnection::sessionBus(), nullptr); if (iface.isValid()) iface.call("setWallpaper", url.toLocalFile()); @@ -837,6 +1264,7 @@ void FolderModel::openContextMenu(QQuickItem *visualParent, Qt::KeyboardModifier updateActions(); const QModelIndexList indexes = m_selectionModel->selectedIndexes(); + const bool isTrash = (resolvedUrl().scheme() == QLatin1String("trash")); QMenu *menu = new QMenu; // Open folder menu. @@ -845,6 +1273,13 @@ void FolderModel::openContextMenu(QQuickItem *visualParent, Qt::KeyboardModifier connect(selectAll, &QAction::triggered, this, &FolderModel::selectAll); menu->addAction(m_actionCollection.action("newFolder")); + + if (!isTrash) { + QMenu *newMenu = new QMenu(tr("New Documents")); + newMenu->addAction(m_actionCollection.action("newTextFile")); + menu->addMenu(newMenu); + } + menu->addSeparator(); menu->addAction(m_actionCollection.action("paste")); menu->addAction(selectAll); @@ -857,12 +1292,23 @@ void FolderModel::openContextMenu(QQuickItem *visualParent, Qt::KeyboardModifier menu->addAction(m_actionCollection.action("changeBackground")); } + menu->addSeparator(); + menu->addAction(m_actionCollection.action("showHidden")); + menu->addSeparator(); menu->addAction(m_actionCollection.action("emptyTrash")); menu->addAction(m_actionCollection.action("properties")); } else { // Open the items menu. + + // Trash items + menu->addAction(m_actionCollection.action("restore")); + menu->addAction(m_actionCollection.action("open")); + menu->addAction(m_actionCollection.action("openInNewWindow")); + + menu->addAction(m_actionCollection.action("openWith")); + menu->addSeparator(); menu->addAction(m_actionCollection.action("cut")); menu->addAction(m_actionCollection.action("copy")); menu->addAction(m_actionCollection.action("trash")); @@ -900,7 +1346,8 @@ void FolderModel::openPropertiesDialog() const QModelIndexList indexes = m_selectionModel->selectedIndexes(); if (indexes.isEmpty()) { - PropertiesDialog::showDialog(QUrl::fromLocalFile(url())); + FilePropertiesDialog *dlg = new FilePropertiesDialog(QUrl::fromLocalFile(url())); + dlg->show(); return; } @@ -913,7 +1360,8 @@ void FolderModel::openPropertiesDialog() } } - PropertiesDialog::showDialog(items); + FilePropertiesDialog *dlg = new FilePropertiesDialog(items); + dlg->show(); } void FolderModel::openInTerminal() @@ -928,7 +1376,7 @@ void FolderModel::openInTerminal() url = rootItem().url().toLocalFile(); } - KToolInvocation::invokeTerminal(QString(), url); + m_mimeAppManager->launchTerminal(url); } void FolderModel::openChangeWallpaperDialog() @@ -936,6 +1384,80 @@ void FolderModel::openChangeWallpaperDialog() QProcess::startDetached("cutefish-settings", QStringList() << "-m" << "background"); } +void FolderModel::openDeleteDialog() +{ + Window *w = new Window; + w->load(QUrl("qrc:/qml/Dialogs/DeleteDialog.qml")); + w->rootContext()->setContextProperty("model", this); +} + +void FolderModel::openInNewWindow(const QString &url) +{ + if (!url.isEmpty()) { + QProcess::startDetached("cutefish-filemanager", QStringList() << url); + return; + } + + // url 为空则打开已选择的 items. + if (!m_selectionModel->hasSelection()) + return; + + for (const QModelIndex &index : m_selectionModel->selectedIndexes()) { + KFileItem item = itemForIndex(index); + if (item.isDir()) { + QProcess::startDetached("cutefish-filemanager", QStringList() << item.url().toLocalFile()); + } + } +} + +void FolderModel::updateSelectedItemsSize() +{ +} + +void FolderModel::keyboardSearch(const QString &text) +{ + if (rowCount() == 0) + return; + + int index; + int currentIndex = -1; + + if (m_selectionModel->hasSelection()) { + currentIndex = m_selectionModel->selectedIndexes().first().row(); + } + + index = indexForKeyboardSearch(text, (currentIndex + 1) % rowCount()); + + if (index < 0 || currentIndex == index) + return; + + if (index >= 0) { + clearSelection(); + setSelected(index); + + emit scrollToItem(index); + } +} + +void FolderModel::clearPixmapCache() +{ + QPixmapCache::clear(); +} + +void FolderModel::restoreFromTrash() +{ + if (!m_selectionModel->hasSelection()) + return; + + if (QAction *action = m_actionCollection.action("restore")) + if (!action->isVisible()) + return; + + + KIO::RestoreJob *job = KIO::restoreFromTrash(selectedUrls()); + job->start(); +} + void FolderModel::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { QModelIndexList indices = selected.indexes(); @@ -959,6 +1481,53 @@ void FolderModel::selectionChanged(const QItemSelection &selected, const QItemSe updateActions(); emit selectionCountChanged(); + + // The desktop does not need to calculate the selected file size. + if (m_isDesktop) + return; + + // Start calculating file size. + if (m_sizeJob == nullptr) { + m_sizeJob = new CFileSizeJob; + + connect(m_sizeJob, &CFileSizeJob::sizeChanged, this, [=] { + m_selectedItemSize = KIO::convertSize(m_sizeJob->totalSize()); + if (!m_selectionModel->hasSelection()) + m_selectedItemSize = ""; + emit selectedItemSizeChanged(); + }); + + connect(m_sizeJob, &CFileSizeJob::result, this, [=] { + m_selectedItemSize = KIO::convertSize(m_sizeJob->totalSize()); + if (!m_selectionModel->hasSelection()) + m_selectedItemSize = ""; + emit selectedItemSizeChanged(); + }); + } + + m_sizeJob->stop(); + + if (!m_selectionModel->hasSelection()) { + m_sizeJob->blockSignals(true); + m_selectedItemSize = ""; + emit selectedItemSizeChanged(); + } else { + bool fileExists = false; + + for (const QModelIndex &index : m_selectionModel->selectedIndexes()) { + if (itemForIndex(index).isFile()) { + fileExists = true; + break; + } + } + + // Reion: The size label at the bottom needs to be updated + // only if you select the include file. + if (fileExists) { + m_sizeJob->blockSignals(false); + m_sizeJob->start(selectedUrls()); + } + } } void FolderModel::dragSelectedInternal(int x, int y) @@ -1009,6 +1578,73 @@ void FolderModel::dragSelectedInternal(int x, int y) } } +void FolderModel::onRowsInserted(const QModelIndex &parent, int first, int last) +{ + if (m_updateNeedSelectTimer->isActive()) { + m_updateNeedSelectTimer->stop(); + } + + QModelIndex changeIdx; + + for (int i = first; i <= last; ++i) { + const auto idx = index(i, 0, parent); + const auto url = itemForIndex(idx).url(); + auto it = m_dropTargetPositions.find(url.fileName()); + if (it != m_dropTargetPositions.end()) { + const auto pos = it.value(); + m_dropTargetPositions.erase(it); + Q_EMIT move(pos.x(), pos.y(), {url}); + } + + if (url == m_newDocumentUrl) { + changeIdx = idx; + m_newDocumentUrl.clear(); + } + } + + // 新建文件夹需要先选择后再发送请求 + QTimer::singleShot(m_updateNeedSelectTimer->interval() + 10, this, [=] { + if (changeIdx.isValid()) { + setSelected(changeIdx.row()); + emit requestRename(); + } + }); + + m_updateNeedSelectTimer->start(); +} + +void FolderModel::delayUpdateNeedSelectUrls() +{ + QTimer::singleShot(100, this, &FolderModel::updateNeedSelectUrls); +} + +void FolderModel::updateNeedSelectUrls() +{ + QModelIndexList needSelectList; + + for (const QUrl &url : m_needSelectUrls) { + const QModelIndex &idx = indexForUrl(url); + + if (!idx.isValid()) + continue; + + const QModelIndex &sourceIdx = mapFromSource(idx); + + needSelectList.append(sourceIdx); + } + + m_needSelectUrls.clear(); + + // If the selected item already exists, clear it immediately. + if (!needSelectList.isEmpty()) { + clearSelection(); + } + + for (const QModelIndex &idx : needSelectList) { + setSelected(idx.row()); + } +} + bool FolderModel::isSupportThumbnails(const QString &mimeType) const { const QStringList supportsMimetypes = {"image/bmp", "image/png", "image/gif", "image/jpeg", "image/web", @@ -1021,6 +1657,78 @@ bool FolderModel::isSupportThumbnails(const QString &mimeType) const return false; } +bool FolderModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + const KDirModel *dirModel = static_cast(sourceModel()); + const KFileItem item = dirModel->itemForIndex(dirModel->index(sourceRow, KDirModel::Name, sourceParent)); + + if (m_filterMode == NoFilter) { + return true; + } + + if (m_filterMode == FilterShowMatches) { + return (matchPattern(item) && matchMimeType(item)); + } else { + return !(matchPattern(item) && matchMimeType(item)); + } +} + +bool FolderModel::matchMimeType(const KFileItem &item) const +{ + if (m_mimeSet.isEmpty()) { + return false; + } + + if (m_mimeSet.contains(QLatin1String("all/all")) || m_mimeSet.contains(QLatin1String("all/allfiles"))) { + return true; + } + + const QString mimeType = item.determineMimeType().name(); + return m_mimeSet.contains(mimeType); +} + +bool FolderModel::matchPattern(const KFileItem &item) const +{ + if (m_filterPatternMatchAll) { + return true; + } + + const QString name = item.name(); + QListIterator i(m_regExps); + while (i.hasNext()) { + if (i.next().exactMatch(name)) { + return true; + } + } + + return false; +} + +bool FolderModel::showHiddenFiles() const +{ + return m_showHiddenFiles; +} + +void FolderModel::setShowHiddenFiles(bool showHiddenFiles) +{ + if (m_showHiddenFiles != showHiddenFiles) { + m_showHiddenFiles = showHiddenFiles; + + m_dirLister->setShowingDotFiles(m_showHiddenFiles); + m_dirLister->emitChanges(); + + QSettings settings("cutefishos", qApp->applicationName()); + settings.setValue("showHiddenFiles", m_showHiddenFiles); + + emit showHiddenFilesChanged(); + } +} + +QString FolderModel::selectedItemSize() const +{ + return m_selectedItemSize; +} + bool FolderModel::isDesktop() const { return m_isDesktop; @@ -1056,6 +1764,9 @@ void FolderModel::createActions() QAction *open = new QAction(tr("Open"), this); connect(open, &QAction::triggered, this, &FolderModel::openSelected); + QAction *openWith = new QAction(tr("Open with"), this); + connect(openWith, &QAction::triggered, this, &FolderModel::showOpenWithDialog); + QAction *cut = new QAction(tr("Cut"), this); connect(cut, &QAction::triggered, this, &FolderModel::cut); @@ -1068,6 +1779,11 @@ void FolderModel::createActions() QAction *newFolder = new QAction(tr("New Folder"), this); connect(newFolder, &QAction::triggered, this, &FolderModel::newFolder); + QMenu *newDocuments = new QMenu(tr("New Documents")); + QAction *newTextFile = new QAction(tr("New Text"), this); + connect(newTextFile, &QAction::triggered, this, &FolderModel::newTextFile); + newDocuments->addAction(newTextFile); + QAction *trash = new QAction(tr("Move To Trash"), this); connect(trash, &QAction::triggered, this, &FolderModel::moveSelectedToTrash); @@ -1075,7 +1791,7 @@ void FolderModel::createActions() connect(emptyTrash, &QAction::triggered, this, &FolderModel::emptyTrash); QAction *del = new QAction(tr("Delete"), this); - connect(del, &QAction::triggered, this, &FolderModel::deleteSelected); + connect(del, &QAction::triggered, this, &FolderModel::openDeleteDialog); QAction *rename = new QAction(tr("Rename"), this); connect(rename, &QAction::triggered, this, &FolderModel::requestRename); @@ -1092,11 +1808,24 @@ void FolderModel::createActions() QAction *changeBackground = new QAction(tr("Change background"), this); QObject::connect(changeBackground, &QAction::triggered, this, &FolderModel::openChangeWallpaperDialog); + QAction *restore = new QAction(tr("Restore"), this); + QObject::connect(restore, &QAction::triggered, this, &FolderModel::restoreFromTrash); + + QAction *showHidden = new QAction(tr("Show hidden files"), this); + QObject::connect(showHidden, &QAction::triggered, this, [=] { + setShowHiddenFiles(!m_showHiddenFiles); + }); + + QAction *openInNewWindow = new QAction(tr("Open in new window"), this); + QObject::connect(openInNewWindow, &QAction::triggered, this, [=] { this->openInNewWindow(); }); + m_actionCollection.addAction(QStringLiteral("open"), open); + m_actionCollection.addAction(QStringLiteral("openWith"), openWith); m_actionCollection.addAction(QStringLiteral("cut"), cut); m_actionCollection.addAction(QStringLiteral("copy"), copy); m_actionCollection.addAction(QStringLiteral("paste"), paste); m_actionCollection.addAction(QStringLiteral("newFolder"), newFolder); + m_actionCollection.addAction(QStringLiteral("newTextFile"), newTextFile); m_actionCollection.addAction(QStringLiteral("trash"), trash); m_actionCollection.addAction(QStringLiteral("emptyTrash"), emptyTrash); m_actionCollection.addAction(QStringLiteral("del"), del); @@ -1105,6 +1834,9 @@ void FolderModel::createActions() m_actionCollection.addAction(QStringLiteral("wallpaper"), wallpaper); m_actionCollection.addAction(QStringLiteral("properties"), properties); m_actionCollection.addAction(QStringLiteral("changeBackground"), changeBackground); + m_actionCollection.addAction(QStringLiteral("restore"), restore); + m_actionCollection.addAction(QStringLiteral("showHidden"), showHidden); + m_actionCollection.addAction(QStringLiteral("openInNewWindow"), openInNewWindow); } void FolderModel::updateActions() @@ -1115,6 +1847,7 @@ void FolderModel::updateActions() QList urls; bool hasRemoteFiles = false; bool isTrashLink = false; + bool hasDir = false; const bool isTrash = (resolvedUrl().scheme() == QLatin1String("trash")); if (indexes.isEmpty()) { @@ -1129,6 +1862,9 @@ void FolderModel::updateActions() items.append(item); urls.append(item.url()); } + + if (item.isDir()) + hasDir = true; } } @@ -1141,11 +1877,37 @@ void FolderModel::updateActions() } } + if (QAction *openAction = m_actionCollection.action(QStringLiteral("open"))) { + openAction->setVisible(!isTrash); + } + + if (QAction *copyAction = m_actionCollection.action(QStringLiteral("copy"))) { + copyAction->setVisible(!isTrash); + } + + if (QAction *cutAction = m_actionCollection.action(QStringLiteral("cut"))) { + cutAction->setVisible(!isTrash); + cutAction->setEnabled(rootItem().isWritable()); + } + + if (QAction *restoreAction = m_actionCollection.action(QStringLiteral("restore"))) { + restoreAction->setVisible(items.count() >= 1 && isTrash); + } + + if (QAction *openWith = m_actionCollection.action(QStringLiteral("openWith"))) { + openWith->setVisible(items.count() == 1 && !isTrash); + } + if (QAction *newFolder = m_actionCollection.action(QStringLiteral("newFolder"))) { newFolder->setVisible(!isTrash); newFolder->setEnabled(rootItem().isWritable()); } + if (QAction *newTextFile = m_actionCollection.action(QStringLiteral("newTextFile"))) { + newTextFile->setVisible(!isTrash); + newTextFile->setEnabled(rootItem().isWritable()); + } + if (QAction *paste = m_actionCollection.action(QStringLiteral("paste"))) { bool enable = false; @@ -1159,11 +1921,12 @@ void FolderModel::updateActions() } paste->setEnabled(enable); + paste->setVisible(!isTrash); } if (QAction *rename = m_actionCollection.action(QStringLiteral("rename"))) { rename->setEnabled(itemProperties.supportsMoving()); - rename->setVisible(!isTrash); + rename->setVisible(!isTrash && !Fm::isFixedFolder(items.first().url())); } if (QAction *trash = m_actionCollection.action("trash")) { @@ -1172,7 +1935,7 @@ void FolderModel::updateActions() } if (QAction *emptyTrash = m_actionCollection.action("emptyTrash")) { - emptyTrash->setVisible(isTrash); + emptyTrash->setVisible(isTrash && rowCount() > 0); } if (QAction *del = m_actionCollection.action(QStringLiteral("del"))) { @@ -1180,16 +1943,28 @@ void FolderModel::updateActions() } if (QAction *terminal = m_actionCollection.action("terminal")) { - terminal->setVisible(items.size() == 1 && items.first().isDir()); + terminal->setVisible(items.size() == 1 && items.first().isDir() && !isTrash); } if (QAction *terminal = m_actionCollection.action("wallpaper")) { - terminal->setVisible(items.size() == 1 && supportSetAsWallpaper(items.first().mimetype())); + terminal->setVisible(items.size() == 1 && + !isTrash && + supportSetAsWallpaper(items.first().mimetype())); } if (QAction *properties = m_actionCollection.action("properties")) { properties->setVisible(!isTrash); } + + if (QAction *showHidden = m_actionCollection.action("showHidden")) { + showHidden->setVisible(!isTrash); + showHidden->setCheckable(true); + showHidden->setChecked(m_showHiddenFiles); + } + + if (QAction *openInNewWindow = m_actionCollection.action("openInNewWindow")) { + openInNewWindow->setVisible(hasDir && !isTrash); + } } void FolderModel::addDragImage(QDrag *drag, int x, int y) diff --git a/model/foldermodel.h b/model/foldermodel.h index b892699..351a827 100644 --- a/model/foldermodel.h +++ b/model/foldermodel.h @@ -27,11 +27,13 @@ #include "../widgets/itemviewadapter.h" #include "../helper/pathhistory.h" +#include "../mimetype/mimeappmanager.h" #include #include #include #include +#include #include #include @@ -39,31 +41,43 @@ #include class QDrag; +class CFileSizeJob; class FolderModel : public QSortFilterProxyModel, public QQmlParserStatus { Q_OBJECT Q_INTERFACES(QQmlParserStatus) Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged) Q_PROPERTY(QUrl resolvedUrl READ resolvedUrl NOTIFY resolvedUrlChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(int sortMode READ sortMode WRITE setSortMode NOTIFY sortModeChanged) Q_PROPERTY(bool sortDirsFirst READ sortDirsFirst WRITE setSortDirsFirst NOTIFY sortDirsFirstChanged) Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged) Q_PROPERTY(QObject *viewAdapter READ viewAdapter WRITE setViewAdapter NOTIFY viewAdapterChanged) Q_PROPERTY(bool isDesktop READ isDesktop WRITE setIsDesktop NOTIFY isDesktopChanged) Q_PROPERTY(int selectionCount READ selectionCount NOTIFY selectionCountChanged) + Q_PROPERTY(int filterMode READ filterMode WRITE setFilterMode NOTIFY filterModeChanged) + Q_PROPERTY(QString filterPattern READ filterPattern WRITE setFilterPattern NOTIFY filterPatternChanged) Q_PROPERTY(int count READ count NOTIFY countChanged) + Q_PROPERTY(QStringList filterMimeTypes READ filterMimeTypes WRITE setFilterMimeTypes NOTIFY filterMimeTypesChanged) + Q_PROPERTY(QString selectedItemSize READ selectedItemSize NOTIFY selectedItemSizeChanged) + Q_PROPERTY(bool showHiddenFiles READ showHiddenFiles WRITE setShowHiddenFiles NOTIFY showHiddenFilesChanged) + Q_PROPERTY(int currentIndex READ currentIndex NOTIFY currentIndexChanged) public: enum DataRole { BlankRole = Qt::UserRole + 1, SelectedRole, IsDirRole, + IsHiddenRole, + IsLinkRole, UrlRole, + DisplayNameRole, FileNameRole, FileSizeRole, IconNameRole, ThumbnailRole, - ModifiedRole + ModifiedRole, + IsDesktopFileRole }; enum FilterMode { @@ -98,10 +112,16 @@ class FolderModel : public QSortFilterProxyModel, public QQmlParserStatus static QHash staticRoleNames(); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + int indexForKeyboardSearch(const QString &text, int startFromIndex = 0) const; KFileItem itemForIndex(const QModelIndex &index) const; + QModelIndex indexForUrl(const QUrl &url) const; + + KFileItem fileItem(int index) const; QList selectedUrls() const; + int currentIndex() const; + QString url() const; void setUrl(const QString &url); @@ -117,6 +137,15 @@ class FolderModel : public QSortFilterProxyModel, public QQmlParserStatus bool sortDirsFirst() const; void setSortDirsFirst(bool enable); + int filterMode() const; + void setFilterMode(int filterMode); + + QStringList filterMimeTypes() const; + void setFilterMimeTypes(const QStringList &mimeList); + + QString filterPattern() const; + void setFilterPattern(const QString &pattern); + QObject *viewAdapter() const; void setViewAdapter(QObject *adapter); @@ -140,6 +169,8 @@ class FolderModel : public QSortFilterProxyModel, public QQmlParserStatus Q_INVOKABLE void up(); Q_INVOKABLE void goBack(); Q_INVOKABLE void goForward(); + Q_INVOKABLE void refresh(); + Q_INVOKABLE void undo(); Q_INVOKABLE bool supportSetAsWallpaper(const QString &mimeType); Q_INVOKABLE int fileExtensionBoundary(int row); @@ -157,11 +188,13 @@ class FolderModel : public QSortFilterProxyModel, public QQmlParserStatus Q_INVOKABLE void unpinSelection(); Q_INVOKABLE void newFolder(); + Q_INVOKABLE void newTextFile(); Q_INVOKABLE void rename(int row, const QString &name); Q_INVOKABLE void copy(); Q_INVOKABLE void paste(); Q_INVOKABLE void cut(); Q_INVOKABLE void openSelected(); + Q_INVOKABLE void showOpenWithDialog(); Q_INVOKABLE void deleteSelected(); Q_INVOKABLE void moveSelectedToTrash(); Q_INVOKABLE void emptyTrash(); @@ -171,6 +204,7 @@ class FolderModel : public QSortFilterProxyModel, public QQmlParserStatus Q_INVOKABLE void addItemDragImage(int row, int x, int y, int width, int height, const QVariant &image); Q_INVOKABLE void clearDragImages(); Q_INVOKABLE void dragSelected(int x, int y); + Q_INVOKABLE void drop(QQuickItem *target, QObject *dropEvent, int row); Q_INVOKABLE void setWallpaperSelected(); @@ -178,27 +212,57 @@ class FolderModel : public QSortFilterProxyModel, public QQmlParserStatus Q_INVOKABLE void openPropertiesDialog(); Q_INVOKABLE void openInTerminal(); Q_INVOKABLE void openChangeWallpaperDialog(); + Q_INVOKABLE void openDeleteDialog(); + Q_INVOKABLE void openInNewWindow(const QString &url = QString()); + + Q_INVOKABLE void updateSelectedItemsSize(); + Q_INVOKABLE void keyboardSearch(const QString &text); + + Q_INVOKABLE void clearPixmapCache(); + + void restoreFromTrash(); bool isDesktop() const; void setIsDesktop(bool isDesktop); + QString selectedItemSize() const; + + bool showHiddenFiles() const; + void setShowHiddenFiles(bool showHiddenFiles); + signals: void urlChanged(); + void listingCompleted() const; + void listingCanceled() const; void resolvedUrlChanged(); void statusChanged(); void sortModeChanged(); void sortDescChanged(); void sortDirsFirstChanged(); + void filterModeChanged(); void requestRename(); void draggingChanged(); void viewAdapterChanged(); void isDesktopChanged(); void selectionCountChanged(); void countChanged(); + void filterPatternChanged(); + void filterMimeTypesChanged(); + void selectedItemSizeChanged(); + void showHiddenFilesChanged(); + void scrollToItem(int index); + + void notification(const QString &message); + void move(int x, int y, QList urls); + + void currentIndexChanged(); private slots: void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); void dragSelectedInternal(int x, int y); + void onRowsInserted(const QModelIndex &parent, int first, int last); + void delayUpdateNeedSelectUrls(); + void updateNeedSelectUrls(); private: void invalidateIfComplete(); @@ -209,33 +273,61 @@ private slots: bool isSupportThumbnails(const QString &mimeType) const; +protected: + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; + bool matchMimeType(const KFileItem &item) const; + bool matchPattern(const KFileItem &item) const; + private: KDirModel *m_dirModel; KDirWatch *m_dirWatch; + KDirLister *m_dirLister; QItemSelectionModel *m_selectionModel; QItemSelection m_pinnedSelection; QString m_url; + QUrl m_newDocumentUrl; + QList m_needSelectUrls; Status m_status; int m_sortMode; bool m_sortDesc; bool m_sortDirsFirst; + bool m_showHiddenFiles; + + FilterMode m_filterMode; + QString m_filterPattern; + bool m_filterPatternMatchAll; + QSet m_mimeSet; + QList m_regExps; + bool m_complete; bool m_isDesktop; bool m_suffixVisible; + QString m_selectedItemSize; + KActionCollection m_actionCollection; QHash m_dragImages; QModelIndexList m_dragIndexes; QPoint m_dragHotSpotScrollOffset; bool m_dragInProgress; + QHash m_dropTargetPositions; + QTimer *m_dropTargetPositionsCleanup; + QPointer m_viewAdapter; // Save path history PathHistory m_pathHistory; + MimeAppManager *m_mimeAppManager; + + CFileSizeJob *m_sizeJob; + + int m_currentIndex; + + QTimer *m_updateNeedSelectTimer; }; #endif // FOLDERMODEL_H diff --git a/model/placesitem.cpp b/model/placesitem.cpp index 8497d8f..262ec04 100644 --- a/model/placesitem.cpp +++ b/model/placesitem.cpp @@ -20,12 +20,17 @@ #include "placesitem.h" #include +#include +#include + PlacesItem::PlacesItem(const QString &displayName, QUrl url, QObject *parent) : QObject(parent) , m_displayName(displayName) , m_url(url) + , m_category("") + , m_isOpticalDisc(false) , m_isAccessible(false) { } @@ -114,7 +119,17 @@ void PlacesItem::updateDeviceInfo(const QString &udi) m_access = m_device.as(); m_iconName = m_device.icon(); m_iconPath = QString("%1.svg").arg(m_iconName); + +#if SOLID_VERSION_MAJOR >= 5 && SOLID_VERSION_MINOR >= 71 m_displayName = m_device.displayName(); +#else + m_displayName = m_device.description(); +#endif + + if (m_device.is()) { + m_isOpticalDisc = true; + emit itemChanged(this); + } if (m_access) { m_url = QUrl::fromLocalFile(m_access->filePath()); @@ -132,3 +147,18 @@ void PlacesItem::onAccessibilityChanged(bool isAccessible) emit itemChanged(this); } + +QString PlacesItem::category() const +{ + return m_category; +} + +void PlacesItem::setCategory(const QString &category) +{ + m_category = category; +} + +bool PlacesItem::isOpticalDisc() const +{ + return m_isOpticalDisc; +} diff --git a/model/placesitem.h b/model/placesitem.h index e19ec00..cd4e515 100644 --- a/model/placesitem.h +++ b/model/placesitem.h @@ -56,6 +56,11 @@ class PlacesItem : public QObject bool isDevice(); bool setupNeeded(); + QString category() const; + void setCategory(const QString &category); + + bool isOpticalDisc() const; + signals: void itemChanged(PlacesItem *); @@ -69,7 +74,9 @@ private slots: QString m_iconPath; QString m_udi; QUrl m_url; + QString m_category; + bool m_isOpticalDisc; bool m_isAccessible; Solid::Device m_device; diff --git a/model/placesmodel.cpp b/model/placesmodel.cpp index e3b7fff..a8cc341 100644 --- a/model/placesmodel.cpp +++ b/model/placesmodel.cpp @@ -37,6 +37,7 @@ PlacesModel::PlacesModel(QObject *parent) if (QDir(homePath).exists()) { PlacesItem *item = new PlacesItem(tr("Home"), QUrl::fromLocalFile(homePath)); + item->setIconName("folder-home"); item->setIconPath("folder-home.svg"); m_items.append(item); } @@ -44,6 +45,7 @@ PlacesModel::PlacesModel(QObject *parent) const QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); if (QDir(desktopPath).exists()) { PlacesItem *item = new PlacesItem(tr("Desktop"), QUrl::fromLocalFile(desktopPath)); + item->setIconName("folder-desktop"); item->setIconPath("folder-desktop.svg"); m_items.append(item); } @@ -51,6 +53,7 @@ PlacesModel::PlacesModel(QObject *parent) const QString documentsPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); if (QDir(documentsPath).exists()) { PlacesItem *item = new PlacesItem(tr("Documents"), QUrl::fromLocalFile(documentsPath)); + item->setIconName("folder-document"); item->setIconPath("folder-document.svg"); m_items.append(item); } @@ -58,6 +61,7 @@ PlacesModel::PlacesModel(QObject *parent) const QString downloadPath = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); if (QDir(downloadPath).exists()) { PlacesItem *item = new PlacesItem(tr("Downloads"), QUrl::fromLocalFile(downloadPath)); + item->setIconName("folder-download"); item->setIconPath("folder-download.svg"); m_items.append(item); } @@ -65,6 +69,7 @@ PlacesModel::PlacesModel(QObject *parent) const QString musicPath = QStandardPaths::writableLocation(QStandardPaths::MusicLocation); if (QDir(musicPath).exists()) { PlacesItem *item = new PlacesItem(tr("Music"), QUrl::fromLocalFile(musicPath)); + item->setIconName("folder-music"); item->setIconPath("folder-music.svg"); m_items.append(item); } @@ -72,6 +77,7 @@ PlacesModel::PlacesModel(QObject *parent) const QString picturePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); if (QDir(picturePath).exists()) { PlacesItem *item = new PlacesItem(tr("Pictures"), QUrl::fromLocalFile(picturePath)); + item->setIconName("folder-picture"); item->setIconPath("folder-picture.svg"); m_items.append(item); } @@ -79,11 +85,13 @@ PlacesModel::PlacesModel(QObject *parent) const QString videoPath = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation); if (QDir(videoPath).exists()) { PlacesItem *item = new PlacesItem(tr("Videos"), QUrl::fromLocalFile(videoPath)); + item->setIconName("folder-video"); item->setIconPath("folder-video.svg"); m_items.append(item); } PlacesItem *trashItem = new PlacesItem(tr("Trash"), QUrl(QStringLiteral("trash:///"))); + trashItem->setIconName("folder-trash"); trashItem->setIconPath("user-trash.svg"); m_items.append(trashItem); @@ -106,8 +114,14 @@ PlacesModel::PlacesModel(QObject *parent) for (const Solid::Device &device : deviceList) { PlacesItem *deviceItem = new PlacesItem; deviceItem->setUdi(device.udi()); + deviceItem->setCategory(tr("Drives")); m_items.append(deviceItem); } + + // Init Signals + for (PlacesItem *item : m_items) { + connect(item, &PlacesItem::itemChanged, this, &PlacesModel::onItemChanged); + } } PlacesModel::~PlacesModel() @@ -118,12 +132,14 @@ QHash PlacesModel::roleNames() const { QHash roleNames; roleNames[PlacesModel::NameRole] = "name"; - roleNames[PlacesModel::IconNameRole] = "icon"; + roleNames[PlacesModel::IconNameRole] = "iconName"; roleNames[PlacesModel::IconPathRole] = "iconPath"; roleNames[PlacesModel::UrlRole] = "url"; roleNames[PlacesModel::PathRole] = "path"; roleNames[PlacesModel::IsDeviceRole] = "isDevice"; + roleNames[PlacesModel::IsOpticalDisc] = "isOpticalDisc"; roleNames[PlacesModel::setupNeededRole] = "setupNeeded"; + roleNames[PlacesModel::CategoryRole] = "category"; return roleNames; } @@ -150,7 +166,7 @@ QVariant PlacesModel::data(const QModelIndex &index, int role) const switch (role) { case PlacesModel::NameRole: - return item->displayName(); + return item->url().toLocalFile() == QDir::rootPath() ? tr("Computer") : item->displayName(); break; case PlacesModel::IconNameRole: return item->iconName(); @@ -167,9 +183,15 @@ QVariant PlacesModel::data(const QModelIndex &index, int role) const case PlacesModel::IsDeviceRole: return item->isDevice(); break; + case PlacesModel::IsOpticalDisc: + return item->isOpticalDisc(); + break; case PlacesModel::setupNeededRole: return item->setupNeeded(); break; + case PlacesModel::CategoryRole: + return item->category(); + break; default: break; } @@ -243,14 +265,31 @@ void PlacesModel::requestEject(const int &index) } } +void PlacesModel::requestTeardown(const int &index) +{ + PlacesItem *item = m_items.at(index); + + if (!item->udi().isEmpty()) { + Solid::Device device = Solid::Device(item->udi()); + Solid::StorageAccess *access = device.as(); + + if (access != nullptr) { + access->teardown(); + } + } +} + void PlacesModel::onDeviceAdded(const QString &udi) { if (m_predicate.matches(Solid::Device(udi))) { beginInsertRows(QModelIndex(), rowCount(), rowCount()); PlacesItem *deviceItem = new PlacesItem; deviceItem->setUdi(udi); + deviceItem->setCategory(tr("Drives")); m_items.append(deviceItem); endInsertRows(); + + connect(deviceItem, &PlacesItem::itemChanged, this, &PlacesModel::onItemChanged); } } @@ -262,6 +301,20 @@ void PlacesModel::onDeviceRemoved(const QString &udi) PlacesItem *item = m_items.at(i); m_items.removeOne(item); endRemoveRows(); + + disconnect(item); } } } + +void PlacesModel::onItemChanged(PlacesItem *item) +{ + // 更新 item 数据 + int index = m_items.indexOf(item); + + if (index < 0 || index > m_items.size()) + return; + + QModelIndex idx = this->index(index, 0); + emit dataChanged(idx, idx); +} diff --git a/model/placesmodel.h b/model/placesmodel.h index fbeb4d3..a407dee 100644 --- a/model/placesmodel.h +++ b/model/placesmodel.h @@ -36,7 +36,9 @@ class PlacesModel : public QAbstractItemModel UrlRole, PathRole, IsDeviceRole, - setupNeededRole + IsOpticalDisc, + setupNeededRole, + CategoryRole }; Q_ENUMS(DataRole); @@ -55,6 +57,7 @@ class PlacesModel : public QAbstractItemModel Q_INVOKABLE QVariantMap get(const int &index) const; Q_INVOKABLE void requestSetup(const int &index); Q_INVOKABLE void requestEject(const int &index); + Q_INVOKABLE void requestTeardown(const int &index); signals: void deviceSetupDone(const QString &filePath); @@ -62,6 +65,7 @@ class PlacesModel : public QAbstractItemModel private slots: void onDeviceAdded(const QString &udi); void onDeviceRemoved(const QString &udi); + void onItemChanged(PlacesItem *); private: QList m_items; diff --git a/qml.qrc b/qml.qrc index 62d532c..9b5e165 100644 --- a/qml.qrc +++ b/qml.qrc @@ -57,5 +57,24 @@ images/dark/user-trash.svg images/dark/drive-optical.svg images/light/drive-optical.svg + qml/Dialogs/OpenWithDialog.qml + qml/Dialogs/DeleteDialog.qml + qml/Desktop/Wallpaper.qml + images/folder-document.svg + images/folder-desktop.svg + images/folder-download.svg + images/folder-home.svg + images/folder-music.svg + images/folder-picture.svg + images/folder-video.svg + images/user-trash.svg + images/drive-harddisk-root.svg + images/drive-harddisk.svg + images/drive-optical.svg + images/drive-removable-media-usb.svg + templates/TextFile.txt + images/media-optical-data.svg + images/media-optical-mixed-cd.svg + images/media-optical.svg diff --git a/qml/Controls/IconButton.qml b/qml/Controls/IconButton.qml index f7a4edf..df84f24 100644 --- a/qml/Controls/IconButton.qml +++ b/qml/Controls/IconButton.qml @@ -45,9 +45,11 @@ Item { Image { id: _image anchors.centerIn: parent - width: control.height * 0.64 + width: 18 height: width sourceSize: Qt.size(width, height) + smooth: false + antialiasing: true } MouseArea { diff --git a/qml/Desktop/Main.qml b/qml/Desktop/Main.qml index 6ce4437..e722aad 100644 --- a/qml/Desktop/Main.qml +++ b/qml/Desktop/Main.qml @@ -30,62 +30,27 @@ import "../" Item { id: rootItem - FM.DesktopSettings { - id: settings - } + LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft + LayoutMirroring.childrenInherit: true GlobalSettings { id: globalSettings } - Loader { - id: backgroundLoader + Wallpaper { anchors.fill: parent - sourceComponent: settings.backgroundType === 0 ? wallpaper : background - } - - Component { - id: background - - Rectangle { - anchors.fill: parent - color: settings.backgroundColor - } - } - - Component { - id: wallpaper - - Image { - source: "file://" + settings.wallpaper - sourceSize: Qt.size(width * Screen.devicePixelRatio, - height * Screen.devicePixelRatio) - fillMode: Image.PreserveAspectCrop - clip: true - cache: false - - ColorOverlay { - id: dimsWallpaper - anchors.fill: parent - source: parent - color: "#000000" - opacity: FishUI.Theme.darkMode && settings.dimsWallpaper ? 0.4 : 0.0 - - Behavior on opacity { - NumberAnimation { - duration: 200 - } - } - - } - } } FM.FolderModel { id: dirModel url: desktopPath() isDesktop: true + sortMode: -1 viewAdapter: viewAdapter + + onCurrentIndexChanged: { + _folderView.currentIndex = dirModel.currentIndex + } } FM.ItemViewAdapter { @@ -109,19 +74,19 @@ Item { isDesktopView: true iconSize: globalSettings.desktopIconSize maximumIconSize: globalSettings.maximumIconSize - minimumIconSize: globalSettings.minimumIconSize + minimumIconSize: 22 focus: true model: dirModel ScrollBar.vertical.policy: ScrollBar.AlwaysOff // Handle for topbar - anchors.topMargin: desktopView.screenAvailableRect.y + topMargin: 28 - leftMargin: desktopView.screenAvailableRect.x - topMargin: 0 - rightMargin: desktopView.screenRect.width - (desktopView.screenAvailableRect.x + desktopView.screenAvailableRect.width) - bottomMargin: desktopView.screenRect.height - (desktopView.screenAvailableRect.y + desktopView.screenAvailableRect.height) + // From dock + leftMargin: Dock.leftMargin + rightMargin: Dock.rightMargin + bottomMargin: Dock.bottomMargin flow: GridView.FlowTopToBottom @@ -174,6 +139,15 @@ Item { onDeleteFile: { dirModel.keyDeletePress() } + onKeyPressed: { + dirModel.keyboardSearch(text) + } + onShowHidden: { + dirModel.showHiddenFiles = !dirModel.showHiddenFiles + } + onUndo: { + dirModel.undo() + } } Component { diff --git a/qml/Desktop/Wallpaper.qml b/qml/Desktop/Wallpaper.qml new file mode 100644 index 0000000..ad9b21e --- /dev/null +++ b/qml/Desktop/Wallpaper.qml @@ -0,0 +1,63 @@ +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Window 2.12 +import QtGraphicalEffects 1.0 + +import Cutefish.FileManager 1.0 as FM +import FishUI 1.0 as FishUI + +Item { + id: control + + FM.DesktopSettings { + id: settings + } + + Loader { + id: backgroundLoader + anchors.fill: parent + anchors.margins: 0 + sourceComponent: settings.backgroundType === 0 ? wallpaper : background + } + + Component { + id: background + + Rectangle { + anchors.fill: parent + color: settings.backgroundColor + } + } + + Component { + id: wallpaper + + Image { + source: "file://" + settings.wallpaper + sourceSize: Qt.size(width * Screen.devicePixelRatio, + height * Screen.devicePixelRatio) + fillMode: Image.PreserveAspectCrop + clip: true + cache: false + + // Clear cache + onSourceChanged: dirModel.clearPixmapCache() + + ColorOverlay { + id: dimsWallpaper + anchors.fill: parent + source: parent + color: "#000000" + opacity: FishUI.Theme.darkMode && settings.dimsWallpaper ? 0.4 : 0.0 + + Behavior on opacity { + NumberAnimation { + duration: 200 + } + } + + } + } + } +} diff --git a/qml/Dialogs/CreateFolderDialog.qml b/qml/Dialogs/CreateFolderDialog.qml index 1b4069a..8f0d2f0 100644 --- a/qml/Dialogs/CreateFolderDialog.qml +++ b/qml/Dialogs/CreateFolderDialog.qml @@ -75,6 +75,8 @@ Window { } RowLayout { + spacing: FishUI.Units.largeSpacing + Button { text: qsTr("Cancel") Layout.fillWidth: true diff --git a/qml/Dialogs/DeleteDialog.qml b/qml/Dialogs/DeleteDialog.qml new file mode 100644 index 0000000..4207f47 --- /dev/null +++ b/qml/Dialogs/DeleteDialog.qml @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Window 2.12 +import QtQuick.Layouts 1.12 +import FishUI 1.0 as FishUI +import Cutefish.FileManager 1.0 + +FishUI.Window { + id: control + + flags: Qt.Dialog | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint + minimizeButtonVisible: false + visible: true + + width: contentWidth + height: contentHeight + + minimumWidth: contentWidth + minimumHeight: contentHeight + maximumWidth: contentWidth + maximumHeight: contentHeight + + property var contentWidth: _mainLayout.implicitWidth + FishUI.Units.largeSpacing * 2 + property var contentHeight: _mainLayout.implicitHeight + control.header.height + FishUI.Units.largeSpacing * 2 + + background.color: FishUI.Theme.secondBackgroundColor + + ColumnLayout { + id: _mainLayout + anchors.fill: parent + anchors.leftMargin: FishUI.Units.largeSpacing + anchors.rightMargin: FishUI.Units.largeSpacing + anchors.bottomMargin: FishUI.Units.smallSpacing + spacing: FishUI.Units.largeSpacing + + Label { + text: qsTr("Do you want to delete it permanently?") + Layout.fillWidth: true + wrapMode: Text.Wrap + } + + RowLayout { + spacing: FishUI.Units.largeSpacing + + Button { + text: qsTr("Cancel") + Layout.fillWidth: true + onClicked: control.close() + } + + Button { + text: qsTr("Delete") + focus: true + Layout.fillWidth: true + onClicked: { + control.close() + model.deleteSelected() + } + flat: true + } + } + } +} diff --git a/qml/Dialogs/EmptyTrashDialog.qml b/qml/Dialogs/EmptyTrashDialog.qml index 1d051de..613dd05 100644 --- a/qml/Dialogs/EmptyTrashDialog.qml +++ b/qml/Dialogs/EmptyTrashDialog.qml @@ -24,20 +24,36 @@ import QtQuick.Layouts 1.12 import FishUI 1.0 as FishUI import Cutefish.FileManager 1.0 -Window { +FishUI.Window { id: control title: qsTr("File Manager") - flags: Qt.Dialog + flags: Qt.Dialog | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint + minimizeButtonVisible: false visible: true - width: 300 + FishUI.Units.largeSpacing * 2 - height: _mainLayout.implicitHeight + FishUI.Units.largeSpacing * 2 + property int contentWidth: 300 + FishUI.Units.largeSpacing * 2 + property int contentHeight: _mainLayout.implicitHeight + control.header.height + FishUI.Units.largeSpacing - minimumWidth: width - minimumHeight: height - maximumWidth: width - maximumHeight: height + width: contentWidth + height: contentHeight + +// x: Screen.virtualX + (Screen.width - contentWidth) / 2 +// y: Screen.virtualY + (Screen.height - contentHeight) / 2 + + minimumWidth: contentWidth + minimumHeight: contentHeight + maximumWidth: contentWidth + maximumHeight: contentHeight + + headerBackground.color: FishUI.Theme.secondBackgroundColor + + DragHandler { + target: null + acceptedDevices: PointerDevice.GenericPointer + grabPermissions: PointerHandler.CanTakeOverFromItems | PointerHandler.CanTakeOverFromHandlersOfDifferentType | PointerHandler.ApprovesTakeOverByAnything + onActiveChanged: if (active) { control.helper.startSystemMove(control) } + } Fm { id: fm @@ -51,9 +67,10 @@ Window { ColumnLayout { id: _mainLayout anchors.fill: parent + anchors.topMargin: 0 anchors.leftMargin: FishUI.Units.largeSpacing anchors.rightMargin: FishUI.Units.largeSpacing - anchors.bottomMargin: FishUI.Units.smallSpacing + anchors.bottomMargin: FishUI.Units.largeSpacing spacing: FishUI.Units.largeSpacing Label { diff --git a/qml/Dialogs/OpenWithDialog.qml b/qml/Dialogs/OpenWithDialog.qml new file mode 100644 index 0000000..d577321 --- /dev/null +++ b/qml/Dialogs/OpenWithDialog.qml @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +import QtQuick 2.12 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.0 +import FishUI 1.0 as FishUI + +Item { + id: control + + property string url: main.url + + width: 400 + FishUI.Units.largeSpacing * 2 + height: _mainLayout.implicitHeight + FishUI.Units.largeSpacing * 2 + + Rectangle { + anchors.fill: parent + color: FishUI.Theme.secondBackgroundColor + } + + Component.onCompleted: { + var items = mimeAppManager.recommendedApps(control.url) + + for (var i in items) { + listView.model.append(items[i]) + } + + defaultCheckBox.checked = false + doneButton.focus = true + } + + function openApp() { + if (defaultCheckBox.checked) + mimeAppManager.setDefaultAppForFile(control.url, listView.model.get(listView.currentIndex).desktopFile) + + launcher.launchApp(listView.model.get(listView.currentIndex).desktopFile, control.url) + main.close() + } + + Keys.enabled: true + Keys.onEscapePressed: main.close() + + ColumnLayout { + id: _mainLayout + anchors.fill: parent + spacing: 0 + + GridView { + id: listView + Layout.fillWidth: true + Layout.preferredHeight: 250 + model: ListModel {} + clip: true + ScrollBar.vertical: ScrollBar {} + + leftMargin: FishUI.Units.smallSpacing + rightMargin: FishUI.Units.smallSpacing + + cellHeight: { + var extraHeight = calcExtraSpacing(80, listView.Layout.preferredHeight - topMargin - bottomMargin) + return 80 + extraHeight + } + + cellWidth: { + var extraWidth = calcExtraSpacing(120, listView.width - leftMargin - rightMargin) + return 120 + extraWidth + } + + Label { + anchors.centerIn: parent + text: qsTr("No applications") + visible: listView.count === 0 + } + + delegate: Item { + id: item + width: GridView.view.cellWidth + height: GridView.view.cellHeight + scale: mouseArea.pressed ? 0.95 : 1.0 + + Behavior on scale { + NumberAnimation { + duration: 100 + } + } + + property bool isSelected: listView.currentIndex === index + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.LeftButton + onDoubleClicked: control.openApp() + onClicked: listView.currentIndex = index + } + + Rectangle { + anchors.fill: parent + anchors.margins: FishUI.Units.smallSpacing + radius: FishUI.Theme.mediumRadius + color: isSelected ? FishUI.Theme.highlightColor + : mouseArea.containsMouse ? Qt.rgba(FishUI.Theme.textColor.r, + FishUI.Theme.textColor.g, + FishUI.Theme.textColor.b, + 0.1) : "transparent" + smooth: true + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: FishUI.Units.smallSpacing + spacing: FishUI.Units.smallSpacing + + FishUI.IconItem { + id: icon + Layout.preferredHeight: 36 + Layout.preferredWidth: height + source: model.icon + Layout.alignment: Qt.AlignHCenter + } + + Label { + text: model.name + Layout.fillWidth: true + elide: Text.ElideMiddle + Layout.alignment: Qt.AlignHCenter + horizontalAlignment: Qt.AlignHCenter + color: isSelected ? FishUI.Theme.highlightedTextColor : FishUI.Theme.textColor + } + } + } + } + + CheckBox { + id: defaultCheckBox + focusPolicy: Qt.NoFocus + text: qsTr("Set as default") + enabled: listView.count >= 1 + padding: 0 + + Layout.leftMargin: FishUI.Units.largeSpacing + Layout.bottomMargin: FishUI.Units.largeSpacing + } + + RowLayout { + spacing: FishUI.Units.largeSpacing + Layout.leftMargin: FishUI.Units.largeSpacing + Layout.rightMargin: FishUI.Units.largeSpacing + Layout.bottomMargin: FishUI.Units.largeSpacing + + Button { + text: qsTr("Cancel") + Layout.fillWidth: true + onClicked: main.close() + } + + Button { + id: doneButton + focus: true + flat: true + text: qsTr("Open") + enabled: listView.count > 0 + Layout.fillWidth: true + onClicked: control.openApp() + } + + } + } + + function calcExtraSpacing(cellSize, containerSize) { + var availableColumns = Math.floor(containerSize / cellSize) + var extraSpacing = 0 + if (availableColumns > 0) { + var allColumnSize = availableColumns * cellSize + var extraSpace = Math.max(containerSize - allColumnSize, 0) + extraSpacing = extraSpace / availableColumns + } + return Math.floor(extraSpacing) + } +} diff --git a/qml/Dialogs/PropertiesDialog.qml b/qml/Dialogs/PropertiesDialog.qml index 0291675..e6908c5 100644 --- a/qml/Dialogs/PropertiesDialog.qml +++ b/qml/Dialogs/PropertiesDialog.qml @@ -23,12 +23,21 @@ import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 import FishUI 1.0 as FishUI -Window { +Item { id: control - title: qsTr("Properties") - flags: Qt.Dialog - visible: true + property int widthValue: _mainLayout.implicitWidth + FishUI.Units.largeSpacing * 3 + property int heightValue: _mainLayout.implicitHeight + FishUI.Units.largeSpacing * 3 + + width: widthValue + height: heightValue + + onWidthValueChanged: main.updateSize(widthValue, heightValue) + onHeightValueChanged: main.updateSize(widthValue, heightValue) + + focus: true + Keys.enabled: true + Keys.onEscapePressed: main.reject() Rectangle { anchors.fill: parent @@ -39,169 +48,150 @@ Window { if (visible) updateWindowSize() } + function close() { + main.close() + } + function updateWindowSize() { if (visible) { - control.width = _mainLayout.implicitWidth + _mainLayout.anchors.leftMargin + _mainLayout.anchors.rightMargin - control.height = _mainLayout.implicitHeight + _mainLayout.anchors.topMargin + _mainLayout.anchors.bottomMargin - control.minimumWidth = control.width - control.minimumHeight = control.height - control.maximumWidth = control.width - control.maximumHeight = control.height - if (_textField.enabled) _textField.forceActiveFocus() } } - Item { - id: _contentItem + ColumnLayout { + id: _mainLayout anchors.fill: parent - focus: true - - Keys.enabled: true - Keys.onEscapePressed: control.close() - - ColumnLayout { - id: _mainLayout - anchors.fill: parent - anchors.leftMargin: FishUI.Units.largeSpacing * 2 - anchors.rightMargin: FishUI.Units.largeSpacing * 2 - anchors.topMargin: FishUI.Units.largeSpacing - anchors.bottomMargin: FishUI.Units.largeSpacing * 1.5 - spacing: FishUI.Units.largeSpacing - - RowLayout { - spacing: FishUI.Units.largeSpacing * 2 - - Image { - width: 64 - height: width - sourceSize: Qt.size(width, height) - source: "image://icontheme/" + main.iconName - } - - TextField { - id: _textField - text: main.fileName - focus: true - Layout.fillWidth: true - Keys.onEscapePressed: control.close() - enabled: !main.multiple && main.isWritable - } + anchors.leftMargin: FishUI.Units.largeSpacing * 1.5 + anchors.rightMargin: FishUI.Units.largeSpacing * 1.5 + anchors.topMargin: FishUI.Units.smallSpacing + anchors.bottomMargin: FishUI.Units.largeSpacing * 1.5 + spacing: FishUI.Units.largeSpacing + + RowLayout { + spacing: FishUI.Units.largeSpacing * 2 + + FishUI.IconItem { + width: 64 + height: 64 + source: main.iconName } - GridLayout { - columns: 2 - columnSpacing: FishUI.Units.largeSpacing - rowSpacing: FishUI.Units.largeSpacing - Layout.alignment: Qt.AlignTop + TextField { + id: _textField + text: main.fileName + focus: true + Layout.fillWidth: true + Keys.onEscapePressed: main.reject() + enabled: main.isWritable + } + } - onHeightChanged: updateWindowSize() - onImplicitHeightChanged: updateWindowSize() + GridLayout { + columns: 2 + columnSpacing: FishUI.Units.largeSpacing + rowSpacing: FishUI.Units.largeSpacing + Layout.alignment: Qt.AlignTop - Label { - text: qsTr("Type:") - Layout.alignment: Qt.AlignRight - color: FishUI.Theme.disabledTextColor - visible: mimeType.visible - } + onHeightChanged: updateWindowSize() + onImplicitHeightChanged: updateWindowSize() - Label { - id: mimeType - text: main.mimeType - visible: text - } + Label { + text: qsTr("Type:") + Layout.alignment: Qt.AlignRight + color: FishUI.Theme.disabledTextColor + visible: mimeType.visible + } - Label { - text: qsTr("Location:") - Layout.alignment: Qt.AlignRight - color: FishUI.Theme.disabledTextColor - } + Label { + id: mimeType + text: main.mimeType + visible: text + } - Label { - id: location - text: main.location - } + Label { + text: qsTr("Location:") + Layout.alignment: Qt.AlignRight + color: FishUI.Theme.disabledTextColor + } - Label { - text: qsTr("Size:") - Layout.alignment: Qt.AlignRight - color: FishUI.Theme.disabledTextColor - // visible: size.visible - } + Label { + id: location + text: main.location + } - Label { - id: size - text: main.size ? main.size : qsTr("Calculating...") - // visible: text - } + Label { + text: qsTr("Size:") + Layout.alignment: Qt.AlignRight + color: FishUI.Theme.disabledTextColor + } - Label { - text: qsTr("Created:") - Layout.alignment: Qt.AlignRight - color: FishUI.Theme.disabledTextColor - visible: creationTime.visible - } + Label { + id: size + text: main.fileSize ? main.fileSize : qsTr("Calculating...") + } - Label { - id: creationTime - text: main.creationTime - visible: text - } + Label { + text: qsTr("Created:") + Layout.alignment: Qt.AlignRight + color: FishUI.Theme.disabledTextColor + visible: creationTime.visible + } - Label { - text: qsTr("Modified:") - Layout.alignment: Qt.AlignRight - color: FishUI.Theme.disabledTextColor - visible: modifiedTime.visible - } + Label { + id: creationTime + text: main.creationTime + visible: text + } - Label { - id: modifiedTime - text: main.modifiedTime - visible: text - } + Label { + text: qsTr("Modified:") + Layout.alignment: Qt.AlignRight + color: FishUI.Theme.disabledTextColor + visible: modifiedTime.visible + } - Label { - text: qsTr("Accessed:") - Layout.alignment: Qt.AlignRight - color: FishUI.Theme.disabledTextColor - visible: accessTime.visible - } + Label { + id: modifiedTime + text: main.modifiedTime + visible: text + } - Label { - id: accessTime - text: main.accessedTime - visible: text - } + Label { + text: qsTr("Accessed:") + Layout.alignment: Qt.AlignRight + color: FishUI.Theme.disabledTextColor + visible: accessTime.visible } - Item { - height: FishUI.Units.largeSpacing + Label { + id: accessTime + text: main.accessedTime + visible: text } + } - RowLayout { - Layout.alignment: Qt.AlignRight - spacing: FishUI.Units.largeSpacing - - Button { - text: qsTr("Cancel") - Layout.fillWidth: true - onClicked: { - control.close() - main.reject() - } - } + Item { + height: FishUI.Units.smallSpacing + } + + RowLayout { + Layout.alignment: Qt.AlignRight + spacing: FishUI.Units.largeSpacing + + Button { + text: qsTr("Cancel") + Layout.fillWidth: true + onClicked: main.reject() + } - Button { - text: qsTr("OK") - Layout.fillWidth: true - onClicked: { - main.accept(_textField.text) - control.close() - } - flat: true + Button { + text: qsTr("OK") + Layout.fillWidth: true + onClicked: { + main.accept(_textField.text) } + flat: true } } } diff --git a/qml/FolderGridItem.qml b/qml/FolderGridItem.qml index 62197f4..a31614d 100644 --- a/qml/FolderGridItem.qml +++ b/qml/FolderGridItem.qml @@ -39,7 +39,26 @@ Item { property bool hovered: GridView.view.hoveredItem === control property bool selected: model.selected property bool blank: model.blank - property var fileName: model.fileName + property var fileName: model.displayName + + // For desktop + visible: GridView.view.isDesktopView ? !blank : true + + onSelectedChanged: { + if (!GridView.view.isDesktopView) + return + + if (selected && !blank) { + control.grabToImage(function(result) { + dirModel.addItemDragImage(control.index, + control.x, + control.y, + control.width, + control.height, + result.image) + }) + } + } Rectangle { id: _background @@ -60,13 +79,15 @@ Item { id: _iconItem anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter - anchors.topMargin: FishUI.Units.largeSpacing - anchors.bottomMargin: FishUI.Units.largeSpacing + anchors.topMargin: FishUI.Units.smallSpacing + anchors.bottomMargin: FishUI.Units.smallSpacing z: 2 width: parent.width - FishUI.Units.largeSpacing * 2 height: control.GridView.view.iconSize + opacity: model.isHidden ? 0.5 : 1.0 + Image { id: _icon width: control.GridView.view.iconSize @@ -75,22 +96,8 @@ Item { sourceSize: Qt.size(width, height) source: "image://icontheme/" + model.iconName visible: !_image.visible - - ColorOverlay { - anchors.fill: _icon - source: _icon - color: FishUI.Theme.highlightColor - opacity: 0.5 - visible: control.selected - } - - ColorOverlay { - anchors.fill: _icon - source: _icon - color: "white" - opacity: FishUI.Theme.darkMode ? 0.3 : 0.4 - visible: control.hovered && !control.selected - } + smooth: true + antialiasing: true } Image { @@ -103,28 +110,12 @@ Item { visible: status === Image.Ready horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter - sourceSize.width: width - sourceSize.height: height + sourceSize: Qt.size(width, height) source: model.thumbnail ? model.thumbnail : "" asynchronous: true - cache: true - - // Because of the effect of OpacityMask. - ColorOverlay { - anchors.fill: _image - source: _image - color: FishUI.Theme.highlightColor - opacity: 0.5 - visible: control.selected - } - - ColorOverlay { - anchors.fill: _image - source: _image - color: "white" - opacity: FishUI.Theme.darkMode ? 0.3 : 0.4 - visible: control.hovered && !control.selected - } + cache: false + smooth: true + antialiasing: true layer.enabled: _image.visible layer.effect: OpacityMask { @@ -142,23 +133,33 @@ Item { } } -// ColorOverlay { -// id: _selectedColorOverlay -// anchors.fill: _image.visible ? _image : _icon -// source: _image.visible ? _image : _icon -// color: FishUI.Theme.highlightColor -// opacity: 0.5 -// visible: control.selected -// } - -// ColorOverlay { -// id: _hoveredColorOverlay -// anchors.fill: _image.visible ? _image : _icon -// source: _image.visible ? _image : _icon -// color: Qt.lighter(FishUI.Theme.highlightColor, 1.6) -// opacity: FishUI.Theme.darkMode ? 0.4 : 0.6 -// visible: control.hovered && !control.selected -// } + Image { + anchors.right: _icon.visible ? _icon.right : _image.right + anchors.bottom: _icon.visible ? _icon.bottom : _image.bottom + source: "image://icontheme/emblem-symbolic-link" + width: 16 + height: 16 + visible: model.isLink + sourceSize: Qt.size(width, height) + } + + ColorOverlay { + id: _selectedColorOverlay + anchors.fill: _iconItem + source: _iconItem + color: FishUI.Theme.highlightColor + opacity: 0.5 + visible: control.selected + } + + ColorOverlay { + id: _hoveredColorOverlay + anchors.fill: _iconItem + source: _iconItem + color: "white" + opacity: 0.3 + visible: control.hovered && !control.selected + } } Label { @@ -167,26 +168,41 @@ Item { anchors.top: _iconItem.bottom anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: FishUI.Units.smallSpacing - maximumLineCount: 2 + maximumLineCount: control.selected ? 3 : 2 horizontalAlignment: Text.AlignHCenter width: parent.width - FishUI.Units.largeSpacing * 2 - FishUI.Units.smallSpacing textFormat: Text.PlainText elide: Qt.ElideRight wrapMode: Text.Wrap - text: model.fileName + text: control.fileName color: control.GridView.view.isDesktopView ? "white" - : selected ? FishUI.Theme.highlightedTextColor : FishUI.Theme.textColor + : selected ? FishUI.Theme.highlightColor + : FishUI.Theme.textColor + opacity: model.isHidden ? 0.8 : 1.0 } Rectangle { z: 1 - x: _label.x + x: _label.x + (_label.width - _label.paintedWidth) / 2 - (FishUI.Units.smallSpacing / 2) y: _label.y - width: _label.width - height: _label.height + width: _label.paintedWidth + FishUI.Units.smallSpacing + height: _label.paintedHeight radius: 4 color: FishUI.Theme.highlightColor - opacity: control.selected ? 1.0 : 0 + + opacity: { + if (control.selected && control.GridView.view.isDesktopView) + return 1 + + if (control.selected) + return 0.2 + + if (control.hovered) + return 0.05 + + return 0 + + } } DropShadow { diff --git a/qml/FolderGridView.qml b/qml/FolderGridView.qml index 92353fe..c5977e0 100644 --- a/qml/FolderGridView.qml +++ b/qml/FolderGridView.qml @@ -16,16 +16,19 @@ * along with this program. If not, see . */ -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Layouts 1.12 +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 import Cutefish.FileManager 1.0 +import Cutefish.DragDrop 1.0 as DragDrop import FishUI 1.0 as FishUI GridView { id: control + objectName: "FolderGridView" + property bool isDesktopView: false property Item rubberBand: null @@ -46,14 +49,13 @@ GridView { property bool ctrlPressed: false property bool shiftPressed: false - property int previouslySelectedItemIndex: -1 property variant cPress: null property Item editor: null property int anchorIndex: 0 property var iconSize: settings.gridIconSize property var maximumIconSize: settings.maximumIconSize - property var minimumIconSize: settings.minimumIconSize + property var minimumIconSize: 22 //settings.minimumIconSize property variant cachedRectangleSelection: null @@ -64,13 +66,18 @@ GridView { signal keyPress(var event) - cacheBuffer: Math.max(0, contentHeight) + cacheBuffer: Math.max(0, control.height * 1.5) + reuseItems: true onIconSizeChanged: { // 图标大小改变时需要重置状态,否则选中定位不准确 positioner.reset() } + onCountChanged: { + positioner.reset() + } + function effectiveNavDirection(flow, layoutDirection, direction) { if (direction === Qt.LeftArrow) { if (flow === GridView.FlowLeftToRight) { @@ -138,17 +145,77 @@ GridView { function reset() { currentIndex = -1 anchorIndex = 0 - previouslySelectedItemIndex = -1 cancelRename() hoveredItem = null pressedItem = null cPress = null } + function drop(target, event, pos) { + var dropPos = mapToItem(control.contentItem, pos.x, pos.y) + var dropIndex = control.indexAt(dropPos.x, dropPos.y) + var dragPos = mapToItem(control.contentItem, control.dragX, control.dragY) + var dragIndex = control.indexAt(dragPos.x, dragPos.y) + + if (control.dragX === -1 || dragIndex !== dropIndex) { + dirModel.drop(control, event, dropItemAt(dropPos)) + } + } + + function dropItemAt(pos) { + var item = control.itemAt(pos.x, pos.y) + + if (item) { + if (item.blank) { + return -1 + } + + var hOffset = Math.abs(Math.min(control.contentX, control.originX)) + var hPos = mapToItem(item, pos.x + hOffset, pos.y) + + if ((hPos.x < 0 || hPos.y < 0 || hPos.x > item.width || hPos.y > item.height)) { + return -1 + } else { + return positioner.map(item.index) + } + } + + return -1 + } + highlightMoveDuration: 0 keyNavigationEnabled : true keyNavigationWraps : true + Keys.onPressed: { + // vim h,j,k,l keybindings + if (event.key === Qt.Key_J || + event.key == Qt.Key_H || + event.key == Qt.Key_K || + event.key == Qt.Key_L + ) { // if a vim H,J,K,L keybinding is pressed + var arrow = Qt.NoArrow; // sample arrow key + switch (event.key) { // setting up the arrow key + case (Qt.Key_J): arrow = Qt.DownArrow; break; + case (Qt.Key_H): arrow = Qt.LeftArrow; break; + case (Qt.Key_L): arrow = Qt.RightArrow; break; + case (Qt.Key_K): arrow = Qt.UpArrow; break; + } + + // setting the selected file to the new one thanks to the arrow + if (!editor || !editor.targetItem) { + var newIndex = positioner.nearestItem( + currentIndex, + effectiveNavDirection(control.flow, control.effectiveLayoutDirection, arrow) + ) + if (newIndex !== -1) { + currentIndex = newIndex + updateSelection(event.modifiers) + } + } + } + + // focus on control/shift event control.keyPress(event) if (event.key === Qt.Key_Control) { @@ -174,15 +241,17 @@ GridView { } Keys.onEscapePressed: { if (!editor || !editor.targetItem) { - previouslySelectedItemIndex = -1 dirModel.clearSelection() event.accepted = false } } Keys.onUpPressed: { if (!editor || !editor.targetItem) { - var newIndex = positioner.nearestItem(currentIndex, - effectiveNavDirection(control.flow, control.effectiveLayoutDirection, Qt.UpArrow)) + var newIndex = positioner.nearestItem( + currentIndex, effectiveNavDirection( + control.flow, control.effectiveLayoutDirection, Qt.UpArrow + ) + ) if (newIndex !== -1) { currentIndex = newIndex updateSelection(event.modifiers) @@ -191,8 +260,11 @@ GridView { } Keys.onDownPressed: { if (!editor || !editor.targetItem) { - var newIndex = positioner.nearestItem(currentIndex, - effectiveNavDirection(control.flow, control.effectiveLayoutDirection, Qt.DownArrow)) + var newIndex = positioner.nearestItem( + currentIndex, effectiveNavDirection( + control.flow, control.effectiveLayoutDirection, Qt.DownArrow + ) + ) if (newIndex !== -1) { currentIndex = newIndex updateSelection(event.modifiers) @@ -201,20 +273,26 @@ GridView { } Keys.onLeftPressed: { if (!editor || !editor.targetItem) { - var newIndex = positioner.nearestItem(currentIndex, - effectiveNavDirection(control.flow, control.effectiveLayoutDirection, Qt.LeftArrow)) + var newIndex = positioner.nearestItem( + currentIndex, effectiveNavDirection( + control.flow, control.effectiveLayoutDirection, Qt.LeftArrow + ) + ) if (newIndex !== -1) { - currentIndex = newIndex; + currentIndex = newIndex updateSelection(event.modifiers) } } } Keys.onRightPressed: { if (!editor || !editor.targetItem) { - var newIndex = positioner.nearestItem(currentIndex, - effectiveNavDirection(control.flow, control.effectiveLayoutDirection, Qt.RightArrow)) + var newIndex = positioner.nearestItem( + currentIndex, effectiveNavDirection( + control.flow, control.effectiveLayoutDirection, Qt.RightArrow + ) + ) if (newIndex !== -1) { - currentIndex = newIndex; + currentIndex = newIndex updateSelection(event.modifiers) } } @@ -275,22 +353,14 @@ GridView { folderModel: dirModel perStripe: Math.floor(((control.flow == GridView.FlowLeftToRight) ? control.width : control.height) / ((control.flow == GridView.FlowLeftToRight) - ? control.cellWidth : control.cellHeight)); + ? control.cellWidth : control.cellHeight)) } - DropArea { - id: _dropArea + DragDrop.DropArea { anchors.fill: parent - onDropped: { - var dropPos = mapToItem(control.contentItem, drop.x, drop.y) - var dropIndex = control.indexAt(drop.x, drop.y) - var dragPos = mapToItem(control.contentItem, control.dragX, control.dragY) - var dragIndex = control.indexAt(dragPos.x, dragPos.y) - - if (control.dragX == -1 || dragIndex !== dropIndex) { - - } + onDrop: { + control.drop(control, event, mapToItem(control, event.x, event.y)) } } @@ -428,7 +498,7 @@ GridView { clearPressState() } else { if (control.editor && control.editor.targetItem) - return; + return dirModel.pinSelection() control.rubberBand = rubberBandObject.createObject(control.contentItem, {x: cPress.x, y: cPress.y}) @@ -461,6 +531,8 @@ GridView { dirModel.setSelected(pressedItem.index) } + dirModel.updateSelectedItemsSize() + pressCanceled() } @@ -600,9 +672,6 @@ GridView { } else { dirModel.clearSelection() dirModel.setSelected(currentIndex) - if (currentIndex == -1) - previouslySelectedItemIndex = -1 - previouslySelectedItemIndex = currentIndex } } @@ -626,7 +695,7 @@ GridView { width = targetItem.width - FishUI.Units.smallSpacing height = targetItem.labelArea.paintedHeight + FishUI.Units.largeSpacing * 2 x = targetItem.x + Math.abs(Math.min(control.contentX, control.originX)) - y = pos.y - FishUI.Units.largeSpacing + y = pos.y - FishUI.Units.smallSpacing text = targetItem.labelArea.text targetItem.labelArea.visible = false _editor.select(0, dirModel.fileExtensionBoundary(targetItem.index)) diff --git a/qml/FolderListItem.qml b/qml/FolderListItem.qml index ebd176a..a9c09bc 100644 --- a/qml/FolderListItem.qml +++ b/qml/FolderListItem.qml @@ -62,6 +62,7 @@ Item { radius: FishUI.Theme.smallRadius color: selected ? FishUI.Theme.highlightColor : hovered ? hoveredColor : "transparent" visible: selected || hovered + opacity: selected ? 0.1 : 2 } RowLayout { @@ -75,6 +76,7 @@ Item { id: iconItem Layout.fillHeight: true width: parent.height * 0.8 + opacity: model.isHidden ? 0.5 : 1.0 Image { id: _icon @@ -98,7 +100,7 @@ Item { visible: _image.status === Image.Ready fillMode: Image.PreserveAspectFit asynchronous: true - smooth: false + cache: false layer.enabled: true layer.effect: OpacityMask { @@ -115,6 +117,16 @@ Item { } } } + + Image { + anchors.right: _icon.visible ? _icon.right : _image.right + anchors.bottom: _icon.visible ? _icon.bottom : _image.bottom + source: "image://icontheme/emblem-symbolic-link" + width: 16 + height: 16 + visible: model.isLink + sourceSize: Qt.size(width, height) + } } ColumnLayout { @@ -124,21 +136,27 @@ Item { id: _label text: model.fileName Layout.fillWidth: true - color: selected ? FishUI.Theme.highlightedTextColor : FishUI.Theme.textColor + color: selected ? FishUI.Theme.highlightColor : FishUI.Theme.textColor + textFormat: Text.PlainText elide: Qt.ElideMiddle + opacity: model.isHidden ? 0.8 : 1.0 } Label { id: _label2 text: model.fileSize - color: selected ? FishUI.Theme.highlightedTextColor : FishUI.Theme.disabledTextColor + color: selected ? FishUI.Theme.highlightColor : FishUI.Theme.disabledTextColor + textFormat: Text.PlainText Layout.fillWidth: true + opacity: model.isHidden ? 0.8 : 1.0 } } Label { text: model.modified - color: selected ? FishUI.Theme.highlightedTextColor : FishUI.Theme.disabledTextColor + textFormat: Text.PlainText + color: selected ? FishUI.Theme.highlightColor : FishUI.Theme.disabledTextColor + opacity: model.isHidden ? 0.8 : 1.0 } } } diff --git a/qml/FolderListView.qml b/qml/FolderListView.qml index cae64ea..a2c5b2a 100644 --- a/qml/FolderListView.qml +++ b/qml/FolderListView.qml @@ -16,15 +16,18 @@ * along with this program. If not, see . */ -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Layouts 1.12 +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 import FishUI 1.0 as FishUI import Cutefish.FileManager 1.0 +import Cutefish.DragDrop 1.0 as DragDrop ListView { id: control + objectName: "FolderListView" + property Item rubberBand: null property Item hoveredItem: null property Item pressedItem: null @@ -40,7 +43,6 @@ ListView { property bool ctrlPressed: false property bool shiftPressed: false - property int previouslySelectedItemIndex: -1 property variant cPress: null property Item editor: null property int anchorIndex: 0 @@ -51,8 +53,9 @@ ListView { signal keyPress(var event) - currentIndex: -1 clip: true + cacheBuffer: width + reuseItems: true ScrollBar.vertical: ScrollBar { } boundsBehavior: Flickable.StopAtBounds @@ -85,13 +88,45 @@ ListView { function reset() { currentIndex = -1 anchorIndex = 0 - previouslySelectedItemIndex = -1 cancelRename() hoveredItem = null pressedItem = null cPress = null } + + function drop(target, event, pos) { + var dropPos = mapToItem(control.contentItem, pos.x, pos.y) + var dropIndex = control.indexAt(dropPos.x, dropPos.y) + var dragPos = mapToItem(control.contentItem, control.dragX, control.dragY) + var dragIndex = control.indexAt(dragPos.x, dragPos.y) + + if (control.dragX === -1 || dragIndex !== dropIndex) { + dirModel.drop(control, event, dropItemAt(dropPos)) + } + } + + function dropItemAt(pos) { + var item = control.itemAt(pos.x, pos.y) + + if (item) { + if (item.blank) { + return -1 + } + + var hOffset = Math.abs(Math.min(control.contentX, control.originX)) + var hPos = mapToItem(item, pos.x + hOffset, pos.y) + + if ((hPos.x < 0 || hPos.y < 0 || hPos.x > item.width || hPos.y > item.height)) { + return -1 + } else { + return item.index + } + } + + return -1 + } + highlightMoveDuration: 0 Keys.enabled: true Keys.onPressed: { @@ -118,7 +153,6 @@ ListView { Keys.onEscapePressed: { if (!editor || !editor.targetItem) { - previouslySelectedItemIndex = -1 dirModel.clearSelection() event.accepted = false } @@ -176,6 +210,14 @@ ListView { cPress = mapToItem(control.contentItem, pressX, pressY) } + DragDrop.DropArea { + anchors.fill: parent + + onDrop: { + control.drop(control, event, mapToItem(control, event.x, event.y)) + } + } + MouseArea { id: _mouseArea anchors.fill: parent @@ -214,7 +256,6 @@ ListView { if (!hoveredItem || hoveredItem.blank) { if (!control.ctrlPressed) { control.currentIndex = -1 - control.previouslySelectedItemIndex = -1 dirModel.clearSelection() } @@ -230,7 +271,6 @@ ListView { dirModel.setRangeSelected(control.anchorIndex, hoveredItem.index) } else { if (!control.ctrlPressed && !dirModel.isSelected(hoveredItem.index)) { - previouslySelectedItemIndex = -1 dirModel.clearSelection() } @@ -394,9 +434,6 @@ ListView { } else { dirModel.clearSelection() dirModel.setSelected(currentIndex) - if (currentIndex == -1) - previouslySelectedItemIndex = -1 - previouslySelectedItemIndex = currentIndex } } @@ -410,6 +447,16 @@ ListView { verticalAlignment: TextEdit.AlignVCenter z: 999 + background: Item { + Rectangle { + anchors.fill: parent + anchors.topMargin: FishUI.Units.smallSpacing + anchors.bottomMargin: FishUI.Units.smallSpacing + radius: FishUI.Theme.smallRadius + color: FishUI.Theme.backgroundColor + } + } + property Item targetItem: null onTargetItemChanged: { diff --git a/qml/FolderPage.qml b/qml/FolderPage.qml index f8ac290..82d4900 100644 --- a/qml/FolderPage.qml +++ b/qml/FolderPage.qml @@ -32,12 +32,16 @@ Item { id: folderPage property alias currentUrl: dirModel.url + property alias model: dirModel property Item currentView: _viewLoader.item property int statusBarHeight: 22 signal requestPathEditor() onCurrentUrlChanged: { + if (!_viewLoader.item) + return + _viewLoader.item.reset() _viewLoader.item.forceActiveFocus() } @@ -65,7 +69,7 @@ Item { MenuItem { text: qsTr("Quit") - onTriggered: Qt.quit() + onTriggered: root.close() } } @@ -76,6 +80,23 @@ Item { text: qsTr("Select All") onTriggered: dirModel.selectAll() } + + MenuSeparator {} + + MenuItem { + text: qsTr("Cut") + onTriggered: dirModel.cut() + } + + MenuItem { + text: qsTr("Copy") + onTriggered: dirModel.copy() + } + + MenuItem { + text: qsTr("Paste") + onTriggered: dirModel.paste() + } } Menu { @@ -83,22 +104,31 @@ Item { MenuItem { text: qsTr("About") + onTriggered: _aboutDialog.show() } } } + FishUI.AboutDialog { + id: _aboutDialog + name: qsTr("File Manager") + description: qsTr("A file manager designed for CutefishOS.") + iconSource: "image://icontheme/file-system-manager" + } + Rectangle { id: _background anchors.fill: parent - radius: FishUI.Theme.smallRadius + anchors.rightMargin: 1 + radius: FishUI.Theme.mediumRadius color: FishUI.Theme.secondBackgroundColor Rectangle { id: _topRightRect anchors.right: parent.right anchors.top: parent.top - height: FishUI.Theme.smallRadius - width: FishUI.Theme.smallRadius + height: FishUI.Theme.mediumRadius + width: FishUI.Theme.mediumRadius color: FishUI.Theme.secondBackgroundColor } @@ -106,8 +136,8 @@ Item { id: _bottomLeftRect anchors.left: parent.left anchors.bottom: parent.bottom - height: FishUI.Theme.smallRadius - width: FishUI.Theme.smallRadius + height: FishUI.Theme.mediumRadius + width: FishUI.Theme.mediumRadius color: FishUI.Theme.secondBackgroundColor } } @@ -117,12 +147,16 @@ Item { text: qsTr("Empty folder") font.pointSize: 15 anchors.centerIn: parent - visible: false + visible: dirModel.status === FM.FolderModel.Ready + && _viewLoader.status === Loader.Ready + && _viewLoader.item.count === 0 } FM.FolderModel { id: dirModel viewAdapter: viewAdapter + sortMode: settings.sortMode + // showHiddenFiles: settings.showHiddenFiles Component.onCompleted: { if (arg) @@ -130,6 +164,24 @@ Item { else dirModel.url = dirModel.homePath() } + + // For new folder rename. + onCurrentIndexChanged: { + _viewLoader.item.currentIndex = dirModel.currentIndex + } + } + + Connections { + target: dirModel + + function onNotification(text) { + root.showPassiveNotification(text, 3000) + } + + // Scroll to item. + function onScrollToItem(index) { + _viewLoader.item.currentIndex = index + } } FM.ItemViewAdapter { @@ -164,6 +216,7 @@ Item { id: _viewLoader Layout.fillWidth: true Layout.fillHeight: true + asynchronous: true sourceComponent: switch (settings.viewMethod) { case 0: return _listViewComponent case 1: return _gridViewComponent @@ -179,7 +232,7 @@ Item { } Item { - visible: settings.viewMethod === 0 + visible: true height: statusBarHeight } } @@ -192,11 +245,11 @@ Item { height: statusBarHeight z: 999 - Rectangle { - anchors.fill: parent - color: FishUI.Theme.backgroundColor - opacity: 0.7 - } +// Rectangle { +// anchors.fill: parent +// color: FishUI.Theme.backgroundColor +// opacity: 0.7 +// } MouseArea { anchors.fill: parent @@ -223,17 +276,33 @@ Item { visible: dirModel.selectionCount >= 1 } + FishUI.BusyIndicator { + id: _busyIndicator + Layout.alignment: Qt.AlignLeft + height: statusBarHeight + width: height + running: visible + visible: dirModel.status === FM.FolderModel.Listing + } + + Label { + text: dirModel.selectedItemSize + visible: dirModel.url !== "trash:///" + } + Item { Layout.fillWidth: true } Button { - Layout.fillHeight: true - Layout.alignment: Qt.AlignRight + id: _emptyTrashBtn + implicitHeight: statusBarHeight text: qsTr("Empty Trash") font.pointSize: 10 onClicked: dirModel.emptyTrash() visible: dirModel.url === "trash:///" + && _viewLoader.item + && _viewLoader.item.count > 0 focusPolicy: Qt.NoFocus } } @@ -281,7 +350,7 @@ Item { topMargin: FishUI.Units.smallSpacing leftMargin: FishUI.Units.largeSpacing rightMargin: FishUI.Units.largeSpacing - bottomMargin: FishUI.Units.largeSpacing + bottomMargin: FishUI.Units.smallSpacing spacing: FishUI.Units.largeSpacing onCountChanged: { @@ -358,6 +427,21 @@ Item { onDeleteFile: { dirModel.keyDeletePress() } + onRefresh: { + dirModel.refresh() + } + onKeyPressed: { + dirModel.keyboardSearch(text) + } + onShowHidden: { + dirModel.showHiddenFiles = !dirModel.showHiddenFiles + } + onClose: { + root.close() + } + onUndo: { + dirModel.undo() + } } function openUrl(url) { diff --git a/qml/GlobalSettings.qml b/qml/GlobalSettings.qml index fbf6ef3..2fa5f54 100644 --- a/qml/GlobalSettings.qml +++ b/qml/GlobalSettings.qml @@ -22,10 +22,13 @@ import Qt.labs.settings 1.0 Settings { property int viewMethod: 1 // controls display mode: list or grid - property bool showHidden: false + + // Port to C++ + // property bool showHiddenFiles: false // Name, Date, Size property int orderBy: 0 + property int sortMode: 0 // UI property int width: 900 diff --git a/qml/OptionsMenu.qml b/qml/OptionsMenu.qml index 313d128..5e63f34 100644 --- a/qml/OptionsMenu.qml +++ b/qml/OptionsMenu.qml @@ -34,8 +34,10 @@ FishUI.DesktopMenu { anchors.left: parent.left anchors.leftMargin: FishUI.Units.largeSpacing source: FishUI.Theme.darkMode ? "qrc:/images/dark/grid.svg" : "qrc:/images/light/grid.svg" + sourceSize: Qt.size(width, height) width: 22 height: width + smooth: false } Text { @@ -51,9 +53,11 @@ FishUI.DesktopMenu { anchors.right: parent.right anchors.rightMargin: FishUI.Units.largeSpacing * 1.5 source: FishUI.Theme.darkMode ? "qrc:/images/dark/checked.svg" : "qrc:/images/light/checked.svg" + sourceSize: Qt.size(width, height) width: 22 height: width visible: settings.viewMethod === 1 + smooth: false } onTriggered: settings.viewMethod = 1 @@ -68,8 +72,10 @@ FishUI.DesktopMenu { anchors.left: parent.left anchors.leftMargin: FishUI.Units.largeSpacing source: FishUI.Theme.darkMode ? "qrc:/images/dark/list.svg" : "qrc:/images/light/list.svg" + sourceSize: Qt.size(width, height) width: 22 height: width + smooth: false } Text { @@ -85,31 +91,37 @@ FishUI.DesktopMenu { anchors.right: parent.right anchors.rightMargin: FishUI.Units.largeSpacing * 1.5 source: FishUI.Theme.darkMode ? "qrc:/images/dark/checked.svg" : "qrc:/images/light/checked.svg" + sourceSize: Qt.size(width, height) width: 22 height: width visible: settings.viewMethod === 0 + smooth: false } onTriggered: settings.viewMethod = 0 } - // MenuSeparator {} + MenuSeparator { + Layout.fillWidth: true + } MenuItem { Layout.fillWidth: true - Image { - id: orderByNameIcon - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: FishUI.Units.largeSpacing - source: FishUI.Theme.darkMode ? "qrc:/images/dark/order_by_name.svg" : "qrc:/images/light/order_by_name.svg" - width: 22 - height: width - } +// Image { +// id: orderByNameIcon +// anchors.verticalCenter: parent.verticalCenter +// anchors.left: parent.left +// anchors.leftMargin: FishUI.Units.largeSpacing +// source: FishUI.Theme.darkMode ? "qrc:/images/dark/order_by_name.svg" : "qrc:/images/light/order_by_name.svg" +// sourceSize: Qt.size(width, height) +// width: 22 +// height: width +// smooth: false +// } Text { - anchors.left: orderByNameIcon.right + anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter anchors.leftMargin: FishUI.Units.largeSpacing text: qsTr("Name") @@ -120,30 +132,34 @@ FishUI.DesktopMenu { anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right anchors.rightMargin: FishUI.Units.largeSpacing * 1.5 - source: FishUI.Theme.darkMode ? "qrc:/images/dark/up.svg" : "qrc:/images/light/up.svg" + source: FishUI.Theme.darkMode ? "qrc:/images/dark/checked.svg" : "qrc:/images/light/checked.svg" + sourceSize: Qt.size(width, height) height: width width: 22 - visible: settings.orderBy === 0 + visible: settings.sortMode === 0 + smooth: false } - onTriggered: settings.orderBy = 0 + onTriggered: settings.sortMode = 0 } MenuItem { Layout.fillWidth: true - Image { - id: orderByDateIcon - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: FishUI.Units.largeSpacing - source: FishUI.Theme.darkMode ? "qrc:/images/dark/date.svg" : "qrc:/images/light/date.svg" - width: 22 - height: width - } +// Image { +// id: orderByDateIcon +// anchors.verticalCenter: parent.verticalCenter +// anchors.left: parent.left +// anchors.leftMargin: FishUI.Units.largeSpacing +// source: FishUI.Theme.darkMode ? "qrc:/images/dark/date.svg" : "qrc:/images/light/date.svg" +// sourceSize: Qt.size(width, height) +// width: 22 +// height: width +// smooth: false +// } Text { - anchors.left: orderByDateIcon.right + anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter anchors.leftMargin: FishUI.Units.largeSpacing text: qsTr("Date") @@ -154,30 +170,58 @@ FishUI.DesktopMenu { anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right anchors.rightMargin: FishUI.Units.largeSpacing * 1.5 - source: FishUI.Theme.darkMode ? "qrc:/images/dark/up.svg" : "qrc:/images/light/up.svg" + source: FishUI.Theme.darkMode ? "qrc:/images/dark/checked.svg" : "qrc:/images/light/checked.svg" + sourceSize: Qt.size(width, height) width: 22 height: width - visible: settings.orderBy === 1 + visible: settings.sortMode === 2 + smooth: false } - onTriggered: settings.orderBy = 1 + onTriggered: settings.sortMode = 2 } MenuItem { - Layout.fillWidth: true + Text { + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: FishUI.Units.largeSpacing + text: qsTr("Type") + color: FishUI.Theme.textColor + } Image { - id: orderBySizeIcon anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: FishUI.Units.largeSpacing - source: FishUI.Theme.darkMode ? "qrc:/images/dark/size.svg" : "qrc:/images/light/size.svg" + anchors.right: parent.right + anchors.rightMargin: FishUI.Units.largeSpacing * 1.5 + source: FishUI.Theme.darkMode ? "qrc:/images/dark/checked.svg" : "qrc:/images/light/checked.svg" + sourceSize: Qt.size(width, height) width: 22 height: width + visible: settings.sortMode === 6 + smooth: false } + onTriggered: settings.sortMode = 6 + } + + MenuItem { + Layout.fillWidth: true + +// Image { +// id: orderBySizeIcon +// anchors.verticalCenter: parent.verticalCenter +// anchors.left: parent.left +// anchors.leftMargin: FishUI.Units.largeSpacing +// source: FishUI.Theme.darkMode ? "qrc:/images/dark/size.svg" : "qrc:/images/light/size.svg" +// sourceSize: Qt.size(width, height) +// width: 22 +// height: width +// smooth: false +// } + Text { - anchors.left: orderBySizeIcon.right + anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter anchors.leftMargin: FishUI.Units.largeSpacing text: qsTr("Size") @@ -188,12 +232,14 @@ FishUI.DesktopMenu { anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right anchors.rightMargin: FishUI.Units.largeSpacing * 1.5 - source: FishUI.Theme.darkMode ? "qrc:/images/dark/up.svg" : "qrc:/images/light/up.svg" + source: FishUI.Theme.darkMode ? "qrc:/images/dark/checked.svg" : "qrc:/images/light/checked.svg" + sourceSize: Qt.size(width, height) width: 22 height: width - visible: settings.orderBy === 2 + visible: settings.sortMode === 1 + smooth: false } - onTriggered: settings.orderBy = 2 + onTriggered: settings.sortMode = 1 } } diff --git a/qml/PathBar.qml b/qml/PathBar.qml index 0be3bed..4ad68a2 100644 --- a/qml/PathBar.qml +++ b/qml/PathBar.qml @@ -32,9 +32,19 @@ Item { signal itemClicked(string path) signal editorAccepted(string path) + Rectangle { + anchors.fill: parent + color: FishUI.Theme.darkMode ? Qt.lighter(FishUI.Theme.secondBackgroundColor, 1.3) + : FishUI.Theme.secondBackgroundColor + radius: FishUI.Theme.smallRadius + z: -1 + } + ListView { id: _pathView anchors.fill: parent + anchors.topMargin: 2 + anchors.bottomMargin: 2 model: _pathBarModel orientation: Qt.Horizontal layoutDirection: Qt.LeftToRight @@ -49,14 +59,6 @@ Item { _pathView.positionViewAtEnd() } - Rectangle { - anchors.fill: parent - color: FishUI.Theme.darkMode ? Qt.lighter(FishUI.Theme.secondBackgroundColor, 1.3) - : FishUI.Theme.secondBackgroundColor - radius: FishUI.Theme.smallRadius - z: -1 - } - MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton @@ -64,10 +66,19 @@ Item { z: -1 } + highlight: Rectangle { + radius: FishUI.Theme.smallRadius + color: Qt.rgba(FishUI.Theme.highlightColor.r, + FishUI.Theme.highlightColor.g, + FishUI.Theme.highlightColor.b, FishUI.Theme.darkMode ? 0.3 : 0.1) + smooth: true + } + delegate: MouseArea { id: _item - height: ListView.view.height + height: ListView.view.height - ListView.view.topMargin - ListView.view.bottomMargin width: _name.width + FishUI.Units.largeSpacing + hoverEnabled: true z: -1 property bool selected: index === _pathView.count - 1 @@ -76,18 +87,23 @@ Item { Rectangle { anchors.fill: parent - anchors.topMargin: 2 - anchors.bottomMargin: 2 - color: FishUI.Theme.highlightColor radius: FishUI.Theme.smallRadius - visible: selected + color: _item.pressed ? Qt.rgba(FishUI.Theme.textColor.r, + FishUI.Theme.textColor.g, + FishUI.Theme.textColor.b, FishUI.Theme.darkMode ? 0.05 : 0.1) : + _item.containsMouse ? Qt.rgba(FishUI.Theme.textColor.r, + FishUI.Theme.textColor.g, + FishUI.Theme.textColor.b, FishUI.Theme.darkMode ? 0.1 : 0.05) : + "transparent" + + smooth: true } Label { id: _name text: model.name - color: selected ? FishUI.Theme.highlightedTextColor : FishUI.Theme.textColor anchors.centerIn: parent + color: selected ? FishUI.Theme.highlightColor : FishUI.Theme.textColor } } } diff --git a/qml/SideBar.qml b/qml/SideBar.qml index d46a136..c2c574d 100644 --- a/qml/SideBar.qml +++ b/qml/SideBar.qml @@ -20,6 +20,8 @@ import QtQuick 2.12 import QtQuick.Layouts 1.12 import QtQuick.Controls 2.12 +import QtQuick.Window 2.12 +import QtGraphicalEffects 1.0 import FishUI 1.0 as FishUI import Cutefish.FileManager 1.0 @@ -28,6 +30,15 @@ ListView { id: sideBar signal clicked(string path) + signal openInNewWindow(string path) + + FishUI.WheelHandler { + target: sideBar + } + + Fm { + id: _fm + } PlacesModel { id: placesModel @@ -51,8 +62,36 @@ ListView { highlightResizeDuration : 0 highlight: Rectangle { - radius: FishUI.Theme.smallRadius - color: FishUI.Theme.highlightColor + radius: FishUI.Theme.mediumRadius + color: FishUI.Theme.secondBackgroundColor + smooth: true + + Rectangle { + anchors.fill: parent + radius: FishUI.Theme.mediumRadius + color: Qt.rgba(FishUI.Theme.highlightColor.r, + FishUI.Theme.highlightColor.g, + FishUI.Theme.highlightColor.b, FishUI.Theme.darkMode ? 0.3 : 0.2) + } + } + + section.property: "category" + section.delegate: Item { + width: ListView.view.width - ListView.view.leftMargin - ListView.view.rightMargin + height: FishUI.Units.fontMetrics.height + FishUI.Units.largeSpacing + FishUI.Units.smallSpacing + + Text { + anchors.left: parent.left + anchors.top: parent.top + anchors.leftMargin: Qt.application.layoutDirection === Qt.RightToLeft ? 0 : FishUI.Units.smallSpacing + anchors.rightMargin: FishUI.Units.smallSpacing + anchors.topMargin: FishUI.Units.largeSpacing + anchors.bottomMargin: FishUI.Units.smallSpacing + color: FishUI.Theme.textColor + font.pointSize: 9 + font.bold: true + text: section + } } delegate: Item { @@ -67,13 +106,70 @@ ListView { id: _mouseArea anchors.fill: parent hoverEnabled: true - acceptedButtons: Qt.LeftButton + acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: { - if (model.isDevice && model.setupNeeded) - placesModel.requestSetup(index) + if (mouse.button === Qt.LeftButton) { + if (model.isDevice && model.setupNeeded) + placesModel.requestSetup(index) + else + sideBar.clicked(model.path ? model.path : model.url) + } else if (mouse.button === Qt.RightButton) { + _menu.popup() + } + } + } + + FishUI.DesktopMenu { + id: _menu + + MenuItem { + text: qsTr("Open") - // sideBar.currentIndex = index - sideBar.clicked(model.path ? model.path : model.url) + onTriggered: { + if (model.isDevice && model.setupNeeded) + placesModel.requestSetup(index) + else + sideBar.clicked(model.path ? model.path : model.url) + } + } + + MenuItem { + text: qsTr("Open in new window") + + onTriggered: { + sideBar.openInNewWindow(model.path ? model.path : model.url) + } + } + + MenuSeparator { + Layout.fillWidth: true + visible: _ejectMenuItem.visible || _umountMenuItem.visible + } + + MenuItem { + id: _ejectMenuItem + text: qsTr("Eject") + visible: model.isDevice && + !model.setupNeeded && + model.isOpticalDisc && + !model.url.toString() === _fm.rootPath() + + onTriggered: { + placesModel.requestEject(index) + } + } + + MenuItem { + id: _umountMenuItem + text: qsTr("Unmount") + visible: model.isDevice && + !model.setupNeeded && + !model.isOpticalDisc && + !model.url.toString() === _fm.rootPath() + + onTriggered: { + placesModel.requestTeardown(index) + } } } @@ -83,7 +179,7 @@ ListView { color: _mouseArea.pressed ? Qt.rgba(FishUI.Theme.textColor.r, FishUI.Theme.textColor.g, FishUI.Theme.textColor.b, FishUI.Theme.darkMode ? 0.05 : 0.1) : - _mouseArea.containsMouse || checked ? Qt.rgba(FishUI.Theme.textColor.r, + _mouseArea.containsMouse && !checked ? Qt.rgba(FishUI.Theme.textColor.r, FishUI.Theme.textColor.g, FishUI.Theme.textColor.b, FishUI.Theme.darkMode ? 0.1 : 0.05) : "transparent" @@ -100,17 +196,25 @@ ListView { Image { height: 22 width: height - sourceSize: Qt.size(width, height) - // source: model.iconPath ? model.iconPath : "image://icontheme/" + model.iconName - source: "qrc:/images/" + (FishUI.Theme.darkMode || _item.checked ? "dark/" : "light/") + model.iconPath + sourceSize: Qt.size(22, 22) + // source: "qrc:/images/dark/" + model.iconPath +// source: "qrc:/images/" + (FishUI.Theme.darkMode || checked ? "dark/" : "light/") + model.iconPath + source: "qrc:/images/" + model.iconPath Layout.alignment: Qt.AlignVCenter - smooth: true + smooth: false + antialiasing: true + + layer.enabled: true + layer.effect: ColorOverlay { + color: checked ? FishUI.Theme.highlightColor : FishUI.Theme.textColor + } } Label { id: _label text: model.name - color: checked ? FishUI.Theme.highlightedTextColor : FishUI.Theme.textColor + color: checked ? FishUI.Theme.highlightColor : FishUI.Theme.textColor + elide: Text.ElideRight Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter } diff --git a/qml/main.qml b/qml/main.qml index 95df297..4a57e5b 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -34,15 +34,11 @@ FishUI.Window { visible: true title: qsTr("File Manager") + background.opacity: 1 header.height: 36 + FishUI.Units.largeSpacing - background.opacity: 0.95 - FishUI.WindowBlur { - view: root - geometry: Qt.rect(root.x, root.y, root.width, root.height) - windowRadius: root.background.radius - enabled: true - } + LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft + LayoutMirroring.childrenInherit: true property QtObject settings: GlobalSettings { } @@ -117,6 +113,7 @@ FishUI.Window { Layout.fillHeight: true width: 180 + FishUI.Units.largeSpacing onClicked: _folderPage.openUrl(path) + onOpenInNewWindow: _folderPage.model.openInNewWindow(path) } FolderPage { diff --git a/screenshots/Screenshot_20211025_151224.png b/screenshots/Screenshot_20211025_151224.png new file mode 100644 index 0000000..865cdfb Binary files /dev/null and b/screenshots/Screenshot_20211025_151224.png differ diff --git a/templates/TextFile.txt b/templates/TextFile.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/templates/TextFile.txt @@ -0,0 +1 @@ + diff --git a/thumbnailer/thumbnailcache.cpp b/thumbnailer/thumbnailcache.cpp new file mode 100644 index 0000000..d7d4c20 --- /dev/null +++ b/thumbnailer/thumbnailcache.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#include "thumbnailcache.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static ThumbnailCache *SELF = nullptr; + +ThumbnailCache *ThumbnailCache::self() +{ + if (!SELF) { + SELF = new ThumbnailCache; + } + + return SELF; +} + +ThumbnailCache::ThumbnailCache(QObject *parent) + : QObject(parent) +{ + m_thumbnailsDir = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1String("/thumbnails/"); + + QDir dir(m_thumbnailsDir); + if (!dir.exists()) + dir.mkdir(m_thumbnailsDir); +} + +QString ThumbnailCache::requestThumbnail(const QString &filePath, const QSize &requestedSize) +{ + QString path(filePath); + if (path.startsWith("file://")) { + path = path.mid(7); + } + + if (!QFile::exists(path)) { + return QString(); + } + + int width = requestedSize.width(); + int height = requestedSize.height(); + int cacheSize = 0; + + // 首先需要找到目录 + if (width <= 128 && height <= 128) + cacheSize = 128; + else if (width <= 256 && height <= 256) + cacheSize = 256; + else + cacheSize = 512; + + struct CachePool { + QString path; + int minSize; + }; + + const static auto pools = { + CachePool{ QStringLiteral("/normal/"), 128 }, + CachePool{ QStringLiteral("/large/"), 256 }, + CachePool{ QStringLiteral("/x-large/"), 512 }, + CachePool{ QStringLiteral("/xx-large/"), 1024 }, + }; + + QString thumbDir; + int wants = /*devicePixelRatio **/ cacheSize; + for (const auto &p : pools) { + if (p.minSize < wants) { + continue; + } else { + thumbDir = p.path; + break; + } + } + + // 尺寸文件夹 + QString sizeDir = m_thumbnailsDir + thumbDir; + + // 不存在需要创建路径 + if (!QDir(sizeDir).exists()) { + if (QDir().mkpath(sizeDir)) { + QFile f(sizeDir); + f.setPermissions(QFile::ReadUser | QFile::WriteUser | QFile::ExeUser); // 0700 + } + } + + // Md5 + QByteArray origName; + const QFileInfo info(path); + const QString canonicalPath = info.canonicalFilePath(); + origName = QUrl::fromLocalFile(canonicalPath).toEncoded(QUrl::RemovePassword | QUrl::FullyEncoded); + + if (origName.isEmpty()) { + return QString(); + } + + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData(origName); + // Image size + md5.addData(QString::number(width).toStdString().c_str()); + md5.addData(QString::number(height).toStdString().c_str()); + // Time + md5.addData(QString::number(info.lastModified().toTime_t()).toStdString().c_str()); + + QString thumbnailsName = QString::fromLatin1(md5.result().toHex()) + QLatin1String(".png"); + QString thumbnailsPath = m_thumbnailsDir + thumbDir + thumbnailsName; + + if (!QFile::exists(thumbnailsPath)) { + return generateThumbnail(path, thumbnailsPath, requestedSize); + } else { + return thumbnailsPath; + } +} + +QString ThumbnailCache::generateThumbnail(const QString &source, const QString &target, const QSize &requestedSize) +{ + QImageReader reader(source); + if (reader.canRead()) { + // Quality in the jpeg reader is binary. >= 50: high quality, < 50 fast + reader.setQuality(49); + + reader.setScaledSize(reader.size().scaled(requestedSize.width(), + requestedSize.height(), Qt::KeepAspectRatio)); + reader.setAutoTransform(true); + + QImage image(reader.read()); + return writeCacheFile(target, image); + } + + return QString(); +} + +QString ThumbnailCache::writeCacheFile(const QString &path, const QImage &image) +{ + const QString thumbnailPath(path); + QFile thumbnailFile(path); + + if (!thumbnailFile.open(QIODevice::WriteOnly)) { + return QString(); + } + + image.save(&thumbnailFile, image.hasAlphaChannel() ? "PNG" : "JPG"); + thumbnailFile.flush(); + thumbnailFile.close(); + + return thumbnailPath; +} diff --git a/helper/thumbnailerjob.h b/thumbnailer/thumbnailcache.h similarity index 58% rename from helper/thumbnailerjob.h rename to thumbnailer/thumbnailcache.h index 10ead87..8edecfd 100644 --- a/helper/thumbnailerjob.h +++ b/thumbnailer/thumbnailcache.h @@ -17,43 +17,27 @@ * along with this program. If not, see . */ -#ifndef THUMBNAILERJOB_H -#define THUMBNAILERJOB_H +#ifndef THUMBNAILCACHE_H +#define THUMBNAILCACHE_H #include -#include -#include -#include -class ThumbnailerJob : public QThread +class QImageReader; +class ThumbnailCache : public QObject { Q_OBJECT public: - explicit ThumbnailerJob(const QString &fileName, const QSize &size, QObject *parent = nullptr); - ~ThumbnailerJob(); + static ThumbnailCache *self(); + explicit ThumbnailCache(QObject *parent = nullptr); - void run() override; - -signals: - void gotPreview(const QPixmap &pixmap); - void failed(); - -private: - void emitPreview(const QImage &image); + QString requestThumbnail(const QString &filePath, const QSize &requestedSize); + QString generateThumbnail(const QString &source, const QString &target, const QSize &requestedSize); + QString writeCacheFile(const QString &path, const QImage &image); private: - QUrl m_url; - QSize m_size; - // thumbnail cache folder QString m_thumbnailsDir; - QString m_thumbnailsPath; - QString m_thumbnailsName; - - uchar *shmaddr; - size_t shmsize; - int shmid; }; -#endif // THUMBNAILERJOB_H +#endif // THUMBNAILCACHE_H diff --git a/thumbnailer/thumbnailprovider.cpp b/thumbnailer/thumbnailprovider.cpp new file mode 100644 index 0000000..6f48b46 --- /dev/null +++ b/thumbnailer/thumbnailprovider.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#include "thumbnailprovider.h" +#include "thumbnailcache.h" + +#include +#include +#include + +QImage ThumbnailProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize) +{ + if (!requestedSize.isValid()) { + return QImage(); + } + + if (size) + *size = requestedSize; + + QString f = id; + QString thumbnail = ThumbnailCache::self()->requestThumbnail(id, requestedSize); + + if (!thumbnail.isEmpty()) { + return QImage(thumbnail); + } + + return QImage(); +} diff --git a/helper/thumbnailer.h b/thumbnailer/thumbnailprovider.h similarity index 56% rename from helper/thumbnailer.h rename to thumbnailer/thumbnailprovider.h index cb9b100..48e25ee 100644 --- a/helper/thumbnailer.h +++ b/thumbnailer/thumbnailprovider.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2021 CutefishOS Team. * - * Author: revenmartin + * Author: Reion Wong * * 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 @@ -17,28 +17,20 @@ * along with this program. If not, see . */ -#ifndef THUMBNAILER_H -#define THUMBNAILER_H +#ifndef THUMBNAILPROVIDER_H +#define THUMBNAILPROVIDER_H -#include #include -class AsyncImageResponse : public QQuickImageResponse +class ThumbnailProvider : public QQuickImageProvider { public: - AsyncImageResponse(const QString &id, const QSize &requestedSize); - QQuickTextureFactory *textureFactory() const override; + ThumbnailProvider() + : QQuickImageProvider(QQuickImageProvider::Image) + { + } -private: - QString m_id; - QSize m_requestedSize; - QImage m_image; + QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize); }; -class Thumbnailer : public QQuickAsyncImageProvider -{ -public: - QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override; -}; - -#endif // THUMBNAILER_H +#endif // THUMBNAILPROVIDER_H diff --git a/translations/ar_AA.ts b/translations/ar_AA.ts new file mode 100644 index 0000000..79bc601 --- /dev/null +++ b/translations/ar_AA.ts @@ -0,0 +1,485 @@ + + + + + CreateFolderDialog + + + New folder name + اسم المجلد الجديد + + + + New folder + مجلد جديد + + + + Cancel + إلغاء + + + + OK + موافق + + + + DateHelper + + + Now + الآن + + + + 1 minute ago + منذ دقيقة واحدة + + + + %1 minutes ago + منذ %1 دقيقة + + + + 1 hour ago + منذ ساعة واحدة + + + + %1 hours ago + منذ %1 ساعة + + + + 1 day ago + منذ يوم واحد + + + + %1 days ago + منذ %1 يوم + + + + DeleteDialog + + + Do you want to delete it permanently? + متأكد من حذف هذا العنصر بشكل نهائي؟ + + + + Cancel + إلغاء + + + + Delete + حذف + + + + DesktopView + + + Desktop + سطح المكتب + + + + EmptyTrashDialog + + + File Manager + مدير الملفات + + + + Do you want to permanently delete all files from the Trash? + هل تريد حذف جميع الملفات بصفة دائمة من سلة المهملات؟ + + + + Cancel + إلغاء + + + + Empty Trash + إفراغ سلة المهملات + + + + FilePropertiesDialog + + + Properties + خصائص + + + + %1 files + %1 ملف + + + + FolderModel + + + %1 item + %1 عنصر + + + + %1 items + %1 عنصر + + + + The file or folder %1 does not exist. + الملف أو المجلد %1 غير موجود. + + + + Select All + تحديد الكل + + + + File Manager + مدير الملفات + + + + Open + فتح + + + + Open with + فتح بواسطة + + + + Cut + قص + + + + Copy + نسخ + + + + Paste + لصق + + + + New Folder + مجلد جديد + + + + Move To Trash + نقل إلى سلة المهملات + + + + Empty Trash + إفراغ سلة المهملات + + + + Delete + حذف + + + + Rename + تعديل الاسم + + + + Open in Terminal + فتح في الطرفية + + + + Set as Wallpaper + تعيين كخلفية + + + + Properties + خصائص + + + + Change background + تغيير الخلفية + + + + Restore + إستعادة + + + + FolderPage + + + Empty folder + مجلد فارغ + + + + Open + فتح + + + + + Properties + خصائص + + + + File + ملف + + + + New Folder + مجلد جديد + + + + Quit + خروج + + + + Edit + تحرير + + + + Select All + تحديد الكل + + + + Cut + قص + + + + Copy + نسخ + + + + Paste + لصق + + + + Help + مساعدة + + + + About + حول + + + + %1 item + %1 عنصر + + + + %1 items + %1 عنصر + + + + %1 selected + تم تحديد %1 + + + + Empty Trash + إفراغ سلة المهملات + + + + OpenWithDialog + + + No applications + لا توجد تطبيقات مناسبة + + + + Set as default + تعيين كإعداد افتراضي + + + + Cancel + إلغاء + + + + Open + فتح + + + + Open With + فتح بواسطة + + + + OptionsMenu + + + Icons + أيقونات + + + + List + قائمة + + + + Name + الاسم + + + + Date + التاريخ + + + + Type + النوع + + + + Size + الحجم + + + + PlacesModel + + + Home + المنزل + + + + Desktop + سطح المكتب + + + + Documents + المستندات + + + + Downloads + التنزيلات + + + + Music + الموسيقى + + + + Pictures + الصور + + + + Videos + الفيديوهات + + + + Trash + سلة المهمات + + + + + Drives + الأقراص + + + + PropertiesDialog + + + Type: + النوع: + + + + Location: + المكان: + + + + Size: + الحجم: + + + + Calculating... + تُجرى عملية الحساب... + + + + Created: + تاريخ الإنشاء: + + + + Modified: + تاريخ أحدث تعديل: + + + + Accessed: + تاريخ أحدث دخول: + + + + Cancel + إلغاء + + + + OK + موافق + + + + main + + + File Manager + مدير الملفات + + + diff --git a/translations/be_BY.ts b/translations/be_BY.ts index 3ead75d..21fd196 100644 --- a/translations/be_BY.ts +++ b/translations/be_BY.ts @@ -14,12 +14,12 @@ Новая папка - + Cancel Адмена - + OK ОК @@ -62,6 +62,24 @@ %1 дзён таму + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + Адмена + + + + Delete + Выдаліць + + DesktopView @@ -93,151 +111,268 @@ Ачысціць сметніцу + + FilePropertiesDialog + + + Properties + Уласцівасці + + + + %1 files + %1 файлаў + + FolderModel - + %1 item %1 аб'ект - + %1 items %1 аб'ектаў - + + The file or folder %1 does not exist. + + + + Select All Вылучыць усё - + + File Manager + + + + Open Адкрыць - + + Open with + + + + Cut Выразаць - + Copy Капіяваць - + Paste Уставіць - + New Folder Новая папка - + Move To Trash Перамясціць у сметніцу - + Empty Trash Ачысціць сметніцу - + Delete Выдаліць - + Rename Перайменаваць - + Open in Terminal Адкрыць у тэрмінале - + Set as Wallpaper Усталяваць як шпалеры - + Properties Уласцівасці - + Change background Змяніць фон + + + Restore + + FolderPage - + Empty folder Пустая папка - + Open Адкрыць - + + Properties Уласцівасці - + + File + + + + + New Folder + Новая папка + + + + Quit + + + + + Edit + + + + + Select All + Вылучыць усё + + + + Cut + Выразаць + + + + Copy + Капіяваць + + + + Paste + Уставіць + + + + Help + + + + + About + + + + %1 item %1 аб'ект - + %1 items %1 аб'ектаў - + %1 selected %1 вылучаны(-а) - + Empty Trash Ачысціць сметніцу + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + Адмена + + + + Open + Адкрыць + + + + Open With + + + OptionsMenu - + Icons Іконкі - + List Спіс - + Name Імя - + Date Дата - + + Type + + + + Size Памер @@ -250,97 +385,101 @@ Дамашняя папка - + Desktop Працоўны стол - + Documents Дакументы - + Downloads Запампоўкі - + Music Музыка - + Pictures Відарысы - + Videos Відэа - + Trash Сметніца + + + + Drives + + PropertiesDialog - Properties - Уласцівасці + Уласцівасці - + Type: Тып: - + Location: Размяшчэнне: - + Size: Памер: - + Calculating... Вылічэнне... - + Created: Створана: - + Modified: Зменена: - + Accessed: Доступ: - + Cancel Адмена - + OK OK - %1 files - %1 файлаў + %1 файлаў diff --git a/translations/be_Latn.ts b/translations/be_Latn.ts index 0593c40..8284a0e 100644 --- a/translations/be_Latn.ts +++ b/translations/be_Latn.ts @@ -14,12 +14,12 @@ Novaja papka - + Cancel Admiena - + OK OK @@ -62,6 +62,24 @@ %1 dzion tamu + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + Admiena + + + + Delete + Vydalić + + DesktopView @@ -93,151 +111,268 @@ Ačyscić smietnicu + + FilePropertiesDialog + + + Properties + Ulascivasci + + + + %1 files + %1 fajlaŭ + + FolderModel - + %1 item %1 abjekt - + %1 items %1 abjektaŭ - + + The file or folder %1 does not exist. + + + + Select All Vylučyć usio - + + File Manager + + + + Open Adkryć - + + Open with + + + + Cut Vyrazać - + Copy Kapijavać - + Paste Ustavić - + New Folder Novaja papka - + Move To Trash Pieramiascić u smietnicu - + Empty Trash Ačyscić smietnicu - + Delete Vydalić - + Rename Pierajmienavać - + Open in Terminal Adkryć u terminalie - + Set as Wallpaper Ustaliavać jak špaliery - + Properties Ulascivasci - + Change background Zmianić fon + + + Restore + + FolderPage - + Empty folder Pustaja papka - + Open Adkryć - + + Properties Ulascivasci - + + File + + + + + New Folder + Novaja papka + + + + Quit + + + + + Edit + + + + + Select All + Vylučyć usio + + + + Cut + Vyrazać + + + + Copy + Kapijavać + + + + Paste + Ustavić + + + + Help + + + + + About + + + + %1 item %1 abjekt - + %1 items %1 abjektaŭ - + %1 selected %1 vylučany - + Empty Trash Ačyscić smietnicu + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + Admiena + + + + Open + Adkryć + + + + Open With + + + OptionsMenu - + Icons Ikonki - + List Spis - + Name Imia - + Date Data - + + Type + + + + Size Pamier @@ -250,97 +385,101 @@ Damašniaja papka - + Desktop Pracoŭny stol - + Documents Dakumienty - + Downloads Zapampoŭki - + Music Muzyka - + Pictures Vidarysy - + Videos Videa - + Trash Smietnica + + + + Drives + + PropertiesDialog - Properties - Ulascivasci + Ulascivasci - + Type: Typ: - + Location: Razmiaščennie: - + Size: Pamier: - + Calculating... Vyličennie... - + Created: Stvorana: - + Modified: Zmieniena: - + Accessed: Dostup: - + Cancel Admiena - + OK OK - %1 files - %1 fajlaŭ + %1 fajlaŭ diff --git a/translations/bg_BG.ts b/translations/bg_BG.ts new file mode 100644 index 0000000..c14252e --- /dev/null +++ b/translations/bg_BG.ts @@ -0,0 +1,485 @@ + + + + + CreateFolderDialog + + + New folder name + Име на нова папка + + + + New folder + Нова папка + + + + Cancel + Отмени + + + + OK + Да + + + + DateHelper + + + Now + Сега + + + + 1 minute ago + преди 1 минута + + + + %1 minutes ago + %1 минути преди + + + + 1 hour ago + преди 1 час + + + + %1 hours ago + преди %1 часа + + + + 1 day ago + преди 1 ден + + + + %1 days ago + преди %1 дни + + + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + Отмени + + + + Delete + Изтрийте + + + + DesktopView + + + Desktop + Работен плот + + + + EmptyTrashDialog + + + File Manager + Файлов мениджър + + + + Do you want to permanently delete all files from the Trash? + Искате ли да изтриете окончателно всички файлове от кошчето? + + + + Cancel + Отмени + + + + Empty Trash + Празен кошчето + + + + FilePropertiesDialog + + + Properties + Свойства + + + + %1 files + %1 файлове + + + + FolderModel + + + %1 item + %1 елемент + + + + %1 items + %1 елементи + + + + The file or folder %1 does not exist. + + + + + Select All + Избери всички + + + + File Manager + Файлов мениджър + + + + Open + Отвори + + + + Open with + Отворете с + + + + Cut + Изрежете + + + + Copy + Копирайте + + + + Paste + + + + + New Folder + Нова папка + + + + Move To Trash + Преместване в кошчето + + + + Empty Trash + Празен кошчето + + + + Delete + Изтрийте + + + + Rename + Преименувайте + + + + Open in Terminal + Отваряне в терминал + + + + Set as Wallpaper + Задаване като тапет + + + + Properties + Свойства + + + + Change background + Смяна на фона + + + + Restore + + + + + FolderPage + + + Empty folder + Празна папка + + + + Open + Отвори + + + + + Properties + Свойства + + + + File + Файл + + + + New Folder + Нова папка + + + + Quit + + + + + Edit + Редактиране + + + + Select All + Изберете всички + + + + Cut + Изрежете + + + + Copy + Копирайте + + + + Paste + + + + + Help + Помощ + + + + About + За + + + + %1 item + %1 елемент + + + + %1 items + %1 елемента + + + + %1 selected + %1 избран + + + + Empty Trash + Празен кошчето + + + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + Отмени + + + + Open + Отвори + + + + Open With + + + + + OptionsMenu + + + Icons + + + + + List + + + + + Name + + + + + Date + + + + + Type + + + + + Size + + + + + PlacesModel + + + Home + + + + + Desktop + Работен плот + + + + Documents + + + + + Downloads + + + + + Music + + + + + Pictures + + + + + Videos + + + + + Trash + + + + + + Drives + + + + + PropertiesDialog + + + Type: + + + + + Location: + + + + + Size: + + + + + Calculating... + + + + + Created: + + + + + Modified: + + + + + Accessed: + + + + + Cancel + Отмени + + + + OK + Да + + + + main + + + File Manager + Файлов мениджър + + + diff --git a/translations/bs_BA.ts b/translations/bs_BA.ts index be78ef9..581c264 100644 --- a/translations/bs_BA.ts +++ b/translations/bs_BA.ts @@ -14,12 +14,12 @@ Nova fascikla - + Cancel Otkaži - + OK U redu @@ -62,6 +62,24 @@ Prije %1 dana + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + Otkaži + + + + Delete + Obriši + + DesktopView @@ -93,151 +111,268 @@ Isprazni smeće + + FilePropertiesDialog + + + Properties + Svojstva + + + + %1 files + %1 fajlova + + FolderModel - + %1 item %1 stavka - + %1 items %1 stavki - + + The file or folder %1 does not exist. + + + + Select All Izaberi sve - + + File Manager + Upravitelj fajlova + + + Open Otvori - + + Open with + + + + Cut Izreži - + Copy Kopiraj - + Paste Zalijepi - + New Folder Nova fascikla - + Move To Trash Premjesti u smeće - + Empty Trash Isprazni smeće - + Delete Obriši - + Rename Preimenuj - + Open in Terminal Otvori u terminalu - + Set as Wallpaper Postavi kao pozadinu - + Properties Svojstva - + Change background Promijeni pozadinu + + + Restore + + FolderPage - + Empty folder Prazna fascikla - + Open Otvori - + + Properties Svojstva - + + File + + + + + New Folder + Nova fascikla + + + + Quit + + + + + Edit + + + + + Select All + Izaberi sve + + + + Cut + Izreži + + + + Copy + Kopiraj + + + + Paste + Zalijepi + + + + Help + + + + + About + + + + %1 item %1 stavka - + %1 items %1 stavki - + %1 selected %1 odabrano - + Empty Trash Isprazni smeće + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + Otkaži + + + + Open + Otvori + + + + Open With + + + OptionsMenu - + Icons Ikone - + List Spisak - + Name Ime - + Date Datum - + + Type + + + + Size Veličina @@ -250,97 +385,101 @@ Dom - + Desktop Radna površina - + Documents Dokumenti - + Downloads Preuzimanja - + Music Muzika - + Pictures Slike - + Videos Videozapisi - + Trash Smeće + + + + Drives + + PropertiesDialog - Properties - Svojstva + Svojstva - + Type: Vrsta: - + Location: Lokacija: - + Size: Veličina: - + Calculating... Računanje... - + Created: Napravljeno: - + Modified: Izmijenjeno: - + Accessed: Pristupljeno: - + Cancel Otkaži - + OK U redu - %1 files - %1 fajlova + %1 fajlova diff --git a/translations/cs_CZ.ts b/translations/cs_CZ.ts index 64f8ad7..db118df 100644 --- a/translations/cs_CZ.ts +++ b/translations/cs_CZ.ts @@ -14,14 +14,14 @@ Nová složka - + Cancel - Zrušit + Storno - + OK - V pořádku + OK @@ -62,6 +62,24 @@ Před %1 dny + + DeleteDialog + + + Do you want to delete it permanently? + Chcete ho nevratně smazat? + + + + Cancel + Storno + + + + Delete + Smazat + + DesktopView @@ -85,7 +103,7 @@ Cancel - Zrušit + Storno @@ -93,151 +111,268 @@ Vysypat Koš + + FilePropertiesDialog + + + Properties + Vlastnosti + + + + %1 files + %1 souborů + + FolderModel - + %1 item %1 položka - + %1 items %1 položek - + + The file or folder %1 does not exist. + Soubor nebo složka %1 neexistuje. + + + Select All Vybrat vše - + + File Manager + Správce souborů + + + Open Otevřít - + + Open with + Otevřít s + + + Cut Vyjmout - + Copy Zkopírovat - + Paste Vložit - + New Folder Nová složka - + Move To Trash Přesunout do Koše - + Empty Trash Vysypat Koš - + Delete Smazat - + Rename Přejmenovat - + Open in Terminal Otevřít v Terminálu - + Set as Wallpaper Nastavit jako pozadí plochy - + Properties Vlastnosti - + Change background Změnit pozadí + + + Restore + Obnovit + FolderPage - + Empty folder - Vyprázdnit složku + Prázdná složka - + Open Otevřít - + + Properties Vlastnosti - + + File + Soubor + + + + New Folder + Nová složka + + + + Quit + Ukončit + + + + Edit + Upravit + + + + Select All + Vybrat vše + + + + Cut + Vyjmout + + + + Copy + Zkopírovat + + + + Paste + Vložit + + + + Help + Nápověda + + + + About + O aplikaci + + + %1 item %1 položka - + %1 items %1 položek - + %1 selected %1 vybráno - + Empty Trash Vysypat Koš + + OpenWithDialog + + + No applications + Žádné aplikace + + + + Set as default + Nastavit jako výchozí + + + + Cancel + Storno + + + + Open + Otevřít + + + + Open With + Otevřít s + + OptionsMenu - + Icons Ikony - + List Seznam - + Name Název - + Date Datum - + + Type + Typ + + + Size Velikost @@ -250,97 +385,101 @@ Domovská složka - + Desktop Plocha - + Documents Dokumenty - + Downloads Stažené - + Music Hudba - + Pictures Obrázky - + Videos Videa - + Trash Koš + + + + Drives + Ovladače + PropertiesDialog - Properties - Vlastnosti + Vlastnosti - + Type: Typ souboru: - + Location: Umístění: - + Size: Velikost: - + Calculating... - Vypočítávám... + Počítání… - + Created: Vytvořeno: - + Modified: Upraveno: - + Accessed: Naposledy otevřeno: - + Cancel - Zrušit + Storno - + OK - V pořádku + OK - %1 files - %1 složek + %1 složek diff --git a/translations/da_DK.ts b/translations/da_DK.ts index 403cc6c..43de1e0 100644 --- a/translations/da_DK.ts +++ b/translations/da_DK.ts @@ -6,22 +6,22 @@ New folder name - + Nyt mappnavn New folder - + Ny mappe - + Cancel - + Annuller - + OK - + OK @@ -29,45 +29,63 @@ Now - + Nu 1 minute ago - + 1 minut siden %1 minutes ago - + %1 minut siden 1 hour ago - + 1 time siden %1 hours ago - + %1 timer siden 1 day ago - + 1 dag siden %1 days ago + %1 dage siden + + + + DeleteDialog + + + Do you want to delete it permanently? + + + Cancel + Annuller + + + + Delete + Slet + DesktopView Desktop - + Skrivebord @@ -75,171 +93,288 @@ File Manager - + File Manager Do you want to permanently delete all files from the Trash? - + Ønsker du at slette alle filer permanent fra papirkurven? Cancel - + Annuller Empty Trash - + Tøm papirkurven + + + + FilePropertiesDialog + + + Properties + Egenskaber + + + + %1 files + %1 filer FolderModel - + %1 item - + %1 element - + %1 items + %1 elementer + + + + The file or folder %1 does not exist. - + Select All - + Vælg alle - + + File Manager + File Manager + + + Open + Åbn + + + + Open with - + Cut - + Skær - + Copy - + Kopier - + Paste - + Indsæt - + New Folder - + Ny mappe - + Move To Trash - + Flyt til papirkurven - + Empty Trash - + Tøm papirkurven - + Delete - + Slet - + Rename - + Omdøb - + Open in Terminal - + Åbn i Terminal - + Set as Wallpaper - + Indstille som tapet - + Properties - + Egenskaber - + Change background + Ændre baggrund + + + + Restore FolderPage - + Empty folder - + Tomme mapper - + Open - + Åbn - + + Properties + Egenskaber + + + + File - - %1 item + + New Folder + Ny mappe + + + + Quit - - %1 items + + Edit - - %1 selected + + Select All + Vælg alle + + + + Cut + Skær + + + + Copy + Kopier + + + + Paste + Indsæt + + + + Help + + + + + About - + + %1 item + %1 element + + + + %1 items + %1 elementer + + + + %1 selected + %1 valgt + + + Empty Trash + Tøm papirkurven + + + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + Annuller + + + + Open + Åbn + + + + Open With OptionsMenu - + Icons - + Ikoner - + List - + Liste - + Name - + Navn - + Date + Dato + + + + Type - + Size - + Størrelse @@ -247,100 +382,104 @@ Home - + Hjem - + Desktop - + Skrivebord - + Documents - + Dokumenter - + Downloads - + Downloads - + Music - + Musik - + Pictures - + Billeder - + Videos - + Videoer - + Trash + Affald + + + + + Drives PropertiesDialog - Properties - + Egenskaber - + Type: - + Type: - + Location: - + Beliggenhed: - + Size: - + Størrelse: - + Calculating... - + Beregning... - + Created: - + Oprettet: - + Modified: - + Ændret: - + Accessed: - + Tilgået: - + Cancel - + Annuller - + OK - + OK - %1 files - + %1 filer @@ -348,7 +487,7 @@ File Manager - + File Manager diff --git a/translations/de_DE.ts b/translations/de_DE.ts index c6cc8c2..32fbb3c 100644 --- a/translations/de_DE.ts +++ b/translations/de_DE.ts @@ -14,12 +14,12 @@ Neuer Ordner - + Cancel Abbrechen - + OK OK @@ -62,12 +62,30 @@ vor %1 Tagen + + DeleteDialog + + + Do you want to delete it permanently? + Wollen Sie es endgültig löschen? + + + + Cancel + Abbrechen + + + + Delete + Löschen + + DesktopView Desktop - Computer-Ansicht + Schreibtisch @@ -93,151 +111,268 @@ Papierkorb leeren + + FilePropertiesDialog + + + Properties + Eigenschaften + + + + %1 files + %1 Dateien + + FolderModel - + %1 item %1 Element - + %1 items %1 Elemente - + + The file or folder %1 does not exist. + Die Datei oder der Ordner %1 existiert nicht. + + + Select All Alle auswählen - + + File Manager + Dateiverwaltung + + + Open Öffnen - + + Open with + Öffnen mit + + + Cut Ausschneiden - + Copy Kopieren - + Paste Einfügen - + New Folder Neuer Ordner - + Move To Trash In Papierkorb verschieben - + Empty Trash Papierkorb leeren - + Delete Löschen - + Rename Umbenennen - + Open in Terminal Im Terminal öffnen - + Set as Wallpaper Als Hintergrundbild festlegen - + Properties Eigenschaften - + Change background Hintergrund ändern + + + Restore + Wiederherstellen + FolderPage - + Empty folder Leerer Ordner - + Open - Ouvrir + Öffnen - + + Properties Eigenschaften - + + File + Datei + + + + New Folder + Neuer Ordner + + + + Quit + Beenden + + + + Edit + Bearbeiten + + + + Select All + Alle auswählen + + + + Cut + Ausschneiden + + + + Copy + Kopieren + + + + Paste + Einfügen + + + + Help + Hilfe + + + + About + Über + + + %1 item %1 Element - + %1 items %1 Elemente - + %1 selected %1 ausgewählt - + Empty Trash Papierkorb leeren + + OpenWithDialog + + + No applications + Keine Anwendungen + + + + Set as default + Als Standard einstellen + + + + Cancel + Abbrechen + + + + Open + Öffnen + + + + Open With + Öffnen mit + + OptionsMenu - + Icons Symbole - + List Liste - + Name Name - + Date Datum - + + Type + Typ + + + Size Größe @@ -250,97 +385,101 @@ Startseite - + Desktop - Computer-Ansicht + Schreibtisch - + Documents Dokumente - + Downloads Heruntergeladene - + Music Musik - + Pictures Bilder - + Videos Videos - + Trash Papierkorb + + + + Drives + Laufwerke + PropertiesDialog - Properties - Eigenschaften + Eigenschaften - + Type: Typ: - + Location: Speicherort: - + Size: Größe: - + Calculating... Berechne … - + Created: Erstellt: - + Modified: Geändert: - + Accessed: Zugegriffen: - + Cancel Abbrechen - + OK OK - %1 files - %1 Dateien + %1 Dateien diff --git a/translations/en_US.ts b/translations/en_US.ts index 1ca0212..1299640 100644 --- a/translations/en_US.ts +++ b/translations/en_US.ts @@ -1,27 +1,27 @@ - + CreateFolderDialog New folder name - + New folder name New folder - + New folder - + Cancel - + Cancel - + OK - + OK @@ -29,45 +29,63 @@ Now - + Now 1 minute ago - + 1 minute ago %1 minutes ago - + %1 minutes ago 1 hour ago - + 1 hour ago %1 hours ago - + %1 hours ago 1 day ago - + 1 day ago %1 days ago - + %1 days ago + + + + DeleteDialog + + + Do you want to delete it permanently? + Do you want to delete it permanently? + + + + Cancel + Cancel + + + + Delete + Delete DesktopView - + Desktop - + Desktop @@ -75,171 +93,321 @@ File Manager - + File Manager - + Do you want to permanently delete all files from the Trash? - + Do you want to permanently delete all files from the Trash? - + Cancel - + Cancel - + Empty Trash - + Empty Trash + + + + FilePropertiesDialog + + + Properties + Properties + + + + %1 files + %1 files FolderModel - + %1 item - + %1 item - + %1 items - + %1 items - + + The file or folder %1 does not exist. + The file or folder %1 does not exist. + + + Select All - + Select All + + + + File Manager + File Manager - + Open - + Open + + + + Open with + Open with - + Cut - + Cut - + Copy - + Copy - + Paste - + Paste - + + New Folder + New Folder + + + + + New Text - - Move To Trash + + + New Documents - + + Move To Trash + Move To Trash + + + Empty Trash - + Empty Trash - + Delete - + Delete - + Rename - + Rename - + Open in Terminal - + Open in Terminal - + Set as Wallpaper - + Set as Wallpaper - + Properties - + Properties - + Change background + Change background + + + + Restore + Restore + + + + Show hidden files + Show hidden files + + + + Open in new window FolderPage - + Empty folder - + Empty folder - + Open - + Open - + + Properties + Properties + + + + File + File + + + + New Folder + New Folder + + + + Quit + Quit + + + + Edit + Edit + + + + Select All + Select All + + + + Cut + Cut + + + + Copy + Copy + + + + Paste + Paste + + + + Help + Help + + + + About + About + + + + File Manager + File Manager + + + + A file manager designed for CutefishOS. - + %1 item - + %1 item - + %1 items - + %1 items - + %1 selected - + %1 selected - + Empty Trash - + Empty Trash + + + + OpenWithDialog + + + No applications + No applications + + + + Set as default + Set as default + + + + Cancel + Cancel + + + + Open + Open + + + + Open With + Open With OptionsMenu - + Icons - + Icons - + List - + List - + Name - + Name - + Date - + Date + + + + Type + Type - + Size - + Size @@ -247,99 +415,123 @@ Home - + Home - + Desktop - + Desktop - + Documents - + Documents - + Downloads - + Downloads - + Music - + Music - + Pictures - + Pictures - + Videos - + Videos - + Trash + Trash + + + + + Drives + Drives + + + + Computer PropertiesDialog - - Properties - - - - + Type: - + Type: - + Location: - + Location: - + Size: - + Size: - + Calculating... - + Calculating... - + Created: - + Created: - + Modified: - + Modified: - + Accessed: - + Accessed: - + Cancel - + Cancel - + OK + OK + + + + SideBar + + + Open + Open + + + + Open in new window - - %1 files + + Eject + + + + + Unmount @@ -348,7 +540,7 @@ File Manager - + File Manager diff --git a/translations/eo_XX.ts b/translations/eo_XX.ts index 3ee6048..df36887 100644 --- a/translations/eo_XX.ts +++ b/translations/eo_XX.ts @@ -14,12 +14,12 @@ - + Cancel - + OK @@ -62,6 +62,24 @@ + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + + + + + Delete + + + DesktopView @@ -93,151 +111,268 @@ + + FilePropertiesDialog + + + Properties + + + + + %1 files + + + FolderModel - + %1 item - + %1 items - + + The file or folder %1 does not exist. + + + + Select All - + + File Manager + + + + Open - + + Open with + + + + Cut - + Copy - + Paste - + New Folder - + Move To Trash - + Empty Trash - + Delete - + Rename - + Open in Terminal - + Set as Wallpaper - + Properties - + Change background + + + Restore + + FolderPage - + Empty folder - + Open - + + Properties - + + File + + + + + New Folder + + + + + Quit + + + + + Edit + + + + + Select All + + + + + Cut + + + + + Copy + + + + + Paste + + + + + Help + + + + + About + + + + %1 item - + %1 items - + %1 selected - + Empty Trash + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + + + + + Open + + + + + Open With + + + OptionsMenu - + Icons - + List - + Name - + Date - + + Type + + + + Size @@ -250,98 +385,94 @@ - + Desktop - + Documents - + Downloads - + Music - + Pictures - + Videos - + Trash - - - PropertiesDialog - - Properties + + + Drives + + + PropertiesDialog - + Type: - + Location: - + Size: - + Calculating... - + Created: - + Modified: - + Accessed: - + Cancel - + OK - - - %1 files - - main diff --git a/translations/es_ES.ts b/translations/es_ES.ts index c21bd95..fe3dfec 100644 --- a/translations/es_ES.ts +++ b/translations/es_ES.ts @@ -14,12 +14,12 @@ Nueva carpeta - + Cancel Cancelar - + OK OK @@ -62,6 +62,24 @@ hace %1 días + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + Cancelar + + + + Delete + Eliminar + + DesktopView @@ -93,151 +111,268 @@ Vaciar Papelera + + FilePropertiesDialog + + + Properties + Propiedades + + + + %1 files + %1 archivos + + FolderModel - + %1 item artículo %1 - + %1 items Artículos %1 - + + The file or folder %1 does not exist. + + + + Select All Seleccionar Todo - + + File Manager + Administrador de Archivos + + + Open Abrir - + + Open with + + + + Cut Cortar - + Copy Copiar - + Paste Pegar - + New Folder Nueva Carpeta - + Move To Trash Mover a la Papelera - + Empty Trash Vaciar Papelera - + Delete Eliminar - + Rename Renombrar - + Open in Terminal Abrir en la Terminal - + Set as Wallpaper Configurar cómo Papel Tapiz - + Properties Propiedades - + Change background Cambiar fondo + + + Restore + + FolderPage - + Empty folder Carpeta vacía - + Open Abrir - + + Properties Propiedades - + + File + + + + + New Folder + Nueva Carpeta + + + + Quit + + + + + Edit + + + + + Select All + Seleccionar Todo + + + + Cut + Cortar + + + + Copy + Copiar + + + + Paste + Pegar + + + + Help + + + + + About + + + + %1 item %1 artículo - + %1 items %1 artículos - + %1 selected %1 seleccionado - + Empty Trash Papelera Vacía + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + Cancelar + + + + Open + Abrir + + + + Open With + + + OptionsMenu - + Icons Iconos - + List Lista - + Name Nombre - + Date Fecha - + + Type + + + + Size Tamaño @@ -250,97 +385,101 @@ Hogar - + Desktop Escritorio - + Documents Documentos - + Downloads Descargas - + Music Música - + Pictures Imágenes - + Videos Vídeos - + Trash Papelera + + + + Drives + + PropertiesDialog - Properties - Propiedades + Propiedades - + Type: Tipo: - + Location: Ubicación: - + Size: Tamaño: - + Calculating... Calculando... - + Created: Creado: - + Modified: Modificado: - + Accessed: Accedido: - + Cancel Cancelar - + OK OK - %1 files - %1 archivos + %1 archivos diff --git a/translations/es_MX.ts b/translations/es_MX.ts index a4d7d45..60e8b2d 100644 --- a/translations/es_MX.ts +++ b/translations/es_MX.ts @@ -14,12 +14,12 @@ Nueva carpeta - + Cancel Cancelar - + OK De acuerdo @@ -62,6 +62,24 @@ Hace %1 días + + DeleteDialog + + + Do you want to delete it permanently? + ¿Quieres eliminarlo permanentemente? + + + + Cancel + Cancelar + + + + Delete + Eliminar + + DesktopView @@ -93,151 +111,268 @@ Papelera Vacía + + FilePropertiesDialog + + + Properties + Propiedades + + + + %1 files + %1 archivos + + FolderModel - + %1 item %1 elemento - + %1 items %1 elementos - + + The file or folder %1 does not exist. + El archivo o carpeta %1 no existe. + + + Select All Seleccionar Todo - + + File Manager + Administrador de archivos + + + Open Abrir - + + Open with + Abrir con + + + Cut Cortar - + Copy Copiar - + Paste Pegar - + New Folder Nueva Carpeta - + Move To Trash Mover a la Papelera - + Empty Trash Papelera vacía - + Delete Eliminar - + Rename Renombrar - + Open in Terminal Abrir en la Terminal - + Set as Wallpaper Establecer como fondo de pantalla - + Properties Propiedades - + Change background Cambiar fondo + + + Restore + Restaurar + FolderPage - + Empty folder Carpeta vacía - + Open Abrir - + + Properties Propiedades - + + File + Archivo + + + + New Folder + Nueva Carpeta + + + + Quit + Quitar + + + + Edit + Editar + + + + Select All + Seleccionar Todo + + + + Cut + Cortar + + + + Copy + Copiar + + + + Paste + Pegar + + + + Help + Ayuda + + + + About + Acerca de + + + %1 item %1 elemento - + %1 items %1 elementos - + %1 selected %1 seleccionado - + Empty Trash Papelera vacía + + OpenWithDialog + + + No applications + Sin aplicaciones + + + + Set as default + Establecer como predeterminado + + + + Cancel + Cancelar + + + + Open + Abrir + + + + Open With + Abrir con + + OptionsMenu - + Icons Iconos - + List Lista - + Name Nombre - + Date Fecha - + + Type + Tipo + + + Size Tamaño @@ -250,97 +385,101 @@ Inicio - + Desktop Escritorio - + Documents Documentos - + Downloads Descargas - + Music Música - + Pictures Imágenes - + Videos Vídeos - + Trash Papelera + + + + Drives + + PropertiesDialog - Properties - Propiedades + Propiedades - + Type: Tipo: - + Location: Ubicación: - + Size: Tamaño: - + Calculating... Calculando... - + Created: Creado: - + Modified: Modificado: - + Accessed: Accedido: - + Cancel Cancelar - + OK De acuerdo - %1 files - %1 archivos + %1 archivos diff --git a/translations/fa_IR.ts b/translations/fa_IR.ts index 1936fe7..736d820 100644 --- a/translations/fa_IR.ts +++ b/translations/fa_IR.ts @@ -14,12 +14,12 @@ پوشه جدید - + Cancel لغو کردن - + OK ساختن @@ -62,6 +62,24 @@ %1 روز قبل + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + لغو کردن + + + + Delete + حذف + + DesktopView @@ -93,151 +111,268 @@ خالی کردن زباله‌دانی + + FilePropertiesDialog + + + Properties + خواص + + + + %1 files + %1 پرونده + + FolderModel - + %1 item %1 مورد - + %1 items %1 مورد - + + The file or folder %1 does not exist. + + + + Select All انتخاب همه - + + File Manager + مدیر پرونده + + + Open باز کردن - + + Open with + + + + Cut برش - + Copy رونوشت - + Paste چسباندن - + New Folder پوشه جدید - + Move To Trash - انتقال به زباله‌دانی + انتقال به سطل زباله - + Empty Trash - خالی کردن زباله‌دانی + خالی کردن سطل زباله - + Delete حذف - + Rename تغییر نام - + Open in Terminal باز کردن در ترمینال - + Set as Wallpaper تنظیم به عنوان تصویر زمینه - + Properties خواص - + Change background تغییر پیش‌زمینه + + + Restore + + FolderPage - + Empty folder خالی کردن پوشه - + Open باز کردن - + + Properties خواص - + + File + + + + + New Folder + پوشه جدید + + + + Quit + + + + + Edit + + + + + Select All + انتخاب همه + + + + Cut + برش + + + + Copy + رونوشت + + + + Paste + چسباندن + + + + Help + + + + + About + + + + %1 item %1 مورد - + %1 items %1 مورد - + %1 selected %1 انتخاب شده - + Empty Trash خالی کردن زباله‌دانی + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + لغو کردن + + + + Open + باز کردن + + + + Open With + + + OptionsMenu - + Icons نمادها - + List فهرست - + Name نام - + Date تاریخ - + + Type + + + + Size اندازه @@ -250,97 +385,101 @@ خانه - + Desktop دسکتاپ - + Documents اسناد - + Downloads بارگیری‌ها - + Music موسیقی - + Pictures تصاویر - + Videos ویدئوها - + Trash زباله‌دانی + + + + Drives + + PropertiesDialog - Properties - خواص + خواص - + Type: نوع: - + Location: مکان: - + Size: اندازه: - + Calculating... در حال محاسبه... - + Created: ساخته شده: - + Modified: اصلاح شده: - + Accessed: دسترسی: - + Cancel لغو کردن - + OK پذیرفتن - %1 files - %1 پرونده + %1 پرونده diff --git a/translations/fi_FI.ts b/translations/fi_FI.ts index 5aea442..cea9d78 100644 --- a/translations/fi_FI.ts +++ b/translations/fi_FI.ts @@ -14,12 +14,12 @@ Uusi kansio - + Cancel Peruuta - + OK OK @@ -62,6 +62,24 @@ %1 päivää sitten + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + Peruuta + + + + Delete + Poista + + DesktopView @@ -93,151 +111,268 @@ Tyhjennä roskakori + + FilePropertiesDialog + + + Properties + Ominaisuudet + + + + %1 files + %1 tiedostoa + + FolderModel - + %1 item %1 kohde - + %1 items %1 kohdetta - + + The file or folder %1 does not exist. + + + + Select All Valitse kaikki - + + File Manager + Tiedostoselain + + + Open Avaa - + + Open with + + + + Cut Leikkaa - + Copy Kopioi - + Paste Liitä - + New Folder Uusi kansio - + Move To Trash Siirrä roskakoriin - + Empty Trash Tyhjennä roskakori - + Delete Poista - + Rename Nimeä uudell. - + Open in Terminal Avaa terminaalissa - + Set as Wallpaper Aseta taustakuvaksi - + Properties Ominaisuudet - + Change background Muuta tausta + + + Restore + + FolderPage - + Empty folder Tyhjä kansio - + Open Avaa - + + Properties Ominaisuudet - + + File + + + + + New Folder + Uusi kansio + + + + Quit + + + + + Edit + + + + + Select All + Valitse kaikki + + + + Cut + Leikkaa + + + + Copy + Kopioi + + + + Paste + Liitä + + + + Help + + + + + About + + + + %1 item %1 kohde - + %1 items %1 kohdetta - + %1 selected %1 valittu - + Empty Trash Tyhjennä roskakori + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + Peruuta + + + + Open + Avaa + + + + Open With + + + OptionsMenu - + Icons Kuvakkeet - + List Lista - + Name Nimi - + Date Päivämäärä - + + Type + + + + Size Koko @@ -250,97 +385,101 @@ Etusivu - + Desktop Työpöytä - + Documents Asiakirjat - + Downloads Lataukset - + Music Musiikki - + Pictures Kuvat - + Videos Videot - + Trash Roskakori + + + + Drives + + PropertiesDialog - Properties - Ominaisuudet + Ominaisuudet - + Type: Tyyppi: - + Location: Sijainti: - + Size: Koko: - + Calculating... Lasketaan… - + Created: Luotu: - + Modified: Muutettu: - + Accessed: Käytetty: - + Cancel Peruuta - + OK OK - %1 files - %1 tiedostoa + %1 tiedostoa diff --git a/translations/fr_FR.ts b/translations/fr_FR.ts index 6d0e32d..b3bfae9 100644 --- a/translations/fr_FR.ts +++ b/translations/fr_FR.ts @@ -14,12 +14,12 @@ Nouveau dossier - + Cancel Annuler - + OK OK @@ -62,12 +62,30 @@ il y a %1 jours + + DeleteDialog + + + Do you want to delete it permanently? + Voulez-vous le supprimer définitivement ? + + + + Cancel + Annuler + + + + Delete + Supprimer + + DesktopView Desktop - Vue ordinateur + Bureau @@ -93,151 +111,268 @@ Vider la corbeille + + FilePropertiesDialog + + + Properties + Propriétés + + + + %1 files + %1 fichiers + + FolderModel - + %1 item %1 élément - + %1 items %1 éléments - + + The file or folder %1 does not exist. + Le fichier ou le dossier %1 n'existe pas. + + + Select All Tout sélectionner - + + File Manager + Gestionnaire de fichiers + + + Open Ouvrir - + + Open with + Ouvrir avec + + + Cut Couper - + Copy Copier - + Paste Coller - + New Folder Nouveau dossier - + Move To Trash Déplacer dans la Corbeille - + Empty Trash Vider la corbeille - + Delete Supprimer - + Rename Renommer - + Open in Terminal Ouvrir dans le terminal - + Set as Wallpaper Définir comme fond d'écran - + Properties Propriétés - + Change background Modifier l'arrière-plan + + + Restore + Restaurer + FolderPage - + Empty folder Dossier vide - + Open Ouvrir - + + Properties Propriétés - + + File + Fichier + + + + New Folder + Nouveau dossier + + + + Quit + Quitter + + + + Edit + Modifier + + + + Select All + Tout sélectionner + + + + Cut + Couper + + + + Copy + Copier + + + + Paste + Coller + + + + Help + Aide + + + + About + À propos + + + %1 item %1 élément - + %1 items %1 éléments - + %1 selected %1 sélectionnés - + Empty Trash Vider la corbeille + + OpenWithDialog + + + No applications + Aucune application + + + + Set as default + Définir comme par défaut + + + + Cancel + Annuler + + + + Open + Ouvrir + + + + Open With + Ouvrir avec + + OptionsMenu - + Icons Icônes - + List Liste - + Name Nom - + Date Date - + + Type + Type + + + Size Taille @@ -250,97 +385,101 @@ Accueil - + Desktop Bureau - + Documents Documents - + Downloads Téléchargements - + Music Musique - + Pictures Images - + Videos Vidéos - + Trash Corbeille + + + + Drives + Disques + PropertiesDialog - Properties - Propriétés + Propriétés - + Type: Type : - + Location: Emplacement : - + Size: Taille : - + Calculating... Calcul… - + Created: Créé le : - + Modified: Modifié le : - + Accessed: Accès le : - + Cancel Annuler - + OK OK - %1 files - %1 fichiers + %1 fichiers diff --git a/translations/he_IL.ts b/translations/he_IL.ts new file mode 100644 index 0000000..a56bf72 --- /dev/null +++ b/translations/he_IL.ts @@ -0,0 +1,485 @@ + + + + + CreateFolderDialog + + + New folder name + שם תיקייה חדשה + + + + New folder + תיקייה חדשה + + + + Cancel + ביטול + + + + OK + אישור + + + + DateHelper + + + Now + עכשיו + + + + 1 minute ago + לפני דקה + + + + %1 minutes ago + לפני %1 דקות + + + + 1 hour ago + לפני שעה + + + + %1 hours ago + לפני %1 שעות + + + + 1 day ago + לפני יום אחד + + + + %1 days ago + לפני %1 ימים + + + + DeleteDialog + + + Do you want to delete it permanently? + האם ברצונך למחוק אותו לצמיתות? + + + + Cancel + ביטול + + + + Delete + מחק + + + + DesktopView + + + Desktop + שולחן העבודה + + + + EmptyTrashDialog + + + File Manager + מנהל הקבצים + + + + Do you want to permanently delete all files from the Trash? + האם אתה בטוח כי ברצונך למחוק לצמיתות את כל הקבצים בפח האשפה? + + + + Cancel + ביטול + + + + Empty Trash + רוקן את פח האשפה + + + + FilePropertiesDialog + + + Properties + מאפיינים + + + + %1 files + %1 קבצים + + + + FolderModel + + + %1 item + פריט אחד + + + + %1 items + %1 פריטים + + + + The file or folder %1 does not exist. + הקובץ או התיקייה %1 לא קיימת. + + + + Select All + בחר הכל + + + + File Manager + מנהל הקבצים + + + + Open + פתח + + + + Open with + פתח באמצעות + + + + Cut + גזור + + + + Copy + העתק + + + + Paste + הדבק + + + + New Folder + תיקייה חדשה + + + + Move To Trash + העבר לאשפה + + + + Empty Trash + רוקן את פח האשפה + + + + Delete + מחק + + + + Rename + שנה שם + + + + Open in Terminal + פתח בשורת הפקודות + + + + Set as Wallpaper + קבע כרקע שולחן העבודה + + + + Properties + מאפיינים + + + + Change background + שנה רקע + + + + Restore + שחזר + + + + FolderPage + + + Empty folder + מחק את הקבצים בתיקייה + + + + Open + פתח + + + + + Properties + מאפיינים + + + + File + קובץ + + + + New Folder + קובץ חדש + + + + Quit + יציאה + + + + Edit + ערוך + + + + Select All + בחר הכל + + + + Cut + גזור + + + + Copy + העתק + + + + Paste + הדבק + + + + Help + עזרה + + + + About + אודות + + + + %1 item + פריט אחד + + + + %1 items + %1 פריטים + + + + %1 selected + %1 נבחרו + + + + Empty Trash + רוקן את פח האשפה + + + + OpenWithDialog + + + No applications + אין אפליקציות + + + + Set as default + קבע כברירת מחדל + + + + Cancel + ביטול + + + + Open + פתח + + + + Open With + פתח באמצעות + + + + OptionsMenu + + + Icons + אייקונים + + + + List + רשימה + + + + Name + שם + + + + Date + תאריך + + + + Type + סוג + + + + Size + גודל + + + + PlacesModel + + + Home + בית + + + + Desktop + שולחן העבודה + + + + Documents + מסמכים + + + + Downloads + הורדות + + + + Music + מוזיקה + + + + Pictures + תמונות + + + + Videos + סרטונים + + + + Trash + פח האשפה + + + + + Drives + כוננים + + + + PropertiesDialog + + + Type: + סוג: + + + + Location: + מיקום: + + + + Size: + גודל: + + + + Calculating... + מחשב... + + + + Created: + תאריך יצירה: + + + + Modified: + תאריך שינוי: + + + + Accessed: + פעם אחרונה נפתח: + + + + Cancel + ביטול + + + + OK + אישור + + + + main + + + File Manager + מנהל הקבצים + + + diff --git a/translations/hi_IN.ts b/translations/hi_IN.ts index 776f6b9..022c72d 100644 --- a/translations/hi_IN.ts +++ b/translations/hi_IN.ts @@ -6,22 +6,22 @@ New folder name - + नया फ़ोल्डर का नाम New folder - + नया फोल्डर - + Cancel - + निरस्त करें - + OK - + ठीक @@ -29,37 +29,55 @@ Now - + अभी 1 minute ago - + 1 मिनट पहले %1 minutes ago - + %1 मिनट पहले - + 1 hour ago - + 1 घंटा पहले %1 hours ago - + %1 घंटा पहले 1 day ago - + 1 दिन पहले %1 days ago - + %1 दिन पहले + + + + DeleteDialog + + + Do you want to delete it permanently? + क्या आप इसे स्थायी रूप से मिटाना चाहते हैं? + + + + Cancel + निरस्त करें + + + + Delete + मिटाये @@ -67,7 +85,7 @@ Desktop - + डेस्कटॉप @@ -75,171 +93,288 @@ File Manager - + फ़ाइल प्रबंधक Do you want to permanently delete all files from the Trash? - + क्या आप ट्रैश से सभी फ़ाइलें स्थायी रूप से मिटाना चाहते हैं? Cancel - + निरस्त करें Empty Trash - + ट्रैश खाली करें + + + + FilePropertiesDialog + + + Properties + गुण + + + + %1 files + %1 फ़ाइलें FolderModel - + %1 item - + %1 वस्तु - + %1 items - + %1 वस्तुये + + + + The file or folder %1 does not exist. + फ़ाइल या फ़ोल्डर %1 मौजूद नहीं है। - + Select All - + सब चुने - + + File Manager + फ़ाइल प्रबंधक + + + Open - + खोले + + + + Open with + अन्य अनुप्रयोग में खोले - + Cut - + कट करना - + Copy - + प्रतिलिपि बनाना - + Paste - + (पेस्ट) यहाँ रखे - + New Folder - + नया फोल्डर - + Move To Trash - + ट्रैश में भेजो - + Empty Trash - + ट्रैश खाली करो - + Delete - + - + Rename - + मिटाये - + Open in Terminal - + टर्मिनल में खोलें - + Set as Wallpaper - + वॉलपेपर के रूप में सेट - + Properties - + गुण - + Change background - + बैकग्राउंड बदलें + + + + Restore + लौटाए FolderPage - + Empty folder - + फ़ोल्डर खाली करे - + Open - + खोले - + + Properties - + गुण + + + + File + फ़ाइल + + + + New Folder + नया फोल्डर + + + + Quit + बंद करे + + + + Edit + संपादित करें + + + + Select All + सब चुने + + + + Cut + कट करें + + + + Copy + कापी करें + + + + Paste + (पेस्ट) यहाँ रखे - + + Help + मदद + + + + About + बारे में + + + %1 item - + %1 वस्तु - + %1 items - + %1 वस्तुए - + %1 selected - + %1 चुने हुए - + Empty Trash - + कचरा (ट्रैश) खाली करें + + + + OpenWithDialog + + + No applications + कोई अनुप्रयोग (एप्लीकेशन) नहीं + + + + Set as default + डिफाल्ट के रूप में सेट + + + + Cancel + निरस्त करें + + + + Open + खोले + + + + Open With + अन्य अनुप्रयोग (एप्लीकेशन) में खोले OptionsMenu - + Icons - + चिह्न - + List - + सूची - + Name - + नाम - + Date - + दिनांक - + + Type + प्रकार + + + Size - + आकार @@ -247,100 +382,96 @@ Home - + होम - + Desktop - + डेस्कटॉप - + Documents - + डाक्यूमेंट - + Downloads - + डाउनलोड - + Music - + संगीत - + Pictures - + चित्र - + Videos - + वीडियो - + Trash - + ट्रैश + + + + + Drives + ड्राइव PropertiesDialog - - Properties - - - - + Type: - + प्रकार: - + Location: - + स्थान: - + Size: - + आकार: - + Calculating... - + परिकलन जारी है... - + Created: - + बनने का समय: - + Modified: - + संसोधन का समय: - + Accessed: - + इस्तेमाल का समय: - + Cancel - + निरस्त करें - + OK - - - - - %1 files - + ठीक @@ -348,7 +479,7 @@ File Manager - + फ़ाइल प्रबंधक diff --git a/translations/hu_HU.ts b/translations/hu_HU.ts index b36e078..7c0368e 100644 --- a/translations/hu_HU.ts +++ b/translations/hu_HU.ts @@ -14,12 +14,12 @@ Új mappa - + Cancel Mégsem - + OK OK @@ -34,32 +34,50 @@ 1 minute ago - 1 perce + 1 perccel ezelőtt %1 minutes ago - %1 perce + %1 perccel ezelőtt 1 hour ago - 1 órája + 1 órával ezelőtt %1 hours ago - %1 órája + %1 órával ezelőtt 1 day ago - 1 napja + 1 nappal ezelőtt %1 days ago - %1 napja + %1 nappal ezelőtt + + + + DeleteDialog + + + Do you want to delete it permanently? + Végleg törölni szeretné? + + + + Cancel + Mégsem + + + + Delete + Törlés @@ -85,7 +103,7 @@ Cancel - Mégse + Mégsem @@ -93,151 +111,268 @@ Kuka ürítése + + FilePropertiesDialog + + + Properties + Tulajdonságok + + + + %1 files + %1 fájl + + FolderModel - + %1 item %1 elem - + %1 items - %1 elem + %1 elem(ek) + + + + The file or folder %1 does not exist. + A %1 fájl vagy mappa nem létezik. - + Select All - Mind kijelölése + Összes kijelölése - + + File Manager + Fájlkezelő + + + Open Megnyitás - + + Open with + Megnyitás ezzel + + + Cut Kivágás - + Copy Másolás - + Paste Beillesztés - + New Folder Új mappa - + Move To Trash Áthelyezés a Kukába - + Empty Trash Kuka ürítése - + Delete Törlés - + Rename Átnevezés - + Open in Terminal Megnyitás a Terminálban - + Set as Wallpaper Beállítás háttérképként - + Properties Tulajdonságok - + Change background Háttér megváltoztatása + + + Restore + Visszaállítás + FolderPage - + Empty folder Üres mappa - + Open Megnyitás - + + Properties Tulajdonságok - + + File + Fájl + + + + New Folder + Új mappa + + + + Quit + Kilépés + + + + Edit + Szerkesztés + + + + Select All + Összes kijelölése + + + + Cut + Kivágás + + + + Copy + Másolás + + + + Paste + Beillesztés + + + + Help + Segítség + + + + About + Rólunk + + + %1 item %1 elem - + %1 items - %1 elem + %1 elem(ek) - + %1 selected %1 kiválasztva - + Empty Trash Kuka kiürítése + + OpenWithDialog + + + No applications + Nincsenek alkalmazások + + + + Set as default + Beállítás alapértelmezettként + + + + Cancel + Mégsem + + + + Open + Megnyitás + + + + Open With + Megnyitás ezzel + + OptionsMenu - + Icons Ikonok - + List - Nézet + Lista - + Name Név - + Date Dátum - + + Type + Típus + + + Size Méret @@ -250,97 +385,101 @@ Saját mappa - + Desktop Asztal - + Documents Dokumentumok - + Downloads Letöltések - + Music Zene - + Pictures Képek - + Videos Videók - + Trash Kuka + + + + Drives + Meghajtók + PropertiesDialog - Properties - Tulajdonságok + Tulajdonságok - + Type: Típus: - + Location: Hely: - + Size: Méret: - + Calculating... Számítás... - + Created: Létrehozva: - + Modified: Módosítva: - + Accessed: - Elérhető: + Hozzáférés: - + Cancel - Mégse + Mégsem - + OK OK - %1 files - %1 fájl + %1 fájl diff --git a/translations/id_ID.ts b/translations/id_ID.ts index 474d79b..343f4a6 100644 --- a/translations/id_ID.ts +++ b/translations/id_ID.ts @@ -14,12 +14,12 @@ Folder baru - + Cancel Batal - + OK OK @@ -62,6 +62,24 @@ %1 hari yang lalu + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + Batal + + + + Delete + Hapus + + DesktopView @@ -93,151 +111,268 @@ Sampah Kosong + + FilePropertiesDialog + + + Properties + Properti + + + + %1 files + %1 berkas + + FolderModel - + %1 item %1 butir - + %1 items %1 butir - + + The file or folder %1 does not exist. + + + + Select All Pilih Semua - + + File Manager + Manajer Berkas + + + Open Buka - + + Open with + + + + Cut Potong - + Copy Salin - + Paste Tempel - + New Folder Folder Baru - + Move To Trash Pindahkan ke Sampah - + Empty Trash Sampah Kosong - + Delete Hapus - + Rename Ubah Nama - + Open in Terminal Buka di Terminal - + Set as Wallpaper Pasang sebagai Wallpaper - + Properties Properti - + Change background Ubah latar belakang + + + Restore + + FolderPage - + Empty folder Folder kosong - + Open Buka - + + Properties Properti - + + File + + + + + New Folder + Folder Baru + + + + Quit + + + + + Edit + + + + + Select All + Pilih Semua + + + + Cut + Potong + + + + Copy + Salin + + + + Paste + Tempel + + + + Help + + + + + About + + + + %1 item %1 butir - + %1 items %1 butir - + %1 selected %1 terpilih - + Empty Trash Sampah Kosong + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + Batal + + + + Open + Buka + + + + Open With + + + OptionsMenu - + Icons Ikon - + List Daftar - + Name Nama - + Date Tanggal - + + Type + + + + Size Ukuran @@ -250,97 +385,101 @@ Rumah - + Desktop Desktop - + Documents Dokumen - + Downloads Unduhan - + Music Musik - + Pictures Gambar - + Videos Video - + Trash Sampah + + + + Drives + + PropertiesDialog - Properties - Properti + Properti - + Type: Tipe: - + Location: Lokasi: - + Size: Ukuran: - + Calculating... Menghitung... - + Created: Dibuat: - + Modified: Diubah: - + Accessed: Diakses: - + Cancel Batal - + OK OK - %1 files - %1 berkas + %1 berkas diff --git a/translations/ie.ts b/translations/ie.ts index 6de9688..2d6502a 100644 --- a/translations/ie.ts +++ b/translations/ie.ts @@ -14,12 +14,12 @@ Nov fólder - + Cancel Anullar - + OK OK @@ -62,6 +62,24 @@ ante %1 dies + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + Anullar + + + + Delete + Remover + + DesktopView @@ -93,151 +111,268 @@ Vacuar li Paper-corb + + FilePropertiesDialog + + + Properties + Proprietás + + + + %1 files + %1 files + + FolderModel - + %1 item %1 element - + %1 items %1 elementes - + + The file or folder %1 does not exist. + + + + Select All Selecter omnicos - + + File Manager + Gerente de files + + + Open Aperter - + + Open with + + + + Cut Exciser - + Copy Copiar - + Paste Collar - + New Folder Crear un fólder - + Move To Trash Mover al Paper-corb - + Empty Trash Vacuar li Paper-corb - + Delete Remover - + Rename Renominar - + Open in Terminal Aperter in li terminale - + Set as Wallpaper Assignar quam tapete - + Properties Proprietás - + Change background Cambiar li funde + + + Restore + + FolderPage - + Empty folder Vacui fólder - + Open Aperter - + + Properties Proprietás - + + File + + + + + New Folder + Crear un fólder + + + + Quit + + + + + Edit + + + + + Select All + Selecter omnicos + + + + Cut + Exciser + + + + Copy + Copiar + + + + Paste + Collar + + + + Help + + + + + About + + + + %1 item %1 element - + %1 items %1 elementes - + %1 selected %1 selectet - + Empty Trash Vacuar li Paper-corb + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + Anullar + + + + Open + Aperter + + + + Open With + + + OptionsMenu - + Icons Icones - + List Liste - + Name Nómine - + Date Date - + + Type + + + + Size Grandore @@ -250,97 +385,101 @@ Hem-fólder - + Desktop Pupitre - + Documents Documentes - + Downloads Descargates - + Music Musica - + Pictures Images - + Videos Videos - + Trash Paper-corb + + + + Drives + + PropertiesDialog - Properties - Proprietás + Proprietás - + Type: Tip: - + Location: Localisation: - + Size: Grandore: - + Calculating... Calculante... - + Created: Creat: - + Modified: Modificat: - + Accessed: Accessat: - + Cancel Anullar - + OK OK - %1 files - %1 files + %1 files diff --git a/translations/it_IT.ts b/translations/it_IT.ts index d8e53cf..de2d2d7 100644 --- a/translations/it_IT.ts +++ b/translations/it_IT.ts @@ -14,12 +14,12 @@ Nuova cartella - + Cancel Annulla - + OK OK @@ -62,6 +62,24 @@ %1 giorni fa + + DeleteDialog + + + Do you want to delete it permanently? + Vuoi rimuoverlo in modo permanente? + + + + Cancel + Annulla + + + + Delete + Elimina + + DesktopView @@ -93,151 +111,268 @@ Svuota il Cestino + + FilePropertiesDialog + + + Properties + Proprietà + + + + %1 files + %1 file + + FolderModel - + %1 item %1 elemento - + %1 items %1 elementi - + + The file or folder %1 does not exist. + Il file o la cartella %1 non esiste. + + + Select All Seleziona tutti - + + File Manager + Gestore di file + + + Open Apri - + + Open with + Apri con + + + Cut Taglia - + Copy Copia - + Paste Incolla - + New Folder Nuova cartella - + Move To Trash Sposta nel Cestino - + Empty Trash Svuota il Cestino - + Delete Elimina - + Rename Rinomina - + Open in Terminal Apri nel Terminale - + Set as Wallpaper Imposta come sfondo - + Properties Proprietà - + Change background Cambia lo sfondo + + + Restore + Ripristina + FolderPage - + Empty folder Cartella vuota - + Open Apri - + + Properties Proprietà - + + File + File + + + + New Folder + Nuova cartella + + + + Quit + Esci + + + + Edit + Modifica + + + + Select All + Seleziona tutti + + + + Cut + Taglia + + + + Copy + Copia + + + + Paste + Incolla + + + + Help + Aiuto + + + + About + Informazioni + + + %1 item %1 elemento - + %1 items %1 elementi - + %1 selected %1 selezionati - + Empty Trash Svuota il Cestino + + OpenWithDialog + + + No applications + Nessuna applicazione + + + + Set as default + Imposta come predefinito + + + + Cancel + Annulla + + + + Open + Apri + + + + Open With + Apri con + + OptionsMenu - + Icons Icone - + List Lista - + Name Nome - + Date Data - + + Type + Tipo + + + Size Dimensione @@ -250,97 +385,101 @@ Pagina principale - + Desktop Desktop - + Documents Documenti - + Downloads Scaricamenti - + Music Musica - + Pictures Immagini - + Videos Video - + Trash Cestino + + + + Drives + Unità + PropertiesDialog - Properties - Proprietà + Proprietà - + Type: Tipo: - + Location: Posizione: - + Size: Dimensione: - + Calculating... Calcolo in corso… - + Created: Creato: - + Modified: Modificato: - + Accessed: Accesso: - + Cancel Annulla - + OK OK - %1 files - %1 file + %1 file diff --git a/translations/ja_JP.ts b/translations/ja_JP.ts new file mode 100644 index 0000000..6c737f0 --- /dev/null +++ b/translations/ja_JP.ts @@ -0,0 +1,495 @@ + + + + + CreateFolderDialog + + + New folder name + 新しいフォルダ名 + + + + New folder + 新しいフォルダ + + + + Cancel + 取り消し + + + + OK + はい + + + + DateHelper + + + Now + + + + + 1 minute ago + 1分前 + + + + %1 minutes ago + %1 分前 + + + + 1 hour ago + 1 時間前 + + + + %1 hours ago + %1時間前 + + + + 1 day ago + 1日前 + + + + %1 days ago + %1日前 + + + + DeleteDialog + + + Do you want to delete it permanently? + 永久に削除しますか? + + + + Cancel + 取り消し + + + + Delete + 削除 + + + + DesktopView + + + Desktop + デスクトップ + + + + EmptyTrashDialog + + + File Manager + ファイルマネージャー + + + + Do you want to permanently delete all files from the Trash? + ごみ箱からすべてのファイルを永久に削除しますか? + + + + Cancel + 取り消し + + + + Empty Trash + ゴミ箱を空にする + + + + FilePropertiesDialog + + + Properties + プロパティ + + + + %1 files + % 1ファイル + + + + FolderModel + + + %1 item + %1 アイテム + + + + %1 items + %1 アイテム + + + + The file or folder %1 does not exist. + ファイルまたはフォルダ%1は存在しません。 + + + + Select All + すべて選択 + + + + File Manager + ファイルマネージャ + + + + Open + 開く + + + + Open with + + + + + Cut + 切り取り + + + + Copy + コピー + + + + Paste + + + + + New Folder + 新しいフォルダ + + + + Move To Trash + ゴミ箱へ移動 + + + + Empty Trash + ゴミ箱を空にする + + + + Delete + 削除 + + + + Rename + 名前を変更 + + + + Open in Terminal + ターミナルで開く + + + + Set as Wallpaper + 壁紙として設定 + + + + Properties + プロパティ + + + + Change background + 背景を変更 + + + + Restore + 元に戻す + + + + Show hidden files + 隠しファイルを表示 + + + + Open in new window + 新しいウィンドウで開く + + + + FolderPage + + + Empty folder + 空のフォルダー + + + + Open + 開く + + + + + Properties + プロパティ + + + + File + ファイル + + + + New Folder + 新しいフォルダ + + + + Quit + 戻す + + + + Edit + 編集 + + + + Select All + すべて選択 + + + + Cut + 切り取り + + + + Copy + コピー + + + + Paste + + + + + Help + ヘルプ + + + + About + + + + + %1 item + %1 アイテム + + + + %1 items + %1 アイテム + + + + %1 selected + %1 が選択ました + + + + Empty Trash + ゴミ箱を空にする + + + + OpenWithDialog + + + No applications + アプリケーションなし + + + + Set as default + 既定として設定 + + + + Cancel + 取り消し + + + + Open + 開く + + + + Open With + + + + + OptionsMenu + + + Icons + アイコン + + + + List + リスト + + + + Name + 名前 + + + + Date + + + + + Type + 種類 + + + + Size + サイズ + + + + PlacesModel + + + Home + + + + + Desktop + デスクトップ + + + + Documents + 書類 + + + + Downloads + ダウンロード + + + + Music + 音楽 + + + + Pictures + ピクチャー + + + + Videos + ビデオ + + + + Trash + ゴミ箱 + + + + + Drives + + + + + PropertiesDialog + + + Type: + 種類: + + + + Location: + 場所: + + + + Size: + サイズ: + + + + Calculating... + 計算中... + + + + Created: + 作成時間: + + + + Modified: + 変更時間: + + + + Accessed: + アクセス時間: + + + + Cancel + 取り消し + + + + OK + はい + + + + main + + + File Manager + ファイルマネージャ + + + diff --git a/translations/lt_LT.ts b/translations/lt_LT.ts new file mode 100644 index 0000000..7d3ee63 --- /dev/null +++ b/translations/lt_LT.ts @@ -0,0 +1,485 @@ + + + + + CreateFolderDialog + + + New folder name + + + + + New folder + Naujas aplankas + + + + Cancel + Atsisakyti + + + + OK + Gerai + + + + DateHelper + + + Now + Dabar + + + + 1 minute ago + + + + + %1 minutes ago + + + + + 1 hour ago + + + + + %1 hours ago + + + + + 1 day ago + + + + + %1 days ago + + + + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + Atsisakyti + + + + Delete + + + + + DesktopView + + + Desktop + + + + + EmptyTrashDialog + + + File Manager + + + + + Do you want to permanently delete all files from the Trash? + + + + + Cancel + Atsisakyti + + + + Empty Trash + + + + + FilePropertiesDialog + + + Properties + + + + + %1 files + + + + + FolderModel + + + %1 item + + + + + %1 items + + + + + The file or folder %1 does not exist. + + + + + Select All + + + + + File Manager + + + + + Open + + + + + Open with + + + + + Cut + + + + + Copy + + + + + Paste + + + + + New Folder + + + + + Move To Trash + + + + + Empty Trash + + + + + Delete + + + + + Rename + + + + + Open in Terminal + + + + + Set as Wallpaper + + + + + Properties + + + + + Change background + + + + + Restore + + + + + FolderPage + + + Empty folder + + + + + Open + + + + + + Properties + + + + + File + + + + + New Folder + + + + + Quit + + + + + Edit + + + + + Select All + + + + + Cut + + + + + Copy + + + + + Paste + + + + + Help + + + + + About + + + + + %1 item + + + + + %1 items + + + + + %1 selected + + + + + Empty Trash + + + + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + Atsisakyti + + + + Open + + + + + Open With + + + + + OptionsMenu + + + Icons + + + + + List + + + + + Name + + + + + Date + + + + + Type + + + + + Size + + + + + PlacesModel + + + Home + + + + + Desktop + + + + + Documents + + + + + Downloads + + + + + Music + + + + + Pictures + + + + + Videos + + + + + Trash + + + + + + Drives + + + + + PropertiesDialog + + + Type: + + + + + Location: + + + + + Size: + + + + + Calculating... + + + + + Created: + + + + + Modified: + + + + + Accessed: + + + + + Cancel + Atsisakyti + + + + OK + Gerai + + + + main + + + File Manager + + + + diff --git a/translations/lv_LV.ts b/translations/lv_LV.ts new file mode 100644 index 0000000..0188d9a --- /dev/null +++ b/translations/lv_LV.ts @@ -0,0 +1,485 @@ + + + + + CreateFolderDialog + + + New folder name + Jaunās mapes nosaukums + + + + New folder + Jauna mape + + + + Cancel + Atcelt + + + + OK + OK + + + + DateHelper + + + Now + Tagad + + + + 1 minute ago + 1 minūti atpakaļ + + + + %1 minutes ago + %1 minūtes atpakaļ + + + + 1 hour ago + 1 stundu atpakaļ + + + + %1 hours ago + %1 stundas atpakaļ + + + + 1 day ago + 1 dienu atpakaļ + + + + %1 days ago + %1 dienas atpakaļ + + + + DeleteDialog + + + Do you want to delete it permanently? + Vai jūs tiešām vēlaties neatgriezeniski to izdzēst? + + + + Cancel + Atcelt + + + + Delete + Izdzēst + + + + DesktopView + + + Desktop + Darbavirsma + + + + EmptyTrashDialog + + + File Manager + Failu Pārvaldnieks + + + + Do you want to permanently delete all files from the Trash? + Vai jūs tiešām vēlaties neatgriezeniski izdzēst visus failus no Atkritnes? + + + + Cancel + Atcelt + + + + Empty Trash + Iztukšot Atkritni + + + + FilePropertiesDialog + + + Properties + Rekvizīti + + + + %1 files + %1 failu + + + + FolderModel + + + %1 item + %1 vienums + + + + %1 items + %1 vienumu + + + + The file or folder %1 does not exist. + Fails vai mape %1 neeksistē. + + + + Select All + Izvēlēties Visu + + + + File Manager + Failu Pārvaldnieks + + + + Open + Atvērt + + + + Open with + Atvērt ar + + + + Cut + Izgriezt + + + + Copy + Kopēt + + + + Paste + Ielīmēt + + + + New Folder + Jauna Mape + + + + Move To Trash + Pārvietot Atrkritnē + + + + Empty Trash + Iztukšot Atkritni + + + + Delete + Izdzēst + + + + Rename + Pārdēvēt + + + + Open in Terminal + Atvērt Terminālā + + + + Set as Wallpaper + Uzlikt kā fona bildi + + + + Properties + Rekvizīti + + + + Change background + Izmainīt fona bildi + + + + Restore + Atjaunot + + + + FolderPage + + + Empty folder + Tukša mape + + + + Open + Atvērt + + + + + Properties + Rekvizīti + + + + File + Fails + + + + New Folder + Jauna Mape + + + + Quit + Iziet + + + + Edit + Rediģēt + + + + Select All + Atlasīt Visu + + + + Cut + Izgriezt + + + + Copy + Kopēt + + + + Paste + Ielīmēt + + + + Help + Palīdzība + + + + About + Par + + + + %1 item + %1 vienums + + + + %1 items + %1 vienumu + + + + %1 selected + %1 atlasīts + + + + Empty Trash + Iztukšot Atkritni + + + + OpenWithDialog + + + No applications + Nav programmu + + + + Set as default + Uzstatīt kā noklusējuma + + + + Cancel + Atcelt + + + + Open + Atvērt + + + + Open With + Atvērt ar + + + + OptionsMenu + + + Icons + Ikonas + + + + List + Saraksts + + + + Name + Nosaukums + + + + Date + Datums + + + + Type + Tips + + + + Size + Izmērs + + + + PlacesModel + + + Home + Mājas + + + + Desktop + Darbavirsma + + + + Documents + Dokumenti + + + + Downloads + Lejupielādes + + + + Music + Mūzika + + + + Pictures + Attēli + + + + Videos + Videoklipi + + + + Trash + Atkritne + + + + + Drives + Diski + + + + PropertiesDialog + + + Type: + Tips: + + + + Location: + Atrašanās vieta: + + + + Size: + Izmērs: + + + + Calculating... + Aprēķina... + + + + Created: + Izveidots: + + + + Modified: + Modificēts: + + + + Accessed: + Piekļūts: + + + + Cancel + Atcelt + + + + OK + OK + + + + main + + + File Manager + Failu Pārvaldnieks + + + diff --git a/translations/ml_IN.ts b/translations/ml_IN.ts new file mode 100644 index 0000000..499f1aa --- /dev/null +++ b/translations/ml_IN.ts @@ -0,0 +1,485 @@ + + + + + CreateFolderDialog + + + New folder name + + + + + New folder + + + + + Cancel + + + + + OK + + + + + DateHelper + + + Now + + + + + 1 minute ago + + + + + %1 minutes ago + + + + + 1 hour ago + + + + + %1 hours ago + + + + + 1 day ago + + + + + %1 days ago + + + + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + + + + + Delete + + + + + DesktopView + + + Desktop + + + + + EmptyTrashDialog + + + File Manager + + + + + Do you want to permanently delete all files from the Trash? + + + + + Cancel + + + + + Empty Trash + + + + + FilePropertiesDialog + + + Properties + + + + + %1 files + + + + + FolderModel + + + %1 item + + + + + %1 items + + + + + The file or folder %1 does not exist. + + + + + Select All + + + + + File Manager + + + + + Open + + + + + Open with + + + + + Cut + + + + + Copy + + + + + Paste + + + + + New Folder + + + + + Move To Trash + + + + + Empty Trash + + + + + Delete + + + + + Rename + + + + + Open in Terminal + + + + + Set as Wallpaper + + + + + Properties + + + + + Change background + + + + + Restore + + + + + FolderPage + + + Empty folder + + + + + Open + + + + + + Properties + + + + + File + + + + + New Folder + + + + + Quit + + + + + Edit + + + + + Select All + + + + + Cut + + + + + Copy + + + + + Paste + + + + + Help + + + + + About + + + + + %1 item + + + + + %1 items + + + + + %1 selected + + + + + Empty Trash + + + + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + + + + + Open + + + + + Open With + + + + + OptionsMenu + + + Icons + + + + + List + + + + + Name + + + + + Date + + + + + Type + + + + + Size + + + + + PlacesModel + + + Home + + + + + Desktop + + + + + Documents + + + + + Downloads + + + + + Music + + + + + Pictures + + + + + Videos + + + + + Trash + + + + + + Drives + + + + + PropertiesDialog + + + Type: + + + + + Location: + + + + + Size: + + + + + Calculating... + + + + + Created: + + + + + Modified: + + + + + Accessed: + + + + + Cancel + + + + + OK + + + + + main + + + File Manager + + + + diff --git a/translations/nb_NO.ts b/translations/nb_NO.ts index 9325615..f954401 100644 --- a/translations/nb_NO.ts +++ b/translations/nb_NO.ts @@ -14,12 +14,12 @@ Ny mappe - + Cancel Avbryt - + OK OK @@ -62,6 +62,24 @@ %1 dager siden + + DeleteDialog + + + Do you want to delete it permanently? + Ønsker du å slette for godt? + + + + Cancel + Avbryt + + + + Delete + Slett + + DesktopView @@ -93,151 +111,268 @@ Tøm papirkurv + + FilePropertiesDialog + + + Properties + Egenskaper + + + + %1 files + %1 filer + + FolderModel - + %1 item %1 element - + %1 items %1 elementer - + + The file or folder %1 does not exist. + Filen eller mappen «%1» finnes ikke. + + + Select All Velg alle - + + File Manager + Filbehandler + + + Open Åpne - + + Open with + Åpne med + + + Cut Klipp ut - + Copy Kopier - + Paste Lim inn - + New Folder Ny mappe - + Move To Trash Flytt til papirkurv - + Empty Trash Tøm papirkurv - + Delete Slett - + Rename Gi nytt navn - + Open in Terminal Åpne i terminal - + Set as Wallpaper Sett som bakgrunnsbilde - + Properties Egenskaper - + Change background Endre bakgrunn + + + Restore + Gjenopprett + FolderPage - + Empty folder Tom mappe - + Open Åpne - + + Properties Egenskaper - + + File + Fil + + + + New Folder + Ny mappe + + + + Quit + Avslutt + + + + Edit + Rediger + + + + Select All + Velg alle + + + + Cut + Klipp ut + + + + Copy + Kopier + + + + Paste + Lim inn + + + + Help + Hjelp + + + + About + Om + + + %1 item %1 element - + %1 items %1 elementer - + %1 selected %1 valgt - + Empty Trash Tøm papirkurv + + OpenWithDialog + + + No applications + Ingen programmer + + + + Set as default + Sett som forvalg + + + + Cancel + Avbryt + + + + Open + Åpne + + + + Open With + Åpne med + + OptionsMenu - + Icons Ikoner - + List Liste - + Name Navn - + Date Dato - + + Type + Type + + + Size Størrelse @@ -250,97 +385,101 @@ Hjem - + Desktop Skrivebord - + Documents Dokumenter - + Downloads Nedlastinger - + Music Musikk - + Pictures Bilder - + Videos Videoer - + Trash Papirkurv + + + + Drives + Disker + PropertiesDialog - Properties - Egenskaper + Egenskaper - + Type: Type: - + Location: Plassering: - + Size: Størrelse: - + Calculating... Regner ut … - + Created: Opprettet: - + Modified: Endret: - + Accessed: Brukt: - + Cancel Avbryt - + OK OK - %1 files - %1 filer + %1 filer diff --git a/translations/ne_NP.ts b/translations/ne_NP.ts index 3cd839c..9e1567a 100644 --- a/translations/ne_NP.ts +++ b/translations/ne_NP.ts @@ -14,12 +14,12 @@ नयाँ फोल्डर - + Cancel रद्द - + OK हुन्छ @@ -62,6 +62,24 @@ %1 दिन अघि + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + रद्द + + + + Delete + हटाउने + + DesktopView @@ -93,151 +111,268 @@ रद्दी खाली गर्ने + + FilePropertiesDialog + + + Properties + स्वामित्व + + + + %1 files + %1 फाइल हरु + + FolderModel - + %1 item %1 वस्तु - + %1 items %1 वस्तुहरु - + + The file or folder %1 does not exist. + + + + Select All सबै चयन - + + File Manager + + + + Open खोल्ने - + + Open with + + + + Cut रित्याएर प्रतिलिपी - + Copy प्रतिलिपि - + Paste टाँस्ने - + New Folder नयाँ फोल्डर - + Move To Trash रद्दी टोकरी मा सार्ने - + Empty Trash रद्दी टोकरी खाली गर्ने - + Delete हटाउने - + Rename पुन:नामाकरण - + Open in Terminal टर्मिनल मा खोल्ने - + Set as Wallpaper वलपेपर लगाउने - + Properties स्वामित्व - + Change background पृष्ठभुमि बदल्ने + + + Restore + + FolderPage - + Empty folder फोल्डर खाली छ - + Open खोल्ने - + + Properties स्वामित्व - + + File + + + + + New Folder + नयाँ फोल्डर + + + + Quit + + + + + Edit + + + + + Select All + सबै चयन + + + + Cut + रित्याएर प्रतिलिपी + + + + Copy + प्रतिलिपि + + + + Paste + टाँस्ने + + + + Help + + + + + About + + + + %1 item %1 वस्तु - + %1 items %1 वस्तुहरु - + %1 selected %1 चयन गरियो - + Empty Trash रद्दी टोकरी खाली गर्ने + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + रद्द + + + + Open + खोल्ने + + + + Open With + + + OptionsMenu - + Icons आइकनहरु - + List सुची - + Name नाम - + Date मिति - + + Type + + + + Size आकार @@ -250,97 +385,101 @@ गृह - + Desktop डेस्क्टप - + Documents कागजात - + Downloads डाउनलोड - + Music संगीत - + Pictures तस्विरहरु - + Videos भिडियो हरु - + Trash रद्दी टोकरि + + + + Drives + + PropertiesDialog - Properties - स्वामित्व + स्वामित्व - + Type: प्रकार: - + Location: स्थान: - + Size: आकार: - + Calculating... हिसाब गर्दै...... - + Created: निर्मित: - + Modified: बदलिएको: - + Accessed: पँहुच भएको: - + Cancel रद्द - + OK हुन्छ - %1 files - %1 फाइल हरु + %1 फाइल हरु diff --git a/translations/pl_PL.ts b/translations/pl_PL.ts index e01c382..1c9c386 100644 --- a/translations/pl_PL.ts +++ b/translations/pl_PL.ts @@ -14,12 +14,12 @@ Nowy folder - + Cancel Anuluj - + OK OK @@ -62,6 +62,24 @@ % godziny temu + + DeleteDialog + + + Do you want to delete it permanently? + Czy chcesz go trwale usunąć? + + + + Cancel + Anuluj + + + + Delete + Usuń + + DesktopView @@ -93,153 +111,270 @@ Opróżnij kosz + + FilePropertiesDialog + + + Properties + Właściwości + + + + %1 files + %1 plików + + FolderModel - + %1 item - % jednej rzeczy + %1 rzecz - + %1 items - % jednych rzeczy + %1 rzeczy - + + The file or folder %1 does not exist. + Plik lub folder %1 nie istnieje. + + + Select All Zaznacz wszystko - + + File Manager + Menedżer plików + + + Open Otwórz - + + Open with + Otwórz za pomocą + + + Cut Wytnij - + Copy Kopiuj - + Paste Wklej - + New Folder Nowy folder - + Move To Trash Przenieś do kosza - + Empty Trash Opróżnij kosz - + Delete Usuń - + Rename Zmień nazwę - + Open in Terminal Otwórz w terminalu - + Set as Wallpaper Ustaw jako tapetę - + Properties Właściwości - + Change background Zmień tło + + + Restore + Przywróć + FolderPage - + Empty folder Pusty folder - + Open Otwórz - + + Properties Właściwości - + + File + Plik + + + + New Folder + Nowy folder + + + + Quit + Zakończ + + + + Edit + Edytuj + + + + Select All + Zaznacz wszystko + + + + Cut + Wytnij + + + + Copy + Kopiuj + + + + Paste + Wklej + + + + Help + Pomoc + + + + About + + + + %1 item - % jednej rzeczy + %1 rzecz - + %1 items - % jednych rzeczy + %1 rzeczy - + %1 selected % zaznaczonych - + Empty Trash Opróżnij kosz + + OpenWithDialog + + + No applications + Brak aplikacji + + + + Set as default + Ustaw jako domyślne + + + + Cancel + Anuluj + + + + Open + Otwórz + + + + Open With + Otwórz za pomocą + + OptionsMenu - + Icons Ikony - + List Lista - + Name Nazwa - + Date Data - + + Type + Typ + + + Size - Wielkość + Rozmiar @@ -250,97 +385,101 @@ Pulpit - + Desktop - Wyświetlanie + Pulpit - + Documents Dokumenty - + Downloads Pobrane - + Music Muzyka - + Pictures Obrazy - + Videos Wideo - + Trash Kosz + + + + Drives + Dyski + PropertiesDialog - Properties - Właściwości + Właściwości - + Type: Typ: - + Location: Lokalizacja: - + Size: Rozmiar: - + Calculating... Przetwarzanie... - + Created: Utworzone: - + Modified: Zmodyfikowane: - + Accessed: Odwiedzone: - + Cancel Anuluj - + OK OK - %1 files - % plików + %1 plików diff --git a/translations/pt_BR.ts b/translations/pt_BR.ts index 87c1889..d57ba73 100644 --- a/translations/pt_BR.ts +++ b/translations/pt_BR.ts @@ -14,12 +14,12 @@ Nova pasta - + Cancel Cancelar - + OK OK @@ -62,6 +62,24 @@ %1 dias atrás + + DeleteDialog + + + Do you want to delete it permanently? + Você deseja excluí-lo permanentemente? + + + + Cancel + Cancelar + + + + Delete + Excluir + + DesktopView @@ -93,151 +111,268 @@ Esvaziar Lixeira + + FilePropertiesDialog + + + Properties + Propriedades + + + + %1 files + 1% de arquivos + + FolderModel - + %1 item %1 item - + %1 items %1 itens - + + The file or folder %1 does not exist. + O arquivo ou pasta não existe. + + + Select All Selecionar tudo - + + File Manager + Gerenciador de arquivos + + + Open Abrir - + + Open with + Abrir com + + + Cut - Cortar + Recortar - + Copy Copiar - + Paste Colar - + New Folder Nova pasta - + Move To Trash Mover para a Lixeira - + Empty Trash Esvaziar Lixeira - + Delete Excluir - + Rename Renomear - + Open in Terminal Abrir no Terminal - + Set as Wallpaper Definir como papel de parede - + Properties Propriedades - + Change background Mudar plano de fundo + + + Restore + Restaurar + FolderPage - + Empty folder Esvaziar pasta - + Open Abrir - + + Properties Propriedades - + + File + Arquivos + + + + New Folder + Nova pasta + + + + Quit + Sair + + + + Edit + Editar + + + + Select All + Selecionar tudo + + + + Cut + Recortar + + + + Copy + Copiar + + + + Paste + Colar + + + + Help + Ajuda + + + + About + Sobre + + + %1 item %1 item - + %1 items %1 itens - + %1 selected %1 selecionado(s) - + Empty Trash Esvaziar Lixeira + + OpenWithDialog + + + No applications + Sem aplicativos + + + + Set as default + Definir como padrão + + + + Cancel + Cancelar + + + + Open + Abrir + + + + Open With + Abrir com + + OptionsMenu - + Icons Ícones - + List Lista - + Name Nome - + Date Data - + + Type + Tipo + + + Size Tamanho @@ -250,97 +385,101 @@ Início - + Desktop Área de Trabalho - + Documents Documentos - + Downloads Downloads - + Music Música - + Pictures Imagens - + Videos Vídeos - + Trash Lixeira + + + + Drives + Drives + PropertiesDialog - Properties - Propriedades + Propriedades - + Type: Tipo: - + Location: Localização: - + Size: Tamanho: - + Calculating... Calculando... - + Created: Criado: - + Modified: Modificado: - + Accessed: Acessado: - + Cancel Cancelar - + OK OK - %1 files - %1 arquivos + %1 arquivos diff --git a/translations/pt_PT.ts b/translations/pt_PT.ts index 710c892..5163787 100644 --- a/translations/pt_PT.ts +++ b/translations/pt_PT.ts @@ -6,22 +6,22 @@ New folder name - + Nome da nova pasta New folder - + Nova pasta - + Cancel - + Cancelar - + OK - + Aceitar @@ -29,37 +29,55 @@ Now - + Agora 1 minute ago - + Há 1 minuto %1 minutes ago - + Há %1 minutos 1 hour ago - + Há 1 hora %1 hours ago - + Há %1 horas 1 day ago - + Há 1 dia %1 days ago - + Há %1 dias + + + + DeleteDialog + + + Do you want to delete it permanently? + Deseja eliminá-lo permanentemente? + + + + Cancel + Cancelar + + + + Delete + Eliminar @@ -67,7 +85,7 @@ Desktop - + Ambiente de trabalho @@ -75,171 +93,288 @@ File Manager - + Gestor de Ficheiros Do you want to permanently delete all files from the Trash? - + Deseja eliminar permanentemente todos os ficheiros do Lixo? Cancel - + Cancelar Empty Trash - + Esvaziar Lixo + + + + FilePropertiesDialog + + + Properties + Propriedades + + + + %1 files + %1 ficheiros FolderModel - + %1 item - + %1 item - + %1 items - + %1 itens - + + The file or folder %1 does not exist. + O ficheiro ou pasta %1 não existe. + + + Select All - + Selecionar tudo + + + + File Manager + Gestor de Ficheiros - + Open - + Abrir - + + Open with + Abrir com + + + Cut - + Cortar - + Copy - + Copiar - + Paste - + Colar - + New Folder - + Nova Pasta - + Move To Trash - + Mover para o Lixo - + Empty Trash - + Esvaziar Lixo - + Delete - + Eliminar - + Rename - + Renomear - + Open in Terminal - + Abrir no Terminal - + Set as Wallpaper - + Definir como Papel de parede - + Properties - + Propriedades - + Change background - + Mudar de fundo + + + + Restore + Restaurar FolderPage - + Empty folder - + Pasta vazia - + Open - + Abrir - + + Properties - + Propriedades + + + + File + Ficheiro + + + + New Folder + Nova Pasta + + + + Quit + Sair + + + + Edit + Editar + + + + Select All + Selecionar tudo + + + + Cut + Cortar + + + + Copy + Copiar - + + Paste + Colar + + + + Help + Ajuda + + + + About + Sobre + + + %1 item - + %1 item - + %1 items - + %1 itens - + %1 selected - + %1 selecionados - + Empty Trash - + Esvaziar Lixo + + + + OpenWithDialog + + + No applications + Nenhuma aplicação + + + + Set as default + Definir como padrão + + + + Cancel + Cancelar + + + + Open + Abrir + + + + Open With + Abrir com OptionsMenu - + Icons - + Ícones - + List - + Lista - + Name - + Nome - + Date - + Data - + + Type + Tipo + + + Size - + Tamanho @@ -247,100 +382,104 @@ Home - + Início - + Desktop - + Ambiente de trabalho - + Documents - + Documentos - + Downloads - + Transferências - + Music - + Música - + Pictures - + Imagens - + Videos - + Vídeos - + Trash - + Lixo + + + + + Drives + Unidades PropertiesDialog - Properties - + Propriedades - + Type: - + Tipo: - + Location: - + Localização: - + Size: - + Tamanho: - + Calculating... - + A calcular... - + Created: - + Criado: - + Modified: - + Modificado: - + Accessed: - + Acedido: - + Cancel - + Cancelar - + OK - + Aceitar - %1 files - + %1 ficheiros @@ -348,7 +487,7 @@ File Manager - + Gestor de Ficheiros diff --git a/translations/ro_RO.ts b/translations/ro_RO.ts new file mode 100644 index 0000000..033fe1e --- /dev/null +++ b/translations/ro_RO.ts @@ -0,0 +1,485 @@ + + + + + CreateFolderDialog + + + New folder name + Noul nume de dosar + + + + New folder + Dosar nou + + + + Cancel + Anulare + + + + OK + Ok + + + + DateHelper + + + Now + Acum + + + + 1 minute ago + 1 minut în urmă + + + + %1 minutes ago + %1 minute în urmă + + + + 1 hour ago + + + + + %1 hours ago + + + + + 1 day ago + + + + + %1 days ago + + + + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + Anulare + + + + Delete + + + + + DesktopView + + + Desktop + + + + + EmptyTrashDialog + + + File Manager + + + + + Do you want to permanently delete all files from the Trash? + + + + + Cancel + Anulare + + + + Empty Trash + + + + + FilePropertiesDialog + + + Properties + + + + + %1 files + + + + + FolderModel + + + %1 item + + + + + %1 items + + + + + The file or folder %1 does not exist. + + + + + Select All + + + + + File Manager + + + + + Open + + + + + Open with + + + + + Cut + + + + + Copy + + + + + Paste + + + + + New Folder + + + + + Move To Trash + + + + + Empty Trash + + + + + Delete + + + + + Rename + + + + + Open in Terminal + + + + + Set as Wallpaper + + + + + Properties + + + + + Change background + + + + + Restore + + + + + FolderPage + + + Empty folder + + + + + Open + + + + + + Properties + + + + + File + + + + + New Folder + + + + + Quit + + + + + Edit + + + + + Select All + + + + + Cut + + + + + Copy + + + + + Paste + + + + + Help + + + + + About + + + + + %1 item + + + + + %1 items + + + + + %1 selected + + + + + Empty Trash + + + + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + Anulare + + + + Open + + + + + Open With + + + + + OptionsMenu + + + Icons + + + + + List + + + + + Name + + + + + Date + + + + + Type + + + + + Size + + + + + PlacesModel + + + Home + + + + + Desktop + + + + + Documents + + + + + Downloads + + + + + Music + + + + + Pictures + + + + + Videos + + + + + Trash + + + + + + Drives + + + + + PropertiesDialog + + + Type: + + + + + Location: + + + + + Size: + + + + + Calculating... + + + + + Created: + + + + + Modified: + + + + + Accessed: + + + + + Cancel + Anulare + + + + OK + Ok + + + + main + + + File Manager + + + + diff --git a/translations/ru_RU.ts b/translations/ru_RU.ts index ba016b0..1178d2e 100644 --- a/translations/ru_RU.ts +++ b/translations/ru_RU.ts @@ -14,12 +14,12 @@ Новая папка - + Cancel Отмена - + OK ОК @@ -62,6 +62,24 @@ %1 дней назад + + DeleteDialog + + + Do you want to delete it permanently? + Вы хотите удалить его навсегда? + + + + Cancel + Отмена + + + + Delete + Удалить + + DesktopView @@ -93,151 +111,268 @@ Очистить корзину + + FilePropertiesDialog + + + Properties + Свойства + + + + %1 files + %1 файлов + + FolderModel - + %1 item %1 объект - + %1 items %1 объектов - + + The file or folder %1 does not exist. + Файл или папка %1 не существует. + + + Select All Выделить всё - + + File Manager + Файловый менеджер + + + Open Открыть - + + Open with + Открыть как + + + Cut Вырезать - + Copy Копировать - + Paste Вставить - + New Folder Новая папка - + Move To Trash Переместить в корзину - + Empty Trash Очистить корзину - + Delete Удалить - + Rename Переименовать - + Open in Terminal - Открыть в Терминале + Открыть в терминале - + Set as Wallpaper - Установить как Обои + Установить как обои - + Properties Свойства - + Change background Изменить фон + + + Restore + Восстановить + FolderPage - + Empty folder Пустая папка - + Open Открыть - + + Properties Свойства - + + File + Файл + + + + New Folder + Новая папка + + + + Quit + Выйти + + + + Edit + Изменить + + + + Select All + Выделить всё + + + + Cut + Вырезать + + + + Copy + Копировать + + + + Paste + Вставить + + + + Help + Помощь + + + + About + О программе + + + %1 item %1 объект - + %1 items %1 объектов - + %1 selected %1 выделено - + Empty Trash - Очистить Корзину + Очистить корзину + + + + OpenWithDialog + + + No applications + Нет приложений + + + + Set as default + Сделать по умолчанию + + + + Cancel + Отмена + + + + Open + Открыть + + + + Open With + Открыть как OptionsMenu - + Icons Иконки - + List Список - + Name Имя - + Date Дата - + + Type + Тип + + + Size Размер @@ -250,97 +385,101 @@ Домашний каталог - + Desktop Рабочий стол - + Documents Документы - + Downloads Загрузки - + Music Музыка - + Pictures Изображения - + Videos Видео - + Trash Корзина + + + + Drives + Диски + PropertiesDialog - Properties - Свойства + Свойства - + Type: Тип: - + Location: Размещение: - + Size: Размер: - + Calculating... Вычисление... - + Created: Создано: - + Modified: Изменено: - + Accessed: Доступ: - + Cancel Отмена - + OK ОК - %1 files - %1 файлов + %1 файлов diff --git a/translations/si_LK.ts b/translations/si_LK.ts new file mode 100644 index 0000000..b0f03ba --- /dev/null +++ b/translations/si_LK.ts @@ -0,0 +1,489 @@ + + + + + CreateFolderDialog + + + New folder name + නව බහාලුමේ නම + + + + New folder + නව බහාලුම + + + + Cancel + අවලංගු කරන්න + + + + OK + හරි + + + + DateHelper + + + Now + දැන් + + + + 1 minute ago + විනාඩි 1 කට පෙරාතුව + + + + %1 minutes ago + විනාඩි %1 කට පෙරාතුව + + + + 1 hour ago + පැය 1 කට පෙරාතුව + + + + %1 hours ago + පැය %1 කට පෙරාතුව + + + + 1 day ago + දින 1 කට පෙරාතුව + + + + %1 days ago + දින %1 කට පෙරාතුව + + + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + අවලංගු කරන්න + + + + Delete + + + + + DesktopView + + + Desktop + + + + + EmptyTrashDialog + + + File Manager + ගොනු කළමනාකරු + + + + Do you want to permanently delete all files from the Trash? + + + + + Cancel + අවලංගු කරන්න + + + + Empty Trash + + + + + FilePropertiesDialog + + + Properties + + + + + %1 files + ගොනු %1 + + + + FolderModel + + + %1 item + + + + + %1 items + + + + + The file or folder %1 does not exist. + + + + + Select All + සියල්ල තෝරන්න + + + + File Manager + ගොනු කළමනාකරු + + + + Open + විවෘත කරන්න + + + + Open with + + + + + Cut + කපන්න + + + + Copy + පිටපත් කරන්න + + + + Paste + අලවන්න + + + + New Folder + නව බහාලුම + + + + Move To Trash + + + + + Empty Trash + + + + + Delete + + + + + Rename + නැවත නම් කරන්න + + + + Open in Terminal + අග්‍රයෙහි විවෘත කරන්න + + + + Set as Wallpaper + + + + + Properties + + + + + Change background + පසුබිම වෙනස් කරන්න + + + + Restore + + + + + FolderPage + + + Empty folder + + + + + Open + විවෘත කරන්න + + + + + Properties + + + + + File + + + + + New Folder + නව බහාලුම + + + + Quit + + + + + Edit + + + + + Select All + සියල්ල තෝරන්න + + + + Cut + කපන්න + + + + Copy + පිටපත් කරන්න + + + + Paste + අලවන්න + + + + Help + + + + + About + + + + + %1 item + + + + + %1 items + + + + + %1 selected + + + + + Empty Trash + + + + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + අවලංගු කරන්න + + + + Open + විවෘත කරන්න + + + + Open With + + + + + OptionsMenu + + + Icons + + + + + List + + + + + Name + නම + + + + Date + දිනය + + + + Type + + + + + Size + ප්‍රමාණය + + + + PlacesModel + + + Home + මුල + + + + Desktop + + + + + Documents + ලේඛන + + + + Downloads + බාගැනීම් + + + + Music + සංගීත + + + + Pictures + පින්තූර + + + + Videos + දෘශ්‍යක + + + + Trash + + + + + + Drives + + + + + PropertiesDialog + + + Type: + වර්ගය: + + + + Location: + ස්ථානය: + + + + Size: + ප්‍රමාණය: + + + + Calculating... + ගණනය වෙමින්... + + + + Created: + + + + + Modified: + + + + + Accessed: + + + + + Cancel + අවලංගු කරන්න + + + + OK + හරි + + + %1 files + ගොනු %1 + + + + main + + + File Manager + ගොනු කළමනාකරු + + + diff --git a/translations/sk_SK.ts b/translations/sk_SK.ts index 43fe096..03dcf20 100644 --- a/translations/sk_SK.ts +++ b/translations/sk_SK.ts @@ -14,12 +14,12 @@ Nový priečinok - + Cancel Zrušiť - + OK OK @@ -62,6 +62,24 @@ Pred %1 dňami + + DeleteDialog + + + Do you want to delete it permanently? + Chcete to nenávratne vymazať? + + + + Cancel + Zrušiť + + + + Delete + Vymazať + + DesktopView @@ -90,154 +108,271 @@ Empty Trash - Vyprázdniť Kôš + Vyprázdniť kôš + + + + FilePropertiesDialog + + + Properties + Vlastnosti + + + + %1 files + %1 súborov FolderModel - + %1 item %1 položka - + %1 items %1 položiek - + + The file or folder %1 does not exist. + Súbor alebo priečinok %1 neexistuje. + + + Select All Vybrať všetky - + + File Manager + Správca súborov + + + Open Otvoriť - + + Open with + Otvoriť v + + + Cut Vystrihnúť - + Copy Kopírovať - + Paste Prilepiť - + New Folder Nový priečinok - + Move To Trash Presunúť do Koša - + Empty Trash Vyprázdniť Kôš - + Delete Odstrániť - + Rename Premenovať - + Open in Terminal Otvoriť v Termináli - + Set as Wallpaper - Nastaviť ako pozadie pracovnej plochy + Nastaviť ako Pozadie pracovnej plochy - + Properties Vlastnosti - + Change background Zmeniť pozadie + + + Restore + Obnoviť + FolderPage - + Empty folder Vyprázdniť priečinok - + Open Otvoriť - + + Properties Vlastnosti - + + File + Súbor + + + + New Folder + Nový priečinok + + + + Quit + Skončiť + + + + Edit + Upraviť + + + + Select All + Vybrať všetko + + + + Cut + Vystrihnúť + + + + Copy + Kopírovať + + + + Paste + Prilepiť + + + + Help + Pomocník + + + + About + O aplikácii + + + %1 item %1 položka - + %1 items %1 položiek - + %1 selected %1 vybrané - + Empty Trash - Vyprázdniť Kôš + Vyprázdniť kôš + + + + OpenWithDialog + + + No applications + Žiadne aplikácie + + + + Set as default + Nastaviť ako predvolené + + + + Cancel + Zrušiť + + + + Open + Otvoriť + + + + Open With + Otvoriť v OptionsMenu - + Icons Ikony - + List Zoznam - + Name Názov - + Date Dátum - + + Type + Typ + + + Size Veľkosť @@ -250,97 +385,101 @@ Domov - + Desktop Pracovná plocha - + Documents Dokumenty - + Downloads Prevzaté súbory - + Music Hudba - + Pictures Obrázky - + Videos Videá - + Trash Kôš + + + + Drives + Disky + PropertiesDialog - Properties - Vlastnosti + Vlastnosti - + Type: Typ súboru: - + Location: Umiestnenie: - + Size: Veľkosť: - + Calculating... Počítanie... - + Created: Vytvorený: - + Modified: Upravený: - + Accessed: Otvorený: - + Cancel Zrušiť - + OK OK - %1 files - %1 súbory + %1 súbory diff --git a/translations/so.ts b/translations/so.ts index 8f40d24..4643c11 100644 --- a/translations/so.ts +++ b/translations/so.ts @@ -14,12 +14,12 @@ Gal cusub - + Cancel Xir - + OK OK @@ -62,6 +62,24 @@ %1 maalmood kahor + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + Xir + + + + Delete + Tirtir + + DesktopView @@ -93,151 +111,268 @@ Qashinka Madhi + + FilePropertiesDialog + + + Properties + + + + + %1 files + %1 fayl + + FolderModel - + %1 item %1 walax - + %1 items %1 walxood - + + The file or folder %1 does not exist. + + + + Select All Dooro dhammaan - + + File Manager + + + + Open Fur - + + Open with + + + + Cut Jar - + Copy Koobbi - + Paste Dhaji - + New Folder Gal Cusub - + Move To Trash Qashinka ku dar - + Empty Trash Qashinka madhi - + Delete Tirtir - + Rename Magacow - + Open in Terminal Kufur Terminal-ka - + Set as Wallpaper Ku dhaji gidaarka - + Properties Astaamaha - + Change background Bedel sawirka gidaarka + + + Restore + + FolderPage - + Empty folder Galka madhi - + Open Fur - + + Properties Astaamaha - + + File + + + + + New Folder + Gal Cusub + + + + Quit + + + + + Edit + + + + + Select All + Dooro dhammaan + + + + Cut + Jar + + + + Copy + Koobbi + + + + Paste + Dhaji + + + + Help + + + + + About + + + + %1 item %1 walax - + %1 items %1 walxood - + %1 selected %1 dooratay - + Empty Trash Qashinka Madhi + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + Xir + + + + Open + Fur + + + + Open With + + + OptionsMenu - + Icons Calaamado - + List Liis - + Name Magac - + Date Taariikh - + + Type + + + + Size Xajmiga @@ -250,97 +385,101 @@ Aqal - + Desktop Kadinka - + Documents Dukumiintiyada - + Downloads Dejisan - + Music Muusig - + Pictures Sawirro - + Videos Muuqaallo - + Trash Qashin + + + + Drives + + PropertiesDialog - Properties - Astaamo + Astaamo - + Type: Nooca: - + Location: Goobta: - + Size: Xajmiga: - + Calculating... Xisaabinayaa... - + Created: La abuuray: - + Modified: La bedelay: - + Accessed: La furay: - + Cancel Xir - + OK OK - %1 files - %1 fayl + %1 fayl diff --git a/translations/sr_RS.ts b/translations/sr_RS.ts new file mode 100644 index 0000000..1a29ec3 --- /dev/null +++ b/translations/sr_RS.ts @@ -0,0 +1,490 @@ + + + + + CreateFolderDialog + + + New folder name + Naziv nove fascikle + + + + New folder + Nova fascikla + + + + Cancel + Otkaži + + + + OK + OK + + + + DateHelper + + + Now + Sad + + + + 1 minute ago + Pre 1 minut + + + + %1 minutes ago + Pre %1 minuta + + + + 1 hour ago + Pre 1 sat + + + + %1 hours ago + Pre %1 sati + + + + 1 day ago + Pre 1 dan + + + + %1 days ago + Pre %1 dana + + + + DeleteDialog + + + Do you want to delete it permanently? + Da li želite trajno ovo da obrišete? + + + + Cancel + Otkaži + + + + Delete + Obriši + + + + DesktopView + + + Desktop + Radna površina + + + + EmptyTrashDialog + + + File Manager + Upravljač datoteka + + + + Do you want to permanently delete all files from the Trash? + Želite li trajno obrisati sve fajlove iz Smeća? + + + + Cancel + Otkaži + + + + Empty Trash + Isprazni smeće + + + + FilePropertiesDialog + + + Properties + Svojstva + + + + %1 files + %1 datoteka + + + + FolderModel + + + %1 item + %1 stavka + + + + %1 items + %1 stavki + + + + The file or folder %1 does not exist. + Datoteka ili fascikla %1 ne postoji. + + + + Select All + Izaberi sve + + + + File Manager + Upravljač datotekama + + + + Open + Otvori + + + + Open with + Otvori pomoću + + + + Cut + Iseci + + + + Copy + Kopiraj + + + + Paste + Zalepi + + + + New Folder + Nova fascikla + + + + Move To Trash + Premesti u smeće + + + + Empty Trash + Isprazni smeće + + + + Delete + Obriši + + + + Rename + Preimenuj + + + + Open in Terminal + Otvori u terminalu + + + + Set as Wallpaper + Postavi kao pozadinu + + + + Properties + Svojstva + + + + Change background + Promeni pozadinu + + + + Restore + Obnovi + + + + Show hidden files + Prikaži skrivene datoteke + + + + FolderPage + + + Empty folder + Prazna fascikla + + + + Open + Otvori + + + + + Properties + Svojstva + + + + File + Datoteka + + + + New Folder + Nova fascikla + + + + Quit + Odustani + + + + Edit + Uredi + + + + Select All + Izaberi sve + + + + Cut + Iseci + + + + Copy + Kopiraj + + + + Paste + Zalepi + + + + Help + Pomoć + + + + About + O Aplikaciji + + + + %1 item + %1 stavka + + + + %1 items + %1 stavki + + + + %1 selected + %1 odabrano + + + + Empty Trash + Isprazni smeće + + + + OpenWithDialog + + + No applications + + + + + Set as default + Postavi kao podrazumevano + + + + Cancel + Otkaži + + + + Open + Otvori + + + + Open With + Otvori pomoću + + + + OptionsMenu + + + Icons + Ikone + + + + List + Spisak + + + + Name + Ime + + + + Date + Datum + + + + Type + Tip + + + + Size + Veličina + + + + PlacesModel + + + Home + + + + + Desktop + Radna površina + + + + Documents + Dokumenti + + + + Downloads + Preuzimanja + + + + Music + Muzika + + + + Pictures + Slike + + + + Videos + Videozapisi + + + + Trash + Smeće + + + + + Drives + Diskovi + + + + PropertiesDialog + + + Type: + Vrsta: + + + + Location: + Lokacija: + + + + Size: + Veličina: + + + + Calculating... + Računanje... + + + + Created: + Napravljeno: + + + + Modified: + Izmenjeno: + + + + Accessed: + Pristupljeno: + + + + Cancel + Otkaži + + + + OK + U redu + + + + main + + + File Manager + Upravljač datotekama + + + diff --git a/translations/sv_SE.ts b/translations/sv_SE.ts index 14faa82..7d29fbd 100644 --- a/translations/sv_SE.ts +++ b/translations/sv_SE.ts @@ -14,12 +14,12 @@ Ny mapp - + Cancel Avbryt - + OK OK @@ -62,6 +62,24 @@ %1 dagar sedan + + DeleteDialog + + + Do you want to delete it permanently? + Vill du ta bort den permanent? + + + + Cancel + Avbryt + + + + Delete + Ta bort + + DesktopView @@ -93,151 +111,268 @@ Töm papperskorgen + + FilePropertiesDialog + + + Properties + Egenskaper + + + + %1 files + %1 filer + + FolderModel - + %1 item %1 objekt - + %1 items %1 objekt - + + The file or folder %1 does not exist. + Denna fil eller katalog %1 existerar inte. + + + Select All Välj alla - + + File Manager + Filhanterare + + + Open Öppna - + + Open with + Öppna med + + + Cut Klipp ut - + Copy Kopiera - + Paste Klistra in - + New Folder Ny mapp - + Move To Trash Flytta till papperskorgen - + Empty Trash Tom papperskorgen - + Delete Ta bort - + Rename Döp om - + Open in Terminal Öppna i Terminal - + Set as Wallpaper Använd som bakgrund - + Properties Egenskaper - + Change background Ändra bakgrund + + + Restore + Återställ + FolderPage - + Empty folder Tom mapp - + Open Öppna - + + Properties Egenskaper - + + File + Fil + + + + New Folder + Ny Mapp + + + + Quit + Avsluta + + + + Edit + Redigera + + + + Select All + Välj alla + + + + Cut + Klipp ut + + + + Copy + Kopiera + + + + Paste + Klistra in + + + + Help + Hjälp + + + + About + Om + + + %1 item %1 objekt - + %1 items %1 objekt - + %1 selected %1 valda - + Empty Trash Töm papperskorgen + + OpenWithDialog + + + No applications + Inga program + + + + Set as default + Ange som standard + + + + Cancel + Avbryt + + + + Open + Öppna + + + + Open With + Öppna med + + OptionsMenu - + Icons Ikoner - + List Lista - + Name Namn - + Date Datum - + + Type + Typ + + + Size Storlek @@ -250,97 +385,101 @@ Hem - + Desktop Skrivbord - + Documents Dokument - + Downloads Hämtade filer - + Music Musik - + Pictures Bilder - + Videos Filmer - + Trash Skräp + + + + Drives + Enheter + PropertiesDialog - Properties - Egenskaper + Egenskaper - + Type: Typ: - + Location: Plats: - + Size: Storlek: - + Calculating... Beräknar... - + Created: Skapad: - + Modified: Ändrad: - + Accessed: Senast öppnad: - + Cancel Avbryt - + OK OK - %1 files - %1 fil + %1 fil diff --git a/translations/sw.ts b/translations/sw.ts new file mode 100644 index 0000000..32ab5ca --- /dev/null +++ b/translations/sw.ts @@ -0,0 +1,485 @@ + + + + + CreateFolderDialog + + + New folder name + Jina la folda mpya + + + + New folder + Folda mpya + + + + Cancel + Ghairi + + + + OK + Sawa + + + + DateHelper + + + Now + Sasa + + + + 1 minute ago + dakika 1 imepita + + + + %1 minutes ago + %1 dakika zimepita + + + + 1 hour ago + saa 1 imepita + + + + %1 hours ago + masaa %1 zimepita + + + + 1 day ago + Siku 1 imepita + + + + %1 days ago + Siku %1 zimepita + + + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + Ghairi + + + + Delete + Futa + + + + DesktopView + + + Desktop + Desktop + + + + EmptyTrashDialog + + + File Manager + meneja la faili + + + + Do you want to permanently delete all files from the Trash? + Unataka kufuta kila kitu kwa Takataka? + + + + Cancel + Ghairi + + + + Empty Trash + Futa Takataka + + + + FilePropertiesDialog + + + Properties + Mali + + + + %1 files + %1 faili + + + + FolderModel + + + %1 item + %1 kitu + + + + %1 items + %1 vitu + + + + The file or folder %1 does not exist. + + + + + Select All + Chagua Zote + + + + File Manager + + + + + Open + Fungua + + + + Open with + Fungua na + + + + Cut + Kata + + + + Copy + Nakala + + + + Paste + Bandika + + + + New Folder + Folda mpya + + + + Move To Trash + Weka ndani ya Takataka + + + + Empty Trash + Futa Takataka + + + + Delete + Futa + + + + Rename + Badilisha jina + + + + Open in Terminal + Fungua ndani ya Terminal + + + + Set as Wallpaper + Weka kama kikaratasi + + + + Properties + Mali + + + + Change background + Badilisha kikaratasi + + + + Restore + + + + + FolderPage + + + Empty folder + Folda tupu + + + + Open + Fungua + + + + + Properties + Mali + + + + File + Faili + + + + New Folder + Folda mpya + + + + Quit + Toka + + + + Edit + Badilisha + + + + Select All + Chagua zote + + + + Cut + Kata + + + + Copy + Nakala + + + + Paste + Bandika + + + + Help + Usaidizi + + + + About + Kuhusu + + + + %1 item + %1 kitu + + + + %1 items + %1 vitu + + + + %1 selected + %1 imechaguliwa + + + + Empty Trash + Futa Takataka + + + + OpenWithDialog + + + No applications + Hakuna programu + + + + Set as default + Weka kama kawaida + + + + Cancel + Ghairi + + + + Open + Fungua + + + + Open With + Fungua na + + + + OptionsMenu + + + Icons + Ikoni + + + + List + Orodha + + + + Name + Jina + + + + Date + Tarehe + + + + Type + + + + + Size + Ukubwa + + + + PlacesModel + + + Home + Nyumbani + + + + Desktop + Desktop + + + + Documents + Hati + + + + Downloads + Mapakuo + + + + Music + Muziki + + + + Pictures + Mapicha + + + + Videos + Mavideo + + + + Trash + Takataka + + + + + Drives + + + + + PropertiesDialog + + + Type: + Aina: + + + + Location: + Mahali: + + + + Size: + Ukubwa: + + + + Calculating... + inapiga hesabu... + + + + Created: + Imetengezwa: + + + + Modified: + Imebadilishwa: + + + + Accessed: + Imefunguliwa: + + + + Cancel + Ghairi + + + + OK + Sawa + + + + main + + + File Manager + Meneja la faili + + + diff --git a/translations/ta_IN.ts b/translations/ta_IN.ts index faa2c9a..b20a25b 100644 --- a/translations/ta_IN.ts +++ b/translations/ta_IN.ts @@ -14,12 +14,12 @@ - + Cancel - + OK @@ -62,6 +62,24 @@ + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + + + + + Delete + + + DesktopView @@ -93,151 +111,268 @@ + + FilePropertiesDialog + + + Properties + + + + + %1 files + + + FolderModel - + %1 item - + %1 items - + + The file or folder %1 does not exist. + + + + Select All - + + File Manager + + + + Open - + + Open with + + + + Cut - + Copy - + Paste - + New Folder - + Move To Trash - + Empty Trash - + Delete - + Rename - + Open in Terminal - + Set as Wallpaper - + Properties - + Change background + + + Restore + + FolderPage - + Empty folder - + Open - + + Properties - + + File + + + + + New Folder + + + + + Quit + + + + + Edit + + + + + Select All + + + + + Cut + + + + + Copy + + + + + Paste + + + + + Help + + + + + About + + + + %1 item - + %1 items - + %1 selected - + Empty Trash + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + + + + + Open + + + + + Open With + + + OptionsMenu - + Icons - + List - + Name - + Date - + + Type + + + + Size @@ -250,98 +385,94 @@ - + Desktop - + Documents - + Downloads - + Music - + Pictures - + Videos - + Trash - - - PropertiesDialog - - Properties + + + Drives + + + PropertiesDialog - + Type: - + Location: - + Size: - + Calculating... - + Created: - + Modified: - + Accessed: - + Cancel - + OK - - - %1 files - - main diff --git a/translations/tr_TR.ts b/translations/tr_TR.ts index 5c1a3d6..ae94060 100644 --- a/translations/tr_TR.ts +++ b/translations/tr_TR.ts @@ -14,12 +14,12 @@ Yeni klasör - + Cancel İptal - + OK Tamam @@ -62,6 +62,24 @@ %1 gün önce + + DeleteDialog + + + Do you want to delete it permanently? + Kalıcı olarak silmek istediğinizden emin misiniz? + + + + Cancel + İptal + + + + Delete + Sil + + DesktopView @@ -93,151 +111,268 @@ Çöpü Boşalt + + FilePropertiesDialog + + + Properties + Özellikler + + + + %1 files + %1 dosyalar + + FolderModel - + %1 item %1 öğe - + %1 items %1 öğe - + + The file or folder %1 does not exist. + Dosyanın veya dizinin %1 yok. + + + Select All Hepsini seç - + + File Manager + Dosya Yöneticisi + + + Open - + + Open with + Birlikte aç + + + Cut Kes - + Copy Kopyala - + Paste Yapıştır - + New Folder Yeni Klasör - + Move To Trash Çöpe Taşı - + Empty Trash Çöpü Boşalt - + Delete Sil - + Rename Yeniden adlandır - + Open in Terminal Uçbirimde aç - + Set as Wallpaper Arkaplan olarak ayarla - + Properties Özellikler - + Change background Arkaplanı değiştir + + + Restore + Onar + FolderPage - + Empty folder Boş klasör - + Open - + + Properties Özellikler - + + File + Dosya + + + + New Folder + Yeni Klasör + + + + Quit + Çıkış + + + + Edit + Düzenle + + + + Select All + Hepsini seç + + + + Cut + Kes + + + + Copy + Kopyala + + + + Paste + Yapıştır + + + + Help + Yardım + + + + About + Hakkında + + + %1 item %1 öğe - + %1 items %1 öğe - + %1 selected %1 seçildi - + Empty Trash Çöpü Boşalt + + OpenWithDialog + + + No applications + Uygulama yok + + + + Set as default + Varsayılan olarak ayarla + + + + Cancel + İptal + + + + Open + + + + + Open With + Birlikte aç + + OptionsMenu - + Icons İkonlar - + List Liste - + Name İsim - + Date Tarih - + + Type + Tür + + + Size Boyut @@ -250,97 +385,101 @@ Ev - + Desktop Masaüstü - + Documents Belgeler - + Downloads İndirilenler - + Music Müzik - + Pictures Resimler - + Videos Videolar - + Trash Çöp + + + + Drives + Sürücüler + PropertiesDialog - Properties - Özellikler + Özellikler - + Type: Tip: - + Location: Lokasyon: - + Size: Boyut: - + Calculating... Hesaplanıyor... - + Created: Oluşturuldu: - + Modified: Düzenlendi: - + Accessed: Erişildi: - + Cancel İptal - + OK Tamam - %1 files - %1 dosyalar + %1 dosyalar diff --git a/translations/uk_UA.ts b/translations/uk_UA.ts index 3286036..974f6d9 100644 --- a/translations/uk_UA.ts +++ b/translations/uk_UA.ts @@ -11,15 +11,15 @@ New folder - Нова папка... + Нова папка - + Cancel - Відмінити + Скасувати - + OK ОК @@ -62,6 +62,24 @@ %1 дні(-в) тому + + DeleteDialog + + + Do you want to delete it permanently? + Ви справді бажаєте видалити це назавжди? + + + + Cancel + Скасувати + + + + Delete + Видалити + + DesktopView @@ -85,7 +103,7 @@ Cancel - Відмінити + Скасувати @@ -93,151 +111,268 @@ Очистити кошик + + FilePropertiesDialog + + + Properties + Властивості + + + + %1 files + %1 файлів + + FolderModel - + %1 item %1 об'єкт - + %1 items %1 об'єкт(-ів) - + + The file or folder %1 does not exist. + Каталогу чи файлу %1 не існує. + + + Select All Виділити усе - + + File Manager + Провідник + + + Open Відкрити - + + Open with + Відкрити за допомогою + + + Cut Вирізати - + Copy Копіювати - + Paste Вставити - + New Folder Нова папка - + Move To Trash В кошик - + Empty Trash Очистити кошик - + Delete Видалити - + Rename Переіменувати - + Open in Terminal Відкрити в командному рядку - + Set as Wallpaper Використати як фоновий малюнок - + Properties Властивості - + Change background Змінити фоновий малюнок + + + Restore + Відновити + FolderPage - + Empty folder Пуста папка - + Open Відкрити - + + Properties Властивості - + + File + Файл + + + + New Folder + Новий каталог + + + + Quit + Вийти + + + + Edit + Редагувати + + + + Select All + Виділити усе + + + + Cut + Вирізати + + + + Copy + Копіювати + + + + Paste + Вставити + + + + Help + Довідка + + + + About + Про застосунок + + + %1 item %1 об'єкт - + %1 items %1 об'єктів - + %1 selected %1 обрано - + Empty Trash Очистити кошик + + OpenWithDialog + + + No applications + Застосунків немає + + + + Set as default + Зробити типовим + + + + Cancel + Скасувати + + + + Open + Відкрити + + + + Open With + Відкрити за допомогою + + OptionsMenu - + Icons Іконки - + List Список - + Name Ім'я - + Date Дата - + + Type + Тип + + + Size Розмір @@ -250,97 +385,101 @@ Домашня папка - + Desktop Робочий стіл - + Documents Документи - + Downloads Завантажені файли - + Music Музика - + Pictures Картинки - + Videos Відео - + Trash Кошик + + + + Drives + Приводи + PropertiesDialog - Properties - Властивості + Властивості - + Type: Тип: - + Location: Розміщення: - + Size: Розмір: - + Calculating... Вираховування... - + Created: Створено: - + Modified: Змінено: - + Accessed: Доступ : - + Cancel - Відміна + Скасувати - + OK ОК - %1 files - %1 файлів + %1 файлів diff --git a/translations/uz_UZ.ts b/translations/uz_UZ.ts index 8635648..f6aecd7 100644 --- a/translations/uz_UZ.ts +++ b/translations/uz_UZ.ts @@ -14,12 +14,12 @@ Yangi jild - + Cancel Bekor - + OK Mayli @@ -62,6 +62,24 @@ %1 kun avval + + DeleteDialog + + + Do you want to delete it permanently? + + + + + Cancel + Bekor + + + + Delete + O'chirish + + DesktopView @@ -93,151 +111,268 @@ Qutichani bo'shatish + + FilePropertiesDialog + + + Properties + + + + + %1 files + %1 fayllar + + FolderModel - + %1 item %1 element - + %1 items %1 element - + + The file or folder %1 does not exist. + + + + Select All Barchasini belgilash - + + File Manager + + + + Open Ochish - + + Open with + + + + Cut Qirqish - + Copy Nusxa olish - + Paste Joylash - + New Folder Yangi jild - + Move To Trash Savatchaga joylash - + Empty Trash Savatchani tozalash - + Delete O'chirish - + Rename Qayta nomlash - + Open in Terminal Terminalda ochish - + Set as Wallpaper Fon rasmi - + Properties Xususiyatlari - + Change background Fon rasmini almashtirish + + + Restore + + FolderPage - + Empty folder Bo'sh jild - + Open Ochish - + + Properties Xususiyatlar - + + File + + + + + New Folder + Yangi jild + + + + Quit + + + + + Edit + + + + + Select All + Barchasini belgilash + + + + Cut + Qirqish + + + + Copy + Nusxa olish + + + + Paste + Joylash + + + + Help + + + + + About + + + + %1 item %1 element - + %1 items %1 element - + %1 selected %1 belgilangan - + Empty Trash Savatchani bo'shatish + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + Bekor + + + + Open + Ochish + + + + Open With + + + OptionsMenu - + Icons Belgichalar - + List Ro'yxat - + Name Nom - + Date Sana - + + Type + + + + Size O'lcham @@ -250,97 +385,101 @@ Uy - + Desktop Ishchi Stol - + Documents Hujjatlar - + Downloads Yuklanmalar - + Music Misiqalar - + Pictures Suratlar - + Videos VIdeolar - + Trash Savatcha + + + + Drives + + PropertiesDialog - Properties - Xususiyatlar + Xususiyatlar - + Type: Turi: - + Location: Joylashuvi: - + Size: O'lchami: - + Calculating... Hisoblanmoqda... - + Created: Yaratildi: - + Modified: O'zgartirildi: - + Accessed: Kirish: - + Cancel Bekor - + OK OK - %1 files - %1 fayllar + %1 fayllar diff --git a/translations/zh_CN.ts b/translations/zh_CN.ts index a12d52a..21abaaa 100644 --- a/translations/zh_CN.ts +++ b/translations/zh_CN.ts @@ -14,12 +14,12 @@ 新建文件夹 - + Cancel 取消 - + OK 确定 @@ -62,10 +62,28 @@ %1天前 + + DeleteDialog + + + Do you want to delete it permanently? + 是否要永久删除? + + + + Cancel + 取消 + + + + Delete + 删除 + + DesktopView - + Desktop 桌面 @@ -78,166 +96,316 @@ 文件管理器 - + Do you want to permanently delete all files from the Trash? 是否要从回收站中永久删除所有文件? - + Cancel 取消 - + Empty Trash 清空回收站 + + FilePropertiesDialog + + + Properties + 属性 + + + + %1 files + %1 项 + + FolderModel - + %1 item %1 项 - + %1 items %1 项 - + + The file or folder %1 does not exist. + 文件或文件夹 %1 不存在 + + + Select All 全选 - + + File Manager + 文件管理器 + + + Open 打开 - + + Open with + 打开方式 + + + Cut 剪切 - + Copy 复制 - + Paste 粘贴 - + + New Folder 新建文件夹 - + + + New Text + 新建文本 + + + + + New Documents + 新建文档 + + + Move To Trash 移动到回收站 - + Empty Trash 清空回收站 - + Delete 删除 - + Rename 重命名 - + Open in Terminal 在终端中打开 - + Set as Wallpaper 设置为壁纸 - + Properties 属性 - + Change background 更改桌面背景 + + + Restore + 恢复 + + + + Show hidden files + 显示隐藏文件 + + + + Open in new window + 在新窗口中打开 + FolderPage - + Empty folder 空文件夹 - + Open 打开 - + + Properties 属性 - + + File + 文件 + + + + New Folder + 新建文件夹 + + + + Quit + 退出 + + + + Edit + 编辑 + + + + Select All + 全选 + + + + Cut + 剪切 + + + + Copy + 复制 + + + + Paste + 粘贴 + + + + Help + 帮助 + + + + About + 关于 + + + + File Manager + 文件管理器 + + + + A file manager designed for CutefishOS. + 专为 CutefishOS 打造的文件管理器 + + + %1 item %1 项 - + %1 items %1 项 - + %1 selected 选中了 %1 项 - + Empty Trash 清空回收站 + + OpenWithDialog + + + No applications + 没有应用程序 + + + + Set as default + 设置为默认 + + + + Cancel + 取消 + + + + Open + 打开 + + + + Open With + 打开方式 + + OptionsMenu - + Icons 图标视图 - + List 列表视图 - + Name 名称 - + Date 日期 - + + Type + 类型 + + + Size 大小 @@ -250,97 +418,121 @@ 主文件夹 - + Desktop 桌面 - + Documents 文档 - + Downloads 下载 - + Music 音乐 - + Pictures 图片 - + Videos 视频 - + Trash 回收站 + + + + Drives + 设备 + + + + Computer + 计算机 + PropertiesDialog - - Properties - 属性 - - - + Type: 类型: - + Location: 位置: - + Size: 大小: - + Calculating... 计算中... - + Created: 创建时间: - + Modified: 修改时间: - + Accessed: 访问时间: - + Cancel 取消 - + OK 确定 + + + SideBar - - %1 files - %1 项 + + Open + 打开 + + + + Open in new window + 在新窗口中打开 + + + + Eject + 弹出 + + + + Unmount + 卸载 diff --git a/translations/zh_TW.ts b/translations/zh_TW.ts index 8b47e96..2e7c82c 100644 --- a/translations/zh_TW.ts +++ b/translations/zh_TW.ts @@ -14,12 +14,12 @@ 新建資料夾 - + Cancel 取消 - + OK @@ -62,6 +62,24 @@ %1 天前 + + DeleteDialog + + + Do you want to delete it permanently? + 是否要永久刪除此文件 + + + + Cancel + 取消 + + + + Delete + 刪除 + + DesktopView @@ -93,151 +111,268 @@ 清空回收筒 + + FilePropertiesDialog + + + Properties + 屬性 + + + + %1 files + %1 檔案 + + FolderModel - + %1 item %1 件物品 - + %1 items %1 件物品 - + + The file or folder %1 does not exist. + 這個文件或文件夾%1不存在。 + + + Select All 選擇全部 - + + File Manager + 檔案管理員 + + + Open 開啟 - + + Open with + 用什麼打開 + + + Cut 剪下 - + Copy 拷貝 - + Paste 貼上 - + New Folder 新建資料夾 - + Move To Trash 移至回收筒 - + Empty Trash 清空回收筒 - + Delete 刪除 - + Rename 重新命名 - + Open in Terminal 在終端機中開啓 - + Set as Wallpaper 設為桌布 - + Properties 屬性 - + Change background 更換背景 + + + Restore + 還原 + FolderPage - + Empty folder 空資料夾 - + Open 開啓 - + + Properties 屬性 - + + File + 文件 + + + + New Folder + 新建資料夾 + + + + Quit + + + + + Edit + + + + + Select All + 選擇全部 + + + + Cut + 剪下 + + + + Copy + 拷貝 + + + + Paste + 貼上 + + + + Help + + + + + About + + + + %1 item %1 件物品 - + %1 items %1 件物品 - + %1 selected 已選 %1 件 - + Empty Trash 清空回收站 + + OpenWithDialog + + + No applications + + + + + Set as default + + + + + Cancel + 取消 + + + + Open + + + + + Open With + + + OptionsMenu - + Icons 圖符 - + List 列表視圖 - + Name 名稱 - + Date 日期 - + + Type + + + + Size 尺寸 @@ -250,97 +385,101 @@ 個人資料夾 - + Desktop 桌面 - + Documents 文件 - + Downloads 下載 - + Music 音樂 - + Pictures 圖片 - + Videos 影片 - + Trash 回收筒 + + + + Drives + + PropertiesDialog - Properties - 屬性 + 屬性 - + Type: 類別: - + Location: 位置: - + Size: 大小: - + Calculating... 計算中… - + Created: 建立時間: - + Modified: 修改時間: - + Accessed: 訪問時間: - + Cancel 取消 - + OK - %1 files - %1 檔案 + %1 檔案 diff --git a/window.cpp b/window.cpp new file mode 100644 index 0000000..2d8f6ea --- /dev/null +++ b/window.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#include "window.h" +#include +#include +#include +#include + +Window::Window(QObject *parent) + : QQmlApplicationEngine(parent) +{ +} + +void Window::load(const QUrl &url) +{ + QQmlApplicationEngine::load(url); + + QQuickWindow *w = qobject_cast(rootObjects().first()); + + if (w) + w->installEventFilter(this); +} + +bool Window::eventFilter(QObject *obj, QEvent *e) +{ + if (e->type() == QEvent::Close) { + QPixmapCache::clear(); + clearComponentCache(); + deleteLater(); + e->accept(); + } + + return QObject::eventFilter(obj, e); +} diff --git a/window.h b/window.h new file mode 100644 index 0000000..e4c30de --- /dev/null +++ b/window.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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, see . + */ + +#ifndef WINDOW_H +#define WINDOW_H + +#include + +class Window : public QQmlApplicationEngine +{ + Q_OBJECT + +public: + explicit Window(QObject *parent = nullptr); + + void load(const QUrl &url); + +protected: + bool eventFilter(QObject *o, QEvent *e); +}; + +#endif // WINDOW_H