From 0bb15fb1bf7b859ab8393ecd8a55dfda7bc7fd1f Mon Sep 17 00:00:00 2001 From: Alf Gaida Date: Sat, 26 May 2018 02:25:33 +0200 Subject: [PATCH] Cherry-picking upstream release 0.13.0. * Bumped build dependency libfm-qt-dev to >= 0.13.0~ * Bumped build dependency lxqt-build-tools to >= 0.5.0~ * Added papirus-icon-theme as default alternative for icon-themes * Bumped year in copyright * Removed ported back upstream patches. * Moved debian/.gitignore -> ./.gitignore --- .gitignore | 17 +- AUTHORS | 2 +- CHANGELOG | 54 +++- CMakeLists.txt | 23 +- README.md | 51 ++-- .../translations/lxqt-desktop_es.desktop | 1 - config/CMakeLists.txt | 2 +- debian/changelog | 10 +- pcmanfm/CMakeLists.txt | 15 +- pcmanfm/about.ui | 2 +- pcmanfm/application.cpp | 32 ++- pcmanfm/autorundialog.cpp | 1 - pcmanfm/bulk-rename.ui | 92 +++++++ pcmanfm/bulkrename.cpp | 103 ++++++++ pcmanfm/bulkrename.h | 57 +++++ pcmanfm/connectserverdialog.cpp | 5 +- pcmanfm/desktoppreferencesdialog.cpp | 10 +- pcmanfm/desktopwindow.cpp | 174 +++++++++++-- pcmanfm/desktopwindow.h | 9 + pcmanfm/launcher.cpp | 15 +- pcmanfm/launcher.h | 2 +- pcmanfm/main-win.ui | 19 ++ pcmanfm/mainwindow.cpp | 235 +++++++++++++----- pcmanfm/mainwindow.h | 9 +- pcmanfm/pcmanfm-qt.desktop.in | 2 +- pcmanfm/pcmanfm.cpp | 2 +- pcmanfm/preferences.ui | 10 +- pcmanfm/preferencesdialog.cpp | 21 +- pcmanfm/settings.cpp | 14 ++ pcmanfm/settings.h | 39 ++- pcmanfm/tabbar.cpp | 83 ++++++- pcmanfm/tabbar.h | 17 +- pcmanfm/tabpage.cpp | 128 ++++++---- pcmanfm/tabpage.h | 8 +- .../pcmanfm-qt-desktop-pref_es.desktop | 3 + .../pcmanfm-qt-desktop-pref_tr.desktop | 2 +- .../pcmanfm-qt-desktop-pref_zh_CN.desktop | 4 + pcmanfm/translations/pcmanfm-qt_ar.desktop | 2 +- pcmanfm/translations/pcmanfm-qt_ca.desktop | 2 +- pcmanfm/translations/pcmanfm-qt_da.desktop | 2 +- pcmanfm/translations/pcmanfm-qt_el.desktop | 2 +- pcmanfm/translations/pcmanfm-qt_es.desktop | 3 + pcmanfm/translations/pcmanfm-qt_it.desktop | 2 +- pcmanfm/translations/pcmanfm-qt_lt.desktop | 2 +- pcmanfm/translations/pcmanfm-qt_pl.desktop | 2 +- pcmanfm/translations/pcmanfm-qt_pt.desktop | 2 +- pcmanfm/translations/pcmanfm-qt_pt_BR.desktop | 2 +- pcmanfm/translations/pcmanfm-qt_ru.desktop | 2 +- pcmanfm/translations/pcmanfm-qt_zh_CN.desktop | 4 + pcmanfm/view.cpp | 3 +- 50 files changed, 1046 insertions(+), 257 deletions(-) create mode 100644 pcmanfm/bulk-rename.ui create mode 100644 pcmanfm/bulkrename.cpp create mode 100644 pcmanfm/bulkrename.h create mode 100644 pcmanfm/translations/pcmanfm-qt-desktop-pref_es.desktop create mode 100644 pcmanfm/translations/pcmanfm-qt-desktop-pref_zh_CN.desktop create mode 100644 pcmanfm/translations/pcmanfm-qt_es.desktop create mode 100644 pcmanfm/translations/pcmanfm-qt_zh_CN.desktop diff --git a/.gitignore b/.gitignore index 424cad8..51594dc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,8 @@ -/*.debhelper -/*.log -/*.substvars -/debhelper-build-stamp -/files -/mangled +debian/*.debhelper +debian/*.log +debian/*.substvars +debian/debhelper-build-stamp +debian/files + +debian/pcmanfm-qt/ -/pcmanfm-qt/ -/libfm-qt5-2/ -/libfm-qt5-dev/ -/tmp diff --git a/AUTHORS b/AUTHORS index 40631a6..e7604db 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,5 +1,5 @@ Upstream Authors: - LXQt team: http://lxqt.org + LXQt team: https://lxqt.org Hong Jen Yee (PCMan) Copyright: diff --git a/CHANGELOG b/CHANGELOG index cde510c..c9ba01d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,59 @@ -pcmanfm-qt-0.12.0 / 2017-10-21 +pcmanfm-qt-0.13.0 / 2018-05-21 ============================== + * Check minimum version of libfm-qt + * Bumped minor version to 13 + * Spanish translation update + * Avoid using the old FmPath struct in libfm and use libfm-qt Fm::FilePath instead. + * Just changed a label in Preferences + * Replace the deprecated Fm::MountOperation::mount() with Fm::MountOperation::mountEnclosingVolume(). + * Cleanup + * Migrate to the new libfm-qt Fm::FileLauncher API. + * CMake: Prevent in-source builds + * Use new libfm-qt Fm::Archiver API. (#660) + * Fixed tab close button setting + * Optionally select newly created files + * fixes http -> https + * Fixed some lxde mentions + * Drop usage of Fm::IconTheme + * Add symlink target info to statusbar + * Add Simplified Chinese desktop entries (#640) + * Follow GLib to know if a file is hidden + * Remember hidden Places items between sessions + * Drop Qt foreach + * Use QString Use multi-arg + * Prevent a possible c++11 range-loop detach container (QList) + * Don't call QList::first() on temporary + * Warnings (#625) + * move config to /usr/share/pcmanfm-qt/lxqt + * Fixed the setting for "backup as hidden"" (#614) + * Sweep a desktop mess under the carpet + * cmake: Don't set CMP0063 + * cmake: Handle CMP0071 - Mark DBus files with SKIP_AUTOGEN + * cmake: Handle CMP0071 related to UI files. + * Refer to PCManFM-Qt in desktop entries + * Add Spanish desktop entries + * Use QChars + * Simplify if statements + * Const it + * Fix typos, move encloseWithBidiMarks to private and fix its behaviour + * Fix direction of statusbar message + * Give context to singleShot() + * Added a short comment + * Wait for events to be processed before chdir + * Rename progress dialog + * Basic bulk rename + * Really cancel multiple renaming on cancelling + * Initialize dragStarted_ in constructor + * Compact disconnection format + * Tab DND + * View tool-buttons + +0.12.0 / 2017-10-21 +=================== + + * Release 0.12.0: Update changelog * Set Version * removed dangeling symlink to debian dir * Text eliding, long texts and newline diff --git a/CMakeLists.txt b/CMakeLists.txt index 7544a18..5110cb1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,39 +1,38 @@ cmake_minimum_required(VERSION 3.0.2) project(pcmanfm-qt) -# CMP0063: Honor visibility properties for all target types. -if (POLICY CMP0063) - cmake_policy (SET CMP0063 NEW) -endif (POLICY CMP0063) - # PcmanFm-Qt Version set(PCMANFM_QT_VERSION_MAJOR 0) -set(PCMANFM_QT_VERSION_MINOR 12) +set(PCMANFM_QT_VERSION_MINOR 13) set(PCMANFM_QT_VERSION_PATCH 0) set(PCMANFM_QT_VERSION ${PCMANFM_QT_VERSION_MAJOR}.${PCMANFM_QT_VERSION_MINOR}.${PCMANFM_QT_VERSION_PATCH}) -set(LXQTBT_MINIMUM_VERSION "0.4.0") +set(QT_MINIMUM_VERSION "5.7.1") +set(LXQTBT_MINIMUM_VERSION "0.5.0") +set(LIBFMQT_MINIMUM_VERSION "5.0.0") list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") -find_package(Qt5Widgets 5.2 REQUIRED) -find_package(Qt5DBus 5.2 REQUIRED) -find_package(Qt5LinguistTools 5.2 REQUIRED) -find_package(Qt5X11Extras 5.2 REQUIRED) -find_package(fm-qt REQUIRED) +find_package(Qt5Widgets ${QT_MINIMUM_VERSION} REQUIRED) +find_package(Qt5DBus ${QT_MINIMUM_VERSION} REQUIRED) +find_package(Qt5LinguistTools ${QT_MINIMUM_VERSION} REQUIRED) +find_package(Qt5X11Extras ${QT_MINIMUM_VERSION} REQUIRED) +find_package(fm-qt ${LIBFMQT_MINIMUM_VERSION} REQUIRED) find_package(lxqt-build-tools ${LXQTBT_MINIMUM_VERSION} REQUIRED) message(STATUS "Building ${PROJECT_NAME} with Qt ${Qt5Core_VERSION}") option(UPDATE_TRANSLATIONS "Update source translation translations/*.ts files" OFF) include(GNUInstallDirs) +include(LXQtPreventInSourceBuilds) include(LXQtConfigVars) include(LXQtTranslateTs) include(LXQtTranslateDesktop) include(LXQtCompilerSettings NO_POLICY_SCOPE) set(CMAKE_AUTOMOC TRUE) +set(CMAKE_AUTOUIC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) add_subdirectory(pcmanfm) diff --git a/README.md b/README.md index 7c90abe..6040939 100644 --- a/README.md +++ b/README.md @@ -2,38 +2,61 @@ ## Overview -PCManFM-Qt is the Qt port of PCManFM, the file manager of [LXDE](http://lxde.org). +PCManFM-Qt is the Qt port of PCManFM, the file manager of [LXDE](https://lxde.org). -In LXQt sessions it is in addition used to handle the desktop. Nevertheless it can be used independently of LXQt as well. +In LXQt sessions it is in addition used to handle the desktop. Nevertheless it +can be used independently of LXQt as well. -PCManFM-Qt is licensed under the terms of the [GPLv2](https://www.gnu.org/licenses/gpl-2.0.en.html) or any later version. See file LICENSE for its full text. +PCManFM-Qt is licensed under the terms of the +[GPLv2](https://www.gnu.org/licenses/gpl-2.0.en.html) or any later version. See +file LICENSE for its full text. ## Installation ### Compiling source code -Runtime dependencies are qtx11extras, lxmenu-data, [liblxqt](https://github.com/lxde/liblxqt) and [libfm-qt](https://github.com/lxde/libfm-qt). -Additional build dependencies are CMake and optionally Git to pull latest VCS checkouts. The localization files were outsourced to repository [lxqt-l10n](https://github.com/lxde/lxqt-l10n) so the corresponding dependencies are needed, too. Please refer to this repository's `README.md` for further information. +Runtime dependencies are qtx11extras, lxmenu-data, +[liblxqt](https://github.com/lxqt/liblxqt) and +[libfm-qt](https://github.com/lxqt/libfm-qt). +Additional build dependencies are CMake and optionally Git to pull latest VCS +checkouts. The localization files were outsourced to repository +[lxqt-l10n](https://github.com/lxqt/lxqt-l10n) so the corresponding dependencies +are needed, too. Please refer to this repository's `README.md` for further information. -Code configuration is handled by CMake. CMake variable `CMAKE_INSTALL_PREFIX` has to be set to `/usr` on most operating systems, depending on the way library paths are dealt with on 64bit systems variables like `CMAKE_INSTALL_LIBDIR` may have to be set as well. +Code configuration is handled by CMake. CMake variable `CMAKE_INSTALL_PREFIX` +has to be set to `/usr` on most operating systems, depending on the way library +paths are dealt with on 64bit systems variables like `CMAKE_INSTALL_LIBDIR` may +have to be set as well. -To build run `make`, to install `make install` which accepts variable `DESTDIR` as usual. +To build run `make`, to install `make install` which accepts variable `DESTDIR` +as usual. ### Binary packages -Official binary packages are available in Arch Linux, Debian (as of Debian stretch), Fedora (version 0.10.0 only so far) and openSUSE (Leap 42.1 and Tumbleweed). +Official binary packages are available in Arch Linux, Debian (as of Debian stretch), +Fedora (version 0.10.0 only so far) and openSUSE (Leap 42.1 and Tumbleweed). ## Usage -The file manager functionality should be self-explanatory, handling of the desktop deserves some notes: +The file manager functionality should be self-explanatory, handling of the +desktop deserves some notes: -To handle the desktop binary `pcmanfm-qt` has to be launched with switch `--desktop` set. Optionally switch `--profile` can be used to safe settings specific to certain session types like the different desktop environments. -In LXQt sessions, PCManFM-Qt is launched with theses switches set as [LXQt Module](https://github.com/lxde/lxqt-session#lxqt-modules). +To handle the desktop binary `pcmanfm-qt` has to be launched with switch +`--desktop` set. Optionally switch `--profile` can be used to safe settings +specific to certain session types like the different desktop environments. +In LXQt sessions, PCManFM-Qt is launched with theses switches set as +[LXQt Module](https://github.com/lxqt/lxqt-session#lxqt-modules). -To configure the desktop there's a dialogue "Desktop Preferences". Technically it corresponds with launching `pcmanfm-qt` with switch `--desktop-pref` set. It is available in the desktop's context menu and included as topic "Desktop" in sub-menu Preferences - LXQt settings of the panel's main menu as well as the [Configuration Center](https://github.com/lxde/lxqt-config#configuration-center) of lxqt-config. +To configure the desktop there's a dialogue "Desktop Preferences". Technically +it corresponds with launching `pcmanfm-qt` with switch `--desktop-pref` set. It +is available in the desktop's context menu and included as topic "Desktop" in +sub-menu Preferences - LXQt settings of the panel's main menu as well as the +[Configuration Center](https://github.com/lxqt/lxqt-config#configuration-center) +of lxqt-config. -All switches (command line options) mentioned above are explained in detail in `man 1 pcmanfm-qt`. +All switches (command line options) mentioned above are explained in detail in +`man 1 pcmanfm-qt`. ## Development -Issues should go to the tracker of PCManFM-Qt at https://github.com/lxde/pcmanfm-qt/issues. +Issues should go to the tracker of PCManFM-Qt at https://github.com/lxqt/pcmanfm-qt/issues. diff --git a/autostart/translations/lxqt-desktop_es.desktop b/autostart/translations/lxqt-desktop_es.desktop index abbfb96..cc88ff1 100644 --- a/autostart/translations/lxqt-desktop_es.desktop +++ b/autostart/translations/lxqt-desktop_es.desktop @@ -1,2 +1 @@ -# Translations Name[es]=Escritorio diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt index e9cfe75..c86bfb3 100644 --- a/config/CMakeLists.txt +++ b/config/CMakeLists.txt @@ -3,6 +3,6 @@ configure_file(pcmanfm-qt/lxqt/settings.conf.in pcmanfm-qt/lxqt/settings.conf @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pcmanfm-qt/lxqt/settings.conf" - DESTINATION "${LXQT_ETC_XDG_DIR}/pcmanfm-qt/lxqt" + DESTINATION "${CMAKE_INSTALL_DATADIR}/pcmanfm-qt/lxqt" COMPONENT Runtime ) diff --git a/debian/changelog b/debian/changelog index d40afb4..648fc28 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,14 @@ pcmanfm-qt (0.13.0-1) experimental; urgency=medium - * + * Cherry-picking upstream release 0.13.0. + * Bumped build dependency libfm-qt-dev to >= 0.13.0~ + * Bumped build dependency lxqt-build-tools to >= 0.5.0~ + * Added papirus-icon-theme as default alternative for icon-themes + * Bumped year in copyright + * Removed ported back upstream patches. + * Moved debian/.gitignore -> ./.gitignore - -- Alf Gaida Mon, 21 May 2018 16:54:34 +0200 + -- Alf Gaida Sat, 26 May 2018 02:25:19 +0200 pcmanfm-qt (0.12.0-6) unstable; urgency=medium diff --git a/pcmanfm/CMakeLists.txt b/pcmanfm/CMakeLists.txt index b6dc98d..09a9eea 100644 --- a/pcmanfm/CMakeLists.txt +++ b/pcmanfm/CMakeLists.txt @@ -14,9 +14,10 @@ set(pcmanfm_SRCS autorundialog.cpp connectserverdialog.cpp settings.cpp + bulkrename.cpp ) -qt5_add_dbus_adaptor(pcmanfm_SRCS +qt5_add_dbus_adaptor(pcmanfm_DBUS_SRCS org.pcmanfm.Application.xml application.h PCManFM::Application @@ -24,6 +25,11 @@ qt5_add_dbus_adaptor(pcmanfm_SRCS ApplicationAdaptor ) +# qt5_add_dbus_adaptor() already generated the moc files. It also marked the +# files with SKIP_AUTOMOC but we still need to mark them witk SKIP_AUTOGEN. +# TODO: Check if this behaviour is a CMake bug. +set_source_files_properties(${pcmanfm_DBUS_SRCS} PROPERTIES SKIP_AUTOGEN ON) + set(pcmanfm_UIS main-win.ui about.ui @@ -32,10 +38,9 @@ set(pcmanfm_UIS desktop-folder.ui autorun.ui connect.ui + bulk-rename.ui ) -qt5_wrap_ui(pcmanfm_UIS_H ${pcmanfm_UIS}) - # add translation for pcmanfm-qt lxqt_translate_ts(QM_FILES UPDATE_TRANSLATIONS ${UPDATE_TRANSLATIONS} @@ -56,7 +61,8 @@ lxqt_translate_desktop(DESKTOP_FILES add_executable(pcmanfm-qt ${pcmanfm_SRCS} - ${pcmanfm_UIS_H} + ${pcmanfm_DBUS_SRCS} + ${pcmanfm_UIS} ${QM_FILES} ${DESKTOP_FILES} ) @@ -66,6 +72,7 @@ target_compile_definitions(pcmanfm-qt PCMANFM_DATA_DIR="${CMAKE_INSTALL_PREFIX}/share/pcmanfm-qt" PCMANFM_QT_VERSION="${PCMANFM_QT_VERSION}" LIBFM_DATA_DIR="${PKG_FM_PREFIX}/share/libfm" + QT_NO_FOREACH ) target_include_directories(pcmanfm-qt diff --git a/pcmanfm/about.ui b/pcmanfm/about.ui index bfce550..27bdd12 100644 --- a/pcmanfm/about.ui +++ b/pcmanfm/about.ui @@ -55,7 +55,7 @@ - <html><head/><body><p><a href="http://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">http://lxqt.org/</span></a></p></body></html> + <html><head/><body><p><a href="https://lxqt.org/"><span style=" text-decoration: underline; color:#0000ff;">https://lxqt.org/</span></a></p></body></html> Qt::RichText diff --git a/pcmanfm/application.cpp b/pcmanfm/application.cpp index f26b003..41acbf5 100644 --- a/pcmanfm/application.cpp +++ b/pcmanfm/application.cpp @@ -42,7 +42,6 @@ #include #include -#include #include #include "applicationadaptor.h" @@ -109,7 +108,6 @@ Application::Application(int& argc, char** argv): if(settings_.useFallbackIconTheme()) { QIcon::setThemeName(settings_.fallbackIconThemeName()); - Fm::IconTheme::checkChanged(); } // Check if LXQt Session is running. LXQt has it's own Desktop Folder @@ -379,7 +377,7 @@ void Application::onLastWindowClosed() { } -void Application::onSaveStateRequest(QSessionManager& manager) { +void Application::onSaveStateRequest(QSessionManager& /*manager*/) { } @@ -390,7 +388,8 @@ void Application::desktopManager(bool enabled) { if(enabled) { if(!enableDesktopManager_) { // installNativeEventFilter(this); - Q_FOREACH(QScreen* screen, screens()) { + const auto allScreens = screens(); + for(QScreen* screen : allScreens) { connect(screen, &QScreen::virtualGeometryChanged, this, &Application::onVirtualGeometryChanged); connect(screen, &QObject::destroyed, this, &Application::onScreenDestroyed); } @@ -425,7 +424,8 @@ void Application::desktopManager(bool enabled) { delete window; } desktopWindows_.clear(); - Q_FOREACH(QScreen* screen, screens()) { + const auto allScreens = screens(); + for(QScreen* screen : allScreens) { disconnect(screen, &QScreen::virtualGeometryChanged, this, &Application::onVirtualGeometryChanged); disconnect(screen, &QObject::destroyed, this, &Application::onScreenDestroyed); } @@ -460,10 +460,8 @@ void Application::onFindFileAccepted() { settings_.setSearchRecursive(dlg->recursive()); settings_.setSearchhHidden(dlg->searchhHidden()); - Fm::Path uri = dlg->searchUri(); Fm::FilePathList paths; - Fm::GFilePtr gf{uri.toGfile(), false}; - paths.push_back(Fm::FilePath{gf.get(), true}); + paths.emplace_back(dlg->searchUri()); MainWindow* window = MainWindow::lastActive(); Launcher(window).launchPaths(nullptr, paths); } @@ -500,11 +498,11 @@ void Application::connectToServer() { dlg->show(); } -void Application::launchFiles(QString cwd, QStringList paths, bool inNewWindow) { +void Application::launchFiles(QString cwd, QStringList paths, bool /*inNewWindow*/) { Fm::FilePathList pathList; Fm::FilePath cwd_path; QStringList::iterator it; - Q_FOREACH(const QString& it, paths) { + for(const QString& it : qAsConst(paths)) { QByteArray pathName = it.toLocal8Bit(); Fm::FilePath path; if(pathName == "~") { // special case for home dir @@ -588,7 +586,7 @@ void Application::setWallpaper(QString path, QString modeString) { // update wallpaper if(changed) { if(enableDesktopManager_) { - Q_FOREACH(DesktopWindow* desktopWindow, desktopWindows_) { + for(DesktopWindow* desktopWindow : qAsConst(desktopWindows_)) { if(!path.isEmpty()) { desktopWindow->setWallpaperFile(path); } @@ -760,7 +758,7 @@ bool Application::autoMountVolume(GVolume* volume, bool interactive) { } // static -void Application::onVolumeAdded(GVolumeMonitor* monitor, GVolume* volume, Application* pThis) { +void Application::onVolumeAdded(GVolumeMonitor* /*monitor*/, GVolume* volume, Application* pThis) { if(pThis->settings_.mountRemovable()) { pThis->autoMountVolume(volume, true); } @@ -788,7 +786,7 @@ void Application::onScreenAdded(QScreen* newScreen) { void Application::onScreenDestroyed(QObject* screenObj) { // NOTE by PCMan: This is a workaround for Qt 5 bug #40681. - // With this very dirty workaround, we can fix lxde/lxde-qt bug #204, #205, and #206. + // With this very dirty workaround, we can fix lxqt/lxqt bug #204, #205, and #206. // Qt 5 has two new regression bugs which breaks lxqt-panel in a multihead environment. // #40681: Regression bug: QWidget::winId() returns old value and QEvent::WinIdChange event is not emitted sometimes. (multihead setup) // #40791: Regression: QPlatformWindow, QWindow, and QWidget::winId() are out of sync. @@ -814,7 +812,7 @@ void Application::onScreenDestroyed(QObject* screenObj) { if(enableDesktopManager_) { bool reloadNeeded = false; // FIXME: add workarounds for Qt5 bug #40681 and #40791 here. - Q_FOREACH(DesktopWindow* desktop, desktopWindows_) { + for(DesktopWindow* desktop : qAsConst(desktopWindows_)) { if(desktop->windowHandle()->screen() == screenObj) { desktop->destroy(); // destroy the underlying native window reloadNeeded = true; @@ -829,7 +827,7 @@ void Application::onScreenDestroyed(QObject* screenObj) { void Application::reloadDesktopsAsNeeded() { if(enableDesktopManager_) { // workarounds for Qt5 bug #40681 and #40791 here. - Q_FOREACH(DesktopWindow* desktop, desktopWindows_) { + for(DesktopWindow* desktop : qAsConst(desktopWindows_)) { if(!desktop->windowHandle()) { desktop->create(); // re-create the underlying native window desktop->queueRelayout(); @@ -841,7 +839,7 @@ void Application::reloadDesktopsAsNeeded() { // This slot is for Qt 5 onlt, but the stupid Qt moc cannot do conditional compilation // so we have to define it for Qt 4 as well. -void Application::onVirtualGeometryChanged(const QRect& rect) { +void Application::onVirtualGeometryChanged(const QRect& /*rect*/) { // NOTE: the following is a workaround for Qt bug 32567. // https://bugreports.qt-project.org/browse/QTBUG-32567 // Though the status of the bug report is closed, it's not yet fixed for X11. @@ -852,7 +850,7 @@ void Application::onVirtualGeometryChanged(const QRect& rect) { // So we use it in Qt5. if(enableDesktopManager_) { // qDebug() << "onVirtualGeometryChanged"; - Q_FOREACH(DesktopWindow* desktop, desktopWindows_) { + for(DesktopWindow* desktop : qAsConst(desktopWindows_)) { desktop->queueRelayout(); } } diff --git a/pcmanfm/autorundialog.cpp b/pcmanfm/autorundialog.cpp index 3ecdb6f..5d129b7 100644 --- a/pcmanfm/autorundialog.cpp +++ b/pcmanfm/autorundialog.cpp @@ -19,7 +19,6 @@ #include "autorundialog.h" -#include #include #include "application.h" #include "mainwindow.h" diff --git a/pcmanfm/bulk-rename.ui b/pcmanfm/bulk-rename.ui new file mode 100644 index 0000000..8efb4cc --- /dev/null +++ b/pcmanfm/bulk-rename.ui @@ -0,0 +1,92 @@ + + + BulkRenameDialog + + + Bulk Rename + + + + 4 + + + + + -1000 + + + 1000 + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 5 + 5 + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + # will be replaced by numbers starting with: + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 5 + 5 + + + + + + + + Rename selected files to: + + + + + + + + 0 + 0 + + + + Name# + + + + + + + + diff --git a/pcmanfm/bulkrename.cpp b/pcmanfm/bulkrename.cpp new file mode 100644 index 0000000..59a6643 --- /dev/null +++ b/pcmanfm/bulkrename.cpp @@ -0,0 +1,103 @@ +/* + Copyright (C) 2017 Pedram Pourang (Tsu Jan) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "bulkrename.h" +#include +#include +#include +#include + +#include + +namespace PCManFM { + +BulkRenameDialog::BulkRenameDialog(QWidget* parent, Qt::WindowFlags flags) : + QDialog(parent, flags) { + ui.setupUi(this); + ui.lineEdit->setFocus(); + connect(ui.buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, this, &QDialog::accept); + connect(ui.buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, this, &QDialog::reject); + resize(minimumSize()); + setMaximumHeight(minimumHeight()); // no vertical resizing +} + +void BulkRenameDialog::showEvent(QShowEvent* event) { + QDialog::showEvent(event); + if(ui.lineEdit->text().endsWith(QLatin1Char('#'))) { // select what's before "#" + QTimer::singleShot(0, [this]() { + ui.lineEdit->setSelection(0, ui.lineEdit->text().size() - 1); + }); + } +} + +BulkRenamer::BulkRenamer(const Fm::FileInfoList& files, QWidget* parent) { + if(files.size() <= 1) { // no bulk rename with just one file + return; + } + QString baseName; + int start = 0; + BulkRenameDialog dlg(parent); + switch(dlg.exec()) { + case QDialog::Accepted: + baseName = dlg.getBaseName(); + start = dlg.getStart(); + break; + default: + return; + } + + if(!baseName.contains(QLatin1Char('#'))) { + // insert "#" before the last dot + int end = baseName.lastIndexOf(QLatin1Char('.')); + if(end == -1) { + end = baseName.size(); + } + baseName.insert(end, QLatin1Char('#')); + } + QProgressDialog progress(QObject::tr("Renaming files..."), QObject::tr("Abort"), 0, files.size(), parent); + progress.setWindowModality(Qt::WindowModal); + int i = 0, failed = 0; + for(auto& file: files) { + progress.setValue(i); + if(progress.wasCanceled()) { + progress.close(); + QMessageBox::warning(parent, QObject::tr("Warning"), QObject::tr("Renaming is aborted.")); + return; + } + auto fileName = QString::fromStdString(file->name()); + QString newName = baseName; + newName.replace(QLatin1Char('#'), QString::number(start + i)); + if (newName == fileName || !Fm::changeFileName(file->path(), newName, nullptr, false)) { + ++failed; + } + ++i; + } + progress.setValue(i); + if(failed == i) { + QMessageBox::critical(parent, QObject::tr("Error"), QObject::tr("No file could be renamed.")); + } + else if(failed > 0) { + QMessageBox::critical(parent, QObject::tr("Error"), QObject::tr("Some files could not be renamed.")); + } +} + +BulkRenamer::~BulkRenamer() { + +} + +} //namespace PCManFM diff --git a/pcmanfm/bulkrename.h b/pcmanfm/bulkrename.h new file mode 100644 index 0000000..7be8d15 --- /dev/null +++ b/pcmanfm/bulkrename.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2017 Pedram Pourang (Tsu Jan) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef PCMANFM_BULKRENAME_H +#define PCMANFM_BULKRENAME_H + +#include "ui_bulk-rename.h" +#include + +#include + +namespace PCManFM { + +class BulkRenameDialog : public QDialog { +Q_OBJECT + +public: + explicit BulkRenameDialog(QWidget* parent = nullptr, Qt::WindowFlags flags = 0); + + QString getBaseName() const { + return ui.lineEdit->text(); + } + int getStart() const { + return ui.spinBox->value(); + } + +protected: + virtual void showEvent(QShowEvent* event) override; + +private: + Ui::BulkRenameDialog ui; +}; + +class BulkRenamer { +public: + BulkRenamer(const Fm::FileInfoList& files, QWidget* parent = nullptr); + ~BulkRenamer(); +}; + +} + +#endif // PCMANFM_BULKRENAME_H diff --git a/pcmanfm/connectserverdialog.cpp b/pcmanfm/connectserverdialog.cpp index dd368f4..741973c 100644 --- a/pcmanfm/connectserverdialog.cpp +++ b/pcmanfm/connectserverdialog.cpp @@ -21,8 +21,7 @@ ConnectServerDialog::ConnectServerDialog(QWidget *parent): QDialog(parent) { connect(ui.host, &QLineEdit::textChanged, this, &ConnectServerDialog::checkInput); connect(ui.userName, &QLineEdit::textChanged, this, &ConnectServerDialog::checkInput); - - for(const auto& serverType: serverTypes) { + for(const auto& serverType : const_cast&>(serverTypes)) { ui.serverType->addItem(serverType.name); } @@ -62,7 +61,7 @@ QString ConnectServerDialog::uriText() { return uri; } -void ConnectServerDialog::onCurrentIndexChanged(int index) { +void ConnectServerDialog::onCurrentIndexChanged(int /*index*/) { int serverTypeIdx = ui.serverType->currentIndex(); const auto& serverType = serverTypes[serverTypeIdx]; ui.port->setValue(serverType.defaultPort); diff --git a/pcmanfm/desktoppreferencesdialog.cpp b/pcmanfm/desktoppreferencesdialog.cpp index 4c22c65..8f3c1a9 100644 --- a/pcmanfm/desktoppreferencesdialog.cpp +++ b/pcmanfm/desktoppreferencesdialog.cpp @@ -203,8 +203,8 @@ void DesktopPreferencesDialog::onBrowseClicked() { filter.reserve(256); filter = tr("Image Files"); filter += " ("; - QList formats = QImageReader::supportedImageFormats(); - Q_FOREACH(QByteArray format, formats) { + const QList formats = QImageReader::supportedImageFormats(); + for(const QByteArray& format : formats) { filter += "*."; filter += format.toLower(); filter += ' '; @@ -214,7 +214,7 @@ void DesktopPreferencesDialog::onBrowseClicked() { dlg.setNameFilterDetailsVisible(false); if(dlg.exec() == QDialog::Accepted) { QString filename; - filename = dlg.selectedFiles().first(); + filename = dlg.selectedFiles().constFirst(); ui.imageFile->setText(filename); } } @@ -227,7 +227,7 @@ void DesktopPreferencesDialog::onFolderBrowseClicked() { dlg.setDirectory(QDir::home().path()); if(dlg.exec() == QDialog::Accepted) { QString foldername; - foldername = dlg.selectedFiles().first(); + foldername = dlg.selectedFiles().constFirst(); ui.imageFolder->setText(foldername); } } @@ -240,7 +240,7 @@ void DesktopPreferencesDialog::onBrowseDesktopFolderClicked() dlg.setFileMode(QFileDialog::DirectoryOnly); if (dlg.exec() == QDialog::Accepted) { QString dir; - dir = dlg.selectedFiles().first(); + dir = dlg.selectedFiles().constFirst(); uiDesktopFolder.desktopFolder->setText(dir); } } diff --git a/pcmanfm/desktopwindow.cpp b/pcmanfm/desktopwindow.cpp index bf5e6f0..abe9061 100644 --- a/pcmanfm/desktopwindow.cpp +++ b/pcmanfm/desktopwindow.cpp @@ -52,6 +52,7 @@ #include #include #include "xdgdir.h" +#include "bulkrename.h" #include #include @@ -73,8 +74,10 @@ DesktopWindow::DesktopWindow(int screenNum): wallpaperRandomize_(false), fileLauncher_(nullptr), showWmMenu_(false), + desktopHideItems_(false), screenNum_(screenNum), - relayoutTimer_(nullptr) { + relayoutTimer_(nullptr), + selectionTimer_(nullptr) { QDesktopWidget* desktopWidget = QApplication::desktop(); setWindowFlags(Qt::Window | Qt::FramelessWindowHint); @@ -108,6 +111,8 @@ DesktopWindow::DesktopWindow(int screenNum): auto desktopPath = Fm::FilePath::fromLocalPath(XdgDir::readDesktopDir().toStdString().c_str()); model_ = Fm::CachedFolderModel::modelFromPath(desktopPath); folder_ = model_->folder(); + connect(folder_.get(), &Fm::Folder::startLoading, this, &DesktopWindow::onFolderStartLoading); + connect(folder_.get(), &Fm::Folder::finishLoading, this, &DesktopWindow::onFolderFinishLoading); proxyModel_ = new Fm::ProxyFolderModel(); proxyModel_->setSourceModel(model_); @@ -147,7 +152,7 @@ DesktopWindow::DesktopWindow(int screenNum): connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onPasteActivated); shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_A), this); // select all - connect(shortcut, &QShortcut::activated, this, &FolderView::selectAll); + connect(shortcut, &QShortcut::activated, this, &DesktopWindow::selectAll); shortcut = new QShortcut(QKeySequence(Qt::Key_Delete), this); // delete connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onDeleteActivated); @@ -155,7 +160,10 @@ DesktopWindow::DesktopWindow(int screenNum): shortcut = new QShortcut(QKeySequence(Qt::Key_F2), this); // rename connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onRenameActivated); - shortcut = new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Return), this); // rename + shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F2), this); // bulk rename + connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onBulkRenameActivated); + + shortcut = new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Return), this); // properties connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onFilePropertiesActivated); shortcut = new QShortcut(QKeySequence(Qt::SHIFT + Qt::Key_Delete), this); // force delete @@ -166,6 +174,8 @@ DesktopWindow::~DesktopWindow() { listView_->viewport()->removeEventFilter(this); listView_->removeEventFilter(this); + disconnect(folder_.get(), nullptr, this, nullptr); + if(relayoutTimer_) { relayoutTimer_->stop(); delete relayoutTimer_; @@ -181,6 +191,7 @@ DesktopWindow::~DesktopWindow() { } if(model_) { + disconnect(model_, &Fm::FolderModel::filesAdded, this, &DesktopWindow::onFilesAdded); model_->unref(); } } @@ -224,9 +235,31 @@ void DesktopWindow::resizeEvent(QResizeEvent* event) { } void DesktopWindow::setDesktopFolder() { + if(folder_) { + // free the previous model and folder + if(model_) { + disconnect(model_, &Fm::FolderModel::filesAdded, this, &DesktopWindow::onFilesAdded); + proxyModel_->setSourceModel(nullptr); + model_->unref(); // unref the cached model + model_ = nullptr; + } + disconnect(folder_.get(), nullptr, this, nullptr); + folder_ = nullptr; + } + auto path = Fm::FilePath::fromLocalPath(XdgDir::readDesktopDir().toStdString().c_str()); model_ = Fm::CachedFolderModel::modelFromPath(path); + folder_ = model_->folder(); + connect(folder_.get(), &Fm::Folder::startLoading, this, &DesktopWindow::onFolderStartLoading); + connect(folder_.get(), &Fm::Folder::finishLoading, this, &DesktopWindow::onFolderFinishLoading); proxyModel_->setSourceModel(model_); + if(folder_->isLoaded()) { + onFolderStartLoading(); + onFolderFinishLoading(); + } + else { + onFolderStartLoading(); + } } void DesktopWindow::setWallpaperFile(QString filename) { @@ -478,6 +511,13 @@ void DesktopWindow::updateFromSettings(Settings& settings, bool changeSlide) { setBackground(settings.desktopBgColor()); setShadow(settings.desktopShadowColor()); showWmMenu_ = settings.showWmMenu(); + desktopHideItems_ = settings.desktopHideItems(); + if(desktopHideItems_) { + // hide all items by hiding the list view and also + // prevent the current item from being changed by arrow keys + listView_->clearFocus(); + listView_->setVisible(false); + } if(slideShowInterval_ > 0 && QFileInfo(wallpaperDir_).isDir()) { @@ -516,7 +556,18 @@ void DesktopWindow::onFileClicked(int type, const std::shared_ptrexec(QCursor::pos()); + delete menu; + } + else { + View::onFileClicked(type, fileInfo); + } } void DesktopWindow::prepareFileMenu(Fm::FileMenu* menu) { @@ -543,11 +594,42 @@ void DesktopWindow::prepareFolderMenu(Fm::FolderMenu* menu) { PCManFM::View::prepareFolderMenu(menu); // remove file properties action menu->removeAction(menu->propertiesAction()); - // add an action for desktop preferences instead - QAction* action = menu->addAction(tr("Desktop Preferences")); + // add desktop actions instead + addDesktopActions(menu); +} + +void DesktopWindow::addDesktopActions(QMenu* menu) { + QAction* action = menu->addAction(tr("Hide Desktop Items")); + action->setCheckable(true); + action->setChecked(desktopHideItems_); + menu->addSeparator(); + connect(action, &QAction::triggered, this, &DesktopWindow::toggleDesktop); + action = menu->addAction(tr("Desktop Preferences")); connect(action, &QAction::triggered, this, &DesktopWindow::onDesktopPreferences); } +void DesktopWindow::toggleDesktop() { + desktopHideItems_ = !desktopHideItems_; + Settings& settings = static_cast(qApp)->settings(); + settings.setDesktopHideItems(desktopHideItems_); + listView_->setVisible(!desktopHideItems_); + // a relayout is needed on showing the items for the first time + // because the positions aren't updated while the view is hidden + if(!desktopHideItems_) { + listView_->setFocus(); // refocus the view + queueRelayout(); + } + else { // prevent the current item from being changed by arrow keys + listView_->clearFocus(); + } +} + +void DesktopWindow::selectAll() { + if(!desktopHideItems_) { + FolderView::selectAll(); + } +} + void DesktopWindow::onDesktopPreferences() { static_cast(qApp)->desktopPrefrences(QString()); } @@ -570,9 +652,8 @@ void DesktopWindow::onRowsAboutToBeRemoved(const QModelIndex& parent, int start, // Here we can't rely on ProxyFolderModel::fileInfoFromIndex() because, although rows // aren't removed yet, files are already removed. bool changed = false; - char* dektopPath = Fm::Path::getDesktop().toStr(); - QString desktopDir = QString(dektopPath) + QString("/"); - g_free(dektopPath); + QString desktopDir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); + desktopDir += '/'; for(auto it = customItemPos_.cbegin(); it != customItemPos_.cend();) { auto& name = it->first; if(!QFile::exists(desktopDir + QString::fromStdString(name))) { @@ -599,7 +680,7 @@ void DesktopWindow::onModelSortFilterChanged() { Settings& settings = static_cast(qApp)->settings(); settings.setDesktopSortColumn(static_cast(proxyModel_->sortColumn())); settings.setDesktopSortOrder(proxyModel_->sortOrder()); - settings.setSesktopSortFolderFirst(proxyModel_->folderFirst()); + settings.setDesktopSortFolderFirst(proxyModel_->folderFirst()); } void DesktopWindow::onDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) { @@ -633,7 +714,7 @@ void DesktopWindow::onIndexesMoved(const QModelIndexList& indexes) { auto delegate = static_cast(listView_->itemDelegateForColumn(0)); auto itemSize = delegate->itemSize(); // remember the custom position for the items - Q_FOREACH(const QModelIndex& index, indexes) { + for(const QModelIndex& index : indexes) { // Under some circumstances, Qt might emit indexMoved for // every single cells in the same row. (when QAbstractItemView::SelectItems is set) // So indexes list may contain several indixes for the same row. @@ -664,6 +745,35 @@ void DesktopWindow::onIndexesMoved(const QModelIndexList& indexes) { queueRelayout(); } +void DesktopWindow::onFolderStartLoading() { // desktop may be reloaded + if(model_) { + disconnect(model_, &Fm::FolderModel::filesAdded, this, &DesktopWindow::onFilesAdded); + } +} + +void DesktopWindow::onFolderFinishLoading() { + QTimer::singleShot(10, [this]() { // Qt delays the UI update (as in TabPage::onFolderFinishLoading) + if(model_) { + connect(model_, &Fm::FolderModel::filesAdded, this, &DesktopWindow::onFilesAdded); + } + }); +} + +void DesktopWindow::onFilesAdded(const Fm::FileInfoList files) { + if(static_cast(qApp)->settings().selectNewFiles()) { + if(!selectionTimer_) { + selectFiles(files, false); + selectionTimer_ = new QTimer (this); + selectionTimer_->setSingleShot(true); + selectionTimer_->start(200); + } + else { + selectFiles(files, selectionTimer_->isActive()); + selectionTimer_->start(200); + } + } +} + void DesktopWindow::removeBottomGap() { /************************************************************ NOTE: Desktop is an area bounded from below while icons snap @@ -673,7 +783,7 @@ void DesktopWindow::removeBottomGap() { ************************************************************/ auto delegate = static_cast(listView_->itemDelegateForColumn(0)); auto itemSize = delegate->itemSize(); - qDebug() << "delegate:" << delegate->itemSize(); + //qDebug() << "delegate:" << delegate->itemSize(); QSize cellMargins = getMargins(); int workAreaHeight = qApp->desktop()->availableGeometry(screenNum_).height() - 24; // a 12-pix margin will be considered everywhere @@ -828,17 +938,16 @@ void DesktopWindow::loadItemPositions() { auto grid = delegate->itemSize(); QRect workArea = qApp->desktop()->availableGeometry(screenNum_); workArea.adjust(12, 12, -12, -12); - char* dektopPath = Fm::Path::getDesktop().toStr(); - QString desktopDir = QString(dektopPath) + QString("/"); - g_free(dektopPath); - + QString desktopDir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); + desktopDir += '/'; std::vector usedPos; for(auto& item: customItemPos_) { usedPos.push_back(item.second); } // FIXME: this is inefficient - Q_FOREACH(const QString& name, file.childGroups()) { + const auto names = file.childGroups(); + for(const QString& name : names) { if(!QFile::exists(desktopDir + name.toUtf8())) { // the file may have been removed from outside LXQT continue; @@ -927,6 +1036,9 @@ void DesktopWindow::queueRelayout(int delay) { // slots for file operations void DesktopWindow::onCutActivated() { + if(desktopHideItems_) { + return; + } auto paths = selectedFilePaths(); if(!paths.empty()) { Fm::cutFilesToClipboard(paths); @@ -934,6 +1046,9 @@ void DesktopWindow::onCutActivated() { } void DesktopWindow::onCopyActivated() { + if(desktopHideItems_) { + return; + } auto paths = selectedFilePaths(); if(!paths.empty()) { Fm::copyFilesToClipboard(paths); @@ -941,10 +1056,16 @@ void DesktopWindow::onCopyActivated() { } void DesktopWindow::onPasteActivated() { + if(desktopHideItems_) { + return; + } Fm::pasteFilesFromClipboard(path()); } void DesktopWindow::onDeleteActivated() { + if(desktopHideItems_) { + return; + } auto paths = selectedFilePaths(); if(!paths.empty()) { Settings& settings = static_cast(qApp)->settings(); @@ -959,6 +1080,9 @@ void DesktopWindow::onDeleteActivated() { } void DesktopWindow::onRenameActivated() { + if(desktopHideItems_) { + return; + } // do inline renaming if only one item is selected, // otherwise use the renaming dialog if(selectedIndexes().size() == 1) { @@ -971,12 +1095,24 @@ void DesktopWindow::onRenameActivated() { auto files = selectedFiles(); if(!files.empty()) { for(auto& info: files) { - Fm::renameFile(info, nullptr); + if(!Fm::renameFile(info, nullptr)) { + break; + } } } } +void DesktopWindow::onBulkRenameActivated() { + if(desktopHideItems_) { + return; + } + BulkRenamer(selectedFiles(), this); +} + void DesktopWindow::onFilePropertiesActivated() { + if(desktopHideItems_) { + return; + } auto files = selectedFiles(); if(!files.empty()) { Fm::FilePropsDialog::showForFiles(std::move(files)); @@ -1052,7 +1188,7 @@ static void forwardMouseEventToRoot(QMouseEvent* event) { bool DesktopWindow::event(QEvent* event) { switch(event->type()) { case QEvent::WinIdChange: { - qDebug() << "winid change:" << effectiveWinId(); + //qDebug() << "winid change:" << effectiveWinId(); if(effectiveWinId() == 0) { break; } diff --git a/pcmanfm/desktopwindow.h b/pcmanfm/desktopwindow.h index fce9f63..07781a3 100644 --- a/pcmanfm/desktopwindow.h +++ b/pcmanfm/desktopwindow.h @@ -105,6 +105,8 @@ protected: protected Q_SLOTS: void onOpenDirRequested(const Fm::FilePath& path, int target); void onDesktopPreferences(); + void selectAll(); + void toggleDesktop(); void onRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end); void onRowsInserted(const QModelIndex& parent, int start, int end); @@ -112,6 +114,9 @@ protected Q_SLOTS: void onModelSortFilterChanged(); void onIndexesMoved(const QModelIndexList& indexes); void onDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); + void onFolderStartLoading(); + void onFolderFinishLoading(); + void onFilesAdded(const Fm::FileInfoList files); void relayoutItems(); void onStickToCurrentPos(bool toggled); @@ -123,11 +128,13 @@ protected Q_SLOTS: void onCopyActivated(); void onPasteActivated(); void onRenameActivated(); + void onBulkRenameActivated(); void onDeleteActivated(); void onFilePropertiesActivated(); private: void removeBottomGap(); + void addDesktopActions(QMenu* menu); void paintBackground(QPaintEvent* event); static void alignToGrid(QPoint& pos, const QPoint& topLeft, const QSize& grid, const int spacing); @@ -150,11 +157,13 @@ private: QPixmap wallpaperPixmap_; Launcher fileLauncher_; bool showWmMenu_; + bool desktopHideItems_; int screenNum_; std::unordered_map customItemPos_; QHash displayNames_; // only for desktop entries and shortcuts QTimer* relayoutTimer_; + QTimer* selectionTimer_; }; } diff --git a/pcmanfm/launcher.cpp b/pcmanfm/launcher.cpp index 113547e..14ec4c4 100644 --- a/pcmanfm/launcher.cpp +++ b/pcmanfm/launcher.cpp @@ -37,12 +37,11 @@ Launcher::~Launcher() { } -bool Launcher::openFolder(GAppLaunchContext* ctx, GList* folder_infos, GError** err) { - GList* l = folder_infos; - FmFileInfo* fi = FM_FILE_INFO(l->data); +bool Launcher::openFolder(GAppLaunchContext* /*ctx*/, const Fm::FileInfoList& folderInfos, Fm::GErrorPtr& /*err*/) { + auto fi = folderInfos[0]; Application* app = static_cast(qApp); MainWindow* mainWindow = mainWindow_; - Fm::FilePath path{fm_path_to_gfile(fm_file_info_get_path(fi)), false}; + Fm::FilePath path = fi->path(); if(!mainWindow) { mainWindow = new MainWindow(std::move(path)); mainWindow->resize(app->settings().windowWidth(), app->settings().windowHeight()); @@ -54,10 +53,10 @@ bool Launcher::openFolder(GAppLaunchContext* ctx, GList* folder_infos, GError** else { mainWindow->chdir(std::move(path)); } - l = l->next; - for(; l; l = l->next) { - fi = FM_FILE_INFO(l->data); - path = Fm::FilePath{fm_path_to_gfile(fm_file_info_get_path(fi)), false}; + + for(size_t i = 1; i < folderInfos.size(); ++i) { + fi = folderInfos[i]; + path = fi->path(); mainWindow->addTab(std::move(path)); } mainWindow->show(); diff --git a/pcmanfm/launcher.h b/pcmanfm/launcher.h index 0e158d2..7e0119c 100644 --- a/pcmanfm/launcher.h +++ b/pcmanfm/launcher.h @@ -33,7 +33,7 @@ public: ~Launcher(); protected: - virtual bool openFolder(GAppLaunchContext* ctx, GList* folder_infos, GError** err); + bool openFolder(GAppLaunchContext* ctx, const Fm::FileInfoList& folderInfos, Fm::GErrorPtr& err) override; private: MainWindow* mainWindow_; diff --git a/pcmanfm/main-win.ui b/pcmanfm/main-win.ui index fd1ee0e..ab57dd0 100644 --- a/pcmanfm/main-win.ui +++ b/pcmanfm/main-win.ui @@ -210,6 +210,9 @@ + + + @@ -278,6 +281,11 @@ + + + + + @@ -828,6 +836,17 @@ &Path Buttons + + + &Bulk Rename + + + Bulk Rename + + + Ctrl+F2 + + diff --git a/pcmanfm/mainwindow.cpp b/pcmanfm/mainwindow.cpp index e088feb..15aa4e2 100644 --- a/pcmanfm/mainwindow.cpp +++ b/pcmanfm/mainwindow.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,7 @@ #include #include "ui_about.h" #include "application.h" +#include "bulkrename.h" using namespace Fm; @@ -57,10 +59,10 @@ MainWindow::MainWindow(Fm::FilePath path): QMainWindow(), pathEntry_(nullptr), pathBar_(nullptr), + bookmarks_{Fm::Bookmarks::globalInstance()}, fileLauncher_(this), rightClickIndex_(-1), - updatingViewMenu_(false), - bookmarks_{Fm::Bookmarks::globalInstance()} { + updatingViewMenu_(false) { Settings& settings = static_cast(qApp)->settings(); setAttribute(Qt::WA_DeleteOnClose); @@ -90,7 +92,7 @@ MainWindow::MainWindow(Fm::FilePath path): // tabbed browsing interface ui.tabBar->setDocumentMode(true); - ui.tabBar->setTabsClosable(true); + ui.tabBar->setTabsClosable(settings.showTabClose()); ui.tabBar->setElideMode(Qt::ElideRight); ui.tabBar->setExpanding(false); ui.tabBar->setMovable(true); // reorder the tabs by dragging @@ -114,6 +116,7 @@ MainWindow::MainWindow(Fm::FilePath path): connect(ui.tabBar, &QTabBar::tabCloseRequested, this, &MainWindow::onTabBarCloseRequested); connect(ui.tabBar, &QTabBar::tabMoved, this, &MainWindow::onTabBarTabMoved); connect(ui.tabBar, &QTabBar::customContextMenuRequested, this, &MainWindow::tabContextMenu); + connect(ui.tabBar, &TabBar::tabDetached, this, &MainWindow::detachTab); connect(ui.stackedWidget, &QStackedWidget::widgetRemoved, this, &MainWindow::onStackedWidgetWidgetRemoved); // FIXME: should we make the filter bar a per-view configuration? @@ -124,12 +127,14 @@ MainWindow::MainWindow(Fm::FilePath path): // side pane ui.sidePane->setIconSize(QSize(settings.sidePaneIconSize(), settings.sidePaneIconSize())); ui.sidePane->setMode(settings.sidePaneMode()); + ui.sidePane->restoreHiddenPlaces(settings.getHiddenPlaces()); connect(ui.sidePane, &Fm::SidePane::chdirRequested, this, &MainWindow::onSidePaneChdirRequested); connect(ui.sidePane, &Fm::SidePane::openFolderInNewWindowRequested, this, &MainWindow::onSidePaneOpenFolderInNewWindowRequested); connect(ui.sidePane, &Fm::SidePane::openFolderInNewTabRequested, this, &MainWindow::onSidePaneOpenFolderInNewTabRequested); connect(ui.sidePane, &Fm::SidePane::openFolderInTerminalRequested, this, &MainWindow::onSidePaneOpenFolderInTerminalRequested); connect(ui.sidePane, &Fm::SidePane::createNewFolderRequested, this, &MainWindow::onSidePaneCreateNewFolderRequested); connect(ui.sidePane, &Fm::SidePane::modeChanged, this, &MainWindow::onSidePaneModeChanged); + connect(ui.sidePane, &Fm::SidePane::hiddenPlaceSet, this, &MainWindow::onSettingHiddenPlace); // detect change of splitter position connect(ui.splitter, &QSplitter::splitterMoved, this, &MainWindow::onSplitterMoved); @@ -158,6 +163,12 @@ MainWindow::MainWindow(Fm::FilePath path): connect(bookmarks_.get(), &Fm::Bookmarks::changed, this, &MainWindow::onBookmarksChanged); loadBookmarksMenu(); + // set generic icons for view actions + ui.actionIconView->setIcon(style()->standardIcon(QStyle::SP_FileDialogContentsView)); + ui.actionThumbnailView->setIcon(style()->standardIcon(QStyle::SP_FileDialogInfoView)); + ui.actionCompactView->setIcon(style()->standardIcon(QStyle::SP_FileDialogListView)); + ui.actionDetailedList->setIcon(style()->standardIcon(QStyle::SP_FileDialogDetailedView)); + // Fix the menu groups which is not done by Qt designer // To my suprise, this was supported in Qt designer 3 :-( QActionGroup* group = new QActionGroup(ui.menu_View); @@ -271,28 +282,31 @@ MainWindow::MainWindow(Fm::FilePath path): } // size from settings - if(settings.rememberWindowSize()) { - resize(settings.windowWidth(), settings.windowHeight()); - if(settings.windowMaximized()) { - setWindowState(windowState() | Qt::WindowMaximized); - } - } + resize(settings.windowWidth(), settings.windowHeight()); + if(settings.rememberWindowSize() && settings.windowMaximized()) { + setWindowState(windowState() | Qt::WindowMaximized); + } if(QApplication::layoutDirection() == Qt::RightToLeft) { setRTLIcons(true); } + + // we want tab dnd + setAcceptDrops(true); } MainWindow::~MainWindow() { } void MainWindow::chdir(Fm::FilePath path) { - TabPage* page = currentPage(); - if(page) { - ui.filterBar->clear(); - page->chdir(path, true); - updateUIForCurrentPage(); - } + // wait until queued events are processed + QTimer::singleShot(0, this, [this, path] { + if(TabPage* page = currentPage()) { + ui.filterBar->clear(); + page->chdir(path, true); + updateUIForCurrentPage(); + } + }); } void MainWindow::createPathBar(bool usePathButtons) { @@ -311,30 +325,38 @@ void MainWindow::createPathBar(bool usePathButtons) { ui.actionGo->setVisible(!usePathButtons); } -// add a new tab -int MainWindow::addTab(Fm::FilePath path) { - Settings& settings = static_cast(qApp)->settings(); +int MainWindow::addTabWithPage(TabPage* page, Fm::FilePath path) { + if(page == nullptr) { + return -1; + } + page->setFileLauncher(&fileLauncher_); + int index = ui.stackedWidget->addWidget(page); + connect(page, &TabPage::titleChanged, this, &MainWindow::onTabPageTitleChanged); + connect(page, &TabPage::statusChanged, this, &MainWindow::onTabPageStatusChanged); + connect(page, &TabPage::openDirRequested, this, &MainWindow::onTabPageOpenDirRequested); + connect(page, &TabPage::sortFilterChanged, this, &MainWindow::onTabPageSortFilterChanged); + connect(page, &TabPage::backwardRequested, this, &MainWindow::on_actionGoBack_triggered); + connect(page, &TabPage::forwardRequested, this, &MainWindow::on_actionGoForward_triggered); - TabPage* newPage = new TabPage(this); - newPage->setFileLauncher(&fileLauncher_); - int index = ui.stackedWidget->addWidget(newPage); - connect(newPage, &TabPage::titleChanged, this, &MainWindow::onTabPageTitleChanged); - connect(newPage, &TabPage::statusChanged, this, &MainWindow::onTabPageStatusChanged); - connect(newPage, &TabPage::openDirRequested, this, &MainWindow::onTabPageOpenDirRequested); - connect(newPage, &TabPage::sortFilterChanged, this, &MainWindow::onTabPageSortFilterChanged); - connect(newPage, &TabPage::backwardRequested, this, &MainWindow::on_actionGoBack_triggered); - connect(newPage, &TabPage::forwardRequested, this, &MainWindow::on_actionGoForward_triggered); - - newPage->chdir(path, true); - ui.tabBar->insertTab(index, newPage->windowTitle()); + if(path) { + page->chdir(path, true); + } + ui.tabBar->insertTab(index, page->windowTitle()); + Settings& settings = static_cast(qApp)->settings(); if(!settings.alwaysShowTabs()) { ui.tabBar->setVisible(ui.tabBar->count() > 1); } return index; } -void MainWindow::toggleMenuBar(bool checked) { +// add a new tab +int MainWindow::addTab(Fm::FilePath path) { + TabPage* newPage = new TabPage(this); + return addTabWithPage(newPage, path); +} + +void MainWindow::toggleMenuBar(bool /*checked*/) { Settings& settings = static_cast(qApp)->settings(); bool showMenuBar = !settings.showMenuBar(); @@ -375,33 +397,34 @@ void MainWindow::onPathBarMiddleClickChdir(const Fm::FilePath& dirPath) { } void MainWindow::on_actionGoUp_triggered() { - TabPage* page = currentPage(); - - if(page) { - ui.filterBar->clear(); - page->up(); - updateUIForCurrentPage(); - } + QTimer::singleShot(0, this, [this] { + if(TabPage* page = currentPage()) { + ui.filterBar->clear(); + page->up(); + updateUIForCurrentPage(); + } + }); } void MainWindow::on_actionGoBack_triggered() { - TabPage* page = currentPage(); - - if(page) { - ui.filterBar->clear(); - page->backward(); - updateUIForCurrentPage(); - } + QTimer::singleShot(0, this, [this] { + if(TabPage* page = currentPage()) { + ui.filterBar->clear(); + page->backward(); + updateUIForCurrentPage(); + } + }); } void MainWindow::on_actionGoForward_triggered() { - TabPage* page = currentPage(); + QTimer::singleShot(0, this, [this] { + if(TabPage* page = currentPage()) { + ui.filterBar->clear(); + page->forward(); + updateUIForCurrentPage(); + } + }); - if(page) { - ui.filterBar->clear(); - page->forward(); - updateUIForCurrentPage(); - } } void MainWindow::on_actionHome_triggered() { @@ -494,31 +517,31 @@ void MainWindow::on_actionShowHidden_triggered(bool checked) { } } -void MainWindow::on_actionByFileName_triggered(bool checked) { +void MainWindow::on_actionByFileName_triggered(bool /*checked*/) { currentPage()->sort(Fm::FolderModel::ColumnFileName, currentPage()->sortOrder()); } -void MainWindow::on_actionByMTime_triggered(bool checked) { +void MainWindow::on_actionByMTime_triggered(bool /*checked*/) { currentPage()->sort(Fm::FolderModel::ColumnFileMTime, currentPage()->sortOrder()); } -void MainWindow::on_actionByOwner_triggered(bool checked) { +void MainWindow::on_actionByOwner_triggered(bool /*checked*/) { currentPage()->sort(Fm::FolderModel::ColumnFileOwner, currentPage()->sortOrder()); } -void MainWindow::on_actionByFileSize_triggered(bool checked) { +void MainWindow::on_actionByFileSize_triggered(bool /*checked*/) { currentPage()->sort(Fm::FolderModel::ColumnFileSize, currentPage()->sortOrder()); } -void MainWindow::on_actionByFileType_triggered(bool checked) { +void MainWindow::on_actionByFileType_triggered(bool /*checked*/) { currentPage()->sort(Fm::FolderModel::ColumnFileType, currentPage()->sortOrder()); } -void MainWindow::on_actionAscending_triggered(bool checked) { +void MainWindow::on_actionAscending_triggered(bool /*checked*/) { currentPage()->sort(currentPage()->sortColumn(), Qt::AscendingOrder); } -void MainWindow::on_actionDescending_triggered(bool checked) { +void MainWindow::on_actionDescending_triggered(bool /*checked*/) { currentPage()->sort(currentPage()->sortColumn(), Qt::DescendingOrder); } @@ -530,7 +553,7 @@ void MainWindow::on_actionFolderFirst_triggered(bool checked) { currentPage()->setSortFolderFirst(checked); } -void MainWindow::on_actionPreserveView_triggered(bool checked) { +void MainWindow::on_actionPreserveView_triggered(bool /*checked*/) { TabPage* page = currentPage(); page->setCustomizedView(!page->hasCustomizedView()); } @@ -623,7 +646,7 @@ void MainWindow::on_actionAbout_triggered() { // the about dialog class AboutDialog : public QDialog { public: - explicit AboutDialog(QWidget* parent = 0, Qt::WindowFlags f = 0) { + explicit AboutDialog(QWidget* parent = 0, Qt::WindowFlags f = 0) : QDialog(parent, f) { ui.setupUi(this); ui.version->setText(tr("Version: %1").arg(PCMANFM_QT_VERSION)); } @@ -816,7 +839,7 @@ void MainWindow::updateViewMenuForCurrentPage() { void MainWindow::updateEditSelectedActions() { bool hasAccessible(false); bool hasDeletable(false); - bool hasRenamable(false); + int renamable(0); if(TabPage* page = currentPage()) { auto files = page->selectedFiles(); for(auto& file: files) { @@ -827,9 +850,9 @@ void MainWindow::updateEditSelectedActions() { hasDeletable = true; } if(file->canSetName()) { - hasRenamable = true; + ++renamable; } - if (hasAccessible && hasDeletable && hasRenamable) { + if (hasAccessible && hasDeletable && renamable > 1) { break; } } @@ -837,7 +860,8 @@ void MainWindow::updateEditSelectedActions() { ui.actionCopy->setEnabled(hasAccessible); ui.actionCut->setEnabled(hasDeletable); ui.actionDelete->setEnabled(hasDeletable); - ui.actionRename->setEnabled(hasRenamable); + ui.actionRename->setEnabled(renamable > 0); + ui.actionBulkRename->setEnabled(renamable > 1); } void MainWindow::updateUIForCurrentPage() { @@ -1013,7 +1037,11 @@ void MainWindow::onSidePaneModeChanged(Fm::SidePane::Mode mode) { static_cast(qApp)->settings().setSidePaneMode(mode); } -void MainWindow::onSplitterMoved(int pos, int index) { +void MainWindow::onSettingHiddenPlace(const QString& str, bool hide) { + static_cast(qApp)->settings().setHiddenPlace(str, hide); +} + +void MainWindow::onSplitterMoved(int pos, int /*index*/) { Application* app = static_cast(qApp); app->settings().setSplitterPos(pos); } @@ -1116,11 +1144,16 @@ void MainWindow::on_actionRename_triggered() { } if(!files.empty()) { for(auto& file: files) { - Fm::renameFile(file, nullptr); + if(!Fm::renameFile(file, nullptr)) { + break; + } } } } +void MainWindow::on_actionBulkRename_triggered() { + BulkRenamer(currentPage()->selectedFiles(), this); +} void MainWindow::on_actionSelectAll_triggered() { currentPage()->selectAll(); @@ -1181,12 +1214,12 @@ void MainWindow::onBackForwardContextMenu(QPoint pos) { Fm::BrowseHistory& history = page->browseHistory(); int current = history.currentIndex(); QMenu menu; - for(int i = 0; i < history.size(); ++i) { + for(size_t i = 0; i < history.size(); ++i) { const BrowseHistoryItem& item = history.at(i); auto path = item.path(); auto name = path.displayName(); QAction* action = menu.addAction(name.get()); - if(i == current) { + if(i == static_cast(current)) { // make the current path bold and checked action->setCheckable(true); action->setChecked(true); @@ -1256,6 +1289,70 @@ void MainWindow::focusPathEntry() { } } +void MainWindow::dragEnterEvent(QDragEnterEvent* event) { + if(event->mimeData()->hasFormat("application/pcmanfm-qt-tab")) { + event->acceptProposedAction(); + } +} + +void MainWindow::dropEvent(QDropEvent* event) { + if(event->mimeData()->hasFormat("application/pcmanfm-qt-tab")) { + dropTab(); + } + event->acceptProposedAction(); +} + +void MainWindow::dropTab() { + if(lastActive_ == nullptr // impossible + || lastActive_ == this) { // don't drop on the same window + ui.tabBar->finishMouseMoveEvent(); + return; + } + + // close the tab in the first window and add + // its page to a new tab in the second window + TabPage* dropPage = lastActive_->currentPage(); + if(dropPage) { + disconnect(dropPage, nullptr, lastActive_, nullptr); + + // release mouse before tab removal because otherwise, the source tabbar + // might not be updated properly with tab reordering during a fast drag-and-drop + lastActive_->ui.tabBar->releaseMouse(); + + QWidget* page = lastActive_->ui.stackedWidget->currentWidget(); + lastActive_->ui.stackedWidget->removeWidget(page); + int index = addTabWithPage(dropPage); + ui.tabBar->setCurrentIndex(index); + } + else { + ui.tabBar->finishMouseMoveEvent(); // impossible + } +} + +void MainWindow::detachTab() { + if (ui.stackedWidget->count() == 1) { // don't detach a single tab + ui.tabBar->finishMouseMoveEvent(); + return; + } + + // close the tab and move its page to a new window + TabPage* dropPage = currentPage(); + if(dropPage) { + disconnect(dropPage, nullptr, this, nullptr); + + ui.tabBar->releaseMouse(); // as in dropTab() + + QWidget* page = ui.stackedWidget->currentWidget(); + ui.stackedWidget->removeWidget(page); + MainWindow* newWin = new MainWindow(); + newWin->addTabWithPage(dropPage); + newWin->show(); + } + else { + ui.tabBar->finishMouseMoveEvent(); // impossible + } +} + void MainWindow::updateFromSettings(Settings& settings) { // apply settings @@ -1289,7 +1386,7 @@ void MainWindow::updateFromSettings(Settings& settings) { } } -static const char* su_cmd_subst(char opt, gpointer user_data) { +static const char* su_cmd_subst(char /*opt*/, gpointer user_data) { return (const char*)user_data; } diff --git a/pcmanfm/mainwindow.h b/pcmanfm/mainwindow.h index 1cf4543..ab01913 100644 --- a/pcmanfm/mainwindow.h +++ b/pcmanfm/mainwindow.h @@ -32,7 +32,6 @@ #include #include #include "launcher.h" -#include #include #include @@ -85,6 +84,7 @@ protected Q_SLOTS: void on_actionPaste_triggered(); void on_actionDelete_triggered(); void on_actionRename_triggered(); + void on_actionBulkRename_triggered(); void on_actionSelectAll_triggered(); void on_actionInvertSelection_triggered(); void on_actionPreferences_triggered(); @@ -173,15 +173,20 @@ protected Q_SLOTS: } void focusPathEntry(); void toggleMenuBar(bool checked); + void detachTab(); void onBookmarksChanged(); + void onSettingHiddenPlace(const QString& str, bool hide); + protected: bool event(QEvent* event) override; void changeEvent(QEvent* event) override; void closeTab(int index); virtual void resizeEvent(QResizeEvent* event) override; virtual void closeEvent(QCloseEvent* event) override; + virtual void dragEnterEvent(QDragEnterEvent* event) override; + virtual void dropEvent(QDropEvent* event) override; private: void loadBookmarksMenu(); @@ -191,6 +196,8 @@ private: void updateStatusBarForCurrentPage(); void setRTLIcons(bool isRTL); void createPathBar(bool usePathButtons); + int addTabWithPage(TabPage* page, Fm::FilePath path = Fm::FilePath()); + void dropTab(); private: Ui::MainWindow ui; diff --git a/pcmanfm/pcmanfm-qt.desktop.in b/pcmanfm/pcmanfm-qt.desktop.in index 0b1a75a..fa7a949 100644 --- a/pcmanfm/pcmanfm-qt.desktop.in +++ b/pcmanfm/pcmanfm-qt.desktop.in @@ -1,6 +1,6 @@ [Desktop Entry] Type=Application -Name=PCManFM File Manager +Name=PCManFM-Qt File Manager GenericName=File Manager Comment=Browse the file system and manage the files Exec=pcmanfm-qt %U diff --git a/pcmanfm/pcmanfm.cpp b/pcmanfm/pcmanfm.cpp index ea3bacd..2b56c36 100644 --- a/pcmanfm/pcmanfm.cpp +++ b/pcmanfm/pcmanfm.cpp @@ -4,7 +4,7 @@ int main(int argc, char** argv) { // ensure that glib integration of Qt is not turned off - // This fixes #168: https://github.com/lxde/pcmanfm-qt/issues/168 + // This fixes #168: https://github.com/lxqt/pcmanfm-qt/issues/168 qunsetenv("QT_NO_GLIB"); PCManFM::Application app(argc, argv); diff --git a/pcmanfm/preferences.ui b/pcmanfm/preferences.ui index c7e6c9d..bc50214 100644 --- a/pcmanfm/preferences.ui +++ b/pcmanfm/preferences.ui @@ -190,7 +190,15 @@ - Don't ask options on launch executable file + Launch executable files without prompt +(Requires application restart to take effect) + + + + + + + Select newly created files diff --git a/pcmanfm/preferencesdialog.cpp b/pcmanfm/preferencesdialog.cpp index da4095e..4da33b0 100644 --- a/pcmanfm/preferencesdialog.cpp +++ b/pcmanfm/preferencesdialog.cpp @@ -28,6 +28,7 @@ #include #include +#include namespace PCManFM { @@ -52,9 +53,9 @@ PreferencesDialog::~PreferencesDialog() { static void findIconThemesInDir(QHash& iconThemes, QString dirName) { QDir dir(dirName); - QStringList subDirs = dir.entryList(QDir::AllDirs); + const QStringList subDirs = dir.entryList(QDir::AllDirs); GKeyFile* kf = g_key_file_new(); - Q_FOREACH(QString subDir, subDirs) { + for(const QString& subDir : subDirs) { QString indexFile = dirName % '/' % subDir % "/index.theme"; if(g_key_file_load_from_file(kf, indexFile.toLocal8Bit().constData(), GKeyFileFlags(0), nullptr)) { // FIXME: skip hidden ones @@ -117,12 +118,11 @@ void PreferencesDialog::initIconThemes(Settings& settings) { } void PreferencesDialog::initArchivers(Settings& settings) { - const GList* allArchivers = fm_archiver_get_all(); - int i = 0; - for(const GList* l = allArchivers; l; l = l->next, ++i) { - FmArchiver* archiver = reinterpret_cast(l->data); - ui.archiver->addItem(archiver->program, QString(archiver->program)); - if(archiver->program == settings.archiver()) { + auto& allArchivers = Fm::Archiver::allArchivers(); + for(int i = 0; i < int(allArchivers.size()); ++i) { + auto& archiver = allArchivers[i]; + ui.archiver->addItem(archiver->program(), QString(archiver->program())); + if(archiver->program() == settings.archiver()) { ui.archiver->setCurrentIndex(i); } } @@ -220,6 +220,7 @@ void PreferencesDialog::initBehaviorPage(Settings& settings) { ui.noUsbTrash->setChecked(settings.noUsbTrash()); ui.confirmTrash->setChecked(settings.confirmTrash()); ui.quickExec->setChecked(settings.quickExec()); + ui.selectNewFiles->setChecked(settings.selectNewFiles()); } void PreferencesDialog::initThumbnailPage(Settings& settings) { @@ -281,7 +282,8 @@ void PreferencesDialog::applyDisplayPage(Settings& settings) { settings.setFallbackIconThemeName(newIconTheme); QIcon::setThemeName(settings.fallbackIconThemeName()); // update the UI by emitting a style change event - Q_FOREACH(QWidget* widget, QApplication::allWidgets()) { + const auto widgets = QApplication::allWidgets(); + for(QWidget* widget : widgets) { QEvent event(QEvent::StyleChange); QApplication::sendEvent(widget, &event); } @@ -327,6 +329,7 @@ void PreferencesDialog::applyBehaviorPage(Settings& settings) { settings.setNoUsbTrash(ui.noUsbTrash->isChecked()); settings.setConfirmTrash(ui.confirmTrash->isChecked()); settings.setQuickExec(ui.quickExec->isChecked()); + settings.setSelectNewFiles(ui.selectNewFiles->isChecked()); } void PreferencesDialog::applyThumbnailPage(Settings& settings) { diff --git a/pcmanfm/settings.cpp b/pcmanfm/settings.cpp index 284f25f..154d7d5 100644 --- a/pcmanfm/settings.cpp +++ b/pcmanfm/settings.cpp @@ -73,6 +73,7 @@ Settings::Settings(): desktopIconSize_(48), showWmMenu_(false), desktopShowHidden_(false), + desktopHideItems_(false), desktopSortOrder_(Qt::AscendingOrder), desktopSortColumn_(Fm::FolderModel::ColumnFileMTime), desktopSortFolderFirst_(true), @@ -104,6 +105,7 @@ Settings::Settings(): noUsbTrash_(false), confirmTrash_(false), quickExec_(false), + selectNewFiles_(false), showThumbnails_(true), archiver_(), siUnit_(false), @@ -207,6 +209,7 @@ bool Settings::loadFile(QString filePath) { setNoUsbTrash(settings.value("NoUsbTrash", false).toBool()); confirmTrash_ = settings.value("ConfirmTrash", false).toBool(); setQuickExec(settings.value("QuickExec", false).toBool()); + selectNewFiles_ = settings.value("SelectNewFiles", false).toBool(); // bool thumbnailLocal_; // bool thumbnailMax; settings.endGroup(); @@ -230,6 +233,7 @@ bool Settings::loadFile(QString filePath) { desktopIconSize_ = settings.value("DesktopIconSize", 48).toInt(); showWmMenu_ = settings.value("ShowWmMenu", false).toBool(); desktopShowHidden_ = settings.value("ShowHidden", false).toBool(); + desktopHideItems_ = settings.value("HideItems", false).toBool(); desktopSortOrder_ = sortOrderFromString(settings.value("SortOrder").toString()); desktopSortColumn_ = sortColumnFromString(settings.value("SortColumn").toString()); @@ -283,6 +287,7 @@ bool Settings::loadFile(QString filePath) { placesRoot_ = settings.value("PlacesRoot", true).toBool(); placesComputer_ = settings.value("PlacesComputer", true).toBool(); placesNetwork_ = settings.value("PlacesNetwork", true).toBool(); + hiddenPlaces_ = settings.value("HiddenPlaces").toStringList().toSet(); settings.endGroup(); settings.beginGroup("Window"); @@ -339,6 +344,7 @@ bool Settings::saveFile(QString filePath) { settings.setValue("NoUsbTrash", noUsbTrash_); settings.setValue("ConfirmTrash", confirmTrash_); settings.setValue("QuickExec", quickExec_); + settings.setValue("SelectNewFiles", selectNewFiles_); // bool thumbnailLocal_; // bool thumbnailMax; settings.endGroup(); @@ -357,6 +363,7 @@ bool Settings::saveFile(QString filePath) { settings.setValue("DesktopIconSize", desktopIconSize_); settings.setValue("ShowWmMenu", showWmMenu_); settings.setValue("ShowHidden", desktopShowHidden_); + settings.setValue("HideItems", desktopHideItems_); settings.setValue("SortOrder", sortOrderToString(desktopSortOrder_)); settings.setValue("SortColumn", sortColumnToString(desktopSortColumn_)); settings.setValue("SortFolderFirst", desktopSortFolderFirst_); @@ -406,6 +413,13 @@ bool Settings::saveFile(QString filePath) { settings.setValue("PlacesRoot", placesRoot_); settings.setValue("PlacesComputer", placesComputer_); settings.setValue("PlacesNetwork", placesNetwork_); + if (hiddenPlaces_.isEmpty()) { // don't save "@Invalid()" + settings.remove("HiddenPlaces"); + } + else { + QStringList hiddenPlaces = hiddenPlaces_.toList(); + settings.setValue("HiddenPlaces", hiddenPlaces); + } settings.endGroup(); settings.beginGroup("Window"); diff --git a/pcmanfm/settings.h b/pcmanfm/settings.h index 5ca17fd..45b49f7 100644 --- a/pcmanfm/settings.h +++ b/pcmanfm/settings.h @@ -28,6 +28,7 @@ #include "desktopwindow.h" #include #include +#include namespace PCManFM { @@ -189,9 +190,7 @@ public: void setArchiver(QString archiver) { archiver_ = archiver; - // override libfm FmConfig - g_free(fm_config->archiver); - fm_config->archiver = g_strdup(archiver_.toLocal8Bit().constData()); + Fm::Archiver::setDefaultArchiverByName(archiver_.toLocal8Bit().constData()); } bool mountOnStartup() const { @@ -330,6 +329,14 @@ public: desktopShowHidden_ = desktopShowHidden; } + bool desktopHideItems() const { + return desktopHideItems_; + } + + void setDesktopHideItems(bool hide) { + desktopHideItems_ = hide; + } + Qt::SortOrder desktopSortOrder() const { return desktopSortOrder_; } @@ -350,7 +357,7 @@ public: return desktopSortFolderFirst_; } - void setSesktopSortFolderFirst(bool desktopFolderFirst) { + void setDesktopSortFolderFirst(bool desktopFolderFirst) { desktopSortFolderFirst_ = desktopFolderFirst; } @@ -546,6 +553,19 @@ public: placesNetwork_ = placesNetwork; } + QSet getHiddenPlaces() const { + return hiddenPlaces_; + } + + void setHiddenPlace(const QString& str, bool hide) { + if(hide) { + hiddenPlaces_ << str; + } + else { + hiddenPlaces_.remove(str); + } + } + Qt::SortOrder sortOrder() const { return sortOrder_; @@ -649,6 +669,14 @@ public: fm_config->quick_exec = quickExec_; } + bool selectNewFiles() const { + return selectNewFiles_; + } + + void setSelectNewFiles(bool value) { + selectNewFiles_ = value; + } + // bool thumbnailLocal_; // bool thumbnailMax; @@ -874,6 +902,7 @@ private: bool showWmMenu_; bool desktopShowHidden_; + bool desktopHideItems_; Qt::SortOrder desktopSortOrder_; Fm::FolderModel::ColumnId desktopSortColumn_; bool desktopSortFolderFirst_; @@ -908,6 +937,7 @@ private: bool noUsbTrash_; // do not trash files on usb removable devices bool confirmTrash_; // Confirm before moving files into "trash can" bool quickExec_; // Don't ask options on launch executable file + bool selectNewFiles_; bool showThumbnails_; @@ -924,6 +954,7 @@ private: bool placesRoot_; bool placesComputer_; bool placesNetwork_; + QSet hiddenPlaces_; int bigIconSize_; int smallIconSize_; diff --git a/pcmanfm/tabbar.cpp b/pcmanfm/tabbar.cpp index f6bf1e5..859e4a0 100644 --- a/pcmanfm/tabbar.cpp +++ b/pcmanfm/tabbar.cpp @@ -19,23 +19,92 @@ #include "tabbar.h" +#include #include +#include +#include +#include namespace PCManFM { TabBar::TabBar(QWidget *parent): - QTabBar(parent) + QTabBar(parent), + dragStarted_(false) { } +void TabBar::mousePressEvent(QMouseEvent *event) { + QTabBar::mousePressEvent (event); + if(event->button() == Qt::LeftButton + && tabAt(event->pos()) > -1) { + dragStartPosition_ = event->pos(); + } + dragStarted_ = false; +} + +void TabBar::mouseMoveEvent(QMouseEvent *event) +{ + if(!dragStartPosition_.isNull() + && (event->pos() - dragStartPosition_).manhattanLength() < QApplication::startDragDistance()) { + dragStarted_ = true; + } + + if((event->buttons() & Qt::LeftButton) + && dragStarted_ + && !window()->geometry().contains(event->globalPos())) { + if(currentIndex() == -1) { + return; + } + + QPointer drag = new QDrag(this); + QMimeData *mimeData = new QMimeData; + mimeData->setData("application/pcmanfm-qt-tab", QByteArray()); + drag->setMimeData(mimeData); + Qt::DropAction dragged = drag->exec(); + if(dragged == Qt::IgnoreAction) { // a tab is dropped outside all windows + if(count() > 1) { + Q_EMIT tabDetached(); + } + else { + finishMouseMoveEvent(); + } + event->accept(); + } + else if(dragged == Qt::MoveAction) { // a tab is dropped into another window + event->accept(); + } + drag->deleteLater(); + } + else { + QTabBar::mouseMoveEvent(event); + } +} + +void TabBar::finishMouseMoveEvent() { + QMouseEvent finishingEvent(QEvent::MouseMove, QPoint(), Qt::NoButton, Qt::NoButton, Qt::NoModifier); + mouseMoveEvent(&finishingEvent); +} + +void TabBar::releaseMouse() { + QMouseEvent releasingEvent(QEvent::MouseButtonRelease, QPoint(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier); + mouseReleaseEvent(&releasingEvent); +} + void TabBar::mouseReleaseEvent(QMouseEvent *event) { - if (event->button() == Qt::MiddleButton) { - int index = tabAt(event->pos()); - if (index != -1) { - Q_EMIT tabCloseRequested(index); + if (event->button() == Qt::MiddleButton) { + int index = tabAt(event->pos()); + if (index != -1) { + Q_EMIT tabCloseRequested(index); + } + } + QTabBar::mouseReleaseEvent(event); +} + +// Let the main window receive dragged tabs! +void TabBar::dragEnterEvent(QDragEnterEvent *event) { + if(event->mimeData()->hasFormat("application/pcmanfm-qt-tab")) { + event->ignore(); } - } - QTabBar::mouseReleaseEvent(event); } } diff --git a/pcmanfm/tabbar.h b/pcmanfm/tabbar.h index a7ac764..c5573cb 100644 --- a/pcmanfm/tabbar.h +++ b/pcmanfm/tabbar.h @@ -31,10 +31,23 @@ class TabBar : public QTabBar { Q_OBJECT public: - explicit TabBar(QWidget *parent = 0); + explicit TabBar(QWidget *parent = 0); + void finishMouseMoveEvent(); + void releaseMouse(); + +Q_SIGNALS: + void tabDetached(); protected: - void mouseReleaseEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + // from qtabbar.cpp + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseMoveEvent(QMouseEvent *event); + virtual void dragEnterEvent(QDragEnterEvent *event); + +private: + QPoint dragStartPosition_; + bool dragStarted_; }; } diff --git a/pcmanfm/tabpage.cpp b/pcmanfm/tabpage.cpp index 929192f..a96d682 100644 --- a/pcmanfm/tabpage.cpp +++ b/pcmanfm/tabpage.cpp @@ -46,38 +46,12 @@ bool ProxyFilter::filterAcceptsRow(const Fm::ProxyFolderModel* model, const std: return true; } QString baseName = QString::fromStdString(info->name()); - if(!virtHiddenList_.isEmpty() && !model->showHidden() && virtHiddenList_.contains(baseName)) { - return false; - } if(!filterStr_.isEmpty() && !baseName.contains(filterStr_, Qt::CaseInsensitive)) { return false; } return true; } -void ProxyFilter::setVirtHidden(const std::shared_ptr &folder) { - virtHiddenList_ = QStringList(); // reset the list - if(!folder) { - return; - } - auto path = folder->path(); - if(path) { - auto pathStr = path.localPath(); - if(pathStr) { - QString dotHidden = QString::fromUtf8(pathStr.get()) + QString("/.hidden"); - // FIXME: this does not work for non-local filesystems - QFile file(dotHidden); - if(file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QTextStream in(&file); - while(!in.atEnd()) { - virtHiddenList_.append(in.readLine()); - } - file.close(); - } - } - } -} - TabPage::TabPage(QWidget* parent): QWidget(parent), folderView_{nullptr}, @@ -85,13 +59,15 @@ TabPage::TabPage(QWidget* parent): proxyModel_{nullptr}, proxyFilter_{nullptr}, verticalLayout{nullptr}, - overrideCursor_(false) { + overrideCursor_(false), + selectionTimer_(nullptr) { Settings& settings = static_cast(qApp)->settings(); // create proxy folder model to do item filtering proxyModel_ = new ProxyFolderModel(); proxyModel_->setShowHidden(settings.showHidden()); + proxyModel_->setBackupAsHidden(settings.backupAsHidden()); proxyModel_->setShowThumbnails(settings.showThumbnails()); connect(proxyModel_, &ProxyFolderModel::sortFilterChanged, this, &TabPage::sortFilterChanged); @@ -122,8 +98,9 @@ TabPage::~TabPage() { if(proxyModel_) { delete proxyModel_; } - disconnect(folderModel_, &Fm::FolderModel::fileSizeChanged, this, &TabPage::onFileSizeChanged); if(folderModel_) { + disconnect(folderModel_, &Fm::FolderModel::fileSizeChanged, this, &TabPage::onFileSizeChanged); + disconnect(folderModel_, &Fm::FolderModel::filesAdded, this, &TabPage::onFilesAdded); folderModel_->unref(); } @@ -144,6 +121,9 @@ void TabPage::freeFolder() { } void TabPage::onFolderStartLoading() { + if(folderModel_){ + disconnect(folderModel_, &Fm::FolderModel::filesAdded, this, &TabPage::onFilesAdded); + } if(!overrideCursor_) { // FIXME: sometimes FmFolder of libfm generates unpaired "start-loading" and // "finish-loading" signals of uncertain reasons. This should be a bug in libfm. @@ -184,8 +164,12 @@ void TabPage::onUiUpdated() { folderView_->childView()->setCurrentIndex(index); } } - // update selection statusbar info when needed - connect(folderModel_, &Fm::FolderModel::fileSizeChanged, this, &TabPage::onFileSizeChanged); + if(folderModel_) { + // update selection statusbar info when needed + connect(folderModel_, &Fm::FolderModel::fileSizeChanged, this, &TabPage::onFileSizeChanged); + // get ready to select files that may be added later + connect(folderModel_, &Fm::FolderModel::filesAdded, this, &TabPage::onFilesAdded); + } } void TabPage::onFileSizeChanged(const QModelIndex& index) { @@ -197,6 +181,22 @@ void TabPage::onFileSizeChanged(const QModelIndex& index) { } } +// slot +void TabPage::onFilesAdded(Fm::FileInfoList files) { + if(static_cast(qApp)->settings().selectNewFiles()) { + if(!selectionTimer_) { + folderView_->selectFiles(files, false); + selectionTimer_ = new QTimer (this); + selectionTimer_->setSingleShot(true); + selectionTimer_->start(200); + } + else { + folderView_->selectFiles(files, selectionTimer_->isActive()); + selectionTimer_->start(200); + } + } +} + void TabPage::onFolderFinishLoading() { auto fi = folder_->info(); if(fi) { // if loading of the folder fails, it's possible that we don't have FmFileInfo. @@ -252,8 +252,8 @@ void TabPage::onFolderError(const Fm::GErrorPtr& err, Fm::Job::ErrorSeverity sev if(err.domain() == G_IO_ERROR) { if(err.code() == G_IO_ERROR_NOT_MOUNTED && severity < Fm::Job::ErrorSeverity::CRITICAL) { auto& path = folder_->path(); - MountOperation* op = new MountOperation(this); - op->mount(path); + MountOperation* op = new MountOperation(true); + op->mountEnclosingVolume(path); if(op->wait()) { // blocking event loop, wait for mount operation to finish. // This will reload the folder, which generates a new "start-loading" // signal, so we get more "start-loading" signals than "finish-loading" @@ -290,8 +290,8 @@ void TabPage::onFolderFsInfo() { fm_file_size_to_str(free_str, sizeof(free_str), free, fm_config->si_unit); fm_file_size_to_str(total_str, sizeof(total_str), total, fm_config->si_unit); msg = tr("Free space: %1 (Total: %2)") - .arg(QString::fromUtf8(free_str)) - .arg(QString::fromUtf8(total_str)); + .arg(QString::fromUtf8(free_str), + QString::fromUtf8(total_str)); } else { msg.clear(); @@ -310,6 +310,12 @@ QString TabPage::formatStatusText() { if(hidden_files > 0) { text += tr(" (%n hidden)", "", hidden_files); } + auto fi = folder_->info(); + if (fi && fi->isSymlink()) { + text += QString(" %2(%1)") + .arg(encloseWithBidiMarks(tr("Link to") + QChar(QChar::Space) + QString::fromStdString(fi->target())), + (layoutDirection() == Qt::RightToLeft) ? QChar(0x200f) : QChar(0x200e)); + } return text; } return QString(); @@ -388,6 +394,7 @@ void TabPage::chdir(Fm::FilePath newPath, bool addHistory) { // free the previous model if(folderModel_) { disconnect(folderModel_, &Fm::FolderModel::fileSizeChanged, this, &TabPage::onFileSizeChanged); + disconnect(folderModel_, &Fm::FolderModel::filesAdded, this, &TabPage::onFilesAdded); proxyModel_->setSourceModel(nullptr); folderModel_->unref(); // unref the cached model folderModel_ = nullptr; @@ -399,7 +406,6 @@ void TabPage::chdir(Fm::FilePath newPath, bool addHistory) { Q_EMIT titleChanged(newPath.baseName().get()); // FIXME: display name folder_ = Fm::Folder::fromPath(newPath); - proxyFilter_->setVirtHidden(folder_); if(addHistory) { // add current path to browse history history_.add(path()); @@ -448,7 +454,6 @@ void TabPage::invertSelection() { void TabPage::reload() { if(folder_) { - proxyFilter_->setVirtHidden(folder_); // reread ".hidden" // don't select or scroll to the previous folder after reload lastFolderPath_ = Fm::FilePath(); // but remember the current scroll position @@ -460,6 +465,17 @@ void TabPage::reload() { } } +// 200e LEFT-TO-RIGHT MARK +// 200f RIGHT-TO-LEFT MARK +// 202a LEFT-TO-RIGHT EMBEDDING +// 202b RIGHT-TO-LEFT EMBEDDING +// 202c POP DIRECTIONAL FORMATTING +QString TabPage::encloseWithBidiMarks(const QString& text) { + QChar bidiMark = text.isRightToLeft() ? QChar(0x200f) : QChar(0x200e); + QChar embedBidiMark = text.isRightToLeft() ? QChar(0x202b) : QChar(0x202a); + return embedBidiMark+text+bidiMark+QChar(0x202c); +} + // when the current selection in the folder view is changed void TabPage::onSelChanged() { QString msg; @@ -467,24 +483,44 @@ void TabPage::onSelChanged() { auto files = folderView_->selectedFiles(); int numSel = files.size(); /* FIXME: display total size of all selected files. */ - if(numSel == 1) { /* only one file is selected */ + if(numSel == 1) { /* only one file is selected (also, tell if it is a symlink)*/ auto& fi = files.front(); if(!fi->isDir()) { - msg = QString("\"%1\" (%2) %3") - .arg(fi->displayName()) - .arg(Fm::formatFileSize(fi->size(), fm_config->si_unit)) // FIXME: deprecate fm_config - .arg(fi->mimeType()->desc()); + if(fi->isSymlink()) { + msg = QString("%5\"%1\" %5(%2) %5%3 %5(%4)") + .arg(encloseWithBidiMarks(fi->displayName()), + encloseWithBidiMarks(Fm::formatFileSize(fi->size(), fm_config->si_unit)), + encloseWithBidiMarks(fi->mimeType()->desc()), + encloseWithBidiMarks(tr("Link to") + QChar(QChar::Space) + QString::fromStdString(fi->target())), + (layoutDirection() == Qt::RightToLeft) ? QChar(0x200f) : QChar(0x200e)); + } + else { + msg = QString("%4\"%1\" %4(%2) %4%3") + .arg(encloseWithBidiMarks(fi->displayName()), + encloseWithBidiMarks(Fm::formatFileSize(fi->size(), fm_config->si_unit)), // FIXME: deprecate fm_config + encloseWithBidiMarks(fi->mimeType()->desc()), + (layoutDirection() == Qt::RightToLeft) ? QChar(0x200f) : QChar(0x200e)); + } } else { - msg = QString("\"%1\" %2") - .arg(fi->displayName()) - .arg(fi->mimeType()->desc()); + if(fi->isSymlink()) { + msg = QString("%4\"%1\" %4%2 %4(%3)") + .arg(encloseWithBidiMarks(fi->displayName()), + encloseWithBidiMarks(fi->mimeType()->desc()), + encloseWithBidiMarks(tr("Link to") + QChar(QChar::Space) + QString::fromStdString(fi->target())), + (layoutDirection() == Qt::RightToLeft) ? QChar(0x200f) : QChar(0x200e)); + } + else { + msg = QString("%3\"%1\" %3%2") + .arg(encloseWithBidiMarks(fi->displayName()), + encloseWithBidiMarks(fi->mimeType()->desc()), + (layoutDirection() == Qt::RightToLeft) ? QChar(0x200f) : QChar(0x200e)); + } } /* FIXME: should we support statusbar plugins as in the gtk+ version? */ } else { goffset sum; - GList* l; msg = tr("%n item(s) selected", nullptr, numSel); /* don't count if too many files are selected, that isn't lightweight */ if(numSel < 1000) { @@ -533,7 +569,7 @@ void TabPage::forward() { } void TabPage::jumpToHistory(int index) { - if(index >= 0 && index < history_.size()) { + if(index >= 0 && static_cast(index) < history_.size()) { // remember current scroll position BrowseHistoryItem& item = history_.currentItem(); QAbstractItemView* childView = folderView_->childView(); diff --git a/pcmanfm/tabpage.h b/pcmanfm/tabpage.h index 1abdc09..424cfe3 100644 --- a/pcmanfm/tabpage.h +++ b/pcmanfm/tabpage.h @@ -26,7 +26,6 @@ #include #include #include "view.h" -#include #include "settings.h" #include @@ -48,7 +47,6 @@ class ProxyFilter : public Fm::ProxyFolderModelFilter { public: bool filterAcceptsRow(const Fm::ProxyFolderModel* model, const std::shared_ptr& info) const; virtual ~ProxyFilter() {} - void setVirtHidden(const std::shared_ptr& folder); QString getFilterStr() { return filterStr_; } @@ -58,7 +56,6 @@ public: private: QString filterStr_; - QStringList virtHiddenList_; }; class TabPage : public QWidget { @@ -212,11 +209,15 @@ protected Q_SLOTS: void onSelChanged(); void onUiUpdated(); void onFileSizeChanged(const QModelIndex& index); + void onFilesAdded(const Fm::FileInfoList files); private: void freeFolder(); QString formatStatusText(); + // Adds bidi marks (RLM/LRM/RLE/LRE/POP) around the text for the statusbar. + QString encloseWithBidiMarks(const QString& text); + void onFolderStartLoading(); void onFolderFinishLoading(); @@ -240,6 +241,7 @@ private: Fm::FilePath lastFolderPath_; // last browsed folder bool overrideCursor_; FolderSettings folderSettings_; + QTimer* selectionTimer_; }; } diff --git a/pcmanfm/translations/pcmanfm-qt-desktop-pref_es.desktop b/pcmanfm/translations/pcmanfm-qt-desktop-pref_es.desktop new file mode 100644 index 0000000..c83e89a --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt-desktop-pref_es.desktop @@ -0,0 +1,3 @@ +Name[es]=Escritorio +GenericName[es]=Configuración del escritorio +Comment[es]=Cambiar el fondo de pantalla y el comportamiento del escritorio diff --git a/pcmanfm/translations/pcmanfm-qt-desktop-pref_tr.desktop b/pcmanfm/translations/pcmanfm-qt-desktop-pref_tr.desktop index 3178a89..7618786 100644 --- a/pcmanfm/translations/pcmanfm-qt-desktop-pref_tr.desktop +++ b/pcmanfm/translations/pcmanfm-qt-desktop-pref_tr.desktop @@ -1,4 +1,4 @@ #Translations / translated by tulliana -Name[tr]=Dosya Yöneticisi (pcmanfm-qt) +Name[tr]=Dosya Yöneticisi (PCManFM-Qt) GenericName[tr]=Dosya ve masaüstü yönetim uygulaması Comment[tr]=Dosya Yöneticisi ve Masaüstü Ayarları (duvarkağıtları, menüler vs..) diff --git a/pcmanfm/translations/pcmanfm-qt-desktop-pref_zh_CN.desktop b/pcmanfm/translations/pcmanfm-qt-desktop-pref_zh_CN.desktop new file mode 100644 index 0000000..f78bea7 --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt-desktop-pref_zh_CN.desktop @@ -0,0 +1,4 @@ +#Translations +Name[zh_CN]=桌面 +GenericName[zh_CN]=桌面设置 +Comment[zh_CN]=更改墙纸与桌面管理器的行为。 diff --git a/pcmanfm/translations/pcmanfm-qt_ar.desktop b/pcmanfm/translations/pcmanfm-qt_ar.desktop index d9ec376..02a9090 100644 --- a/pcmanfm/translations/pcmanfm-qt_ar.desktop +++ b/pcmanfm/translations/pcmanfm-qt_ar.desktop @@ -1,4 +1,4 @@ #Translations -Name[ar]=مدير الملفّات PCManFM +Name[ar]=مدير الملفّات PCManFM-Qt GenericName[ar]=مدير ملفّات Comment[ar]=تصفّح نظام الملفّات وأدر ملفّاتك diff --git a/pcmanfm/translations/pcmanfm-qt_ca.desktop b/pcmanfm/translations/pcmanfm-qt_ca.desktop index 004f601..d4f691c 100644 --- a/pcmanfm/translations/pcmanfm-qt_ca.desktop +++ b/pcmanfm/translations/pcmanfm-qt_ca.desktop @@ -1,4 +1,4 @@ #Translations -Name[ca]=Gestor de fitxers PCManFM +Name[ca]=Gestor de fitxers PCManFM-Qt GenericName[ca]=Gestor de fitxers Comment[ca]=Navegueu pel sistema de fitxers i gestioneu els fitxers diff --git a/pcmanfm/translations/pcmanfm-qt_da.desktop b/pcmanfm/translations/pcmanfm-qt_da.desktop index c3c2e2b..973e9ad 100644 --- a/pcmanfm/translations/pcmanfm-qt_da.desktop +++ b/pcmanfm/translations/pcmanfm-qt_da.desktop @@ -1,3 +1,3 @@ -Name[da]=PCManFM-filhåndtering +Name[da]=PCManFM-Qt-filhåndtering GenericName[da]=Filhåndtering Comment[da]=Gennemse filsystemet og håndtér filerne diff --git a/pcmanfm/translations/pcmanfm-qt_el.desktop b/pcmanfm/translations/pcmanfm-qt_el.desktop index 7665191..11ac432 100644 --- a/pcmanfm/translations/pcmanfm-qt_el.desktop +++ b/pcmanfm/translations/pcmanfm-qt_el.desktop @@ -1,4 +1,4 @@ -Name[el]=Διαχειριστής αρχείων PCManFM +Name[el]=Διαχειριστής αρχείων PCManFM-Qt GenericName[el]=Διαχειριστής αρχείων Comment[el]=Περιήγηση του συστήματος αρχείων και διαχείριση των αρχείων diff --git a/pcmanfm/translations/pcmanfm-qt_es.desktop b/pcmanfm/translations/pcmanfm-qt_es.desktop new file mode 100644 index 0000000..c88737f --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_es.desktop @@ -0,0 +1,3 @@ +Name[es]=Gestor de archivos PCManFM-Qt +GenericName[es]=Gestor de archivos +Comment[es]=Explorar el sistema de archivos y gestionar los archivos diff --git a/pcmanfm/translations/pcmanfm-qt_it.desktop b/pcmanfm/translations/pcmanfm-qt_it.desktop index 1ebfc53..41992c0 100644 --- a/pcmanfm/translations/pcmanfm-qt_it.desktop +++ b/pcmanfm/translations/pcmanfm-qt_it.desktop @@ -1,4 +1,4 @@ #Translations -Name[it]=Gestore file PCmanFM +Name[it]=Gestore file PCManFM-Qt GenericName[it]=Gestore file Comment[it]=Esplora e organizza file e cartelle diff --git a/pcmanfm/translations/pcmanfm-qt_lt.desktop b/pcmanfm/translations/pcmanfm-qt_lt.desktop index afea779..8e8a3be 100644 --- a/pcmanfm/translations/pcmanfm-qt_lt.desktop +++ b/pcmanfm/translations/pcmanfm-qt_lt.desktop @@ -1,4 +1,4 @@ #Translations -Name[lt]=PCManFM failų tvarkytuvė +Name[lt]=PCManFM-Qt failų tvarkytuvė GenericName[lt]=Failų tvarkytuvė Comment[lt]=Naršyti failų sistemą ir tvarkyti failus diff --git a/pcmanfm/translations/pcmanfm-qt_pl.desktop b/pcmanfm/translations/pcmanfm-qt_pl.desktop index 1a6fbd7..f8cae09 100644 --- a/pcmanfm/translations/pcmanfm-qt_pl.desktop +++ b/pcmanfm/translations/pcmanfm-qt_pl.desktop @@ -1,4 +1,4 @@ #Translations -Name[pl]=Menedżer plików PCManFM +Name[pl]=Menedżer plików PCManFM-Qt GenericName[pl]=Menedżer plików Comment[pl]=Przegląd systemu plików i zarządzanie plikami diff --git a/pcmanfm/translations/pcmanfm-qt_pt.desktop b/pcmanfm/translations/pcmanfm-qt_pt.desktop index e9a31be..64df8a8 100644 --- a/pcmanfm/translations/pcmanfm-qt_pt.desktop +++ b/pcmanfm/translations/pcmanfm-qt_pt.desktop @@ -1,4 +1,4 @@ #Translations -Name[pt]=Gestor de ficheiros PCManFM +Name[pt]=Gestor de ficheiros PCManFM-Qt GenericName[pt]=Gestor de ficheiros Comment[pt]=Explorar o sistema de ficheiros e gerir os seus ficheiros e pastas diff --git a/pcmanfm/translations/pcmanfm-qt_pt_BR.desktop b/pcmanfm/translations/pcmanfm-qt_pt_BR.desktop index c823793..575577a 100644 --- a/pcmanfm/translations/pcmanfm-qt_pt_BR.desktop +++ b/pcmanfm/translations/pcmanfm-qt_pt_BR.desktop @@ -1,4 +1,4 @@ #Translations -Name[pt_BR]=Gerenciador de Arquivos PCManFM +Name[pt_BR]=Gerenciador de Arquivos PCManFM-Qt GenericName[pt_BR]=Gerenciador de Arquivos Comment[pt_BR]=Navegue pelo sistema de arquivos e gerencie arquivos e pastas diff --git a/pcmanfm/translations/pcmanfm-qt_ru.desktop b/pcmanfm/translations/pcmanfm-qt_ru.desktop index b98b6a3..dcf93da 100644 --- a/pcmanfm/translations/pcmanfm-qt_ru.desktop +++ b/pcmanfm/translations/pcmanfm-qt_ru.desktop @@ -1,4 +1,4 @@ #Translations -Name[ru]=Диспетчер файлов PCManFM +Name[ru]=Диспетчер файлов PCManFM-Qt GenericName[ru]=Диспетчер файлов Comment[ru]=Просматривайте файловую систему и управляйте файлами \ No newline at end of file diff --git a/pcmanfm/translations/pcmanfm-qt_zh_CN.desktop b/pcmanfm/translations/pcmanfm-qt_zh_CN.desktop new file mode 100644 index 0000000..3c2d264 --- /dev/null +++ b/pcmanfm/translations/pcmanfm-qt_zh_CN.desktop @@ -0,0 +1,4 @@ +#Translations +Name[zh_CN]=PCManFM-Qt 文件管理器 +GenericName[zh_CN]=文件管理器 +Comment[zh_CN]=浏览文件系统并管理文件。 diff --git a/pcmanfm/view.cpp b/pcmanfm/view.cpp index d6b6d0b..c11161f 100644 --- a/pcmanfm/view.cpp +++ b/pcmanfm/view.cpp @@ -126,7 +126,7 @@ void View::prepareFileMenu(Fm::FileMenu* menu) { } } -void View::prepareFolderMenu(Fm::FolderMenu* menu) { +void View::prepareFolderMenu(Fm::FolderMenu* /*menu*/) { } void View::updateFromSettings(Settings& settings) { @@ -143,6 +143,7 @@ void View::updateFromSettings(Settings& settings) { Fm::ProxyFolderModel* proxyModel = model(); if(proxyModel) { proxyModel->setShowThumbnails(settings.showThumbnails()); + proxyModel->setBackupAsHidden(settings.backupAsHidden()); } }