Adding upstream version 0.14.0.
Signed-off-by: Alf Gaida <agaida@siduction.org>
This commit is contained in:
parent
d87479cc69
commit
20752f38c5
47
CHANGELOG
47
CHANGELOG
@ -1,3 +1,26 @@
|
||||
pcmanfm-qt-0.14.0 / 2019-01-25
|
||||
==============================
|
||||
|
||||
* Removed the use of libfm C APIs.
|
||||
* An option for showing full names (instead of display names).
|
||||
* Prefer theme icons for view actions.
|
||||
* Shadow hidden icons optionally.
|
||||
* Fixed DND and drop indicator on desktop.
|
||||
* Fixed closing tab on ejecting/unmounting.
|
||||
* Fixed a rare crash on unmounting.
|
||||
* Fixed filtering for detailed list mode
|
||||
* Fixed status-bar message when some selected files were filtered out.
|
||||
* Restart warning bar for Preferences.
|
||||
* A (warning) bar for the root instance.
|
||||
* Transient filter-bar by default.
|
||||
* Added split view.
|
||||
* Delete trashed files with Delete key.
|
||||
* Select the first row of Preferences by default.
|
||||
* Optional Desktop shortcuts (Trash, Home, Computer, and Network). The Trash shortcut is interactive.
|
||||
* A Tool menu item (and shortcut) to copy the full path of the selected file.
|
||||
* Really use the terminal emulator chosen by user when launching desktop files.
|
||||
* Preserve relative positions of Desktop items with DND.
|
||||
* Dropped QDesktopWidget, and used QScreen instead.
|
||||
|
||||
pcmanfm-qt-0.13.0 / 2018-05-21
|
||||
==============================
|
||||
@ -50,8 +73,8 @@ pcmanfm-qt-0.13.0 / 2018-05-21
|
||||
* Tab DND
|
||||
* View tool-buttons
|
||||
|
||||
0.12.0 / 2017-10-21
|
||||
===================
|
||||
pcmanfm-qt-0.12.0 / 2017-10-21
|
||||
==============================
|
||||
|
||||
* Release 0.12.0: Update changelog
|
||||
* Set Version
|
||||
@ -136,8 +159,8 @@ pcmanfm-qt-0.13.0 / 2018-05-21
|
||||
* Use const iterators
|
||||
* Checks bookmarks iterators validity (#444)
|
||||
|
||||
0.11.3 / 2017-01-14
|
||||
===================
|
||||
pcmanfm-qt-0.11.3 / 2017-01-14
|
||||
==============================
|
||||
|
||||
* Release 0.11.3: Update changelog
|
||||
* remove 0.11.3 changelog entries
|
||||
@ -146,8 +169,8 @@ pcmanfm-qt-0.13.0 / 2018-05-21
|
||||
* Add a workaround for the Qt5 bug which causes broken wallpaper background.
|
||||
* Update AUTHORS
|
||||
|
||||
0.11.2 / 2016-12-21
|
||||
===================
|
||||
pcmanfm-qt-0.11.2 / 2016-12-21
|
||||
==============================
|
||||
|
||||
* Release 0.11.2: Update changelog
|
||||
* Use static_cast instead of the C style cast
|
||||
@ -179,8 +202,8 @@ pcmanfm-qt-0.13.0 / 2018-05-21
|
||||
* Add Catalan translations
|
||||
* Added Brazilian Portuguese Translation (pt_BR)
|
||||
|
||||
0.11.1 / 2016-09-24
|
||||
===================
|
||||
pcmanfm-qt-0.11.1 / 2016-09-24
|
||||
==============================
|
||||
|
||||
* Release 0.11.1: Add changelog
|
||||
* Bump version to 0.11.1 (#399)
|
||||
@ -208,8 +231,8 @@ pcmanfm-qt-0.13.0 / 2018-05-21
|
||||
* Add setting for Desktop con size
|
||||
* Fix a few compiler warnings
|
||||
|
||||
0.11.0 / 2016-03-13
|
||||
===================
|
||||
pcmanfm-qt-0.11.0 / 2016-03-13
|
||||
==============================
|
||||
|
||||
* Switch automatically to newly opened tabs
|
||||
* Fixes libfm-qt dependency contradiction on README.md
|
||||
@ -247,8 +270,8 @@ pcmanfm-qt-0.13.0 / 2018-05-21
|
||||
* Add config values for customizing "places" (not implemented yet).
|
||||
* Updated Russian translation Removed ru_RU files
|
||||
|
||||
0.10.1 / 2015-12-05
|
||||
===================
|
||||
pcmanfm-qt-0.10.1 / 2015-12-05
|
||||
==============================
|
||||
|
||||
* hide 'Create New...' menu for files
|
||||
* Russian translation update
|
||||
|
@ -1,22 +1,28 @@
|
||||
cmake_minimum_required(VERSION 3.0.2)
|
||||
cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
|
||||
# CMP0000: Call the cmake_minimum_required() command at the beginning of the top-level
|
||||
# CMakeLists.txt file even before calling the project() command.
|
||||
# The cmake_minimum_required(VERSION) command implicitly invokes the cmake_policy(VERSION)
|
||||
# command to specify that the current project code is written for the given range of CMake
|
||||
# versions.
|
||||
project(pcmanfm-qt)
|
||||
|
||||
# PcmanFm-Qt Version
|
||||
set(PCMANFM_QT_VERSION_MAJOR 0)
|
||||
set(PCMANFM_QT_VERSION_MINOR 13)
|
||||
set(PCMANFM_QT_VERSION_MINOR 14)
|
||||
set(PCMANFM_QT_VERSION_PATCH 0)
|
||||
|
||||
set(PCMANFM_QT_VERSION ${PCMANFM_QT_VERSION_MAJOR}.${PCMANFM_QT_VERSION_MINOR}.${PCMANFM_QT_VERSION_PATCH})
|
||||
|
||||
# Minimum versions
|
||||
set(LIBFMQT_MINIMUM_VERSION "0.14.0")
|
||||
set(LXQTBT_MINIMUM_VERSION "0.6.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 ${QT_MINIMUM_VERSION} REQUIRED)
|
||||
find_package(Qt5DBus ${QT_MINIMUM_VERSION} REQUIRED)
|
||||
find_package(Qt5LinguistTools ${QT_MINIMUM_VERSION} REQUIRED)
|
||||
find_package(Qt5Widgets ${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)
|
||||
@ -64,6 +70,5 @@ if(BUILD_DOCUMENTATION)
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/docs" DESTINATION "${CMAKE_INSTALL_DOCDIR}")
|
||||
endif()
|
||||
|
||||
# merged from lxqt-common
|
||||
add_subdirectory(autostart)
|
||||
add_subdirectory(config)
|
||||
|
@ -60,3 +60,10 @@ All switches (command line options) mentioned above are explained in detail in
|
||||
## Development
|
||||
|
||||
Issues should go to the tracker of PCManFM-Qt at https://github.com/lxqt/pcmanfm-qt/issues.
|
||||
|
||||
|
||||
### Translation (Weblate)
|
||||
|
||||
<a href="https://weblate.lxqt.org/projects/lxqt/pcmanfm-qt/">
|
||||
<img src="https://weblate.lxqt.org/widgets/lxqt/-/pcmanfm-qt/multi-auto.svg" alt="Translation status" />
|
||||
</a>
|
||||
|
@ -1,5 +1,3 @@
|
||||
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
|
||||
|
||||
file(GLOB DESKTOP_FILES_IN *.desktop.in)
|
||||
|
||||
# Translations **********************************
|
||||
|
@ -1,2 +0,0 @@
|
||||
# Translations
|
||||
Name[cs_CZ]=Plocha
|
@ -46,10 +46,6 @@ lxqt_translate_ts(QM_FILES
|
||||
UPDATE_TRANSLATIONS ${UPDATE_TRANSLATIONS}
|
||||
SOURCES ${pcmanfm_SRCS} ${pcmanfm_UIS}
|
||||
INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/translations"
|
||||
PULL_TRANSLATIONS ${PULL_TRANSLATIONS}
|
||||
CLEAN_TRANSLATIONS ${CLEAN_TRANSLATIONS}
|
||||
TRANSLATIONS_REPO ${TRANSLATIONS_REPO}
|
||||
TRANSLATIONS_REFSPEC ${TRANSLATIONS_REFSPEC}
|
||||
)
|
||||
|
||||
# translate desktop entry files for pcmanfm-qt and desktop preferences
|
||||
@ -72,7 +68,6 @@ 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
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusInterface>
|
||||
#include <QDir>
|
||||
#include <QDesktopWidget>
|
||||
#include <QVector>
|
||||
#include <QLocale>
|
||||
#include <QLibraryInfo>
|
||||
@ -43,6 +42,8 @@
|
||||
#include <libfm-qt/mountoperation.h>
|
||||
#include <libfm-qt/filesearchdialog.h>
|
||||
#include <libfm-qt/core/terminal.h>
|
||||
#include <libfm-qt/core/bookmarks.h>
|
||||
#include <libfm-qt/core/folderconfig.h>
|
||||
|
||||
#include "applicationadaptor.h"
|
||||
#include "preferencesdialog.h"
|
||||
@ -93,7 +94,7 @@ Application::Application(int& argc, char** argv):
|
||||
// we successfully registered the service
|
||||
isPrimaryInstance = true;
|
||||
setStyle(new ProxyStyle());
|
||||
desktop()->installEventFilter(this);
|
||||
//desktop()->installEventFilter(this);
|
||||
|
||||
new ApplicationAdaptor(this);
|
||||
dbus.registerObject("/Application", this);
|
||||
@ -101,14 +102,6 @@ Application::Application(int& argc, char** argv):
|
||||
connect(this, &Application::aboutToQuit, this, &Application::onAboutToQuit);
|
||||
// aboutToQuit() is not signalled on SIGTERM, install signal handler
|
||||
installSigtermHandler();
|
||||
settings_.load(profileName_);
|
||||
|
||||
// decrease the cache size to reduce memory usage
|
||||
QPixmapCache::setCacheLimit(2048);
|
||||
|
||||
if(settings_.useFallbackIconTheme()) {
|
||||
QIcon::setThemeName(settings_.fallbackIconThemeName());
|
||||
}
|
||||
|
||||
// Check if LXQt Session is running. LXQt has it's own Desktop Folder
|
||||
// editor. We just hide our editor when LXQt is running.
|
||||
@ -133,7 +126,7 @@ Application::Application(int& argc, char** argv):
|
||||
}
|
||||
|
||||
Application::~Application() {
|
||||
desktop()->removeEventFilter(this);
|
||||
//desktop()->removeEventFilter(this);
|
||||
|
||||
if(volumeMonitor_) {
|
||||
g_signal_handlers_disconnect_by_func(volumeMonitor_, gpointer(onVolumeAdded), this);
|
||||
@ -212,9 +205,20 @@ bool Application::parseCommandLineArgs() {
|
||||
profileName_ = parser.value(profileOption);
|
||||
}
|
||||
|
||||
// load settings
|
||||
// load app config
|
||||
settings_.load(profileName_);
|
||||
|
||||
// init per-folder config
|
||||
QString perFolderConfigFile = settings_.profileDir(profileName_) + "/dir-settings.conf";
|
||||
Fm::FolderConfig::init(perFolderConfigFile.toLocal8Bit().constData());
|
||||
|
||||
// decrease the cache size to reduce memory usage
|
||||
QPixmapCache::setCacheLimit(2048);
|
||||
|
||||
if(settings_.useFallbackIconTheme()) {
|
||||
QIcon::setThemeName(settings_.fallbackIconThemeName());
|
||||
}
|
||||
|
||||
// desktop icon management
|
||||
if(parser.isSet(desktopOption)) {
|
||||
desktopManager(true);
|
||||
@ -363,7 +367,7 @@ void Application::onAboutToQuit() {
|
||||
settings_.save();
|
||||
}
|
||||
|
||||
bool Application::eventFilter(QObject* watched, QEvent* event) {
|
||||
/*bool Application::eventFilter(QObject* watched, QEvent* event) {
|
||||
if(watched == desktop()) {
|
||||
if(event->type() == QEvent::StyleChange ||
|
||||
event->type() == QEvent::ThemeChange) {
|
||||
@ -371,7 +375,7 @@ bool Application::eventFilter(QObject* watched, QEvent* event) {
|
||||
}
|
||||
}
|
||||
return QObject::eventFilter(watched, event);
|
||||
}
|
||||
}*/
|
||||
|
||||
void Application::onLastWindowClosed() {
|
||||
|
||||
@ -383,29 +387,28 @@ void Application::onSaveStateRequest(QSessionManager& /*manager*/) {
|
||||
|
||||
void Application::desktopManager(bool enabled) {
|
||||
// TODO: turn on or turn off desktpo management (desktop icons & wallpaper)
|
||||
qDebug("desktopManager: %d", enabled);
|
||||
QDesktopWidget* desktopWidget = desktop();
|
||||
//qDebug("desktopManager: %d", enabled);
|
||||
if(enabled) {
|
||||
if(!enableDesktopManager_) {
|
||||
// installNativeEventFilter(this);
|
||||
const auto allScreens = screens();
|
||||
for(QScreen* screen : allScreens) {
|
||||
connect(screen, &QScreen::virtualGeometryChanged, this, &Application::onVirtualGeometryChanged);
|
||||
connect(screen, &QScreen::availableGeometryChanged, this, &Application::onAvailableGeometryChanged);
|
||||
connect(screen, &QObject::destroyed, this, &Application::onScreenDestroyed);
|
||||
}
|
||||
connect(this, &QApplication::screenAdded, this, &Application::onScreenAdded);
|
||||
connect(desktopWidget, &QDesktopWidget::resized, this, &Application::onScreenResized);
|
||||
connect(desktopWidget, &QDesktopWidget::screenCountChanged, this, &Application::onScreenCountChanged);
|
||||
connect(this, &QApplication::screenRemoved, this, &Application::onScreenRemoved);
|
||||
|
||||
// NOTE: there are two modes
|
||||
// When virtual desktop is used (all screens are combined to form a large virtual desktop),
|
||||
// we only create one DesktopWindow. Otherwise, we create one for each screen.
|
||||
if(desktopWidget->isVirtualDesktop()) {
|
||||
if(primaryScreen() && primaryScreen()->virtualSiblings().size() > 1) {
|
||||
DesktopWindow* window = createDesktopWindow(-1);
|
||||
desktopWindows_.push_back(window);
|
||||
}
|
||||
else {
|
||||
int n = desktopWidget->numScreens();
|
||||
int n = qMax(allScreens.size(), 1);
|
||||
desktopWindows_.reserve(n);
|
||||
for(int i = 0; i < n; ++i) {
|
||||
DesktopWindow* window = createDesktopWindow(i);
|
||||
@ -416,8 +419,6 @@ void Application::desktopManager(bool enabled) {
|
||||
}
|
||||
else {
|
||||
if(enableDesktopManager_) {
|
||||
disconnect(desktopWidget, &QDesktopWidget::resized, this, &Application::onScreenResized);
|
||||
disconnect(desktopWidget, &QDesktopWidget::screenCountChanged, this, &Application::onScreenCountChanged);
|
||||
int n = desktopWindows_.size();
|
||||
for(int i = 0; i < n; ++i) {
|
||||
DesktopWindow* window = desktopWindows_.at(i);
|
||||
@ -427,9 +428,11 @@ void Application::desktopManager(bool enabled) {
|
||||
const auto allScreens = screens();
|
||||
for(QScreen* screen : allScreens) {
|
||||
disconnect(screen, &QScreen::virtualGeometryChanged, this, &Application::onVirtualGeometryChanged);
|
||||
disconnect(screen, &QScreen::availableGeometryChanged, this, &Application::onAvailableGeometryChanged);
|
||||
disconnect(screen, &QObject::destroyed, this, &Application::onScreenDestroyed);
|
||||
}
|
||||
disconnect(this, &QApplication::screenAdded, this, &Application::onScreenAdded);
|
||||
disconnect(this, &QApplication::screenRemoved, this, &Application::onScreenRemoved);
|
||||
// removeNativeEventFilter(this);
|
||||
}
|
||||
}
|
||||
@ -470,7 +473,7 @@ void Application::onConnectToServerAccepted() {
|
||||
ConnectServerDialog* dlg = static_cast<ConnectServerDialog*>(sender());
|
||||
QString uri = dlg->uriText();
|
||||
Fm::FilePathList paths;
|
||||
paths.push_back(Fm::FilePath::fromDisplayName(uri.toUtf8().constData()));
|
||||
paths.push_back(Fm::FilePath::fromUri(uri.toUtf8().constData()));
|
||||
MainWindow* window = MainWindow::lastActive();
|
||||
Launcher(window).launchPaths(nullptr, paths);
|
||||
}
|
||||
@ -586,93 +589,41 @@ void Application::setWallpaper(QString path, QString modeString) {
|
||||
// update wallpaper
|
||||
if(changed) {
|
||||
if(enableDesktopManager_) {
|
||||
for(DesktopWindow* desktopWindow : qAsConst(desktopWindows_)) {
|
||||
for(DesktopWindow* desktopWin : qAsConst(desktopWindows_)) {
|
||||
if(!path.isEmpty()) {
|
||||
desktopWindow->setWallpaperFile(path);
|
||||
desktopWin->setWallpaperFile(path);
|
||||
}
|
||||
if(mode != settings_.wallpaperMode()) {
|
||||
desktopWindow->setWallpaperMode(mode);
|
||||
desktopWin->setWallpaperMode(mode);
|
||||
}
|
||||
desktopWindow->updateWallpaper();
|
||||
desktopWin->updateWallpaper();
|
||||
}
|
||||
settings_.save(); // save the settings to the config file
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::onScreenResized(int num) {
|
||||
if(desktop()->isVirtualDesktop()) {
|
||||
// in virtual desktop mode, we only have one desktop window. that is the first one.
|
||||
DesktopWindow* window = desktopWindows_.at(0);
|
||||
window->setGeometry(desktop()->geometry());
|
||||
}
|
||||
else {
|
||||
DesktopWindow* window = desktopWindows_.at(num);
|
||||
QRect rect = desktop()->screenGeometry(num);
|
||||
window->setGeometry(rect);
|
||||
}
|
||||
}
|
||||
|
||||
DesktopWindow* Application::createDesktopWindow(int screenNum) {
|
||||
DesktopWindow* window = new DesktopWindow(screenNum);
|
||||
|
||||
if(screenNum == -1) { // one large virtual desktop only
|
||||
QRect rect = desktop()->geometry();
|
||||
QRect rect = primaryScreen()->virtualGeometry();
|
||||
window->setGeometry(rect);
|
||||
}
|
||||
else {
|
||||
QRect rect = desktop()->screenGeometry(screenNum);
|
||||
QRect rect;
|
||||
const auto allScreens = screens();
|
||||
if(auto screen = window->getDesktopScreen()) {
|
||||
rect = screen->geometry();
|
||||
}
|
||||
window->setGeometry(rect);
|
||||
}
|
||||
|
||||
window->updateFromSettings(settings_);
|
||||
window->show();
|
||||
return window;
|
||||
}
|
||||
|
||||
void Application::onScreenCountChanged(int newCount) {
|
||||
QDesktopWidget* desktopWidget = desktop();
|
||||
bool oldVirtual = (desktopWindows_.size() == 1 && desktopWindows_.at(0)->screenNum() == -1);
|
||||
bool isVirtual = desktopWidget->isVirtualDesktop();
|
||||
|
||||
if(oldVirtual && isVirtual) {
|
||||
// if we are using virtual desktop mode previously, and the new mode is sitll virtual
|
||||
// no further change is needed, only do relayout.
|
||||
desktopWindows_.at(0)->queueRelayout();
|
||||
return;
|
||||
}
|
||||
|
||||
// we used non-virtual mode originally, but now we're switched to virtual mode
|
||||
if(isVirtual) {
|
||||
newCount = 1; // we only want one desktop window for all screens in virtual mode
|
||||
}
|
||||
|
||||
if(newCount > desktopWindows_.size()) {
|
||||
// add more desktop windows
|
||||
for(int i = desktopWindows_.size(); i < newCount; ++i) {
|
||||
DesktopWindow* desktop = createDesktopWindow(i);
|
||||
desktopWindows_.push_back(desktop);
|
||||
}
|
||||
}
|
||||
else if(newCount < desktopWindows_.size()) {
|
||||
// delete excessive desktop windows
|
||||
for(int i = newCount; i < desktopWindows_.size(); ++i) {
|
||||
DesktopWindow* desktop = desktopWindows_.at(i);
|
||||
delete desktop;
|
||||
}
|
||||
desktopWindows_.resize(newCount);
|
||||
}
|
||||
|
||||
if(newCount == 1) { // now only 1 screen is in use
|
||||
DesktopWindow* desktop = desktopWindows_.at(0);
|
||||
if(isVirtual) {
|
||||
desktop->setScreenNum(-1);
|
||||
}
|
||||
else { // non-virtual mode, and we only have 1 screen
|
||||
desktop->setScreenNum(0);
|
||||
}
|
||||
desktop->updateWallpaper();
|
||||
}
|
||||
}
|
||||
|
||||
// called when Settings is changed to update UI
|
||||
void Application::updateFromSettings() {
|
||||
// if(iconTheme.isEmpty())
|
||||
@ -696,16 +647,14 @@ void Application::updateFromSettings() {
|
||||
void Application::updateDesktopsFromSettings(bool changeSlide) {
|
||||
QVector<DesktopWindow*>::iterator it;
|
||||
for(it = desktopWindows_.begin(); it != desktopWindows_.end(); ++it) {
|
||||
DesktopWindow* desktopWindow = static_cast<DesktopWindow*>(*it);
|
||||
desktopWindow->updateFromSettings(settings_, changeSlide);
|
||||
DesktopWindow* desktopWin = static_cast<DesktopWindow*>(*it);
|
||||
desktopWin->updateFromSettings(settings_, changeSlide);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::editBookmarks() {
|
||||
if(!editBookmarksialog_) {
|
||||
FmBookmarks* bookmarks = fm_bookmarks_dup();
|
||||
editBookmarksialog_ = new Fm::EditBookmarksDialog(bookmarks);
|
||||
g_object_unref(bookmarks);
|
||||
editBookmarksialog_ = new Fm::EditBookmarksDialog(Fm::Bookmarks::globalInstance());
|
||||
}
|
||||
editBookmarksialog_.data()->show();
|
||||
}
|
||||
@ -780,7 +729,58 @@ bool Application::nativeEventFilter(const QByteArray& eventType, void* message,
|
||||
void Application::onScreenAdded(QScreen* newScreen) {
|
||||
if(enableDesktopManager_) {
|
||||
connect(newScreen, &QScreen::virtualGeometryChanged, this, &Application::onVirtualGeometryChanged);
|
||||
connect(newScreen, &QScreen::availableGeometryChanged, this, &Application::onAvailableGeometryChanged);
|
||||
connect(newScreen, &QObject::destroyed, this, &Application::onScreenDestroyed);
|
||||
const auto siblings = primaryScreen()->virtualSiblings();
|
||||
if(siblings.contains(newScreen)) { // the primary screen is changed
|
||||
if(desktopWindows_.size() == 1) {
|
||||
desktopWindows_.at(0)->setGeometry(newScreen->virtualGeometry());
|
||||
if(siblings.size() > 1) { // a virtual desktop is created
|
||||
desktopWindows_.at(0)->setScreenNum(-1);
|
||||
}
|
||||
}
|
||||
else if(desktopWindows_.isEmpty()) { // for the sake of certainty
|
||||
DesktopWindow* window = createDesktopWindow(desktopWindows_.size());
|
||||
desktopWindows_.push_back(window);
|
||||
}
|
||||
}
|
||||
else { // a separate screen is added
|
||||
DesktopWindow* window = createDesktopWindow(desktopWindows_.size());
|
||||
desktopWindows_.push_back(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::onScreenRemoved(QScreen* oldScreen) {
|
||||
if(enableDesktopManager_){
|
||||
disconnect(oldScreen, &QScreen::virtualGeometryChanged, this, &Application::onVirtualGeometryChanged);
|
||||
disconnect(oldScreen, &QScreen::availableGeometryChanged, this, &Application::onAvailableGeometryChanged);
|
||||
disconnect(oldScreen, &QObject::destroyed, this, &Application::onScreenDestroyed);
|
||||
if(desktopWindows_.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if(desktopWindows_.size() == 1) { // a single desktop is changed
|
||||
if(primaryScreen() != nullptr) {
|
||||
desktopWindows_.at(0)->setGeometry(primaryScreen()->virtualGeometry());
|
||||
if(primaryScreen()->virtualSiblings().size() == 1) {
|
||||
desktopWindows_.at(0)->setScreenNum(0); // there is no virtual desktop anymore
|
||||
}
|
||||
}
|
||||
else if (screens().isEmpty()) { // for the sake of certainty
|
||||
desktopWindows_.at(0)->setScreenNum(0);
|
||||
}
|
||||
}
|
||||
else { // a separate desktop is removed
|
||||
int n = desktopWindows_.size();
|
||||
for(int i = 0; i < n; ++i) {
|
||||
DesktopWindow* window = desktopWindows_.at(i);
|
||||
if(window->getDesktopScreen() == oldScreen) {
|
||||
desktopWindows_.remove(i);
|
||||
delete window;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -812,9 +812,9 @@ void Application::onScreenDestroyed(QObject* screenObj) {
|
||||
if(enableDesktopManager_) {
|
||||
bool reloadNeeded = false;
|
||||
// FIXME: add workarounds for Qt5 bug #40681 and #40791 here.
|
||||
for(DesktopWindow* desktop : qAsConst(desktopWindows_)) {
|
||||
if(desktop->windowHandle()->screen() == screenObj) {
|
||||
desktop->destroy(); // destroy the underlying native window
|
||||
for(DesktopWindow* desktopWin : qAsConst(desktopWindows_)) {
|
||||
if(desktopWin->windowHandle()->screen() == screenObj) {
|
||||
desktopWin->destroy(); // destroy the underlying native window
|
||||
reloadNeeded = true;
|
||||
}
|
||||
}
|
||||
@ -827,31 +827,33 @@ void Application::onScreenDestroyed(QObject* screenObj) {
|
||||
void Application::reloadDesktopsAsNeeded() {
|
||||
if(enableDesktopManager_) {
|
||||
// workarounds for Qt5 bug #40681 and #40791 here.
|
||||
for(DesktopWindow* desktop : qAsConst(desktopWindows_)) {
|
||||
if(!desktop->windowHandle()) {
|
||||
desktop->create(); // re-create the underlying native window
|
||||
desktop->queueRelayout();
|
||||
desktop->show();
|
||||
for(DesktopWindow* desktopWin : qAsConst(desktopWindows_)) {
|
||||
if(!desktopWin->windowHandle()) {
|
||||
desktopWin->create(); // re-create the underlying native window
|
||||
desktopWin->queueRelayout();
|
||||
desktopWin->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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*/) {
|
||||
// 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.
|
||||
// In theory, QDesktopWidget should emit "workAreaResized()" signal when the work area
|
||||
// of any screen is changed, but in fact it does not do it.
|
||||
// However, QScreen provided since Qt5 does not have the bug and
|
||||
// virtualGeometryChanged() is emitted correctly when the workAreas changed.
|
||||
// So we use it in Qt5.
|
||||
// update desktop geometries
|
||||
if(enableDesktopManager_) {
|
||||
// qDebug() << "onVirtualGeometryChanged";
|
||||
for(DesktopWindow* desktop : qAsConst(desktopWindows_)) {
|
||||
desktop->queueRelayout();
|
||||
for(DesktopWindow* desktopWin : qAsConst(desktopWindows_)) {
|
||||
auto desktopScreen = desktopWin->getDesktopScreen();
|
||||
if(desktopScreen) {
|
||||
desktopWin->setGeometry(desktopScreen->virtualGeometry());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::onAvailableGeometryChanged(const QRect& /*rect*/) {
|
||||
// update desktop layouts
|
||||
if(enableDesktopManager_) {
|
||||
for(DesktopWindow* desktopWin : qAsConst(desktopWindows_)) {
|
||||
desktopWin->queueRelayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,20 +102,20 @@ protected Q_SLOTS:
|
||||
|
||||
void onLastWindowClosed();
|
||||
void onSaveStateRequest(QSessionManager& manager);
|
||||
void onScreenResized(int num);
|
||||
void onScreenCountChanged(int newCount);
|
||||
void initVolumeManager();
|
||||
|
||||
void onVirtualGeometryChanged(const QRect& rect);
|
||||
void onAvailableGeometryChanged(const QRect& rect);
|
||||
void onScreenDestroyed(QObject* screenObj);
|
||||
void onScreenAdded(QScreen* newScreen);
|
||||
void onScreenRemoved(QScreen* oldScreen);
|
||||
void reloadDesktopsAsNeeded();
|
||||
|
||||
void onFindFileAccepted();
|
||||
void onConnectToServerAccepted();
|
||||
|
||||
protected:
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
//virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
bool parseCommandLineArgs();
|
||||
DesktopWindow* createDesktopWindow(int screenNum);
|
||||
bool autoMountVolume(GVolume* volume, bool interactive = true);
|
||||
|
@ -173,7 +173,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select text color:</string>
|
||||
<string>Select text color:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -453,6 +453,59 @@ A space is also reserved for 3 lines of text.</string>
|
||||
<string>Advanced</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="advancedPageLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_6">
|
||||
<property name="title">
|
||||
<string>Visible Shortcuts</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="homeBox">
|
||||
<property name="text">
|
||||
<string>Home</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="user-home">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="trashBox">
|
||||
<property name="text">
|
||||
<string>Trash</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="user-trash">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="computerBox">
|
||||
<property name="text">
|
||||
<string>Computer</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="computer">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="networkBox">
|
||||
<property name="text">
|
||||
<string>Network</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="folder-network">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
|
@ -104,6 +104,13 @@ DesktopPreferencesDialog::DesktopPreferencesDialog(QWidget* parent, Qt::WindowFl
|
||||
ui.backgroundColor->setColor(settings.desktopBgColor());
|
||||
ui.textColor->setColor(settings.desktopFgColor());
|
||||
ui.shadowColor->setColor(settings.desktopShadowColor());
|
||||
|
||||
const QStringList ds = settings.desktopShortcuts();
|
||||
ui.homeBox->setChecked(ds.contains(QLatin1String("Home")));
|
||||
ui.trashBox->setChecked(ds.contains(QLatin1String("Trash")));
|
||||
ui.computerBox->setChecked(ds.contains(QLatin1String("Computer")));
|
||||
ui.networkBox->setChecked(ds.contains(QLatin1String("Network")));
|
||||
|
||||
ui.showWmMenu->setChecked(settings.showWmMenu());
|
||||
|
||||
connect(ui.buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked,
|
||||
@ -167,6 +174,22 @@ void DesktopPreferencesDialog::applySettings()
|
||||
settings.setDesktopBgColor(ui.backgroundColor->color());
|
||||
settings.setDesktopFgColor(ui.textColor->color());
|
||||
settings.setDesktopShadowColor(ui.shadowColor->color());
|
||||
|
||||
QStringList ds;
|
||||
if(ui.homeBox->isChecked()) {
|
||||
ds << QLatin1String("Home");
|
||||
}
|
||||
if(ui.trashBox->isChecked()) {
|
||||
ds << QLatin1String("Trash");
|
||||
}
|
||||
if(ui.computerBox->isChecked()) {
|
||||
ds << QLatin1String("Computer");
|
||||
}
|
||||
if(ui.networkBox->isChecked()) {
|
||||
ds << QLatin1String("Network");
|
||||
}
|
||||
settings.setDesktopShortcuts(ds);
|
||||
|
||||
settings.setShowWmMenu(ui.showWmMenu->isChecked());
|
||||
|
||||
settings.setDesktopCellMargins(QSize(ui.hMargin->value(), ui.vMargin->value()));
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
#include "desktopwindow.h"
|
||||
#include <QWidget>
|
||||
#include <QDesktopWidget>
|
||||
#include <QPainter>
|
||||
#include <QImage>
|
||||
#include <QImageReader>
|
||||
@ -39,6 +38,8 @@
|
||||
#include <QMimeData>
|
||||
#include <QPaintEvent>
|
||||
#include <QStandardPaths>
|
||||
#include <QClipboard>
|
||||
#include <QWindow>
|
||||
|
||||
#include "./application.h"
|
||||
#include "mainwindow.h"
|
||||
@ -59,6 +60,7 @@
|
||||
#include <xcb/xcb.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#define WORK_AREA_MARGIN 12 // margin of the work area
|
||||
#define MIN_SLIDE_INTERVAL 5*60000 // 5 min
|
||||
#define MAX_SLIDE_INTERVAL (24*60+55)*60000 // 24 h and 55 min
|
||||
|
||||
@ -77,9 +79,10 @@ DesktopWindow::DesktopWindow(int screenNum):
|
||||
desktopHideItems_(false),
|
||||
screenNum_(screenNum),
|
||||
relayoutTimer_(nullptr),
|
||||
selectionTimer_(nullptr) {
|
||||
selectionTimer_(nullptr),
|
||||
trashUpdateTimer_(nullptr),
|
||||
trashMonitor_(nullptr) {
|
||||
|
||||
QDesktopWidget* desktopWidget = QApplication::desktop();
|
||||
setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
|
||||
setAttribute(Qt::WA_X11NetWmWindowTypeDesktop);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
@ -91,6 +94,7 @@ DesktopWindow::DesktopWindow(int screenNum):
|
||||
listView_->setMovement(QListView::Snap);
|
||||
listView_->setResizeMode(QListView::Adjust);
|
||||
listView_->setFlow(QListView::TopToBottom);
|
||||
listView_->setDropIndicatorShown(false); // we draw the drop indicator ourself
|
||||
|
||||
// This is to workaround Qt bug 54384 which affects Qt >= 5.6
|
||||
// https://bugreports.qt.io/browse/QTBUG-54384
|
||||
@ -99,14 +103,17 @@ DesktopWindow::DesktopWindow(int screenNum):
|
||||
// Then we paint desktop's background ourselves by using its paint event handling method.
|
||||
listView_->viewport()->setAutoFillBackground(false);
|
||||
|
||||
// NOTE: When XRnadR is in use, the all screens are actually combined to form a
|
||||
Settings& settings = static_cast<Application* >(qApp)->settings();
|
||||
|
||||
// NOTE: When XRandR is in use, the all screens are actually combined to form a
|
||||
// large virtual desktop and only one DesktopWindow needs to be created and screenNum is -1.
|
||||
// In some older multihead setups, such as xinerama, every physical screen
|
||||
// is treated as a separate desktop so many instances of DesktopWindow may be created.
|
||||
// In this case we only want to show desktop icons on the primary screen.
|
||||
if(desktopWidget->isVirtualDesktop() || screenNum_ == desktopWidget->primaryScreen()) {
|
||||
if((screenNum_ == 0 || qApp->primaryScreen()->virtualSiblings().size() > 1)) {
|
||||
loadItemPositions();
|
||||
Settings& settings = static_cast<Application* >(qApp)->settings();
|
||||
|
||||
setShadowHidden(settings.shadowHidden());
|
||||
|
||||
auto desktopPath = Fm::FilePath::fromLocalPath(XdgDir::readDesktopDir().toStdString().c_str());
|
||||
model_ = Fm::CachedFolderModel::modelFromPath(desktopPath);
|
||||
@ -126,7 +133,6 @@ DesktopWindow::DesktopWindow(int screenNum):
|
||||
connect(proxyModel_, &Fm::ProxyFolderModel::layoutChanged, this, &DesktopWindow::onLayoutChanged);
|
||||
connect(proxyModel_, &Fm::ProxyFolderModel::sortFilterChanged, this, &DesktopWindow::onModelSortFilterChanged);
|
||||
connect(proxyModel_, &Fm::ProxyFolderModel::dataChanged, this, &DesktopWindow::onDataChanged);
|
||||
connect(listView_, &QListView::indexesMoved, this, &DesktopWindow::onIndexesMoved);
|
||||
}
|
||||
|
||||
// remove frame
|
||||
@ -148,6 +154,9 @@ DesktopWindow::DesktopWindow(int screenNum):
|
||||
shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_C), this); // copy
|
||||
connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onCopyActivated);
|
||||
|
||||
shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C), this); // copy full path
|
||||
connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onCopyFullPathActivated);
|
||||
|
||||
shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_V), this); // paste
|
||||
connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onPasteActivated);
|
||||
|
||||
@ -171,6 +180,12 @@ DesktopWindow::DesktopWindow(int screenNum):
|
||||
}
|
||||
|
||||
DesktopWindow::~DesktopWindow() {
|
||||
if(trashMonitor_) {
|
||||
g_signal_handlers_disconnect_by_func(trashMonitor_, (gpointer)G_CALLBACK(onTrashChanged), this);
|
||||
g_object_unref(trashMonitor_);
|
||||
trashMonitor_ = nullptr;
|
||||
}
|
||||
|
||||
listView_->viewport()->removeEventFilter(this);
|
||||
listView_->removeEventFilter(this);
|
||||
|
||||
@ -196,6 +211,221 @@ DesktopWindow::~DesktopWindow() {
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopWindow::updateShortcutsFromSettings(Settings& settings) {
|
||||
// Shortcuts should be deleted only when the user removes them
|
||||
// in the Preferences dialog, not when the desktop is created.
|
||||
static bool firstCall = true;
|
||||
|
||||
const QStringList ds = settings.desktopShortcuts();
|
||||
Fm::FilePathList paths;
|
||||
// Trash
|
||||
if(ds.contains(QLatin1String("Trash")) && settings.useTrash()) {
|
||||
createTrash();
|
||||
}
|
||||
else {
|
||||
if(trashUpdateTimer_) {
|
||||
trashUpdateTimer_->stop();
|
||||
delete trashUpdateTimer_;
|
||||
trashUpdateTimer_ = nullptr;
|
||||
}
|
||||
if(trashMonitor_) {
|
||||
g_signal_handlers_disconnect_by_func(trashMonitor_, (gpointer)G_CALLBACK(onTrashChanged), this);
|
||||
g_object_unref(trashMonitor_);
|
||||
trashMonitor_ = nullptr;
|
||||
}
|
||||
if(!firstCall) {
|
||||
QString trash = XdgDir::readDesktopDir() + QLatin1String("/trash-can.desktop");
|
||||
if(QFile::exists(trash)) {
|
||||
paths.push_back(Fm::FilePath::fromLocalPath(trash.toStdString().c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Home
|
||||
if(ds.contains(QLatin1String("Home"))) {
|
||||
createHomeShortcut();
|
||||
}
|
||||
else if(!firstCall) {
|
||||
QString home = XdgDir::readDesktopDir() + QLatin1String("/user-home.desktop");
|
||||
if(QFile::exists(home)) {
|
||||
paths.push_back(Fm::FilePath::fromLocalPath(home.toStdString().c_str()));
|
||||
}
|
||||
}
|
||||
// Computer
|
||||
if(ds.contains(QLatin1String("Computer"))) {
|
||||
createComputerShortcut();
|
||||
}
|
||||
else if(!firstCall) {
|
||||
QString computer = XdgDir::readDesktopDir() + QLatin1String("/computer.desktop");
|
||||
if(QFile::exists(computer)) {
|
||||
paths.push_back(Fm::FilePath::fromLocalPath(computer.toStdString().c_str()));
|
||||
}
|
||||
}
|
||||
// Network
|
||||
if(ds.contains(QLatin1String("Network"))) {
|
||||
createNetworkShortcut();
|
||||
}
|
||||
else if(!firstCall) {
|
||||
QString network = XdgDir::readDesktopDir() + QLatin1String("/network.desktop");
|
||||
if(QFile::exists(network)) {
|
||||
paths.push_back(Fm::FilePath::fromLocalPath(network.toStdString().c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
// WARNING: QFile::remove() is not compatible with libfm-qt and should not be used.
|
||||
if(!paths.empty()) {
|
||||
Fm::FileOperation::deleteFiles(paths, false);
|
||||
}
|
||||
|
||||
firstCall = false; // desktop is created
|
||||
}
|
||||
|
||||
void DesktopWindow::createTrashShortcut(int items) {
|
||||
GKeyFile* kf = g_key_file_new();
|
||||
g_key_file_set_string(kf, "Desktop Entry", "Type", "Application");
|
||||
g_key_file_set_string(kf, "Desktop Entry", "Exec", "pcmanfm-qt trash:///");
|
||||
// icon
|
||||
const char* icon_name = items > 0 ? "user-trash-full" : "user-trash";
|
||||
g_key_file_set_string(kf, "Desktop Entry", "Icon", icon_name);
|
||||
// name
|
||||
QString name;
|
||||
if(items > 0) {
|
||||
if (items == 1) {
|
||||
name = tr("Trash (One item)");
|
||||
}
|
||||
else {
|
||||
name = tr("Trash (%Ln items)", "", items);
|
||||
}
|
||||
}
|
||||
else {
|
||||
name = tr("Trash (Empty)");
|
||||
}
|
||||
g_key_file_set_string(kf, "Desktop Entry", "Name", name.toStdString().c_str());
|
||||
|
||||
auto path = Fm::FilePath::fromLocalPath(XdgDir::readDesktopDir().toStdString().c_str()).localPath();
|
||||
auto trash_can = Fm::CStrPtr{g_build_filename(path.get(), "trash-can.desktop", nullptr)};
|
||||
g_key_file_save_to_file(kf, trash_can.get(), nullptr);
|
||||
g_key_file_free(kf);
|
||||
}
|
||||
|
||||
void DesktopWindow::createHomeShortcut() {
|
||||
GKeyFile* kf = g_key_file_new();
|
||||
g_key_file_set_string(kf, "Desktop Entry", "Type", "Application");
|
||||
g_key_file_set_string(kf, "Desktop Entry", "Exec", "pcmanfm-qt");
|
||||
g_key_file_set_string(kf, "Desktop Entry", "Icon", "user-home");
|
||||
const QString name = tr("Home");
|
||||
g_key_file_set_string(kf, "Desktop Entry", "Name", name.toStdString().c_str());
|
||||
|
||||
auto path = Fm::FilePath::fromLocalPath(XdgDir::readDesktopDir().toStdString().c_str()).localPath();
|
||||
auto trash_can = Fm::CStrPtr{g_build_filename(path.get(), "user-home.desktop", nullptr)};
|
||||
g_key_file_save_to_file(kf, trash_can.get(), nullptr);
|
||||
g_key_file_free(kf);
|
||||
}
|
||||
|
||||
void DesktopWindow::createComputerShortcut() {
|
||||
GKeyFile* kf = g_key_file_new();
|
||||
g_key_file_set_string(kf, "Desktop Entry", "Type", "Application");
|
||||
g_key_file_set_string(kf, "Desktop Entry", "Exec", "pcmanfm-qt computer:///");
|
||||
g_key_file_set_string(kf, "Desktop Entry", "Icon", "computer");
|
||||
const QString name = tr("Computer");
|
||||
g_key_file_set_string(kf, "Desktop Entry", "Name", name.toStdString().c_str());
|
||||
|
||||
auto path = Fm::FilePath::fromLocalPath(XdgDir::readDesktopDir().toStdString().c_str()).localPath();
|
||||
auto trash_can = Fm::CStrPtr{g_build_filename(path.get(), "computer.desktop", nullptr)};
|
||||
g_key_file_save_to_file(kf, trash_can.get(), nullptr);
|
||||
g_key_file_free(kf);
|
||||
}
|
||||
|
||||
void DesktopWindow::createNetworkShortcut() {
|
||||
GKeyFile* kf = g_key_file_new();
|
||||
g_key_file_set_string(kf, "Desktop Entry", "Type", "Application");
|
||||
g_key_file_set_string(kf, "Desktop Entry", "Exec", "pcmanfm-qt network:///");
|
||||
g_key_file_set_string(kf, "Desktop Entry", "Icon", "folder-network");
|
||||
const QString name = tr("Network");
|
||||
g_key_file_set_string(kf, "Desktop Entry", "Name", name.toStdString().c_str());
|
||||
|
||||
auto path = Fm::FilePath::fromLocalPath(XdgDir::readDesktopDir().toStdString().c_str()).localPath();
|
||||
auto trash_can = Fm::CStrPtr{g_build_filename(path.get(), "network.desktop", nullptr)};
|
||||
g_key_file_save_to_file(kf, trash_can.get(), nullptr);
|
||||
g_key_file_free(kf);
|
||||
}
|
||||
|
||||
void DesktopWindow::createTrash() {
|
||||
if(trashMonitor_) {
|
||||
return;
|
||||
}
|
||||
Fm::FilePath trashPath = Fm::FilePath::fromUri("trash:///");
|
||||
// check if trash is supported by the current vfs
|
||||
// if gvfs is not installed, this can be unavailable.
|
||||
if(!g_file_query_exists(trashPath.gfile().get(), nullptr)) {
|
||||
trashMonitor_ = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
trashMonitor_ = g_file_monitor_directory(trashPath.gfile().get(), G_FILE_MONITOR_NONE, nullptr, nullptr);
|
||||
if(trashMonitor_) {
|
||||
if(trashUpdateTimer_ == nullptr) {
|
||||
trashUpdateTimer_ = new QTimer(this);
|
||||
trashUpdateTimer_->setSingleShot(true);
|
||||
connect(trashUpdateTimer_, &QTimer::timeout, this, &DesktopWindow::updateTrashIcon);
|
||||
}
|
||||
updateTrashIcon();
|
||||
g_signal_connect(trashMonitor_, "changed", G_CALLBACK(onTrashChanged), this);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void DesktopWindow::onTrashChanged(GFileMonitor* /*monitor*/, GFile* /*gf*/, GFile* /*other*/, GFileMonitorEvent /*evt*/, DesktopWindow* pThis) {
|
||||
if(pThis->trashUpdateTimer_ != nullptr && !pThis->trashUpdateTimer_->isActive()) {
|
||||
pThis->trashUpdateTimer_->start(250); // don't update trash very fast
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopWindow::updateTrashIcon() {
|
||||
struct UpdateTrashData {
|
||||
QPointer<DesktopWindow> desktop;
|
||||
Fm::FilePath trashPath;
|
||||
UpdateTrashData(DesktopWindow* _desktop) : desktop(_desktop) {
|
||||
trashPath = Fm::FilePath::fromUri("trash:///");
|
||||
}
|
||||
};
|
||||
|
||||
UpdateTrashData* data = new UpdateTrashData(this);
|
||||
g_file_query_info_async(data->trashPath.gfile().get(), G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT, G_FILE_QUERY_INFO_NONE, G_PRIORITY_LOW, nullptr,
|
||||
[](GObject * /*source_object*/, GAsyncResult * res, gpointer user_data) {
|
||||
// the callback lambda function is called when the asyn query operation is finished
|
||||
UpdateTrashData* data = reinterpret_cast<UpdateTrashData*>(user_data);
|
||||
DesktopWindow* _this = data->desktop.data();
|
||||
if(_this != nullptr) {
|
||||
Fm::GFileInfoPtr inf{g_file_query_info_finish(data->trashPath.gfile().get(), res, nullptr), false};
|
||||
if(inf) {
|
||||
guint32 n = g_file_info_get_attribute_uint32(inf.get(), G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT);
|
||||
_this->createTrashShortcut(static_cast<int>(n));
|
||||
}
|
||||
}
|
||||
delete data; // free the data used for this async operation.
|
||||
}, data);
|
||||
}
|
||||
|
||||
bool DesktopWindow::isTrashCan(std::shared_ptr<const Fm::FileInfo> file) {
|
||||
bool ret(false);
|
||||
if(file && (file->isDesktopEntry() || file->isShortcut()) && trashMonitor_) {
|
||||
const QString fileName = QString::fromStdString(file->name());
|
||||
const char* execStr = fileName == QLatin1String("trash-can.desktop")
|
||||
? "pcmanfm-qt trash:///" : nullptr;
|
||||
if(execStr) {
|
||||
GKeyFile* kf = g_key_file_new();
|
||||
if(g_key_file_load_from_file(kf, file->path().toString().get(), G_KEY_FILE_NONE, nullptr)) {
|
||||
Fm::CStrPtr str{g_key_file_get_string(kf, "Desktop Entry", "Exec", nullptr)};
|
||||
if(str && strcmp(str.get(), execStr) == 0) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
g_key_file_free(kf);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DesktopWindow::setBackground(const QColor& color) {
|
||||
bgColor_ = color;
|
||||
}
|
||||
@ -505,6 +735,7 @@ void DesktopWindow::updateFromSettings(Settings& settings, bool changeSlide) {
|
||||
setFont(settings.desktopFont());
|
||||
setIconSize(Fm::FolderView::IconMode, QSize(settings.desktopIconSize(), settings.desktopIconSize()));
|
||||
setMargins(settings.desktopCellMargins());
|
||||
updateShortcutsFromSettings(settings);
|
||||
// setIconSize and setMargins may trigger relayout of items by QListView, so we need to do the layout again.
|
||||
queueRelayout();
|
||||
setForeground(settings.desktopFgColor());
|
||||
@ -566,6 +797,54 @@ void DesktopWindow::onFileClicked(int type, const std::shared_ptr<const Fm::File
|
||||
delete menu;
|
||||
}
|
||||
else {
|
||||
// special right-click menus for our desktop shortcuts
|
||||
if(fileInfo && (fileInfo->isDesktopEntry() || fileInfo->isShortcut())
|
||||
&& type == Fm::FolderView::ContextMenuClick) {
|
||||
Settings& settings = static_cast<Application* >(qApp)->settings();
|
||||
const QStringList ds = settings.desktopShortcuts();
|
||||
if(!ds.isEmpty()) {
|
||||
const QString fileName = QString::fromStdString(fileInfo->name());
|
||||
if((fileName == QLatin1String("trash-can.desktop") && ds.contains(QLatin1String("Trash")))
|
||||
|| (fileName == QLatin1String("user-home.desktop") && ds.contains(QLatin1String("Home")))
|
||||
|| (fileName == QLatin1String("computer.desktop") && ds.contains(QLatin1String("Computer")))
|
||||
|| (fileName == QLatin1String("network.desktop") && ds.contains(QLatin1String("Network")))) {
|
||||
QMenu* menu = new QMenu(this);
|
||||
// "Open" action for all
|
||||
QAction* action = menu->addAction(tr("Open"));
|
||||
connect(action, &QAction::triggered, this, [this, fileInfo] {
|
||||
onFileClicked(Fm::FolderView::ActivatedClick, fileInfo);
|
||||
});
|
||||
// "Stick" action for all
|
||||
action = menu->addAction(tr("Stic&k to Current Position"));
|
||||
action->setCheckable(true);
|
||||
action->setChecked(customItemPos_.find(fileInfo->name()) != customItemPos_.cend());
|
||||
connect(action, &QAction::toggled, this, &DesktopWindow::onStickToCurrentPos);
|
||||
// "Empty Trash" action for Trash shortcut
|
||||
if(fileName == QLatin1String("trash-can.desktop")) {
|
||||
menu->addSeparator();
|
||||
action = menu->addAction(tr("Empty Trash"));
|
||||
// disable the item is Trash is empty
|
||||
GKeyFile* kf = g_key_file_new();
|
||||
if(g_key_file_load_from_file(kf, fileInfo->path().toString().get(), G_KEY_FILE_NONE, nullptr)) {
|
||||
Fm::CStrPtr str{g_key_file_get_string(kf, "Desktop Entry", "Icon", nullptr)};
|
||||
if(str && strcmp(str.get(), "user-trash") == 0) {
|
||||
action->setEnabled(false);
|
||||
}
|
||||
}
|
||||
g_key_file_free(kf);
|
||||
// empty Trash on clicking the item
|
||||
connect(action, &QAction::triggered, this, [] {
|
||||
Fm::FilePathList files;
|
||||
files.push_back(Fm::FilePath::fromUri("trash:///"));
|
||||
Fm::FileOperation::deleteFiles(std::move(files));
|
||||
});
|
||||
}
|
||||
menu->exec(QCursor::pos());
|
||||
delete menu;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
View::onFileClicked(type, fileInfo);
|
||||
}
|
||||
}
|
||||
@ -710,41 +989,6 @@ void DesktopWindow::onDataChanged(const QModelIndex& topLeft, const QModelIndex&
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopWindow::onIndexesMoved(const QModelIndexList& indexes) {
|
||||
auto delegate = static_cast<Fm::FolderItemDelegate*>(listView_->itemDelegateForColumn(0));
|
||||
auto itemSize = delegate->itemSize();
|
||||
// remember the custom position for the items
|
||||
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.
|
||||
// Since we only care about rows, not individual cells,
|
||||
// let's handle column 0 of every row here.
|
||||
if(index.column() == 0) {
|
||||
auto file = proxyModel_->fileInfoFromIndex(index);
|
||||
QRect itemRect = listView_->rectForIndex(index);
|
||||
QPoint tl = itemRect.topLeft();
|
||||
QRect workArea = qApp->desktop()->availableGeometry(screenNum_);
|
||||
workArea.adjust(12, 12, -12, -12);
|
||||
|
||||
// check if the position is occupied by another item
|
||||
auto existingItem = std::find_if(customItemPos_.cbegin(), customItemPos_.cend(), [tl](const std::pair<std::string, QPoint>& elem){
|
||||
return elem.second == tl;
|
||||
});
|
||||
|
||||
if(existingItem == customItemPos_.cend() // don't put items on each other
|
||||
&& tl.x() >= workArea.x() && tl.y() >= workArea.y()
|
||||
&& tl.x() + itemSize.width() <= workArea.right() + 1 // for historical reasons (-> Qt doc)
|
||||
&& tl.y() + itemSize.height() <= workArea.bottom() + 1) { // as above
|
||||
customItemPos_[file->name()] = tl;
|
||||
// qDebug() << "indexMoved:" << name << index << itemRect;
|
||||
}
|
||||
}
|
||||
}
|
||||
saveItemPositions();
|
||||
queueRelayout();
|
||||
}
|
||||
|
||||
void DesktopWindow::onFolderStartLoading() { // desktop may be reloaded
|
||||
if(model_) {
|
||||
disconnect(model_, &Fm::FolderModel::filesAdded, this, &DesktopWindow::onFilesAdded);
|
||||
@ -775,6 +1019,10 @@ void DesktopWindow::onFilesAdded(const Fm::FileInfoList files) {
|
||||
}
|
||||
|
||||
void DesktopWindow::removeBottomGap() {
|
||||
auto screen = getDesktopScreen();
|
||||
if(screen == nullptr) {
|
||||
return;
|
||||
}
|
||||
/************************************************************
|
||||
NOTE: Desktop is an area bounded from below while icons snap
|
||||
to its grid srarting from above. Therefore, we try to adjust
|
||||
@ -785,8 +1033,8 @@ void DesktopWindow::removeBottomGap() {
|
||||
auto itemSize = 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
|
||||
int workAreaHeight = screen->availableVirtualGeometry().height()
|
||||
- 2 * WORK_AREA_MARGIN;
|
||||
int cellHeight = itemSize.height() + listView_->spacing();
|
||||
int iconNumber = workAreaHeight / cellHeight;
|
||||
int bottomGap = workAreaHeight % cellHeight;
|
||||
@ -832,9 +1080,39 @@ void DesktopWindow::paintBackground(QPaintEvent* event) {
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopWindow::trustOurDesktopShortcut(std::shared_ptr<const Fm::FileInfo> file) {
|
||||
if(file->isTrustable()) {
|
||||
return;
|
||||
}
|
||||
Settings& settings = static_cast<Application*>(qApp)->settings();
|
||||
const QStringList ds = settings.desktopShortcuts();
|
||||
if(ds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
const QString fileName = QString::fromStdString(file->name());
|
||||
const char* execStr = fileName == QLatin1String("trash-can.desktop") && ds.contains(QLatin1String("Trash")) ? "pcmanfm-qt trash:///" :
|
||||
fileName == QLatin1String("user-home.desktop") && ds.contains(QLatin1String("Home")) ? "pcmanfm-qt" :
|
||||
fileName == QLatin1String("computer.desktop") && ds.contains(QLatin1String("Computer")) ? "pcmanfm-qt computer:///" :
|
||||
fileName == QLatin1String("network.desktop") && ds.contains(QLatin1String("Network")) ? "pcmanfm-qt network:///" : nullptr;
|
||||
if(execStr) {
|
||||
GKeyFile* kf = g_key_file_new();
|
||||
if(g_key_file_load_from_file(kf, file->path().toString().get(), G_KEY_FILE_NONE, nullptr)) {
|
||||
Fm::CStrPtr str{g_key_file_get_string(kf, "Desktop Entry", "Exec", nullptr)};
|
||||
if(str && strcmp(str.get(), execStr) == 0) {
|
||||
file->setTrustable(true);
|
||||
}
|
||||
}
|
||||
g_key_file_free(kf);
|
||||
}
|
||||
}
|
||||
|
||||
// QListView does item layout in a very inflexible way, so let's do our custom layout again.
|
||||
// FIXME: this is very inefficient, but due to the design flaw of QListView, this is currently the only workaround.
|
||||
void DesktopWindow::relayoutItems() {
|
||||
auto screen = getDesktopScreen();
|
||||
if(screen == nullptr) {
|
||||
return;
|
||||
}
|
||||
displayNames_.clear();
|
||||
loadItemPositions(); // something may have changed
|
||||
// qDebug("relayoutItems()");
|
||||
@ -844,81 +1122,58 @@ void DesktopWindow::relayoutItems() {
|
||||
relayoutTimer_ = nullptr;
|
||||
}
|
||||
|
||||
QDesktopWidget* desktop = qApp->desktop();
|
||||
int screen = 0;
|
||||
int row = 0;
|
||||
int rowCount = proxyModel_->rowCount();
|
||||
|
||||
auto delegate = static_cast<Fm::FolderItemDelegate*>(listView_->itemDelegateForColumn(0));
|
||||
auto itemSize = delegate->itemSize();
|
||||
|
||||
for(;;) {
|
||||
if(desktop->isVirtualDesktop()) {
|
||||
if(screen >= desktop->numScreens()) {
|
||||
QRect workArea = screen->availableVirtualGeometry();
|
||||
workArea.adjust(WORK_AREA_MARGIN, WORK_AREA_MARGIN, -WORK_AREA_MARGIN, -WORK_AREA_MARGIN);
|
||||
// qDebug() << "workArea" << screenNum_ << workArea;
|
||||
// FIXME: we use an internal class declared in a private header here, which is pretty bad.
|
||||
QPoint pos = workArea.topLeft();
|
||||
for(; row < rowCount; ++row) {
|
||||
QModelIndex index = proxyModel_->index(row, 0);
|
||||
int itemWidth = delegate->sizeHint(listView_->getViewOptions(), index).width();
|
||||
auto file = proxyModel_->fileInfoFromIndex(index);
|
||||
// remember display names of desktop entries and shortcuts
|
||||
if(file->isDesktopEntry() || file->isShortcut()) {
|
||||
displayNames_[index] = file->displayName();
|
||||
trustOurDesktopShortcut(file);
|
||||
}
|
||||
auto name = file->name();
|
||||
auto find_it = customItemPos_.find(name);
|
||||
if(find_it != customItemPos_.cend()) { // the item has a custom position
|
||||
QPoint customPos = find_it->second;
|
||||
// center the contents vertically
|
||||
listView_->setPositionForIndex(customPos + QPoint((itemSize.width() - itemWidth) / 2, 0), index);
|
||||
// qDebug() << "set custom pos:" << name << row << index << customPos;
|
||||
continue;
|
||||
}
|
||||
// check if the current pos is already occupied by a custom item
|
||||
bool used = false;
|
||||
for(auto it = customItemPos_.cbegin(); it != customItemPos_.cend(); ++it) {
|
||||
QPoint customPos = it->second;
|
||||
if(QRect(customPos, itemSize).contains(pos)) {
|
||||
used = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(used) { // go to next pos
|
||||
--row;
|
||||
}
|
||||
else {
|
||||
screen = screenNum_;
|
||||
// center the contents vertically
|
||||
listView_->setPositionForIndex(pos + QPoint((itemSize.width() - itemWidth) / 2, 0), index);
|
||||
// qDebug() << "set pos" << name << row << index << pos;
|
||||
}
|
||||
QRect workArea = desktop->availableGeometry(screen);
|
||||
workArea.adjust(12, 12, -12, -12); // add a 12 pixel margin to the work area
|
||||
// qDebug() << "workArea" << screen << workArea;
|
||||
// FIXME: we use an internal class declared in a private header here, which is pretty bad.
|
||||
QPoint pos = workArea.topLeft();
|
||||
for(; row < rowCount; ++row) {
|
||||
QModelIndex index = proxyModel_->index(row, 0);
|
||||
int itemWidth = delegate->sizeHint(listView_->getViewOptions(), index).width();
|
||||
auto file = proxyModel_->fileInfoFromIndex(index);
|
||||
// remember display names of desktop entries and shortcuts
|
||||
if(file->isDesktopEntry() || file->isShortcut()) {
|
||||
displayNames_[index] = file->displayName();
|
||||
}
|
||||
auto name = file->name();
|
||||
auto find_it = customItemPos_.find(name);
|
||||
if(find_it != customItemPos_.cend()) { // the item has a custom position
|
||||
QPoint customPos = find_it->second;
|
||||
// center the contents vertically
|
||||
listView_->setPositionForIndex(customPos + QPoint((itemSize.width() - itemWidth) / 2, 0), index);
|
||||
// qDebug() << "set custom pos:" << name << row << index << customPos;
|
||||
continue;
|
||||
}
|
||||
// check if the current pos is alredy occupied by a custom item
|
||||
bool used = false;
|
||||
for(auto it = customItemPos_.cbegin(); it != customItemPos_.cend(); ++it) {
|
||||
QPoint customPos = it->second;
|
||||
if(QRect(customPos, itemSize).contains(pos)) {
|
||||
used = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(used) { // go to next pos
|
||||
--row;
|
||||
}
|
||||
else {
|
||||
// center the contents vertically
|
||||
listView_->setPositionForIndex(pos + QPoint((itemSize.width() - itemWidth) / 2, 0), index);
|
||||
// qDebug() << "set pos" << name << row << index << pos;
|
||||
}
|
||||
// move to next cell in the column
|
||||
pos.setY(pos.y() + itemSize.height() + listView_->spacing());
|
||||
if(pos.y() + itemSize.height() > workArea.bottom() + 1) {
|
||||
// if the next position may exceed the bottom of work area, go to the top of next column
|
||||
pos.setX(pos.x() + itemSize.width() + listView_->spacing());
|
||||
pos.setY(workArea.top());
|
||||
|
||||
// check if the new column exceeds the right margin of work area
|
||||
if(pos.x() + itemSize.width() > workArea.right() + 1) {
|
||||
if(desktop->isVirtualDesktop()) {
|
||||
// in virtual desktop mode, go to next screen
|
||||
++screen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(row >= rowCount) {
|
||||
break;
|
||||
// move to next cell in the column
|
||||
pos.setY(pos.y() + itemSize.height() + listView_->spacing());
|
||||
if(pos.y() + itemSize.height() > workArea.bottom() + 1) {
|
||||
// if the next position may exceed the bottom of work area, go to the top of next column
|
||||
pos.setX(pos.x() + itemSize.width() + listView_->spacing());
|
||||
pos.setY(workArea.top());
|
||||
}
|
||||
}
|
||||
|
||||
@ -928,6 +1183,10 @@ void DesktopWindow::relayoutItems() {
|
||||
}
|
||||
|
||||
void DesktopWindow::loadItemPositions() {
|
||||
auto screen = getDesktopScreen();
|
||||
if(screen == nullptr) {
|
||||
return;
|
||||
}
|
||||
// load custom item positions
|
||||
customItemPos_.clear();
|
||||
Settings& settings = static_cast<Application*>(qApp)->settings();
|
||||
@ -936,8 +1195,8 @@ void DesktopWindow::loadItemPositions() {
|
||||
|
||||
auto delegate = static_cast<Fm::FolderItemDelegate*>(listView_->itemDelegateForColumn(0));
|
||||
auto grid = delegate->itemSize();
|
||||
QRect workArea = qApp->desktop()->availableGeometry(screenNum_);
|
||||
workArea.adjust(12, 12, -12, -12);
|
||||
QRect workArea = screen->availableVirtualGeometry();
|
||||
workArea.adjust(WORK_AREA_MARGIN, WORK_AREA_MARGIN, -WORK_AREA_MARGIN, -WORK_AREA_MARGIN);
|
||||
QString desktopDir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
desktopDir += '/';
|
||||
std::vector<QPoint> usedPos;
|
||||
@ -1055,6 +1314,16 @@ void DesktopWindow::onCopyActivated() {
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopWindow::onCopyFullPathActivated() {
|
||||
if(desktopHideItems_) {
|
||||
return;
|
||||
}
|
||||
auto paths = selectedFilePaths();
|
||||
if(paths.size() == 1) {
|
||||
QApplication::clipboard()->setText(QString(paths.front().toString().get()), QClipboard::Clipboard);
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopWindow::onPasteActivated() {
|
||||
if(desktopHideItems_) {
|
||||
return;
|
||||
@ -1247,6 +1516,14 @@ bool DesktopWindow::eventFilter(QObject* watched, QEvent* event) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QEvent::Paint:
|
||||
// NOTE: The drop indicator isn't drawn/updated automatically, perhaps,
|
||||
// because we paint desktop ourself. So, we draw it here.
|
||||
paintDropIndicator();
|
||||
break;
|
||||
case QEvent::Wheel:
|
||||
// removal of scrollbars is not enough to prevent scrolling
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1254,55 +1531,173 @@ bool DesktopWindow::eventFilter(QObject* watched, QEvent* event) {
|
||||
return Fm::FolderView::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void DesktopWindow::childDragMoveEvent(QDragMoveEvent* e) {
|
||||
// see DesktopWindow::eventFilter for an explanation
|
||||
QRect oldDropRect = dropRect_;
|
||||
dropRect_ = QRect();
|
||||
QModelIndex dropIndex = listView_->indexAt(e->pos());
|
||||
if(dropIndex.isValid()) {
|
||||
bool dragOnSelf = false;
|
||||
if(e->source() == listView_ && e->keyboardModifiers() == Qt::NoModifier) { // drag source is desktop
|
||||
QModelIndex curIndx = listView_->currentIndex();
|
||||
if(curIndx.isValid() && curIndx == dropIndex) {
|
||||
dragOnSelf = true;
|
||||
}
|
||||
}
|
||||
if(!dragOnSelf && dropIndex.model()) {
|
||||
QVariant data = dropIndex.model()->data(dropIndex, Fm::FolderModel::Role::FileInfoRole);
|
||||
auto info = data.value<std::shared_ptr<const Fm::FileInfo>>();
|
||||
if(info && (info->isDir() || isTrashCan(info))) {
|
||||
dropRect_ = listView_->rectForIndex(dropIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(oldDropRect != dropRect_) {
|
||||
listView_->viewport()->update();
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopWindow::paintDropIndicator()
|
||||
{
|
||||
if(!dropRect_.isNull()) {
|
||||
QPainter painter(listView_->viewport());
|
||||
QStyleOption opt;
|
||||
opt.init(listView_->viewport());
|
||||
opt.rect = dropRect_;
|
||||
style()->drawPrimitive(QStyle::PE_IndicatorItemViewItemDrop, &opt, &painter, listView_);
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopWindow::childDropEvent(QDropEvent* e) {
|
||||
const QMimeData* mimeData = e->mimeData();
|
||||
bool moveItem = false;
|
||||
QModelIndex curIndx = listView_->currentIndex();
|
||||
if(e->source() == listView_ && e->keyboardModifiers() == Qt::NoModifier) {
|
||||
// drag source is our list view, and no other modifier keys are pressed
|
||||
// => we're dragging desktop items
|
||||
if(mimeData->hasFormat("application/x-qabstractitemmodeldatalist")) {
|
||||
QModelIndex dropIndex = listView_->indexAt(e->pos());
|
||||
if(dropIndex.isValid()) { // drop on an item
|
||||
QModelIndexList selected = selectedIndexes(); // the dragged items
|
||||
if(selected.contains(dropIndex)) { // drop on self, ignore
|
||||
moveItem = true;
|
||||
if(dropIndex.isValid() // drop on an item
|
||||
&& curIndx.isValid() && curIndx != dropIndex) { // not a drop on self
|
||||
if(auto file = proxyModel_->fileInfoFromIndex(dropIndex)) {
|
||||
if(!file->isDir()) { // drop on a non-directory file
|
||||
// if the files are dropped on our Trash shortcut item,
|
||||
// move them to Trash instead of moving them on desktop
|
||||
if(isTrashCan(file)) {
|
||||
auto paths = selectedFilePaths();
|
||||
if(!paths.empty()) {
|
||||
e->accept();
|
||||
Settings& settings = static_cast<Application*>(qApp)->settings();
|
||||
Fm::FileOperation::trashFiles(paths, settings.confirmTrash());
|
||||
// remove the drop indicator
|
||||
dropRect_ = QRect();
|
||||
listView_->viewport()->update();
|
||||
return;
|
||||
}
|
||||
}
|
||||
moveItem = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // drop on a blank area
|
||||
else { // drop on a blank area (maybe, between other items)
|
||||
moveItem = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(moveItem) {
|
||||
auto screen = getDesktopScreen();
|
||||
if(screen == nullptr) {
|
||||
return;
|
||||
}
|
||||
e->accept();
|
||||
// move selected items to the drop position, preserving their relative positions
|
||||
const QPoint dropPos = e->pos();
|
||||
if(curIndx.isValid()) {
|
||||
auto delegate = static_cast<Fm::FolderItemDelegate*>(listView_->itemDelegateForColumn(0));
|
||||
auto grid = delegate->itemSize();
|
||||
QRect workArea = screen->availableVirtualGeometry();
|
||||
workArea.adjust(WORK_AREA_MARGIN, WORK_AREA_MARGIN, -WORK_AREA_MARGIN, -WORK_AREA_MARGIN);
|
||||
QPoint curPoint = listView_->visualRect(curIndx).topLeft();
|
||||
|
||||
// first move the current item to the drop position
|
||||
auto file = proxyModel_->fileInfoFromIndex(curIndx);
|
||||
if(file) {
|
||||
QPoint pos = dropPos;
|
||||
stickToPosition(file->name(), pos, workArea, grid);
|
||||
}
|
||||
|
||||
// then move the other items so that their relative postions are preserved
|
||||
const QModelIndexList selected = selectedIndexes();
|
||||
for(const QModelIndex& indx : selected) {
|
||||
if(indx == curIndx) {
|
||||
continue;
|
||||
}
|
||||
file = proxyModel_->fileInfoFromIndex(indx);
|
||||
if(file) {
|
||||
QPoint nxtDropPos = dropPos + listView_->visualRect(indx).topLeft() - curPoint;
|
||||
nxtDropPos.setX(qBound(workArea.left(), nxtDropPos.x(), workArea.right() + 1));
|
||||
nxtDropPos.setY(qBound(workArea.top(), nxtDropPos.y(), workArea.bottom() + 1));
|
||||
stickToPosition(file->name(), nxtDropPos, workArea, grid);
|
||||
}
|
||||
}
|
||||
}
|
||||
saveItemPositions();
|
||||
queueRelayout();
|
||||
}
|
||||
else {
|
||||
auto delegate = static_cast<Fm::FolderItemDelegate*>(listView_->itemDelegateForColumn(0));
|
||||
auto grid = delegate->itemSize();
|
||||
// remove the drop indicator
|
||||
dropRect_ = QRect();
|
||||
listView_->viewport()->update();
|
||||
|
||||
// move items to Trash if they are dropped on Trash shortcut
|
||||
QModelIndex dropIndex = listView_->indexAt(e->pos());
|
||||
if(dropIndex.isValid()) {
|
||||
if(auto file = proxyModel_->fileInfoFromIndex(dropIndex)) {
|
||||
if(isTrashCan(file)) {
|
||||
if(mimeData->hasUrls()) {
|
||||
Fm::FilePathList paths;
|
||||
const QList<QUrl> urlList = mimeData->urls();
|
||||
for(const QUrl& url : urlList) {
|
||||
QString uri = url.toDisplayString();
|
||||
if(!uri.isEmpty()) {
|
||||
paths.push_back(Fm::FilePath::fromUri(uri.toStdString().c_str()));
|
||||
}
|
||||
}
|
||||
if(!paths.empty()) {
|
||||
e->accept();
|
||||
Settings& settings = static_cast<Application*>(qApp)->settings();
|
||||
Fm::FileOperation::trashFiles(paths, settings.confirmTrash());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Fm::FolderView::childDropEvent(e);
|
||||
// position dropped items successively, starting with the drop rectangle
|
||||
if(mimeData->hasUrls()
|
||||
&& (e->dropAction() == Qt::CopyAction
|
||||
|| e->dropAction() == Qt::MoveAction
|
||||
|| e->dropAction() == Qt::LinkAction)) {
|
||||
QList<QUrl> urlList = mimeData->urls();
|
||||
for(int i = 0; i < urlList.count(); ++i) {
|
||||
std::string name = urlList.at(i).fileName().toUtf8().constData();
|
||||
if(!name.empty()) { // respect the positions of existing files
|
||||
QString desktopDir = XdgDir::readDesktopDir() + QString(QLatin1String("/"));
|
||||
if(!QFile::exists(desktopDir + QString::fromStdString(name))) {
|
||||
QRect workArea = qApp->desktop()->availableGeometry(screenNum_);
|
||||
workArea.adjust(12, 12, -12, -12);
|
||||
QPoint pos = mapFromGlobal(e->pos());
|
||||
alignToGrid(pos, workArea.topLeft(), grid, listView_->spacing());
|
||||
if(i > 0)
|
||||
pos.setY(pos.y() + grid.height() + listView_->spacing());
|
||||
if(pos.y() + grid.height() > workArea.bottom() + 1) {
|
||||
pos.setX(pos.x() + grid.width() + listView_->spacing());
|
||||
pos.setY(workArea.top());
|
||||
}
|
||||
customItemPos_[name] = pos;
|
||||
}
|
||||
auto screen = getDesktopScreen();
|
||||
if(screen == nullptr) {
|
||||
return;
|
||||
}
|
||||
auto delegate = static_cast<Fm::FolderItemDelegate*>(listView_->itemDelegateForColumn(0));
|
||||
auto grid = delegate->itemSize();
|
||||
QRect workArea = screen->availableVirtualGeometry();
|
||||
workArea.adjust(WORK_AREA_MARGIN, WORK_AREA_MARGIN, -WORK_AREA_MARGIN, -WORK_AREA_MARGIN);
|
||||
const QString desktopDir = XdgDir::readDesktopDir() + QString(QLatin1String("/"));
|
||||
QPoint dropPos = e->pos();
|
||||
const QList<QUrl> urlList = mimeData->urls();
|
||||
bool reachedLastCell = false;
|
||||
for(const QUrl& url : urlList) {
|
||||
QString name = url.fileName();
|
||||
if(!name.isEmpty()
|
||||
// don't stick to the position if there is an overwrite prompt
|
||||
&& !QFile::exists(desktopDir + name)) {
|
||||
reachedLastCell = stickToPosition(name.toStdString(), dropPos, workArea, grid, reachedLastCell);
|
||||
}
|
||||
}
|
||||
saveItemPositions();
|
||||
@ -1310,13 +1705,93 @@ void DesktopWindow::childDropEvent(QDropEvent* e) {
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This function positions items from top to bottom and left to right,
|
||||
// starting from the drop point, and carries the existing sticky items with them,
|
||||
// until it reaches the last cell and then puts the remaining items in the opposite
|
||||
// direction. In this way, it creates a natural DND, especially with multiple files.
|
||||
bool DesktopWindow::stickToPosition(const std::string& file, QPoint& pos, const QRect& workArea, const QSize& grid, bool reachedLastCell) {
|
||||
// normalize the position, depending on the positioning direction
|
||||
if(!reachedLastCell) { // default direction: top -> bottom, left -> right
|
||||
|
||||
// put the drop point inside the work area to prevent unnatural jumps
|
||||
if(pos.y() + grid.height() > workArea.bottom() + 1) {
|
||||
pos.setY(workArea.bottom() + 1 - grid.height());
|
||||
}
|
||||
if(pos.x() + grid.width() > workArea.right() + 1) {
|
||||
pos.setX(workArea.right() + 1 - grid.width());
|
||||
}
|
||||
pos.setX(qMax(workArea.left(), pos.x()));
|
||||
pos.setY(qMax(workArea.top(), pos.y()));
|
||||
|
||||
alignToGrid(pos, workArea.topLeft(), grid, listView_->spacing());
|
||||
}
|
||||
else { // backward direction: bottom -> top, right -> left
|
||||
if(pos.y() < workArea.top()) {
|
||||
// reached the top; go to the left bottom
|
||||
pos.setY(workArea.bottom() + 1 - grid.height());
|
||||
pos.setX(pos.x() - grid.width() - listView_->spacing());
|
||||
}
|
||||
|
||||
alignToGrid(pos, workArea.topLeft(), grid, listView_->spacing());
|
||||
|
||||
if (pos.x() < workArea.left()) {
|
||||
// there's no space to the left, which means that
|
||||
// the work area is exhausted, so ignore stickiness
|
||||
return reachedLastCell;
|
||||
}
|
||||
}
|
||||
|
||||
// find if there is a sticky item at this position
|
||||
std::string otherFile;
|
||||
auto oldItem = std::find_if(customItemPos_.cbegin(),
|
||||
customItemPos_.cend(),
|
||||
[pos](const std::pair<std::string, QPoint>& elem) {
|
||||
return elem.second == pos;
|
||||
});
|
||||
if(oldItem != customItemPos_.cend()) {
|
||||
otherFile = oldItem->first;
|
||||
}
|
||||
|
||||
// stick to the position
|
||||
customItemPos_[file] = pos;
|
||||
|
||||
// check whether we are in the last visible cell if it isn't reached already
|
||||
if(!reachedLastCell
|
||||
&& pos.y() + 2 * grid.height() + listView_->spacing() > workArea.bottom() + 1
|
||||
&& pos.x() + 2 * grid.width() + listView_->spacing() > workArea.right() + 1) {
|
||||
reachedLastCell = true;
|
||||
}
|
||||
|
||||
// find the next position
|
||||
if(reachedLastCell) {
|
||||
// when this is the last visible cell, reverse the positioning direction
|
||||
// to avoid off-screen items later
|
||||
pos.setY(pos.y() - grid.height() - listView_->spacing());
|
||||
}
|
||||
else {
|
||||
// the last visible cell is not reached yet; go forward
|
||||
if(pos.y() + 2 * grid.height() + listView_->spacing() > workArea.bottom() + 1) {
|
||||
pos.setY(workArea.top());
|
||||
pos.setX(pos.x() + grid.width() + listView_->spacing());
|
||||
}
|
||||
else {
|
||||
pos.setY(pos.y() + grid.height() + listView_->spacing());
|
||||
}
|
||||
}
|
||||
|
||||
// if there was another sticky item at the same position, move it to the next position
|
||||
if(!otherFile.empty() && otherFile != file) {
|
||||
reachedLastCell = stickToPosition(otherFile, pos, workArea, grid, reachedLastCell);
|
||||
}
|
||||
|
||||
return reachedLastCell;
|
||||
}
|
||||
|
||||
void DesktopWindow::alignToGrid(QPoint& pos, const QPoint& topLeft, const QSize& grid, const int spacing) {
|
||||
qreal w = qAbs((qreal)pos.x() - (qreal)topLeft.x())
|
||||
/ (qreal)(grid.width() + spacing);
|
||||
qreal h = qAbs(pos.y() - (qreal)topLeft.y())
|
||||
/ (qreal)(grid.height() + spacing);
|
||||
pos.setX(topLeft.x() + qRound(w) * (grid.width() + spacing));
|
||||
pos.setY(topLeft.y() + qRound(h) * (grid.height() + spacing));
|
||||
int w = (pos.x() - topLeft.x()) / (grid.width() + spacing); // can be negative with DND
|
||||
int h = (pos.y() - topLeft.y()) / (grid.height() + spacing); // can be negative with DND
|
||||
pos.setX(topLeft.x() + w * (grid.width() + spacing));
|
||||
pos.setY(topLeft.y() + h * (grid.height() + spacing));
|
||||
}
|
||||
|
||||
void DesktopWindow::closeEvent(QCloseEvent* event) {
|
||||
@ -1324,7 +1799,7 @@ void DesktopWindow::closeEvent(QCloseEvent* event) {
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
void DesktopWindow::paintEvent(QPaintEvent *event) {
|
||||
void DesktopWindow::paintEvent(QPaintEvent* event) {
|
||||
paintBackground(event);
|
||||
QWidget::paintEvent(event);
|
||||
}
|
||||
@ -1336,4 +1811,21 @@ void DesktopWindow::setScreenNum(int num) {
|
||||
}
|
||||
}
|
||||
|
||||
QScreen* DesktopWindow::getDesktopScreen() const {
|
||||
QScreen* desktopScreen = nullptr;
|
||||
if(screenNum_ == -1) {
|
||||
desktopScreen = qApp->primaryScreen();
|
||||
}
|
||||
else {
|
||||
const auto allScreens = qApp->screens();
|
||||
if(allScreens.size() > screenNum_) {
|
||||
desktopScreen = allScreens.at(screenNum_);
|
||||
}
|
||||
if(desktopScreen == nullptr && windowHandle()) {
|
||||
desktopScreen = windowHandle()->screen();
|
||||
}
|
||||
}
|
||||
return desktopScreen;
|
||||
}
|
||||
|
||||
} // namespace PCManFM
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <QHash>
|
||||
#include <QPoint>
|
||||
#include <QByteArray>
|
||||
#include <QScreen>
|
||||
#include <xcb/xcb.h>
|
||||
#include <libfm-qt/core/folder.h>
|
||||
|
||||
@ -84,6 +85,8 @@ public:
|
||||
|
||||
void setScreenNum(int num);
|
||||
|
||||
QScreen* getDesktopScreen() const;
|
||||
|
||||
protected:
|
||||
virtual void prepareFolderMenu(Fm::FolderMenu* menu) override;
|
||||
virtual void prepareFileMenu(Fm::FileMenu* menu) override;
|
||||
@ -98,9 +101,10 @@ protected:
|
||||
virtual bool event(QEvent* event) override;
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event) override;
|
||||
|
||||
virtual void childDragMoveEvent(QDragMoveEvent* e) override;
|
||||
virtual void childDropEvent(QDropEvent* e) override;
|
||||
virtual void closeEvent(QCloseEvent* event) override;
|
||||
virtual void paintEvent(QPaintEvent *event) override;
|
||||
virtual void paintEvent(QPaintEvent* event) override;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onOpenDirRequested(const Fm::FilePath& path, int target);
|
||||
@ -112,7 +116,6 @@ protected Q_SLOTS:
|
||||
void onRowsInserted(const QModelIndex& parent, int start, int end);
|
||||
void onLayoutChanged();
|
||||
void onModelSortFilterChanged();
|
||||
void onIndexesMoved(const QModelIndexList& indexes);
|
||||
void onDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||
void onFolderStartLoading();
|
||||
void onFolderFinishLoading();
|
||||
@ -126,18 +129,34 @@ protected Q_SLOTS:
|
||||
// file operations
|
||||
void onCutActivated();
|
||||
void onCopyActivated();
|
||||
void onCopyFullPathActivated();
|
||||
void onPasteActivated();
|
||||
void onRenameActivated();
|
||||
void onBulkRenameActivated();
|
||||
void onDeleteActivated();
|
||||
void onFilePropertiesActivated();
|
||||
|
||||
void updateTrashIcon();
|
||||
|
||||
private:
|
||||
void removeBottomGap();
|
||||
void addDesktopActions(QMenu* menu);
|
||||
void paintBackground(QPaintEvent* event);
|
||||
void paintDropIndicator();
|
||||
bool stickToPosition(const std::string& file, QPoint& pos, const QRect& workArea, const QSize& grid, bool reachedLastCell = false);
|
||||
static void alignToGrid(QPoint& pos, const QPoint& topLeft, const QSize& grid, const int spacing);
|
||||
|
||||
void updateShortcutsFromSettings(Settings& settings);
|
||||
void createTrashShortcut(int items);
|
||||
void createHomeShortcut();
|
||||
void createComputerShortcut();
|
||||
void createNetworkShortcut();
|
||||
|
||||
void createTrash();
|
||||
static void onTrashChanged(GFileMonitor* monitor, GFile* gf, GFile* other, GFileMonitorEvent evt, DesktopWindow* pThis);
|
||||
void trustOurDesktopShortcut(std::shared_ptr<const Fm::FileInfo> file);
|
||||
bool isTrashCan(std::shared_ptr<const Fm::FileInfo> file);
|
||||
|
||||
private:
|
||||
Fm::ProxyFolderModel* proxyModel_;
|
||||
Fm::CachedFolderModel* model_;
|
||||
@ -164,6 +183,11 @@ private:
|
||||
QHash<QModelIndex, QString> displayNames_; // only for desktop entries and shortcuts
|
||||
QTimer* relayoutTimer_;
|
||||
QTimer* selectionTimer_;
|
||||
|
||||
QRect dropRect_;
|
||||
|
||||
QTimer* trashUpdateTimer_;
|
||||
GFileMonitor* trashMonitor_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -31,19 +31,6 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="PCManFM::TabBar" name="tabBar" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="acceptDrops">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
@ -57,47 +44,10 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QFrame" name="frame">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stackedWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="filterBar">
|
||||
<property name="toolTip">
|
||||
<string>Focus with Ctrl+I</string>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Filter by string...</string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<widget class="QSplitter" name="viewSplitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
@ -187,15 +137,25 @@
|
||||
<addaction name="actionLocationBar"/>
|
||||
<addaction name="actionPathButtons"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuFiltering">
|
||||
<property name="title">
|
||||
<string>&Filtering</string>
|
||||
</property>
|
||||
<addaction name="actionShowFilter"/>
|
||||
<addaction name="actionUnfilter"/>
|
||||
</widget>
|
||||
<addaction name="actionReload"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionShowHidden"/>
|
||||
<addaction name="actionSplitView"/>
|
||||
<addaction name="menuSorting"/>
|
||||
<addaction name="menu_View_2"/>
|
||||
<addaction name="actionPreserveView"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="menuToolbars"/>
|
||||
<addaction name="menuPathBarStyle"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="menuFiltering"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_Edit">
|
||||
<property name="title">
|
||||
@ -245,6 +205,7 @@
|
||||
</property>
|
||||
<addaction name="actionOpenTerminal"/>
|
||||
<addaction name="actionOpenAsRoot"/>
|
||||
<addaction name="actionCopyFullPath"/>
|
||||
<addaction name="actionFindFiles"/>
|
||||
</widget>
|
||||
<addaction name="menu_File"/>
|
||||
@ -752,12 +713,20 @@
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Filter</string>
|
||||
<string>Permanent &filter bar</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+B</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionUnfilter">
|
||||
<property name="text">
|
||||
<string>&Clear All Filters</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+K</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCloseLeft">
|
||||
<property name="icon">
|
||||
<iconset theme="go-previous">
|
||||
@ -847,14 +816,41 @@
|
||||
<string>Ctrl+F2</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionShowFilter">
|
||||
<property name="text">
|
||||
<string>&Show/Focus Filter Bar</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Show Filter Bar</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+I</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSplitView">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>S&plit View</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Split View</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F6</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCopyFullPath">
|
||||
<property name="text">
|
||||
<string>&Copy Full Path</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+C</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>PCManFM::TabBar</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>tabbar.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>PCManFM::StatusBar</class>
|
||||
<extends>QStatusBar</extends>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,12 +26,12 @@
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QLineEdit>
|
||||
#include <QTabWidget>
|
||||
#include <libfm/fm.h>
|
||||
#include <QMessageBox>
|
||||
#include <QTabBar>
|
||||
#include <QStackedWidget>
|
||||
#include <QSplitter>
|
||||
#include "launcher.h"
|
||||
#include "tabbar.h"
|
||||
#include <libfm-qt/core/filepath.h>
|
||||
#include <libfm-qt/core/bookmarks.h>
|
||||
|
||||
@ -42,6 +42,33 @@ class PathBar;
|
||||
|
||||
namespace PCManFM {
|
||||
|
||||
class ViewFrame : public QFrame {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ViewFrame(QWidget* parent = nullptr);
|
||||
~ViewFrame() {};
|
||||
|
||||
void createTopBar(bool usePathButtons);
|
||||
void removeTopBar();
|
||||
|
||||
QWidget* getTopBar() const {
|
||||
return topBar_;
|
||||
}
|
||||
TabBar* getTabBar() const {
|
||||
return tabBar_;
|
||||
}
|
||||
QStackedWidget* getStackedWidget() const {
|
||||
return stackedWidget_;
|
||||
}
|
||||
|
||||
private:
|
||||
QWidget* topBar_;
|
||||
TabBar* tabBar_;
|
||||
QStackedWidget* stackedWidget_;
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
|
||||
class TabPage;
|
||||
class Settings;
|
||||
|
||||
@ -51,11 +78,21 @@ public:
|
||||
MainWindow(Fm::FilePath path = Fm::FilePath());
|
||||
virtual ~MainWindow();
|
||||
|
||||
void chdir(Fm::FilePath path);
|
||||
int addTab(Fm::FilePath path);
|
||||
void chdir(Fm::FilePath path, ViewFrame* viewFrame);
|
||||
void chdir(Fm::FilePath path) {
|
||||
chdir(path, activeViewFrame_);
|
||||
}
|
||||
|
||||
int addTab(Fm::FilePath path, ViewFrame* viewFrame);
|
||||
int addTab(Fm::FilePath path) {
|
||||
return addTab(path, activeViewFrame_);
|
||||
}
|
||||
|
||||
TabPage* currentPage(ViewFrame* viewFrame) {
|
||||
return reinterpret_cast<TabPage*>(viewFrame->getStackedWidget()->currentWidget());
|
||||
}
|
||||
TabPage* currentPage() {
|
||||
return reinterpret_cast<TabPage*>(ui.stackedWidget->currentWidget());
|
||||
return currentPage(activeViewFrame_);
|
||||
}
|
||||
|
||||
void updateFromSettings(Settings& settings);
|
||||
@ -103,6 +140,7 @@ protected Q_SLOTS:
|
||||
|
||||
void on_actionGo_triggered();
|
||||
void on_actionShowHidden_triggered(bool check);
|
||||
void on_actionSplitView_triggered(bool check);
|
||||
void on_actionPreserveView_triggered(bool checked);
|
||||
|
||||
void on_actionByFileName_triggered(bool checked);
|
||||
@ -115,6 +153,8 @@ protected Q_SLOTS:
|
||||
void on_actionFolderFirst_triggered(bool checked);
|
||||
void on_actionCaseSensitive_triggered(bool checked);
|
||||
void on_actionFilter_triggered(bool checked);
|
||||
void on_actionUnfilter_triggered();
|
||||
void on_actionShowFilter_triggered();
|
||||
|
||||
void on_actionLocationBar_triggered(bool checked);
|
||||
void on_actionPathButtons_triggered(bool checked);
|
||||
@ -129,6 +169,7 @@ protected Q_SLOTS:
|
||||
|
||||
void on_actionOpenTerminal_triggered();
|
||||
void on_actionOpenAsRoot_triggered();
|
||||
void on_actionCopyFullPath_triggered();
|
||||
void on_actionFindFiles_triggered();
|
||||
|
||||
void on_actionAbout_triggered();
|
||||
@ -139,9 +180,6 @@ protected Q_SLOTS:
|
||||
void onTabBarCurrentChanged(int index);
|
||||
void onTabBarTabMoved(int from, int to);
|
||||
|
||||
void focusFilterBar();
|
||||
void onFilterStringChanged(QString str);
|
||||
|
||||
void onShortcutPrevTab();
|
||||
void onShortcutNextTab();
|
||||
void onShortcutJumpToTab();
|
||||
@ -164,7 +202,10 @@ protected Q_SLOTS:
|
||||
|
||||
void onBackForwardContextMenu(QPoint pos);
|
||||
|
||||
void onFolderUnmounted();
|
||||
|
||||
void tabContextMenu(const QPoint& pos);
|
||||
void onTabBarClicked(int index);
|
||||
void closeLeftTabs();
|
||||
void closeRightTabs();
|
||||
void closeOtherTabs() {
|
||||
@ -182,21 +223,27 @@ protected Q_SLOTS:
|
||||
protected:
|
||||
bool event(QEvent* event) override;
|
||||
void changeEvent(QEvent* event) override;
|
||||
void closeTab(int index);
|
||||
void closeTab(int index, ViewFrame* viewFrame);
|
||||
void closeTab(int index) {
|
||||
closeTab(index, activeViewFrame_);
|
||||
}
|
||||
virtual void resizeEvent(QResizeEvent* event) override;
|
||||
virtual void closeEvent(QCloseEvent* event) override;
|
||||
virtual void dragEnterEvent(QDragEnterEvent* event) override;
|
||||
virtual void dropEvent(QDropEvent* event) override;
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
private:
|
||||
void loadBookmarksMenu();
|
||||
void updateUIForCurrentPage();
|
||||
void updateUIForCurrentPage(bool setFocus = true);
|
||||
void updateViewMenuForCurrentPage();
|
||||
void updateEditSelectedActions();
|
||||
void updateStatusBarForCurrentPage();
|
||||
void setRTLIcons(bool isRTL);
|
||||
void createPathBar(bool usePathButtons);
|
||||
int addTabWithPage(TabPage* page, Fm::FilePath path = Fm::FilePath());
|
||||
void addViewFrame(const Fm::FilePath& path);
|
||||
ViewFrame* viewFrameForTabPage(TabPage* page);
|
||||
int addTabWithPage(TabPage* page, ViewFrame* viewFrame, Fm::FilePath path = Fm::FilePath());
|
||||
void dropTab();
|
||||
|
||||
private:
|
||||
@ -209,6 +256,12 @@ private:
|
||||
int rightClickIndex_;
|
||||
bool updatingViewMenu_;
|
||||
QAction* menuSep_;
|
||||
QAction* menuSpacer_;
|
||||
|
||||
ViewFrame* activeViewFrame_;
|
||||
// The split mode of this window is changed only from its settings,
|
||||
// not from another window. So, we get the mode at the start and keep it.
|
||||
bool splitView_;
|
||||
|
||||
static MainWindow* lastActive_;
|
||||
};
|
||||
|
@ -1,4 +1,3 @@
|
||||
#include <libfm/fm.h>
|
||||
#include "application.h"
|
||||
#include <libfm-qt/libfmqt.h>
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="currentRow">
|
||||
<number>-1</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
@ -189,9 +189,11 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="quickExec">
|
||||
<property name="toolTip">
|
||||
<string>Requires application restart to take effect completely</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Launch executable files without prompt
|
||||
(Requires application restart to take effect)</string>
|
||||
<string>Launch executable files without prompt</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -337,8 +339,8 @@
|
||||
</item>
|
||||
<item row="2" column="0" colspan="6">
|
||||
<widget class="QCheckBox" name="showFullNames">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
<property name="toolTip">
|
||||
<string>Requires application restart to take effect completely</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Always show full file names</string>
|
||||
@ -347,8 +349,8 @@
|
||||
</item>
|
||||
<item row="3" column="0" colspan="6">
|
||||
<widget class="QCheckBox" name="shadowHidden">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
<property name="toolTip">
|
||||
<string>Requires application restart to take effect completely</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show icons of hidden files shadowed</string>
|
||||
@ -479,52 +481,41 @@ only if there are more than one tab.</string>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="fullWidthTabbar">
|
||||
<property name="toolTip">
|
||||
<string>If unchecked, the tab bar will be positioned only
|
||||
above the folder-view and not above the left pane.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Fullwidth tab bar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="showTabClose">
|
||||
<property name="text">
|
||||
<string>Show 'Close' buttons on tabs </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="rememberWindowSize">
|
||||
<property name="text">
|
||||
<string>Remember the size of the last closed window</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Default width of new windows:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="fixedWindowWidth">
|
||||
<property name="maximum">
|
||||
<number>32768</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>Default height of new windows:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QSpinBox" name="fixedWindowHeight">
|
||||
<property name="maximum">
|
||||
<number>32768</number>
|
||||
@ -534,100 +525,6 @@ above the folder-view and not above the left pane.</string>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_10">
|
||||
<property name="title">
|
||||
<string>Show in places</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||
<item>
|
||||
<widget class="QListWidget" name="showInPlaces">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Home</string>
|
||||
</property>
|
||||
<property name="checkState">
|
||||
<enum>Unchecked</enum>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="user-home">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Desktop</string>
|
||||
</property>
|
||||
<property name="checkState">
|
||||
<enum>Unchecked</enum>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="user-desktop">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Trash can</string>
|
||||
</property>
|
||||
<property name="checkState">
|
||||
<enum>Unchecked</enum>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="user-trash">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Computer</string>
|
||||
</property>
|
||||
<property name="checkState">
|
||||
<enum>Unchecked</enum>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="computer">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Applications</string>
|
||||
</property>
|
||||
<property name="checkState">
|
||||
<enum>Unchecked</enum>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Devices</string>
|
||||
</property>
|
||||
<property name="checkState">
|
||||
<enum>Unchecked</enum>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Network</string>
|
||||
</property>
|
||||
<property name="checkState">
|
||||
<enum>Unchecked</enum>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="folder-network">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
@ -887,6 +784,22 @@ above the folder-view and not above the left pane.</string>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="warningLabel">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color:#7d0000; color:white; font-weight:bold; border-radius:3px; margin:2px; padding:5px;</string>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Application restart is needed for changes to take effect.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
|
@ -36,6 +36,8 @@ PreferencesDialog::PreferencesDialog(QString activePage, QWidget* parent):
|
||||
QDialog(parent) {
|
||||
ui.setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
warningCounter_ = 0;
|
||||
ui.warningLabel->hide();
|
||||
|
||||
// resize the list widget according to the width of its content.
|
||||
ui.listWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||
@ -168,21 +170,21 @@ void PreferencesDialog::initDisplayPage(Settings& settings) {
|
||||
ui.showFullNames->setChecked(settings.showFullNames());
|
||||
ui.shadowHidden->setChecked(settings.shadowHidden());
|
||||
|
||||
// FIXME: Hide options that we don't support yet.
|
||||
ui.showFullNames->hide();
|
||||
ui.shadowHidden->hide();
|
||||
// app restart warning
|
||||
connect(ui.showFullNames, &QAbstractButton::toggled, [this, &settings] (bool checked) {
|
||||
restartWarning(settings.showFullNames() != checked);
|
||||
});
|
||||
connect(ui.shadowHidden, &QAbstractButton::toggled, [this, &settings] (bool checked) {
|
||||
restartWarning(settings.shadowHidden() != checked);
|
||||
});
|
||||
}
|
||||
|
||||
void PreferencesDialog::initUiPage(Settings& settings) {
|
||||
ui.alwaysShowTabs->setChecked(settings.alwaysShowTabs());
|
||||
ui.fullWidthTabbar->setChecked(settings.fullWidthTabBar());
|
||||
ui.showTabClose->setChecked(settings.showTabClose());
|
||||
ui.rememberWindowSize->setChecked(settings.rememberWindowSize());
|
||||
ui.fixedWindowWidth->setValue(settings.fixedWindowWidth());
|
||||
ui.fixedWindowHeight->setValue(settings.fixedWindowHeight());
|
||||
|
||||
// FIXME: Hide options that we don't support yet.
|
||||
ui.showInPlaces->parentWidget()->hide();
|
||||
}
|
||||
|
||||
void PreferencesDialog::initBehaviorPage(Settings& settings) {
|
||||
@ -221,6 +223,11 @@ void PreferencesDialog::initBehaviorPage(Settings& settings) {
|
||||
ui.confirmTrash->setChecked(settings.confirmTrash());
|
||||
ui.quickExec->setChecked(settings.quickExec());
|
||||
ui.selectNewFiles->setChecked(settings.selectNewFiles());
|
||||
|
||||
// app restart warning
|
||||
connect(ui.quickExec, &QAbstractButton::toggled, [this, &settings] (bool checked) {
|
||||
restartWarning(settings.quickExec() != checked);
|
||||
});
|
||||
}
|
||||
|
||||
void PreferencesDialog::initThumbnailPage(Settings& settings) {
|
||||
@ -304,7 +311,6 @@ void PreferencesDialog::applyDisplayPage(Settings& settings) {
|
||||
|
||||
void PreferencesDialog::applyUiPage(Settings& settings) {
|
||||
settings.setAlwaysShowTabs(ui.alwaysShowTabs->isChecked());
|
||||
settings.setFullWidthTabBar(ui.fullWidthTabbar->isChecked());
|
||||
settings.setShowTabClose(ui.showTabClose->isChecked());
|
||||
settings.setRememberWindowSize(ui.rememberWindowSize->isChecked());
|
||||
settings.setFixedWindowWidth(ui.fixedWindowWidth->value());
|
||||
@ -397,4 +403,14 @@ void PreferencesDialog::lockMargins(bool lock) {
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::restartWarning(bool warn) {
|
||||
if(warn) {
|
||||
++warningCounter_;
|
||||
}
|
||||
else {
|
||||
--warningCounter_;
|
||||
}
|
||||
ui.warningLabel->setVisible(warningCounter_ > 0);
|
||||
}
|
||||
|
||||
} // namespace PCManFM
|
||||
|
@ -65,8 +65,11 @@ private:
|
||||
void initFromSettings();
|
||||
void applySettings();
|
||||
|
||||
void restartWarning(bool warn);
|
||||
|
||||
private:
|
||||
Ui::PreferencesDialog ui;
|
||||
int warningCounter_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -26,7 +26,8 @@
|
||||
#include <QApplication>
|
||||
#include "desktopwindow.h"
|
||||
#include <libfm-qt/utilities.h>
|
||||
#include <libfm-qt/folderconfig.h>
|
||||
#include <libfm-qt/core/folderconfig.h>
|
||||
#include <libfm-qt/core/terminal.h>
|
||||
#include <QStandardPaths>
|
||||
|
||||
namespace PCManFM {
|
||||
@ -88,7 +89,7 @@ Settings::Settings():
|
||||
splitterPos_(120),
|
||||
sidePaneMode_(Fm::SidePane::ModePlaces),
|
||||
showMenuBar_(true),
|
||||
fullWidthTabBar_(true),
|
||||
splitView_(false),
|
||||
viewMode_(Fm::FolderView::IconMode),
|
||||
showHidden_(false),
|
||||
sortOrder_(Qt::AscendingOrder),
|
||||
@ -231,6 +232,7 @@ bool Settings::loadFile(QString filePath) {
|
||||
desktopFont_ = QApplication::font();
|
||||
}
|
||||
desktopIconSize_ = settings.value("DesktopIconSize", 48).toInt();
|
||||
desktopShortcuts_ = settings.value("DesktopShortcuts").toStringList();
|
||||
showWmMenu_ = settings.value("ShowWmMenu", false).toBool();
|
||||
desktopShowHidden_ = settings.value("ShowHidden", false).toBool();
|
||||
desktopHideItems_ = settings.value("HideItems", false).toBool();
|
||||
@ -302,7 +304,7 @@ bool Settings::loadFile(QString filePath) {
|
||||
splitterPos_ = settings.value("SplitterPos", 150).toInt();
|
||||
sidePaneMode_ = sidePaneModeFromString(settings.value("SidePaneMode").toString());
|
||||
showMenuBar_ = settings.value("ShowMenuBar", true).toBool();
|
||||
fullWidthTabBar_ = settings.value("FullWidthTabBar", true).toBool();
|
||||
splitView_ = settings.value("SplitView", false).toBool();
|
||||
pathBarButtons_ = settings.value("PathBarButtons", true).toBool();
|
||||
settings.endGroup();
|
||||
|
||||
@ -361,6 +363,7 @@ bool Settings::saveFile(QString filePath) {
|
||||
settings.setValue("ShadowColor", desktopShadowColor_.name());
|
||||
settings.setValue("Font", desktopFont_.toString());
|
||||
settings.setValue("DesktopIconSize", desktopIconSize_);
|
||||
settings.setValue("DesktopShortcuts", desktopShortcuts_);
|
||||
settings.setValue("ShowWmMenu", showWmMenu_);
|
||||
settings.setValue("ShowHidden", desktopShowHidden_);
|
||||
settings.setValue("HideItems", desktopHideItems_);
|
||||
@ -434,7 +437,7 @@ bool Settings::saveFile(QString filePath) {
|
||||
settings.setValue("SplitterPos", splitterPos_);
|
||||
settings.setValue("SidePaneMode", sidePaneModeToString(sidePaneMode_));
|
||||
settings.setValue("ShowMenuBar", showMenuBar_);
|
||||
settings.setValue("FullWidthTabBar", fullWidthTabBar_);
|
||||
settings.setValue("SplitView", splitView_);
|
||||
settings.setValue("PathBarButtons", pathBarButtons_);
|
||||
settings.endGroup();
|
||||
|
||||
@ -686,10 +689,7 @@ static Fm::SidePane::Mode sidePaneModeFromString(const QString& str) {
|
||||
|
||||
void Settings::setTerminal(QString terminalCommand) {
|
||||
terminal_ = terminalCommand;
|
||||
// override the settings in libfm FmConfig.
|
||||
g_free(fm_config->terminal);
|
||||
fm_config->terminal = g_strdup(terminal_.toLocal8Bit().constData());
|
||||
g_signal_emit_by_name(fm_config, "changed::terminal");
|
||||
Fm::setDefaultTerminal(terminal_.toStdString());
|
||||
}
|
||||
|
||||
|
||||
@ -730,17 +730,17 @@ FolderSettings Settings::loadFolderSettings(const Fm::FilePath& path) const {
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
gboolean show_hidden;
|
||||
bool show_hidden;
|
||||
if(cfg.getBoolean("ShowHidden", &show_hidden)) {
|
||||
settings.setShowHidden(show_hidden);
|
||||
}
|
||||
|
||||
gboolean folder_first;
|
||||
bool folder_first;
|
||||
if(cfg.getBoolean("SortFolderFirst", &folder_first)) {
|
||||
settings.setSortFolderFirst(folder_first);
|
||||
}
|
||||
|
||||
gboolean case_sensitive;
|
||||
bool case_sensitive;
|
||||
if(cfg.getBoolean("SortCaseSensitive", &case_sensitive)) {
|
||||
settings.setSortCaseSensitive(case_sensitive);
|
||||
}
|
||||
|
@ -22,13 +22,13 @@
|
||||
#define PCMANFM_SETTINGS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <libfm/fm.h>
|
||||
#include <libfm-qt/folderview.h>
|
||||
#include <libfm-qt/foldermodel.h>
|
||||
#include "desktopwindow.h"
|
||||
#include <libfm-qt/sidepane.h>
|
||||
#include <libfm-qt/core/thumbnailjob.h>
|
||||
#include <libfm-qt/core/archiver.h>
|
||||
#include <libfm-qt/core/legacy/fm-config.h>
|
||||
|
||||
namespace PCManFM {
|
||||
|
||||
@ -313,6 +313,14 @@ public:
|
||||
desktopIconSize_ = desktopIconSize;
|
||||
}
|
||||
|
||||
QStringList desktopShortcuts() const {
|
||||
return desktopShortcuts_;
|
||||
}
|
||||
|
||||
void setDesktopShortcuts(const QStringList& list) {
|
||||
desktopShortcuts_ = list;
|
||||
}
|
||||
|
||||
bool showWmMenu() const {
|
||||
return showWmMenu_;
|
||||
}
|
||||
@ -464,12 +472,12 @@ public:
|
||||
showMenuBar_ = showMenuBar;
|
||||
}
|
||||
|
||||
bool fullWidthTabBar() const {
|
||||
return fullWidthTabBar_;
|
||||
bool splitView() const {
|
||||
return splitView_;
|
||||
}
|
||||
|
||||
void setFullWidthTabBar(bool fullWith) {
|
||||
fullWidthTabBar_ = fullWith;
|
||||
void setSplitView(bool split) {
|
||||
splitView_ = split;
|
||||
}
|
||||
|
||||
Fm::FolderView::ViewMode viewMode() const {
|
||||
@ -899,6 +907,7 @@ private:
|
||||
QColor desktopShadowColor_;
|
||||
QFont desktopFont_;
|
||||
int desktopIconSize_;
|
||||
QStringList desktopShortcuts_;
|
||||
bool showWmMenu_;
|
||||
|
||||
bool desktopShowHidden_;
|
||||
@ -918,7 +927,7 @@ private:
|
||||
int splitterPos_;
|
||||
Fm::SidePane::Mode sidePaneMode_;
|
||||
bool showMenuBar_;
|
||||
bool fullWidthTabBar_;
|
||||
bool splitView_;
|
||||
|
||||
Fm::FolderView::ViewMode viewMode_;
|
||||
bool showHidden_;
|
||||
|
@ -29,23 +29,31 @@ namespace PCManFM {
|
||||
|
||||
TabBar::TabBar(QWidget *parent):
|
||||
QTabBar(parent),
|
||||
dragStarted_(false)
|
||||
dragStarted_(false),
|
||||
detachable_(true)
|
||||
{
|
||||
}
|
||||
|
||||
void TabBar::mousePressEvent(QMouseEvent *event) {
|
||||
QTabBar::mousePressEvent (event);
|
||||
if(event->button() == Qt::LeftButton
|
||||
&& tabAt(event->pos()) > -1) {
|
||||
dragStartPosition_ = event->pos();
|
||||
if(detachable_){
|
||||
if(event->button() == Qt::LeftButton
|
||||
&& tabAt(event->pos()) > -1) {
|
||||
dragStartPosition_ = event->pos();
|
||||
}
|
||||
dragStarted_ = false;
|
||||
}
|
||||
dragStarted_ = false;
|
||||
}
|
||||
|
||||
void TabBar::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if(!detachable_) {
|
||||
QTabBar::mouseMoveEvent(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!dragStartPosition_.isNull()
|
||||
&& (event->pos() - dragStartPosition_).manhattanLength() < QApplication::startDragDistance()) {
|
||||
&& (event->pos() - dragStartPosition_).manhattanLength() >= QApplication::startDragDistance()) {
|
||||
dragStarted_ = true;
|
||||
}
|
||||
|
||||
@ -102,7 +110,7 @@ void TabBar::mouseReleaseEvent(QMouseEvent *event) {
|
||||
|
||||
// Let the main window receive dragged tabs!
|
||||
void TabBar::dragEnterEvent(QDragEnterEvent *event) {
|
||||
if(event->mimeData()->hasFormat("application/pcmanfm-qt-tab")) {
|
||||
if(detachable_ && event->mimeData()->hasFormat("application/pcmanfm-qt-tab")) {
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,10 @@ public:
|
||||
void finishMouseMoveEvent();
|
||||
void releaseMouse();
|
||||
|
||||
void setDetachable(bool detachable) {
|
||||
detachable_ = detachable;
|
||||
}
|
||||
|
||||
Q_SIGNALS:
|
||||
void tabDetached();
|
||||
|
||||
@ -48,6 +52,7 @@ protected:
|
||||
private:
|
||||
QPoint dragStartPosition_;
|
||||
bool dragStarted_;
|
||||
bool detachable_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -30,6 +30,8 @@
|
||||
#include <QCursor>
|
||||
#include <QMessageBox>
|
||||
#include <QScrollBar>
|
||||
#include <QToolButton>
|
||||
#include <QLabel>
|
||||
#include <QDir>
|
||||
#include "settings.h"
|
||||
#include "application.h"
|
||||
@ -52,6 +54,50 @@ bool ProxyFilter::filterAcceptsRow(const Fm::ProxyFolderModel* model, const std:
|
||||
return true;
|
||||
}
|
||||
|
||||
//==================================================
|
||||
|
||||
FilterEdit::FilterEdit(QWidget* parent) : QLineEdit(parent) {
|
||||
setClearButtonEnabled(true);
|
||||
if(QToolButton *clearButton = findChild<QToolButton*>()) {
|
||||
clearButton->setToolTip(tr("Clear text (Ctrl+K)"));
|
||||
}
|
||||
}
|
||||
|
||||
void FilterEdit::keyPressEvent(QKeyEvent* event) {
|
||||
// since two views can be shown in the split mode, Ctrl+K can't be
|
||||
// used as a QShortcut but can come here for clearing the text
|
||||
if(event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_K) {
|
||||
clear();
|
||||
}
|
||||
QLineEdit::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void FilterEdit::keyPressed(QKeyEvent* event) {
|
||||
// NOTE: Movement and delete keys should be left to the view.
|
||||
// Copy/paste shortcuts are taken by the view but they aren't needed here
|
||||
// (Shift+Insert works for pasting but, since most users may not be familiar
|
||||
// with it, an action is added to the main window for focusing an empty bar).
|
||||
if(!hasFocus()
|
||||
&& event->key() != Qt::Key_Left && event->key() != Qt::Key_Right
|
||||
&& event->key() != Qt::Key_Home && event->key() != Qt::Key_End
|
||||
&& event->key() != Qt::Key_Delete) {
|
||||
keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
FilterBar::FilterBar(QWidget* parent) : QWidget(parent) {
|
||||
QHBoxLayout* HLayout = new QHBoxLayout(this);
|
||||
HLayout->setSpacing(5);
|
||||
filterEdit_ = new FilterEdit();
|
||||
QLabel *label = new QLabel(tr("Filter:"));
|
||||
HLayout->addWidget(label);
|
||||
HLayout->addWidget(filterEdit_);
|
||||
connect(filterEdit_, &QLineEdit::textChanged, this, &FilterBar::textChanged);
|
||||
connect(filterEdit_, &FilterEdit::lostFocus, this, &FilterBar::lostFocus);
|
||||
}
|
||||
|
||||
//==================================================
|
||||
|
||||
TabPage::TabPage(QWidget* parent):
|
||||
QWidget(parent),
|
||||
folderView_{nullptr},
|
||||
@ -60,7 +106,8 @@ TabPage::TabPage(QWidget* parent):
|
||||
proxyFilter_{nullptr},
|
||||
verticalLayout{nullptr},
|
||||
overrideCursor_(false),
|
||||
selectionTimer_(nullptr) {
|
||||
selectionTimer_(nullptr),
|
||||
filterBar_(nullptr) {
|
||||
|
||||
Settings& settings = static_cast<Application*>(qApp)->settings();
|
||||
|
||||
@ -76,6 +123,7 @@ TabPage::TabPage(QWidget* parent):
|
||||
|
||||
folderView_ = new View(settings.viewMode(), this);
|
||||
folderView_->setMargins(settings.folderViewCellMargins());
|
||||
folderView_->setShadowHidden(settings.shadowHidden());
|
||||
// newView->setColumnWidth(Fm::FolderModel::ColumnName, 200);
|
||||
connect(folderView_, &View::openDirRequested, this, &TabPage::openDirRequested);
|
||||
connect(folderView_, &View::selChanged, this, &TabPage::onSelChanged);
|
||||
@ -88,6 +136,14 @@ TabPage::TabPage(QWidget* parent):
|
||||
// FIXME: this is very dirty
|
||||
folderView_->setModel(proxyModel_);
|
||||
verticalLayout->addWidget(folderView_);
|
||||
|
||||
// filter-bar and its settings
|
||||
filterBar_ = new FilterBar();
|
||||
verticalLayout->addWidget(filterBar_);
|
||||
if(!settings.showFilter()){
|
||||
transientFilterBar(true);
|
||||
}
|
||||
connect(filterBar_, &FilterBar::textChanged, this, &TabPage::onFilterStringChanged);
|
||||
}
|
||||
|
||||
TabPage::~TabPage() {
|
||||
@ -109,6 +165,78 @@ TabPage::~TabPage() {
|
||||
}
|
||||
}
|
||||
|
||||
void TabPage::transientFilterBar(bool transient) {
|
||||
if(filterBar_) {
|
||||
filterBar_->clear();
|
||||
if(transient) {
|
||||
filterBar_->hide();
|
||||
folderView_->childView()->removeEventFilter(this);
|
||||
folderView_->childView()->installEventFilter(this);
|
||||
connect(filterBar_, &FilterBar::lostFocus, this, &TabPage::onLosingFilterBarFocus);
|
||||
}
|
||||
else {
|
||||
filterBar_->show();
|
||||
folderView_->childView()->removeEventFilter(this);
|
||||
disconnect(filterBar_, &FilterBar::lostFocus, this, &TabPage::onLosingFilterBarFocus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TabPage::onLosingFilterBarFocus() {
|
||||
// hide the empty transient filter-bar when it loses focus
|
||||
if(getFilterStr().isEmpty()) {
|
||||
filterBar_->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void TabPage::showFilterBar() {
|
||||
if(filterBar_) {
|
||||
filterBar_->show();
|
||||
if(isVisibleTo(this)) { // the page itself may be in an inactive tab
|
||||
filterBar_->focusBar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TabPage::eventFilter(QObject* watched, QEvent* event) {
|
||||
// when a text is typed inside the view, type it inside the filter-bar
|
||||
if(filterBar_ && watched == folderView_->childView() && event->type() == QEvent::KeyPress) {
|
||||
if(QKeyEvent* ke = static_cast<QKeyEvent*>(event)) {
|
||||
filterBar_->keyPressed(ke);
|
||||
}
|
||||
}
|
||||
return QWidget::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void TabPage::backspacePressed() {
|
||||
if(filterBar_ && filterBar_->isVisible()) {
|
||||
QKeyEvent bs = QKeyEvent(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier);
|
||||
filterBar_->keyPressed(&bs);
|
||||
}
|
||||
}
|
||||
|
||||
void TabPage::onFilterStringChanged(QString str) {
|
||||
if(filterBar_ && str != getFilterStr()) {
|
||||
setFilterStr(str);
|
||||
applyFilter();
|
||||
// show/hide the transient filter-bar appropriately
|
||||
if(!static_cast<Application*>(qApp)->settings().showFilter()) {
|
||||
if(filterBar_->isVisibleTo(this)) { // the page itself may be in an inactive tab
|
||||
if(str.isEmpty()) {
|
||||
// focus the view BEFORE hiding the filter-bar to avoid redundant "FocusIn" events;
|
||||
// otherwise, another widget inside the main window might gain focus immediately
|
||||
// after the filter-bar is hidden and only after that, the view will be focused.
|
||||
folderView()->childView()->setFocus();
|
||||
filterBar_->hide();
|
||||
}
|
||||
}
|
||||
else if(!str.isEmpty()) {
|
||||
filterBar_->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TabPage::freeFolder() {
|
||||
if(folder_) {
|
||||
if(folderSettings_.isCustomized()) {
|
||||
@ -285,13 +413,9 @@ void TabPage::onFolderFsInfo() {
|
||||
guint64 free, total;
|
||||
QString& msg = statusText_[StatusTextFSInfo];
|
||||
if(folder_->getFilesystemInfo(&total, &free)) {
|
||||
char total_str[64];
|
||||
char free_str[64];
|
||||
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),
|
||||
QString::fromUtf8(total_str));
|
||||
.arg(formatFileSize(free, fm_config->si_unit))
|
||||
.arg(formatFileSize(total, fm_config->si_unit));
|
||||
}
|
||||
else {
|
||||
msg.clear();
|
||||
@ -340,21 +464,12 @@ void TabPage::onFolderRemoved() {
|
||||
void TabPage::onFolderUnmount() {
|
||||
// the folder we're showing is unmounted, destroy the widget
|
||||
qDebug("folder unmount");
|
||||
// NOTE: call deleteLater() directly from this GObject signal handler
|
||||
// does not work but I don't know why.
|
||||
// Maybe it's the problem of glib mainloop integration?
|
||||
// Call it when idle works, though.
|
||||
Settings& settings = static_cast<Application*>(qApp)->settings();
|
||||
// NOTE: call deleteLater() directly from this GObject signal handler
|
||||
// does not work but I don't know why.
|
||||
// Maybe it's the problem of glib mainloop integration?
|
||||
// Call it when idle works, though.
|
||||
if(settings.closeOnUnmount()) {
|
||||
QTimer::singleShot(0, this, SLOT(deleteLater()));
|
||||
}
|
||||
else {
|
||||
chdir(Fm::FilePath::homeDir());
|
||||
}
|
||||
// NOTE: We cannot delete the page or change its directory here
|
||||
// because unmounting might be done from places view, in which case,
|
||||
// the mount operation is a child of the places view and should be
|
||||
// finished before doing anything else.
|
||||
freeFolder();
|
||||
Q_EMIT folderUnmounted();
|
||||
}
|
||||
|
||||
void TabPage::onFolderContentChanged() {
|
||||
@ -372,6 +487,9 @@ QString TabPage::pathName() {
|
||||
|
||||
void TabPage::chdir(Fm::FilePath newPath, bool addHistory) {
|
||||
// qDebug() << "TABPAGE CHDIR:" << newPath.toString().get();
|
||||
if(filterBar_){
|
||||
filterBar_->clear();
|
||||
}
|
||||
if(folder_) {
|
||||
// we're already in the specified dir
|
||||
if(newPath == folder_->path()) {
|
||||
@ -421,10 +539,11 @@ void TabPage::chdir(Fm::FilePath newPath, bool addHistory) {
|
||||
connect(folder_.get(), &Fm::Folder::unmount, this, &TabPage::onFolderUnmount);
|
||||
connect(folder_.get(), &Fm::Folder::contentChanged, this, &TabPage::onFolderContentChanged);
|
||||
|
||||
Settings& settings = static_cast<Application*>(qApp)->settings();
|
||||
folderModel_ = CachedFolderModel::modelFromFolder(folder_);
|
||||
folderModel_->setShowFullName(settings.showFullNames());
|
||||
|
||||
// set sorting, considering customized folders
|
||||
Settings& settings = static_cast<Application*>(qApp)->settings();
|
||||
folderSettings_ = settings.loadFolderSettings(path());
|
||||
proxyModel_->sort(folderSettings_.sortColumn(), folderSettings_.sortOrder());
|
||||
proxyModel_->setFolderFirst(folderSettings_.sortFolderFirst());
|
||||
@ -432,7 +551,7 @@ void TabPage::chdir(Fm::FilePath newPath, bool addHistory) {
|
||||
proxyModel_->setSortCaseSensitivity(folderSettings_.sortCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive);
|
||||
proxyModel_->setSourceModel(folderModel_);
|
||||
|
||||
folderView_->setViewMode(folderSettings_.viewMode());
|
||||
setViewMode(folderSettings_.viewMode());
|
||||
|
||||
if(folder_->isLoaded()) {
|
||||
onFolderStartLoading();
|
||||
@ -600,13 +719,22 @@ void TabPage::updateFromSettings(Settings& settings) {
|
||||
}
|
||||
|
||||
void TabPage::setViewMode(Fm::FolderView::ViewMode mode) {
|
||||
Settings& settings = static_cast<Application*>(qApp)->settings();
|
||||
if(folderSettings_.viewMode() != mode) {
|
||||
folderSettings_.setViewMode(mode);
|
||||
if(folderSettings_.isCustomized()) {
|
||||
static_cast<Application*>(qApp)->settings().saveFolderSettings(path(), folderSettings_);
|
||||
settings.saveFolderSettings(path(), folderSettings_);
|
||||
}
|
||||
}
|
||||
Fm::FolderView::ViewMode prevMode = folderView_->viewMode();
|
||||
folderView_->setViewMode(mode);
|
||||
folderView_->childView()->setFocus();
|
||||
if(!settings.showFilter() && prevMode != folderView_->viewMode()) {
|
||||
// FolderView::setViewMode() may delete the view to switch between list and tree.
|
||||
// So, the event filter should be re-installed.
|
||||
folderView_->childView()->removeEventFilter(this);
|
||||
folderView_->childView()->installEventFilter(this);
|
||||
}
|
||||
}
|
||||
|
||||
void TabPage::sort(int col, Qt::SortOrder order) {
|
||||
@ -665,7 +793,12 @@ void TabPage::applyFilter() {
|
||||
if(!proxyModel_) {
|
||||
return;
|
||||
}
|
||||
int prevSelSize = folderView_->selectionModel()->selectedIndexes().size();
|
||||
proxyModel_->updateFilters();
|
||||
// if some selected files are filtered out, "View::selChanged()" won't be emitted
|
||||
if(prevSelSize > folderView_->selectionModel()->selectedIndexes().size()) {
|
||||
onSelChanged();
|
||||
}
|
||||
statusText_[StatusTextNormal] = formatStatusText();
|
||||
Q_EMIT statusChanged(StatusTextNormal, statusText_[StatusTextNormal]);
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
#include <QWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <libfm/fm.h>
|
||||
#include <QLineEdit>
|
||||
#include <libfm-qt/browsehistory.h>
|
||||
#include "view.h"
|
||||
#include "settings.h"
|
||||
@ -58,6 +58,52 @@ private:
|
||||
QString filterStr_;
|
||||
};
|
||||
|
||||
//==================================================
|
||||
|
||||
class FilterEdit : public QLineEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
FilterEdit(QWidget *parent = nullptr);
|
||||
~FilterEdit() {};
|
||||
void keyPressed(QKeyEvent* event);
|
||||
|
||||
protected:
|
||||
virtual void focusOutEvent(QFocusEvent* event) override {
|
||||
Q_EMIT lostFocus();
|
||||
QLineEdit::focusOutEvent(event);
|
||||
}
|
||||
virtual void keyPressEvent(QKeyEvent* event) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void lostFocus();
|
||||
};
|
||||
|
||||
class FilterBar : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
FilterBar(QWidget *parent = nullptr);
|
||||
~FilterBar() {};
|
||||
|
||||
void focusBar() {
|
||||
filterEdit_->setFocus();
|
||||
}
|
||||
void clear() {
|
||||
filterEdit_->clear();
|
||||
}
|
||||
void keyPressed(QKeyEvent* event) {
|
||||
filterEdit_->keyPressed(event);
|
||||
}
|
||||
|
||||
Q_SIGNALS:
|
||||
void textChanged(const QString &text);
|
||||
void lostFocus();
|
||||
|
||||
private:
|
||||
FilterEdit* filterEdit_;
|
||||
};
|
||||
|
||||
//==================================================
|
||||
|
||||
class TabPage : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
@ -197,6 +243,20 @@ public:
|
||||
|
||||
void setCustomizedView(bool value);
|
||||
|
||||
void transientFilterBar(bool transient);
|
||||
|
||||
void showFilterBar();
|
||||
bool isFilterBarVisible() const {
|
||||
return (filterBar_ && filterBar_->isVisible());
|
||||
}
|
||||
void clearFilter() {
|
||||
if(filterBar_) {
|
||||
filterBar_->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void backspacePressed();
|
||||
|
||||
Q_SIGNALS:
|
||||
void statusChanged(int type, QString statusText);
|
||||
void titleChanged(QString title);
|
||||
@ -204,12 +264,18 @@ Q_SIGNALS:
|
||||
void sortFilterChanged();
|
||||
void forwardRequested();
|
||||
void backwardRequested();
|
||||
void folderUnmounted();
|
||||
|
||||
protected:
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onSelChanged();
|
||||
void onUiUpdated();
|
||||
void onFileSizeChanged(const QModelIndex& index);
|
||||
void onFilesAdded(const Fm::FileInfoList files);
|
||||
void onFilterStringChanged(QString str);
|
||||
void onLosingFilterBarFocus();
|
||||
|
||||
private:
|
||||
void freeFolder();
|
||||
@ -242,6 +308,7 @@ private:
|
||||
bool overrideCursor_;
|
||||
FolderSettings folderSettings_;
|
||||
QTimer* selectionTimer_;
|
||||
FilterBar* filterBar_;
|
||||
};
|
||||
|
||||
}
|
||||
|
3
pcmanfm/translations/CMakeLists.txt
Normal file
3
pcmanfm/translations/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
project(pcmanfm-qt)
|
||||
|
||||
build_component("." "${CMAKE_INSTALL_FULL_DATADIR}/pcmanfm-qt/translations")
|
4
pcmanfm/translations/pcmanfm-qt-desktop-pref_cs.desktop
Normal file
4
pcmanfm/translations/pcmanfm-qt-desktop-pref_cs.desktop
Normal file
@ -0,0 +1,4 @@
|
||||
#Translations
|
||||
Name[cs]=Pracovní plocha
|
||||
GenericName[cs]=Nastavení pracovní plochy
|
||||
Comment[cs]=Změna pozadí plochy a chování jejího správce
|
4
pcmanfm/translations/pcmanfm-qt-desktop-pref_ja.desktop
Normal file
4
pcmanfm/translations/pcmanfm-qt-desktop-pref_ja.desktop
Normal file
@ -0,0 +1,4 @@
|
||||
#Translations
|
||||
Name[ja]=デスクトップ
|
||||
GenericName[ja]=デスクトップ設定
|
||||
Comment[ja]=壁紙やその他のデスクトップ設定を変更します
|
1796
pcmanfm/translations/pcmanfm-qt.ts
Normal file
1796
pcmanfm/translations/pcmanfm-qt.ts
Normal file
File diff suppressed because it is too large
Load Diff
1835
pcmanfm/translations/pcmanfm-qt_ar.ts
Normal file
1835
pcmanfm/translations/pcmanfm-qt_ar.ts
Normal file
File diff suppressed because it is too large
Load Diff
1825
pcmanfm/translations/pcmanfm-qt_ca.ts
Normal file
1825
pcmanfm/translations/pcmanfm-qt_ca.ts
Normal file
File diff suppressed because it is too large
Load Diff
4
pcmanfm/translations/pcmanfm-qt_cs.desktop
Normal file
4
pcmanfm/translations/pcmanfm-qt_cs.desktop
Normal file
@ -0,0 +1,4 @@
|
||||
#Translations
|
||||
Name[cs]=PCManFM-Qt
|
||||
GenericName[cs]=Správce souborů
|
||||
Comment[cs]=Procházejte souborový systém a spravujte soubory
|
1826
pcmanfm/translations/pcmanfm-qt_cs.ts
Normal file
1826
pcmanfm/translations/pcmanfm-qt_cs.ts
Normal file
File diff suppressed because it is too large
Load Diff
1812
pcmanfm/translations/pcmanfm-qt_cy.ts
Normal file
1812
pcmanfm/translations/pcmanfm-qt_cy.ts
Normal file
File diff suppressed because it is too large
Load Diff
1820
pcmanfm/translations/pcmanfm-qt_da.ts
Normal file
1820
pcmanfm/translations/pcmanfm-qt_da.ts
Normal file
File diff suppressed because it is too large
Load Diff
1824
pcmanfm/translations/pcmanfm-qt_de.ts
Normal file
1824
pcmanfm/translations/pcmanfm-qt_de.ts
Normal file
File diff suppressed because it is too large
Load Diff
1822
pcmanfm/translations/pcmanfm-qt_el.ts
Normal file
1822
pcmanfm/translations/pcmanfm-qt_el.ts
Normal file
File diff suppressed because it is too large
Load Diff
1800
pcmanfm/translations/pcmanfm-qt_en_GB.ts
Normal file
1800
pcmanfm/translations/pcmanfm-qt_en_GB.ts
Normal file
File diff suppressed because it is too large
Load Diff
1820
pcmanfm/translations/pcmanfm-qt_es.ts
Normal file
1820
pcmanfm/translations/pcmanfm-qt_es.ts
Normal file
File diff suppressed because it is too large
Load Diff
1820
pcmanfm/translations/pcmanfm-qt_et.ts
Normal file
1820
pcmanfm/translations/pcmanfm-qt_et.ts
Normal file
File diff suppressed because it is too large
Load Diff
1823
pcmanfm/translations/pcmanfm-qt_fr.ts
Normal file
1823
pcmanfm/translations/pcmanfm-qt_fr.ts
Normal file
File diff suppressed because it is too large
Load Diff
1820
pcmanfm/translations/pcmanfm-qt_gl.ts
Normal file
1820
pcmanfm/translations/pcmanfm-qt_gl.ts
Normal file
File diff suppressed because it is too large
Load Diff
1817
pcmanfm/translations/pcmanfm-qt_hu.ts
Normal file
1817
pcmanfm/translations/pcmanfm-qt_hu.ts
Normal file
File diff suppressed because it is too large
Load Diff
1820
pcmanfm/translations/pcmanfm-qt_id.ts
Normal file
1820
pcmanfm/translations/pcmanfm-qt_id.ts
Normal file
File diff suppressed because it is too large
Load Diff
1807
pcmanfm/translations/pcmanfm-qt_it.ts
Normal file
1807
pcmanfm/translations/pcmanfm-qt_it.ts
Normal file
File diff suppressed because it is too large
Load Diff
4
pcmanfm/translations/pcmanfm-qt_ja.desktop
Normal file
4
pcmanfm/translations/pcmanfm-qt_ja.desktop
Normal file
@ -0,0 +1,4 @@
|
||||
#Translations
|
||||
Name[ja]=PCManFM-Qt ファイルマネージャ
|
||||
GenericName[ja]=ファイルマネージャ
|
||||
Comment[ja]=LXQt環境のファイル管理をします
|
1801
pcmanfm/translations/pcmanfm-qt_ja.ts
Normal file
1801
pcmanfm/translations/pcmanfm-qt_ja.ts
Normal file
File diff suppressed because it is too large
Load Diff
1825
pcmanfm/translations/pcmanfm-qt_lt.ts
Normal file
1825
pcmanfm/translations/pcmanfm-qt_lt.ts
Normal file
File diff suppressed because it is too large
Load Diff
1800
pcmanfm/translations/pcmanfm-qt_nb_NO.ts
Normal file
1800
pcmanfm/translations/pcmanfm-qt_nb_NO.ts
Normal file
File diff suppressed because it is too large
Load Diff
1821
pcmanfm/translations/pcmanfm-qt_nl.ts
Normal file
1821
pcmanfm/translations/pcmanfm-qt_nl.ts
Normal file
File diff suppressed because it is too large
Load Diff
1826
pcmanfm/translations/pcmanfm-qt_pl.ts
Normal file
1826
pcmanfm/translations/pcmanfm-qt_pl.ts
Normal file
File diff suppressed because it is too large
Load Diff
1822
pcmanfm/translations/pcmanfm-qt_pt.ts
Normal file
1822
pcmanfm/translations/pcmanfm-qt_pt.ts
Normal file
File diff suppressed because it is too large
Load Diff
1823
pcmanfm/translations/pcmanfm-qt_pt_BR.ts
Normal file
1823
pcmanfm/translations/pcmanfm-qt_pt_BR.ts
Normal file
File diff suppressed because it is too large
Load Diff
1826
pcmanfm/translations/pcmanfm-qt_ru.ts
Normal file
1826
pcmanfm/translations/pcmanfm-qt_ru.ts
Normal file
File diff suppressed because it is too large
Load Diff
1817
pcmanfm/translations/pcmanfm-qt_tr.ts
Normal file
1817
pcmanfm/translations/pcmanfm-qt_tr.ts
Normal file
File diff suppressed because it is too large
Load Diff
1826
pcmanfm/translations/pcmanfm-qt_uk.ts
Normal file
1826
pcmanfm/translations/pcmanfm-qt_uk.ts
Normal file
File diff suppressed because it is too large
Load Diff
1799
pcmanfm/translations/pcmanfm-qt_zh_CN.ts
Normal file
1799
pcmanfm/translations/pcmanfm-qt_zh_CN.ts
Normal file
File diff suppressed because it is too large
Load Diff
1817
pcmanfm/translations/pcmanfm-qt_zh_TW.ts
Normal file
1817
pcmanfm/translations/pcmanfm-qt_zh_TW.ts
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user