diff --git a/debian/changelog b/debian/changelog index 193db67..cace6d4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,10 +1,24 @@ +pcmanfm-qt (0.9.0+20150925-1) experimental; urgency=medium + + * Cherry-picked upstream version 0.9.0+20150925. + * Fixed source/options - no need to ignore .kdev4, fixed upstream + * Changed symbols + - put the arch bit at the end and comment them + - put the new search symbols before the arch bits - they need a review + * Fixed the copied pdmanfm menu file + * Fixed rules --fail-missing is enough and will list missed files + * Switched to experimental because of LXQt namespace change + * Added minimum version for liblxqt0-dev (>= 0.9.0+20150911) + + -- Alf Gaida Fri, 25 Sep 2015 22:12:50 +0200 + pcmanfm-qt (0.9.0+20150908-1) unstable; urgency=medium [ Alf Gaida ] * Cherry-picked upstream version 0.9.0+20150908. * Tar-ignore .gitignore * Fixed control with cme fix - * Added upstream signing-key and use it in watch file + * Added upstream signing-key and use it in watch file * Removed automoc build dependency - not needed with Qt5 * Fixed symbols for i386 and amd64 diff --git a/debian/control b/debian/control index d4ce23f..4a1608b 100644 --- a/debian/control +++ b/debian/control @@ -10,7 +10,7 @@ Build-Depends: cmake (>= 3.0.2), debhelper (>= 9), libfm-dev (>= 1.2.0), libglib2.0-dev, - liblxqt0-dev, + liblxqt0-dev (>= 0.9.0+20150911), libmenu-cache-dev, libqt5x11extras5-dev, libqt5xdg-dev, diff --git a/debian/libfm-qt5-2.symbols b/debian/libfm-qt5-2.symbols index c2ae035..d3f237c 100644 --- a/debian/libfm-qt5-2.symbols +++ b/debian/libfm-qt5-2.symbols @@ -1,8 +1,4 @@ libfm-qt5.so.2 libfm-qt5-2 #MINVER# - (arch-bits=32|c++)"Fm::MountOperation::onShowUnmountProgress(_GMountOperation*, char*, long long, long long, Fm::MountOperation*)@Base" 0.9.0+20150903 - (arch-bits=32|c++)"Fm::ThumbnailLoader::readImageFromStream(_GInputStream*, unsigned long long, _GCancellable*)@Base" 0.9.0+20150903 - (arch-bits=64|c++)"Fm::MountOperation::onShowUnmountProgress(_GMountOperation*, char*, long, long, Fm::MountOperation*)@Base" 0.9.0+20150903 - (arch-bits=64|c++)"Fm::ThumbnailLoader::readImageFromStream(_GInputStream*, unsigned long, _GCancellable*)@Base" 0.9.0+20150903 (c++)"Fm::AppChooserComboBox::~AppChooserComboBox()@Base" 0.9.0+20150903 (c++)"Fm::AppChooserComboBox::AppChooserComboBox(QWidget*)@Base" 0.9.0+20150903 (c++)"Fm::AppChooserComboBox::isChanged()@Base" 0.9.0+20150903 @@ -101,8 +97,6 @@ libfm-qt5.so.2 libfm-qt5-2 #MINVER# (c++)"Fm::DirTreeModelItem::childFromPath(_FmPath*, bool) const@Base" 0.9.0+20150903 (c++)"Fm::DirTreeModelItem::~DirTreeModelItem()@Base" 0.9.0+20150903 (c++)"Fm::DirTreeModelItem::DirTreeModelItem()@Base" 0.9.0+20150903 - (c++)"Fm::DirTreeModelItem::DirTreeModelItem()@Base" 0.9.0+20150903 - (c++)"Fm::DirTreeModelItem::DirTreeModelItem(_FmFileInfo*, Fm::DirTreeModel*, Fm::DirTreeModelItem*)@Base" 0.9.0+20150903 (c++)"Fm::DirTreeModelItem::DirTreeModelItem(_FmFileInfo*, Fm::DirTreeModel*, Fm::DirTreeModelItem*)@Base" 0.9.0+20150903 (c++)"Fm::DirTreeModelItem::freeFolder()@Base" 0.9.0+20150903 (c++)"Fm::DirTreeModel::itemFromIndex(QModelIndex const&) const@Base" 0.9.0+20150903 @@ -178,8 +172,6 @@ libfm-qt5.so.2 libfm-qt5-2 #MINVER# (c++)"Fm::FileMenu::createMenu(_FmFileInfoList*, _FmFileInfo*, _FmPath*)@Base" 0.9.0+20150903 (c++)"Fm::FileMenu::~FileMenu()@Base" 0.9.0+20150903 (c++)"Fm::FileMenu::FileMenu(_FmFileInfoList*, _FmFileInfo*, _FmPath*, QString const&, QWidget*)@Base" 0.9.0+20150903 - (c++)"Fm::FileMenu::FileMenu(_FmFileInfoList*, _FmFileInfo*, _FmPath*, QString const&, QWidget*)@Base" 0.9.0+20150903 - (c++)"Fm::FileMenu::FileMenu(_FmFileInfoList*, _FmFileInfo*, _FmPath*, QWidget*)@Base" 0.9.0+20150903 (c++)"Fm::FileMenu::FileMenu(_FmFileInfoList*, _FmFileInfo*, _FmPath*, QWidget*)@Base" 0.9.0+20150903 (c++)"Fm::FileMenu::metaObject() const@Base" 0.9.0+20150903 (c++)"Fm::FileMenu::onApplicationTriggered()@Base" 0.9.0+20150903 @@ -257,6 +249,11 @@ libfm-qt5.so.2 libfm-qt5-2 #MINVER# (c++)"Fm::FilePropsDialog::qt_metacall(QMetaObject::Call, int, void**)@Base" 0.9.0+20150903 (c++)"Fm::FilePropsDialog::qt_metacast(char const*)@Base" 0.9.0+20150903 (c++)"Fm::FilePropsDialog::staticMetaObject@Base" 0.9.0+20150903 + (c++)"Fm::FileSearchDialog::accept()@Base" 0.9.0+20150925 + (c++)"Fm::FileSearchDialog::~FileSearchDialog()@Base" 0.9.0+20150925 + (c++)"Fm::FileSearchDialog::FileSearchDialog(QStringList, QWidget*, QFlags)@Base" 0.9.0+20150925 + (c++)"Fm::FileSearchDialog::onAddPath()@Base" 0.9.0+20150925 + (c++)"Fm::FileSearchDialog::onRemovePath()@Base" 0.9.0+20150925 (c++)"Fm::FolderItemDelegate::drawText(QPainter*, QStyleOptionViewItem&, QRectF&) const@Base" 0.9.0+20150903 (c++)"Fm::FolderItemDelegate::~FolderItemDelegate()@Base" 0.9.0+20150903 (c++)"Fm::FolderItemDelegate::FolderItemDelegate(QAbstractItemView*, QObject*)@Base" 0.9.0+20150903 @@ -301,8 +298,6 @@ libfm-qt5.so.2 libfm-qt5-2 #MINVER# (c++)"Fm::FolderModelItem::findThumbnail(int)@Base" 0.9.0+20150903 (c++)"Fm::FolderModelItem::~FolderModelItem()@Base" 0.9.0+20150903 (c++)"Fm::FolderModelItem::FolderModelItem(_FmFileInfo*)@Base" 0.9.0+20150903 - (c++)"Fm::FolderModelItem::FolderModelItem(_FmFileInfo*)@Base" 0.9.0+20150903 - (c++)"Fm::FolderModelItem::FolderModelItem(Fm::FolderModelItem const&)@Base" 0.9.0+20150903 (c++)"Fm::FolderModelItem::FolderModelItem(Fm::FolderModelItem const&)@Base" 0.9.0+20150903 (c++)"Fm::FolderModel::itemFromIndex(QModelIndex const&) const@Base" 0.9.0+20150903 (c++)"Fm::FolderModelItem::removeThumbnail(int)@Base" 0.9.0+20150903 @@ -446,12 +441,8 @@ libfm-qt5.so.2 libfm-qt5-2 #MINVER# (c++)"Fm::PlacesModel::itemFromVolume(_GVolume*)@Base" 0.9.0+20150903 (c++)"Fm::PlacesModelItem::~PlacesModelItem()@Base" 0.9.0+20150903 (c++)"Fm::PlacesModelItem::PlacesModelItem()@Base" 0.9.0+20150903 - (c++)"Fm::PlacesModelItem::PlacesModelItem()@Base" 0.9.0+20150903 - (c++)"Fm::PlacesModelItem::PlacesModelItem(char const*, QString, _FmPath*)@Base" 0.9.0+20150903 (c++)"Fm::PlacesModelItem::PlacesModelItem(char const*, QString, _FmPath*)@Base" 0.9.0+20150903 (c++)"Fm::PlacesModelItem::PlacesModelItem(_FmIcon*, QString, _FmPath*)@Base" 0.9.0+20150903 - (c++)"Fm::PlacesModelItem::PlacesModelItem(_FmIcon*, QString, _FmPath*)@Base" 0.9.0+20150903 - (c++)"Fm::PlacesModelItem::PlacesModelItem(QIcon, QString, _FmPath*)@Base" 0.9.0+20150903 (c++)"Fm::PlacesModelItem::PlacesModelItem(QIcon, QString, _FmPath*)@Base" 0.9.0+20150903 (c++)"Fm::PlacesModelItem::setFileInfo(_FmFileInfo*)@Base" 0.9.0+20150903 (c++)"Fm::PlacesModelItem::setIcon(_FmIcon*)@Base" 0.9.0+20150903 @@ -596,6 +587,7 @@ libfm-qt5.so.2 libfm-qt5-2 #MINVER# (c++)"non-virtual thunk to Fm::FileMenu::~FileMenu()@Base" 0.9.0+20150903 (c++)"non-virtual thunk to Fm::FileOperationDialog::~FileOperationDialog()@Base" 0.9.0+20150903 (c++)"non-virtual thunk to Fm::FilePropsDialog::~FilePropsDialog()@Base" 0.9.0+20150903 + (c++)"non-virtual thunk to Fm::FileSearchDialog::~FileSearchDialog()@Base" 0.9.0+20150925 (c++)"non-virtual thunk to Fm::FolderMenu::~FolderMenu()@Base" 0.9.0+20150903 (c++)"non-virtual thunk to Fm::FolderView::~FolderView()@Base" 0.9.0+20150903 (c++)"non-virtual thunk to Fm::FontButton::~FontButton()@Base" 0.9.0+20150903 @@ -619,6 +611,7 @@ libfm-qt5.so.2 libfm-qt5-2 #MINVER# (c++)"typeinfo for Fm::FileOperation@Base" 0.9.0+20150903 (c++)"typeinfo for Fm::FileOperationDialog@Base" 0.9.0+20150903 (c++)"typeinfo for Fm::FilePropsDialog@Base" 0.9.0+20150903 + (c++)"typeinfo for Fm::FileSearchDialog@Base" 0.9.0+20150925 (c++)"typeinfo for Fm::FolderItemDelegate@Base" 0.9.0+20150903 (c++)"typeinfo for Fm::FolderMenu@Base" 0.9.0+20150903 (c++)"typeinfo for Fm::FolderModel@Base" 0.9.0+20150903 @@ -655,6 +648,7 @@ libfm-qt5.so.2 libfm-qt5-2 #MINVER# (c++)"typeinfo name for Fm::FileOperation@Base" 0.9.0+20150903 (c++)"typeinfo name for Fm::FileOperationDialog@Base" 0.9.0+20150903 (c++)"typeinfo name for Fm::FilePropsDialog@Base" 0.9.0+20150903 + (c++)"typeinfo name for Fm::FileSearchDialog@Base" 0.9.0+20150925 (c++)"typeinfo name for Fm::FolderItemDelegate@Base" 0.9.0+20150903 (c++)"typeinfo name for Fm::FolderMenu@Base" 0.9.0+20150903 (c++)"typeinfo name for Fm::FolderModel@Base" 0.9.0+20150903 @@ -691,6 +685,7 @@ libfm-qt5.so.2 libfm-qt5-2 #MINVER# (c++)"vtable for Fm::FileOperation@Base" 0.9.0+20150903 (c++)"vtable for Fm::FileOperationDialog@Base" 0.9.0+20150903 (c++)"vtable for Fm::FilePropsDialog@Base" 0.9.0+20150903 + (c++)"vtable for Fm::FileSearchDialog@Base" 0.9.0+20150925 (c++)"vtable for Fm::FolderItemDelegate@Base" 0.9.0+20150903 (c++)"vtable for Fm::FolderMenu@Base" 0.9.0+20150903 (c++)"vtable for Fm::FolderModel@Base" 0.9.0+20150903 @@ -712,3 +707,45 @@ libfm-qt5.so.2 libfm-qt5-2 #MINVER# (c++)"vtable for Fm::SidePane@Base" 0.9.0+20150903 (c++)"vtable for Fm::ThumbnailLoader@Base" 0.9.0+20150903 +## some new symbols i dont know + fm_search_add_dir@Base 0.9.0+20150925 + fm_search_add_mime_type@Base 0.9.0+20150925 + fm_search_dup_path@Base 0.9.0+20150925 + fm_search_free@Base 0.9.0+20150925 + fm_search_get_content_ci@Base 0.9.0+20150925 + fm_search_get_content_pattern@Base 0.9.0+20150925 + fm_search_get_content_regex@Base 0.9.0+20150925 + fm_search_get_dirs@Base 0.9.0+20150925 + fm_search_get_max_mtime@Base 0.9.0+20150925 + fm_search_get_max_size@Base 0.9.0+20150925 + fm_search_get_mime_types@Base 0.9.0+20150925 + fm_search_get_min_mtime@Base 0.9.0+20150925 + fm_search_get_min_size@Base 0.9.0+20150925 + fm_search_get_name_ci@Base 0.9.0+20150925 + fm_search_get_name_patterns@Base 0.9.0+20150925 + fm_search_get_name_regex@Base 0.9.0+20150925 + fm_search_get_recursive@Base 0.9.0+20150925 + fm_search_get_show_hidden@Base 0.9.0+20150925 + fm_search_new@Base 0.9.0+20150925 + fm_search_remove_dir@Base 0.9.0+20150925 + fm_search_remove_mime_type@Base 0.9.0+20150925 + fm_search_set_content_ci@Base 0.9.0+20150925 + fm_search_set_content_pattern@Base 0.9.0+20150925 + fm_search_set_content_regex@Base 0.9.0+20150925 + fm_search_set_max_mtime@Base 0.9.0+20150925 + fm_search_set_max_size@Base 0.9.0+20150925 + fm_search_set_min_mtime@Base 0.9.0+20150925 + fm_search_set_min_size@Base 0.9.0+20150925 + fm_search_set_name_ci@Base 0.9.0+20150925 + fm_search_set_name_patterns@Base 0.9.0+20150925 + fm_search_set_name_regex@Base 0.9.0+20150925 + fm_search_set_recursive@Base 0.9.0+20150925 + fm_search_set_show_hidden@Base 0.9.0+20150925 + +## arch-bits for 32 bit + (arch-bits=32|c++)"Fm::MountOperation::onShowUnmountProgress(_GMountOperation*, char*, long long, long long, Fm::MountOperation*)@Base" 0.9.0+20150903 + (arch-bits=32|c++)"Fm::ThumbnailLoader::readImageFromStream(_GInputStream*, unsigned long long, _GCancellable*)@Base" 0.9.0+20150903 + +## arch-bits for 64 bit + (arch-bits=64|c++)"Fm::MountOperation::onShowUnmountProgress(_GMountOperation*, char*, long, long, Fm::MountOperation*)@Base" 0.9.0+20150903 + (arch-bits=64|c++)"Fm::ThumbnailLoader::readImageFromStream(_GInputStream*, unsigned long, _GCancellable*)@Base" 0.9.0+20150903 diff --git a/debian/pcmanfm.menu b/debian/pcmanfm.menu index 9783ad0..ac2fafa 100644 --- a/debian/pcmanfm.menu +++ b/debian/pcmanfm.menu @@ -1,4 +1,4 @@ -?package(pcmanfm):needs="X11" section="Applications/File Management"\ - title="PCManFM" longtitle="Real Tabbed File Manager"\ - description="PCMan File Manager is an extremely fast and lightweight GTK+ based file manager."\ - command="/usr/bin/pcmanfm" hints="File manager" +?package(pcmanfm-qt):needs="X11" section="Applications/File Management"\ + title="PCManFM-Qt" longtitle="Real Tabbed File Manager"\ + description="PCMan File Manager is an extremely fast and lightweight Qt based file manager."\ + command="/usr/bin/pcmanfm-qt" hints="File manager" diff --git a/debian/rules b/debian/rules index d618ab5..f63bd01 100755 --- a/debian/rules +++ b/debian/rules @@ -8,7 +8,7 @@ export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed dh ${@} --buildsystem cmake --parallel override_dh_install: - dh_install --exclude=pcmanfm-qt.1 --fail-missing --list-missing + dh_install --exclude=pcmanfm-qt.1 --fail-missing override_dh_strip: dh_strip -ppcmanfm-qt --dbg-package=pcmanfm-qt-dbg diff --git a/debian/source/options b/debian/source/options index 293c310..efee896 100644 --- a/debian/source/options +++ b/debian/source/options @@ -1,2 +1 @@ tar-ignore = .gitignore -tar-ignore = pcmanfm-qt.kdev4 diff --git a/libfm-qt/CMakeLists.txt b/libfm-qt/CMakeLists.txt index 84c8049..c0cbc1e 100644 --- a/libfm-qt/CMakeLists.txt +++ b/libfm-qt/CMakeLists.txt @@ -63,6 +63,8 @@ set(libfm_SRCS appchoosercombobox.cpp appmenuview.cpp appchooserdialog.cpp + filesearchdialog.cpp + fm-search.c # might be moved to libfm later ) set(libfm_UIS @@ -73,6 +75,7 @@ set(libfm_UIS edit-bookmarks.ui exec-file.ui app-chooser-dialog.ui + filesearch.ui ) qt5_wrap_ui(libfm_UIS_H ${libfm_UIS}) diff --git a/libfm-qt/filemenu.cpp b/libfm-qt/filemenu.cpp index 9dbe7e0..15dcb38 100644 --- a/libfm-qt/filemenu.cpp +++ b/libfm-qt/filemenu.cpp @@ -62,6 +62,19 @@ void FileMenu::createMenu(FmFileInfoList* files, FmFileInfo* info, FmPath* cwd) confirmDelete_ = true; confirmTrash_ = false; // Confirm before moving files into "trash can" + openAction_ = NULL; + openWithMenuAction_ = NULL; + openWithAction_ = NULL; + separator1_ = NULL; + cutAction_ = NULL; + copyAction_ = NULL; + pasteAction_ = NULL; + deleteAction_ = NULL; + unTrashAction_ = NULL; + renameAction_ = NULL; + separator2_ = NULL; + propertiesAction_ = NULL; + files_ = fm_file_info_list_ref(files); info_ = info ? fm_file_info_ref(info) : NULL; cwd_ = cwd ? fm_path_ref(cwd) : NULL; @@ -346,8 +359,10 @@ void FileMenu::onRenameTriggered() { void FileMenu::setUseTrash(bool trash) { if(useTrash_ != trash) { useTrash_ = trash; - deleteAction_->setText(useTrash_ ? tr("&Move to Trash") : tr("&Delete")); - deleteAction_->setIcon(useTrash_ ? QIcon::fromTheme("user-trash") : QIcon::fromTheme("edit-delete")); + if(deleteAction_) { + deleteAction_->setText(useTrash_ ? tr("&Move to Trash") : tr("&Delete")); + deleteAction_->setIcon(useTrash_ ? QIcon::fromTheme("user-trash") : QIcon::fromTheme("edit-delete")); + } } } diff --git a/libfm-qt/filesearch.ui b/libfm-qt/filesearch.ui new file mode 100644 index 0000000..f5f6051 --- /dev/null +++ b/libfm-qt/filesearch.ui @@ -0,0 +1,449 @@ + + + SearchDialog + + + + 0 + 0 + 512 + 420 + + + + Search Files + + + + + + + + + + + 0 + + + + Name/Location + + + + + + File Name Patterns: + + + + + + * + + + + + + + Case insensitive + + + + + + + Use regular expression + + + + + + + + + + Places to Search: + + + + + + + + + + + + + &Add + + + + + + + + + + + + &Remove + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Search in sub directories + + + + + + + Search for hidden files + + + + + + + + + + + File Type + + + + + + Only search for files of following types: + + + + + + Text files + + + + + + + Image files + + + + + + + Audio files + + + + + + + Video files + + + + + + + Documents + + + + + + + Folders + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Content + + + + + + File contains: + + + + + + + + + Case insensiti&ve + + + + + + + &Use regular expression + + + + + + + + + + Qt::Vertical + + + + 20 + 186 + + + + + + + + + Properties + + + + + + File Size: + + + + + + Larger than: + + + + + + + + + + + + 2 + + + + Bytes + + + + + KiB + + + + + MiB + + + + + GiB + + + + + + + + + + Smaller than: + + + + + + + + + + + + 2 + + + + Bytes + + + + + KiB + + + + + MiB + + + + + GiB + + + + + + + + + + + + + Last Modified Time: + + + + + + Earlier than: + + + + + + + Later than: + + + + + + + true + + + + + + + true + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SearchDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SearchDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/libfm-qt/filesearchdialog.cpp b/libfm-qt/filesearchdialog.cpp new file mode 100644 index 0000000..eeaeaa3 --- /dev/null +++ b/libfm-qt/filesearchdialog.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2015 Hong Jen Yee (PCMan) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "filesearchdialog.h" +#include +#include "fm-search.h" +#include "ui_filesearch.h" +#include +#include + +namespace Fm { + +FileSearchDialog::FileSearchDialog(QStringList paths, QWidget* parent, Qt::WindowFlags f): + QDialog(parent, f), + ui(new Ui::SearchDialog()) { + ui->setupUi(this); + ui->minSize->setMaximum(std::numeric_limits().max()); + ui->maxSize->setMaximum(std::numeric_limits().max()); + Q_FOREACH(const QString& path, paths) { + ui->listView->addItem(path); + } + + ui->maxTime->setDate(QDate::currentDate()); + ui->minTime->setDate(QDate::currentDate()); + + connect(ui->addPath, &QPushButton::clicked, this, &FileSearchDialog::onAddPath); + connect(ui->removePath, &QPushButton::clicked, this, &FileSearchDialog::onRemovePath); +} + +FileSearchDialog::~FileSearchDialog() { + delete ui; +} + +void FileSearchDialog::accept() { + // build the search:/// uri + int n = ui->listView->count(); + if(n > 0) { + FmSearch* search = fm_search_new(); + int i; + for(i = 0; i < n; ++i) { // add directories + QListWidgetItem* item = ui->listView->item(i); + fm_search_add_dir(search, item->text().toLocal8Bit().constData()); + } + + fm_search_set_recursive(search, ui->recursiveSearch->isChecked()); + fm_search_set_show_hidden(search, ui->searchHidden->isChecked()); + fm_search_set_name_patterns(search, ui->namePatterns->text().toUtf8().constData()); + fm_search_set_name_ci(search, ui->nameCaseInsensitive->isChecked()); + fm_search_set_name_regex(search, ui->nameRegExp->isChecked()); + + fm_search_set_content_pattern(search, ui->contentPattern->text().toUtf8().constData()); + fm_search_set_content_ci(search, ui->contentCaseInsensitive->isChecked()); + fm_search_set_content_regex(search, ui->contentRegExp->isChecked()); + + // search for the files of specific mime-types + if(ui->searchTextFiles->isChecked()) + fm_search_add_mime_type(search, "text/plain"); + if(ui->searchImages->isChecked()) + fm_search_add_mime_type(search, "image/*"); + if(ui->searchAudio->isChecked()) + fm_search_add_mime_type(search, "audio/*"); + if(ui->searchVideo->isChecked()) + fm_search_add_mime_type(search, "video/*"); + if(ui->searchFolders->isChecked()) + fm_search_add_mime_type(search, "inode/directory"); + if(ui->searchDocuments->isChecked()) { + const char* doc_types[] = { + "application/pdf", + /* "text/html;" */ + "application/vnd.oasis.opendocument.*", + "application/vnd.openxmlformats-officedocument.*", + "application/msword;application/vnd.ms-word", + "application/msexcel;application/vnd.ms-excel" + }; + for(i = 0; i < sizeof(doc_types)/sizeof(char*); ++i) + fm_search_add_mime_type(search, doc_types[i]); + } + + // search based on file size + const unsigned int unit_bytes[] = {1, (1024), (1024*1024), (1024*1024*1024)}; + if(ui->largerThan->isChecked()) { + guint64 size = ui->minSize->value() * unit_bytes[ui->minSizeUnit->currentIndex()]; + fm_search_set_min_size(search, size); + } + + if(ui->smallerThan->isChecked()) { + guint64 size = ui->maxSize->value() * unit_bytes[ui->maxSizeUnit->currentIndex()]; + fm_search_set_min_size(search, size); + } + + // search based on file mtime (we only support date in YYYY-MM-DD format) + if(ui->earlierThan->isChecked()) { + fm_search_set_max_mtime(search, ui->maxTime->date().toString(QStringLiteral("yyyy-MM-dd")).toUtf8().constData()); + } + if(ui->laterThan->isChecked()) { + fm_search_set_min_mtime(search, ui->minTime->date().toString(QStringLiteral("yyyy-MM-dd")).toUtf8().constData()); + } + + searchUri_.take(fm_search_dup_path(search)); + + fm_search_free(search); + } + else { + QMessageBox::critical(this, tr("Error"), tr("You should add at least add one directory to search.")); + return; + } + QDialog::accept(); +} + +void FileSearchDialog::onAddPath() { + QString dir = QFileDialog::getExistingDirectory(this, tr("Select a folder")); + if(dir.isEmpty()) + return; + // avoid adding duplicated items + if(ui->listView->findItems(dir, Qt::MatchFixedString|Qt::MatchCaseSensitive).isEmpty()) { + ui->listView->addItem(dir); + } +} + +void FileSearchDialog::onRemovePath() { + // remove selected items + Q_FOREACH(QListWidgetItem* item, ui->listView->selectedItems()) { + delete item; + } +} + +} diff --git a/libfm-qt/filesearchdialog.h b/libfm-qt/filesearchdialog.h new file mode 100644 index 0000000..dc6dc08 --- /dev/null +++ b/libfm-qt/filesearchdialog.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015 Hong Jen Yee (PCMan) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef FM_FILESEARCHDIALOG_H +#define FM_FILESEARCHDIALOG_H + +#include "libfmqtglobals.h" +#include +#include "path.h" + +namespace Ui { + class SearchDialog; +} + +namespace Fm { + +class LIBFM_QT_API FileSearchDialog : public QDialog +{ +public: + FileSearchDialog(QStringList paths = QStringList(), QWidget * parent = 0, Qt::WindowFlags f = 0); + ~FileSearchDialog(); + + Path searchUri() const { + return searchUri_; + } + + virtual void accept(); + +private Q_SLOTS: + void onAddPath(); + void onRemovePath(); + +private: + Ui::SearchDialog* ui; + Path searchUri_; +}; + +} + +#endif // FM_FILESEARCHDIALOG_H diff --git a/libfm-qt/fm-search.c b/libfm-qt/fm-search.c new file mode 100644 index 0000000..b8e26ca --- /dev/null +++ b/libfm-qt/fm-search.c @@ -0,0 +1,317 @@ +/* + * fm-search-uri.c + * + * Copyright 2015 Hong Jen Yee (PCMan) + * Copyright 2012-2014 Andriy Grytsenko (LStranger) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "fm-search.h" +#include + +struct _FmSearch +{ + gboolean recursive; + gboolean show_hidden; + char* name_patterns; + gboolean name_ci; + gboolean name_regex; + char* content_pattern; + gboolean content_ci; + gboolean content_regex; + GList* mime_types; + GList* search_path_list; + guint64 max_size; + guint64 min_size; + char* max_mtime; + char* min_mtime; +}; + +FmSearch* fm_search_new (void) +{ + FmSearch* search = (FmSearch*)g_slice_new0(FmSearch); + return search; +} + +void fm_search_free(FmSearch* search) +{ + g_list_free_full(search->mime_types, (GDestroyNotify)g_free); + g_list_free_full(search->search_path_list, (GDestroyNotify)g_free); + g_free(search->name_patterns); + g_free(search->content_pattern); + g_free(search->max_mtime); + g_free(search->min_mtime); + g_slice_free(FmSearch, search); +} + +gboolean fm_search_get_recursive(FmSearch* search) +{ + return search->recursive; +} + +void fm_search_set_recursive(FmSearch* search, gboolean recursive) +{ + search->recursive = recursive; +} + +gboolean fm_search_get_show_hidden(FmSearch* search) +{ + return search->show_hidden; +} + +void fm_search_set_show_hidden(FmSearch* search, gboolean show_hidden) +{ + search->show_hidden = show_hidden; +} + +const char* fm_search_get_name_patterns(FmSearch* search) +{ + return search->name_patterns; +} + +void fm_search_set_name_patterns(FmSearch* search, const char* name_patterns) +{ + g_free(search->name_patterns); + search->name_patterns = g_strdup(name_patterns); +} + +gboolean fm_search_get_name_ci(FmSearch* search) +{ + return search->name_ci; +} + +void fm_search_set_name_ci(FmSearch* search, gboolean name_ci) +{ + search->name_ci = name_ci; +} + +gboolean fm_search_get_name_regex(FmSearch* search) +{ + return search->name_regex; +} + +void fm_search_set_name_regex(FmSearch* search, gboolean name_regex) +{ + search->name_regex = name_regex; +} + +const char* fm_search_get_content_pattern(FmSearch* search) +{ + return search->content_pattern; +} + +void fm_search_set_content_pattern(FmSearch* search, const char* content_pattern) +{ + g_free(search->content_pattern); + search->content_pattern = g_strdup(content_pattern); +} + +gboolean fm_search_get_content_ci(FmSearch* search) +{ + return search->content_ci; +} + +void fm_search_set_content_ci(FmSearch* search, gboolean content_ci) +{ + search->content_ci = content_ci; +} + +gboolean fm_search_get_content_regex(FmSearch* search) +{ + return search->content_regex; +} + +void fm_search_set_content_regex(FmSearch* search, gboolean content_regex) +{ + search->content_regex = content_regex; +} + +void fm_search_add_dir(FmSearch* search, const char* dir) +{ + GList* l = g_list_find_custom(search->search_path_list, dir, (GCompareFunc)strcmp); + if(!l) + search->search_path_list = g_list_prepend(search->search_path_list, g_strdup(dir)); +} + +void fm_search_remove_dir(FmSearch* search, const char* dir) +{ + GList* l = g_list_find_custom(search->search_path_list, dir, (GCompareFunc)strcmp); + if(G_LIKELY(l)) + { + g_free(l->data); + search->search_path_list = g_list_delete_link(search->search_path_list, l); + } +} + +GList* fm_search_get_dirs(FmSearch* search) +{ + return search->search_path_list; +} + +void fm_search_add_mime_type(FmSearch* search, const char* mime_type) +{ + GList* l = g_list_find_custom(search->mime_types, mime_type, (GCompareFunc)strcmp); + if(!l) + search->mime_types = g_list_prepend(search->mime_types, g_strdup(mime_type)); +} + +void fm_search_remove_mime_type(FmSearch* search, const char* mime_type) +{ + GList* l = g_list_find_custom(search->mime_types, mime_type, (GCompareFunc)strcmp); + if(G_LIKELY(l)) + { + g_free(l->data); + search->mime_types = g_list_delete_link(search->mime_types, l); + } +} + +GList* fm_search_get_mime_types(FmSearch* search) +{ + return search->mime_types; +} + +guint64 fm_search_get_max_size(FmSearch* search) +{ + return search->max_size; +} + +void fm_search_set_max_size(FmSearch* search, guint64 size) +{ + search->max_size = size; +} + +guint64 fm_search_get_min_size(FmSearch* search) +{ + return search->min_size; +} + +void fm_search_set_min_size(FmSearch* search, guint64 size) +{ + search->min_size = size; +} + +/* format of mtime: YYYY-MM-DD */ +const char* fm_search_get_max_mtime(FmSearch* search) +{ + return search->max_mtime; +} + +void fm_search_set_max_mtime(FmSearch* search, const char* mtime) +{ + g_free(search->max_mtime); + search->max_mtime = g_strdup(mtime); +} + +/* format of mtime: YYYY-MM-DD */ +const char* fm_search_get_min_mtime(FmSearch* search) +{ + return search->min_mtime; +} + +void fm_search_set_min_mtime(FmSearch* search, const char* mtime) +{ + g_free(search->min_mtime); + search->min_mtime = g_strdup(mtime); +} + +/* really build the path */ +FmPath* fm_search_dup_path(FmSearch* search) +{ + FmPath* search_path = NULL; + GString* search_str = g_string_sized_new(1024); + /* build the search:// URI to perform the search */ + g_string_append(search_str, "search://"); + + if(search->search_path_list) /* we need to have at least one dir path */ + { + char *escaped; + /* add paths */ + GList* l; + for(l = search->search_path_list; ; ) + { + char *path_str = (char*)l->data; + /* escape possible '?' and ',' */ + escaped = g_uri_escape_string(path_str, "!$&'()*+:;=/@", TRUE); + g_string_append(search_str, escaped); + g_free(escaped); + + l = l->next; + if(!l) /* no more items */ + break; + g_string_append_c(search_str, ','); /* separator for paths */ + } + + g_string_append_c(search_str, '?'); + g_string_append_printf(search_str, "recursive=%c", search->recursive ? '1' : '0'); + g_string_append_printf(search_str, "&show_hidden=%c", search->show_hidden ? '1' : '0'); + if(search->name_patterns && *search->name_patterns) + { + /* escape ampersands in pattern */ + escaped = g_uri_escape_string(search->name_patterns, ":/?#[]@!$'()*+,;", TRUE); + if(search->name_regex) + g_string_append_printf(search_str, "&name_regex=%s", escaped); + else + g_string_append_printf(search_str, "&name=%s", escaped); + if(search->name_ci) + g_string_append_printf(search_str, "&name_ci=%c", search->name_ci ? '1' : '0'); + g_free(escaped); + } + + if(search->content_pattern && *search->content_pattern) + { + /* escape ampersands in pattern */ + escaped = g_uri_escape_string(search->content_pattern, ":/?#[]@!$'()*+,;^<>{}", TRUE); + if(search->content_regex) + g_string_append_printf(search_str, "&content_regex=%s", escaped); + else + g_string_append_printf(search_str, "&content=%s", escaped); + g_free(escaped); + if(search->content_ci) + g_string_append_printf(search_str, "&content_ci=%c", search->content_ci ? '1' : '0'); + } + + /* search for the files of specific mime-types */ + if(search->mime_types) + { + GList* l; + g_string_append(search_str, "&mime_types="); + for(l = search->mime_types; l; l=l->next) + { + const char* mime_type = (const char*)l->data; + g_string_append(search_str, mime_type); + if(l->next) + g_string_append_c(search_str, ';'); + } + } + + if(search->min_size) + g_string_append_printf(search_str, "&min_size=%llu", search->min_size); + + if(search->max_size) + g_string_append_printf(search_str, "&max_size=%llu", search->max_size); + + if(search->min_mtime) + g_string_append_printf(search_str, "&min_mtime=%s", search->min_mtime); + + if(search->max_mtime) + g_string_append_printf(search_str, "&max_mtime=%s", search->max_mtime); + + search_path = fm_path_new_for_uri(search_str->str); + g_string_free(search_str, TRUE); + } + return search_path; +} diff --git a/libfm-qt/fm-search.h b/libfm-qt/fm-search.h new file mode 100644 index 0000000..1ae397e --- /dev/null +++ b/libfm-qt/fm-search.h @@ -0,0 +1,88 @@ +/* + * fm-search-uri.h + * + * Copyright 2015 Hong Jen Yee (PCMan) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +/* FmSearch implements a tool used to generate a search:// URI used by libfm to search for files. + * This API might become part of libfm in the future. + */ + +#ifndef _FM_SEARCH_H_ +#define _FM_SEARCH_H_ + +#include + +G_BEGIN_DECLS + +typedef struct _FmSearch FmSearch; + +FmSearch* fm_search_new(void); +void fm_search_free(FmSearch* search); + +FmPath* fm_search_dup_path(FmSearch* search); + +gboolean fm_search_get_recursive(FmSearch* search); +void fm_search_set_recursive(FmSearch* search, gboolean recursive); + +gboolean fm_search_get_show_hidden(FmSearch* search); +void fm_search_set_show_hidden(FmSearch* search, gboolean show_hidden); + +const char* fm_search_get_name_patterns(FmSearch* search); +void fm_search_set_name_patterns(FmSearch* search, const char* name_patterns); + +gboolean fm_search_get_name_ci(FmSearch* search); +void fm_search_set_name_ci(FmSearch* search, gboolean name_ci); + +gboolean fm_search_get_name_regex(FmSearch* search); +void fm_search_set_name_regex(FmSearch* search, gboolean name_regex); + +const char* fm_search_get_content_pattern(FmSearch* search); +void fm_search_set_content_pattern(FmSearch* search, const char* content_pattern); + +gboolean fm_search_get_content_ci(FmSearch* search); +void fm_search_set_content_ci(FmSearch* search, gboolean content_ci); + +gboolean fm_search_get_content_regex(FmSearch* search); +void fm_search_set_content_regex(FmSearch* search, gboolean content_regex); + +void fm_search_add_dir(FmSearch* search, const char* dir); +void fm_search_remove_dir(FmSearch* search, const char* dir); +GList* fm_search_get_dirs(FmSearch* search); + +void fm_search_add_mime_type(FmSearch* search, const char* mime_type); +void fm_search_remove_mime_type(FmSearch* search, const char* mime_type); +GList* fm_search_get_mime_types(FmSearch* search); + +guint64 fm_search_get_max_size(FmSearch* search); +void fm_search_set_max_size(FmSearch* search, guint64 size); + +guint64 fm_search_get_min_size(FmSearch* search); +void fm_search_set_min_size(FmSearch* search, guint64 size); + +/* format of mtime: YYYY-MM-DD */ +const char* fm_search_get_max_mtime(FmSearch* search); +void fm_search_set_max_mtime(FmSearch* search, const char* mtime); + +/* format of mtime: YYYY-MM-DD */ +const char* fm_search_get_min_mtime(FmSearch* search); +void fm_search_set_min_mtime(FmSearch* search, const char* mtime); + +G_END_DECLS + +#endif /* _FM_SEARCH_H_ */ diff --git a/libfm-qt/path.h b/libfm-qt/path.h index de6b53c..06238f0 100644 --- a/libfm-qt/path.h +++ b/libfm-qt/path.h @@ -188,6 +188,12 @@ public: return fm_path_hash(data_); } + void take(FmPath* path) { // take the ownership of the "path" + if(data_) + fm_path_unref(data_); + data_ = path; + } + Path& operator = (const Path& other) { if(data_) fm_path_unref(data_); diff --git a/libfm-qt/placesview.cpp b/libfm-qt/placesview.cpp index fc2f99a..9ea93a9 100644 --- a/libfm-qt/placesview.cpp +++ b/libfm-qt/placesview.cpp @@ -322,6 +322,8 @@ void PlacesView::onEjectVolume() { void PlacesView::contextMenuEvent(QContextMenuEvent* event) { QModelIndex index = indexAt(event->pos()); if(index.isValid() && index.parent().isValid()) { + if(index.column() != 0) // the real item is at column 0 + index = index.sibling(index.row(), 0); QMenu* menu = new QMenu(this); QAction* action; PlacesModelItem* item = static_cast(model_->itemFromIndex(index)); diff --git a/libfm-qt/proxyfoldermodel.cpp b/libfm-qt/proxyfoldermodel.cpp index 963e870..ce815c6 100644 --- a/libfm-qt/proxyfoldermodel.cpp +++ b/libfm-qt/proxyfoldermodel.cpp @@ -118,6 +118,12 @@ bool ProxyFolderModel::lessThan(const QModelIndex& left, const QModelIndex& righ FmFileInfo* leftInfo = srcModel->fileInfoFromIndex(left); FmFileInfo* rightInfo = srcModel->fileInfoFromIndex(right); + if(Q_UNLIKELY(!leftInfo || !rightInfo)) { + // In theory, this should not happen, but it's safer to add the null check. + // This is reported in https://github.com/lxde/pcmanfm-qt/issues/205 + return false; + } + if(folderFirst_) { bool leftIsFolder = (bool)fm_file_info_is_dir(leftInfo); bool rightIsFolder = (bool)fm_file_info_is_dir(rightInfo); diff --git a/pcmanfm-qt.kdev4 b/pcmanfm-qt.kdev4 deleted file mode 100644 index 4588e29..0000000 --- a/pcmanfm-qt.kdev4 +++ /dev/null @@ -1,4 +0,0 @@ -[Project] -Manager=KDevCMakeManager -Name=pcmanfm-qt -VersionControl= diff --git a/pcmanfm/application.cpp b/pcmanfm/application.cpp index ffedfcd..0595b9d 100644 --- a/pcmanfm/application.cpp +++ b/pcmanfm/application.cpp @@ -42,6 +42,7 @@ #include "mountoperation.h" #include "autorundialog.h" #include "launcher.h" +#include "filesearchdialog.h" #include #include @@ -113,8 +114,8 @@ Application::~Application() { g_object_unref(volumeMonitor_); } - if(enableDesktopManager_) - removeNativeEventFilter(this); + // if(enableDesktopManager_) + // removeNativeEventFilter(this); } bool Application::parseCommandLineArgs() { @@ -311,7 +312,7 @@ void Application::desktopManager(bool enabled) { QDesktopWidget* desktopWidget = desktop(); if(enabled) { if(!enableDesktopManager_) { - installNativeEventFilter(this); + // installNativeEventFilter(this); Q_FOREACH(QScreen* screen, screens()) { connect(screen, &QScreen::virtualGeometryChanged, this, &Application::onVirtualGeometryChanged); connect(screen, &QObject::destroyed, this, &Application::onScreenDestroyed); @@ -352,7 +353,7 @@ void Application::desktopManager(bool enabled) { disconnect(screen, &QObject::destroyed, this, &Application::onScreenDestroyed); } disconnect(this, &QApplication::screenAdded, this, &Application::onScreenAdded); - removeNativeEventFilter(this); + // removeNativeEventFilter(this); } } enableDesktopManager_ = enabled; @@ -369,9 +370,22 @@ void Application::desktopPrefrences(QString page) { desktopPreferencesDialog_.data()->activateWindow(); } +void Application::onFindFileAccepted() { + Fm::FileSearchDialog* dlg = static_cast(sender()); + Fm::Path uri = dlg->searchUri(); + // FIXME: we should be able to open it in an existing window + FmPathList* paths = fm_path_list_new(); + fm_path_list_push_tail(paths, uri.data()); + Launcher(NULL).launchPaths(NULL, paths); + fm_path_list_unref(paths); +} + void Application::findFiles(QStringList paths) { - // TODO: add a file searching utility here. - qDebug("findFiles"); + // launch file searching utility. + Fm::FileSearchDialog* dlg = new Fm::FileSearchDialog(paths); + connect(dlg, &QDialog::accepted, this, &Application::onFindFileAccepted); + dlg->setAttribute(Qt::WA_DeleteOnClose); + dlg->show(); } void Application::launchFiles(QString cwd, QStringList paths, bool inNewWindow) { @@ -635,17 +649,18 @@ void Application::onVolumeAdded(GVolumeMonitor* monitor, GVolume* volume, Applic pThis->autoMountVolume(volume, true); } +#if 0 bool Application::nativeEventFilter(const QByteArray & eventType, void * message, long * result) { if(eventType == "xcb_generic_event_t") { // XCB event // filter all native X11 events (xcb) xcb_generic_event_t* generic_event = reinterpret_cast(message); // qDebug("XCB event: %d", generic_event->response_type & ~0x80); Q_FOREACH(DesktopWindow * window, desktopWindows_) { - window->xcbEvent(generic_event); } } return false; } +#endif void Application::onScreenAdded(QScreen* newScreen) { if(enableDesktopManager_) { diff --git a/pcmanfm/application.h b/pcmanfm/application.h index c0dc727..ccc80e4 100644 --- a/pcmanfm/application.h +++ b/pcmanfm/application.h @@ -25,7 +25,6 @@ #include "settings.h" #include "libfmqt.h" #include "editbookmarksdialog.h" -#include #include #include #include @@ -49,7 +48,7 @@ public: virtual int styleHint(StyleHint hint, const QStyleOption * option = 0, const QWidget * widget = 0, QStyleHintReturn * returnData = 0) const; }; -class Application : public QApplication, public QAbstractNativeEventFilter { +class Application : public QApplication { Q_OBJECT Q_PROPERTY(bool desktopManagerEnabled READ desktopManagerEnabled) @@ -75,7 +74,7 @@ public: void desktopPrefrences(QString page); void editBookmarks(); void desktopManager(bool enabled); - void findFiles(QStringList paths); + void findFiles(QStringList paths = QStringList()); bool desktopManagerEnabled() { return enableDesktopManager_; @@ -91,8 +90,6 @@ public: return profileName_; } - virtual bool nativeEventFilter(const QByteArray & eventType, void * message, long * result); - protected Q_SLOTS: void onAboutToQuit(); void onSigtermNotified(); @@ -108,6 +105,8 @@ protected Q_SLOTS: void onScreenAdded(QScreen* newScreen); void reloadDesktopsAsNeeded(); + void onFindFileAccepted(); + protected: virtual bool eventFilter(QObject* watched, QEvent* event); bool parseCommandLineArgs(); diff --git a/pcmanfm/desktop-preferences.ui b/pcmanfm/desktop-preferences.ui index 7182bd5..258cd95 100644 --- a/pcmanfm/desktop-preferences.ui +++ b/pcmanfm/desktop-preferences.ui @@ -6,8 +6,8 @@ 0 0 - 473 - 428 + 501 + 376 @@ -200,6 +200,19 @@ + + + + Qt::Vertical + + + + 20 + 10 + + + + diff --git a/pcmanfm/desktopwindow.cpp b/pcmanfm/desktopwindow.cpp index 8c3260e..effb80d 100644 --- a/pcmanfm/desktopwindow.cpp +++ b/pcmanfm/desktopwindow.cpp @@ -389,49 +389,6 @@ void DesktopWindow::prepareFolderMenu(Fm::FolderMenu* menu) { connect(action, &QAction::triggered, this, &DesktopWindow::onDesktopPreferences); } -void DesktopWindow::xcbEvent(xcb_generic_event_t* generic_event) { - int event_type = generic_event->response_type & ~0x80; - if(showWmMenu_) { - // If we want to show the desktop menus provided by the window manager instead of ours, - // we have to forward the mouse events we received to the root window. - switch(event_type) { - case XCB_BUTTON_PRESS: { - xcb_button_press_event_t* event = reinterpret_cast(generic_event); - if(event->event == effectiveWinId()) { - // check if the user click on blank area - QModelIndex index = listView_->indexAt(QPoint(event->event_x, event->event_y)); - if(!index.isValid()) { - xcb_ungrab_pointer(QX11Info::connection(), event->time); - // forward the event to the root window - xcb_button_press_event_t event2 = *event; - WId root = QX11Info::appRootWindow(QX11Info::appScreen()); - event2.event = root; - xcb_send_event(QX11Info::connection(), 0, root, XCB_EVENT_MASK_BUTTON_PRESS, (char*)&event2); - } - } - break; - } - case XCB_BUTTON_RELEASE: { - xcb_button_release_event_t* event = reinterpret_cast(generic_event); - if(event->event == effectiveWinId()) { - // check if the user click on blank area - QModelIndex index = listView_->indexAt(QPoint(event->event_x, event->event_y)); - if(!index.isValid()) { - // forward the event to the root window - xcb_button_release_event_t event2 = *event; - WId root = QX11Info::appRootWindow(QX11Info::appScreen()); - event2.event = root; - xcb_send_event(QX11Info::connection(), 0, root, XCB_EVENT_MASK_BUTTON_RELEASE, (char*)&event2); - } - } - break; - } - default: - break; - } - } -} - void DesktopWindow::onDesktopPreferences() { static_cast(qApp)->desktopPrefrences(QString()); } @@ -675,6 +632,69 @@ void DesktopWindow::onFilePropertiesActivated() { } } +static void forwardMouseEventToRoot(QMouseEvent* event) { + xcb_ungrab_pointer(QX11Info::connection(), event->timestamp()); + // forward the event to the root window + xcb_button_press_event_t xcb_event; + uint32_t mask = 0; + xcb_event.state = 0; + switch(event->type()) { + case QEvent::MouseButtonPress: + xcb_event.response_type = XCB_BUTTON_PRESS; + mask = XCB_EVENT_MASK_BUTTON_PRESS; + break; + case QEvent::MouseButtonRelease: + xcb_event.response_type = XCB_BUTTON_RELEASE; + mask = XCB_EVENT_MASK_BUTTON_RELEASE; + break; + default: + return; + } + + // convert Qt button to XCB button + switch(event->button()) { + case Qt::LeftButton: + xcb_event.detail = 1; + xcb_event.state |= XCB_BUTTON_MASK_1; + break; + case Qt::MiddleButton: + xcb_event.detail = 2; + xcb_event.state |= XCB_BUTTON_MASK_2; + break; + case Qt::RightButton: + xcb_event.detail = 3; + xcb_event.state |= XCB_BUTTON_MASK_3; + break; + default: + xcb_event.detail = 0; + } + + // convert Qt modifiers to XCB states + if(event->modifiers() & Qt::ShiftModifier) + xcb_event.state |= XCB_MOD_MASK_SHIFT; + if(event->modifiers() & Qt::ControlModifier) + xcb_event.state |= XCB_MOD_MASK_SHIFT; + if(event->modifiers() & Qt::AltModifier) + xcb_event.state |= XCB_MOD_MASK_1; + + xcb_event.sequence = 0; + xcb_event.time = event->timestamp(); + + WId root = QX11Info::appRootWindow(QX11Info::appScreen()); + xcb_event.event = root; + xcb_event.root = root; + xcb_event.child = 0; + + xcb_event.root_x = event->globalX(); + xcb_event.root_y = event->globalY(); + xcb_event.event_x = event->x(); + xcb_event.event_y = event->y(); + xcb_event.same_screen = 1; + + xcb_send_event(QX11Info::connection(), 0, root, mask, (char*)&xcb_event); + xcb_flush(QX11Info::connection()); +} + bool DesktopWindow::event(QEvent* event) { switch(event->type()) { @@ -721,6 +741,25 @@ bool DesktopWindow::eventFilter(QObject * watched, QEvent * event) { break; } } + else if(watched == listView_->viewport()) { + switch(event->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + if(showWmMenu_) { + QMouseEvent* e = static_cast(event); + // If we want to show the desktop menus provided by the window manager instead of ours, + // we have to forward the mouse events we received to the root window. + // check if the user click on blank area + QModelIndex index = listView_->indexAt(e->pos()); + if(!index.isValid() && e->button() != Qt::LeftButton) { + forwardMouseEventToRoot(e); + } + } + break; + default: + break; + } + } return false; } diff --git a/pcmanfm/desktopwindow.h b/pcmanfm/desktopwindow.h index f1ad12b..c28e322 100644 --- a/pcmanfm/desktopwindow.h +++ b/pcmanfm/desktopwindow.h @@ -66,8 +66,6 @@ public: void updateWallpaper(); void updateFromSettings(Settings& settings); - void xcbEvent(xcb_generic_event_t* generic_event); - void queueRelayout(int delay = 0); int screenNum() const { diff --git a/pcmanfm/file-search.ui b/pcmanfm/file-search.ui index a698eae..20dc03c 100644 --- a/pcmanfm/file-search.ui +++ b/pcmanfm/file-search.ui @@ -7,7 +7,7 @@ 0 0 431 - 359 + 416 @@ -76,7 +76,9 @@ Add - + + + @@ -86,7 +88,9 @@ Remove - + + + @@ -125,9 +129,6 @@ - buttonBox - groupBox - groupBox_2 @@ -256,7 +257,7 @@ File Size - + @@ -265,18 +266,22 @@ - - - false - - - - - - - false - - + + + + + false + + + + + + + false + + + + @@ -286,18 +291,22 @@ - - - false - - - - - - - false - - + + + + + false + + + + + + + false + + + + @@ -307,7 +316,7 @@ Last Modified Time - + @@ -315,6 +324,16 @@ + + + + false + + + true + + + @@ -332,16 +351,6 @@ - - - - false - - - true - - - diff --git a/pcmanfm/main-win.ui b/pcmanfm/main-win.ui index 13740b1..408c4a6 100644 --- a/pcmanfm/main-win.ui +++ b/pcmanfm/main-win.ui @@ -20,7 +20,16 @@ - + + 0 + + + 0 + + + 0 + + 0 @@ -67,7 +76,7 @@ 0 0 460 - 27 + 23 @@ -171,6 +180,7 @@ + @@ -227,7 +237,7 @@ - Home + &Home Alt+Home @@ -447,7 +457,7 @@ true - Ascending + &Ascending @@ -455,7 +465,7 @@ true - Descending + &Descending @@ -463,7 +473,7 @@ true - By File Name + &By File Name @@ -471,7 +481,7 @@ true - By Modification Time + By &Modification Time @@ -479,7 +489,7 @@ true - By File Type + By File &Type @@ -487,7 +497,7 @@ true - By Owner + By &Owner @@ -495,7 +505,7 @@ true - Folder First + &Folder First @@ -598,7 +608,7 @@ true - Case Sensitive + &Case Sensitive @@ -606,12 +616,12 @@ true - By File Size + By File &Size - Close Window + &Close Window @@ -639,10 +649,12 @@ - + + + - Folder + &Folder Ctrl+Shift+N @@ -650,15 +662,25 @@ - + + + - Blank File + &Blank File Ctrl+Alt+N + + + &Find Files + + + F3 + + diff --git a/pcmanfm/mainwindow.cpp b/pcmanfm/mainwindow.cpp index 19c22f9..1276d30 100644 --- a/pcmanfm/mainwindow.cpp +++ b/pcmanfm/mainwindow.cpp @@ -949,6 +949,25 @@ void MainWindow::on_actionOpenAsRoot_triggered() { } } +void MainWindow::on_actionFindFiles_triggered() { + Application* app = static_cast(qApp); + FmPathList* selectedPaths = currentPage()->selectedFilePaths(); + QStringList paths; + if(selectedPaths) { + for(GList* l = fm_path_list_peek_head_link(selectedPaths); l; l = l->next) { + // FIXME: is it ok to use display name here? + // This might be broken on filesystems with non-UTF-8 filenames. + Fm::Path path(FM_PATH(l->data)); + paths.append(path.displayName(false)); + } + fm_path_list_unref(selectedPaths); + } + else { + paths.append(currentPage()->pathName()); + } + app->findFiles(paths); +} + void MainWindow::on_actionOpenTerminal_triggered() { TabPage* page = currentPage(); if(page) { diff --git a/pcmanfm/mainwindow.h b/pcmanfm/mainwindow.h index 58b6aa6..a36ec93 100644 --- a/pcmanfm/mainwindow.h +++ b/pcmanfm/mainwindow.h @@ -109,6 +109,7 @@ protected Q_SLOTS: void on_actionOpenTerminal_triggered(); void on_actionOpenAsRoot_triggered(); + void on_actionFindFiles_triggered(); void on_actionAbout_triggered();