diff --git a/krusader/CMakeLists.txt b/krusader/CMakeLists.txt index 2dba1320..0ade19c5 100644 --- a/krusader/CMakeLists.txt +++ b/krusader/CMakeLists.txt @@ -1,132 +1,132 @@ include_directories(${KF5_INCLUDES_DIRS} ${QT_INCLUDES}) configure_file(krusaderversion.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/krusaderversion.h) add_subdirectory(ActionMan) add_subdirectory(Archive) add_subdirectory(BookMan) add_subdirectory(Dialogs) add_subdirectory(DiskUsage) add_subdirectory(FileSystem) add_subdirectory(Filter) add_subdirectory(GUI) add_subdirectory(Konfigurator) add_subdirectory(KViewer) add_subdirectory(JobMan) add_subdirectory(Locate) add_subdirectory(MountMan) add_subdirectory(Panel) add_subdirectory(Search) add_subdirectory(Splitter) add_subdirectory(UserAction) if(SYNCHRONIZER_ENABLED) add_subdirectory(Synchronizer) endif(SYNCHRONIZER_ENABLED) message(STATUS "${CMAKE_CURRENT_SOURCE_DIR}: skipped subdir $(KRJSDIR)") set(krusader_SRCS krglobal.cpp icon.cpp + filelisticon.cpp actionsbase.cpp tabactions.cpp kractions.cpp paneltabbar.cpp panelmanager.cpp krservices.cpp main.cpp krusaderview.cpp krusader.cpp krslots.cpp - kicons.cpp krdebuglogger.cpp ) file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/icons/*-apps-krusader_user.png") ecm_add_app_icon(krusader_SRCS ICONS ${ICONS_SRCS}) qt5_add_resources(krusader_RC_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/resources.qrc" ) add_executable(krusader ${krusader_SRCS} ${krusader_RC_SRCS}) target_link_libraries(krusader Panel PanelView BookMan Dialogs DiskUsage GUI Konfigurator KViewer MountMan FileSystem Search Splitter Locate UserAction ActionMan KViewer Filter Dialogs GUI Archive JobMan KF5::Notifications KF5::Parts KF5::WindowSystem Qt5::PrintSupport Qt5::Concurrent ) if(SYNCHRONIZER_ENABLED) target_link_libraries( krusader Synchronizer ) endif(SYNCHRONIZER_ENABLED) install(TARGETS krusader ${INSTALL_TARGETS_DEFAULT_ARGS}) install(PROGRAMS org.kde.krusader.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) install(FILES krusaderui.rc krusaderlisterui.rc krviewer.rc DESTINATION ${KXMLGUI_INSTALL_DIR}/krusader) install(FILES midnight_commander.color total_commander.color total_commander.keymap total_commander.keymap.info useraction_examples.xml layout.xml splash.png DESTINATION ${DATA_INSTALL_DIR}/krusader) install(FILES org.kde.krusader.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) ecm_install_icons(ICONS icons/16-apps-krusader_blue.png icons/16-apps-krusader_red.png icons/16-apps-krusader_root.png icons/16-apps-krusader_user.png icons/22-apps-krusader_blue.png icons/22-apps-krusader_red.png icons/22-apps-krusader_root.png icons/22-apps-krusader_shield.png icons/22-apps-krusader_user.png icons/32-apps-krusader_blue.png icons/32-apps-krusader_red.png icons/32-apps-krusader_root.png icons/32-apps-krusader_shield.png icons/32-apps-krusader_user.png icons/48-apps-krusader_blue.png icons/48-apps-krusader_red.png icons/48-apps-krusader_root.png icons/48-apps-krusader_shield.png icons/48-apps-krusader_user.png icons/64-apps-krusader_blue.png icons/64-apps-krusader_red.png icons/64-apps-krusader_root.png icons/64-apps-krusader_shield.png icons/64-apps-krusader_user.png icons/128-apps-krusader_root.png icons/128-apps-krusader_user.png DESTINATION ${ICON_INSTALL_DIR} ) diff --git a/krusader/Dialogs/krspwidgets.cpp b/krusader/Dialogs/krspwidgets.cpp index 19eb616b..ddcbafe9 100644 --- a/krusader/Dialogs/krspwidgets.cpp +++ b/krusader/Dialogs/krspwidgets.cpp @@ -1,261 +1,260 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * Copyright (C) 2000 Rafi Yanai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "krspwidgets.h" #include "../krglobal.h" #include "../icon.h" -#include "../kicons.h" #include "../Filter/filtertabs.h" #include "../GUI/krlistwidget.h" // QtCore #include // QtGui #include // QtWidgets #include #include #include #include #include #include // missing ? #include #include #include #include #include #include ///////////////////// initiation of the static members //////////////////////// QStringList KRSpWidgets::maskList; /////////////////////////////////////////////////////////////////////////////// KRSpWidgets::KRSpWidgets() { } KRQuery KRSpWidgets::getMask(QString caption, bool nameOnly, QWidget * parent) { if (!nameOnly) { return FilterTabs::getQuery(parent); } else { QPointer p = new KRMaskChoiceSub(parent); p->setWindowTitle(caption); p->exec(); QString selection = p->selection->currentText(); delete p; if (selection.isEmpty()) { return KRQuery(); } else { return KRQuery(selection); } } } /////////////////////////// newFTP //////////////////////////////////////// QUrl KRSpWidgets::newFTP() { QPointer p = new newFTPSub(); p->exec(); QString uri = p->url->currentText(); if (uri.isEmpty()) { delete p; return QUrl(); // empty url } QString protocol = p->prefix->currentText(); protocol.truncate(protocol.length() - 3); // remove the trailing :// QString username = p->username->text().simplified(); QString password = p->password->text().simplified(); int uriStart = uri.lastIndexOf('@'); /* lets the user enter user and password in the URI field */ if (uriStart != -1) { QString uriUser = uri.left(uriStart); QString uriPsw; uri = uri.mid(uriStart + 1); int pswStart = uriUser.indexOf(':'); /* getting the password name from the URL */ if (pswStart != -1) { uriPsw = uriUser.mid(pswStart + 1); uriUser = uriUser.left(pswStart); } if (!uriUser.isEmpty()) { /* handling the ftp proxy username and password also */ username = username.isEmpty() ? uriUser : username + '@' + uriUser; } if (!uriPsw.isEmpty()) { /* handling the ftp proxy username and password also */ password = password.isEmpty() ? uriPsw : password + '@' + uriPsw; } } QString host = uri; /* separating the hostname and path from the uri */ QString path; int pathStart = uri.indexOf("/"); if (pathStart != -1) { path = host.mid(pathStart); host = host.left(pathStart); } /* setting the parameters of the URL */ QUrl url; url.setScheme(protocol); url.setHost(host); url.setPath(path); if (protocol == "ftp" || protocol == "fish" || protocol == "sftp") { url.setPort(p->port->cleanText().toInt()); } if (!username.isEmpty()) { url.setUserName(username); } if (!password.isEmpty()) { url.setPassword(password); } delete p; return url; } newFTPSub::newFTPSub() : newFTPGUI(0) { url->setFocus(); setGeometry(krMainWindow->x() + krMainWindow->width() / 2 - width() / 2, krMainWindow->y() + krMainWindow->height() / 2 - height() / 2, width(), height()); } void newFTPSub::accept() { url->addToHistory(url->currentText()); // save the history and completion list when the history combo is // destroyed KConfigGroup group(krConfig, "Private"); QStringList list = url->completionObject()->items(); group.writeEntry("newFTP Completion list", list); list = url->historyItems(); group.writeEntry("newFTP History list", list); QString protocol = prefix->currentText(); group.writeEntry("newFTP Protocol", protocol); newFTPGUI::accept(); } void newFTPSub::reject() { url->lineEdit()->setText(""); newFTPGUI::reject(); } /////////////////////////// KRMaskChoiceSub /////////////////////////////// KRMaskChoiceSub::KRMaskChoiceSub(QWidget * parent) : KRMaskChoice(parent) { PixmapLabel1->setPixmap(Icon("edit-select").pixmap(32)); label->setText(i18n("Enter a selection:")); // the predefined selections list KConfigGroup group(krConfig, "Private"); QStringList lst = group.readEntry("Predefined Selections", QStringList()); if (lst.size() > 0) preSelections->addItems(lst); // the combo-box tweaks selection->setDuplicatesEnabled(false); selection->addItems(KRSpWidgets::maskList); selection->lineEdit()->setText("*"); selection->lineEdit()->selectAll(); selection->setFocus(); } void KRMaskChoiceSub::reject() { selection->clear(); KRMaskChoice::reject(); } void KRMaskChoiceSub::accept() { bool add = true; // make sure we don't have that already for (int i = 0; i != KRSpWidgets::maskList.count(); i++) if (KRSpWidgets::maskList[ i ].simplified() == selection->currentText().simplified()) { // break if we found one such as this add = false; break; } if (add) KRSpWidgets::maskList.insert(0, selection->currentText().toLocal8Bit()); // write down the predefined selections list QStringList list; for (int j = 0; j != preSelections->count(); j++) { QListWidgetItem *i = preSelections->item(j); list.append(i->text()); } KConfigGroup group(krConfig, "Private"); group.writeEntry("Predefined Selections", list); KRMaskChoice::accept(); } void KRMaskChoiceSub::addSelection() { QString temp = selection->currentText(); bool itemExists = false; // check if the selection already exists for (int j = 0; j != preSelections->count(); j++) { QListWidgetItem *i = preSelections->item(j); if (i->text() == temp) { itemExists = true; break; } } if (!temp.isEmpty() && !itemExists) { preSelections->addItem(selection->currentText()); preSelections->update(); } } void KRMaskChoiceSub::deleteSelection() { delete preSelections->currentItem(); preSelections->update(); } void KRMaskChoiceSub::clearSelections() { preSelections->clear(); preSelections->update(); } void KRMaskChoiceSub::acceptFromList(QListWidgetItem *i) { selection->addItem(i->text(), 0); accept(); } void KRMaskChoiceSub::currentItemChanged(QListWidgetItem *i) { if (i) selection->setEditText(i->text()); } diff --git a/krusader/DiskUsage/diskusage.cpp b/krusader/DiskUsage/diskusage.cpp index 530c4050..fa5a3d57 100644 --- a/krusader/DiskUsage/diskusage.cpp +++ b/krusader/DiskUsage/diskusage.cpp @@ -1,1133 +1,1133 @@ /***************************************************************************** * Copyright (C) 2004 Csaba Karai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "diskusage.h" // QtCore #include #include #include #include #include #include // QtGui #include #include #include #include #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dufilelight.h" #include "dulines.h" #include "dulistview.h" #include "filelightParts/Config.h" #include "../FileSystem/fileitem.h" #include "../FileSystem/filesystemprovider.h" #include "../FileSystem/krpermhandler.h" #include "../Panel/krpanel.h" #include "../Panel/panelfunc.h" #include "../defaults.h" -#include "../kicons.h" #include "../krglobal.h" +#include "../filelisticon.h" // these are the values that will exist in the menu #define DELETE_ID 90 #define EXCLUDE_ID 91 #define PARENT_DIR_ID 92 #define NEW_SEARCH_ID 93 #define REFRESH_ID 94 #define STEP_INTO_ID 95 #define INCLUDE_ALL_ID 96 #define VIEW_POPUP_ID 97 #define LINES_VIEW_ID 98 #define DETAILED_VIEW_ID 99 #define FILELIGHT_VIEW_ID 100 #define NEXT_VIEW_ID 101 #define PREVIOUS_VIEW_ID 102 #define ADDITIONAL_POPUP_ID 103 #define MAX_FILENUM 100 LoaderWidget::LoaderWidget(QWidget *parent) : QScrollArea(parent), cancelled(false) { QPalette palette = viewport()->palette(); palette.setColor(viewport()->backgroundRole(), Qt::white); viewport()->setPalette(palette); widget = new QWidget(parent); QGridLayout *loaderLayout = new QGridLayout(widget); loaderLayout->setSpacing(0); loaderLayout->setContentsMargins(0, 0, 0, 0); QFrame *loaderBox = new QFrame(widget); loaderBox->setFrameShape(QFrame::Box); loaderBox->setFrameShadow(QFrame::Sunken); loaderBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); loaderBox->setFrameStyle(QFrame::Panel + QFrame::Raised); loaderBox->setLineWidth(2); QGridLayout *synchGrid = new QGridLayout(loaderBox); synchGrid->setSpacing(6); synchGrid->setContentsMargins(11, 11, 11, 11); QLabel *titleLabel = new QLabel(i18n("Loading Usage Information"), loaderBox); titleLabel->setAlignment(Qt::AlignHCenter); synchGrid->addWidget(titleLabel, 0, 0, 1, 2); QLabel *filesLabel = new QLabel(i18n("Files:"), loaderBox); filesLabel->setFrameShape(QLabel::StyledPanel); filesLabel->setFrameShadow(QLabel::Sunken); synchGrid->addWidget(filesLabel, 1, 0); QLabel *directoriesLabel = new QLabel(i18n("Directories:"), loaderBox); directoriesLabel->setFrameShape(QLabel::StyledPanel); directoriesLabel->setFrameShadow(QLabel::Sunken); synchGrid->addWidget(directoriesLabel, 2, 0); QLabel *totalSizeLabel = new QLabel(i18n("Total Size:"), loaderBox); totalSizeLabel->setFrameShape(QLabel::StyledPanel); totalSizeLabel->setFrameShadow(QLabel::Sunken); synchGrid->addWidget(totalSizeLabel, 3, 0); files = new QLabel(loaderBox); files->setFrameShape(QLabel::StyledPanel); files->setFrameShadow(QLabel::Sunken); files->setAlignment(Qt::AlignRight); synchGrid->addWidget(files, 1, 1); directories = new QLabel(loaderBox); directories->setFrameShape(QLabel::StyledPanel); directories->setFrameShadow(QLabel::Sunken); directories->setAlignment(Qt::AlignRight); synchGrid->addWidget(directories, 2, 1); totalSize = new QLabel(loaderBox); totalSize->setFrameShape(QLabel::StyledPanel); totalSize->setFrameShadow(QLabel::Sunken); totalSize->setAlignment(Qt::AlignRight); synchGrid->addWidget(totalSize, 3, 1); int width; searchedDirectory = new KSqueezedTextLabel(loaderBox); searchedDirectory->setFrameShape(QLabel::StyledPanel); searchedDirectory->setFrameShadow(QLabel::Sunken); searchedDirectory->setMinimumWidth(width = QFontMetrics(searchedDirectory->font()).width("W") * 30); searchedDirectory->setMaximumWidth(width); synchGrid->addWidget(searchedDirectory, 4, 0, 1, 2); QFrame *line = new QFrame(loaderBox); line->setFrameStyle(QFrame::HLine | QFrame::Sunken); synchGrid->addWidget(line, 5, 0, 1, 2); QWidget *hboxWidget = new QWidget(loaderBox); QHBoxLayout * hbox = new QHBoxLayout(hboxWidget); QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); hbox->addItem(spacer); QPushButton *cancelButton = new QPushButton(hboxWidget); KStandardGuiItem::assign(cancelButton, KStandardGuiItem::Cancel); hbox->addWidget(cancelButton); synchGrid->addWidget(hboxWidget, 6, 1); loaderLayout->addWidget(loaderBox, 0, 0); setWidget(widget); setAlignment(Qt::AlignCenter); connect(cancelButton, SIGNAL(clicked()), this, SLOT(slotCancelled())); } void LoaderWidget::init() { cancelled = false; } void LoaderWidget::setCurrentURL(const QUrl &url) { searchedDirectory->setText(FileSystem::ensureTrailingSlash(url).toDisplayString(QUrl::PreferLocalFile)); } void LoaderWidget::setValues(int fileNum, int dirNum, KIO::filesize_t total) { files->setText(QString("%1").arg(fileNum)); directories->setText(QString("%1").arg(dirNum)); totalSize->setText(QString("%1").arg(KRpermHandler::parseSize(total).trimmed())); } void LoaderWidget::slotCancelled() { cancelled = true; } DiskUsage::DiskUsage(QString confGroup, QWidget *parent) : QStackedWidget(parent), currentDirectory(0), root(0), configGroup(confGroup), loading(false), abortLoading(false), clearAfterAbort(false), deleting(false), searchFileSystem(0) { listView = new DUListView(this); lineView = new DULines(this); filelightView = new DUFilelight(this); loaderView = new LoaderWidget(this); addWidget(listView); addWidget(lineView); addWidget(filelightView); addWidget(loaderView); setView(VIEW_LINES); Filelight::Config::read(); connect(&loadingTimer, SIGNAL(timeout()), this, SLOT(slotLoadDirectory())); } DiskUsage::~DiskUsage() { if (listView) // don't remove these lines. The module will crash at exit if removed delete listView; if (lineView) delete lineView; if (filelightView) delete filelightView; if (root) delete root; QHashIterator< File *, Properties * > lit(propertyMap); while (lit.hasNext()) delete lit.next().value(); } void DiskUsage::load(const QUrl &baseDir) { fileNum = dirNum = 0; currentSize = 0; emit status(i18n("Loading the disk usage information...")); clear(); baseURL = baseDir.adjusted(QUrl::StripTrailingSlash); root = new Directory(baseURL.fileName(), baseDir.toDisplayString(QUrl::PreferLocalFile)); directoryStack.clear(); parentStack.clear(); directoryStack.push(""); parentStack.push(root); if (searchFileSystem) { delete searchFileSystem; searchFileSystem = 0; } searchFileSystem = FileSystemProvider::instance().getFilesystem(baseDir); if (searchFileSystem == 0) { qWarning() << "could not get filesystem for directory=" << baseDir; loading = abortLoading = clearAfterAbort = false; emit loadFinished(false); return; } currentFileItem = 0; if (!loading) { viewBeforeLoad = activeView; setView(VIEW_LOADER); } loading = true; loaderView->init(); loaderView->setCurrentURL(baseURL); loaderView->setValues(fileNum, dirNum, currentSize); loadingTimer.setSingleShot(true); loadingTimer.start(0); } void DiskUsage::slotLoadDirectory() { if ((currentFileItem == 0 && directoryStack.isEmpty()) || loaderView->wasCancelled() || abortLoading) { if (searchFileSystem) delete searchFileSystem; searchFileSystem = 0; currentFileItem = 0; setView(viewBeforeLoad); if (clearAfterAbort) clear(); else { calculateSizes(); changeDirectory(root); } emit loadFinished(!(loaderView->wasCancelled() || abortLoading)); loading = abortLoading = clearAfterAbort = false; } else if (loading) { for (int counter = 0; counter != MAX_FILENUM; counter ++) { if (currentFileItem == 0) { if (directoryStack.isEmpty()) break; dirToCheck = directoryStack.pop(); currentParent = parentStack.pop(); contentMap.insert(dirToCheck, currentParent); QUrl url = baseURL; if (!dirToCheck.isEmpty()) { url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + (dirToCheck)); } #ifdef BSD if (url.isLocalFile() && url.path().left(7) == "/procfs") break; #else if (url.isLocalFile() && url.path().left(5) == "/proc") break; #endif loaderView->setCurrentURL(url); if (!searchFileSystem->scanDir(url)) break; fileItems = searchFileSystem->fileItems(); dirNum++; currentFileItem = fileItems.isEmpty() ? 0 : fileItems.takeFirst(); } else { fileNum++; File *newItem = 0; QString mime = currentFileItem->getMime(); // fast == not using mimetype magic if (currentFileItem->isDir() && !currentFileItem->isSymLink()) { newItem = new Directory(currentParent, currentFileItem->getName(), dirToCheck, currentFileItem->getSize(), currentFileItem->getMode(), currentFileItem->getOwner(), currentFileItem->getGroup(), currentFileItem->getPerm(), currentFileItem->getTime_t(), currentFileItem->isSymLink(), mime); directoryStack.push((dirToCheck.isEmpty() ? "" : dirToCheck + '/') + currentFileItem->getName()); parentStack.push(dynamic_cast(newItem)); } else { newItem = new File(currentParent, currentFileItem->getName(), dirToCheck, currentFileItem->getSize(), currentFileItem->getMode(), currentFileItem->getOwner(), currentFileItem->getGroup(), currentFileItem->getPerm(), currentFileItem->getTime_t(), currentFileItem->isSymLink(), mime); currentSize += currentFileItem->getSize(); } currentParent->append(newItem); currentFileItem = fileItems.isEmpty() ? 0 : fileItems.takeFirst(); } } loaderView->setValues(fileNum, dirNum, currentSize); loadingTimer.setSingleShot(true); loadingTimer.start(0); } } void DiskUsage::stopLoad() { abortLoading = true; } void DiskUsage::close() { if (loading) { abortLoading = true; clearAfterAbort = true; } } void DiskUsage::dirUp() { if (currentDirectory != 0) { if (currentDirectory->parent() != 0) changeDirectory((Directory *)(currentDirectory->parent())); else { QUrl up = KIO::upUrl(baseURL); if (KMessageBox::questionYesNo(this, i18n("Stepping into the parent folder requires " "loading the content of the \"%1\" URL. Do you wish " "to continue?", up.toDisplayString(QUrl::PreferLocalFile)), i18n("Krusader::DiskUsage"), KStandardGuiItem::yes(), KStandardGuiItem::no(), "DiskUsageLoadParentDir" ) == KMessageBox::Yes) load(up); } } } Directory * DiskUsage::getDirectory(QString dir) { while (dir.endsWith('/')) dir.truncate(dir.length() - 1); if (dir.isEmpty()) return root; if (contentMap.find(dir) == contentMap.end()) return 0; return contentMap[ dir ]; } File * DiskUsage::getFile(QString path) { if (path.isEmpty()) return root; QString dir = path; int ndx = path.lastIndexOf('/'); QString file = path.mid(ndx + 1); if (ndx == -1) dir = ""; else dir.truncate(ndx); Directory *dirEntry = getDirectory(dir); if (dirEntry == 0) return 0; for (Iterator it = dirEntry->iterator(); it != dirEntry->end(); ++it) if ((*it)->name() == file) return *it; return 0; } void DiskUsage::clear() { baseURL = QUrl(); emit clearing(); QHashIterator< File *, Properties * > lit(propertyMap); while (lit.hasNext()) delete lit.next().value(); propertyMap.clear(); contentMap.clear(); if (root) delete root; root = currentDirectory = 0; } int DiskUsage::calculateSizes(Directory *dirEntry, bool emitSig, int depth) { int changeNr = 0; if (dirEntry == 0) dirEntry = root; KIO::filesize_t own = 0, total = 0; for (Iterator it = dirEntry->iterator(); it != dirEntry->end(); ++it) { File * item = *it; if (!item->isExcluded()) { if (item->isDir()) changeNr += calculateSizes(dynamic_cast(item), emitSig, depth + 1); else own += item->size(); total += item->size(); } } KIO::filesize_t oldOwn = dirEntry->ownSize(), oldTotal = dirEntry->size(); dirEntry->setSizes(total, own); if (dirEntry == currentDirectory) currentSize = total; if (emitSig && (own != oldOwn || total != oldTotal)) { emit changed(dirEntry); changeNr++; } if (depth == 0 && changeNr != 0) emit changeFinished(); return changeNr; } int DiskUsage::exclude(File *file, bool calcPercents, int depth) { int changeNr = 0; if (!file->isExcluded()) { file->exclude(true); emit changed(file); changeNr++; if (file->isDir()) { Directory *dir = dynamic_cast(file); for (Iterator it = dir->iterator(); it != dir->end(); ++it) changeNr += exclude(*it, false, depth + 1); } } if (calcPercents) { calculateSizes(root, true); calculatePercents(true); createStatus(); } if (depth == 0 && changeNr != 0) emit changeFinished(); return changeNr; } int DiskUsage::include(Directory *dir, int depth) { int changeNr = 0; if (dir == 0) return 0; for (Iterator it = dir->iterator(); it != dir->end(); ++it) { File *item = *it; if (item->isDir()) changeNr += include(dynamic_cast(item), depth + 1); if (item->isExcluded()) { item->exclude(false); emit changed(item); changeNr++; } } if (depth == 0 && changeNr != 0) emit changeFinished(); return changeNr; } void DiskUsage::includeAll() { include(root); calculateSizes(root, true); calculatePercents(true); createStatus(); } int DiskUsage::del(File *file, bool calcPercents, int depth) { int deleteNr = 0; if (file == root) return 0; KConfigGroup gg(krConfig, "General"); bool trash = gg.readEntry("Move To Trash", _MoveToTrash); QUrl url = QUrl::fromLocalFile(file->fullPath()); if (calcPercents) { // now ask the user if he want to delete: KConfigGroup ga(krConfig, "Advanced"); if (ga.readEntry("Confirm Delete", _ConfirmDelete)) { QString s; KGuiItem b; if (trash && url.isLocalFile()) { s = i18nc("singularOnly", "Do you really want to move this item to the trash?"); b = KGuiItem(i18n("&Trash")); } else { s = i18nc("singularOnly", "Do you really want to delete this item?"); b = KStandardGuiItem::del(); } QStringList name; name.append(file->fullPath()); // show message // note: i'm using continue and not yes/no because the yes/no has cancel as default button if (KMessageBox::warningContinueCancelList(krMainWindow, s, name, i18n("Warning"), b) != KMessageBox::Continue) return 0; } emit status(i18n("Deleting %1...", file->name())); } if (file == currentDirectory) dirUp(); if (file->isDir()) { Directory *dir = dynamic_cast(file); Iterator it; while ((it = dir->iterator()) != dir->end()) deleteNr += del(*it, false, depth + 1); QString path; for (const Directory *d = (Directory*)file; d != root && d && d->parent() != 0; d = d->parent()) { if (!path.isEmpty()) path = '/' + path; path = d->name() + path; } contentMap.remove(path); } emit deleted(file); deleteNr++; KIO::Job *job; if (trash) { job = KIO::trash(url); } else { job = KIO::del(QUrl::fromLocalFile(file->fullPath()), KIO::HideProgressInfo); } deleting = true; // during qApp->processEvent strange things can occur grabMouse(); // that's why we disable the mouse and keyboard events grabKeyboard(); job->exec(); delete job; releaseMouse(); releaseKeyboard(); deleting = false; ((Directory *)(file->parent()))->remove(file); delete file; if (depth == 0) createStatus(); if (calcPercents) { calculateSizes(root, true); calculatePercents(true); createStatus(); emit enteringDirectory(currentDirectory); } if (depth == 0 && deleteNr != 0) emit deleteFinished(); return deleteNr; } void * DiskUsage::getProperty(File *item, QString key) { QHash< File *, Properties *>::iterator itr = propertyMap.find(item); if (itr == propertyMap.end()) return 0; QHash::iterator it = (*itr)->find(key); if (it == (*itr)->end()) return 0; return it.value(); } void DiskUsage::addProperty(File *item, QString key, void * prop) { Properties *props; QHash< File *, Properties *>::iterator itr = propertyMap.find(item); if (itr == propertyMap.end()) { props = new Properties(); propertyMap.insert(item, props); } else props = *itr; props->insert(key, prop); } void DiskUsage::removeProperty(File *item, QString key) { QHash< File *, Properties *>::iterator itr = propertyMap.find(item); if (itr == propertyMap.end()) return; (*itr)->remove(key); if ((*itr)->count() == 0) propertyMap.remove(item); } void DiskUsage::createStatus() { Directory *dirEntry = currentDirectory; if (dirEntry == 0) return; QUrl url = baseURL; if (dirEntry != root) { url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + (dirEntry->directory())); } emit status(i18n("Current folder:%1, Total size:%2, Own size:%3", url.toDisplayString(QUrl::PreferLocalFile | QUrl::StripTrailingSlash), ' ' + KRpermHandler::parseSize(dirEntry->size()), ' ' + KRpermHandler::parseSize(dirEntry->ownSize()))); } void DiskUsage::changeDirectory(Directory *dir) { currentDirectory = dir; currentSize = dir->size(); calculatePercents(true, dir); createStatus(); emit enteringDirectory(dir); } Directory* DiskUsage::getCurrentDir() { return currentDirectory; } void DiskUsage::rightClickMenu(const QPoint & pos, File *fileItem, QMenu *addPopup, QString addPopupName) { QMenu popup(this); popup.setTitle(i18n("Disk Usage")); QHash actionHash; if (fileItem != 0) { QAction * actDelete = popup.addAction(i18n("Delete")); actionHash[ actDelete ] = DELETE_ID; actDelete->setShortcut(Qt::Key_Delete); QAction * actExclude = popup.addAction(i18n("Exclude")); actionHash[ actExclude ] = EXCLUDE_ID; actExclude->setShortcut(Qt::CTRL + Qt::Key_E); popup.addSeparator(); } QAction * myAct = popup.addAction(i18n("Up one folder")); actionHash[ myAct ] = PARENT_DIR_ID; myAct->setShortcut(Qt::SHIFT + Qt::Key_Up); myAct = popup.addAction(i18n("New search")); actionHash[ myAct ] = NEW_SEARCH_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_N); myAct = popup.addAction(i18n("Refresh")); actionHash[ myAct ] = REFRESH_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_R); myAct = popup.addAction(i18n("Include all")); actionHash[ myAct ] = INCLUDE_ALL_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_I); myAct = popup.addAction(i18n("Step into")); actionHash[ myAct ] = STEP_INTO_ID; myAct->setShortcut(Qt::SHIFT + Qt::Key_Down); popup.addSeparator(); if (addPopup != 0) { QAction * menu = popup.addMenu(addPopup); menu->setText(addPopupName); } QMenu viewPopup; myAct = viewPopup.addAction(i18n("Lines")); actionHash[ myAct ] = LINES_VIEW_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_L); myAct = viewPopup.addAction(i18n("Detailed")); actionHash[ myAct ] = DETAILED_VIEW_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_D); myAct = viewPopup.addAction(i18n("Filelight")); actionHash[ myAct ] = FILELIGHT_VIEW_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_F); viewPopup.addSeparator(); myAct = viewPopup.addAction(i18n("Next")); actionHash[ myAct ] = NEXT_VIEW_ID; myAct->setShortcut(Qt::SHIFT + Qt::Key_Right); myAct = viewPopup.addAction(i18n("Previous")); actionHash[ myAct ] = PREVIOUS_VIEW_ID; myAct->setShortcut(Qt::SHIFT + Qt::Key_Left); QAction * menu = popup.addMenu(&viewPopup); menu->setText(i18n("View")); QAction * res = popup.exec(pos); if (actionHash.contains(res)) executeAction(actionHash[ res ], fileItem); } void DiskUsage::executeAction(int action, File * fileItem) { // check out the user's option switch (action) { case DELETE_ID: if (fileItem) del(fileItem); break; case EXCLUDE_ID: if (fileItem) exclude(fileItem); break; case PARENT_DIR_ID: dirUp(); break; case NEW_SEARCH_ID: emit newSearch(); break; case REFRESH_ID: load(baseURL); break; case INCLUDE_ALL_ID: includeAll(); break; case STEP_INTO_ID: { QString uri; if (fileItem && fileItem->isDir()) uri = fileItem->fullPath(); else uri = currentDirectory->fullPath(); ACTIVE_FUNC->openUrl(QUrl::fromLocalFile(uri)); } break; case LINES_VIEW_ID: setView(VIEW_LINES); break; case DETAILED_VIEW_ID: setView(VIEW_DETAILED); break; case FILELIGHT_VIEW_ID: setView(VIEW_FILELIGHT); break; case NEXT_VIEW_ID: setView((activeView + 1) % 3); break; case PREVIOUS_VIEW_ID: setView((activeView + 2) % 3); break; } // currentWidget()->setFocus(); } void DiskUsage::keyPressEvent(QKeyEvent *e) { if (activeView != VIEW_LOADER) { switch (e->key()) { case Qt::Key_E: if (e->modifiers() == Qt::ControlModifier) { executeAction(EXCLUDE_ID, getCurrentFile()); return; } break; case Qt::Key_D: if (e->modifiers() == Qt::ControlModifier) { executeAction(DETAILED_VIEW_ID); return; } break; case Qt::Key_F: if (e->modifiers() == Qt::ControlModifier) { executeAction(FILELIGHT_VIEW_ID); return; } break; case Qt::Key_I: if (e->modifiers() == Qt::ControlModifier) { executeAction(INCLUDE_ALL_ID); return; } break; case Qt::Key_L: if (e->modifiers() == Qt::ControlModifier) { executeAction(LINES_VIEW_ID); return; } break; case Qt::Key_N: if (e->modifiers() == Qt::ControlModifier) { executeAction(NEW_SEARCH_ID); return; } break; case Qt::Key_R: if (e->modifiers() == Qt::ControlModifier) { executeAction(REFRESH_ID); return; } break; case Qt::Key_Up: if (e->modifiers() == Qt::ShiftModifier) { executeAction(PARENT_DIR_ID); return; } break; case Qt::Key_Down: if (e->modifiers() == Qt::ShiftModifier) { executeAction(STEP_INTO_ID); return; } break; case Qt::Key_Left: if (e->modifiers() == Qt::ShiftModifier) { executeAction(PREVIOUS_VIEW_ID); return; } break; case Qt::Key_Right: if (e->modifiers() == Qt::ShiftModifier) { executeAction(NEXT_VIEW_ID); return; } break; case Qt::Key_Delete: if (!e->modifiers()) { executeAction(DELETE_ID, getCurrentFile()); return; } break; case Qt::Key_Plus: if (activeView == VIEW_FILELIGHT) { filelightView->zoomIn(); return; } break; case Qt::Key_Minus: if (activeView == VIEW_FILELIGHT) { filelightView->zoomOut(); return; } break; } } QStackedWidget::keyPressEvent(e); } QPixmap DiskUsage::getIcon(QString mime) { QPixmap icon; if (!QPixmapCache::find(mime, icon)) { // get the icon. if (mime == "Broken Link !") // FIXME: this doesn't work anymore - the reported mimetype for a broken link is now "unknown" - icon = FL_LOADICON("file-broken"); + icon = FileListIcon("file-broken").pixmap(); else { QMimeDatabase db; QMimeType mt = db.mimeTypeForName(mime); if (mt.isValid()) - icon = FL_LOADICON(mt.iconName()); + icon = FileListIcon(mt.iconName()).pixmap(); else - icon = FL_LOADICON("file-broken"); + icon = FileListIcon("file-broken").pixmap(); } // insert it into the cache QPixmapCache::insert(mime, icon); } return icon; } int DiskUsage::calculatePercents(bool emitSig, Directory *dirEntry, int depth) { int changeNr = 0; if (dirEntry == 0) dirEntry = root; for (Iterator it = dirEntry->iterator(); it != dirEntry->end(); ++it) { File *item = *it; if (!item->isExcluded()) { int newPerc; if (dirEntry->size() == 0 && item->size() == 0) newPerc = 0; else if (dirEntry->size() == 0) newPerc = -1; else newPerc = (int)((double)item->size() / (double)currentSize * 10000. + 0.5); int oldPerc = item->intPercent(); item->setPercent(newPerc); if (emitSig && newPerc != oldPerc) { emit changed(item); changeNr++; } if (item->isDir()) changeNr += calculatePercents(emitSig, dynamic_cast(item), depth + 1); } } if (depth == 0 && changeNr != 0) emit changeFinished(); return changeNr; } QString DiskUsage::getToolTip(File *item) { QMimeDatabase db; QMimeType mt = db.mimeTypeForName(item->mime()); QString mime; if (mt.isValid()) mime = mt.comment(); time_t tma = item->time(); struct tm* t = localtime((time_t *) & tma); QDateTime tmp(QDate(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday), QTime(t->tm_hour, t->tm_min)); QString date = QLocale().toString(tmp, QLocale::ShortFormat); QString str = "
" + "" + ""; if (item->isDir()) str += ""; str += "" + "" + "" + "
" + i18n("Name:") + "" + item->name() + "
" + i18n("Type:") + "" + mime + "
" + i18n("Size:") + "" + KRpermHandler::parseSize(item->size()) + "
" + i18n("Own size:") + "" + KRpermHandler::parseSize(item->ownSize()) + "
" + i18n("Last modified:") + "" + date + "
" + i18n("Permissions:") + "" + item->perm() + "
" + i18n("Owner:") + "" + item->owner() + " - " + item->group() + "
"; str.replace(' ', " "); return str; } void DiskUsage::setView(int view) { switch (view) { case VIEW_LINES: setCurrentWidget(lineView); break; case VIEW_DETAILED: setCurrentWidget(listView); break; case VIEW_FILELIGHT: setCurrentWidget(filelightView); break; case VIEW_LOADER: setCurrentWidget(loaderView); break; } // currentWidget()->setFocus(); emit viewChanged(activeView = view); } File * DiskUsage::getCurrentFile() { File * file = 0; switch (activeView) { case VIEW_LINES: file = lineView->getCurrentFile(); break; case VIEW_DETAILED: file = listView->getCurrentFile(); break; case VIEW_FILELIGHT: file = filelightView->getCurrentFile(); break; } return file; } bool DiskUsage::event(QEvent * e) { if (deleting) { // if we are deleting, disable the mouse and switch (e->type()) { // keyboard events case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: case QEvent::MouseMove: case QEvent::KeyPress: case QEvent::KeyRelease: return true; default: break; } } if (e->type() == QEvent::ShortcutOverride) { QKeyEvent* ke = (QKeyEvent*) e; if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::KeypadModifier) { switch (ke->key()) { case Qt::Key_Delete: case Qt::Key_Plus: case Qt::Key_Minus: ke->accept(); break; } } else if (ke->modifiers() == Qt::ShiftModifier) { switch (ke->key()) { case Qt::Key_Left: case Qt::Key_Right: case Qt::Key_Up: case Qt::Key_Down: ke->accept(); break; } } else if (ke->modifiers() & Qt::ControlModifier) { switch (ke->key()) { case Qt::Key_D: case Qt::Key_E: case Qt::Key_F: case Qt::Key_I: case Qt::Key_L: case Qt::Key_N: case Qt::Key_R: ke->accept(); break; } } } return QStackedWidget::event(e); } diff --git a/krusader/DiskUsage/diskusagegui.cpp b/krusader/DiskUsage/diskusagegui.cpp index ac5bb6f4..c47b500b 100644 --- a/krusader/DiskUsage/diskusagegui.cpp +++ b/krusader/DiskUsage/diskusagegui.cpp @@ -1,244 +1,243 @@ /***************************************************************************** * Copyright (C) 2004 Csaba Karai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "diskusagegui.h" // QtCore #include // QtGui #include // QtWidgets #include #include #include #include #include #include #include -#include "../kicons.h" #include "../krglobal.h" #include "../icon.h" #include "../FileSystem/filesystem.h" #include "../Dialogs/krdialogs.h" DiskUsageGUI::DiskUsageGUI(const QUrl &openDir) : QDialog(nullptr), exitAtFailure(true) { setWindowTitle(i18n("Krusader::Disk Usage")); setAttribute(Qt::WA_DeleteOnClose); baseDirectory = openDir; QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QGridLayout *duGrid = new QGridLayout(); duGrid->setSpacing(6); duGrid->setContentsMargins(11, 11, 11, 11); QWidget *duTools = new QWidget(this); QHBoxLayout *duHBox = new QHBoxLayout(duTools); duHBox->setContentsMargins(0, 0, 0, 0); duTools->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); btnNewSearch = new QToolButton(duTools); btnNewSearch->setIcon(Icon("document-open")); duHBox->addWidget(btnNewSearch); btnNewSearch->setToolTip(i18n("Start new disk usage search")); btnRefresh = new QToolButton(duTools); btnRefresh->setIcon(Icon("view-refresh")); duHBox->addWidget(btnRefresh); btnRefresh->setToolTip(i18n("Refresh")); btnDirUp = new QToolButton(duTools); btnDirUp->setIcon(Icon("go-up")); duHBox->addWidget(btnDirUp); btnDirUp->setToolTip(i18n("Parent folder")); QWidget *separatorWidget = new QWidget(duTools); separatorWidget->setMinimumWidth(10); duHBox->addWidget(separatorWidget); btnLines = new QToolButton(duTools); btnLines->setIcon(Icon("view-list-details")); btnLines->setCheckable(true); duHBox->addWidget(btnLines); btnLines->setToolTip(i18n("Line view")); btnDetailed = new QToolButton(duTools); btnDetailed->setIcon(Icon("view-list-tree")); btnDetailed->setCheckable(true); duHBox->addWidget(btnDetailed); btnDetailed->setToolTip(i18n("Detailed view")); btnFilelight = new QToolButton(duTools); btnFilelight->setIcon(Icon("kr_diskusage")); btnFilelight->setCheckable(true); duHBox->addWidget(btnFilelight); btnFilelight->setToolTip(i18n("Filelight view")); QWidget *spacerWidget = new QWidget(duTools); duHBox->addWidget(spacerWidget); QHBoxLayout *hboxlayout = new QHBoxLayout(spacerWidget); QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Fixed); hboxlayout->addItem(spacer); duGrid->addWidget(duTools, 0, 0); diskUsage = new DiskUsage("DiskUsage", this); duGrid->addWidget(diskUsage, 1, 0); status = new KSqueezedTextLabel(this); duGrid->addWidget(status, 2, 0); mainLayout->addLayout(duGrid); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); mainLayout->addWidget(buttonBox); connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); connect(diskUsage, SIGNAL(status(QString)), this, SLOT(slotStatus(QString))); connect(diskUsage, SIGNAL(viewChanged(int)), this, SLOT(slotViewChanged(int))); connect(diskUsage, SIGNAL(newSearch()), this, SLOT(askDir())); connect(diskUsage, SIGNAL(loadFinished(bool)), this, SLOT(slotLoadFinished(bool))); connect(btnNewSearch, SIGNAL(clicked()), this, SLOT(askDir())); connect(btnRefresh, SIGNAL(clicked()), this, SLOT(slotLoadUsageInfo())); connect(btnDirUp, SIGNAL(clicked()), diskUsage, SLOT(dirUp())); connect(btnLines, SIGNAL(clicked()), this, SLOT(slotSelectLinesView())); connect(btnDetailed, SIGNAL(clicked()), this, SLOT(slotSelectListView())); connect(btnFilelight, SIGNAL(clicked()), this, SLOT(slotSelectFilelightView())); KConfigGroup group(krConfig, "DiskUsage"); int view = group.readEntry("View", VIEW_LINES); if (view < VIEW_LINES || view > VIEW_FILELIGHT) view = VIEW_LINES; diskUsage->setView(view); sizeX = group.readEntry("Window Width", QFontMetrics(font()).width("W") * 70); sizeY = group.readEntry("Window Height", QFontMetrics(font()).height() * 25); resize(sizeX, sizeY); if (group.readEntry("Window Maximized", false)) { setWindowState(windowState() | Qt::WindowMaximized); } } void DiskUsageGUI::askDirAndShow() { if (askDir()) { show(); } } void DiskUsageGUI::slotLoadFinished(bool result) { if (exitAtFailure && !result) { close(); } else { exitAtFailure = false; } } void DiskUsageGUI::enableButtons(bool isOn) { btnNewSearch->setEnabled(isOn); btnRefresh->setEnabled(isOn); btnDirUp->setEnabled(isOn); btnLines->setEnabled(isOn); btnDetailed->setEnabled(isOn); btnFilelight->setEnabled(isOn); } void DiskUsageGUI::resizeEvent(QResizeEvent *e) { if (!isMaximized()) { sizeX = e->size().width(); sizeY = e->size().height(); } QDialog::resizeEvent(e); } void DiskUsageGUI::closeEvent(QCloseEvent *event) { KConfigGroup group(krConfig, "DiskUsage"); group.writeEntry("Window Width", sizeX); group.writeEntry("Window Height", sizeY); group.writeEntry("Window Maximized", isMaximized()); group.writeEntry("View", diskUsage->getActiveView()); event->accept(); } void DiskUsageGUI::slotLoadUsageInfo() { diskUsage->load(baseDirectory); } void DiskUsageGUI::slotStatus(QString stat) { status->setText(stat); } void DiskUsageGUI::slotViewChanged(int view) { if (view == VIEW_LOADER) { enableButtons(false); return; } enableButtons(true); btnLines->setChecked(false); btnDetailed->setChecked(false); btnFilelight->setChecked(false); switch (view) { case VIEW_LINES: btnLines->setChecked(true); break; case VIEW_DETAILED: btnDetailed->setChecked(true); break; case VIEW_FILELIGHT: btnFilelight->setChecked(true); break; case VIEW_LOADER: break; } } bool DiskUsageGUI::askDir() { // ask the user for the copy destX const QUrl newDir = KChooseDir::getDir(i18n("Viewing the usage of folder:"), baseDirectory, baseDirectory); if (newDir.isEmpty()) return false; baseDirectory = newDir; QTimer::singleShot(0, this, SLOT(slotLoadUsageInfo())); return true; } diff --git a/krusader/DiskUsage/dulines.cpp b/krusader/DiskUsage/dulines.cpp index c1bfa977..b51517dc 100644 --- a/krusader/DiskUsage/dulines.cpp +++ b/krusader/DiskUsage/dulines.cpp @@ -1,536 +1,535 @@ /***************************************************************************** * Copyright (C) 2004 Csaba Karai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "dulines.h" #include "../icon.h" -#include "../kicons.h" #include "../krglobal.h" #include "../FileSystem/krpermhandler.h" // QtCore #include // QtGui #include #include #include #include #include #include // QtWidgets #include #include #include #include #include #include #include class DULinesItemDelegate : public QItemDelegate { public: explicit DULinesItemDelegate(QObject *parent = 0) : QItemDelegate(parent) {} virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE { QItemDelegate::paint(painter, option, index); QVariant value = index.data(Qt::UserRole); if (value.isValid()) { QString text = value.toString(); value = index.data(Qt::DisplayRole); QString display; if (value.isValid()) display = value.toString(); QSize iconSize; value = index.data(Qt::DecorationRole); if (value.isValid()) iconSize = qvariant_cast(value).actualSize(option.decorationSize); painter->save(); painter->setClipRect(option.rect); QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)) cg = QPalette::Inactive; if (option.state & QStyle::State_Selected) { painter->setPen(option.palette.color(cg, QPalette::HighlightedText)); } else { painter->setPen(option.palette.color(cg, QPalette::Text)); } QFont fnt = option.font; fnt.setItalic(true); painter->setFont(fnt); QFontMetrics fm(fnt); QString renderedText = text; int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin); int pos = 3 * textMargin + option.fontMetrics.width(display) + iconSize.width(); bool truncd = false; QRect rct = option.rect; if (rct.width() > pos) { rct.setX(rct.x() + pos); if (fm.width(renderedText) > rct.width()) { truncd = true; int points = fm.width("..."); while (!renderedText.isEmpty() && (fm.width(renderedText) + points > rct.width())) renderedText.truncate(renderedText.length() - 1); renderedText += "..."; } painter->drawText(rct, Qt::AlignLeft, renderedText); } else truncd = true; if (truncd) ((QAbstractItemModel *)index.model())->setData(index, QVariant(display + " " + text), Qt::ToolTipRole); else ((QAbstractItemModel *)index.model())->setData(index, QVariant(), Qt::ToolTipRole); painter->restore(); } } }; class DULinesItem : public QTreeWidgetItem { public: DULinesItem(DiskUsage *diskUsageIn, File *fileItem, QTreeWidget * parent, QString label1, QString label2, QString label3) : QTreeWidgetItem(parent), diskUsage(diskUsageIn), file(fileItem) { setText(0, label1); setText(1, label2); setText(2, label3); setTextAlignment(1, Qt::AlignRight); } DULinesItem(DiskUsage *diskUsageIn, File *fileItem, QTreeWidget * parent, QTreeWidgetItem * after, QString label1, QString label2, QString label3) : QTreeWidgetItem(parent, after), diskUsage(diskUsageIn), file(fileItem) { setText(0, label1); setText(1, label2); setText(2, label3); setTextAlignment(1, Qt::AlignRight); } virtual bool operator<(const QTreeWidgetItem &other) const Q_DECL_OVERRIDE { int column = treeWidget() ? treeWidget()->sortColumn() : 0; if (text(0) == "..") return true; const DULinesItem *compWith = dynamic_cast< const DULinesItem * >(&other); if (compWith == 0) return false; switch (column) { case 0: case 1: return file->size() > compWith->file->size(); default: return text(column) < other.text(column); } } inline File * getFile() { return file; } private: DiskUsage *diskUsage; File *file; }; DULines::DULines(DiskUsage *usage) : KrTreeWidget(usage), diskUsage(usage), refreshNeeded(false), started(false) { setItemDelegate(itemDelegate = new DULinesItemDelegate()); setAllColumnsShowFocus(true); setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); setIndentation(10); int defaultSize = QFontMetrics(font()).width("W"); QStringList labels; labels << i18n("Line View"); labels << i18n("Percent"); labels << i18n("Name"); setHeaderLabels(labels); header()->setSectionResizeMode(QHeaderView::Interactive); KConfigGroup group(krConfig, diskUsage->getConfigGroup()); showFileSize = group.readEntry("L Show File Size", true); if (group.hasKey("L State")) header()->restoreState(group.readEntry("L State", QByteArray())); else { setColumnWidth(0, defaultSize * 20); setColumnWidth(1, defaultSize * 6); setColumnWidth(2, defaultSize * 20); } setStretchingColumn(0); header()->setSortIndicatorShown(true); sortItems(1, Qt::AscendingOrder); // toolTip = new DULinesToolTip( diskUsage, viewport(), this ); connect(diskUsage, SIGNAL(enteringDirectory(Directory*)), this, SLOT(slotDirChanged(Directory*))); connect(diskUsage, SIGNAL(clearing()), this, SLOT(clear())); connect(header(), SIGNAL(sectionResized(int,int,int)), this, SLOT(sectionResized(int))); connect(this, SIGNAL(itemRightClicked(QTreeWidgetItem*,QPoint,int)), this, SLOT(slotRightClicked(QTreeWidgetItem*,QPoint))); connect(diskUsage, SIGNAL(changed(File*)), this, SLOT(slotChanged(File*))); connect(diskUsage, SIGNAL(deleted(File*)), this, SLOT(slotDeleted(File*))); started = true; } DULines::~DULines() { KConfigGroup group(krConfig, diskUsage->getConfigGroup()); group.writeEntry("L State", header()->saveState()); delete itemDelegate; } bool DULines::event(QEvent * event) { switch (event->type()) { case QEvent::ToolTip: { QHelpEvent *he = static_cast(event); if (viewport()) { QPoint pos = viewport()->mapFromGlobal(he->globalPos()); QTreeWidgetItem * item = itemAt(pos); int column = columnAt(pos.x()); if (item && column == 1) { File *fileItem = ((DULinesItem *)item)->getFile(); QToolTip::showText(he->globalPos(), diskUsage->getToolTip(fileItem), this); return true; } } } break; default: break; } return KrTreeWidget::event(event); } void DULines::slotDirChanged(Directory *dirEntry) { clear(); QTreeWidgetItem * lastItem = 0; if (!(dirEntry->parent() == 0)) { lastItem = new QTreeWidgetItem(this); lastItem->setText(0, ".."); lastItem->setIcon(0, Icon("go-up")); lastItem->setFlags(lastItem->flags() & (~Qt::ItemIsSelectable)); } int maxPercent = -1; for (Iterator it = dirEntry->iterator(); it != dirEntry->end(); ++it) { File *item = *it; if (!item->isExcluded() && item->intPercent() > maxPercent) maxPercent = item->intPercent(); } for (Iterator it = dirEntry->iterator(); it != dirEntry->end(); ++it) { File *item = *it; QString fileName = item->name(); if (lastItem == 0) lastItem = new DULinesItem(diskUsage, item, this, "", item->percent() + " ", fileName); else lastItem = new DULinesItem(diskUsage, item, this, lastItem, "", item->percent() + " ", fileName); if (item->isExcluded()) lastItem->setHidden(true); int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; lastItem->setIcon(2, diskUsage->getIcon(item->mime())); lastItem->setData(0, Qt::DecorationRole, createPixmap(item->intPercent(), maxPercent, header()->sectionSize(0) - 2 * textMargin)); if (showFileSize) lastItem->setData(2, Qt::UserRole, " [" + KIO::convertSize(item->size()) + ']'); QSize size = lastItem->sizeHint(0); size.setWidth(16); lastItem->setSizeHint(0, size); } if (topLevelItemCount() > 0) { setCurrentItem(topLevelItem(0)); } } QPixmap DULines::createPixmap(int percent, int maxPercent, int maxWidth) { if (percent < 0 || percent > maxPercent || maxWidth < 2 || maxPercent == 0) return QPixmap(); maxWidth -= 2; int actualWidth = maxWidth * percent / maxPercent; if (actualWidth == 0) return QPixmap(); QPen pen; pen.setColor(Qt::black); QPainter painter; int size = QFontMetrics(font()).height() - 2; QRect rect(0, 0, actualWidth, size); QRect frameRect(0, 0, actualWidth - 1, size - 1); QPixmap pixmap(rect.width(), rect.height()); painter.begin(&pixmap); painter.setPen(pen); for (int i = 1; i < actualWidth - 1; i++) { int color = (511 * i / (maxWidth - 1)); if (color < 256) pen.setColor(QColor(255 - color, 255, 0)); else pen.setColor(QColor(color - 256, 511 - color, 0)); painter.setPen(pen); painter.drawLine(i, 1, i, size - 1); } pen.setColor(Qt::black); painter.setPen(pen); if (actualWidth != 1) painter.drawRect(frameRect); else painter.drawLine(0, 0, 0, size); painter.end(); pixmap.detach(); return pixmap; } void DULines::resizeEvent(QResizeEvent * re) { KrTreeWidget::resizeEvent(re); if (started && (re->oldSize() != re->size())) sectionResized(0); } void DULines::sectionResized(int column) { if (topLevelItemCount() == 0 || column != 0) return; Directory * currentDir = diskUsage->getCurrentDir(); if (currentDir == 0) return; int maxPercent = -1; for (Iterator it = currentDir->iterator(); it != currentDir->end(); ++it) { File *item = *it; if (!item->isExcluded() && item->intPercent() > maxPercent) maxPercent = item->intPercent(); } QTreeWidgetItemIterator it2(this); while (*it2) { QTreeWidgetItem *lvitem = *it2; if (lvitem->text(0) != "..") { DULinesItem *duItem = dynamic_cast< DULinesItem *>(lvitem); if (duItem) { int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; duItem->setData(0, Qt::DecorationRole, createPixmap(duItem->getFile()->intPercent(), maxPercent, header()->sectionSize(0) - 2 * textMargin)); QSize size = duItem->sizeHint(0); size.setWidth(16); duItem->setSizeHint(0, size); } } it2++; } } bool DULines::doubleClicked(QTreeWidgetItem * item) { if (item) { if (item->text(0) != "..") { File *fileItem = ((DULinesItem *)item)->getFile(); if (fileItem->isDir()) diskUsage->changeDirectory(dynamic_cast(fileItem)); return true; } else { Directory *upDir = (Directory *)diskUsage->getCurrentDir()->parent(); if (upDir) diskUsage->changeDirectory(upDir); return true; } } return false; } void DULines::mouseDoubleClickEvent(QMouseEvent * e) { if (e || e->button() == Qt::LeftButton) { QPoint vp = viewport()->mapFromGlobal(e->globalPos()); QTreeWidgetItem * item = itemAt(vp); if (doubleClicked(item)) return; } KrTreeWidget::mouseDoubleClickEvent(e); } void DULines::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_Return : case Qt::Key_Enter : if (doubleClicked(currentItem())) return; break; case Qt::Key_Left : case Qt::Key_Right : case Qt::Key_Up : case Qt::Key_Down : if (e->modifiers() == Qt::ShiftModifier) { e->ignore(); return; } break; case Qt::Key_Delete : e->ignore(); return; } KrTreeWidget::keyPressEvent(e); } void DULines::slotRightClicked(QTreeWidgetItem *item, const QPoint &pos) { File * file = 0; if (item && item->text(0) != "..") file = ((DULinesItem *)item)->getFile(); QMenu linesPopup; QAction *act = linesPopup.addAction(i18n("Show file sizes"), this, SLOT(slotShowFileSizes())); act->setChecked(showFileSize); diskUsage->rightClickMenu(pos, file, &linesPopup, i18n("Lines")); } void DULines::slotShowFileSizes() { showFileSize = !showFileSize; slotDirChanged(diskUsage->getCurrentDir()); } File * DULines::getCurrentFile() { QTreeWidgetItem *item = currentItem(); if (item == 0 || item->text(0) == "..") return 0; return ((DULinesItem *)item)->getFile(); } void DULines::slotChanged(File * item) { QTreeWidgetItemIterator it(this); while (*it) { QTreeWidgetItem *lvitem = *it; it++; if (lvitem->text(0) != "..") { DULinesItem *duItem = (DULinesItem *)(lvitem); if (duItem->getFile() == item) { setSortingEnabled(false); duItem->setHidden(item->isExcluded()); duItem->setText(1, item->percent()); if (!refreshNeeded) { refreshNeeded = true; QTimer::singleShot(0, this, SLOT(slotRefresh())); } break; } } } } void DULines::slotDeleted(File * item) { QTreeWidgetItemIterator it(this); while (*it) { QTreeWidgetItem *lvitem = *it; it++; if (lvitem->text(0) != "..") { DULinesItem *duItem = (DULinesItem *)(lvitem); if (duItem->getFile() == item) { delete duItem; break; } } } } void DULines::slotRefresh() { if (refreshNeeded) { refreshNeeded = false; setSortingEnabled(true); sortItems(1, Qt::AscendingOrder); } } diff --git a/krusader/DiskUsage/dulistview.cpp b/krusader/DiskUsage/dulistview.cpp index 1af2d4b1..716bd69d 100644 --- a/krusader/DiskUsage/dulistview.cpp +++ b/krusader/DiskUsage/dulistview.cpp @@ -1,274 +1,273 @@ /***************************************************************************** * Copyright (C) 2004 Csaba Karai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "dulistview.h" #include "../krglobal.h" #include "../icon.h" -#include "../kicons.h" #include "../FileSystem/krpermhandler.h" // QtCore #include #include // QtGui #include #include #include // QtWidgets #include #include #include DUListView::DUListView(DiskUsage *usage) : KrTreeWidget(usage), diskUsage(usage) { setAllColumnsShowFocus(true); setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); setRootIsDecorated(true); setIndentation(10); setItemsExpandable(true); QStringList labels; labels << i18n("Name"); labels << i18n("Percent"); labels << i18n("Total size"); labels << i18n("Own size"); labels << i18n("Type"); labels << i18n("Date"); labels << i18n("Permissions"); labels << i18n("Owner"); labels << i18n("Group"); setHeaderLabels(labels); header()->setSectionResizeMode(QHeaderView::Interactive); KConfigGroup group(krConfig, diskUsage->getConfigGroup()); if (group.hasKey("D State")) header()->restoreState(group.readEntry("D State", QByteArray())); else { int defaultSize = QFontMetrics(font()).width("W"); setColumnWidth(0, defaultSize * 20); setColumnWidth(1, defaultSize * 5); setColumnWidth(2, defaultSize * 10); setColumnWidth(3, defaultSize * 10); setColumnWidth(4, defaultSize * 10); setColumnWidth(5, defaultSize * 10); setColumnWidth(6, defaultSize * 6); setColumnWidth(7, defaultSize * 5); setColumnWidth(8, defaultSize * 5); } header()->setSortIndicatorShown(true); sortItems(2, Qt::AscendingOrder); connect(diskUsage, SIGNAL(enteringDirectory(Directory*)), this, SLOT(slotDirChanged(Directory*))); connect(diskUsage, SIGNAL(clearing()), this, SLOT(clear())); connect(diskUsage, SIGNAL(changed(File*)), this, SLOT(slotChanged(File*))); connect(diskUsage, SIGNAL(deleted(File*)), this, SLOT(slotDeleted(File*))); connect(this, SIGNAL(itemRightClicked(QTreeWidgetItem*,QPoint,int)), this, SLOT(slotRightClicked(QTreeWidgetItem*,QPoint))); connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(slotExpanded(QTreeWidgetItem*))); } DUListView::~ DUListView() { KConfigGroup group(krConfig, diskUsage->getConfigGroup()); group.writeEntry("D State", header()->saveState()); } void DUListView::addDirectory(Directory *dirEntry, QTreeWidgetItem *parent) { QTreeWidgetItem * lastItem = 0; if (parent == 0 && !(dirEntry->parent() == 0)) { lastItem = new QTreeWidgetItem(this); lastItem->setText(0, ".."); lastItem->setIcon(0, Icon("go-up")); lastItem->setFlags(Qt::ItemIsEnabled); } for (Iterator it = dirEntry->iterator(); it != dirEntry->end(); ++it) { File *item = *it; QMimeDatabase db; QMimeType mt = db.mimeTypeForName(item->mime()); QString mime; if (mt.isValid()) mime = mt.comment(); time_t tma = item->time(); struct tm* t = localtime((time_t *) & tma); QDateTime tmp(QDate(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday), QTime(t->tm_hour, t->tm_min)); QString date = QLocale().toString(tmp, QLocale::ShortFormat); QString totalSize = KRpermHandler::parseSize(item->size()) + ' '; QString ownSize = KRpermHandler::parseSize(item->ownSize()) + ' '; QString percent = item->percent(); if (lastItem == 0 && parent == 0) lastItem = new DUListViewItem(diskUsage, item, this, item->name(), percent, totalSize, ownSize, mime, date, item->perm(), item->owner(), item->group()); else if (lastItem == 0) lastItem = new DUListViewItem(diskUsage, item, parent, item->name(), percent, totalSize, ownSize, mime, date, item->perm(), item->owner(), item->group()); else if (parent == 0) lastItem = new DUListViewItem(diskUsage, item, this, lastItem, item->name(), percent, totalSize, ownSize, mime, date, item->perm(), item->owner(), item->group()); else lastItem = new DUListViewItem(diskUsage, item, parent, lastItem, item->name(), percent, totalSize, ownSize, mime, date, item->perm(), item->owner(), item->group()); if (item->isExcluded()) lastItem->setHidden(true); lastItem->setIcon(0, diskUsage->getIcon(item->mime())); if (item->isDir() && !item->isSymLink()) lastItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); } if (topLevelItemCount() > 0) { setCurrentItem(topLevelItem(0)); } } void DUListView::slotDirChanged(Directory *dirEntry) { clear(); addDirectory(dirEntry, 0); } File * DUListView::getCurrentFile() { QTreeWidgetItem *item = currentItem(); if (item == 0 || item->text(0) == "..") return 0; return ((DUListViewItem *)item)->getFile(); } void DUListView::slotChanged(File * item) { void * itemPtr = diskUsage->getProperty(item, "ListView-Ref"); if (itemPtr == 0) return; DUListViewItem *duItem = (DUListViewItem *)itemPtr; duItem->setHidden(item->isExcluded()); duItem->setText(1, item->percent()); duItem->setText(2, KRpermHandler::parseSize(item->size()) + ' '); duItem->setText(3, KRpermHandler::parseSize(item->ownSize()) + ' '); } void DUListView::slotDeleted(File * item) { void * itemPtr = diskUsage->getProperty(item, "ListView-Ref"); if (itemPtr == 0) return; DUListViewItem *duItem = (DUListViewItem *)itemPtr; delete duItem; } void DUListView::slotRightClicked(QTreeWidgetItem *item, const QPoint & pos) { File * file = 0; if (item && item->text(0) != "..") file = ((DUListViewItem *)item)->getFile(); diskUsage->rightClickMenu(pos, file); } bool DUListView::doubleClicked(QTreeWidgetItem * item) { if (item) { if (item->text(0) != "..") { File *fileItem = ((DUListViewItem *)item)->getFile(); if (fileItem->isDir()) diskUsage->changeDirectory(dynamic_cast(fileItem)); return true; } else { Directory *upDir = (Directory *)diskUsage->getCurrentDir()->parent(); if (upDir) diskUsage->changeDirectory(upDir); return true; } } return false; } void DUListView::mouseDoubleClickEvent(QMouseEvent * e) { if (e || e->button() == Qt::LeftButton) { QPoint vp = viewport()->mapFromGlobal(e->globalPos()); QTreeWidgetItem * item = itemAt(vp); if (doubleClicked(item)) return; } KrTreeWidget::mouseDoubleClickEvent(e); } void DUListView::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_Return : case Qt::Key_Enter : if (doubleClicked(currentItem())) return; break; case Qt::Key_Left : case Qt::Key_Right : case Qt::Key_Up : case Qt::Key_Down : if (e->modifiers() == Qt::ShiftModifier) { e->ignore(); return; } break; case Qt::Key_Delete : e->ignore(); return; } KrTreeWidget::keyPressEvent(e); } void DUListView::slotExpanded(QTreeWidgetItem * item) { if (item == 0 || item->text(0) == "..") return; if (item->childCount() == 0) { File *fileItem = ((DUListViewItem *)item)->getFile(); if (fileItem->isDir()) addDirectory(dynamic_cast(fileItem), item); } } diff --git a/krusader/GUI/kcmdline.cpp b/krusader/GUI/kcmdline.cpp index add559b6..af726ec4 100644 --- a/krusader/GUI/kcmdline.cpp +++ b/krusader/GUI/kcmdline.cpp @@ -1,316 +1,315 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * Copyright (C) 2000 Rafi Yanai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "kcmdline.h" // QtCore #include #include #include // QtGui #include #include #include #include #include // QtWidgets #include #include #include #include #include #include #include #include "../krglobal.h" -#include "../kicons.h" #include "../krslots.h" #include "../defaults.h" #include "../krusaderview.h" #include "../krservices.h" #include "../ActionMan/addplaceholderpopup.h" #include "kcmdmodebutton.h" CmdLineCombo::CmdLineCombo(QWidget *parent) : KHistoryComboBox(parent), _handlingLineEditResize(false) { lineEdit()->installEventFilter(this); _pathLabel = new QLabel(this); _pathLabel->setWhatsThis(i18n("Name of folder where command will be processed.")); _pathLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); } bool CmdLineCombo::eventFilter(QObject *watched, QEvent *e) { if(watched == lineEdit() && (e->type() == QEvent::Move || e->type() == QEvent::Resize)) { if(!_handlingLineEditResize) { // avoid infinite recursion _handlingLineEditResize = true; updateLineEditGeometry(); _handlingLineEditResize = false; } } return false; } void CmdLineCombo::setPath(QString path) { _path = path; doLayout(); } void CmdLineCombo::updateLineEditGeometry() { QRect r = lineEdit()->geometry(); r.setLeft(_pathLabel->geometry().right()); lineEdit()->setGeometry(r); } void CmdLineCombo::doLayout() { QString pathNameLabel = _path; QFontMetrics fm(_pathLabel->fontMetrics()); int textWidth = fm.width(_path); int maxWidth = (width() + _pathLabel->width()) * 2 / 5; int letters = _path.length() / 2; while (letters && textWidth > maxWidth) { pathNameLabel = _path.left(letters) + "..." + _path.right(letters); letters--; textWidth = fm.width(pathNameLabel); } _pathLabel->setText(pathNameLabel + "> "); _pathLabel->adjustSize(); QStyleOptionComboBox opt; initStyleOption(&opt); QRect labelRect = style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, this); labelRect.adjust(2, 0, 0, 0); labelRect.setWidth(_pathLabel->width()); _pathLabel->setGeometry(labelRect); updateLineEditGeometry(); } void CmdLineCombo::resizeEvent(QResizeEvent *e) { KHistoryComboBox::resizeEvent(e); doLayout(); } void CmdLineCombo::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_Enter: case Qt::Key_Return: if (e->modifiers() & Qt::ControlModifier) { SLOTS->insertFileName((e->modifiers()&Qt::ShiftModifier)!=0); break; } KHistoryComboBox::keyPressEvent(e); break; case Qt::Key_Down: if (e->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { MAIN_VIEW->focusTerminalEmulator(); return; } else KHistoryComboBox::keyPressEvent(e); break; case Qt::Key_Up: if (e->modifiers() == Qt::ControlModifier || e->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { emit returnToPanel(); return; } else KHistoryComboBox::keyPressEvent(e); break; case Qt::Key_Escape: if (e->modifiers() == 0) { emit returnToPanel(); return; } else KHistoryComboBox::keyPressEvent(e); break; default: KHistoryComboBox::keyPressEvent(e); } } KCMDLine::KCMDLine(QWidget *parent) : QWidget(parent) { QGridLayout * layout = new QGridLayout(this); layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); int height = QFontMetrics(QFontDatabase::systemFont(QFontDatabase::GeneralFont)).height(); height = height + 5 * (height > 14) + 6; // and editable command line completion.setMode(KUrlCompletion::FileCompletion); cmdLine = new CmdLineCombo(this); cmdLine->setMaxCount(100); // remember 100 commands cmdLine->setMinimumContentsLength(10); cmdLine->setDuplicatesEnabled(false); cmdLine->setMaximumHeight(height); cmdLine->setCompletionObject(&completion); cmdLine->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); // load the history KConfigGroup grpSvr(krConfig, "Private"); QStringList list = grpSvr.readEntry("cmdline history", QStringList()); cmdLine->setHistoryItems(list); connect(cmdLine, SIGNAL(returnPressed(QString)), this, SLOT(slotRun())); connect(cmdLine, SIGNAL(returnPressed(QString)), cmdLine->lineEdit(), SLOT(clear())); connect(cmdLine, SIGNAL(returnToPanel()), this, SLOT(slotReturnFocus())); cmdLine->setWhatsThis(i18n("

Well, it is actually quite simple: you type your command here and Krusader obeys.

Tip: move within command line history with <Up> and <Down> arrows.

")); layout->addWidget(cmdLine, 0, 1); buttonAddPlaceholder = new QToolButton(this); buttonAddPlaceholder->setAutoRaise(true); buttonAddPlaceholder->setIcon(SmallIcon("list-add")); connect(buttonAddPlaceholder, SIGNAL(clicked()), this, SLOT(addPlaceholder())); buttonAddPlaceholder->setWhatsThis(i18n("Add Placeholders for the selected files in the panel.")); layout->addWidget(buttonAddPlaceholder, 0, 2); // a run in terminal button terminal = new KCMDModeButton(this); terminal->setAutoRaise(true); layout->addWidget(terminal, 0, 3); layout->activate(); } KCMDLine::~KCMDLine() { KConfigGroup grpSvr(krConfig, "Private"); QStringList list = cmdLine->historyItems(); //qWarning() << list[0]; grpSvr.writeEntry("cmdline history", list); krConfig->sync(); } void KCMDLine::addPlaceholder() { AddPlaceholderPopup popup(this); QString exp = popup.getPlaceholder( buttonAddPlaceholder->mapToGlobal(QPoint(0, 0)) ); this->addText(exp); } void KCMDLine::setCurrent(const QString &path) { cmdLine->setPath(path); completion.setDir(QUrl::fromLocalFile(path)); // make sure our command is executed in the right directory // This line is important for Krusader overall functions -> do not remove ! QDir::setCurrent(path); } void KCMDLine::slotRun() { const QString command1(cmdLine->currentText()); if (command1.isEmpty()) return; cmdLine->addToHistory(command1); // bugfix by aardvark: current editline is destroyed by addToHistory() in some cases cmdLine->setEditText(command1); if (command1.simplified().left(3) == "cd ") { // cd command effect the active panel QString dir = command1.right(command1.length() - command1.indexOf(" ")).trimmed(); if (dir == "~") dir = QDir::homePath(); else if (dir.left(1) != "/" && !dir.contains(":/")) dir = cmdLine->path() + (cmdLine->path() == "/" ? "" : "/") + dir; SLOTS->refresh(QUrl::fromUserInput(dir,QDir::currentPath(),QUrl::AssumeLocalFile)); } else { exec(); cmdLine->clearEditText(); } } void KCMDLine::slotReturnFocus() { MAIN_VIEW->cmdLineUnFocus(); } static const KrActionBase::ExecType execModesMenu[] = { KrActionBase::Normal, KrActionBase::CollectOutputSeparateStderr, KrActionBase::CollectOutput, KrActionBase::Terminal, KrActionBase::RunInTE, }; QString KCMDLine::command() const { return cmdLine->currentText(); } KrActionBase::ExecType KCMDLine::execType() const { KConfigGroup grp(krConfig, "Private"); int i = grp.readEntry("Command Execution Mode", (int)0); return execModesMenu[i]; } QString KCMDLine::startpath() const { return cmdLine->path(); // return path->text().left(path->text().length() - 1); } QString KCMDLine::user() const { return QString(); } QString KCMDLine::text() const { return cmdLine->currentText(); } bool KCMDLine::acceptURLs() const { return false; } bool KCMDLine::confirmExecution() const { return false; } bool KCMDLine::doSubstitution() const { return true; } void KCMDLine::setText(QString text) { cmdLine->lineEdit()->setText(text); } diff --git a/krusader/GUI/krremoteencodingmenu.cpp b/krusader/GUI/krremoteencodingmenu.cpp index 1442188f..12a3b842 100644 --- a/krusader/GUI/krremoteencodingmenu.cpp +++ b/krusader/GUI/krremoteencodingmenu.cpp @@ -1,227 +1,226 @@ /***************************************************************************** * Copyright (C) 2005 Csaba Karai * * Copyright (C) 2005-2018 Krusader Krew [https://krusader.org] * * * * Based on KRemoteEncodingPlugin from Dawit Alemayehu * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "krremoteencodingmenu.h" // QtCore #include // QtWidgets #include #include #include #include #include #include #include #include #include "../krglobal.h" #include "../icon.h" #include "../Panel/krpanel.h" #include "../Panel/panelfunc.h" -#include "../kicons.h" #define DATA_KEY QString::fromLatin1("Charset") KrRemoteEncodingMenu::KrRemoteEncodingMenu(const QString &text, const QString &icon, KActionCollection *parent) : KActionMenu(Icon(icon), text, parent), settingsLoaded(false) { connect(menu(), SIGNAL(aboutToShow()), this, SLOT(slotAboutToShow())); parent->addAction("changeremoteencoding", this); } void KrRemoteEncodingMenu::slotAboutToShow() { if (!settingsLoaded) loadSettings(); // uncheck everything QList acts = menu()->actions(); foreach(QAction *act, acts) act->setChecked(false); QString charset = currentCharacterSet(); if (!charset.isEmpty()) { int id = 1; QStringList::Iterator it; for (it = encodingNames.begin(); it != encodingNames.end(); ++it, ++id) if ((*it).indexOf(charset) != -1) break; bool found = false; foreach(QAction *act, acts) { if (act->data().canConvert ()) { int idr = act->data().toInt(); if (idr == id) { act->setChecked(found = true); break; } } } if (!found) qWarning() << Q_FUNC_INFO << "could not find entry for charset=" << charset; } else { foreach(QAction *act, acts) { if (act->data().canConvert ()) { int idr = act->data().toInt(); if (idr == -2) { act->setChecked(true); break; } } } } } QString KrRemoteEncodingMenu::currentCharacterSet() { QUrl currentURL = ACTIVE_PANEL->virtualPath(); return KProtocolManager::charsetFor(currentURL); } void KrRemoteEncodingMenu::loadSettings() { settingsLoaded = true; encodingNames = KCharsets::charsets()->descriptiveEncodingNames(); QMenu *qmenu = menu(); disconnect(qmenu, SIGNAL(triggered(QAction*)), this, SLOT(slotTriggered(QAction*))); connect(qmenu, SIGNAL(triggered(QAction*)), this, SLOT(slotTriggered(QAction*))); qmenu->clear(); QStringList::ConstIterator it; int count = 0; QAction *act; for (it = encodingNames.constBegin(); it != encodingNames.constEnd(); ++it) { act = qmenu->addAction(*it); act->setData(QVariant(++count)); act->setCheckable(true); } qmenu->addSeparator(); act = qmenu->addAction(i18n("Reload")); act->setCheckable(true); act->setData(QVariant(-1)); act = qmenu->addAction(i18nc("Default encoding", "Default")); act->setCheckable(true); act->setData(QVariant(-2)); } void KrRemoteEncodingMenu::slotTriggered(QAction * act) { if (!act || !act->data().canConvert ()) return; int id = act->data().toInt(); switch (id) { case -1: slotReload(); return; case -2: chooseDefault(); return; default: chooseEncoding(encodingNames[id - 1]); } } void KrRemoteEncodingMenu::chooseEncoding(QString encoding) { QUrl currentURL = ACTIVE_PANEL->virtualPath(); KConfig config(("kio_" + currentURL.scheme() + "rc").toLatin1()); QString host = currentURL.host(); QString charset = KCharsets::charsets()->encodingForName(encoding); KConfigGroup group(&config, host); group.writeEntry(DATA_KEY, charset); config.sync(); // Update the io-slaves... updateKIOSlaves(); } void KrRemoteEncodingMenu::slotReload() { loadSettings(); } void KrRemoteEncodingMenu::chooseDefault() { QUrl currentURL = ACTIVE_PANEL->virtualPath(); // We have no choice but delete all higher domain level // settings here since it affects what will be matched. KConfig config(("kio_" + currentURL.scheme() + "rc").toLatin1()); QStringList partList = currentURL.host().split('.', QString::SkipEmptyParts); if (!partList.isEmpty()) { partList.erase(partList.begin()); QStringList domains; // Remove the exact name match... domains << currentURL.host(); while (partList.count()) { if (partList.count() == 2) if (partList[0].length() <= 2 && partList[1].length() == 2) break; if (partList.count() == 1) break; domains << partList.join("."); partList.erase(partList.begin()); } for (QStringList::Iterator it = domains.begin(); it != domains.end(); ++it) { //qDebug() << "Domain to remove: " << *it; if (config.hasGroup(*it)) config.deleteGroup(*it); else if (config.group("").hasKey(*it)) config.group("").deleteEntry(*it); //don't know what group name is supposed to be XXX } } config.sync(); updateKIOSlaves(); } void KrRemoteEncodingMenu::updateKIOSlaves() { KIO::Scheduler::emitReparseSlaveConfiguration(); // Reload the page with the new charset QTimer::singleShot(500, ACTIVE_FUNC, SLOT(refresh())); } diff --git a/krusader/KViewer/krviewer.cpp b/krusader/KViewer/krviewer.cpp index 6e6d018d..ec5e0804 100644 --- a/krusader/KViewer/krviewer.cpp +++ b/krusader/KViewer/krviewer.cpp @@ -1,716 +1,715 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 Rafi Yanai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "krviewer.h" // QtCore #include #include #include #include #include // QtGui #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../defaults.h" #include "../icon.h" -#include "../kicons.h" #include "panelviewer.h" #define VIEW_ICON "document-preview" #define EDIT_ICON "document-edit" #define MODIFIED_ICON "document-save-as" #define CHECK_MODFIED_INTERVAL 500 /* NOTE: Currently the code expects PanelViewer::openUrl() to be called only once in the panel viewer's life time - otherwise unexpected things might happen. */ QList KrViewer::viewers; KrViewer::KrViewer(QWidget *parent) : KParts::MainWindow(parent, (Qt::WindowFlags)KDE_DEFAULT_WINDOWFLAGS), manager(this, this), tabBar(this), reservedKeys(), reservedKeyActions(), sizeX(-1), sizeY(-1) { //setWFlags(Qt::WType_TopLevel | WDestructiveClose); setXMLFile("krviewer.rc"); // kpart-related xml file setHelpMenuEnabled(false); connect(&manager, SIGNAL(activePartChanged(KParts::Part*)), this, SLOT(createGUI(KParts::Part*))); connect(&tabBar, &QTabWidget::currentChanged, this, &KrViewer::tabChanged); connect(&tabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(tabCloseRequest(int))); tabBar.setDocumentMode(true); tabBar.setMovable(true); setCentralWidget(&tabBar); printAction = KStandardAction::print(this, SLOT(print()), 0); copyAction = KStandardAction::copy(this, SLOT(copy()), 0); viewerMenu = new QMenu(this); QAction *tempAction; KActionCollection *ac = actionCollection(); #define addCustomMenuAction(name, text, slot, shortcut)\ tempAction = ac->addAction(name, this, slot);\ tempAction->setText(text);\ ac->setDefaultShortcut(tempAction, shortcut);\ viewerMenu->addAction(tempAction); addCustomMenuAction("genericViewer", i18n("&Generic Viewer"), SLOT(viewGeneric()), Qt::CTRL + Qt::SHIFT + Qt::Key_G); addCustomMenuAction("textViewer", i18n("&Text Viewer"), SLOT(viewText()), Qt::CTRL + Qt::SHIFT + Qt::Key_T); addCustomMenuAction("hexViewer", i18n("&Hex Viewer"), SLOT(viewHex()), Qt::CTRL + Qt::SHIFT + Qt::Key_H); addCustomMenuAction("lister", i18n("&Lister"), SLOT(viewLister()), Qt::CTRL + Qt::SHIFT + Qt::Key_L); viewerMenu->addSeparator(); addCustomMenuAction("textEditor", i18n("Text &Editor"), SLOT(editText()), Qt::CTRL + Qt::SHIFT + Qt::Key_E); viewerMenu->addSeparator(); QList actList = menuBar()->actions(); bool hasPrint = false, hasCopy = false; foreach(QAction *a, actList) { if (a->shortcut().matches(printAction->shortcut()) != QKeySequence::NoMatch) hasPrint = true; if (a->shortcut().matches(copyAction->shortcut()) != QKeySequence::NoMatch) hasCopy = true; } QAction *printAct = viewerMenu->addAction(printAction->icon(), printAction->text(), this, SLOT(print())); if (hasPrint) printAct->setShortcut(printAction->shortcut()); QAction *copyAct = viewerMenu->addAction(copyAction->icon(), copyAction->text(), this, SLOT(copy())); if (hasCopy) copyAct->setShortcut(copyAction->shortcut()); viewerMenu->addSeparator(); configKeysAction = ac->addAction(KStandardAction::KeyBindings, this, SLOT(configureShortcuts())); viewerMenu->addAction(configKeysAction); viewerMenu->addSeparator(); detachAction = ac->addAction("detachTab", this, SLOT(detachTab())); detachAction->setText(i18n("&Detach Tab")); //no point in detaching only one tab.. detachAction->setEnabled(false); ac->setDefaultShortcut(detachAction, Qt::META + Qt::Key_D); viewerMenu->addAction(detachAction); quitAction = ac->addAction(KStandardAction::Quit, this, SLOT(close())); viewerMenu->addAction(quitAction); QList shortcuts; tabCloseAction = ac->addAction("closeTab", this, SLOT(tabCloseRequest())); tabCloseAction->setText(i18n("&Close Current Tab")); shortcuts = KStandardShortcut::close(); shortcuts.append(Qt::Key_Escape); ac->setDefaultShortcuts(tabCloseAction, shortcuts); tabNextAction = ac->addAction("nextTab", this, SLOT(nextTab())); tabNextAction->setText(i18n("&Next Tab")); shortcuts = KStandardShortcut::tabNext(); shortcuts.append(Qt::CTRL + Qt::Key_Tab); // reenforce QTabWidget shortcut ac->setDefaultShortcuts(tabNextAction, shortcuts); tabPrevAction = ac->addAction("prevTab", this, SLOT(prevTab())); tabPrevAction->setText(i18n("&Previous Tab")); shortcuts = KStandardShortcut::tabPrev(); shortcuts.append(Qt::CTRL + Qt::SHIFT + Qt::Key_Tab); // reenforce QTabWidget shortcut ac->setDefaultShortcuts(tabPrevAction, shortcuts); tabBar.setTabsClosable(true); checkModified(); KConfigGroup group(krConfig, "KrViewerWindow"); int sx = group.readEntry("Window Width", -1); int sy = group.readEntry("Window Height", -1); if (sx != -1 && sy != -1) resize(sx, sy); else resize(900, 700); if (group.readEntry("Window Maximized", false)) { setWindowState(windowState() | Qt::WindowMaximized); } // filtering out the key events menuBar() ->installEventFilter(this); } KrViewer::~KrViewer() { disconnect(&manager, SIGNAL(activePartChanged(KParts::Part*)), this, SLOT(createGUI(KParts::Part*))); viewers.removeAll(this); // close tabs before deleting tab bar - this avoids Qt bug 26115 // https://bugreports.qt-project.org/browse/QTBUG-26115 while(tabBar.count()) tabCloseRequest(tabBar.currentIndex(), true); delete printAction; delete copyAction; } void KrViewer::configureDeps() { PanelEditor::configureDeps(); } void KrViewer::createGUI(KParts::Part* part) { KParts::MainWindow::createGUI(part); updateActions(); toolBar() ->show(); statusBar() ->show(); // the KParts part may override the viewer shortcuts. We prevent it // by installing an event filter on the menuBar() and the part reservedKeys.clear(); reservedKeyActions.clear(); QList list = viewerMenu->actions(); // also add the actions that are not in the menu... list << tabCloseAction << tabNextAction << tabPrevAction; // getting the key sequences of the viewer menu for (int w = 0; w != list.count(); w++) { QAction *act = list[ w ]; QList sequences = act->shortcuts(); foreach(QKeySequence keySeq, sequences) { for(int i = 0; i < keySeq.count(); ++i) { reservedKeys.push_back(keySeq[i]); reservedKeyActions.push_back(act); //the same action many times in case of multiple shortcuts } } } // and "fix" the menubar QList actList = menuBar()->actions(); viewerMenu->setTitle(i18n("&KrViewer")); QAction * act = menuBar() ->addMenu(viewerMenu); act->setData(QVariant(70)); menuBar() ->show(); } void KrViewer::configureShortcuts() { KShortcutsDialog::configure(actionCollection(), KShortcutsEditor::LetterShortcutsAllowed, this); } bool KrViewer::eventFilter(QObject * /* watched */, QEvent * e) { // TODO: after porting to Qt5/KF5 we never catch *ANY* KeyPress or ShortcutOverride events here anymore. // Should look into if there is any way to fix it. Currently if a KPart has same shortcut as KrViewer then // it causes a conflict, messagebox shown to user and no action triggered. if (e->type() == QEvent::ShortcutOverride) { QKeyEvent* ke = (QKeyEvent*) e; if (reservedKeys.contains(ke->key())) { ke->accept(); QAction *act = reservedKeyActions[ reservedKeys.indexOf(ke->key())]; if (act != 0) { // don't activate the close functions immediately! // it can cause crash if (act == tabCloseAction || act == quitAction) { QTimer::singleShot(0, act, SLOT(trigger())); } else { act->activate(QAction::Trigger); } } return true; } } else if (e->type() == QEvent::KeyPress) { QKeyEvent* ke = (QKeyEvent*) e; if (reservedKeys.contains(ke->key())) { ke->accept(); return true; } } return false; } KrViewer* KrViewer::getViewer(bool new_window) { if (!new_window) { if (viewers.isEmpty()) { viewers.prepend(new KrViewer()); // add to first (active) } else { if (viewers.first()->isMinimized()) { // minimized? -> show it again viewers.first()->setWindowState((viewers.first()->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive); viewers.first()->show(); } viewers.first()->raise(); viewers.first()->activateWindow(); } return viewers.first(); } else { KrViewer *newViewer = new KrViewer(); viewers.prepend(newViewer); return newViewer; } } void KrViewer::view(QUrl url, QWidget * parent) { KConfigGroup group(krConfig, "General"); bool defaultWindow = group.readEntry("View In Separate Window", _ViewInSeparateWindow); view(url, Default, defaultWindow, parent); } void KrViewer::view(QUrl url, Mode mode, bool new_window, QWidget * parent) { KrViewer* viewer = getViewer(new_window); viewer->viewInternal(url, mode, parent); viewer->show(); } void KrViewer::edit(QUrl url, QWidget * parent) { edit(url, Text, -1, parent); } void KrViewer::edit(QUrl url, Mode mode, int new_window, QWidget * parent) { KConfigGroup group(krConfig, "General"); QString editor = group.readEntry("Editor", _Editor); if (new_window == -1) new_window = group.readEntry("View In Separate Window", _ViewInSeparateWindow); if (editor != "internal editor" && !editor.isEmpty()) { KProcess proc; QStringList cmdArgs = KShell::splitArgs(editor, KShell::TildeExpand); if (cmdArgs.isEmpty()) { KMessageBox::error(krMainWindow, i18nc("Arg is a string containing the bad quoting.", "Bad quoting in editor command:\n%1", editor)); return; } // if the file is local, pass a normal path and not a url. this solves // the problem for editors that aren't url-aware proc << cmdArgs << url.toDisplayString(QUrl::PreferLocalFile); if (!proc.startDetached()) KMessageBox::sorry(krMainWindow, i18n("Can not open \"%1\"", editor)); return; } KrViewer* viewer = getViewer(new_window); viewer->editInternal(url, mode, parent); viewer->show(); } void KrViewer::addTab(PanelViewerBase *pvb) { int tabIndex = tabBar.addTab(pvb, makeTabIcon(pvb), makeTabText(pvb)); tabBar.setCurrentIndex(tabIndex); tabBar.setTabToolTip(tabIndex, makeTabToolTip(pvb)); updateActions(); // now we can offer the option to detach tabs (we have more than one) if (tabBar.count() > 1) { detachAction->setEnabled(true); } tabBar.show(); connect(pvb, SIGNAL(openUrlFinished(PanelViewerBase*,bool)), SLOT(openUrlFinished(PanelViewerBase*,bool))); connect(pvb, SIGNAL(urlChanged(PanelViewerBase*,QUrl)), this, SLOT(tabURLChanged(PanelViewerBase*,QUrl))); } void KrViewer::tabURLChanged(PanelViewerBase *pvb, const QUrl &url) { Q_UNUSED(url) refreshTab(pvb); } void KrViewer::openUrlFinished(PanelViewerBase *pvb, bool success) { if (success) { KParts::ReadOnlyPart *part = pvb->part(); if (part) { if (!isPartAdded(part)) addPart(part); if (tabBar.currentWidget() == pvb) { manager.setActivePart(part); if (part->widget()) part->widget()->setFocus(); } } } else { tabCloseRequest(tabBar.currentIndex(), false); } } void KrViewer::tabChanged(int index) { QWidget *w = tabBar.widget(index); if(!w) return; KParts::ReadOnlyPart *part = static_cast(w)->part(); if (part && isPartAdded(part)) { manager.setActivePart(part); if (part->widget()) part->widget()->setFocus(); } else manager.setActivePart(0); // set this viewer to be the main viewer if (viewers.removeAll(this)) viewers.prepend(this); // move to first } void KrViewer::tabCloseRequest(int index, bool force) { // important to save as returnFocusTo will be cleared at removePart QWidget *returnFocusToThisWidget = returnFocusTo; PanelViewerBase *pvb = static_cast(tabBar.widget(index)); if (!pvb) return; if (!force && !pvb->queryClose()) return; if (pvb->part() && isPartAdded(pvb->part())) removePart(pvb->part()); disconnect(pvb, 0, this, 0); pvb->closeUrl(); tabBar.removeTab(index); delete pvb; pvb = 0; if (tabBar.count() <= 0) { if (returnFocusToThisWidget) { returnFocusToThisWidget->raise(); returnFocusToThisWidget->activateWindow(); } else { krMainWindow->raise(); krMainWindow->activateWindow(); } QTimer::singleShot(0, this, SLOT(close())); } else if (tabBar.count() == 1) { // no point in detaching only one tab.. detachAction->setEnabled(false); } } void KrViewer::tabCloseRequest() { tabCloseRequest(tabBar.currentIndex()); } bool KrViewer::queryClose() { KConfigGroup group(krConfig, "KrViewerWindow"); group.writeEntry("Window Width", sizeX); group.writeEntry("Window Height", sizeY); group.writeEntry("Window Maximized", isMaximized()); for (int i = 0; i != tabBar.count(); i++) { PanelViewerBase* pvb = static_cast(tabBar.widget(i)); if (!pvb) continue; tabBar.setCurrentIndex(i); if (!pvb->queryClose()) return false; } return true; } void KrViewer::viewGeneric() { PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (pvb) viewInternal(pvb->url(), Generic); } void KrViewer::viewText() { PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (pvb) viewInternal(pvb->url(), Text); } void KrViewer::viewLister() { PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (pvb) viewInternal(pvb->url(), Lister); } void KrViewer::viewHex() { PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (pvb) viewInternal(pvb->url(), Hex); } void KrViewer::editText() { PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (pvb) editInternal(pvb->url(), Text); } void KrViewer::checkModified() { QTimer::singleShot(CHECK_MODFIED_INTERVAL, this, SLOT(checkModified())); PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (pvb) refreshTab(pvb); } void KrViewer::refreshTab(PanelViewerBase* pvb) { int ndx = tabBar.indexOf(pvb); tabBar.setTabText(ndx, makeTabText(pvb)); tabBar.setTabIcon(ndx, makeTabIcon(pvb)); tabBar.setTabToolTip(ndx, makeTabToolTip(pvb)); } void KrViewer::nextTab() { int index = (tabBar.currentIndex() + 1) % tabBar.count(); tabBar.setCurrentIndex(index); } void KrViewer::prevTab() { int index = (tabBar.currentIndex() - 1) % tabBar.count(); while (index < 0) index += tabBar.count(); tabBar.setCurrentIndex(index); } void KrViewer::detachTab() { PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (!pvb) return; KrViewer* viewer = getViewer(true); bool wasPartAdded = false; KParts::ReadOnlyPart *part = pvb->part(); if (part && isPartAdded(part)) { wasPartAdded = true; removePart(part); } disconnect(pvb, 0, this, 0); tabBar.removeTab(tabBar.indexOf(pvb)); if (tabBar.count() == 1) { //no point in detaching only one tab.. detachAction->setEnabled(false); } pvb->setParent(&viewer->tabBar); pvb->move(QPoint(0, 0)); viewer->addTab(pvb); if (wasPartAdded) { viewer->addPart(part); if (part->widget()) part->widget()->setFocus(); } viewer->show(); } void KrViewer::changeEvent(QEvent *e) { if (e->type() == QEvent::ActivationChange && isActiveWindow()) if (viewers.removeAll(this)) viewers.prepend(this); // move to first } void KrViewer::print() { PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (!pvb || !pvb->part() || !isPartAdded(pvb->part())) return; KParts::BrowserExtension * ext = KParts::BrowserExtension::childObject(pvb->part()); if (ext && ext->isActionEnabled("print")) Invoker(ext, SLOT(print())).invoke(); } void KrViewer::copy() { PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (!pvb || !pvb->part() || !isPartAdded(pvb->part())) return; KParts::BrowserExtension * ext = KParts::BrowserExtension::childObject(pvb->part()); if (ext && ext->isActionEnabled("copy")) Invoker(ext, SLOT(copy())).invoke(); } void KrViewer::updateActions() { QList actList = toolBar()->actions(); bool hasPrint = false, hasCopy = false; foreach(QAction *a, actList) { if (a->text() == printAction->text()) hasPrint = true; if (a->text() == copyAction->text()) hasCopy = true; } if (!hasPrint) toolBar()->addAction(printAction->icon(), printAction->text(), this, SLOT(print())); if (!hasCopy) toolBar()->addAction(copyAction->icon(), copyAction->text(), this, SLOT(copy())); } bool KrViewer::isPartAdded(KParts::Part* part) { return manager.parts().contains(part); } void KrViewer::resizeEvent(QResizeEvent *e) { if (!isMaximized()) { sizeX = e->size().width(); sizeY = e->size().height(); } KParts::MainWindow::resizeEvent(e); } QString KrViewer::makeTabText(PanelViewerBase *pvb) { QString fileName = pvb->url().fileName(); if (pvb->isModified()) fileName.prepend("*"); return pvb->isEditor() ? i18nc("filename (filestate)", "%1 (Editing)", fileName) : i18nc("filename (filestate)", "%1 (Viewing)", fileName); } QString KrViewer::makeTabToolTip(PanelViewerBase *pvb) { QString url = pvb->url().toDisplayString(QUrl::PreferLocalFile); return pvb->isEditor() ? i18nc("filestate: filename", "Editing: %1", url) : i18nc("filestate: filename", "Viewing: %1", url); } QIcon KrViewer::makeTabIcon(PanelViewerBase *pvb) { QString iconName; if (pvb->isModified()) iconName = MODIFIED_ICON; else if (pvb->isEditor()) iconName = EDIT_ICON; else iconName = VIEW_ICON; return Icon(iconName); } void KrViewer::addPart(KParts::ReadOnlyPart *part) { Q_ASSERT(part); Q_ASSERT(!isPartAdded(part)); if (isPartAdded(part)) { qDebug()<<"part already added:"<installEventFilter(this); manager.addPart(part, false); // don't automatically set active part } void KrViewer::removePart(KParts::ReadOnlyPart *part) { Q_ASSERT(part); Q_ASSERT(isPartAdded(part)); if (isPartAdded(part)) { disconnect(part, 0, this, 0); part->removeEventFilter(this); manager.removePart(part); } else qDebug()<<"part hasn't been added:"<openUrl(url); } void KrViewer::editInternal(QUrl url, Mode mode, QWidget * parent) { returnFocusTo = parent; PanelViewerBase* editWidget = new PanelEditor(&tabBar, mode); addTab(editWidget); editWidget->openUrl(url); } diff --git a/krusader/Konfigurator/kggeneral.cpp b/krusader/Konfigurator/kggeneral.cpp index cb6d9411..b3ecc62e 100644 --- a/krusader/Konfigurator/kggeneral.cpp +++ b/krusader/Konfigurator/kggeneral.cpp @@ -1,332 +1,331 @@ /***************************************************************************** * Copyright (C) 2004 Csaba Karai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "kggeneral.h" // QtCore #include // QtGui #include #include // QtWidgets #include #include #include #include #include #include #include #include #include "krresulttabledialog.h" #include "../defaults.h" #include "../icon.h" -#include "../kicons.h" #include "../krglobal.h" #define PAGE_GENERAL 0 #define PAGE_VIEWER 1 #define PAGE_EXTENSIONS 2 KgGeneral::KgGeneral(bool first, QWidget* parent) : KonfiguratorPage(first, parent) { if (first) slotFindTools(); tabWidget = new QTabWidget(this); setWidget(tabWidget); setWidgetResizable(true); createGeneralTab(); createViewerTab(); createExtensionsTab(); } QWidget* KgGeneral::createTab(QString name) { QScrollArea *scrollArea = new QScrollArea(tabWidget); tabWidget->addTab(scrollArea, name); scrollArea->setFrameStyle(QFrame::NoFrame); scrollArea->setWidgetResizable(true); QWidget *tab = new QWidget(scrollArea); scrollArea->setWidget(tab); return tab; } void KgGeneral::createViewerTab() { QWidget *tab = createTab(i18n("Viewer/Editor")); QGridLayout *tabLayout = new QGridLayout(tab); tabLayout->setSpacing(6); tabLayout->setContentsMargins(11, 11, 11, 11); tabLayout->addWidget(createCheckBox("General", "View In Separate Window", _ViewInSeparateWindow, i18n("Internal editor and viewer opens each file in a separate window"), tab, false, i18n("If checked, each file will open in a separate window, otherwise, the viewer will work in a single, tabbed mode"), PAGE_VIEWER)); // ------------------------- viewer ---------------------------------- QGroupBox *viewerGrp = createFrame(i18n("Viewer"), tab); tabLayout->addWidget(viewerGrp, 1, 0); QGridLayout *viewerGrid = createGridLayout(viewerGrp); QWidget * hboxWidget2 = new QWidget(viewerGrp); QHBoxLayout * hbox2 = new QHBoxLayout(hboxWidget2); QWidget * vboxWidget = new QWidget(hboxWidget2); QVBoxLayout * vbox = new QVBoxLayout(vboxWidget); vbox->addWidget(new QLabel(i18n("Default viewer mode:"), vboxWidget)); KONFIGURATOR_NAME_VALUE_TIP viewMode[] = // name value tooltip {{ i18n("Generic mode"), "generic", i18n("Use the system's default viewer") }, { i18n("Text mode"), "text", i18n("View the file in text-only mode") }, { i18n("Hex mode"), "hex", i18n("View the file in hex-mode (better for binary files)") }, { i18n("Lister mode"), "lister", i18n("View the file with lister (for huge text files)") } }; vbox->addWidget(createRadioButtonGroup("General", "Default Viewer Mode", "generic", 0, 4, viewMode, 4, vboxWidget, false, PAGE_VIEWER)); vbox->addWidget( createCheckBox("General", "UseOktetaViewer", _UseOktetaViewer, i18n("Use Okteta as Hex viewer"), vboxWidget, false, i18n("If available, use Okteta as Hex viewer instead of the internal viewer"), PAGE_VIEWER) ); QWidget * hboxWidget4 = new QWidget(vboxWidget); QHBoxLayout * hbox4 = new QHBoxLayout(hboxWidget4); QLabel *label5 = new QLabel(i18n("Use lister if the text file is bigger than:"), hboxWidget4); hbox4->addWidget(label5); KonfiguratorSpinBox *spinBox = createSpinBox("General", "Lister Limit", _ListerLimit, 0, 0x7FFFFFFF, hboxWidget4, false, PAGE_VIEWER); hbox4->addWidget(spinBox); QLabel *label6 = new QLabel(i18n("MB"), hboxWidget4); hbox4->addWidget(label6); vbox->addWidget(hboxWidget4); hbox2->addWidget(vboxWidget); viewerGrid->addWidget(hboxWidget2, 0, 0); // ------------------------- editor ---------------------------------- QGroupBox *editorGrp = createFrame(i18n("Editor"), tab); tabLayout->addWidget(editorGrp, 2, 0); QGridLayout *editorGrid = createGridLayout(editorGrp); QLabel *label1 = new QLabel(i18n("Editor:"), editorGrp); editorGrid->addWidget(label1, 0, 0); KonfiguratorURLRequester *urlReq = createURLRequester("General", "Editor", "internal editor", editorGrp, false, PAGE_VIEWER, false); editorGrid->addWidget(urlReq, 0, 1); QLabel *label2 = new QLabel(i18n("Hint: use 'internal editor' if you want to use Krusader's fast built-in editor"), editorGrp); editorGrid->addWidget(label2, 1, 0, 1, 2); } void KgGeneral::createExtensionsTab() { // ------------------------- atomic extensions ---------------------------------- QWidget *tab = createTab(i18n("Atomic extensions")); QGridLayout *tabLayout = new QGridLayout(tab); tabLayout->setSpacing(6); tabLayout->setContentsMargins(11, 11, 11, 11); QWidget * vboxWidget2 = new QWidget(tab); tabLayout->addWidget(vboxWidget2); QVBoxLayout * vbox2 = new QVBoxLayout(vboxWidget2); QWidget * hboxWidget3 = new QWidget(vboxWidget2); vbox2->addWidget(hboxWidget3); QHBoxLayout * hbox3 = new QHBoxLayout(hboxWidget3); QLabel * atomLabel = new QLabel(i18n("Atomic extensions:"), hboxWidget3); hbox3->addWidget(atomLabel); int size = QFontMetrics(atomLabel->font()).height(); QToolButton *addButton = new QToolButton(hboxWidget3); hbox3->addWidget(addButton); QPixmap icon = Icon("list-add").pixmap(size); addButton->setFixedSize(icon.width() + 4, icon.height() + 4); addButton->setIcon(QIcon(icon)); connect(addButton, SIGNAL(clicked()), this, SLOT(slotAddExtension())); QToolButton *removeButton = new QToolButton(hboxWidget3); hbox3->addWidget(removeButton); icon = Icon("list-remove").pixmap(size); removeButton->setFixedSize(icon.width() + 4, icon.height() + 4); removeButton->setIcon(QIcon(icon)); connect(removeButton, SIGNAL(clicked()), this, SLOT(slotRemoveExtension())); QStringList defaultAtomicExtensions; defaultAtomicExtensions += ".tar.gz"; defaultAtomicExtensions += ".tar.bz2"; defaultAtomicExtensions += ".tar.lzma"; defaultAtomicExtensions += ".tar.xz"; defaultAtomicExtensions += ".moc.cpp"; listBox = createListBox("Look&Feel", "Atomic Extensions", defaultAtomicExtensions, vboxWidget2, true, PAGE_EXTENSIONS); vbox2->addWidget(listBox); } void KgGeneral::createGeneralTab() { QWidget *tab = createTab(i18n("General")); QGridLayout *kgGeneralLayout = new QGridLayout(tab); kgGeneralLayout->setSpacing(6); kgGeneralLayout->setContentsMargins(11, 11, 11, 11); // -------------------------- GENERAL GROUPBOX ---------------------------------- QGroupBox *generalGrp = createFrame(i18n("General"), tab); QGridLayout *generalGrid = createGridLayout(generalGrp); KONFIGURATOR_CHECKBOX_PARAM settings[] = { // cfg_class cfg_name default text restart tooltip {"Look&Feel", "Warn On Exit", _WarnOnExit, i18n("Warn on exit"), false, i18n("Display a warning when trying to close the main window.") }, // KDE4: move warn on exit to the other confirmations {"Look&Feel", "Minimize To Tray", _ShowTrayIcon, i18n("Show and close to tray"), false, i18n("Show an icon in the system tray and keep running in the background when the window is closed.") }, }; KonfiguratorCheckBoxGroup *cbs = createCheckBoxGroup(2, 0, settings, 2 /*count*/, generalGrp, PAGE_GENERAL); generalGrid->addWidget(cbs, 0, 0); // temp dir QHBoxLayout *hbox = new QHBoxLayout(); hbox->addWidget(new QLabel(i18n("Temp Folder:"), generalGrp)); KonfiguratorURLRequester *urlReq3 = createURLRequester("General", "Temp Directory", _TempDirectory, generalGrp, false, PAGE_GENERAL); urlReq3->setMode(KFile::Directory); connect(urlReq3->extension(), SIGNAL(applyManually(QObject*,QString,QString)), this, SLOT(applyTempDir(QObject*,QString,QString))); hbox->addWidget(urlReq3); generalGrid->addLayout(hbox, 13, 0, 1, 1); QLabel *label4 = new QLabel(i18n("Note: you must have full permissions for the temporary folder."), generalGrp); generalGrid->addWidget(label4, 14, 0, 1, 1); kgGeneralLayout->addWidget(generalGrp, 0 , 0); // ----------------------- delete mode -------------------------------------- QGroupBox *delGrp = createFrame(i18n("Delete mode"), tab); QGridLayout *delGrid = createGridLayout(delGrp); KONFIGURATOR_NAME_VALUE_TIP deleteMode[] = // name value tooltip {{i18n("Move to trash"), "true", i18n("Files will be moved to trash when deleted.")}, {i18n("Delete files"), "false", i18n("Files will be permanently deleted.")} }; KonfiguratorRadioButtons *trashRadio = createRadioButtonGroup("General", "Move To Trash", _MoveToTrash ? "true" : "false", 2, 0, deleteMode, 2, delGrp, false, PAGE_GENERAL); delGrid->addWidget(trashRadio); kgGeneralLayout->addWidget(delGrp, 1 , 0); // ----------------------- terminal ----------------------------------------- QGroupBox *terminalGrp = createFrame(i18n("Terminal"), tab); QGridLayout *terminalGrid = createGridLayout(terminalGrp); QLabel *label3 = new QLabel(i18n("External Terminal:"), generalGrp); terminalGrid->addWidget(label3, 0, 0); KonfiguratorURLRequester *urlReq2 = createURLRequester("General", "Terminal", _Terminal, generalGrp, false, PAGE_GENERAL, false); terminalGrid->addWidget(urlReq2, 0, 1); QLabel *terminalLabel = new QLabel(i18n("%d will be replaced by the workdir."), terminalGrp); terminalGrid->addWidget(terminalLabel, 1, 1); KONFIGURATOR_CHECKBOX_PARAM terminal_settings[] = { // cfg_class cfg_name default text restart tooltip {"General", "Send CDs", _SendCDs, i18n("Embedded Terminal sends Chdir on panel change"), false, i18n("When checked, whenever the panel is changed (for example, by pressing Tab), Krusader changes the current folder in the embedded terminal.") }, }; cbs = createCheckBoxGroup(1, 0, terminal_settings, 1 /*count*/, terminalGrp, PAGE_GENERAL); terminalGrid->addWidget(cbs, 2, 0, 1, 2); kgGeneralLayout->addWidget(terminalGrp, 2 , 0); } void KgGeneral::applyTempDir(QObject *obj, QString configGroup, QString name) { KonfiguratorURLRequester *urlReq = (KonfiguratorURLRequester *)obj; QString value = urlReq->url().toDisplayString(QUrl::PreferLocalFile); KConfigGroup(krConfig, configGroup).writeEntry(name, value); } void KgGeneral::slotFindTools() { QPointer dlg = new KrResultTableDialog(this, KrResultTableDialog::Tool, i18n("Search results"), i18n("Searching for tools..."), "tools-wizard", i18n("Make sure to install new tools in your $PATH (e.g. /usr/bin)")); dlg->exec(); delete dlg; } void KgGeneral::slotAddExtension() { bool ok; QString atomExt = QInputDialog::getText(this, i18n("Add new atomic extension"), i18n("Extension:"), QLineEdit::Normal, QString(), &ok); if (ok) { if (!atomExt.startsWith('.') || atomExt.indexOf('.', 1) == -1) KMessageBox::error(krMainWindow, i18n("Atomic extensions must start with '.' and must contain at least one more '.' character."), i18n("Error")); else listBox->addItem(atomExt); } } void KgGeneral::slotRemoveExtension() { QList list = listBox->selectedItems(); for (int i = 0; i != list.count(); i++) listBox->removeItem(list[ i ]->text()); } diff --git a/krusader/Konfigurator/konfigurator.cpp b/krusader/Konfigurator/konfigurator.cpp index 28882ed8..a2b7cb30 100644 --- a/krusader/Konfigurator/konfigurator.cpp +++ b/krusader/Konfigurator/konfigurator.cpp @@ -1,242 +1,241 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * Copyright (C) 2000 Rafi Yanai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "konfigurator.h" #include "../krglobal.h" #include "../icon.h" #include "../Dialogs/krdialogs.h" -#include "../kicons.h" // QtGui #include #include #include #include #include #include #include "../defaults.h" #include "../krusaderview.h" #include "../GUI/kfnkeys.h" // the frames #include "kgstartup.h" #include "kgpanel.h" #include "kggeneral.h" #include "kgadvanced.h" #include "kgarchives.h" #include "kgdependencies.h" #include "kgcolors.h" #include "kguseractions.h" #include "kgprotocols.h" Konfigurator::Konfigurator(bool f, int startPage) : KPageDialog((QWidget *)0), firstTime(f), internalCall(false), sizeX(-1), sizeY(-1) { setWindowTitle(i18n("Konfigurator - Creating Your Own Krusader")); setWindowModality(Qt::ApplicationModal); setFaceType(KPageDialog::List); setStandardButtons(QDialogButtonBox::Help|QDialogButtonBox::RestoreDefaults|QDialogButtonBox::Close| QDialogButtonBox::Apply|QDialogButtonBox::Reset); button(QDialogButtonBox::Apply)->setDefault(true); connect(button(QDialogButtonBox::Close), SIGNAL(clicked()), SLOT(slotClose())); connect(button(QDialogButtonBox::Help), SIGNAL(clicked()), SLOT(slotShowHelp())); connect(button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked()), SLOT(slotRestoreDefaults())); connect(button(QDialogButtonBox::Reset), SIGNAL(clicked()), SLOT(slotReset())); connect(button(QDialogButtonBox::Apply), SIGNAL(clicked()), SLOT(slotApply())); connect(this, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), this, SLOT(slotPageSwitch(KPageWidgetItem*,KPageWidgetItem*))); connect(&restoreTimer, SIGNAL(timeout()), this, SLOT(slotRestorePage())); createLayout(startPage); KConfigGroup group(krConfig, "Konfigurator"); int sx = group.readEntry("Window Width", -1); int sy = group.readEntry("Window Height", -1); if (sx != -1 && sy != -1) resize(sx, sy); else resize(900, 680); if (group.readEntry("Window Maximized", false)) showMaximized(); else show(); } void Konfigurator::resizeEvent(QResizeEvent *e) { if (!isMaximized()) { sizeX = e->size().width(); sizeY = e->size().height(); } QDialog::resizeEvent(e); } void Konfigurator::closeDialog() { KConfigGroup group(krConfig, "Konfigurator"); group.writeEntry("Window Width", sizeX); group.writeEntry("Window Height", sizeY); group.writeEntry("Window Maximized", isMaximized()); } void Konfigurator::reject() { closeDialog(); QDialog::reject(); } void Konfigurator::newPage(KonfiguratorPage *page, const QString &name, const QString &desc, const QIcon &icon) { KPageWidgetItem *item = new KPageWidgetItem(page, name); item->setIcon(icon); item->setHeader(desc); addPage(item); kgPages.append(item); connect(page, SIGNAL(sigChanged()), this, SLOT(slotApplyEnable())); } void Konfigurator::createLayout(int startPage) { // startup newPage(new KgStartup(firstTime, this), i18n("Startup"), i18n("Krusader's settings upon startup"), Icon("go-home")); // panel newPage(new KgPanel(firstTime, this), i18n("Panel"), i18n("Panel"), Icon("view-choose")); // colors newPage(new KgColors(firstTime, this), i18n("Colors"), i18n("Colors"), Icon("color-picker")); // general newPage(new KgGeneral(firstTime, this), i18n("General"), i18n("Basic Operations"), Icon("system-run")); // advanced newPage(new KgAdvanced(firstTime, this), i18n("Advanced"), i18n("Be sure you know what you are doing."), Icon("dialog-messages")); // archives newPage(new KgArchives(firstTime, this), i18n("Archives"), i18n("Customize the way Krusader deals with archives"), Icon("archive-extract")); // dependencies newPage(new KgDependencies(firstTime, this), i18n("Dependencies"), i18n("Set the full path of the external applications"), Icon("debug-run")); // useractions newPage(new KgUserActions(firstTime, this), i18n("User Actions"), i18n("Configure your personal actions"), Icon("user-properties")); // protocols newPage(new KgProtocols(firstTime, this), i18n("Protocols"), i18n("Link MIMEs to protocols"), Icon("document-preview")); setCurrentPage(kgPages.at(startPage)); slotApplyEnable(); } void Konfigurator::closeEvent(QCloseEvent *event) { lastPage = currentPage(); if(slotPageSwitch(lastPage, lastPage)) { hide(); KPageDialog::closeEvent(event); } else event->ignore(); } void Konfigurator::slotApplyEnable() { lastPage = currentPage(); bool isChanged = ((KonfiguratorPage *)(lastPage->widget()))->isChanged(); button(QDialogButtonBox::Apply)->setEnabled(isChanged); button(QDialogButtonBox::Reset)->setEnabled(isChanged); } bool Konfigurator::slotPageSwitch(KPageWidgetItem *current, KPageWidgetItem *before) { if (before == 0) return true; KonfiguratorPage *currentPg = (KonfiguratorPage *)(before->widget()); if (internalCall) { internalCall = false; return true; } if (currentPg->isChanged()) { int result = KMessageBox::questionYesNoCancel(0, i18n("The current page has been changed. Do you want to apply changes?")); switch (result) { case KMessageBox::No: currentPg->loadInitialValues(); currentPg->apply(); break; case KMessageBox::Yes: emit configChanged(currentPg->apply()); break; default: restoreTimer.setSingleShot(true); restoreTimer.start(0); return false; } } button(QDialogButtonBox::Apply)->setEnabled(currentPg->isChanged()); lastPage = current; return true; } void Konfigurator::slotRestorePage() { if (lastPage != currentPage()) { internalCall = true; setCurrentPage(lastPage); } } void Konfigurator::slotClose() { lastPage = currentPage(); if (slotPageSwitch(lastPage, lastPage)) { reject(); } } void Konfigurator::slotApply() { emit configChanged(((KonfiguratorPage*)(currentPage()->widget()))->apply()); } void Konfigurator::slotReset() { ((KonfiguratorPage *)(currentPage()->widget()))->loadInitialValues(); } void Konfigurator::slotRestoreDefaults() { ((KonfiguratorPage *)(currentPage()->widget()))->setDefaults(); } void Konfigurator::slotShowHelp() { KHelpClient::invokeHelp(QStringLiteral("konfigurator")); } diff --git a/krusader/Locate/locate.cpp b/krusader/Locate/locate.cpp index 172e4cde..825a7c42 100644 --- a/krusader/Locate/locate.cpp +++ b/krusader/Locate/locate.cpp @@ -1,693 +1,692 @@ /***************************************************************************** * Copyright (C) 2004 Csaba Karai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "locate.h" #include "../kractions.h" #include "../krglobal.h" -#include "../icon.h" +#include "../filelisticon.h" #include "../krslots.h" #include "../krusaderview.h" #include "../Panel/krpanel.h" #include "../Panel/panelfunc.h" #include "../GUI/krtreewidget.h" #include "../defaults.h" #include "../krservices.h" #include "../FileSystem/filesystem.h" #include "../FileSystem/virtualfilesystem.h" #include "../KViewer/krviewer.h" #include "../panelmanager.h" -#include "../kicons.h" // QtCore #include #include #include #include // QtGui #include #include #include #include #include #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // these are the values that will exist in the menu #define VIEW_ID 90 #define EDIT_ID 91 #define FIND_ID 92 #define FIND_NEXT_ID 93 #define FIND_PREV_ID 94 #define COPY_SELECTED_TO_CLIPBOARD 95 #define COMPARE_ID 96 ////////////////////////////////////////////////////////// class LocateListView : public KrTreeWidget { public: explicit LocateListView(QWidget * parent) : KrTreeWidget(parent) { setAlternatingRowColors(true); } void startDrag(Qt::DropActions supportedActs) { Q_UNUSED(supportedActs); QList urls; QList list = selectedItems(); QListIterator it(list); while (it.hasNext()) { QTreeWidgetItem * item = it.next(); urls.push_back(QUrl::fromLocalFile(item->text(0))); } if (urls.count() == 0) return; QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; - mimeData->setImageData(FL_LOADICON("file")); + mimeData->setImageData(FileListIcon("file").pixmap()); mimeData->setUrls(urls); drag->setMimeData(mimeData); drag->start(); } }; KProcess * LocateDlg::updateProcess = 0; LocateDlg * LocateDlg::LocateDialog = 0; LocateDlg::LocateDlg() : QDialog(0), isFeedToListBox(false) { setWindowTitle(i18n("Krusader::Locate")); setWindowModality(Qt::NonModal); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QGridLayout *grid = new QGridLayout(); grid->setSpacing(6); grid->setContentsMargins(11, 11, 11, 11); QWidget *hboxWidget = new QWidget(this); QHBoxLayout *hbox = new QHBoxLayout(hboxWidget); hbox->setContentsMargins(0, 0, 0, 0); QLabel *label = new QLabel(i18n("Search for:"), hboxWidget); hbox->addWidget(label); locateSearchFor = new KHistoryComboBox(false, hboxWidget); locateSearchFor->setMinimumContentsLength(10); hbox->addWidget(locateSearchFor); label->setBuddy(locateSearchFor); KConfigGroup group(krConfig, "Locate"); QStringList list = group.readEntry("Search For", QStringList()); locateSearchFor->setMaxCount(25); // remember 25 items locateSearchFor->setHistoryItems(list); locateSearchFor->setEditable(true); locateSearchFor->setDuplicatesEnabled(false); locateSearchFor->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); locateSearchFor->lineEdit()->setFocus(); grid->addWidget(hboxWidget, 0, 0); QWidget *hboxWidget2 = new QWidget(this); QHBoxLayout * hbox2 = new QHBoxLayout(hboxWidget2); hbox2->setContentsMargins(0, 0, 0, 0); QSpacerItem* spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); hbox2->addItem(spacer); dontSearchInPath = new QCheckBox(i18n("Do not search in path"), hboxWidget2); hbox2->addWidget(dontSearchInPath); dontSearchInPath->setChecked(group.readEntry("Don't Search In Path", false)); existingFiles = new QCheckBox(i18n("Show only the existing files"), hboxWidget2); existingFiles->setChecked(group.readEntry("Existing Files", false)); hbox2->addWidget(existingFiles); caseSensitive = new QCheckBox(i18n("Case Sensitive"), hboxWidget2); caseSensitive->setChecked(group.readEntry("Case Sensitive", false)); hbox2->addWidget(caseSensitive); grid->addWidget(hboxWidget2, 1, 0); QFrame *line1 = new QFrame(this); line1->setFrameStyle(QFrame::HLine | QFrame::Sunken); grid->addWidget(line1, 2, 0); resultList = new LocateListView(this); // create the main container resultList->setColumnCount(1); resultList->setHeaderLabel(i18n("Results")); resultList->setColumnWidth(0, QFontMetrics(resultList->font()).width("W") * 60); KConfigGroup gl(krConfig, "Look&Feel"); resultList->setFont(gl.readEntry("Filelist Font", _FilelistFont)); resultList->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); resultList->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); resultList->header()->setSortIndicatorShown(false); resultList->setSortingEnabled(false); resultList->setSelectionMode(QAbstractItemView::ExtendedSelection); resultList->setDragEnabled(true); connect(resultList, SIGNAL(itemRightClicked(QTreeWidgetItem*,QPoint,int)), this, SLOT(slotRightClick(QTreeWidgetItem*,QPoint))); connect(resultList, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(slotDoubleClick(QTreeWidgetItem*))); connect(resultList, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(slotDoubleClick(QTreeWidgetItem*))); grid->addWidget(resultList, 3, 0); QFrame *line2 = new QFrame(this); line2->setFrameStyle(QFrame::HLine | QFrame::Sunken); grid->addWidget(line2, 4, 0); mainLayout->addLayout(grid); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); mainLayout->addWidget(buttonBox); locateButton = new QPushButton(i18n("Locate")); locateButton->setIcon(Icon(QStringLiteral("system-search"))); locateButton->setDefault(true); buttonBox->addButton(locateButton, QDialogButtonBox::ActionRole); updateDbButton = new QPushButton(i18n("Update DB")); updateDbButton->setIcon(Icon(QStringLiteral("view-refresh"))); buttonBox->addButton(updateDbButton, QDialogButtonBox::ActionRole); feedStopButton = new QPushButton; buttonBox->addButton(feedStopButton, QDialogButtonBox::ActionRole); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(locateButton, SIGNAL(clicked()), this, SLOT(slotLocate())); connect(updateDbButton, SIGNAL(clicked()), this, SLOT(slotUpdateDb())); connect(feedStopButton, SIGNAL(clicked()), this, SLOT(slotFeedStop())); updateButtons(false); if (updateProcess) { if (updateProcess->state() == QProcess::Running) { connect(updateProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(updateFinished())); updateDbButton->setEnabled(false); } else updateFinished(); } show(); LocateDialog = this; } void LocateDlg::slotFeedStop() /* The stop / feed to listbox button */ { if (isFeedToListBox) feedToListBox(); else locateProc->kill(); } void LocateDlg::slotUpdateDb() /* The Update DB button */ { if (!updateProcess) { KConfigGroup group(krConfig, "Locate"); updateProcess = new KProcess(); // don't set the parent to 'this'! That would cause this process to be deleted once the dialog is closed *updateProcess << KrServices::fullPathName("updatedb"); *updateProcess << KShell::splitArgs(group.readEntry("UpdateDB Arguments")); connect(updateProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(updateFinished())); updateProcess->start(); updateDbButton->setEnabled(false); } } void LocateDlg::updateFinished() { delete updateProcess; updateProcess = 0; updateDbButton->setEnabled(true); } void LocateDlg::slotLocate() /* The locate button */ { locateSearchFor->addToHistory(locateSearchFor->currentText()); QStringList list = locateSearchFor->historyItems(); KConfigGroup group(krConfig, "Locate"); group.writeEntry("Search For", list); group.writeEntry("Don't Search In Path", dontSearchPath = dontSearchInPath->isChecked()); group.writeEntry("Existing Files", onlyExist = existingFiles->isChecked()); group.writeEntry("Case Sensitive", isCs = caseSensitive->isChecked()); if (!KrServices::cmdExist("locate")) { KMessageBox::error(0, i18n("Cannot start 'locate'. Check the 'Dependencies' page in konfigurator.")); return; } resultList->clear(); lastItem = 0; remaining = ""; updateButtons(true); isFeedToListBox = false; resultList->setFocus(); qApp->processEvents(); //FIXME - whats's this for ? locateProc = new KProcess(this); locateProc->setOutputChannelMode(KProcess::SeparateChannels); // default is forwarding to the parent channels connect(locateProc, SIGNAL(readyReadStandardOutput()), SLOT(processStdout())); connect(locateProc, SIGNAL(readyReadStandardError()), SLOT(processStderr())); connect(locateProc, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(locateFinished())); connect(locateProc, SIGNAL(error(QProcess::ProcessError)), SLOT(locateError())); *locateProc << KrServices::fullPathName("locate"); if (!isCs) *locateProc << "-i"; *locateProc << (pattern = locateSearchFor->currentText()); if (!pattern.startsWith('*')) pattern = '*' + pattern; if (!pattern.endsWith('*')) pattern = pattern + '*'; collectedErr = ""; locateProc->start(); } void LocateDlg::locateError() { if (locateProc->error() == QProcess::FailedToStart) KMessageBox::error(krMainWindow, i18n("Error during the start of 'locate' process.")); } void LocateDlg::locateFinished() { if (locateProc->exitStatus() != QProcess::NormalExit || locateProc->exitStatus()) { if (!collectedErr.isEmpty()) KMessageBox::error(krMainWindow, i18n("Locate produced the following error message:\n\n%1", collectedErr)); } if (resultList->topLevelItemCount() == 0) { locateSearchFor->setFocus(); isFeedToListBox = false; } else { isFeedToListBox = true; } updateButtons(false); } void LocateDlg::processStdout() { remaining += QString::fromLocal8Bit(locateProc->readAllStandardOutput()); QStringList list = remaining.split('\n'); int items = list.size(); for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) { if (--items == 0 && !remaining.endsWith('\n')) remaining = *it; else { if (dontSearchPath) { QRegExp regExp(pattern, isCs ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard); QString fileName = (*it).trimmed(); if (fileName.endsWith(QLatin1String("/")) && fileName != "/") { fileName.truncate(fileName.length() - 1); } fileName = fileName.mid(fileName.lastIndexOf('/') + 1); if (!regExp.exactMatch(fileName)) continue; } if (onlyExist) { KFileItem file(QUrl::fromLocalFile((*it).trimmed())); if (!file.isReadable()) continue; } if (lastItem) lastItem = new QTreeWidgetItem(resultList, lastItem); else lastItem = new QTreeWidgetItem(resultList); lastItem->setText(0, *it); } } } void LocateDlg::processStderr() { collectedErr += QString::fromLocal8Bit(locateProc->readAllStandardError()); } void LocateDlg::slotRightClick(QTreeWidgetItem *item, const QPoint &pos) { if (!item) return; // create the menu QMenu popup; popup.setTitle(i18nc("@title:menu", "Locate")); QAction * actView = popup.addAction(i18n("View (F3)")); QAction * actEdit = popup.addAction(i18n("Edit (F4)")); QAction * actComp = popup.addAction(i18n("Compare by content (F10)")); if (resultList->selectedItems().count() != 2) actComp->setEnabled(false); popup.addSeparator(); QAction * actFind = popup.addAction(i18n("Find (Ctrl+F)")); QAction * actNext = popup.addAction(i18n("Find next (Ctrl+N)")); QAction * actPrev = popup.addAction(i18n("Find previous (Ctrl+P)")); popup.addSeparator(); QAction * actClip = popup.addAction(i18n("Copy selected to clipboard")); QAction * result = popup.exec(pos); int ret = -1; if (result == actView) ret = VIEW_ID; else if (result == actEdit) ret = EDIT_ID; else if (result == actFind) ret = FIND_ID; else if (result == actNext) ret = FIND_NEXT_ID; else if (result == actPrev) ret = FIND_PREV_ID; else if (result == actClip) ret = COPY_SELECTED_TO_CLIPBOARD; else if (result == actComp) ret = COMPARE_ID; if (ret != - 1) operate(item, ret); } void LocateDlg::slotDoubleClick(QTreeWidgetItem *item) { if (!item) return; QString dirName = item->text(0); QString fileName; if (!QDir(dirName).exists()) { fileName = dirName.mid(dirName.lastIndexOf('/') + 1); dirName.truncate(dirName.lastIndexOf('/')); } ACTIVE_FUNC->openUrl(QUrl::fromLocalFile(dirName), fileName); QDialog::accept(); } void LocateDlg::keyPressEvent(QKeyEvent *e) { if (KrGlobal::copyShortcut == QKeySequence(e->key() | e->modifiers())) { operate(0, COPY_SELECTED_TO_CLIPBOARD); e->accept(); return; } switch (e->key()) { case Qt::Key_M : if (e->modifiers() == Qt::ControlModifier) { resultList->setFocus(); e->accept(); } break; case Qt::Key_F3 : if (resultList->currentItem()) operate(resultList->currentItem(), VIEW_ID); break; case Qt::Key_F4 : if (resultList->currentItem()) operate(resultList->currentItem(), EDIT_ID); break; case Qt::Key_F10 : operate(0, COMPARE_ID); break; case Qt::Key_N : if (e->modifiers() == Qt::ControlModifier) operate(resultList->currentItem(), FIND_NEXT_ID); break; case Qt::Key_P : if (e->modifiers() == Qt::ControlModifier) operate(resultList->currentItem(), FIND_PREV_ID); break; case Qt::Key_F : if (e->modifiers() == Qt::ControlModifier) operate(resultList->currentItem(), FIND_ID); break; } QDialog::keyPressEvent(e); } void LocateDlg::operate(QTreeWidgetItem *item, int task) { QUrl name; if (item != 0) name = QUrl::fromLocalFile(item->text(0)); switch (task) { case VIEW_ID: KrViewer::view(name, this); // view the file break; case EDIT_ID: KrViewer::edit(name, this); // view the file break; case COMPARE_ID: { QList list = resultList->selectedItems(); if (list.count() != 2) break; QUrl url1 = QUrl::fromLocalFile(list[ 0 ]->text(0)); QUrl url2 = QUrl::fromLocalFile(list[ 1 ]->text(0)); SLOTS->compareContent(url1,url2); } break; case FIND_ID: { KConfigGroup group(krConfig, "Locate"); long options = group.readEntry("Find Options", (long long)0); QStringList list = group.readEntry("Find Patterns", QStringList()); QPointer dlg = new KFindDialog(this, options, list); if (dlg->exec() != QDialog::Accepted) { delete dlg; return; } QString first; if (list.count() != 0) { first = list.first(); } if (first != (findPattern = dlg->pattern())) { list.push_front(dlg->pattern()); } group.writeEntry("Find Options", (long long)(findOptions = dlg->options())); group.writeEntry("Find Patterns", list); if (!(findOptions & KFind::FromCursor) && resultList->topLevelItemCount()) resultList->setCurrentItem((findOptions & KFind::FindBackwards) ? resultList->topLevelItem(resultList->topLevelItemCount() - 1) : resultList->topLevelItem(0)); findCurrentItem = resultList->currentItem(); if (find() && findCurrentItem) { resultList->selectionModel()->clearSelection(); // HACK: QT 4 is not able to paint the focus frame because of a bug resultList->setCurrentItem(findCurrentItem); } else { KMessageBox::information(this, i18n("Search string not found.")); } resultList->scrollTo(resultList->currentIndex()); delete dlg; } break; case FIND_NEXT_ID: case FIND_PREV_ID: { if (task == FIND_PREV_ID) findOptions ^= KFind::FindBackwards; findCurrentItem = resultList->currentItem(); nextLine(); if (find() && findCurrentItem) { resultList->selectionModel()->clearSelection(); // HACK: QT 4 is not able to paint the focus frame because of a bug resultList->setCurrentItem(findCurrentItem); } else KMessageBox::information(this, i18n("Search string not found.")); resultList->scrollTo(resultList->currentIndex()); if (task == FIND_PREV_ID) findOptions ^= KFind::FindBackwards; } break; case COPY_SELECTED_TO_CLIPBOARD: { QList urls; QTreeWidgetItemIterator it(resultList); while (*it) { if ((*it)->isSelected()) urls.push_back(QUrl::fromLocalFile((*it)->text(0))); it++; } if (urls.count() == 0) return; QMimeData *mimeData = new QMimeData; - mimeData->setImageData(FL_LOADICON("file")); + mimeData->setImageData(FileListIcon("file").pixmap()); mimeData->setUrls(urls); QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); } break; } } void LocateDlg::nextLine() { if (findOptions & KFind::FindBackwards) findCurrentItem = resultList->itemAbove(findCurrentItem); else findCurrentItem = resultList->itemBelow(findCurrentItem); } bool LocateDlg::find() { while (findCurrentItem) { QString item = findCurrentItem->text(0); if (findOptions & KFind::RegularExpression) { if (item.contains(QRegExp(findPattern, ((findOptions & KFind::CaseSensitive) != 0) ? Qt::CaseSensitive : Qt::CaseInsensitive))) return true; } else { if (item.contains(findPattern, ((findOptions & KFind::CaseSensitive) != 0) ? Qt::CaseSensitive : Qt::CaseInsensitive)) return true; } nextLine(); } return false; } void LocateDlg::feedToListBox() { VirtualFileSystem virtFilesystem; virtFilesystem.scanDir(QUrl::fromLocalFile(QStringLiteral("/"))); KConfigGroup group(krConfig, "Locate"); int listBoxNum = group.readEntry("Feed To Listbox Counter", 1); QString queryName; do { queryName = i18n("Locate results") + QString(" %1").arg(listBoxNum++); } while (virtFilesystem.getFileItem(queryName) != 0); group.writeEntry("Feed To Listbox Counter", listBoxNum); KConfigGroup ga(krConfig, "Advanced"); if (ga.readEntry("Confirm Feed to Listbox", _ConfirmFeedToListbox)) { bool ok; queryName = QInputDialog::getText(this, i18n("Query Name"), i18n("Here you can name the file collection:"), QLineEdit::Normal, queryName, &ok); if (! ok) return; } QList urlList; QTreeWidgetItemIterator it(resultList); while (*it) { QTreeWidgetItem * item = *it; urlList.push_back(QUrl::fromLocalFile(item->text(0))); it++; } QUrl url = QUrl(QStringLiteral("virt:/") + queryName); virtFilesystem.refresh(url); // create directory if it does not exist virtFilesystem.addFiles(urlList); //ACTIVE_FUNC->openUrl(url); ACTIVE_MNG->slotNewTab(url); accept(); } void LocateDlg::reset() { locateSearchFor->lineEdit()->setFocus(); locateSearchFor->lineEdit()->selectAll(); } void LocateDlg::updateButtons(bool locateIsRunning) { locateButton->setEnabled(!locateIsRunning); if (locateIsRunning) { feedStopButton->setEnabled(true); feedStopButton->setText(i18n("Stop")); feedStopButton->setIcon(Icon(QStringLiteral("process-stop"))); } else { if (resultList->topLevelItemCount() == 0) { feedStopButton->setEnabled(false); feedStopButton->setText(i18n("Stop")); feedStopButton->setIcon(Icon(QStringLiteral("process-stop"))); } else { feedStopButton->setEnabled(true); feedStopButton->setText(i18n("Feed to listbox")); feedStopButton->setIcon(Icon(QStringLiteral("list-add"))); } } } diff --git a/krusader/MountMan/kmountmangui.cpp b/krusader/MountMan/kmountmangui.cpp index 183962ae..a3ae8dbf 100644 --- a/krusader/MountMan/kmountmangui.cpp +++ b/krusader/MountMan/kmountmangui.cpp @@ -1,532 +1,531 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * Copyright (C) 2000 Rafi Yanai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "kmountmangui.h" #include "../krglobal.h" #include "../icon.h" #include "../Dialogs/krspecialwidgets.h" -#include "../kicons.h" #include "../defaults.h" #include "../FileSystem/filesystem.h" // QtCore #include #include #include // QtGui #include #include #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef BSD #define MTAB "/etc/mtab" #endif KMountManGUI::KMountManGUI(KMountMan *mntMan) : QDialog(mntMan->parentWindow), mountMan(mntMan), info(0), mountList(0), cbShowOnlyRemovable(0), watcher(0), sizeX(-1), sizeY(-1) { setWindowTitle(i18n("MountMan - Your Mount-Manager")); setWindowModality(Qt::WindowModal); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); watcher = new QTimer(this); connect(watcher, SIGNAL(timeout()), this, SLOT(checkMountChange())); mainLayout->addLayout(createMainPage()); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); mainLayout->addWidget(buttonBox); ejectButton = new QPushButton(i18n("&Eject")); ejectButton->setIcon(Icon(QStringLiteral("media-eject"))); ejectButton->setEnabled(false); buttonBox->addButton(ejectButton, QDialogButtonBox::ActionRole); mountButton = new QPushButton(i18n("&Unmount")); mountButton->setEnabled(false); buttonBox->addButton(mountButton, QDialogButtonBox::ActionRole); // connections connect(buttonBox, SIGNAL(rejected()), SLOT(reject())); connect(ejectButton, SIGNAL(clicked()), SLOT(slotEject())); connect(mountButton, SIGNAL(clicked()), SLOT(slotToggleMount())); connect(mountList, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(doubleClicked(QTreeWidgetItem*))); connect(mountList, SIGNAL(itemRightClicked(QTreeWidgetItem*,QPoint,int)), this, SLOT(clicked(QTreeWidgetItem*,QPoint))); connect(mountList, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(changeActive(QTreeWidgetItem*))); connect(mountList, SIGNAL(itemSelectionChanged()), this, SLOT(changeActive())); KConfigGroup group(krConfig, "MountMan"); int sx = group.readEntry("Window Width", -1); int sy = group.readEntry("Window Height", -1); if (sx != -1 && sy != -1) resize(sx, sy); else resize(600, 300); if (group.readEntry("Window Maximized", false)) showMaximized(); else show(); getSpaceData(); exec(); } KMountManGUI::~KMountManGUI() { watcher->stop(); delete watcher; KConfigGroup group(krConfig, "MountMan"); group.writeEntry("Window Width", sizeX); group.writeEntry("Window Height", sizeY); group.writeEntry("Window Maximized", isMaximized()); group.writeEntry("Last State", mountList->header()->saveState()); group.writeEntry("ShowOnlyRemovable", cbShowOnlyRemovable->isChecked()); } void KMountManGUI::resizeEvent(QResizeEvent *e) { if (!isMaximized()) { sizeX = e->size().width(); sizeY = e->size().height(); } QDialog::resizeEvent(e); } QLayout *KMountManGUI::createMainPage() { QGridLayout *layout = new QGridLayout(); layout->setSpacing(10); mountList = new KrTreeWidget(this); // create the main container KConfigGroup grp(krConfig, "Look&Feel"); mountList->setFont(grp.readEntry("Filelist Font", _FilelistFont)); mountList->setSelectionMode(QAbstractItemView::SingleSelection); mountList->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); mountList->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); QStringList labels; labels << i18n("Name"); labels << i18n("Type"); labels << i18n("Mnt.Point"); labels << i18n("Total Size"); labels << i18n("Free Size"); labels << i18n("Free %"); mountList->setHeaderLabels(labels); mountList->header()->setSectionResizeMode(QHeaderView::Interactive); grp = KConfigGroup(krConfig, "MountMan"); if (grp.hasKey("Last State")) mountList->header()->restoreState(grp.readEntry("Last State", QByteArray())); else { int i = QFontMetrics(mountList->font()).width("W"); int j = QFontMetrics(mountList->font()).width("0"); j = (i > j ? i : j); mountList->setColumnWidth(0, j*8); mountList->setColumnWidth(1, j*4); mountList->setColumnWidth(2, j*8); mountList->setColumnWidth(3, j*6); mountList->setColumnWidth(4, j*6); mountList->setColumnWidth(5, j*5); } mountList->setAllColumnsShowFocus(true); mountList->header()->setSortIndicatorShown(true); mountList->sortItems(0, Qt::AscendingOrder); // now the list is created, time to fill it with data. //=>mountMan->forceUpdate(); QGroupBox *box = new QGroupBox(i18n("MountMan.Info"), this); box->setAlignment(Qt::AlignHCenter); QVBoxLayout *vboxl = new QVBoxLayout(box); info = new KRFSDisplay(box); vboxl->addWidget(info); info->resize(info->width(), height()); cbShowOnlyRemovable = new QCheckBox(i18n("Show only removable devices"), this); cbShowOnlyRemovable->setChecked(grp.readEntry("ShowOnlyRemovable", false)); connect(cbShowOnlyRemovable , SIGNAL(stateChanged(int)), SLOT(updateList())); layout->addWidget(box, 0, 0); layout->addWidget(cbShowOnlyRemovable, 1, 0); layout->addWidget(mountList, 0, 1, 2, 1); return layout; } void KMountManGUI::getSpaceData() { fileSystems.clear(); KrMountDetector::getInstance()->hasMountsChanged(); mounted = KMountPoint::currentMountPoints(); possible = KMountPoint::possibleMountPoints(); if (mounted.size() == 0) { // nothing is mounted addNonMounted(); updateList(); // let's continue return; } for (KMountPoint::List::iterator it = mounted.begin(); it != mounted.end(); ++it) { // don't bother with invalid file systems if (mountMan->invalidFilesystem((*it)->mountType())) { continue; } KDiskFreeSpaceInfo info = KDiskFreeSpaceInfo::freeSpaceInfo((*it) ->mountPoint()); if(!info.isValid()) { continue; } fsData data; data.setMntPoint((*it) ->mountPoint()); data.setMounted(true); data.setTotalBlks(info.size() / 1024); data.setFreeBlks(info.available() / 1024); data.setName((*it)->mountedFrom()); data.setType((*it)->mountType()); fileSystems.append(data); } addNonMounted(); updateList(); } void KMountManGUI::addNonMounted() { // handle the non-mounted ones for (KMountPoint::List::iterator it = possible.begin(); it != possible.end(); ++it) { // make sure we don't add things we've already added if (KMountMan::findInListByMntPoint(mounted, (*it)->mountPoint())) { continue; } else { fsData data; data.setMntPoint((*it)->mountPoint()); data.setMounted(false); data.setType((*it)->mountType()); data.setName((*it)->mountedFrom()); if (mountMan->invalidFilesystem(data.type())) continue; fileSystems.append(data); } } } void KMountManGUI::addItemToMountList(KrTreeWidget *lst, fsData &fs) { Solid::Device device(mountMan->findUdiForPath(fs.mntPoint(), Solid::DeviceInterface::StorageAccess)); if (cbShowOnlyRemovable->isChecked() && !mountMan->removable(device)) return; bool mtd = fs.mounted(); QString tSize = QString("%1").arg(KIO::convertSizeFromKiB(fs.totalBlks())); QString fSize = QString("%1").arg(KIO::convertSizeFromKiB(fs.freeBlks())); QString sPrct = QString("%1%").arg(100 - (fs.usedPerct())); QTreeWidgetItem *item = new QTreeWidgetItem(lst); item->setText(0, fs.name()); item->setText(1, fs.type()); item->setText(2, fs.mntPoint()); item->setText(3, (mtd ? tSize : QString("N/A"))); item->setText(4, (mtd ? fSize : QString("N/A"))); item->setText(5, (mtd ? sPrct : QString("N/A"))); Solid::StorageVolume *vol = device.as (); QString icon; if(device.isValid()) icon = device.icon(); else if(mountMan->networkFilesystem(fs.type())) icon = "folder-remote"; QStringList overlays; if (mtd) { overlays << "emblem-mounted"; } else { overlays << QString(); // We have to guarantee the placement of the next emblem } if (vol && vol->usage() == Solid::StorageVolume::Encrypted) { overlays << "security-high"; } item->setIcon(0, KDE::icon(icon, overlays)); } void KMountManGUI::updateList() { QString currentMP; int currentIdx = 0; QTreeWidgetItem *currentItem = mountList->currentItem(); if(currentItem) { currentMP = getMntPoint(currentItem); currentIdx = mountList->indexOfTopLevelItem(currentItem); } mountList->clearSelection(); mountList->clear(); for (QList::iterator it = fileSystems.begin(); it != fileSystems.end() ; ++it) addItemToMountList(mountList, *it); currentItem = mountList->topLevelItem(currentIdx); for(int i = 0; i < mountList->topLevelItemCount(); i++) { QTreeWidgetItem *item = mountList->topLevelItem(i); if(getMntPoint(item) == currentMP) currentItem = item; } if(!currentItem) currentItem = mountList->topLevelItem(0); mountList->setCurrentItem(currentItem); changeActive(currentItem); mountList->setFocus(); watcher->setSingleShot(true); watcher->start(WATCHER_DELAY); // starting the watch timer ( single shot ) } void KMountManGUI::checkMountChange() { if (KrMountDetector::getInstance()->hasMountsChanged()) getSpaceData(); watcher->setSingleShot(true); watcher->start(WATCHER_DELAY); // starting the watch timer ( single shot ) } void KMountManGUI::doubleClicked(QTreeWidgetItem *i) { if (!i) return; // we don't want to refresh to swap, do we ? // change the active panel to this mountpoint mountMan->emitRefreshPanel(QUrl::fromLocalFile(getMntPoint(i))); close(); } void KMountManGUI::changeActive() { QList seld = mountList->selectedItems(); if (seld.count() > 0) changeActive(seld[ 0 ]); } // when user clicks on a filesystem, change information void KMountManGUI::changeActive(QTreeWidgetItem *i) { if (!i) { if (info) { info->setEmpty(true); info->update(); } mountButton->setEnabled(false); ejectButton->setEnabled(false); return; } fsData *system = getFsData(i); info->setAlias(system->mntPoint()); info->setRealName(system->name()); info->setMounted(system->mounted()); info->setEmpty(false); info->setTotalSpace(system->totalBlks()); info->setFreeSpace(system->freeBlks()); info->repaint(); if(system->mounted()) mountButton->setText(i18n("&Unmount")); else mountButton->setText(i18n("&Mount")); ejectButton->setEnabled(mountMan->ejectable(system->mntPoint())); mountButton->setEnabled(true); } // called when right-clicked on a filesystem void KMountManGUI::clicked(QTreeWidgetItem *item, const QPoint & pos) { // these are the values that will exist in the menu #define MOUNT_ID 90 #define UNMOUNT_ID 91 #define FORMAT_ID 93 #define EJECT_ID 94 ////////////////////////////////////////////////////////// if (!item) return; fsData *system = getFsData(item); // create the menu QMenu popup; popup.setTitle(i18n("MountMan")); if (!system->mounted()) { QAction *mountAct = popup.addAction(i18n("Mount")); mountAct->setData(QVariant(MOUNT_ID)); bool enable = !(mountMan->nonmountFilesystem(system->type(), system->mntPoint())); mountAct->setEnabled(enable); } else { QAction * umountAct = popup.addAction(i18n("Unmount")); umountAct->setData(QVariant(UNMOUNT_ID)); bool enable = !(mountMan->nonmountFilesystem(system->type(), system->mntPoint())); umountAct->setEnabled(enable); } if (mountMan->ejectable(system->mntPoint())) // if (system->type()=="iso9660" || mountMan->followLink(system->name()).left(2)=="cd") popup.addAction(i18n("Eject"))->setData(QVariant(EJECT_ID)); else { QAction *formatAct = popup.addAction(i18n("Format")); formatAct->setData(QVariant(FORMAT_ID)); formatAct->setEnabled(false); } QString mountPoint = system->mntPoint(); QAction * res = popup.exec(pos); int result = -1; if (res && res->data().canConvert()) result = res->data().toInt(); // check out the user's option switch (result) { case - 1 : return ; // the user clicked outside of the menu case MOUNT_ID : case UNMOUNT_ID : mountMan->toggleMount(mountPoint); break; case FORMAT_ID : break; case EJECT_ID : mountMan->eject(mountPoint); break; } } void KMountManGUI::slotToggleMount() { QTreeWidgetItem *item = mountList->currentItem(); if(item) { mountMan->toggleMount(getFsData(item)->mntPoint()); } } void KMountManGUI::slotEject() { QTreeWidgetItem *item = mountList->currentItem(); if(item) { mountMan->eject(getFsData(item)->mntPoint()); } } fsData* KMountManGUI::getFsData(QTreeWidgetItem *item) { for (QList::Iterator it = fileSystems.begin(); it != fileSystems.end(); ++it) { // the only thing which is unique is the mount point if ((*it).mntPoint() == getMntPoint(item)) { return & (*it); } } //this point shouldn't be reached abort(); return 0; } QString KMountManGUI::getMntPoint(QTreeWidgetItem *item) { return item->text(2); // text(2) ? ugly ugly ugly } KrMountDetector::KrMountDetector() { hasMountsChanged(); } bool KrMountDetector::hasMountsChanged() { bool result = false; #ifndef BSD QFileInfo mtabInfo(MTAB); if (!mtabInfo.exists() || mtabInfo.isSymLink()) { // if mtab is a symlimk to /proc/mounts the mtime is unusable #endif KMountPoint::List mountPoints = KMountPoint::currentMountPoints(KMountPoint::NeedRealDeviceName); QCryptographicHash md5(QCryptographicHash::Md5); for (KMountPoint::List::iterator i = mountPoints.begin(); i != mountPoints.end(); ++i) { md5.addData((*i)->mountedFrom().toUtf8()); md5.addData((*i)->realDeviceName().toUtf8()); md5.addData((*i)->mountPoint().toUtf8()); md5.addData((*i)->mountType().toUtf8()); } QString s = md5.result(); result = s != checksum; checksum = s; #ifndef BSD } else { result = mtabInfo.lastModified() != lastMtab; lastMtab = mtabInfo.lastModified(); } #endif return result; } KrMountDetector krMountDetector; KrMountDetector * KrMountDetector::getInstance() { return & krMountDetector; } diff --git a/krusader/Panel/PanelView/krview.cpp b/krusader/Panel/PanelView/krview.cpp index c925dff1..d8148755 100644 --- a/krusader/Panel/PanelView/krview.cpp +++ b/krusader/Panel/PanelView/krview.cpp @@ -1,1224 +1,1223 @@ /***************************************************************************** * Copyright (C) 2000-2002 Shie Erlich * * Copyright (C) 2000-2002 Rafi Yanai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "krview.h" #include "krselectionmode.h" #include "krviewfactory.h" #include "krviewitem.h" #include "../FileSystem/dirlisterinterface.h" #include "../FileSystem/fileitem.h" #include "../FileSystem/krpermhandler.h" #include "../Filter/filterdialog.h" #include "../defaults.h" -#include "../icon.h" -#include "../kicons.h" +#include "../filelisticon.h" #include "../krcolorcache.h" #include "../krglobal.h" #include "../krpreviews.h" #include "../viewactions.h" // QtCore #include #include // QtGui #include #include #include #include // QtWidgets #include #include #include #include #include #include #include #include #define FILEITEM getFileItem() KrView *KrViewOperator::_changedView = 0; KrViewProperties::PropertyType KrViewOperator::_changedProperties = KrViewProperties::NoProperty; // ----------------------------- operator KrViewOperator::KrViewOperator(KrView *view, QWidget *widget) : _view(view), _widget(widget), _massSelectionUpdate(false) { _saveDefaultSettingsTimer.setSingleShot(true); connect(&_saveDefaultSettingsTimer, SIGNAL(timeout()), SLOT(saveDefaultSettings())); } KrViewOperator::~KrViewOperator() { if(_changedView == _view) saveDefaultSettings(); } void KrViewOperator::startUpdate() { _view->refresh(); } void KrViewOperator::cleared() { _view->clear(); } void KrViewOperator::fileAdded(FileItem *fileitem) { _view->addItem(fileitem); } void KrViewOperator::fileUpdated(FileItem *newFileitem) { _view->updateItem(newFileitem); } void KrViewOperator::startDrag() { QStringList items; _view->getSelectedItems(&items); if (items.empty()) return ; // don't drag an empty thing QPixmap px; if (items.count() > 1 || _view->getCurrentKrViewItem() == 0) - px = FL_LOADICON("queue"); // how much are we dragging + px = FileListIcon("queue").pixmap(); // we are dragging multiple items else - px = _view->getCurrentKrViewItem() ->icon(); + px = _view->getCurrentKrViewItem()->icon(); emit letsDrag(items, px); } bool KrViewOperator::searchItem(const QString &text, bool caseSensitive, int direction) { KrViewItem * item = _view->getCurrentKrViewItem(); if (!item) { return false; } const QRegExp regeEx(text, caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard); if (!direction) { if (regeEx.indexIn(item->name()) == 0) { return true; } direction = 1; } KrViewItem * startItem = item; while (true) { item = (direction > 0) ? _view->getNext(item) : _view->getPrev(item); if (!item) item = (direction > 0) ? _view->getFirst() : _view->getLast(); if (regeEx.indexIn(item->name()) == 0) { _view->setCurrentKrViewItem(item); _view->makeItemVisible(item); return true; } if (item == startItem) { return false; } } } bool KrViewOperator::filterSearch(const QString &text, bool caseSensitive) { _view->_quickFilterMask = QRegExp(text, caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard); _view->refresh(); return _view->_count || !_view->_files->numFileItems(); } void KrViewOperator::setMassSelectionUpdate(bool upd) { _massSelectionUpdate = upd; if (!upd) { emit selectionChanged(); _view->redraw(); } } void KrViewOperator::settingsChanged(KrViewProperties::PropertyType properties) { if(!_view->_updateDefaultSettings || _view->_ignoreSettingsChange) return; if(_changedView != _view) saveDefaultSettings(); _changedView = _view; _changedProperties = static_cast(_changedProperties | properties); _saveDefaultSettingsTimer.start(100); } void KrViewOperator::saveDefaultSettings() { _saveDefaultSettingsTimer.stop(); if(_changedView) _changedView->saveDefaultSettings(_changedProperties); _changedProperties = KrViewProperties::NoProperty; _changedView = 0; } // ----------------------------- krview const KrView::IconSizes KrView::iconSizes; KrView::KrView(KrViewInstance &instance, KConfig *cfg) : _config(cfg), _properties(0), _focused(false), _fileIconSize(0), _instance(instance), _files(0), _mainWindow(0), _widget(0), _nameToMakeCurrent(QString()), _previews(0), _updateDefaultSettings(false), _ignoreSettingsChange(false), _count(0), _numDirs(0), _dummyFileItem(0) { } KrView::~KrView() { _instance.m_objects.removeOne(this); delete _previews; _previews = 0; delete _dummyFileItem; _dummyFileItem = 0; if (_properties) qFatal("A class inheriting KrView didn't delete _properties!"); if (_operator) qFatal("A class inheriting KrView didn't delete _operator!"); } void KrView::init(bool enableUpdateDefaultSettings) { // sanity checks: if (!_widget) qFatal("_widget must be set during construction of KrView inheritors"); // ok, continue initProperties(); _operator = createOperator(); setup(); restoreDefaultSettings(); _updateDefaultSettings = enableUpdateDefaultSettings && KConfigGroup(_config, "Startup").readEntry("Update Default Panel Settings", _RememberPos); _instance.m_objects.append(this); } void KrView::initProperties() { const KConfigGroup grpInstance(_config, _instance.name()); const bool displayIcons = grpInstance.readEntry("With Icons", _WithIcons); const KConfigGroup grpSvr(_config, "Look&Feel"); const bool numericPermissions = grpSvr.readEntry("Numeric permissions", _NumericPermissions); int sortOps = 0; if (grpSvr.readEntry("Show Directories First", true)) sortOps |= KrViewProperties::DirsFirst; if(grpSvr.readEntry("Always sort dirs by name", false)) sortOps |= KrViewProperties::AlwaysSortDirsByName; if (!grpSvr.readEntry("Case Sensative Sort", _CaseSensativeSort)) sortOps |= KrViewProperties::IgnoreCase; if (grpSvr.readEntry("Locale Aware Sort", true)) sortOps |= KrViewProperties::LocaleAwareSort; KrViewProperties::SortOptions sortOptions = static_cast(sortOps); KrViewProperties::SortMethod sortMethod = static_cast( grpSvr.readEntry("Sort method", (int)_DefaultSortMethod)); const bool humanReadableSize = grpSvr.readEntry("Human Readable Size", _HumanReadableSize); // see KDE bug #40131 const bool localeAwareCompareIsCaseSensitive = QString("a").localeAwareCompare("B") > 0; QStringList defaultAtomicExtensions; defaultAtomicExtensions += ".tar.gz"; defaultAtomicExtensions += ".tar.bz2"; defaultAtomicExtensions += ".tar.lzma"; defaultAtomicExtensions += ".tar.xz"; defaultAtomicExtensions += ".moc.cpp"; QStringList atomicExtensions = grpSvr.readEntry("Atomic Extensions", defaultAtomicExtensions); for (QStringList::iterator i = atomicExtensions.begin(); i != atomicExtensions.end();) { QString & ext = *i; ext = ext.trimmed(); if (!ext.length()) { i = atomicExtensions.erase(i); continue; } if (!ext.startsWith('.')) ext.insert(0, '.'); ++i; } _properties = new KrViewProperties(displayIcons, numericPermissions, sortOptions, sortMethod, humanReadableSize, localeAwareCompareIsCaseSensitive, atomicExtensions); } void KrView::showPreviews(bool show) { if(show) { if(!_previews) { _previews = new KrPreviews(this); _previews->update(); } } else { delete _previews; _previews = 0; } redraw(); // op()->settingsChanged(KrViewProperties::PropShowPreviews); op()->emitRefreshActions(); } void KrView::updatePreviews() { if(_previews) _previews->update(); } QPixmap KrView::processIcon(const QPixmap &icon, bool dim, const QColor & dimColor, int dimFactor, bool symlink) { QPixmap pixmap = icon; if (symlink) { const QStringList overlays = QStringList() << QString() << "emblem-symbolic-link"; KIconLoader::global()->drawOverlays(overlays, pixmap, KIconLoader::Desktop); } if(!dim) return pixmap; QImage dimmed = pixmap.toImage(); QPainter p(&dimmed); p.setCompositionMode(QPainter::CompositionMode_SourceIn); p.fillRect(0, 0, icon.width(), icon.height(), dimColor); p.setCompositionMode(QPainter::CompositionMode_SourceOver); p.setOpacity((qreal)dimFactor / (qreal)100); p.drawPixmap(0, 0, icon.width(), icon.height(), pixmap); return QPixmap::fromImage(dimmed, Qt::ColorOnly | Qt::ThresholdDither | Qt::ThresholdAlphaDither | Qt::NoOpaqueDetection ); } QPixmap KrView::getIcon(FileItem *fileitem, bool active, int size/*, KRListItem::cmpColor color*/) { // KConfigGroup ag( krConfig, "Advanced"); ////////////////////////////// QPixmap icon; QString icon_name = fileitem->getIcon(); QString cacheName; if(!size) size = _FilelistIconSize.toInt(); QColor dimColor; int dimFactor; bool dim = !active && KrColorCache::getColorCache().getDimSettings(dimColor, dimFactor); if (icon_name.isNull()) icon_name = ""; cacheName.append(QString::number(size)); if(fileitem->isSymLink()) cacheName.append("LINK_"); if(dim) cacheName.append("DIM_"); cacheName.append(icon_name); //QPixmapCache::setCacheLimit( ag.readEntry("Icon Cache Size",_IconCacheSize) ); // first try the cache if (!QPixmapCache::find(cacheName, icon)) { icon = processIcon(Icon(icon_name).pixmap(size), dim, dimColor, dimFactor, fileitem->isSymLink()); // insert it into the cache QPixmapCache::insert(cacheName, icon); } return icon; } QPixmap KrView::getIcon(FileItem *fileitem) { if(_previews) { QPixmap icon; if(_previews->getPreview(fileitem, icon, _focused)) return icon; } return getIcon(fileitem, _focused, _fileIconSize); } /** * this function ADDs a list of selected item names into 'names'. * it assumes the list is ready and doesn't initialize it, or clears it */ void KrView::getItemsByMask(QString mask, QStringList* names, bool dirs, bool files) { for (KrViewItem * it = getFirst(); it != 0; it = getNext(it)) { if ((it->name() == "..") || !QDir::match(mask, it->name())) continue; // if we got here, than the item fits the mask if (it->getFileItem()->isDir() && !dirs) continue; // do we need to skip folders? if (!it->getFileItem()->isDir() && !files) continue; // do we need to skip files names->append(it->name()); } } /** * this function ADDs a list of selected item names into 'names'. * it assumes the list is ready and doesn't initialize it, or clears it */ void KrView::getSelectedItems(QStringList *names, bool fallbackToFocused) { for (KrViewItem *it = getFirst(); it != 0; it = getNext(it)) if (it->isSelected() && (it->name() != "..")) names->append(it->name()); if (fallbackToFocused) { // if all else fails, take the current item const QString item = getCurrentItem(); if (names->empty() && !item.isEmpty() && item != "..") { names->append(item); } } } void KrView::getSelectedKrViewItems(KrViewItemList *items) { for (KrViewItem * it = getFirst(); it != 0; it = getNext(it)) if (it->isSelected() && (it->name() != "..")) items->append(it); // if all else fails, take the current item QString item = getCurrentItem(); if (items->empty() && !item.isEmpty() && item != ".." && getCurrentKrViewItem() != 0) { items->append(getCurrentKrViewItem()); } } QString KrView::statistics() { KIO::filesize_t size = calcSize(); KIO::filesize_t selectedSize = calcSelectedSize(); QString tmp; KConfigGroup grp(_config, "Look&Feel"); if(grp.readEntry("Show Size In Bytes", false)) { tmp = i18nc("%1=number of selected items,%2=total number of items, \ %3=filesize of selected items,%4=filesize in Bytes, \ %5=filesize of all items in folder,%6=filesize in Bytes", "%1 out of %2, %3 (%4) out of %5 (%6)", numSelected(), _count, KIO::convertSize(selectedSize), KRpermHandler::parseSize(selectedSize), KIO::convertSize(size), KRpermHandler::parseSize(size)); } else { tmp = i18nc("%1=number of selected items,%2=total number of items, \ %3=filesize of selected items,%4=filesize of all items in folder", "%1 out of %2, %3 out of %4", numSelected(), _count, KIO::convertSize(selectedSize), KIO::convertSize(size)); } // notify if we're running a filtered view if (filter() != KrViewProperties::All) tmp = ">> [ " + filterMask().nameFilter() + " ] " + tmp; return tmp; } bool KrView::changeSelection(const KRQuery& filter, bool select) { KConfigGroup grpSvr(_config, "Look&Feel"); return changeSelection(filter, select, grpSvr.readEntry("Mark Dirs", _MarkDirs), true); } bool KrView::changeSelection(const KRQuery& filter, bool select, bool includeDirs, bool makeVisible) { if (op()) op()->setMassSelectionUpdate(true); KrViewItem *temp = getCurrentKrViewItem(); KrViewItem *firstMatch = 0; for (KrViewItem * it = getFirst(); it != 0; it = getNext(it)) { if (it->name() == "..") continue; if (it->getFileItem()->isDir() && !includeDirs) continue; FileItem * file = it->getMutableFileItem(); // filter::match calls getMimetype which isn't const if (file == 0) continue; if (filter.match(file)) { it->setSelected(select); if (!firstMatch) firstMatch = it; } } if (op()) op()->setMassSelectionUpdate(false); updateView(); if (ensureVisibilityAfterSelect() && temp != 0) { makeItemVisible(temp); } else if (makeVisible && firstMatch != 0) { // if no selected item is visible... KrViewItemList selectedItems; getSelectedKrViewItems(&selectedItems); bool anyVisible = false; for (KrViewItem *item : selectedItems) { if (isItemVisible(item)) { anyVisible = true; break; } } if (!anyVisible) { // ...scroll to fist selected item makeItemVisible(firstMatch); } } redraw(); return firstMatch != 0; // return if any file was selected } void KrView::invertSelection() { if (op()) op()->setMassSelectionUpdate(true); KConfigGroup grpSvr(_config, "Look&Feel"); bool markDirs = grpSvr.readEntry("Mark Dirs", _MarkDirs); KrViewItem *temp = getCurrentKrViewItem(); for (KrViewItem * it = getFirst(); it != 0; it = getNext(it)) { if (it->name() == "..") continue; if (it->getFileItem()->isDir() && !markDirs && !it->isSelected()) continue; it->setSelected(!it->isSelected()); } if (op()) op()->setMassSelectionUpdate(false); updateView(); if (ensureVisibilityAfterSelect() && temp != 0) makeItemVisible(temp); } QString KrView::firstUnmarkedBelowCurrent(const bool skipCurrent) { if (getCurrentKrViewItem() == 0) return QString(); KrViewItem *iterator = getCurrentKrViewItem(); if (skipCurrent) iterator = getNext(iterator); while (iterator && iterator->isSelected()) iterator = getNext(iterator); if (!iterator) { iterator = getPrev(getCurrentKrViewItem()); while (iterator && iterator->isSelected()) iterator = getPrev(iterator); } if (!iterator) return QString(); return iterator->name(); } void KrView::deleteItem(const QString &name, bool onUpdate) { KrViewItem *viewItem = findItemByName(name); if (!viewItem) return; if (_previews && !onUpdate) _previews->deletePreview(viewItem); preDeleteItem(viewItem); if (viewItem->FILEITEM->isDir()) { --_numDirs; } --_count; delete viewItem; if (!onUpdate) op()->emitSelectionChanged(); } void KrView::addItem(FileItem *fileItem, bool onUpdate) { if (isFiltered(fileItem)) return; KrViewItem *viewItem = preAddItem(fileItem); if (!viewItem) return; // not added if (_previews) _previews->updatePreview(viewItem); if (fileItem->isDir()) ++_numDirs; ++_count; if (!onUpdate) { op()->emitSelectionChanged(); } } void KrView::updateItem(FileItem *newFileItem) { // file name did not change const QString name = newFileItem->getName(); // preserve 'current' and 'selection' const bool isCurrent = getCurrentItem() == name; QStringList selectedNames; getSelectedItems(&selectedNames, false); const bool isSelected = selectedNames.contains(name); // delete old file item deleteItem(name, true); if (!isFiltered(newFileItem)) { addItem(newFileItem, true); } if (isCurrent) setCurrentItem(name, false); if (isSelected) setSelected(newFileItem, true); op()->emitSelectionChanged(); } void KrView::clear() { if(_previews) _previews->clear(); _count = _numDirs = 0; delete _dummyFileItem; _dummyFileItem = 0; redraw(); } bool KrView::handleKeyEvent(QKeyEvent *e) { qDebug() << "key event=" << e; switch (e->key()) { case Qt::Key_Enter : case Qt::Key_Return : { if (e->modifiers() & Qt::ControlModifier) // let the panel handle it e->ignore(); else { KrViewItem * i = getCurrentKrViewItem(); if (i == 0) return true; QString tmp = i->name(); op()->emitExecuted(tmp); } return true; } case Qt::Key_QuoteLeft : // Terminal Emulator bugfix if (e->modifiers() == Qt::ControlModifier) { // let the panel handle it e->ignore(); } else { // a normal click - do a lynx-like moving thing // ask krusader to move to the home directory op()->emitGoHome(); } return true; case Qt::Key_Delete : // delete/trash the file (delete with alternative mode is a panel action) // allow only no modifier or KeypadModifier (i.e. Del on a Numeric Keypad) if ((e->modifiers() & ~Qt::KeypadModifier) == Qt::NoModifier) { op()->emitDefaultDeleteFiles(); } return true; case Qt::Key_Insert: { KrViewItem * i = getCurrentKrViewItem(); if (!i) return true; i->setSelected(!i->isSelected()); if (KrSelectionMode::getSelectionHandler()->insertMovesDown()) { KrViewItem * next = getNext(i); if (next) { setCurrentKrViewItem(next); makeItemVisible(next); } } op()->emitSelectionChanged(); return true; } case Qt::Key_Space: { KrViewItem * viewItem = getCurrentKrViewItem(); if (viewItem != 0) { viewItem->setSelected(!viewItem->isSelected()); if (viewItem->getFileItem()->isDir() && KrSelectionMode::getSelectionHandler()->spaceCalculatesDiskSpace()) { op()->emitQuickCalcSpace(viewItem); } if (KrSelectionMode::getSelectionHandler()->spaceMovesDown()) { KrViewItem * next = getNext(viewItem); if (next) { setCurrentKrViewItem(next); makeItemVisible(next); } } op()->emitSelectionChanged(); } return true; } case Qt::Key_Backspace : // Terminal Emulator bugfix case Qt::Key_Left : if (e->modifiers() == Qt::ControlModifier || e->modifiers() == Qt::ShiftModifier || e->modifiers() == Qt::AltModifier) { // let the panel handle it e->ignore(); } else { // a normal click - do a lynx-like moving thing // ask krusader to move up a directory op()->emitDirUp(); } return true; // safety case Qt::Key_Right : if (e->modifiers() == Qt::ControlModifier || e->modifiers() == Qt::ShiftModifier || e->modifiers() == Qt::AltModifier) { // let the panel handle it e->ignore(); } else { // just a normal click - do a lynx-like moving thing KrViewItem *i = getCurrentKrViewItem(); if (i) op()->emitGoInside(i->name()); } return true; case Qt::Key_Up : if (e->modifiers() == Qt::ControlModifier) { // let the panel handle it - jump to the Location Bar e->ignore(); } else { KrViewItem *item = getCurrentKrViewItem(); if (item) { if (e->modifiers() == Qt::ShiftModifier) { item->setSelected(!item->isSelected()); op()->emitSelectionChanged(); } item = getPrev(item); if (item) { setCurrentKrViewItem(item); makeItemVisible(item); } } } return true; case Qt::Key_Down : if (e->modifiers() == Qt::ControlModifier || e->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { // let the panel handle it - jump to command line e->ignore(); } else { KrViewItem *item = getCurrentKrViewItem(); if (item) { if (e->modifiers() == Qt::ShiftModifier) { item->setSelected(!item->isSelected()); op()->emitSelectionChanged(); } item = getNext(item); if (item) { setCurrentKrViewItem(item); makeItemVisible(item); } } } return true; case Qt::Key_Home: { if (e->modifiers() & Qt::ShiftModifier) { bool select = true; KrViewItem *pos = getCurrentKrViewItem(); if (pos == 0) pos = getLast(); KrViewItem *item = getFirst(); op()->setMassSelectionUpdate(true); while (item) { item->setSelected(select); if (item == pos) select = false; item = getNext(item); } op()->setMassSelectionUpdate(false); } KrViewItem * first = getFirst(); if (first) { setCurrentKrViewItem(first); makeItemVisible(first); } } return true; case Qt::Key_End: if (e->modifiers() & Qt::ShiftModifier) { bool select = false; KrViewItem *pos = getCurrentKrViewItem(); if (pos == 0) pos = getFirst(); op()->setMassSelectionUpdate(true); KrViewItem *item = getFirst(); while (item) { if (item == pos) select = true; item->setSelected(select); item = getNext(item); } op()->setMassSelectionUpdate(false); } else { KrViewItem *last = getLast(); if (last) { setCurrentKrViewItem(last); makeItemVisible(last); } } return true; case Qt::Key_PageDown: { KrViewItem * current = getCurrentKrViewItem(); int downStep = itemsPerPage(); while (downStep != 0 && current) { KrViewItem * newCurrent = getNext(current); if (newCurrent == 0) break; current = newCurrent; downStep--; } if (current) { setCurrentKrViewItem(current); makeItemVisible(current); } return true; } case Qt::Key_PageUp: { KrViewItem * current = getCurrentKrViewItem(); int upStep = itemsPerPage(); while (upStep != 0 && current) { KrViewItem * newCurrent = getPrev(current); if (newCurrent == 0) break; current = newCurrent; upStep--; } if (current) { setCurrentKrViewItem(current); makeItemVisible(current); } return true; } case Qt::Key_Escape: e->ignore(); return true; // otherwise the selection gets lost??!?? // also it is needed by the panel case Qt::Key_A : // mark all if (e->modifiers() == Qt::ControlModifier) { //FIXME: shouldn't there also be a shortcut for unselecting everything ? selectAllIncludingDirs(); return true; } #if __GNUC__ >= 7 [[gnu::fallthrough]]; #endif default: return false; } return false; } void KrView::zoomIn() { int idx = iconSizes.indexOf(_fileIconSize); if(idx >= 0 && (idx+1) < iconSizes.count()) setFileIconSize(iconSizes[idx+1]); } void KrView::zoomOut() { int idx = iconSizes.indexOf(_fileIconSize); if(idx > 0) setFileIconSize(iconSizes[idx-1]); } void KrView::setFileIconSize(int size) { if(iconSizes.indexOf(size) < 0) return; _fileIconSize = size; if(_previews) { _previews->clear(); _previews->update(); } redraw(); op()->emitRefreshActions(); } int KrView::defaultFileIconSize() { KConfigGroup grpSvr(_config, _instance.name()); return grpSvr.readEntry("IconSize", _FilelistIconSize).toInt(); } void KrView::saveDefaultSettings(KrViewProperties::PropertyType properties) { saveSettings(KConfigGroup(_config, _instance.name()), properties); op()->emitRefreshActions(); } void KrView::restoreDefaultSettings() { restoreSettings(KConfigGroup(_config, _instance.name())); } void KrView::saveSettings(KConfigGroup group, KrViewProperties::PropertyType properties) { if(properties & KrViewProperties::PropIconSize) group.writeEntry("IconSize", fileIconSize()); if(properties & KrViewProperties::PropShowPreviews) group.writeEntry("ShowPreviews", previewsShown()); if(properties & KrViewProperties::PropSortMode) saveSortMode(group); if(properties & KrViewProperties::PropFilter) { group.writeEntry("Filter", static_cast(_properties->filter)); group.writeEntry("FilterApplysToDirs", _properties->filterApplysToDirs); if(_properties->filterSettings.isValid()) _properties->filterSettings.save(KConfigGroup(&group, "FilterSettings")); } } void KrView::restoreSettings(KConfigGroup group) { _ignoreSettingsChange = true; doRestoreSettings(group); _ignoreSettingsChange = false; refresh(); } void KrView::doRestoreSettings(KConfigGroup group) { restoreSortMode(group); setFileIconSize(group.readEntry("IconSize", defaultFileIconSize())); showPreviews(group.readEntry("ShowPreviews", false)); _properties->filter = static_cast(group.readEntry("Filter", static_cast(KrViewProperties::All))); _properties->filterApplysToDirs = group.readEntry("FilterApplysToDirs", false); _properties->filterSettings.load(KConfigGroup(&group, "FilterSettings")); _properties->filterMask = _properties->filterSettings.toQuery(); } void KrView::applySettingsToOthers() { for(int i = 0; i < _instance.m_objects.length(); i++) { KrView *view = _instance.m_objects[i]; if(this != view) { view->_ignoreSettingsChange = true; view->copySettingsFrom(this); view->_ignoreSettingsChange = false; } } } void KrView::sortModeUpdated(KrViewProperties::ColumnType sortColumn, bool descending) { if(sortColumn == _properties->sortColumn && descending == (bool) (_properties->sortOptions & KrViewProperties::Descending)) return; int options = _properties->sortOptions; if(descending) options |= KrViewProperties::Descending; else options &= ~KrViewProperties::Descending; _properties->sortColumn = sortColumn; _properties->sortOptions = static_cast(options); // op()->settingsChanged(KrViewProperties::PropSortMode); } bool KrView::drawCurrent() const { return isFocused() || KConfigGroup(_config, "Look&Feel") .readEntry("Always Show Current Item", _AlwaysShowCurrentItem); } void KrView::saveSortMode(KConfigGroup &group) { group.writeEntry("Sort Column", static_cast(_properties->sortColumn)); group.writeEntry("Descending Sort Order", _properties->sortOptions & KrViewProperties::Descending); } void KrView::restoreSortMode(KConfigGroup &group) { int column = group.readEntry("Sort Column", static_cast(KrViewProperties::Name)); bool isDescending = group.readEntry("Descending Sort Order", false); setSortMode(static_cast(column), isDescending); } QString KrView::krPermissionText(const FileItem * fileitem) { QString tmp; switch (fileitem->isReadable()) { case ALLOWED_PERM: tmp+='r'; break; case UNKNOWN_PERM: tmp+='?'; break; case NO_PERM: tmp+='-'; break; } switch (fileitem->isWriteable()) { case ALLOWED_PERM: tmp+='w'; break; case UNKNOWN_PERM: tmp+='?'; break; case NO_PERM: tmp+='-'; break; } switch (fileitem->isExecutable()) { case ALLOWED_PERM: tmp+='x'; break; case UNKNOWN_PERM: tmp+='?'; break; case NO_PERM: tmp+='-'; break; } return tmp; } QString KrView::permissionsText(const KrViewProperties *properties, const FileItem *fileItem) { return properties->numericPermissions ? QString().asprintf("%.4o", fileItem->getMode() & (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)) : fileItem->getPerm(); } QString KrView::sizeText(const KrViewProperties *properties, KIO::filesize_t size) { return properties->humanReadableSize ? KIO::convertSize(size) : KRpermHandler::parseSize(size); } QString KrView::mimeTypeText(FileItem *fileItem) { QMimeType mt = QMimeDatabase().mimeTypeForName(fileItem->getMime()); return mt.isValid() ? mt.comment() : QString(); } bool KrView::isFiltered(FileItem *fileitem) { if (_quickFilterMask.isValid() && _quickFilterMask.indexIn(fileitem->getName()) == -1) return true; bool filteredOut = false; bool isDir = fileitem->isDir(); if (!isDir || (isDir && properties()->filterApplysToDirs)) { switch (properties()->filter) { case KrViewProperties::All : break; case KrViewProperties::Custom : if (!properties()->filterMask.match(fileitem)) filteredOut = true; break; case KrViewProperties::Dirs: if (!isDir) filteredOut = true; break; case KrViewProperties::Files: if (isDir) filteredOut = true; break; default: break; } } return filteredOut; } void KrView::setFiles(DirListerInterface *files) { if(files != _files) { clear(); if(_files) QObject::disconnect(_files, 0, op(), 0); _files = files; } if(!_files) return; QObject::disconnect(_files, 0, op(), 0); QObject::connect(_files, &DirListerInterface::scanDone, op(), &KrViewOperator::startUpdate); QObject::connect(_files, &DirListerInterface::cleared, op(), &KrViewOperator::cleared); QObject::connect(_files, &DirListerInterface::addedFileItem, op(), &KrViewOperator::fileAdded); QObject::connect(_files, &DirListerInterface::updatedFileItem, op(), &KrViewOperator::fileUpdated); } void KrView::setFilter(KrViewProperties::FilterSpec filter, FilterSettings customFilter, bool applyToDirs) { _properties->filter = filter; _properties->filterSettings = customFilter; _properties->filterMask = customFilter.toQuery(); _properties->filterApplysToDirs = applyToDirs; refresh(); } void KrView::setFilter(KrViewProperties::FilterSpec filter) { KConfigGroup cfg(_config, "Look&Feel"); bool rememberSettings = cfg.readEntry("FilterDialogRemembersSettings", _FilterDialogRemembersSettings); bool applyToDirs = rememberSettings ? _properties->filterApplysToDirs : false; switch (filter) { case KrViewProperties::All : break; case KrViewProperties::Custom : { FilterDialog dialog(_widget, i18n("Filter Files"), QStringList(i18n("Apply filter to folders")), false); dialog.checkExtraOption(i18n("Apply filter to folders"), applyToDirs); if(rememberSettings) dialog.applySettings(_properties->filterSettings); dialog.exec(); FilterSettings s(dialog.getSettings()); if(!s.isValid()) // if the user canceled - quit return; _properties->filterSettings = s; _properties->filterMask = s.toQuery(); applyToDirs = dialog.isExtraOptionChecked(i18n("Apply filter to folders")); } break; default: return; } _properties->filterApplysToDirs = applyToDirs; _properties->filter = filter; refresh(); } void KrView::customSelection(bool select) { KConfigGroup grpSvr(_config, "Look&Feel"); bool includeDirs = grpSvr.readEntry("Mark Dirs", _MarkDirs); FilterDialog dialog(0, i18n("Select Files"), QStringList(i18n("Apply selection to folders")), false); dialog.checkExtraOption(i18n("Apply selection to folders"), includeDirs); dialog.exec(); KRQuery query = dialog.getQuery(); // if the user canceled - quit if (query.isNull()) return; includeDirs = dialog.isExtraOptionChecked(i18n("Apply selection to folders")); changeSelection(query, select, includeDirs); } void KrView::refresh() { const QString currentItem = !nameToMakeCurrent().isEmpty() ? // nameToMakeCurrent() : getCurrentItem(); bool scrollToCurrent = !nameToMakeCurrent().isEmpty() || isItemVisible(getCurrentKrViewItem()); setNameToMakeCurrent(QString()); const QModelIndex currentIndex = getCurrentIndex(); const QList selection = selectedUrls(); clear(); if(!_files) return; QList fileItems; // if we are not at the root add the ".." entry if(!_files->isRoot()) { _dummyFileItem = FileItem::createDummy(); fileItems << _dummyFileItem; } foreach(FileItem *fileitem, _files->fileItems()) { if(!fileitem || isFiltered(fileitem)) continue; if(fileitem->isDir()) _numDirs++; _count++; fileItems << fileitem; } populate(fileItems, _dummyFileItem); if(!selection.isEmpty()) setSelectionUrls(selection); if (!currentItem.isEmpty()) { if (currentItem == ".." && _count > 0 && // !_quickFilterMask.isEmpty() && _quickFilterMask.isValid()) { // In a filtered view we should never select the dummy entry if // there are real matches. setCurrentKrViewItem(getNext(getFirst())); } else { setCurrentItem(currentItem, scrollToCurrent, currentIndex); } } else { setCurrentKrViewItem(getFirst()); } updatePreviews(); redraw(); op()->emitSelectionChanged(); } void KrView::setSelected(const FileItem* fileitem, bool select) { if (fileitem == _dummyFileItem) return; if (select) clearSavedSelection(); intSetSelected(fileitem, select); } void KrView::saveSelection() { _savedSelection = selectedUrls(); op()->emitRefreshActions(); } void KrView::restoreSelection() { if(canRestoreSelection()) setSelectionUrls(_savedSelection); } void KrView::clearSavedSelection() { _savedSelection.clear(); op()->emitRefreshActions(); } void KrView::markSameBaseName() { KrViewItem* item = getCurrentKrViewItem(); if (!item) return; KRQuery query(QString("%1.*").arg(item->name(false))); changeSelection(query, true, false); } void KrView::markSameExtension() { KrViewItem* item = getCurrentKrViewItem(); if (!item) return; KRQuery query(QString("*.%1").arg(item->extension())); changeSelection(query, true, false); } diff --git a/krusader/Panel/listpanel.cpp b/krusader/Panel/listpanel.cpp index a0bb339c..48ae7e50 100644 --- a/krusader/Panel/listpanel.cpp +++ b/krusader/Panel/listpanel.cpp @@ -1,1380 +1,1379 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * Copyright (C) 2000 Rafi Yanai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "listpanel.h" // QtCore #include #include #include #include #include #include #include // QtGui #include #include #include #include #include #include #include #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dirhistoryqueue.h" #include "krcolorcache.h" #include "krerrordisplay.h" #include "krlayoutfactory.h" #include "krpreviewpopup.h" #include "krsearchbar.h" #include "listpanelactions.h" #include "panelcontextmenu.h" #include "panelfunc.h" #include "sidebar.h" #include "viewactions.h" #include "PanelView/krview.h" #include "PanelView/krviewfactory.h" #include "PanelView/krviewitem.h" #include "../defaults.h" #include "../icon.h" -#include "../kicons.h" #include "../krservices.h" #include "../krslots.h" #include "../krusader.h" #include "../krusaderview.h" #include "../Archive/krarchandler.h" #include "../BookMan/krbookmarkbutton.h" #include "../FileSystem/fileitem.h" #include "../FileSystem/filesystem.h" #include "../FileSystem/krpermhandler.h" #include "../FileSystem/sizecalculator.h" #include "../Dialogs/krdialogs.h" #include "../Dialogs/krspwidgets.h" #include "../Dialogs/krsqueezedtextlabel.h" #include "../Dialogs/percentalsplitter.h" #include "../Dialogs/popularurls.h" #include "../GUI/dirhistorybutton.h" #include "../GUI/kcmdline.h" #include "../GUI/mediabutton.h" #include "../MountMan/kmountman.h" #include "../UserAction/useractionpopupmenu.h" class ActionButton : public QToolButton { public: ActionButton(QWidget *parent, ListPanel *panel, QAction *action, QString text = QString()) : QToolButton(parent), panel(panel), action(action) { setText(text); setAutoRaise(true); if(KConfigGroup(krConfig, "ListPanelButtons").readEntry("Icons", false) || text.isEmpty()) setIcon(action->icon()); setToolTip(action->toolTip()); } protected: virtual void mousePressEvent(QMouseEvent *) Q_DECL_OVERRIDE { panel->slotFocusOnMe(); action->trigger(); } ListPanel *panel; QAction *action; }; ///////////////////////////////////////////////////// // The list panel constructor // ///////////////////////////////////////////////////// ListPanel::ListPanel(QWidget *parent, AbstractPanelManager *manager, KConfigGroup cfg) : QWidget(parent), KrPanel(manager, this, new ListPanelFunc(this)), panelType(-1), colorMask(255), compareMode(false), previewJob(0), inlineRefreshJob(0), searchBar(0), cdRootButton(0), cdUpButton(0), sidebarButton(0), sidebar(0), fileSystemError(0), _navigatorUrl(), _tabState(TabState::DEFAULT) { if(cfg.isValid()) panelType = cfg.readEntry("Type", -1); if (panelType == -1) panelType = defaultPanelType(); _actions = krApp->listPanelActions(); setAcceptDrops(true); QHash widgets; #define ADD_WIDGET(widget) widgets.insert(#widget, widget); // media button mediaButton = new MediaButton(this); connect(mediaButton, SIGNAL(aboutToShow()), this, SLOT(slotFocusOnMe())); connect(mediaButton, SIGNAL(openUrl(QUrl)), func, SLOT(openUrl(QUrl))); connect(mediaButton, SIGNAL(newTab(QUrl)), SLOT(newTab(QUrl))); ADD_WIDGET(mediaButton); // status bar status = new KrSqueezedTextLabel(this); KConfigGroup group(krConfig, "Look&Feel"); status->setFont(group.readEntry("Filelist Font", _FilelistFont)); status->setAutoFillBackground(false); status->setText(""); // needed for initialization code! status->setWhatsThis(i18n("The statusbar displays information about the filesystem " "which holds your current folder: total size, free space, " "type of filesystem, etc.")); ADD_WIDGET(status); // back button backButton = new ActionButton(this, this, _actions->actHistoryBackward); ADD_WIDGET(backButton); // forward button forwardButton = new ActionButton(this, this, _actions->actHistoryForward); ADD_WIDGET(forwardButton); // ... create the history button historyButton = new DirHistoryButton(func->history, this); connect(historyButton, SIGNAL(aboutToShow()), this, SLOT(slotFocusOnMe())); connect(historyButton, SIGNAL(gotoPos(int)), func, SLOT(historyGotoPos(int))); ADD_WIDGET(historyButton); // bookmarks button bookmarksButton = new KrBookmarkButton(this); connect(bookmarksButton, SIGNAL(aboutToShow()), this, SLOT(slotFocusOnMe())); connect(bookmarksButton, SIGNAL(openUrl(QUrl)), func, SLOT(openUrl(QUrl))); bookmarksButton->setWhatsThis(i18n("Open menu with bookmarks. You can also add " "current location to the list, edit bookmarks " "or add subfolder to the list.")); ADD_WIDGET(bookmarksButton); // url input field urlNavigator = new KUrlNavigator(new KFilePlacesModel(this), QUrl(), this); urlNavigator->setWhatsThis(i18n("Name of folder where you are. You can also " "enter name of desired location to move there. " "Use of Net protocols like ftp or fish is possible.")); // handle certain key events here in event filter urlNavigator->editor()->installEventFilter(this); urlNavigator->setUrlEditable(isNavigatorEditModeSet()); urlNavigator->setShowFullPath(group.readEntry("Navigator Full Path", false)); connect(urlNavigator, SIGNAL(returnPressed()), this, SLOT(slotFocusOnMe())); connect(urlNavigator, &KUrlNavigator::urlChanged, this, &ListPanel::slotNavigatorUrlChanged); connect(urlNavigator->editor()->lineEdit(), &QLineEdit::editingFinished, this, &ListPanel::resetNavigatorMode); connect(urlNavigator, SIGNAL(tabRequested(QUrl)), this, SLOT(newTab(QUrl))); connect(urlNavigator, SIGNAL(urlsDropped(QUrl,QDropEvent*)), this, SLOT(handleDrop(QUrl,QDropEvent*))); ADD_WIDGET(urlNavigator); // toolbar QWidget * toolbar = new QWidget(this); QHBoxLayout * toolbarLayout = new QHBoxLayout(toolbar); toolbarLayout->setContentsMargins(0, 0, 0, 0); toolbarLayout->setSpacing(0); ADD_WIDGET(toolbar); fileSystemError = new KrErrorDisplay(this); fileSystemError->setWordWrap(true); fileSystemError->hide(); ADD_WIDGET(fileSystemError); // client area clientArea = new QWidget(this); QVBoxLayout *clientLayout = new QVBoxLayout(clientArea); clientLayout->setSpacing(0); clientLayout->setContentsMargins(0, 0, 0, 0); ADD_WIDGET(clientArea); // totals label totals = new KrSqueezedTextLabel(this); totals->setFont(group.readEntry("Filelist Font", _FilelistFont)); totals->setAutoFillBackground(false); totals->setWhatsThis(i18n("The totals bar shows how many files exist, " "how many selected and the bytes math")); ADD_WIDGET(totals); // free space label freeSpace = new KrSqueezedTextLabel(this); freeSpace->setFont(group.readEntry("Filelist Font", _FilelistFont)); freeSpace->setAutoFillBackground(false); freeSpace->setText(""); freeSpace->setAlignment(Qt::AlignRight | Qt::AlignVCenter); ADD_WIDGET(freeSpace); // progress indicator and cancel button for the quick calc size quickSizeCalcProgress = new QProgressBar(this); quickSizeCalcProgress->hide(); ADD_WIDGET(quickSizeCalcProgress); cancelQuickSizeCalcButton = new QToolButton(this); cancelQuickSizeCalcButton->hide(); cancelQuickSizeCalcButton->setIcon(Icon("dialog-cancel")); cancelQuickSizeCalcButton->setToolTip(i18n("Cancel directory space calculation")); ADD_WIDGET(cancelQuickSizeCalcButton); // progress indicator for the preview job previewProgress = new QProgressBar(this); previewProgress->hide(); ADD_WIDGET(previewProgress); // a cancel button for the filesystem refresh and preview job cancelProgressButton = new QToolButton(this); cancelProgressButton->hide(); cancelProgressButton->setIcon(Icon("dialog-cancel")); connect(cancelProgressButton, SIGNAL(clicked()), this, SLOT(cancelProgress())); ADD_WIDGET(cancelProgressButton); // button for changing the panel sidebar position in the panel sidebarPositionButton = new QToolButton(this); sidebarPositionButton->hide(); sidebarPositionButton->setAutoRaise(true); sidebarPositionButton->setIcon(Icon("exchange-positions")); sidebarPositionButton->setToolTip(i18n("Move Sidebar clockwise")); connect(sidebarPositionButton, &QToolButton::clicked, [this]() { // moving position clockwise setSidebarPosition((sidebarPosition() + 1) % 4); }); ADD_WIDGET(sidebarPositionButton); // a quick button to open the sidebar sidebarButton = new QToolButton(this); sidebarButton->setAutoRaise(true); sidebarButton->setIcon(Icon("arrow-up")); connect(sidebarButton, &QToolButton::clicked, this, &ListPanel::toggleSidebar); sidebarButton->setToolTip(i18n("Open the Sidebar")); ADD_WIDGET(sidebarButton); #undef ADD_WIDGET // toolbar buttons cdOtherButton = new ActionButton(toolbar, this, _actions->actCdToOther, "="); toolbarLayout->addWidget(cdOtherButton); cdUpButton = new ActionButton(toolbar, this, _actions->actDirUp, ".."); toolbarLayout->addWidget(cdUpButton); cdHomeButton = new ActionButton(toolbar, this, _actions->actHome, "~"); toolbarLayout->addWidget(cdHomeButton); cdRootButton = new ActionButton(toolbar, this, _actions->actRoot, "/"); toolbarLayout->addWidget(cdRootButton); // create the button for sync-browsing syncBrowseButton = new QToolButton(toolbar); syncBrowseButton->setIcon(Icon("kr_syncbrowse_off")); syncBrowseButton->setCheckable(true); const QString syncBrowseText = i18n("This button toggles the sync-browse mode.\n" "When active, each folder change is performed in the\n" "active and inactive panel - if possible."); syncBrowseButton->setText(syncBrowseText); syncBrowseButton->setToolTip(syncBrowseText); connect(syncBrowseButton, &QToolButton::toggled, [=](bool checked) { syncBrowseButton->setIcon( Icon(checked ? "kr_syncbrowse_on" : "kr_syncbrowse_off")); }); syncBrowseButton->setAutoRaise(true); toolbarLayout->addWidget(syncBrowseButton); setButtons(); // create a splitter to hold the view and the sidebar sidebarSplitter = new PercentalSplitter(clientArea); sidebarSplitter->setChildrenCollapsible(true); sidebarSplitter->setOrientation(Qt::Horizontal); // expand vertical if splitter orientation is horizontal QSizePolicy sizePolicy = sidebarSplitter->sizePolicy(); sizePolicy.setVerticalPolicy(QSizePolicy::Expanding); sidebarSplitter->setSizePolicy(sizePolicy); clientLayout->addWidget(sidebarSplitter); // view createView(); // search (in folder) bar searchBar = new KrSearchBar(view, clientArea); searchBar->hide(); bool top = group.readEntry("Quicksearch Position", "bottom") == "top"; clientLayout->insertWidget(top ? 0 : -1, searchBar); // create the layout KrLayoutFactory fact(this, widgets); QLayout *layout = fact.createLayout(); if(!layout) { // fallback: create a layout by ourself QVBoxLayout *v = new QVBoxLayout; v->setContentsMargins(0, 0, 0, 0); v->setSpacing(0); QHBoxLayout *h = new QHBoxLayout; h->setContentsMargins(0, 0, 0, 0); h->setSpacing(0); h->addWidget(urlNavigator); h->addWidget(toolbar); h->addStretch(); v->addLayout(h); h = new QHBoxLayout; h->setContentsMargins(0, 0, 0, 0); h->setSpacing(0); h->addWidget(mediaButton); h->addWidget(status); h->addWidget(backButton); h->addWidget(forwardButton); h->addWidget(historyButton); h->addWidget(bookmarksButton); v->addLayout(h); v->addWidget(fileSystemError); v->addWidget(clientArea); h = new QHBoxLayout; h->setContentsMargins(0, 0, 0, 0); h->setSpacing(0); h->addWidget(totals); h->addWidget(freeSpace); h->addWidget(quickSizeCalcProgress); h->addWidget(cancelQuickSizeCalcButton); h->addWidget(previewProgress); h->addWidget(cancelProgressButton); h->addWidget(sidebarButton); v->addLayout(h); layout = v; } setLayout(layout); connect(&KrColorCache::getColorCache(), SIGNAL(colorsRefreshed()), this, SLOT(refreshColors())); connect(krApp, SIGNAL(shutdown()), SLOT(cancelProgress())); } ListPanel::~ListPanel() { cancelProgress(); delete view; view = 0; delete func; delete status; delete bookmarksButton; delete totals; delete urlNavigator; delete cdRootButton; delete cdHomeButton; delete cdUpButton; delete cdOtherButton; delete syncBrowseButton; // delete layout; } void ListPanel::reparent(QWidget *parent, AbstractPanelManager *manager) { setParent(parent); _manager = manager; } int ListPanel::defaultPanelType() { KConfigGroup group(krConfig, "Look&Feel"); return group.readEntry("Default Panel Type", KrViewFactory::defaultViewId()); } bool ListPanel::isNavigatorEditModeSet() { KConfigGroup group(krConfig, "Look&Feel"); return group.readEntry("Navigator Edit Mode", false); } void ListPanel::createView() { view = KrViewFactory::createView(panelType, sidebarSplitter, krConfig); view->init(); view->setMainWindow(krApp); // KrViewFactory may create a different view type than requested panelType = view->instance()->id(); if(this == ACTIVE_PANEL) view->prepareForActive(); else view->prepareForPassive(); view->refreshColors(); sidebarSplitter->insertWidget(sidebarPosition() < 2 ? 1 : 0, view->widget()); view->widget()->installEventFilter(this); connect(view->op(), &KrViewOperator::quickCalcSpace, func, &ListPanelFunc::quickCalcSpace); connect(view->op(), SIGNAL(goHome()), func, SLOT(home())); connect(view->op(), SIGNAL(dirUp()), func, SLOT(dirUp())); connect(view->op(), &KrViewOperator::defaultDeleteFiles, func, &ListPanelFunc::defaultDeleteFiles); connect(view->op(), SIGNAL(middleButtonClicked(KrViewItem*)), SLOT(newTab(KrViewItem*))); connect(view->op(), SIGNAL(currentChanged(KrViewItem*)), SLOT(slotCurrentChanged(KrViewItem*))); connect(view->op(), SIGNAL(renameItem(QString,QString)), func, SLOT(rename(QString,QString))); connect(view->op(), SIGNAL(executed(QString)), func, SLOT(execute(QString))); connect(view->op(), SIGNAL(goInside(QString)), func, SLOT(goInside(QString))); connect(view->op(), SIGNAL(needFocus()), this, SLOT(slotFocusOnMe())); connect(view->op(), SIGNAL(selectionChanged()), this, SLOT(slotUpdateTotals())); connect(view->op(), SIGNAL(itemDescription(QString)), krApp, SLOT(statusBarUpdate(QString))); connect(view->op(), SIGNAL(contextMenu(QPoint)), this, SLOT(popRightClickMenu(QPoint))); connect(view->op(), SIGNAL(emptyContextMenu(QPoint)), this, SLOT(popEmptyRightClickMenu(QPoint))); connect(view->op(), SIGNAL(letsDrag(QStringList,QPixmap)), this, SLOT(startDragging(QStringList,QPixmap))); connect(view->op(), &KrViewOperator::gotDrop, this, [this](QDropEvent *event) {handleDrop(event, true); }); connect(view->op(), SIGNAL(previewJobStarted(KJob*)), this, SLOT(slotPreviewJobStarted(KJob*))); connect(view->op(), SIGNAL(refreshActions()), krApp->viewActions(), SLOT(refreshActions())); connect(view->op(), SIGNAL(currentChanged(KrViewItem*)), func->history, SLOT(saveCurrentItem())); connect(view->op(), &KrViewOperator::goBack, func, &ListPanelFunc::historyBackward); connect(view->op(), &KrViewOperator::goForward, func, &ListPanelFunc::historyForward); view->setFiles(func->files()); func->refreshActions(); } void ListPanel::changeType(int type) { if (panelType != type) { QString current = view->getCurrentItem(); QList selection = view->selectedUrls(); bool filterApplysToDirs = view->properties()->filterApplysToDirs; KrViewProperties::FilterSpec filter = view->filter(); FilterSettings filterSettings = view->properties()->filterSettings; panelType = type; KrView *oldView = view; createView(); searchBar->setView(view); delete oldView; view->setFilter(filter, filterSettings, filterApplysToDirs); view->setSelectionUrls(selection); view->setCurrentItem(current); view->makeItemVisible(view->getCurrentKrViewItem()); } } int ListPanel::getProperties() { int props = 0; if (syncBrowseButton->isChecked()) { props |= PROP_SYNC_BUTTON_ON; } if (isLocked()) { props |= PROP_LOCKED; } else if (isPinned()) { props |= PROP_PINNED; } return props; } void ListPanel::setProperties(int prop) { syncBrowseButton->setChecked(prop & PROP_SYNC_BUTTON_ON); if (prop & PROP_LOCKED) { _tabState = TabState::LOCKED; } else if (prop & PROP_PINNED) { _tabState = TabState::PINNED; } else { _tabState = TabState::DEFAULT; } } bool ListPanel::eventFilter(QObject * watched, QEvent * e) { if(view && watched == view->widget()) { if(e->type() == QEvent::FocusIn && this != ACTIVE_PANEL && !isHidden()) slotFocusOnMe(); else if(e->type() == QEvent::ShortcutOverride) { QKeyEvent *ke = static_cast(e); if(ke->key() == Qt::Key_Escape && ke->modifiers() == Qt::NoModifier) { // if the cancel refresh action has no shortcut assigned, // we need this event ourselves to cancel refresh if(_actions->actCancelRefresh->shortcut().isEmpty()) { e->accept(); return true; } } } } // handle URL navigator key events else if(watched == urlNavigator->editor()) { // override default shortcut for panel focus if(e->type() == QEvent::ShortcutOverride) { QKeyEvent *ke = static_cast(e); if ((ke->key() == Qt::Key_Escape) && (ke->modifiers() == Qt::NoModifier)) { e->accept(); // we will get the key press event now return true; } } else if(e->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(e); if ((ke->key() == Qt::Key_Down) && (ke->modifiers() == Qt::ControlModifier)) { slotFocusOnMe(); return true; } else if ((ke->key() == Qt::Key_Escape) && (ke->modifiers() == Qt::NoModifier)) { // reset navigator urlNavigator->editor()->setUrl(urlNavigator->locationUrl()); slotFocusOnMe(); return true; } } } return false; } void ListPanel::toggleSidebar() { if(!sidebar) { sidebar = new Sidebar(sidebarSplitter); // fix vertical grow of splitter (and entire window) if its content // demands more space QSizePolicy sizePolicy = sidebar->sizePolicy(); sizePolicy.setVerticalPolicy(QSizePolicy::Ignored); sidebar->setSizePolicy(sizePolicy); connect(this, &ListPanel::pathChanged, sidebar, &Sidebar::onPanelPathChange); connect(sidebar, &Sidebar::urlActivated, SLOTS, &KRslots::refresh); sidebarSplitter->insertWidget(0, sidebar); } if (sidebar->isHidden()) { if (sidebarSplitterSizes.count() > 0) { sidebarSplitter->setSizes(sidebarSplitterSizes); } else { // on the first time, resize to 50% QList lst; lst << height() / 2 << height() / 2; sidebarSplitter->setSizes(lst); } sidebar->show(); sidebarButton->setIcon(Icon("arrow-down")); sidebarButton->setToolTip(i18n("Close the Sidebar")); sidebarPositionButton->show(); } else { sidebarSplitterSizes.clear(); sidebarSplitterSizes = sidebarSplitter->sizes(); sidebar->hide(); sidebarButton->setIcon(Icon("arrow-up")); sidebarButton->setToolTip(i18n("Open the Sidebar")); sidebarPositionButton->hide(); QList lst; lst << height() << 0; sidebarSplitter->setSizes(lst); if (ACTIVE_PANEL) ACTIVE_PANEL->gui->slotFocusOnMe(); } } QString ListPanel::lastLocalPath() const { return _lastLocalPath; } void ListPanel::setButtons() { KConfigGroup group(krConfig, "Look&Feel"); mediaButton->setVisible(group.readEntry("Media Button Visible", true)); backButton->setVisible(group.readEntry("Back Button Visible", false)); forwardButton->setVisible(group.readEntry("Forward Button Visible", false)); historyButton->setVisible(group.readEntry("History Button Visible", true)); bookmarksButton->setVisible(group.readEntry("Bookmarks Button Visible", true)); if (group.readEntry("Panel Toolbar visible", _PanelToolBar)) { cdRootButton->setVisible(group.readEntry("Root Button Visible", _cdRoot)); cdHomeButton->setVisible(group.readEntry("Home Button Visible", _cdHome)); cdUpButton->setVisible(group.readEntry("Up Button Visible", _cdUp)); cdOtherButton->setVisible(group.readEntry("Equal Button Visible", _cdOther)); syncBrowseButton->setVisible(group.readEntry("SyncBrowse Button Visible", _syncBrowseButton)); } else { cdRootButton->hide(); cdHomeButton->hide(); cdUpButton->hide(); cdOtherButton->hide(); syncBrowseButton->hide(); } } void ListPanel::slotUpdateTotals() { totals->setText(view->statistics()); } void ListPanel::compareDirs(bool otherPanelToo) { // Performs a check in order to avoid that the next code is executed twice if (otherPanelToo == true) { // If both panels are showing the same directory if (_manager->currentPanel()->virtualPath() == otherPanel()->virtualPath()) { if (KMessageBox::warningContinueCancel(this, i18n("Warning: The left and the right side are showing the same folder.")) != KMessageBox::Continue) { return; } } } KConfigGroup pg(krConfig, "Private"); int compareMode = pg.readEntry("Compare Mode", 0); KConfigGroup group(krConfig, "Look&Feel"); bool selectDirs = group.readEntry("Mark Dirs", false); KrViewItem *item, *otherItem; for (item = view->getFirst(); item != 0; item = view->getNext(item)) { if (item->name() == "..") continue; for (otherItem = otherPanel()->view->getFirst(); otherItem != 0 && otherItem->name() != item->name(); otherItem = otherPanel()->view->getNext(otherItem)); bool isSingle = (otherItem == 0), isDifferent = false, isNewer = false; if (func->getFileItem(item)->isDir() && !selectDirs) { item->setSelected(false); continue; } if (otherItem) { if (!func->getFileItem(item)->isDir()) isDifferent = otherPanel()->func->getFileItem(otherItem)->getSize() != func->getFileItem(item)->getSize(); isNewer = func->getFileItem(item)->getTime_t() > otherPanel()->func->getFileItem(otherItem)->getTime_t(); } switch (compareMode) { case 0: item->setSelected(isNewer || isSingle); break; case 1: item->setSelected(isNewer); break; case 2: item->setSelected(isSingle); break; case 3: item->setSelected(isDifferent || isSingle); break; case 4: item->setSelected(isDifferent); break; } } view->updateView(); if (otherPanelToo) otherPanel()->gui->compareDirs(false); } void ListPanel::refreshColors() { view->refreshColors(); emit refreshColors(this == ACTIVE_PANEL); } void ListPanel::slotFocusOnMe(bool focus) { if (focus && _manager->currentPanel() != this) { // ignore focus request if this panel is not shown return; } krApp->setUpdatesEnabled(false); if(focus) { emit activate(); _actions->activePanelChanged(); func->refreshActions(); slotCurrentChanged(view->getCurrentKrViewItem()); view->prepareForActive(); otherPanel()->gui->slotFocusOnMe(false); } else { // in case a new url was entered but not refreshed to, // reset url navigator to the current url setNavigatorUrl(virtualPath()); view->prepareForPassive(); } urlNavigator->setActive(focus); refreshColors(); krApp->setUpdatesEnabled(true); } // this is used to start the panel ////////////////////////////////////////////////////////////////// void ListPanel::start(const QUrl &url) { QUrl startUrl(url); if (!startUrl.isValid()) startUrl = QUrl::fromLocalFile(ROOT_DIR); _lastLocalPath = startUrl.isLocalFile() ? startUrl.path() : ROOT_DIR; func->openUrl(startUrl); setJumpBack(startUrl); } void ListPanel::slotStartUpdate(bool directoryChange) { if (inlineRefreshJob) inlineRefreshListResult(0); setCursor(Qt::BusyCursor); const QUrl currentUrl = virtualPath(); if (directoryChange) { if (this == ACTIVE_PANEL) { slotFocusOnMe(); } if (currentUrl.isLocalFile()) _lastLocalPath = currentUrl.path(); setNavigatorUrl(currentUrl); emit pathChanged(currentUrl); krApp->popularUrls()->addUrl(currentUrl); searchBar->hideBar(); } if (compareMode) otherPanel()->view->refresh(); // return cursor to normal arrow setCursor(Qt::ArrowCursor); slotUpdateTotals(); } void ListPanel::updateFilesystemStats(const QString &metaInfo, const QString &fsType, KIO::filesize_t total, KIO::filesize_t free) { QString statusText, mountPoint, freeSpaceText; if (!metaInfo.isEmpty()) { statusText = metaInfo; mountPoint = freeSpaceText = ""; } else { const int perc = total == 0 ? 0 : (int)(((float)free / (float)total) * 100.0); mountPoint = func->files()->mountPoint(); statusText = i18nc("%1=free space,%2=total space,%3=percentage of usage, " "%4=mountpoint,%5=filesystem type", "%1 free out of %2 (%3%) on %4 [(%5)]", KIO::convertSize(free), KIO::convertSize(total), perc, mountPoint, fsType); freeSpaceText = " " + i18n("%1 free", KIO::convertSize(free)); } status->setText(statusText); freeSpace->setText(freeSpaceText); mediaButton->updateIcon(mountPoint); } void ListPanel::handleDrop(QDropEvent *event, bool onView) { // check what was dropped const QList urls = KUrlMimeData::urlsFromMimeData(event->mimeData()); if (urls.isEmpty()) { event->ignore(); // not for us to handle! return; } // find dropping destination QString destinationDir = ""; const bool dragFromThisPanel = event->source() == this; const KrViewItem *item = onView ? view->getKrViewItemAt(event->pos()) : 0; if (item) { const FileItem *file = item->getFileItem(); if (file && !file->isDir() && dragFromThisPanel) { event->ignore(); // dragging on files in same panel, ignore return; } else if (!file || file->isDir()) { // item is ".." dummy or a directory destinationDir = item->name(); } } else if (dragFromThisPanel) { event->ignore(); // dragged from this panel onto an empty spot in this panel, ignore return; } QUrl destination = QUrl(virtualPath()); destination.setPath(destination.path() + '/' + destinationDir); func->files()->dropFiles(destination, event); if(KConfigGroup(krConfig, "Look&Feel").readEntry("UnselectBeforeOperation", _UnselectBeforeOperation)) { KrPanel *p = dragFromThisPanel ? this : otherPanel(); p->view->saveSelection(); p->view->unselectAll(); } } void ListPanel::handleDrop(const QUrl &destination, QDropEvent *event) { func->files()->dropFiles(destination, event); } void ListPanel::startDragging(QStringList names, QPixmap px) { if (names.isEmpty()) { // avoid dragging empty urls return; } QList urls = func->files()->getUrls(names); QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; drag->setPixmap(px); mimeData->setUrls(urls); drag->setMimeData(mimeData); drag->start(Qt::MoveAction | Qt::CopyAction | Qt::LinkAction); } // pops a right-click menu for items void ListPanel::popRightClickMenu(const QPoint &loc) { // run it, on the mouse location int j = QFontMetrics(font()).height() * 2; PanelContextMenu::run(QPoint(loc.x() + 5, loc.y() + j), this); } void ListPanel::popEmptyRightClickMenu(const QPoint &loc) { PanelContextMenu::run(loc, this); } QString ListPanel::getCurrentName() { QString name = view->getCurrentItem(); if (name != "..") return name; else return QString(); } QStringList ListPanel::getSelectedNames() { QStringList fileNames; view->getSelectedItems(&fileNames); return fileNames; } void ListPanel::prepareToDelete() { const bool skipCurrent = (view->numSelected() == 0); view->setNameToMakeCurrent(view->firstUnmarkedBelowCurrent(skipCurrent)); } void ListPanel::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_Enter : case Qt::Key_Return : if (e->modifiers() & Qt::ControlModifier) { if (e->modifiers() & Qt::AltModifier) { FileItem *fileitem = func->files()->getFileItem(view->getCurrentKrViewItem()->name()); if (fileitem && fileitem->isDir()) newTab(fileitem->getUrl(), true); } else { SLOTS->insertFileName((e->modifiers() & Qt::ShiftModifier) != 0); } } else { e->ignore(); } break; case Qt::Key_Right : case Qt::Key_Left : if (e->modifiers() == Qt::ControlModifier) { // user pressed CTRL+Right/Left - refresh other panel to the selected path if it's a // directory otherwise as this one if ((isLeft() && e->key() == Qt::Key_Right) || (!isLeft() && e->key() == Qt::Key_Left)) { QUrl newPath; KrViewItem *it = view->getCurrentKrViewItem(); if (it->name() == "..") { newPath = KIO::upUrl(virtualPath()); } else { FileItem *v = func->getFileItem(it); // If it's a directory different from ".." if (v && v->isDir() && v->getName() != "..") { newPath = v->getUrl(); } else { // If it's a supported compressed file if (v && KRarcHandler::arcSupported(v->getMime())) { newPath = func->browsableArchivePath(v->getUrl().fileName()); } else { newPath = virtualPath(); } } } otherPanel()->func->openUrl(newPath); } else { func->openUrl(otherPanel()->virtualPath()); } return; } else e->ignore(); break; case Qt::Key_Down : if (e->modifiers() == Qt::ControlModifier) { // give the keyboard focus to the command line if (MAIN_VIEW->cmdLine()->isVisible()) MAIN_VIEW->cmdLineFocus(); else MAIN_VIEW->focusTerminalEmulator(); return; } else if (e->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { // give the keyboard focus to TE MAIN_VIEW->focusTerminalEmulator(); } else e->ignore(); break; case Qt::Key_Up : if (e->modifiers() == Qt::ControlModifier) { // give the keyboard focus to the url navigator editLocation(); return; } else e->ignore(); break; case Qt::Key_Escape: cancelProgress(); break; default: // if we got this, it means that the view is not doing // the quick search thing, so send the characters to the commandline, if normal key if (e->modifiers() == Qt::NoModifier) MAIN_VIEW->cmdLine()->addText(e->text()); //e->ignore(); } } void ListPanel::showEvent(QShowEvent *e) { panelVisible(); QWidget::showEvent(e); } void ListPanel::hideEvent(QHideEvent *e) { panelHidden(); QWidget::hideEvent(e); } void ListPanel::panelVisible() { func->setPaused(false); } void ListPanel::panelHidden() { func->setPaused(true); } void ListPanel::slotPreviewJobStarted(KJob *job) { previewJob = job; connect(job, SIGNAL(percent(KJob*,ulong)), SLOT(slotPreviewJobPercent(KJob*,ulong))); connect(job, &KJob::result, this, &ListPanel::slotPreviewJobResult); cancelProgressButton->setMaximumHeight(sidebarButton->height()); cancelProgressButton->show(); previewProgress->setValue(0); previewProgress->setFormat(i18n("loading previews: %p%")); previewProgress->setMaximumHeight(cancelProgressButton->height()); previewProgress->show(); } void ListPanel::slotPreviewJobPercent(KJob* /*job*/, unsigned long percent) { previewProgress->setValue(percent); } void ListPanel::slotPreviewJobResult(KJob* /*job*/) { previewJob = 0; previewProgress->hide(); if(!inlineRefreshJob) cancelProgressButton->hide(); } void ListPanel::slotRefreshJobStarted(KIO::Job* job) { // disable the parts of the panel we don't want touched status->setEnabled(false); urlNavigator->setEnabled(false); cdRootButton->setEnabled(false); cdHomeButton->setEnabled(false); cdUpButton->setEnabled(false); cdOtherButton->setEnabled(false); sidebarButton->setEnabled(false); if(sidebar) sidebar->setEnabled(false); bookmarksButton->setEnabled(false); historyButton->setEnabled(false); syncBrowseButton->setEnabled(false); // connect to the job interface to provide in-panel refresh notification connect(job, SIGNAL(infoMessage(KJob*,QString)), SLOT(inlineRefreshInfoMessage(KJob*,QString))); connect(job, SIGNAL(percent(KJob*,ulong)), SLOT(inlineRefreshPercent(KJob*,ulong))); connect(job, SIGNAL(result(KJob*)), this, SLOT(inlineRefreshListResult(KJob*))); inlineRefreshJob = job; totals->setText(i18n(">> Reading...")); cancelProgressButton->show(); } void ListPanel::cancelProgress() { if (inlineRefreshJob) { disconnect(inlineRefreshJob, 0, this, 0); inlineRefreshJob->kill(KJob::EmitResult); inlineRefreshListResult(0); } if(previewJob) { disconnect(previewJob, 0, this, 0); previewJob->kill(KJob::EmitResult); slotPreviewJobResult(0); } } void ListPanel::setNavigatorUrl(const QUrl &url) { _navigatorUrl = url; urlNavigator->setLocationUrl(url); } void ListPanel::inlineRefreshPercent(KJob*, unsigned long perc) { QString msg = i18n(">> Reading: %1 % complete...", perc); totals->setText(msg); } void ListPanel::inlineRefreshInfoMessage(KJob*, const QString &msg) { totals->setText(i18n(">> Reading: %1", msg)); } void ListPanel::inlineRefreshListResult(KJob*) { if(inlineRefreshJob) disconnect(inlineRefreshJob, 0, this, 0); inlineRefreshJob = 0; // reenable everything status->setEnabled(true); urlNavigator->setEnabled(true); cdRootButton->setEnabled(true); cdHomeButton->setEnabled(true); cdUpButton->setEnabled(true); cdOtherButton->setEnabled(true); sidebarButton->setEnabled(true); if(sidebar) sidebar->setEnabled(true); bookmarksButton->setEnabled(true); historyButton->setEnabled(true); syncBrowseButton->setEnabled(true); if(!previewJob) cancelProgressButton->hide(); } void ListPanel::jumpBack() { func->openUrl(_jumpBackURL); } void ListPanel::setJumpBack(QUrl url) { _jumpBackURL = url; } void ListPanel::slotFilesystemError(QString msg) { refreshColors(); fileSystemError->setText(i18n("Error: %1", msg)); fileSystemError->show(); } void ListPanel::showButtonMenu(QToolButton *b) { if(this != ACTIVE_PANEL) slotFocusOnMe(); if(b->isHidden()) b->menu()->exec(mapToGlobal(clientArea->pos())); else b->click(); } void ListPanel::openBookmarks() { showButtonMenu(bookmarksButton); } void ListPanel::openHistory() { showButtonMenu(historyButton); } void ListPanel::openMedia() { showButtonMenu(mediaButton); } void ListPanel::rightclickMenu() { if (view->getCurrentKrViewItem()) popRightClickMenu(mapToGlobal(view->getCurrentKrViewItem()->itemRect().topLeft())); } void ListPanel::toggleSyncBrowse() { syncBrowseButton->toggle(); } void ListPanel::editLocation() { urlNavigator->setUrlEditable(true); urlNavigator->setFocus(); urlNavigator->editor()->lineEdit()->selectAll(); } void ListPanel::showSearchBar() { searchBar->showBar(); } void ListPanel::showSearchFilter() { searchBar->showBar(KrSearchBar::MODE_FILTER); } void ListPanel::saveSettings(KConfigGroup cfg, bool saveHistory) { QUrl url = virtualPath(); url.setPassword(QString()); // make sure no password is saved cfg.writeEntry("Url", url.toString()); cfg.writeEntry("Type", getType()); cfg.writeEntry("Properties", getProperties()); cfg.writeEntry("PinnedUrl", pinnedUrl().toString()); if(saveHistory) func->history->save(KConfigGroup(&cfg, "History")); view->saveSettings(KConfigGroup(&cfg, "View")); // splitter/sidebar state if (sidebar && !sidebar->isHidden()) { sidebar->saveSettings(KConfigGroup(&cfg, "PanelPopup")); cfg.writeEntry("PopupPosition", sidebarPosition()); cfg.writeEntry("SplitterSizes", sidebarSplitter->saveState()); cfg.writeEntry("PopupPage", sidebar->currentPage()); } else { cfg.deleteEntry("PopupPosition"); cfg.deleteEntry("SplitterSizes"); cfg.deleteEntry("PopupPage"); } } void ListPanel::restoreSettings(KConfigGroup cfg) { changeType(cfg.readEntry("Type", defaultPanelType())); view->restoreSettings(KConfigGroup(&cfg, "View")); // "locked" property must be set after URL path is restored! // This panel can be reused when loading a profile, // so we reset its properties before calling openUrl(). setProperties(0); _lastLocalPath = ROOT_DIR; if(func->history->restore(KConfigGroup(&cfg, "History"))) { func->refresh(); } else { QUrl url(cfg.readEntry("Url", "invalid")); if (!url.isValid()) url = QUrl::fromLocalFile(ROOT_DIR); func->openUrl(url); } setJumpBack(func->history->currentUrl()); setProperties(cfg.readEntry("Properties", 0)); if (isPinned()) { QUrl pinnedUrl(cfg.readEntry("PinnedUrl", "invalid")); if (!pinnedUrl.isValid()) { pinnedUrl = func->history->currentUrl(); } func->openUrl(pinnedUrl); setPinnedUrl(pinnedUrl); } if (cfg.hasKey("PopupPosition")) { // sidebar was visible, restore toggleSidebar(); // create and show sidebar->restoreSettings(KConfigGroup(&cfg, "PanelPopup")); setSidebarPosition(cfg.readEntry("PopupPosition", 42 /* dummy */)); sidebarSplitter->restoreState(cfg.readEntry("SplitterSizes", QByteArray())); sidebar->setCurrentPage(cfg.readEntry("PopupPage", 0)); } } void ListPanel::slotCurrentChanged(KrViewItem *item) { // update status bar if (item) krApp->statusBarUpdate(item->description()); // update sidebar; which panel to display on? Sidebar *p; if (sidebar && !sidebar->isHidden()) { p = sidebar; } else if(otherPanel()->gui->sidebar && !otherPanel()->gui->sidebar->isHidden()) { p = otherPanel()->gui->sidebar; } else { return; } p->update(item ? func->files()->getFileItem(item->name()) : nullptr); } void ListPanel::otherPanelChanged() { func->syncURL = QUrl(); } void ListPanel::getFocusCandidates(QVector &widgets) { if(urlNavigator->editor()->isVisible()) widgets << urlNavigator->editor(); if(view->widget()->isVisible()) widgets << view->widget(); if(sidebar && sidebar->isVisible()) widgets << sidebar; } void ListPanel::updateButtons() { backButton->setEnabled(func->history->canGoBack()); forwardButton->setEnabled(func->history->canGoForward()); historyButton->setEnabled(func->history->count() > 1); cdRootButton->setEnabled(!virtualPath().matches(QUrl::fromLocalFile(ROOT_DIR), QUrl::StripTrailingSlash)); cdUpButton->setEnabled(!func->files()->isRoot()); cdHomeButton->setEnabled(!func->atHome()); } void ListPanel::newTab(KrViewItem *it) { if (!it) return; else if (it->name() == "..") { newTab(KIO::upUrl(virtualPath()), true); } else if (func->getFileItem(it)->isDir()) { QUrl url = virtualPath(); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + (it->name())); newTab(url, true); } } void ListPanel::newTab(const QUrl &url, bool nextToThis) { _manager->newTab(url, nextToThis ? this : 0); } void ListPanel::slotNavigatorUrlChanged(const QUrl &url) { if (url == _navigatorUrl) return; // this is the URL we just set ourself if (!isNavigatorEditModeSet()) { urlNavigator->setUrlEditable(false); } func->openUrl(KrServices::escapeFileUrl(url), QString(), true); } void ListPanel::resetNavigatorMode() { if (isNavigatorEditModeSet()) return; // set to "navigate" mode if url wasn't changed if (urlNavigator->uncommittedUrl().matches(virtualPath(), QUrl::StripTrailingSlash)) { // NOTE: this also sets focus to the navigator urlNavigator->setUrlEditable(false); slotFocusOnMe(); } } int ListPanel::sidebarPosition() const { int pos = sidebarSplitter->orientation() == Qt::Vertical ? 1 : 0; return pos + (qobject_cast(sidebarSplitter->widget(0)) == NULL ? 2 : 0); } void ListPanel::setSidebarPosition(int pos) { sidebarSplitter->setOrientation(pos % 2 == 0 ? Qt::Horizontal : Qt::Vertical); if ((pos < 2) != (qobject_cast(sidebarSplitter->widget(0)) != NULL)) { sidebarSplitter->insertWidget(0, sidebarSplitter->widget(1)); // swapping widgets in splitter } } void ListPanel::connectQuickSizeCalculator(SizeCalculator *sizeCalculator) { connect(sizeCalculator, &SizeCalculator::started, this, [=]() { quickSizeCalcProgress->reset(); quickSizeCalcProgress->show(); cancelQuickSizeCalcButton->show(); }); connect(cancelQuickSizeCalcButton, &QToolButton::clicked, sizeCalculator, &SizeCalculator::cancel); connect(sizeCalculator, &SizeCalculator::progressChanged, quickSizeCalcProgress, &QProgressBar::setValue); connect(sizeCalculator, &SizeCalculator::finished, this, [=]() { cancelQuickSizeCalcButton->hide(); quickSizeCalcProgress->hide(); }); } diff --git a/krusader/Panel/sidebar.cpp b/krusader/Panel/sidebar.cpp index d130300a..f2dd5233 100644 --- a/krusader/Panel/sidebar.cpp +++ b/krusader/Panel/sidebar.cpp @@ -1,290 +1,289 @@ /***************************************************************************** * Copyright (C) 2003 Shie Erlich * * Copyright (C) 2003 Rafi Yanai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "sidebar.h" #include "krfiletreeview.h" #include "krpanel.h" #include "panelfunc.h" #include "viewactions.h" #include "../defaults.h" #include "../icon.h" -#include "../kicons.h" #include "../Dialogs/krsqueezedtextlabel.h" #include "../FileSystem/fileitem.h" #include "../FileSystem/filesystem.h" #include "../KViewer/diskusageviewer.h" #include "../KViewer/panelviewer.h" #include "PanelView/krview.h" #include "PanelView/krviewitem.h" // QtCore #include #include // QtWidgets #include #include #include #include #include Sidebar::Sidebar(QWidget *parent) : QWidget(parent), stack(0), imageFilePreview(0), pjob(0) { QGridLayout * layout = new QGridLayout(this); layout->setContentsMargins(0, 0, 0, 0); // create the label+buttons setup dataLine = new KrSqueezedTextLabel(this); KConfigGroup lg(krConfig, "Look&Feel"); dataLine->setFont(lg.readEntry("Filelist Font", _FilelistFont)); // --- hack: setup colors to be the same as an inactive panel dataLine->setBackgroundRole(QPalette::Window); int sheight = QFontMetrics(dataLine->font()).height() + 4; dataLine->setMaximumHeight(sheight); btns = new QButtonGroup(this); btns->setExclusive(true); connect(btns, SIGNAL(buttonClicked(int)), this, SLOT(tabSelected(int))); treeBtn = new QToolButton(this); treeBtn->setToolTip(i18n("Tree Panel: a tree view of the local file system")); treeBtn->setIcon(Icon("view-list-tree")); treeBtn->setFixedSize(20, 20); treeBtn->setCheckable(true); btns->addButton(treeBtn, Tree); previewBtn = new QToolButton(this); previewBtn->setToolTip(i18n("Preview Panel: display a preview of the current file")); previewBtn->setIcon(Icon("view-preview")); previewBtn->setFixedSize(20, 20); previewBtn->setCheckable(true); btns->addButton(previewBtn, Preview); viewerBtn = new QToolButton(this); viewerBtn->setToolTip(i18n("View Panel: view the current file")); viewerBtn->setIcon(Icon("zoom-original")); viewerBtn->setFixedSize(20, 20); viewerBtn->setCheckable(true); btns->addButton(viewerBtn, View); duBtn = new QToolButton(this); duBtn->setToolTip(i18n("Disk Usage Panel: view the usage of a folder")); duBtn->setIcon(Icon("kr_diskusage")); duBtn->setFixedSize(20, 20); duBtn->setCheckable(true); btns->addButton(duBtn, DskUsage); layout->addWidget(dataLine, 0, 0); layout->addWidget(treeBtn, 0, 1); layout->addWidget(previewBtn, 0, 2); layout->addWidget(viewerBtn, 0, 3); layout->addWidget(duBtn, 0, 4); // create a widget stack on which to put the parts stack = new QStackedWidget(this); // create the tree part ---------- tree = new KrFileTreeView(stack); tree->setProperty("KrusaderWidgetId", QVariant(Tree)); stack->addWidget(tree); // NOTE: the F2 key press event is caught before it gets to the tree tree->setEditTriggers(QAbstractItemView::EditKeyPressed); // connecting signal to signal connect(tree, &KrFileTreeView::urlActivated, this, &Sidebar::urlActivated); // create the quickview part ------ imageFilePreview = new KImageFilePreview(stack); imageFilePreview->setProperty("KrusaderWidgetId", QVariant(Preview)); stack->addWidget(imageFilePreview); // create the panelview fileViewer = new PanelViewer(stack); fileViewer->setProperty("KrusaderWidgetId", QVariant(View)); // kparts demand too much width QSizePolicy sizePolicy = fileViewer->sizePolicy(); sizePolicy.setHorizontalPolicy(QSizePolicy::Ignored); fileViewer->setSizePolicy(sizePolicy); stack->addWidget(fileViewer); connect(fileViewer, &PanelViewer::openUrlRequest, this, &Sidebar::handleOpenUrlRequest); // create the disk usage view diskusage = new DiskUsageViewer(stack); diskusage->setStatusLabel(dataLine, i18n("Disk Usage:")); diskusage->setProperty("KrusaderWidgetId", QVariant(DskUsage)); stack->addWidget(diskusage); connect(diskusage, &DiskUsageViewer::openUrlRequest, this, &Sidebar::handleOpenUrlRequest); // -------- finish the layout (General one) layout->addWidget(stack, 1, 0, 1, 5); hide(); // for not to open the 3rd hand tool at start (selecting the last used tab) setCurrentPage(0); } Sidebar::~Sidebar() {} void Sidebar::saveSettings(KConfigGroup cfg) const { tree->saveSettings(cfg); } void Sidebar::restoreSettings(const KConfigGroup &cfg) { tree->restoreSettings(cfg); } void Sidebar::setCurrentPage(int id) { QAbstractButton * curr = btns->button(id); if (curr) { curr->click(); } } void Sidebar::show() { QWidget::show(); tabSelected(currentPage()); } void Sidebar::hide() { QWidget::hide(); if (currentPage() == View) fileViewer->closeUrl(); if (currentPage() == DskUsage) diskusage->closeUrl(); } void Sidebar::focusInEvent(QFocusEvent*) { switch (currentPage()) { case Preview: if (!isHidden()) imageFilePreview->setFocus(); break; case View: if (!isHidden() && fileViewer->part() && fileViewer->part()->widget()) fileViewer->part()->widget()->setFocus(); break; case DskUsage: if (!isHidden() && diskusage->getWidget() && diskusage->getWidget()->currentWidget()) diskusage->getWidget()->currentWidget()->setFocus(); break; case Tree: if (!isHidden()) tree->setFocus(); break; } } void Sidebar::handleOpenUrlRequest(const QUrl &url) { QMimeDatabase db; QMimeType mime = db.mimeTypeForUrl(url); if (mime.isValid() && mime.name() == "inode/directory") ACTIVE_PANEL->func->openUrl(url); } void Sidebar::tabSelected(int id) { QUrl url; const FileItem *fileitem = 0; if (ACTIVE_PANEL && ACTIVE_PANEL->view) fileitem = ACTIVE_PANEL->func->files()->getFileItem(ACTIVE_PANEL->view->getCurrentItem()); if(fileitem) url = fileitem->getUrl(); // if tab is tree, set something logical in the data line switch (id) { case Tree: stack->setCurrentWidget(tree); dataLine->setText(i18n("Tree:")); if (!isHidden()) tree->setFocus(); if (ACTIVE_PANEL) tree->setCurrentUrl(ACTIVE_PANEL->virtualPath()); break; case Preview: stack->setCurrentWidget(imageFilePreview); dataLine->setText(i18n("Preview:")); update(fileitem); break; case View: stack->setCurrentWidget(fileViewer); dataLine->setText(i18n("View:")); update(fileitem); if (!isHidden() && fileViewer->part() && fileViewer->part()->widget()) fileViewer->part()->widget()->setFocus(); break; case DskUsage: stack->setCurrentWidget(diskusage); dataLine->setText(i18n("Disk Usage:")); update(fileitem); if (!isHidden() && diskusage->getWidget() && diskusage->getWidget()->currentWidget()) diskusage->getWidget()->currentWidget()->setFocus(); break; } if (id != View) fileViewer->closeUrl(); } // decide which part to update, if at all void Sidebar::update(const FileItem *fileitem) { if (isHidden()) return; QUrl url; if(fileitem) url = fileitem->getUrl(); switch (currentPage()) { case Preview: imageFilePreview->showPreview(url); dataLine->setText(i18n("Preview: %1", url.fileName())); break; case View: if(fileitem && !fileitem->isDir() && fileitem->isReadable()) fileViewer->openUrl(fileitem->getUrl()); else fileViewer->closeUrl(); dataLine->setText(i18n("View: %1", url.fileName())); break; case DskUsage: { if(fileitem && !fileitem->isDir()) url = KIO::upUrl(url); dataLine->setText(i18n("Disk Usage: %1", url.fileName())); diskusage->openUrl(url); } break; case Tree: // nothing to do break; } } void Sidebar::onPanelPathChange(const QUrl &url) { switch (currentPage()) { case Tree: if (url.isLocalFile()) { tree->setCurrentUrl(url); // synchronize panel path with tree path } break; } } diff --git a/krusader/Search/krsearchdialog.cpp b/krusader/Search/krsearchdialog.cpp index f5d18e63..3b95a125 100644 --- a/krusader/Search/krsearchdialog.cpp +++ b/krusader/Search/krsearchdialog.cpp @@ -1,671 +1,670 @@ /***************************************************************************** * Copyright (C) 2001 Shie Erlich * * Copyright (C) 2001 Rafi Yanai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "krsearchdialog.h" // QtCore #include #include // QtGui #include #include #include #include #include #include // QtWidgets #include #include #include #include #include #include #include #include #include "krsearchmod.h" #include "../Dialogs/krdialogs.h" #include "../Dialogs/krspecialwidgets.h" #include "../Dialogs/krsqueezedtextlabel.h" #include "../FileSystem/fileitem.h" #include "../FileSystem/krquery.h" #include "../FileSystem/virtualfilesystem.h" #include "../Filter/filtertabs.h" #include "../Filter/generalfilter.h" #include "../KViewer/krviewer.h" #include "../Panel/PanelView/krview.h" #include "../Panel/PanelView/krviewfactory.h" #include "../Panel/PanelView/krviewitem.h" #include "../Panel/krpanel.h" #include "../Panel/krsearchbar.h" #include "../Panel/panelfunc.h" #include "../defaults.h" -#include "../kicons.h" #include "../kractions.h" #include "../krglobal.h" -#include "../icon.h" +#include "../filelisticon.h" #include "../krservices.h" #include "../krslots.h" #include "../krusaderview.h" #include "../panelmanager.h" #define RESULTVIEW_TYPE 0 class SearchResultContainer : public DirListerInterface { public: explicit SearchResultContainer(QObject *parent) : DirListerInterface(parent) {} virtual ~SearchResultContainer() { clear(); } virtual QList fileItems() const Q_DECL_OVERRIDE { return _fileItems; } virtual unsigned long numFileItems() const Q_DECL_OVERRIDE { return _fileItems.count(); } virtual bool isRoot() const Q_DECL_OVERRIDE { return true; } void clear() { emit cleared(); foreach(FileItem *fileitem, _fileItems) delete fileitem; _fileItems.clear(); _foundText.clear(); } void addItem(const FileItem &file, const QString &foundText) { const QString path = file.getUrl().toDisplayString(QUrl::PreferLocalFile); FileItem *fileitem = FileItem::createCopy(file, path); _fileItems << fileitem; if(!foundText.isEmpty()) _foundText[fileitem] = foundText; emit addedFileItem(fileitem); } QString foundText(const FileItem *fileitem) { return _foundText[fileitem]; } private: QList _fileItems; QHash _foundText; }; KrSearchDialog *KrSearchDialog::SearchDialog = 0; QString KrSearchDialog::lastSearchText = QString('*'); int KrSearchDialog::lastSearchType = 0; bool KrSearchDialog::lastSearchForCase = false; bool KrSearchDialog::lastContainsWholeWord = false; bool KrSearchDialog::lastContainsWithCase = false; bool KrSearchDialog::lastSearchInSubDirs = true; bool KrSearchDialog::lastSearchInArchives = false; bool KrSearchDialog::lastFollowSymLinks = false; bool KrSearchDialog::lastContainsRegExp = false; // class starts here ///////////////////////////////////////// KrSearchDialog::KrSearchDialog(QString profile, QWidget* parent) : QDialog(parent), query(0), searcher(0), isBusy(false), closed(false) { KConfigGroup group(krConfig, "Search"); setWindowTitle(i18n("Krusader::Search")); setWindowIcon(Icon("system-search")); QGridLayout* searchBaseLayout = new QGridLayout(this); searchBaseLayout->setSpacing(6); searchBaseLayout->setContentsMargins(11, 11, 11, 11); // creating the dialog buttons ( Search, Stop, Close ) QHBoxLayout* buttonsLayout = new QHBoxLayout(); buttonsLayout->setSpacing(6); buttonsLayout->setContentsMargins(0, 0, 0, 0); profileManager = new ProfileManager("SearcherProfile", this); buttonsLayout->addWidget(profileManager); searchTextToClipboard = new QCheckBox(this); searchTextToClipboard->setText(i18n("Query to clipboard")); searchTextToClipboard->setToolTip(i18n("Place search text to clipboard when a found file is opened.")); searchTextToClipboard->setCheckState(static_cast(group.readEntry("QueryToClipboard", 0))); connect(searchTextToClipboard, &QCheckBox::stateChanged, this, [=](int state) { KConfigGroup group(krConfig, "Search"); group.writeEntry("QueryToClipboard", state); }); buttonsLayout->addWidget(searchTextToClipboard); QSpacerItem* spacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); buttonsLayout->addItem(spacer); mainFeedToListBoxBtn = new QPushButton(this); mainFeedToListBoxBtn->setText(i18n("Feed to listbox")); mainFeedToListBoxBtn->setIcon(Icon("list-add")); mainFeedToListBoxBtn->setEnabled(false); buttonsLayout->addWidget(mainFeedToListBoxBtn); mainSearchBtn = new QPushButton(this); mainSearchBtn->setText(i18n("Search")); mainSearchBtn->setIcon(Icon("edit-find")); mainSearchBtn->setDefault(true); buttonsLayout->addWidget(mainSearchBtn); mainStopBtn = new QPushButton(this); mainStopBtn->setEnabled(false); mainStopBtn->setText(i18n("Stop")); mainStopBtn->setIcon(Icon("process-stop")); buttonsLayout->addWidget(mainStopBtn); mainCloseBtn = new QPushButton(this); mainCloseBtn->setText(i18n("Close")); mainCloseBtn->setIcon(Icon("dialog-close")); buttonsLayout->addWidget(mainCloseBtn); searchBaseLayout->addLayout(buttonsLayout, 1, 0); // creating the searcher tabs searcherTabs = new QTabWidget(this); filterTabs = FilterTabs::addTo(searcherTabs, FilterTabs::Default); generalFilter = (GeneralFilter *)filterTabs->get("GeneralFilter"); QWidget* resultTab = new QWidget(searcherTabs); QGridLayout* resultLayout = new QGridLayout(resultTab); resultLayout->setSpacing(6); resultLayout->setContentsMargins(6, 6, 6, 6); // creating the result tab QHBoxLayout* resultLabelLayout = new QHBoxLayout(); resultLabelLayout->setSpacing(6); resultLabelLayout->setContentsMargins(0, 0, 0, 0); foundLabel = new QLabel(resultTab); QSizePolicy foundpolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); foundpolicy.setHeightForWidth(foundLabel->sizePolicy().hasHeightForWidth()); foundLabel->setSizePolicy(foundpolicy); foundLabel->setFrameShape(QLabel::StyledPanel); foundLabel->setFrameShadow(QLabel::Sunken); foundLabel->setText(i18n("Found 0 matches.")); resultLabelLayout->addWidget(foundLabel); searchingLabel = new KSqueezedTextLabel(resultTab); searchingLabel->setFrameShape(QLabel::StyledPanel); searchingLabel->setFrameShadow(QLabel::Sunken); searchingLabel->setText(""); resultLabelLayout->addWidget(searchingLabel); resultLayout->addLayout(resultLabelLayout, 2, 0); // creating the result list view result = new SearchResultContainer(this); // the view resultView = KrViewFactory::createView(RESULTVIEW_TYPE, resultTab, krConfig); resultView->init(false); resultView->restoreSettings(KConfigGroup(&group, "ResultView")); resultView->setMainWindow(this); resultView->prepareForActive(); resultView->refreshColors(); resultView->setFiles(result); resultView->refresh(); resultLayout->addWidget(resultView->widget(), 0, 0); // search bar searchBar = new KrSearchBar(resultView, this); searchBar->hide(); resultLayout->addWidget(searchBar, 1, 0); QHBoxLayout* foundTextLayout = new QHBoxLayout(); foundTextLayout->setSpacing(6); foundTextLayout->setContentsMargins(0, 0, 0, 0); QLabel *l1 = new QLabel(resultTab); QSizePolicy l1policy(QSizePolicy::Minimum, QSizePolicy::Minimum); l1policy.setHeightForWidth(l1->sizePolicy().hasHeightForWidth()); l1->setSizePolicy(l1policy); l1->setFrameShape(QLabel::StyledPanel); l1->setFrameShadow(QLabel::Sunken); l1->setText(i18n("Text found:")); foundTextLayout->addWidget(l1); foundTextLabel = new KrSqueezedTextLabel(resultTab); foundTextLabel->setFrameShape(QLabel::StyledPanel); foundTextLabel->setFrameShadow(QLabel::Sunken); foundTextLabel->setText(""); foundTextLayout->addWidget(foundTextLabel); resultLayout->addLayout(foundTextLayout, 3, 0); searcherTabs->addTab(resultTab, i18n("&Results")); searchBaseLayout->addWidget(searcherTabs, 0, 0); // signals and slots connections connect(mainSearchBtn, SIGNAL(clicked()), this, SLOT(startSearch())); connect(mainStopBtn, SIGNAL(clicked()), this, SLOT(stopSearch())); connect(mainCloseBtn, SIGNAL(clicked()), this, SLOT(closeDialog())); connect(mainFeedToListBoxBtn, SIGNAL(clicked()), this, SLOT(feedToListBox())); connect(profileManager, SIGNAL(loadFromProfile(QString)), filterTabs, SLOT(loadFromProfile(QString))); connect(profileManager, SIGNAL(saveToProfile(QString)), filterTabs, SLOT(saveToProfile(QString))); connect(resultView->op(), SIGNAL(currentChanged(KrViewItem*)), SLOT(currentChanged(KrViewItem*))); connect(resultView->op(), SIGNAL(executed(QString)), SLOT(executed(QString))); connect(resultView->op(), SIGNAL(contextMenu(QPoint)), SLOT(contextMenu(QPoint))); // tab order setTabOrder(mainSearchBtn, mainCloseBtn); setTabOrder(mainCloseBtn, mainStopBtn); setTabOrder(mainStopBtn, searcherTabs); setTabOrder(searcherTabs, resultView->widget()); sizeX = group.readEntry("Window Width", -1); sizeY = group.readEntry("Window Height", -1); if (sizeX != -1 && sizeY != -1) resize(sizeX, sizeY); if (group.readEntry("Window Maximized", false)) showMaximized(); else show(); generalFilter->searchFor->setFocus(); // finaly, load a profile of apply defaults: if (profile.isEmpty()) { // load the last used values generalFilter->searchFor->setEditText(lastSearchText); generalFilter->searchFor->lineEdit()->selectAll(); generalFilter->ofType->setCurrentIndex(lastSearchType); generalFilter->searchForCase->setChecked(lastSearchForCase); generalFilter->containsWholeWord->setChecked(lastContainsWholeWord); generalFilter->containsTextCase->setChecked(lastContainsWithCase); generalFilter->containsRegExp->setChecked(lastContainsRegExp); generalFilter->searchInDirs->setChecked(lastSearchInSubDirs); generalFilter->searchInArchives->setChecked(lastSearchInArchives); generalFilter->followLinks->setChecked(lastFollowSymLinks); // the path in the active panel should be the default search location generalFilter->searchIn->lineEdit()->setText(ACTIVE_PANEL->virtualPath().toDisplayString(QUrl::PreferLocalFile)); } else profileManager->loadProfile(profile); // important: call this _after_ you've connected profileManager ot the loadFromProfile!! } KrSearchDialog::~KrSearchDialog() { delete query; query = 0; delete resultView; resultView = 0; } void KrSearchDialog::closeDialog(bool isAccept) { if(isBusy) { closed = true; return; } // stop the search if it's on-going if (searcher != 0) { delete searcher; searcher = 0; } // saving the searcher state KConfigGroup group(krConfig, "Search"); group.writeEntry("Window Width", sizeX); group.writeEntry("Window Height", sizeY); group.writeEntry("Window Maximized", isMaximized()); resultView->saveSettings(KConfigGroup(&group, "ResultView")); lastSearchText = generalFilter->searchFor->currentText(); lastSearchType = generalFilter->ofType->currentIndex(); lastSearchForCase = generalFilter->searchForCase->isChecked(); lastContainsWholeWord = generalFilter->containsWholeWord->isChecked(); lastContainsWithCase = generalFilter->containsTextCase->isChecked(); lastContainsRegExp = generalFilter->containsRegExp->isChecked(); lastSearchInSubDirs = generalFilter->searchInDirs->isChecked(); lastSearchInArchives = generalFilter->searchInArchives->isChecked(); lastFollowSymLinks = generalFilter->followLinks->isChecked(); hide(); SearchDialog = 0; if (isAccept) QDialog::accept(); else QDialog::reject(); this->deleteLater(); } void KrSearchDialog::reject() { closeDialog(false); } void KrSearchDialog::resizeEvent(QResizeEvent *e) { if (!isMaximized()) { sizeX = e->size().width(); sizeY = e->size().height(); } } void KrSearchDialog::slotFound(const FileItem &file, const QString &foundText) { result->addItem(file, foundText); foundLabel->setText(i18np("Found %1 match.", "Found %1 matches.", result->numFileItems())); } bool KrSearchDialog::gui2query() { // prepare the query ... /////////////////// names, locations and greps if (query != 0) { delete query; query = 0; } query = new KRQuery(); return filterTabs->fillQuery(query); } void KrSearchDialog::startSearch() { if(isBusy) return; // prepare the query ///////////////////////////////////////////// if (!gui2query()) return; // first, informative messages if (query->searchInArchives()) { KMessageBox::information(this, i18n("Since you chose to also search in archives, " "note the following limitations:\n" "You cannot search for text (grep) while doing" " a search that includes archives."), 0, "searchInArchives"); } // prepare the gui /////////////////////////////////////////////// mainSearchBtn->setEnabled(false); mainCloseBtn->setEnabled(false); mainStopBtn->setEnabled(true); mainFeedToListBoxBtn->setEnabled(false); result->clear(); resultView->setSortMode(KrViewProperties::NoColumn, 0); searchingLabel->setText(""); foundLabel->setText(i18n("Found 0 matches.")); searcherTabs->setCurrentIndex(2); // show the results page foundTextLabel->setText(""); isBusy = true; qApp->processEvents(); // start the search. if (searcher != 0) abort(); searcher = new KRSearchMod(query); connect(searcher, SIGNAL(searching(QString)), searchingLabel, SLOT(setText(QString))); connect(searcher, &KRSearchMod::found, this, &KrSearchDialog::slotFound); connect(searcher, SIGNAL(finished()), this, SLOT(stopSearch())); searcher->start(); isBusy = false; delete searcher; searcher = 0; // gui stuff mainSearchBtn->setEnabled(true); mainCloseBtn->setEnabled(true); mainStopBtn->setEnabled(false); if (result->numFileItems()) mainFeedToListBoxBtn->setEnabled(true); searchingLabel->setText(i18n("Finished searching.")); if (closed) closeDialog(); } void KrSearchDialog::stopSearch() { if (searcher != 0) { searcher->stop(); disconnect(searcher, 0, 0, 0); } } void KrSearchDialog::executed(const QString &name) { // 'name' is (local) file path or complete URL QString path = name; QString fileName; if(!name.endsWith('/')) { // not a directory, split filename and path int idx = name.lastIndexOf("/"); fileName = name.mid(idx+1); path = name.left(idx); } QUrl url(path); if (url.scheme().isEmpty()) { url = QUrl::fromLocalFile(path); } ACTIVE_FUNC->openUrl(url, fileName); showMinimized(); } void KrSearchDialog::currentChanged(KrViewItem *item) { if(!item) return; QString text = result->foundText(item->getFileItem()); if(!text.isEmpty()) { // ugly hack: find the and in the text, then // use it to set the are which we don't want squeezed int idx = text.indexOf("") - 4; // take "" into account int length = text.indexOf("") - idx + 4; foundTextLabel->setText(text, idx, length); } } void KrSearchDialog::closeEvent(QCloseEvent *e) { /* if searching is in progress we must not close the window */ if (isBusy) /* because qApp->processEvents() is called by the searcher and */ { /* at window desruction, the searcher object will be deleted */ stopSearch(); /* instead we stop searching */ closed = true; /* and after stopping: startSearch can close the window */ e->ignore(); /* ignoring the close event */ } else QDialog::closeEvent(e); /* if no searching, let QDialog handle the event */ } void KrSearchDialog::keyPressEvent(QKeyEvent *e) { // TODO: don't use hardcoded shortcuts if (isBusy && e->key() == Qt::Key_Escape) { /* at searching we must not close the window */ stopSearch(); /* so we simply stop searching */ return; } if (resultView->widget()->hasFocus()) { if ((e->key() | e->modifiers()) == (Qt::CTRL | Qt::Key_I)) { searchBar->showBar(KrSearchBar::MODE_FILTER); } else if (e->key() == Qt::Key_F4) { tryPlaceSearchQueryToClipboard(); editCurrent(); return; } else if (e->key() == Qt::Key_F3) { tryPlaceSearchQueryToClipboard(); viewCurrent(); return; } else if (e->key() == Qt::Key_F10) { compareByContent(); return; } else if (KrGlobal::copyShortcut == QKeySequence(e->key() | e->modifiers())) { copyToClipBoard(); return; } } QDialog::keyPressEvent(e); } void KrSearchDialog::editCurrent() { KrViewItem *current = resultView->getCurrentKrViewItem(); if (current) KrViewer::edit(current->getFileItem()->getUrl(), this); } void KrSearchDialog::viewCurrent() { KrViewItem *current = resultView->getCurrentKrViewItem(); if (current) KrViewer::view(current->getFileItem()->getUrl(), this); } void KrSearchDialog::compareByContent() { KrViewItemList list; resultView->getSelectedKrViewItems(&list); if (list.count() != 2) return; SLOTS->compareContent(list[0]->getFileItem()->getUrl(),list[1]->getFileItem()->getUrl()); } void KrSearchDialog::contextMenu(const QPoint &pos) { // create the menu QMenu popup; popup.setTitle(i18n("Krusader Search")); QAction *actView = popup.addAction(i18n("View File (F3)")); QAction *actEdit = popup.addAction(i18n("Edit File (F4)")); QAction *actComp = popup.addAction(i18n("Compare by content (F10)")); if(resultView->numSelected() != 2) actComp->setEnabled(false); QAction *actClip = popup.addAction(i18n("Copy selected to clipboard")); QAction *result = popup.exec(pos); // check out the user's option if (result == actView) viewCurrent(); else if (result == actEdit) editCurrent(); else if (result == actClip) copyToClipBoard(); else if (result == actComp) compareByContent(); } void KrSearchDialog::feedToListBox() { VirtualFileSystem virtFilesystem; virtFilesystem.scanDir(QUrl::fromLocalFile("/")); KConfigGroup group(krConfig, "Search"); int listBoxNum = group.readEntry("Feed To Listbox Counter", 1); QString queryName; if(query) { QString where = KrServices::toStringList(query->searchInDirs()).join(", "); if(query->content().isEmpty()) queryName = i18n("Search results for \"%1\" in %2", query->nameFilter(), where); else queryName = i18n("Search results for \"%1\" containing \"%2\" in %3", query->nameFilter(), query->content(), where); } QString fileSystemName; do { fileSystemName = i18n("Search results") + QString(" %1").arg(listBoxNum++); } while (virtFilesystem.getFileItem(fileSystemName) != 0); group.writeEntry("Feed To Listbox Counter", listBoxNum); KConfigGroup ga(krConfig, "Advanced"); if (ga.readEntry("Confirm Feed to Listbox", _ConfirmFeedToListbox)) { bool ok; fileSystemName = QInputDialog::getText(this, i18n("Query name"), i18n("Here you can name the file collection"), QLineEdit::Normal, fileSystemName, &ok); if (! ok) return; } QList urlList; foreach(FileItem *fileitem, result->fileItems()) urlList.push_back(fileitem->getUrl()); mainSearchBtn->setEnabled(false); mainCloseBtn->setEnabled(false); mainFeedToListBoxBtn->setEnabled(false); isBusy = true; const QUrl url = QUrl(QString("virt:/") + fileSystemName); virtFilesystem.scanDir(url); virtFilesystem.addFiles(urlList); virtFilesystem.setMetaInformation(queryName); //ACTIVE_FUNC->openUrl(url); ACTIVE_MNG->slotNewTab(url); isBusy = false; closeDialog(); } void KrSearchDialog::copyToClipBoard() { QList urls; foreach(FileItem *fileitem, result->fileItems()) urls.push_back(fileitem->getUrl()); if (urls.count() == 0) return; QMimeData *mimeData = new QMimeData; - mimeData->setImageData(FL_LOADICON("file")); + mimeData->setImageData(FileListIcon("file").pixmap()); mimeData->setUrls(urls); QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); } void KrSearchDialog::tryPlaceSearchQueryToClipboard() { if (searchTextToClipboard->isChecked() && !generalFilter->containsText->currentText().isEmpty() && QApplication::clipboard()->text() != generalFilter->containsText->currentText()) { QApplication::clipboard()->setText(generalFilter->containsText->currentText()); } } diff --git a/krusader/Synchronizer/synchronizergui.cpp b/krusader/Synchronizer/synchronizergui.cpp index 27859875..a6ed6aae 100644 --- a/krusader/Synchronizer/synchronizergui.cpp +++ b/krusader/Synchronizer/synchronizergui.cpp @@ -1,1629 +1,1628 @@ /***************************************************************************** * Copyright (C) 2003 Csaba Karai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "synchronizergui.h" #include "../krglobal.h" -#include "../icon.h" +#include "../filelisticon.h" #include "../defaults.h" #include "../krusaderview.h" #include "../Panel/listpanel.h" #include "../Panel/panelfunc.h" #include "../FileSystem/krpermhandler.h" #include "../KViewer/krviewer.h" #include "../Dialogs/krspwidgets.h" #include "../FileSystem/krquery.h" #include "../krservices.h" #include "../krslots.h" -#include "../kicons.h" #include "synchronizedialog.h" #include "feedtolistboxdialog.h" #include "synchronizercolors.h" // QtCore #include #include #include #include // QtGui #include #include #include #include #include #include #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class SynchronizerListView : public KrTreeWidget { private: Synchronizer *synchronizer; bool isLeft; public: SynchronizerListView(Synchronizer * sync, QWidget * parent) : KrTreeWidget(parent), synchronizer(sync) { } void mouseMoveEvent(QMouseEvent * e) { isLeft = ((e->modifiers() & Qt::ShiftModifier) == 0); KrTreeWidget::mouseMoveEvent(e); } void startDrag(Qt::DropActions /* supportedActs */) { QList urls; unsigned ndx = 0; SynchronizerFileItem *currentItem; while ((currentItem = synchronizer->getItemAt(ndx++)) != 0) { SynchronizerGUI::SyncViewItem *viewItem = (SynchronizerGUI::SyncViewItem *)currentItem->userData(); if (!viewItem || !viewItem->isSelected() || viewItem->isHidden()) continue; SynchronizerFileItem *item = viewItem->synchronizerItemRef(); if (item) { if (isLeft && item->existsInLeft()) { QString leftDirName = item->leftDirectory().isEmpty() ? "" : item->leftDirectory() + '/'; QUrl leftURL = Synchronizer::fsUrl(synchronizer->leftBaseDirectory() + leftDirName + item->leftName()); urls.push_back(leftURL); } else if (!isLeft && item->existsInRight()) { QString rightDirName = item->rightDirectory().isEmpty() ? "" : item->rightDirectory() + '/'; QUrl rightURL = Synchronizer::fsUrl(synchronizer->rightBaseDirectory() + rightDirName + item->rightName()); urls.push_back(rightURL); } } } if (urls.count() == 0) return; QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; - mimeData->setImageData(FL_LOADICON(isLeft ? "arrow-left-double" : "arrow-right-double")); + mimeData->setImageData(FileListIcon(isLeft ? "arrow-left-double" : "arrow-right-double").pixmap()); mimeData->setUrls(urls); drag->setMimeData(mimeData); drag->start(); } }; SynchronizerGUI::SynchronizerGUI(QWidget* parent, QUrl leftURL, QUrl rightURL, QStringList selList) : QDialog(parent) { initGUI(QString(), leftURL, rightURL, selList); } SynchronizerGUI::SynchronizerGUI(QWidget* parent, QString profile) : QDialog(parent) { initGUI(profile, QUrl(), QUrl(), QStringList()); } void SynchronizerGUI::initGUI(QString profileName, QUrl leftURL, QUrl rightURL, QStringList selList) { setAttribute(Qt::WA_DeleteOnClose); selectedFiles = selList; isComparing = wasClosed = wasSync = false; firstResize = true; sizeX = sizeY = -1; bool equalSizes = false; hasSelectedFiles = (selectedFiles.count() != 0); if (leftURL.isEmpty()) leftURL = QUrl::fromLocalFile(ROOT_DIR); if (rightURL.isEmpty()) rightURL = QUrl::fromLocalFile(ROOT_DIR); setWindowTitle(i18n("Krusader::Synchronize Folders")); QGridLayout *synchGrid = new QGridLayout(this); synchGrid->setSpacing(6); synchGrid->setContentsMargins(11, 11, 11, 11); synchronizerTabs = new QTabWidget(this); /* ============================== Compare groupbox ============================== */ QWidget *synchronizerTab = new QWidget(this); QGridLayout *synchronizerGrid = new QGridLayout(synchronizerTab); synchronizerGrid->setSpacing(6); synchronizerGrid->setContentsMargins(11, 11, 11, 11); QGroupBox *compareDirs = new QGroupBox(synchronizerTab); compareDirs->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); compareDirs->setTitle(i18n("Folder Comparison")); QGridLayout *grid = new QGridLayout(compareDirs); grid->setSpacing(6); grid->setContentsMargins(11, 11, 11, 11); leftDirLabel = new QLabel(compareDirs); leftDirLabel->setAlignment(Qt::AlignHCenter); grid->addWidget(leftDirLabel, 0 , 0); QLabel *filterLabel = new QLabel(compareDirs); filterLabel->setText(i18n("File &Filter:")); filterLabel->setAlignment(Qt::AlignHCenter); grid->addWidget(filterLabel, 0 , 1); rightDirLabel = new QLabel(compareDirs); rightDirLabel->setAlignment(Qt::AlignHCenter); grid->addWidget(rightDirLabel, 0 , 2); KConfigGroup group(krConfig, "Synchronize"); leftLocation = new KHistoryComboBox(false, compareDirs); leftLocation->setMaxCount(25); // remember 25 items leftLocation->setDuplicatesEnabled(false); leftLocation->setEditable(true); leftLocation->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); QStringList list = group.readEntry("Left Folder History", QStringList()); leftLocation->setHistoryItems(list); KUrlRequester *leftUrlReq = new KUrlRequester(leftLocation, compareDirs); leftUrlReq->setUrl(leftURL); leftUrlReq->setMode(KFile::Directory); leftUrlReq->setMinimumWidth(250); grid->addWidget(leftUrlReq, 1 , 0); leftLocation->setWhatsThis(i18n("The left base folder used during the synchronization process.")); leftUrlReq->setEnabled(!hasSelectedFiles); leftLocation->setEnabled(!hasSelectedFiles); leftDirLabel->setBuddy(leftLocation); fileFilter = new KHistoryComboBox(false, compareDirs); fileFilter->setMaxCount(25); // remember 25 items fileFilter->setDuplicatesEnabled(false); fileFilter->setMinimumWidth(100); fileFilter->setMaximumWidth(100); fileFilter->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); list = group.readEntry("File Filter", QStringList()); fileFilter->setHistoryItems(list); fileFilter->setEditText("*"); grid->addWidget(fileFilter, 1 , 1); filterLabel->setBuddy(fileFilter); QString wtFilter = "

" + i18n("

The filename filtering criteria is defined here.

You can make use of wildcards. Multiple patterns are separated by space (means logical OR) and patterns are excluded from the search using the pipe symbol.

If the pattern is ended with a slash (*pattern*/), that means that pattern relates to recursive search of folders.

  • pattern - means to search those files/folders that name is pattern, recursive search goes through all subfolders independently of the value of pattern
  • pattern/ - means to search all files/folders, but recursive search goes through/excludes the folders that name is pattern

It is allowed to use quotation marks for names that contain space. Filter \"Program Files\" searches out those files/folders that name is Program Files.

Examples:

  • *.o
  • *.h *.c\?\?
  • *.cpp *.h | *.moc.cpp
  • * | .svn/ .git/

Note: the search term 'text' is equivalent to '*text*'.

"); fileFilter->setWhatsThis(wtFilter); filterLabel->setWhatsThis(wtFilter); rightLocation = new KHistoryComboBox(compareDirs); rightLocation->setMaxCount(25); // remember 25 items rightLocation->setDuplicatesEnabled(false); rightLocation->setEditable(true); rightLocation->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); list = group.readEntry("Right Folder History", QStringList()); rightLocation->setHistoryItems(list); KUrlRequester *rightUrlReq = new KUrlRequester(rightLocation, compareDirs); rightUrlReq->setUrl(rightURL); rightUrlReq->setMode(KFile::Directory); rightUrlReq->setMinimumWidth(250); grid->addWidget(rightUrlReq, 1 , 2); rightLocation->setWhatsThis(i18n("The right base folder used during the synchronization process.")); rightUrlReq->setEnabled(!hasSelectedFiles); rightLocation->setEnabled(!hasSelectedFiles); rightDirLabel->setBuddy(rightLocation); QWidget *optionWidget = new QWidget(compareDirs); QHBoxLayout *optionBox = new QHBoxLayout(optionWidget); optionBox->setContentsMargins(0, 0, 0, 0); QWidget *optionGridWidget = new QWidget(optionWidget); QGridLayout *optionGrid = new QGridLayout(optionGridWidget); optionBox->addWidget(optionGridWidget); cbSubdirs = new QCheckBox(i18n("Recurse subfolders"), optionGridWidget); cbSubdirs->setChecked(group.readEntry("Recurse Subdirectories", _RecurseSubdirs)); optionGrid->addWidget(cbSubdirs, 0, 0); cbSubdirs->setWhatsThis(i18n("Compare not only the base folders but their subfolders as well.")); cbSymlinks = new QCheckBox(i18n("Follow symlinks"), optionGridWidget); cbSymlinks->setChecked(group.readEntry("Follow Symlinks", _FollowSymlinks)); cbSymlinks->setEnabled(cbSubdirs->isChecked()); optionGrid->addWidget(cbSymlinks, 0, 1); cbSymlinks->setWhatsThis(i18n("Follow symbolic links during the compare process.")); cbByContent = new QCheckBox(i18n("Compare by content"), optionGridWidget); cbByContent->setChecked(group.readEntry("Compare By Content", _CompareByContent)); optionGrid->addWidget(cbByContent, 0, 2); cbByContent->setWhatsThis(i18n("Compare duplicated files with same size by content.")); cbIgnoreDate = new QCheckBox(i18n("Ignore Date"), optionGridWidget); cbIgnoreDate->setChecked(group.readEntry("Ignore Date", _IgnoreDate)); optionGrid->addWidget(cbIgnoreDate, 1, 0); cbIgnoreDate->setWhatsThis(i18n("

Ignore date information during the compare process.

Note: useful if the files are located on network filesystems or in archives.

")); cbAsymmetric = new QCheckBox(i18n("Asymmetric"), optionGridWidget); cbAsymmetric->setChecked(group.readEntry("Asymmetric", _Asymmetric)); optionGrid->addWidget(cbAsymmetric, 1, 1); cbAsymmetric->setWhatsThis(i18n("

Asymmetric mode

The left side is the destination, the right is the source folder. Files existing only in the left folder will be deleted, the other differing ones will be copied from right to left.

Note: useful when updating a folder from a file server.

")); cbIgnoreCase = new QCheckBox(i18n("Ignore Case"), optionGridWidget); cbIgnoreCase->setChecked(group.readEntry("Ignore Case", _IgnoreCase)); optionGrid->addWidget(cbIgnoreCase, 1, 2); cbIgnoreCase->setWhatsThis(i18n("

Case insensitive filename compare.

Note: useful when synchronizing Windows filesystems.

")); /* =========================== Show options groupbox ============================= */ QGroupBox *showOptions = new QGroupBox(optionWidget); optionBox->addWidget(showOptions); showOptions->setTitle(i18n("S&how options")); showOptions->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QGridLayout *showOptionsLayout = new QGridLayout(showOptions); showOptionsLayout->setSpacing(4); showOptionsLayout->setContentsMargins(11, 11, 11, 11); bool checked; QString description; checked = group.readEntry("LeftToRight Button", _BtnLeftToRight); description = i18n("Show files marked to Copy from left to right."); btnLeftToRight = createButton(showOptions, "arrow-right", checked, Qt::CTRL + Qt::Key_L, description); showOptionsLayout->addWidget(btnLeftToRight, 0, 0); checked = group.readEntry("Equals Button", _BtnEquals); description = i18n("Show files considered to be identical."); btnEquals = createButton(showOptions, "equals", checked, Qt::CTRL + Qt::Key_E, description, "="); showOptionsLayout->addWidget(btnEquals, 0, 1); checked = group.readEntry("Differents Button", _BtnDifferents); description = i18n("Show excluded files."); btnDifferents = createButton(showOptions, "unequals", checked, Qt::CTRL + Qt::Key_D, description, "!="); showOptionsLayout->addWidget(btnDifferents, 0, 2); checked = group.readEntry("RightToLeft Button", _BtnRightToLeft); description = i18n("Show files marked to Copy from right to left."); btnRightToLeft = createButton(showOptions, "arrow-left", checked, Qt::CTRL + Qt::Key_R, description); showOptionsLayout->addWidget(btnRightToLeft, 0, 3); checked = group.readEntry("Deletable Button", _BtnDeletable); description = i18n("Show files marked to delete."); btnDeletable = createButton(showOptions, "user-trash", checked, Qt::CTRL + Qt::Key_T, description); showOptionsLayout->addWidget(btnDeletable, 0, 4); checked = group.readEntry("Duplicates Button", _BtnDuplicates); description = i18n("Show files that exist on both sides."); btnDuplicates = createButton(showOptions, "arrow-up", checked, Qt::CTRL + Qt::Key_I, description, i18n("Duplicates"), true); showOptionsLayout->addWidget(btnDuplicates, 0, 5); checked = group.readEntry("Singles Button", _BtnSingles); description = i18n("Show files that exist on one side only."); btnSingles = createButton(showOptions, "arrow-down", checked, Qt::CTRL + Qt::Key_N, description, i18n("Singles"), true); showOptionsLayout->addWidget(btnSingles, 0, 6); grid->addWidget(optionWidget, 2, 0, 1, 3); synchronizerGrid->addWidget(compareDirs, 0, 0); /* ========================= Synchronization list view ========================== */ syncList = new SynchronizerListView(&synchronizer, synchronizerTab); // create the main container syncList->setWhatsThis(i18n("The compare results of the synchronizer (Ctrl+M).")); syncList->setAutoFillBackground(true); syncList->installEventFilter(this); KConfigGroup gl(krConfig, "Look&Feel"); syncList->setFont(gl.readEntry("Filelist Font", _FilelistFont)); syncList->setBackgroundRole(QPalette::Window); syncList->setAutoFillBackground(true); QStringList labels; labels << i18nc("@title:column file name", "Name"); labels << i18nc("@title:column", "Size"); labels << i18nc("@title:column", "Date"); labels << i18n("<=>"); labels << i18nc("@title:column", "Date"); labels << i18nc("@title:column", "Size"); labels << i18nc("@title:column file name", "Name"); syncList->setHeaderLabels(labels); syncList->header()->setSectionResizeMode(QHeaderView::Interactive); if (group.hasKey("State")) syncList->header()->restoreState(group.readEntry("State", QByteArray())); else { int i = QFontMetrics(syncList->font()).width("W"); int j = QFontMetrics(syncList->font()).width("0"); j = (i > j ? i : j); int typeWidth = j * 7 / 2; syncList->setColumnWidth(0, typeWidth * 4); syncList->setColumnWidth(1, typeWidth * 2); syncList->setColumnWidth(2, typeWidth * 3); syncList->setColumnWidth(3, typeWidth * 1); syncList->setColumnWidth(4, typeWidth * 3); syncList->setColumnWidth(5, typeWidth * 2); syncList->setColumnWidth(6, typeWidth * 4); equalSizes = true; } syncList->setAllColumnsShowFocus(true); syncList->setSelectionMode(QAbstractItemView::ExtendedSelection); syncList->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); syncList->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); syncList->header()->setSortIndicatorShown(false); syncList->setSortingEnabled(false); syncList->setRootIsDecorated(true); syncList->setIndentation(10); syncList->setDragEnabled(true); syncList->setAutoFillBackground(true); synchronizerGrid->addWidget(syncList, 1, 0); synchronizerTabs->addTab(synchronizerTab, i18n("&Synchronizer")); synchGrid->addWidget(synchronizerTabs, 0, 0); filterTabs = FilterTabs::addTo(synchronizerTabs, FilterTabs::HasDontSearchIn); generalFilter = (GeneralFilter *)filterTabs->get("GeneralFilter"); generalFilter->searchFor->setEditText(fileFilter->currentText()); generalFilter->searchForCase->setChecked(true); // creating the time shift, equality threshold, hidden files options QGroupBox *optionsGroup = new QGroupBox(generalFilter); optionsGroup->setTitle(i18n("&Options")); QGridLayout *optionsLayout = new QGridLayout(optionsGroup); optionsLayout->setAlignment(Qt::AlignTop); optionsLayout->setSpacing(6); optionsLayout->setContentsMargins(11, 11, 11, 11); QLabel * parallelThreadsLabel = new QLabel(i18n("Parallel threads:"), optionsGroup); optionsLayout->addWidget(parallelThreadsLabel, 0, 0); parallelThreadsSpinBox = new QSpinBox(optionsGroup); parallelThreadsSpinBox->setMinimum(1); parallelThreadsSpinBox->setMaximum(15); int parThreads = group.readEntry("Parallel Threads", 1); parallelThreadsSpinBox->setValue(parThreads); optionsLayout->addWidget(parallelThreadsSpinBox, 0, 1); QLabel * equalityLabel = new QLabel(i18n("Equality threshold:"), optionsGroup); optionsLayout->addWidget(equalityLabel, 1, 0); equalitySpinBox = new QSpinBox(optionsGroup); equalitySpinBox->setMaximum(9999); optionsLayout->addWidget(equalitySpinBox, 1, 1); equalityUnitCombo = new QComboBox(optionsGroup); equalityUnitCombo->addItem(i18n("sec")); equalityUnitCombo->addItem(i18n("min")); equalityUnitCombo->addItem(i18n("hour")); equalityUnitCombo->addItem(i18n("day")); optionsLayout->addWidget(equalityUnitCombo, 1, 2); QLabel * timeShiftLabel = new QLabel(i18n("Time shift (right-left):"), optionsGroup); optionsLayout->addWidget(timeShiftLabel, 2, 0); timeShiftSpinBox = new QSpinBox(optionsGroup); timeShiftSpinBox->setMinimum(-9999); timeShiftSpinBox->setMaximum(9999); optionsLayout->addWidget(timeShiftSpinBox, 2, 1); timeShiftUnitCombo = new QComboBox(optionsGroup); timeShiftUnitCombo->addItem(i18n("sec")); timeShiftUnitCombo->addItem(i18n("min")); timeShiftUnitCombo->addItem(i18n("hour")); timeShiftUnitCombo->addItem(i18n("day")); optionsLayout->addWidget(timeShiftUnitCombo, 2, 2); QFrame *line = new QFrame(optionsGroup); line->setFrameStyle(QFrame::HLine | QFrame::Sunken); optionsLayout->addWidget(line, 3, 0, 1, 3); ignoreHiddenFilesCB = new QCheckBox(i18n("Ignore hidden files"), optionsGroup); optionsLayout->addWidget(ignoreHiddenFilesCB, 4, 0, 1, 3); generalFilter->middleLayout->addWidget(optionsGroup); /* ================================== Buttons =================================== */ QHBoxLayout *buttons = new QHBoxLayout; buttons->setSpacing(6); buttons->setContentsMargins(0, 0, 0, 0); profileManager = new ProfileManager("SynchronizerProfile", this); profileManager->setShortcut(Qt::CTRL + Qt::Key_P); profileManager->setWhatsThis(i18n("Profile manager (Ctrl+P).")); buttons->addWidget(profileManager); btnSwapSides = new QPushButton(this); btnSwapSides->setIcon(Icon("document-swap")); btnSwapSides->setShortcut(Qt::CTRL + Qt::Key_S); btnSwapSides->setWhatsThis(i18n("Swap sides (Ctrl+S).")); buttons->addWidget(btnSwapSides); statusLabel = new QLabel(this); buttons->addWidget(statusLabel); QSpacerItem* spacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); buttons->addItem(spacer); btnCompareDirs = new QPushButton(this); btnCompareDirs->setText(i18n("Compare")); btnCompareDirs->setIcon(Icon("kr_comparedirs")); btnCompareDirs->setDefault(true); buttons->addWidget(btnCompareDirs); btnScrollResults = new QPushButton(this); btnScrollResults->setCheckable(true); btnScrollResults->setChecked(group.readEntry("Scroll Results", _ScrollResults)); btnScrollResults->hide(); if (btnScrollResults->isChecked()) btnScrollResults->setText(i18n("Quiet")); else btnScrollResults->setText(i18n("Scroll Results")); buttons->addWidget(btnScrollResults); btnStopComparing = new QPushButton(this); btnStopComparing->setText(i18n("Stop")); btnStopComparing->setIcon(Icon("process-stop")); btnStopComparing->setEnabled(false); buttons->addWidget(btnStopComparing); btnFeedToListBox = new QPushButton(this); btnFeedToListBox->setText(i18n("Feed to listbox")); btnFeedToListBox->setIcon(Icon("list-add")); btnFeedToListBox->setEnabled(false); btnFeedToListBox->hide(); buttons->addWidget(btnFeedToListBox); btnSynchronize = new QPushButton(this); btnSynchronize->setText(i18n("Synchronize")); btnSynchronize->setIcon(Icon("folder-sync")); btnSynchronize->setEnabled(false); buttons->addWidget(btnSynchronize); QPushButton *btnCloseSync = new QPushButton(this); btnCloseSync->setText(i18n("Close")); btnCloseSync->setIcon(Icon("dialog-close")); buttons->addWidget(btnCloseSync); synchGrid->addLayout(buttons, 1, 0); /* =============================== Connect table ================================ */ connect(syncList, SIGNAL(itemRightClicked(QTreeWidgetItem*,QPoint,int)), this, SLOT(rightMouseClicked(QTreeWidgetItem*,QPoint))); connect(syncList, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(doubleClicked(QTreeWidgetItem*))); connect(profileManager, SIGNAL(loadFromProfile(QString)), this, SLOT(loadFromProfile(QString))); connect(profileManager, SIGNAL(saveToProfile(QString)), this, SLOT(saveToProfile(QString))); connect(btnSwapSides, SIGNAL(clicked()), this, SLOT(swapSides())); connect(btnCompareDirs, SIGNAL(clicked()), this, SLOT(compare())); connect(btnStopComparing, SIGNAL(clicked()), this, SLOT(stop())); connect(btnFeedToListBox, SIGNAL(clicked()), this, SLOT(feedToListBox())); connect(btnSynchronize, SIGNAL(clicked()), this, SLOT(synchronize())); connect(btnScrollResults, SIGNAL(toggled(bool)), this, SLOT(setScrolling(bool))); connect(btnCloseSync, SIGNAL(clicked()), this, SLOT(closeDialog())); connect(cbSubdirs, SIGNAL(toggled(bool)), this, SLOT(subdirsChecked(bool))); connect(cbAsymmetric, SIGNAL(toggled(bool)), this, SLOT(setPanelLabels())); connect(&synchronizer, SIGNAL(comparedFileData(SynchronizerFileItem*)), this, SLOT(addFile(SynchronizerFileItem*))); connect(&synchronizer, SIGNAL(markChanged(SynchronizerFileItem*,bool)), this, SLOT(markChanged(SynchronizerFileItem*,bool))); connect(&synchronizer, SIGNAL(statusInfo(QString)), this, SLOT(statusInfo(QString))); connect(btnLeftToRight, SIGNAL(toggled(bool)), this, SLOT(refresh())); connect(btnEquals, SIGNAL(toggled(bool)), this, SLOT(refresh())); connect(btnDifferents, SIGNAL(toggled(bool)), this, SLOT(refresh())); connect(btnRightToLeft, SIGNAL(toggled(bool)), this, SLOT(refresh())); connect(btnDeletable, SIGNAL(toggled(bool)), this, SLOT(refresh())); connect(btnDuplicates, SIGNAL(toggled(bool)), this, SLOT(refresh())); connect(btnSingles, SIGNAL(toggled(bool)), this, SLOT(refresh())); connect(fileFilter, SIGNAL(currentTextChanged(QString)), this, SLOT(connectFilters(QString))); connect(generalFilter->searchFor, SIGNAL(currentTextChanged(QString)), this, SLOT(connectFilters(QString))); connect(generalFilter->searchFor, SIGNAL(currentTextChanged(QString)), this, SLOT(setCompletion())); connect(generalFilter->dontSearchIn, SIGNAL(checkValidity(QString&,QString&)), this, SLOT(checkExcludeURLValidity(QString&,QString&))); connect(profileManager, SIGNAL(loadFromProfile(QString)), filterTabs, SLOT(loadFromProfile(QString))); connect(profileManager, SIGNAL(saveToProfile(QString)), filterTabs, SLOT(saveToProfile(QString))); setPanelLabels(); setCompletion(); /* =============================== Loading the colors ================================ */ KConfigGroup gc(krConfig, "Colors"); QString COLOR_NAMES[] = { "Equals", "Differs", "LeftCopy", "RightCopy", "Delete" }; QPalette defaultPalette = QGuiApplication::palette(); DECLARE_SYNCHRONIZER_BACKGROUND_DEFAULTS; DECLARE_SYNCHRONIZER_FOREGROUND_DEFAULTS; for (int clr = 0; clr != TT_MAX; clr ++) { QString colorName = clr > 4 ? "Equals" : COLOR_NAMES[ clr ]; QColor backgroundDefault = clr > 4 ? defaultPalette.color(QPalette::Active, QPalette::Base) : SYNCHRONIZER_BACKGROUND_DEFAULTS[ clr ]; QColor foregroundDefault = clr > 4 ? defaultPalette.color(QPalette::Active, QPalette::Text) : SYNCHRONIZER_FOREGROUND_DEFAULTS[ clr ]; QString foreEntry = QString("Synchronizer ") + colorName + QString(" Foreground"); QString bckgEntry = QString("Synchronizer ") + colorName + QString(" Background"); if (gc.readEntry(foreEntry, QString()) == "KDE default") foreGrounds[ clr ] = QColor(); else if (gc.readEntry(foreEntry, QString()).isEmpty()) // KDE4 workaround, default color doesn't work foreGrounds[ clr ] = foregroundDefault; else foreGrounds[ clr ] = gc.readEntry(foreEntry, foregroundDefault); if (gc.readEntry(bckgEntry, QString()) == "KDE default") backGrounds[ clr ] = QColor(); else if (gc.readEntry(foreEntry, QString()).isEmpty()) // KDE4 workaround, default color doesn't work backGrounds[ clr ] = backgroundDefault; else backGrounds[ clr ] = gc.readEntry(bckgEntry, backgroundDefault); } if (backGrounds[ TT_EQUALS ].isValid()) { QPalette pal = syncList->palette(); pal.setColor(QPalette::Base, backGrounds[ TT_EQUALS ]); syncList->setPalette(pal); } int sx = group.readEntry("Window Width", -1); int sy = group.readEntry("Window Height", -1); if (sx != -1 && sy != -1) resize(sx, sy); if (group.readEntry("Window Maximized", false)) { setWindowState(windowState() | Qt::WindowMaximized); } if (equalSizes) { int newSize6 = syncList->header()->sectionSize(6); int newSize0 = syncList->header()->sectionSize(0); int delta = newSize6 - newSize0 + (newSize6 & 1); newSize0 += (delta / 2); if (newSize0 > 20) syncList->header()->resizeSection(0, newSize0); } if (!profileName.isNull()) profileManager->loadProfile(profileName); synchronizer.setParentWidget(this); } SynchronizerGUI::~SynchronizerGUI() { syncList->clear(); // for sanity: deletes the references to the synchronizer list } void SynchronizerGUI::setPanelLabels() { if (hasSelectedFiles && cbAsymmetric->isChecked()) { leftDirLabel->setText(i18n("Selected files from targ&et folder:")); rightDirLabel->setText(i18n("Selected files from sou&rce folder:")); } else if (hasSelectedFiles && !cbAsymmetric->isChecked()) { leftDirLabel->setText(i18n("Selected files from &left folder:")); rightDirLabel->setText(i18n("Selected files from &right folder:")); } else if (cbAsymmetric->isChecked()) { leftDirLabel->setText(i18n("Targ&et folder:")); rightDirLabel->setText(i18n("Sou&rce folder:")); } else { leftDirLabel->setText(i18n("&Left folder:")); rightDirLabel->setText(i18n("&Right folder:")); } } void SynchronizerGUI::setCompletion() { generalFilter->dontSearchIn->setCompletionDir(Synchronizer::fsUrl(rightLocation->currentText())); } void SynchronizerGUI::checkExcludeURLValidity(QString &text, QString &error) { QUrl url = Synchronizer::fsUrl(text); if (url.isRelative()) return; QString leftBase = leftLocation->currentText(); if (!leftBase.endsWith('/')) leftBase += '/'; QUrl leftBaseURL = Synchronizer::fsUrl(leftBase); if (leftBaseURL.isParentOf(url) && !url.isParentOf(leftBaseURL)) { text = QDir(leftBaseURL.path()).relativeFilePath(url.path()); return; } QString rightBase = rightLocation->currentText(); if (!rightBase.endsWith('/')) rightBase += '/'; QUrl rightBaseURL = Synchronizer::fsUrl(rightBase); if (rightBaseURL.isParentOf(url) && !url.isParentOf(rightBaseURL)) { text = QDir(rightBaseURL.path()).relativeFilePath(url.path()); return; } error = i18n("URL must be the descendant of either the left or the right base URL."); } void SynchronizerGUI::doubleClicked(QTreeWidgetItem *itemIn) { if (!itemIn) return; SyncViewItem *syncItem = (SyncViewItem *)itemIn; SynchronizerFileItem *item = syncItem->synchronizerItemRef(); if (item && item->existsInLeft() && item->existsInRight() && !item->isDir()) { QString leftDirName = item->leftDirectory().isEmpty() ? "" : item->leftDirectory() + '/'; QString rightDirName = item->rightDirectory().isEmpty() ? "" : item->rightDirectory() + '/'; QUrl leftURL = Synchronizer::fsUrl(synchronizer.leftBaseDirectory() + leftDirName + item->leftName()); QUrl rightURL = Synchronizer::fsUrl(synchronizer.rightBaseDirectory() + rightDirName + item->rightName()); SLOTS->compareContent(leftURL,rightURL); } else if (item && item->isDir()) { itemIn->setExpanded(!itemIn->isExpanded()); } } void SynchronizerGUI::rightMouseClicked(QTreeWidgetItem *itemIn, const QPoint &pos) { // these are the values that will exist in the menu #define EXCLUDE_ID 90 #define RESTORE_ID 91 #define COPY_TO_LEFT_ID 92 #define COPY_TO_RIGHT_ID 93 #define REVERSE_DIR_ID 94 #define DELETE_ID 95 #define VIEW_LEFT_FILE_ID 96 #define VIEW_RIGHT_FILE_ID 97 #define COMPARE_FILES_ID 98 #define SELECT_ITEMS_ID 99 #define DESELECT_ITEMS_ID 100 #define INVERT_SELECTION_ID 101 #define SYNCH_WITH_KGET_ID 102 #define COPY_CLPBD_LEFT_ID 103 #define COPY_CLPBD_RIGHT_ID 104 ////////////////////////////////////////////////////////// if (!itemIn) return; SyncViewItem *syncItem = (SyncViewItem *)itemIn; if (syncItem == 0) return; SynchronizerFileItem *item = syncItem->synchronizerItemRef(); bool isDuplicate = item->existsInLeft() && item->existsInRight(); bool isDir = item->isDir(); // create the menu QMenu popup; QAction *myact; QHash< QAction *, int > actHash; popup.setTitle(i18n("Synchronize Folders")); myact = popup.addAction(i18n("E&xclude")); actHash[ myact ] = EXCLUDE_ID; myact = popup.addAction(i18n("Restore ori&ginal operation")); actHash[ myact ] = RESTORE_ID; myact = popup.addAction(i18n("Re&verse direction")); actHash[ myact ] = REVERSE_DIR_ID; myact = popup.addAction(i18n("Copy from &right to left")); actHash[ myact ] = COPY_TO_LEFT_ID; myact = popup.addAction(i18n("Copy from &left to right")); actHash[ myact ] = COPY_TO_RIGHT_ID; myact = popup.addAction(i18n("&Delete (left single)")); actHash[ myact ] = DELETE_ID; popup.addSeparator(); myact = popup.addAction(i18n("V&iew left file")); myact->setEnabled(!isDir && item->existsInLeft()); actHash[ myact ] = VIEW_LEFT_FILE_ID; myact = popup.addAction(i18n("Vi&ew right file")); myact->setEnabled(!isDir && item->existsInRight()); actHash[ myact ] = VIEW_RIGHT_FILE_ID; myact = popup.addAction(i18n("&Compare Files")); myact->setEnabled(!isDir && isDuplicate); actHash[ myact ] = COMPARE_FILES_ID; popup.addSeparator(); myact = popup.addAction(i18n("C&opy selected to clipboard (left)")); actHash[ myact ] = COPY_CLPBD_LEFT_ID; myact = popup.addAction(i18n("Co&py selected to clipboard (right)")); actHash[ myact ] = COPY_CLPBD_RIGHT_ID; popup.addSeparator(); myact = popup.addAction(i18n("&Select items")); actHash[ myact ] = SELECT_ITEMS_ID; myact = popup.addAction(i18n("Deselec&t items")); actHash[ myact ] = DESELECT_ITEMS_ID; myact = popup.addAction(i18n("I&nvert selection")); actHash[ myact ] = INVERT_SELECTION_ID; QUrl leftBDir = Synchronizer::fsUrl(synchronizer.leftBaseDirectory()); QUrl rightBDir = Synchronizer::fsUrl(synchronizer.rightBaseDirectory()); if (KrServices::cmdExist("kget") && ((!leftBDir.isLocalFile() && rightBDir.isLocalFile() && btnLeftToRight->isChecked()) || (leftBDir.isLocalFile() && !rightBDir.isLocalFile() && btnRightToLeft->isChecked()))) { popup.addSeparator(); myact = popup.addAction(i18n("Synchronize with &KGet")); actHash[ myact ] = SYNCH_WITH_KGET_ID; } QAction * res = popup.exec(pos); int result = -1; if (actHash.contains(res)) result = actHash[ res ]; if (result != -1) executeOperation(item, result); } void SynchronizerGUI::executeOperation(SynchronizerFileItem *item, int op) { // check out the user's option QString leftDirName = item->leftDirectory().isEmpty() ? "" : item->leftDirectory() + '/'; QString rightDirName = item->rightDirectory().isEmpty() ? "" : item->rightDirectory() + '/'; QUrl leftURL = Synchronizer::fsUrl(synchronizer.leftBaseDirectory() + leftDirName + item->leftName()); QUrl rightURL = Synchronizer::fsUrl(synchronizer.rightBaseDirectory() + rightDirName + item->rightName()); switch (op) { case EXCLUDE_ID: case RESTORE_ID: case COPY_TO_LEFT_ID: case COPY_TO_RIGHT_ID: case REVERSE_DIR_ID: case DELETE_ID: { unsigned ndx = 0; SynchronizerFileItem *currentItem; while ((currentItem = synchronizer.getItemAt(ndx++)) != 0) { SyncViewItem *viewItem = (SyncViewItem *)currentItem->userData(); if (!viewItem || !viewItem->isSelected() || viewItem->isHidden()) continue; switch (op) { case EXCLUDE_ID: synchronizer.exclude(viewItem->synchronizerItemRef()); break; case RESTORE_ID: synchronizer.restore(viewItem->synchronizerItemRef()); break; case REVERSE_DIR_ID: synchronizer.reverseDirection(viewItem->synchronizerItemRef()); break; case COPY_TO_LEFT_ID: synchronizer.copyToLeft(viewItem->synchronizerItemRef()); break; case COPY_TO_RIGHT_ID: synchronizer.copyToRight(viewItem->synchronizerItemRef()); break; case DELETE_ID: synchronizer.deleteLeft(viewItem->synchronizerItemRef()); break; } } refresh(); } break; case VIEW_LEFT_FILE_ID: KrViewer::view(leftURL, this); // view the file break; case VIEW_RIGHT_FILE_ID: KrViewer::view(rightURL, this); // view the file break; case COMPARE_FILES_ID: SLOTS->compareContent(leftURL,rightURL); break; case SELECT_ITEMS_ID: case DESELECT_ITEMS_ID: { KRQuery query = KRSpWidgets::getMask((op == SELECT_ITEMS_ID ? i18n("Select items") : i18n("Deselect items")), true, this); if (query.isNull()) break; unsigned ndx = 0; SynchronizerFileItem *currentItem; while ((currentItem = synchronizer.getItemAt(ndx++)) != 0) { SyncViewItem *viewItem = (SyncViewItem *)currentItem->userData(); if (!viewItem || viewItem->isHidden()) continue; if (query.match(currentItem->leftName()) || query.match(currentItem->rightName())) viewItem->setSelected(op == SELECT_ITEMS_ID); } } break; case INVERT_SELECTION_ID: { unsigned ndx = 0; SynchronizerFileItem *currentItem; while ((currentItem = synchronizer.getItemAt(ndx++)) != 0) { SyncViewItem *viewItem = (SyncViewItem *)currentItem->userData(); if (!viewItem || viewItem->isHidden()) continue; viewItem->setSelected(!viewItem->isSelected()); } } break; case SYNCH_WITH_KGET_ID: synchronizer.synchronizeWithKGet(); closeDialog(); break; case COPY_CLPBD_LEFT_ID: copyToClipboard(true); break; case COPY_CLPBD_RIGHT_ID: copyToClipboard(false); break; case -1 : return; // the user clicked outside of the menu } } void SynchronizerGUI::closeDialog() { if (isComparing) { stop(); wasClosed = true; return; } KConfigGroup group(krConfig, "Synchronize"); QStringList list; foreach(const QString &item, leftLocation->historyItems()) { QUrl url(item); // make sure no passwords are saved in config url.setPassword(QString()); list << url.toDisplayString(QUrl::PreferLocalFile); } group.writeEntry("Left Folder History", list); list.clear(); foreach(const QString &item, rightLocation->historyItems()) { QUrl url(item); // make sure no passwords are saved in config url.setPassword(QString()); list << url.toDisplayString(QUrl::PreferLocalFile); } group.writeEntry("Right Folder History", list); list = fileFilter->historyItems(); group.writeEntry("File Filter", list); group.writeEntry("Recurse Subdirectories", cbSubdirs->isChecked()); group.writeEntry("Follow Symlinks", cbSymlinks->isChecked()); group.writeEntry("Compare By Content", cbByContent->isChecked()); group.writeEntry("Ignore Date", cbIgnoreDate->isChecked()); group.writeEntry("Asymmetric", cbAsymmetric->isChecked()); group.writeEntry("Ignore Case", cbIgnoreCase->isChecked()); group.writeEntry("LeftToRight Button", btnLeftToRight->isChecked()); group.writeEntry("Equals Button", btnEquals->isChecked()); group.writeEntry("Differents Button", btnDifferents->isChecked()); group.writeEntry("RightToLeft Button", btnRightToLeft->isChecked()); group.writeEntry("Deletable Button", btnDeletable->isChecked()); group.writeEntry("Duplicates Button", btnDuplicates->isChecked()); group.writeEntry("Singles Button", btnSingles->isChecked()); group.writeEntry("Scroll Results", btnScrollResults->isChecked()); group.writeEntry("Parallel Threads", parallelThreadsSpinBox->value()); group.writeEntry("Window Width", sizeX); group.writeEntry("Window Height", sizeY); group.writeEntry("Window Maximized", isMaximized()); group.writeEntry("State", syncList->header()->saveState()); QDialog::reject(); this->deleteLater(); if (wasSync) { LEFT_PANEL->func->refresh(); RIGHT_PANEL->func->refresh(); ACTIVE_PANEL->gui->slotFocusOnMe(); } } void SynchronizerGUI::compare() { KRQuery query; if (!filterTabs->fillQuery(&query)) return; // perform some previous tests QString leftLocationTrimmed = leftLocation->currentText().trimmed(); QString rightLocationTrimmed = rightLocation->currentText().trimmed(); if (leftLocationTrimmed.isEmpty()) { KMessageBox::error(this, i18n("The target folder must not be empty.")); leftLocation->setFocus(); return; } if (rightLocationTrimmed.isEmpty()) { KMessageBox::error(this, i18n("The source folder must not be empty.")); rightLocation->setFocus(); return; } if (leftLocationTrimmed == rightLocationTrimmed) { if (KMessageBox::warningContinueCancel(this, i18n("Warning: The left and the right side are showing the same folder.")) != KMessageBox::Continue) { return; } } query.setNameFilter(fileFilter->currentText(), query.isCaseSensitive()); synchronizerTabs->setCurrentIndex(0); syncList->clear(); lastItem = 0; leftLocation->addToHistory(leftLocation->currentText()); rightLocation->addToHistory(rightLocation->currentText()); fileFilter->addToHistory(fileFilter->currentText()); setMarkFlags(); btnCompareDirs->setEnabled(false); profileManager->setEnabled(false); btnSwapSides->setEnabled(false); btnStopComparing->setEnabled(isComparing = true); btnStopComparing->show(); btnFeedToListBox->setEnabled(false); btnFeedToListBox->hide(); btnSynchronize->setEnabled(false); btnCompareDirs->hide(); btnScrollResults->show(); disableMarkButtons(); int fileCount = synchronizer.compare(leftLocation->currentText(), rightLocation->currentText(), &query, cbSubdirs->isChecked(), cbSymlinks->isChecked(), cbIgnoreDate->isChecked(), cbAsymmetric->isChecked(), cbByContent->isChecked(), cbIgnoreCase->isChecked(), btnScrollResults->isChecked(), selectedFiles, convertToSeconds(equalitySpinBox->value(), equalityUnitCombo->currentIndex()), convertToSeconds(timeShiftSpinBox->value(), timeShiftUnitCombo->currentIndex()), parallelThreadsSpinBox->value(), ignoreHiddenFilesCB->isChecked()); enableMarkButtons(); btnStopComparing->setEnabled(isComparing = false); btnStopComparing->hide(); btnFeedToListBox->show(); btnCompareDirs->setEnabled(true); profileManager->setEnabled(true); btnSwapSides->setEnabled(true); btnCompareDirs->show(); btnScrollResults->hide(); if (fileCount) { btnSynchronize->setEnabled(true); btnFeedToListBox->setEnabled(true); } syncList->setFocus(); if (wasClosed) closeDialog(); } void SynchronizerGUI::stop() { synchronizer.stop(); } void SynchronizerGUI::feedToListBox() { FeedToListBoxDialog listBox(this, &synchronizer, syncList, btnEquals->isChecked()); if (listBox.isAccepted()) closeDialog(); } void SynchronizerGUI::reject() { closeDialog(); } void SynchronizerGUI::addFile(SynchronizerFileItem *item) { QString leftName = "", rightName = "", leftDate = "", rightDate = "", leftSize = "", rightSize = ""; bool isDir = item->isDir(); QColor textColor = foreGrounds[ item->task()]; QColor baseColor = backGrounds[ item->task()]; if (item->existsInLeft()) { leftName = item->leftName(); leftSize = isDir ? dirLabel() + ' ' : KRpermHandler::parseSize(item->leftSize()); leftDate = SynchronizerGUI::convertTime(item->leftDate()); } if (item->existsInRight()) { rightName = item->rightName(); rightSize = isDir ? dirLabel() + ' ' : KRpermHandler::parseSize(item->rightSize()); rightDate = SynchronizerGUI::convertTime(item->rightDate()); } SyncViewItem *listItem = 0; SyncViewItem *dirItem; if (item->parent() == 0) { listItem = new SyncViewItem(item, textColor, baseColor, syncList, lastItem, leftName, leftSize, leftDate, Synchronizer::getTaskTypeName(item->task()), rightDate, rightSize, rightName); lastItem = listItem; } else { dirItem = (SyncViewItem *)item->parent()->userData(); if (dirItem) { dirItem->setExpanded(true); listItem = new SyncViewItem(item, textColor, baseColor, dirItem, dirItem->lastItem(), leftName, leftSize, leftDate, Synchronizer::getTaskTypeName(item->task()), rightDate, rightSize, rightName); dirItem->setLastItem(listItem); } } if (listItem) { listItem->setIcon(0, Icon(isDir ? "folder" : "document-new")); if (!item->isMarked()) listItem->setHidden(true); else syncList->scrollTo(syncList->indexOf(listItem)); } } void SynchronizerGUI::markChanged(SynchronizerFileItem *item, bool ensureVisible) { SyncViewItem *listItem = (SyncViewItem *)item->userData(); if (listItem) { if (!item->isMarked()) { listItem->setHidden(true); } else { QString leftName = "", rightName = "", leftDate = "", rightDate = "", leftSize = "", rightSize = ""; bool isDir = item->isDir(); if (item->existsInLeft()) { leftName = item->leftName(); leftSize = isDir ? dirLabel() + ' ' : KRpermHandler::parseSize(item->leftSize()); leftDate = SynchronizerGUI::convertTime(item->leftDate()); } if (item->existsInRight()) { rightName = item->rightName(); rightSize = isDir ? dirLabel() + ' ' : KRpermHandler::parseSize(item->rightSize()); rightDate = SynchronizerGUI::convertTime(item->rightDate()); } listItem->setHidden(false); listItem->setText(0, leftName); listItem->setText(1, leftSize); listItem->setText(2, leftDate); listItem->setText(3, Synchronizer::getTaskTypeName(item->task())); listItem->setText(4, rightDate); listItem->setText(5, rightSize); listItem->setText(6, rightName); listItem->setColors(foreGrounds[ item->task()], backGrounds[ item->task()]); if (ensureVisible) syncList->scrollTo(syncList->indexOf(listItem)); } } } void SynchronizerGUI::subdirsChecked(bool isOn) { cbSymlinks->setEnabled(isOn); } void SynchronizerGUI::disableMarkButtons() { btnLeftToRight->setEnabled(false); btnEquals->setEnabled(false); btnDifferents->setEnabled(false); btnRightToLeft->setEnabled(false); btnDeletable->setEnabled(false); btnDuplicates->setEnabled(false); btnSingles->setEnabled(false); } void SynchronizerGUI::enableMarkButtons() { btnLeftToRight->setEnabled(true); btnEquals->setEnabled(true); btnDifferents->setEnabled(true); btnRightToLeft->setEnabled(true); btnDeletable->setEnabled(true); btnDuplicates->setEnabled(true); btnSingles->setEnabled(true); } QString SynchronizerGUI::convertTime(time_t time) const { // convert the time_t to struct tm struct tm* t = localtime((time_t *) & time); QDateTime tmp(QDate(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday), QTime(t->tm_hour, t->tm_min)); return QLocale().toString(tmp, QLocale::ShortFormat); } void SynchronizerGUI::setMarkFlags() { synchronizer.setMarkFlags(btnRightToLeft->isChecked(), btnEquals->isChecked(), btnDifferents->isChecked(), btnLeftToRight->isChecked(), btnDuplicates->isChecked(), btnSingles->isChecked(), btnDeletable->isChecked()); } void SynchronizerGUI::refresh() { if (!isComparing) { syncList->clearSelection(); setMarkFlags(); btnCompareDirs->setEnabled(false); profileManager->setEnabled(false); btnSwapSides->setEnabled(false); btnSynchronize->setEnabled(false); btnFeedToListBox->setEnabled(false); disableMarkButtons(); int fileCount = synchronizer.refresh(); enableMarkButtons(); btnCompareDirs->setEnabled(true); profileManager->setEnabled(true); btnSwapSides->setEnabled(true); if (fileCount) { btnFeedToListBox->setEnabled(true); btnSynchronize->setEnabled(true); } } } void SynchronizerGUI::synchronize() { int copyToLeftNr, copyToRightNr, deleteNr; KIO::filesize_t copyToLeftSize, copyToRightSize, deleteSize; if (!synchronizer.totalSizes(©ToLeftNr, ©ToLeftSize, ©ToRightNr, ©ToRightSize, &deleteNr, &deleteSize)) { KMessageBox::sorry(parentWidget(), i18n("Synchronizer has nothing to do.")); return; } SynchronizeDialog *sd = new SynchronizeDialog(this, &synchronizer, copyToLeftNr, copyToLeftSize, copyToRightNr, copyToRightSize, deleteNr, deleteSize, parallelThreadsSpinBox->value()); wasSync = sd->wasSyncronizationStarted(); delete sd; if (wasSync) closeDialog(); } void SynchronizerGUI::resizeEvent(QResizeEvent *e) { if (!isMaximized()) { sizeX = e->size().width(); sizeY = e->size().height(); } if (!firstResize) { int delta = e->size().width() - e->oldSize().width() + (e->size().width() & 1); int newSize = syncList->header()->sectionSize(0) + delta / 2; if (newSize > 20) syncList->header()->resizeSection(0, newSize); } firstResize = false; QDialog::resizeEvent(e); } void SynchronizerGUI::statusInfo(QString info) { statusLabel->setText(info); qApp->processEvents(); } void SynchronizerGUI::swapSides() { if (btnCompareDirs->isEnabled()) { QString leftCurrent = leftLocation->currentText(); leftLocation->lineEdit()->setText(rightLocation->currentText()); rightLocation->lineEdit()->setText(leftCurrent); synchronizer.swapSides(); refresh(); } } void SynchronizerGUI::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_M : { if (e->modifiers() == Qt::ControlModifier) { syncList->setFocus(); e->accept(); } break; } case Qt::Key_F3 : case Qt::Key_F4 : { e->accept(); syncList->setFocus(); QTreeWidgetItem *listItem = syncList->currentItem(); if (listItem == 0) break; bool isedit = e->key() == Qt::Key_F4; SynchronizerFileItem *item = ((SyncViewItem *)listItem)->synchronizerItemRef(); QString leftDirName = item->leftDirectory().isEmpty() ? "" : item->leftDirectory() + '/'; QString rightDirName = item->rightDirectory().isEmpty() ? "" : item->rightDirectory() + '/'; if (item->isDir()) return; if (e->modifiers() == Qt::ShiftModifier && item->existsInRight()) { QUrl rightURL = Synchronizer::fsUrl(synchronizer.rightBaseDirectory() + rightDirName + item->rightName()); if (isedit) KrViewer::edit(rightURL, this); // view the file else KrViewer::view(rightURL, this); // view the file return; } else if (e->modifiers() == 0 && item->existsInLeft()) { QUrl leftURL = Synchronizer::fsUrl(synchronizer.leftBaseDirectory() + leftDirName + item->leftName()); if (isedit) KrViewer::edit(leftURL, this); // view the file else KrViewer::view(leftURL, this); // view the file return; } } break; case Qt::Key_U : if (e->modifiers() != Qt::ControlModifier) break; e->accept(); swapSides(); return; case Qt::Key_Escape: if (!btnStopComparing->isHidden() && btnStopComparing->isEnabled()) { // is it comparing? e->accept(); btnStopComparing->animateClick(); // just click the stop button } else { e->accept(); if (syncList->topLevelItemCount() != 0) { int result = KMessageBox::warningYesNo(this, i18n("The synchronizer window contains data from a previous compare. If you exit, this data will be lost. Do you really want to exit?"), i18n("Krusader::Synchronize Folders"), KStandardGuiItem::yes(), KStandardGuiItem::no(), "syncGUIexit"); if (result != KMessageBox::Yes) return; } QDialog::reject(); } return; } QDialog::keyPressEvent(e); } bool SynchronizerGUI::eventFilter(QObject * /* watched */, QEvent * e) { if (e->type() == QEvent::KeyPress) { QKeyEvent* ke = (QKeyEvent*) e; switch (ke->key()) { case Qt::Key_Down: case Qt::Key_Left: case Qt::Key_Right: case Qt::Key_Up: case Qt::Key_Delete: case Qt::Key_W: { if (ke->key() == Qt::Key_W) { if (ke->modifiers() != Qt::ControlModifier) return false; } else if (ke->modifiers() != Qt::AltModifier) return false; int op = -1; switch (ke->key()) { case Qt::Key_Down: op = EXCLUDE_ID; break; case Qt::Key_Left: op = COPY_TO_LEFT_ID; break; case Qt::Key_Right: op = COPY_TO_RIGHT_ID; break; case Qt::Key_Up: op = RESTORE_ID; break; case Qt::Key_Delete: op = DELETE_ID; break; case Qt::Key_W: op = REVERSE_DIR_ID; break; } ke->accept(); QTreeWidgetItem *listItem = syncList->currentItem(); if (listItem == 0) return true; SynchronizerFileItem *item = ((SyncViewItem *)listItem)->synchronizerItemRef(); bool hasSelected = false; QList selected = syncList->selectedItems(); for (int i = 0; i != selected.count(); i++) if (selected[ i ]->isSelected() && !selected[ i ]->isHidden()) hasSelected = true; if (!hasSelected) listItem->setSelected(true); executeOperation(item, op); return true; } } } return false; } void SynchronizerGUI::loadFromProfile(QString profile) { syncList->clear(); synchronizer.reset(); isComparing = wasClosed = false; btnSynchronize->setEnabled(false); btnFeedToListBox->setEnabled(false); KConfigGroup pg(krConfig, profile); if (!hasSelectedFiles) { leftLocation->lineEdit()->setText(pg.readEntry("Left Location", QString())); rightLocation->lineEdit()->setText(pg.readEntry("Right Location", QString())); } fileFilter->lineEdit()->setText(pg.readEntry("Search For", QString())); cbSubdirs-> setChecked(pg.readEntry("Recurse Subdirectories", true)); cbSymlinks-> setChecked(pg.readEntry("Follow Symlinks", false)); cbByContent-> setChecked(pg.readEntry("Compare By Content", false)); cbIgnoreDate->setChecked(pg.readEntry("Ignore Date", false)); cbAsymmetric->setChecked(pg.readEntry("Asymmetric", false)); cbIgnoreCase->setChecked(pg.readEntry("Ignore Case", false)); btnScrollResults->setChecked(pg.readEntry("Scroll Results", false)); btnLeftToRight->setChecked(pg.readEntry("Show Left To Right", true)); btnEquals ->setChecked(pg.readEntry("Show Equals", true)); btnDifferents ->setChecked(pg.readEntry("Show Differents", true)); btnRightToLeft->setChecked(pg.readEntry("Show Right To Left", true)); btnDeletable ->setChecked(pg.readEntry("Show Deletable", true)); btnDuplicates ->setChecked(pg.readEntry("Show Duplicates", true)); btnSingles ->setChecked(pg.readEntry("Show Singles", true)); int equalityThreshold = pg.readEntry("Equality Threshold", 0); int equalityCombo = 0; convertFromSeconds(equalityThreshold, equalityCombo, equalityThreshold); equalitySpinBox->setValue(equalityThreshold); equalityUnitCombo->setCurrentIndex(equalityCombo); int timeShift = pg.readEntry("Time Shift", 0); int timeShiftCombo = 0; convertFromSeconds(timeShift, timeShiftCombo, timeShift); timeShiftSpinBox->setValue(timeShift); timeShiftUnitCombo->setCurrentIndex(timeShiftCombo); int parallelThreads = pg.readEntry("Parallel Threads", 1); parallelThreadsSpinBox->setValue(parallelThreads); bool ignoreHidden = pg.readEntry("Ignore Hidden Files", false); ignoreHiddenFilesCB->setChecked(ignoreHidden); refresh(); } void SynchronizerGUI::saveToProfile(QString profile) { KConfigGroup group(krConfig, profile); group.writeEntry("Left Location", leftLocation->currentText()); group.writeEntry("Search For", fileFilter->currentText()); group.writeEntry("Right Location", rightLocation->currentText()); group.writeEntry("Recurse Subdirectories", cbSubdirs->isChecked()); group.writeEntry("Follow Symlinks", cbSymlinks->isChecked()); group.writeEntry("Compare By Content", cbByContent->isChecked()); group.writeEntry("Ignore Date", cbIgnoreDate->isChecked()); group.writeEntry("Asymmetric", cbAsymmetric->isChecked()); group.writeEntry("Ignore Case", cbIgnoreCase->isChecked()); group.writeEntry("Scroll Results", btnScrollResults->isChecked()); group.writeEntry("Show Left To Right", btnLeftToRight->isChecked()); group.writeEntry("Show Equals", btnEquals->isChecked()); group.writeEntry("Show Differents", btnDifferents->isChecked()); group.writeEntry("Show Right To Left", btnRightToLeft->isChecked()); group.writeEntry("Show Deletable", btnDeletable->isChecked()); group.writeEntry("Show Duplicates", btnDuplicates->isChecked()); group.writeEntry("Show Singles", btnSingles->isChecked()); group.writeEntry("Equality Threshold", convertToSeconds(equalitySpinBox->value(), equalityUnitCombo->currentIndex())); group.writeEntry("Time Shift", convertToSeconds(timeShiftSpinBox->value(), timeShiftUnitCombo->currentIndex())); group.writeEntry("Parallel Threads", parallelThreadsSpinBox->value()); group.writeEntry("Ignore Hidden Files", ignoreHiddenFilesCB->isChecked()); } void SynchronizerGUI::connectFilters(const QString &newString) { if (synchronizerTabs->currentIndex()) fileFilter->setEditText(newString); else generalFilter->searchFor->setEditText(newString); } void SynchronizerGUI::setScrolling(bool isOn) { if (isOn) btnScrollResults->setText(i18n("Quiet")); else btnScrollResults->setText(i18n("Scroll Results")); synchronizer.setScrolling(isOn); } int SynchronizerGUI::convertToSeconds(int time, int unit) { switch (unit) { case 1: return time * 60; case 2: return time * 3600; case 3: return time * 86400; default: return time; } } void SynchronizerGUI::convertFromSeconds(int &time, int &unit, int second) { unit = 0; time = second; int absTime = (time < 0) ? -time : time; if (absTime >= 86400 && (absTime % 86400) == 0) { time /= 86400; unit = 3; } else if (absTime >= 3600 && (absTime % 3600) == 0) { time /= 3600; unit = 2; } else if (absTime >= 60 && (absTime % 60) == 0) { time /= 60; unit = 1; } } QPushButton *SynchronizerGUI::createButton(QWidget *parent, const QString &iconName, bool checked, const QKeySequence &shortCut, const QString &description, const QString &text, bool textAndIcon) { QPushButton *button = new QPushButton(parent); bool iconExists = Icon::exists(iconName); if (!text.isEmpty() && (textAndIcon || !iconExists)) { button->setText(text); } if (iconExists) { button->setIcon(Icon(iconName)); } button->setCheckable(true); button->setChecked(checked); button->setShortcut(shortCut); const QString infoText = QString("%1 (%2)").arg(description, shortCut.toString(QKeySequence::NativeText)); button->setWhatsThis(infoText); button->setToolTip(infoText); return button; } void SynchronizerGUI::copyToClipboard(bool isLeft) { QList urls; unsigned ndx = 0; SynchronizerFileItem *currentItem; while ((currentItem = synchronizer.getItemAt(ndx++)) != 0) { SynchronizerGUI::SyncViewItem *viewItem = (SynchronizerGUI::SyncViewItem *)currentItem->userData(); if (!viewItem || !viewItem->isSelected() || viewItem->isHidden()) continue; SynchronizerFileItem *item = viewItem->synchronizerItemRef(); if (item) { if (isLeft && item->existsInLeft()) { QString leftDirName = item->leftDirectory().isEmpty() ? "" : item->leftDirectory() + '/'; QUrl leftURL = Synchronizer::fsUrl(synchronizer.leftBaseDirectory() + leftDirName + item->leftName()); urls.push_back(leftURL); } else if (!isLeft && item->existsInRight()) { QString rightDirName = item->rightDirectory().isEmpty() ? "" : item->rightDirectory() + '/'; QUrl rightURL = Synchronizer::fsUrl(synchronizer.rightBaseDirectory() + rightDirName + item->rightName()); urls.push_back(rightURL); } } } if (urls.count() == 0) return; QMimeData *mimeData = new QMimeData; - mimeData->setImageData(FL_LOADICON(isLeft ? "arrow-left-double" : "arrow-right-double")); + mimeData->setImageData(FileListIcon(isLeft ? "arrow-left-double" : "arrow-right-double").pixmap()); mimeData->setUrls(urls); QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); } QString SynchronizerGUI::dirLabel() { //HACK add <> brackets AFTER translating - otherwise KUIT thinks it's a tag static QString label = QString("<") + i18nc("Show the string 'DIR' instead of file size in detailed view (for folders)", "DIR") + '>'; return label; } diff --git a/krusader/kicons.cpp b/krusader/filelisticon.cpp similarity index 71% rename from krusader/kicons.cpp rename to krusader/filelisticon.cpp index 22e0e345..3ba4aeeb 100644 --- a/krusader/kicons.cpp +++ b/krusader/filelisticon.cpp @@ -1,43 +1,38 @@ /***************************************************************************** - * Copyright (C) 2000 Shie Erlich * - * Copyright (C) 2000 Rafi Yanai * - * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * + * Copyright (C) 2018 Nikita Melnichenko * + * Copyright (C) 2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ -#include "kicons.h" +#include "filelisticon.h" #include "krglobal.h" -#include "icon.h" #include "defaults.h" -// QtCore -#include -// QtGui -#include -// QtWidgets -#include - #include -#include -QPixmap FL_LOADICON(QString name) + +QSize FileListIcon::size() const +{ + int linearSize = KConfigGroup(krConfig, "Look&Feel").readEntry("Filelist Icon Size", _FilelistIconSize).toInt(); + return QSize(linearSize, linearSize); +} + +QPixmap FileListIcon::pixmap() const { - KConfigGroup group(krConfig, "Look&Feel"); - int size = (group.readEntry("Filelist Icon Size", _FilelistIconSize)).toInt(); - return Icon(name).pixmap(size); + return QIcon::pixmap(size()); } diff --git a/krusader/kicons.h b/krusader/filelisticon.h similarity index 74% rename from krusader/kicons.h rename to krusader/filelisticon.h index 3f3cfd1e..f0a46d70 100644 --- a/krusader/kicons.h +++ b/krusader/filelisticon.h @@ -1,31 +1,42 @@ /***************************************************************************** - * Copyright (C) 2000 Shie Erlich * - * Copyright (C) 2000 Rafi Yanai * - * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * + * Copyright (C) 2018 Nikita Melnichenko * + * Copyright (C) 2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ -#ifndef KICONS_H -#define KICONS_H +#ifndef FILELISTICON_H +#define FILELISTICON_H + +#include "icon.h" // QtGui #include -// used only for calls within the kfilelist framework, handles icon sizes -QPixmap FL_LOADICON(QString name); -#endif +class FileListIcon : public Icon +{ +public: + explicit FileListIcon(QString name) : Icon(name) {} + + /// Load pixmap of standard file list icon size + QPixmap pixmap() const; + + /// Get icon size as configured by user + QSize size() const; +}; + +#endif // FILELISTICON_H diff --git a/krusader/krusader.cpp b/krusader/krusader.cpp index 47b50056..beeae8ee 100644 --- a/krusader/krusader.cpp +++ b/krusader/krusader.cpp @@ -1,644 +1,643 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * Copyright (C) 2000 Rafi Yanai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader 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. * * * * Krusader 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 Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "krusader.h" // QtCore #include #include #include #include // QtGui #include #include // QtWidgets #include #include #include // QtDBus #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "defaults.h" -#include "kicons.h" #include "kractions.h" #include "krglobal.h" #include "krservices.h" #include "krslots.h" #include "krtrashhandler.h" #include "krusaderversion.h" #include "krusaderview.h" #include "panelmanager.h" #include "tabactions.h" #include "BookMan/krbookmarkhandler.h" #include "Dialogs/checksumdlg.h" #include "Dialogs/krpleasewait.h" #include "Dialogs/popularurls.h" #include "FileSystem/fileitem.h" #include "FileSystem/krpermhandler.h" #include "GUI/kcmdline.h" #include "GUI/kfnkeys.h" #include "GUI/krremoteencodingmenu.h" #include "GUI/krusaderstatus.h" #include "GUI/terminaldock.h" #include "JobMan/jobman.h" #include "KViewer/krviewer.h" #include "Konfigurator/kgprotocols.h" #include "MountMan/kmountman.h" #include "Panel/PanelView/krview.h" #include "Panel/PanelView/krviewfactory.h" #include "Panel/krcolorcache.h" #include "Panel/krpanel.h" #include "Panel/listpanelactions.h" #include "Panel/viewactions.h" #include "UserAction/expander.h" // This makes gcc-4.1 happy. Warning about possible problem with KrAction's dtor not called #include "UserAction/kraction.h" #include "UserAction/useraction.h" #ifdef __KJSEMBED__ #include "KrJS/krjs.h" #endif // define the static members Krusader *Krusader::App = 0; QString Krusader::AppName; // KrBookmarkHandler *Krusader::bookman = 0; //QTextOStream *Krusader::_krOut = QTextOStream(::stdout); #ifdef __KJSEMBED__ KrJS *Krusader::js = 0; QAction *Krusader::actShowJSConsole = 0; #endif // construct the views, statusbar and menu bars and prepare Krusader to start Krusader::Krusader(const QCommandLineParser &parser) : KParts::MainWindow(0, Qt::Window | Qt::WindowTitleHint | Qt::WindowContextHelpButtonHint), _listPanelActions(0), isStarting(true), isExiting(false), _quit(false) { // create the "krusader" App = this; krMainWindow = this; SLOTS = new KRslots(this); setXMLFile("krusaderui.rc"); // kpart-related xml file plzWait = new KRPleaseWaitHandler(this); const bool runKonfig = versionControl(); QString message; switch (krConfig->accessMode()) { case KConfigBase::NoAccess : message = "Krusader's configuration file can't be found. Default values will be used."; break; case KConfigBase::ReadOnly : message = "Krusader's configuration file is in READ ONLY mode (why is that!?) Changed values will not be saved"; break; case KConfigBase::ReadWrite : message = ""; break; } if (!message.isEmpty()) { KMessageBox::error(krApp, message); } // create an icon loader krLoader = KIconLoader::global(); // create MountMan KrGlobal::mountMan = new KMountMan(this); connect(KrGlobal::mountMan, SIGNAL(refreshPanel(QUrl)), SLOTS, SLOT(refresh(QUrl))); // create popular URLs container _popularUrls = new PopularUrls(this); // create bookman krBookMan = new KrBookmarkHandler(this); // create job manager krJobMan = new JobMan(this); // create the main view MAIN_VIEW = new KrusaderView(this); // setup all the krusader's actions setupActions(); // init the permmision handler class KRpermHandler::init(); // init the protocol handler KgProtocols::init(); const KConfigGroup lookFeelGroup(krConfig, "Look&Feel"); FileItem::loadUserDefinedFolderIcons(lookFeelGroup.readEntry("Load User Defined Folder Icons", _UserDefinedFolderIcons)); const KConfigGroup startupGroup(krConfig, "Startup"); QString startProfile = startupGroup.readEntry("Starter Profile Name", QString()); QList leftTabs; QList rightTabs; // get command-line arguments if (parser.isSet("left")) { leftTabs = KrServices::toUrlList(parser.value("left").split(',')); startProfile.clear(); } if (parser.isSet("right")) { rightTabs = KrServices::toUrlList(parser.value("right").split(',')); startProfile.clear(); } if (parser.isSet("profile")) startProfile = parser.value("profile"); if (!startProfile.isEmpty()) { leftTabs.clear(); rightTabs.clear(); } // starting the panels MAIN_VIEW->start(startupGroup, startProfile.isEmpty(), leftTabs, rightTabs); // create a status bar KrusaderStatus *status = new KrusaderStatus(this); setStatusBar(status); status->setWhatsThis(i18n("Statusbar will show basic information " "about file below mouse pointer.")); // create tray icon (if needed) const bool startToTray = startupGroup.readEntry("Start To Tray", _StartToTray); setTray(startToTray); setCentralWidget(MAIN_VIEW); // manage our keyboard short-cuts //KAcceleratorManager::manage(this,true); setCursor(Qt::ArrowCursor); if (! startProfile.isEmpty()) MAIN_VIEW->profiles(startProfile); // restore gui settings { // now, check if we need to create a konsole_part // call the XML GUI function to draw the UI createGUI(MAIN_VIEW->terminalDock()->part()); // this needs to be called AFTER createGUI() !!! updateUserActions(); _listPanelActions->guiUpdated(); // not using this. See savePosition() //applyMainWindowSettings(); const KConfigGroup cfgToolbar(krConfig, "Main Toolbar"); toolBar()->applySettings(cfgToolbar); const KConfigGroup cfgJobBar(krConfig, "Job Toolbar"); toolBar("jobToolBar")->applySettings(cfgJobBar); const KConfigGroup cfgActionsBar(krConfig, "Actions Toolbar"); toolBar("actionsToolBar")->applySettings(cfgActionsBar); // restore toolbars position and visibility restoreState(startupGroup.readEntry("State", QByteArray())); statusBar()->setVisible(startupGroup.readEntry("Show status bar", _ShowStatusBar)); MAIN_VIEW->updateGUI(startupGroup); // popular urls _popularUrls->load(); } if (runKonfig) SLOTS->runKonfigurator(true); KConfigGroup viewerModuleGrp(krConfig, "ViewerModule"); if (viewerModuleGrp.readEntry("FirstRun", true)) { KrViewer::configureDeps(); viewerModuleGrp.writeEntry("FirstRun", false); } if (!runKonfig) { KConfigGroup cfg(krConfig, "Private"); move(cfg.readEntry("Start Position", _StartPosition)); resize(cfg.readEntry("Start Size", _StartSize)); } // view initialized; show window or only tray if (!startToTray) { show(); } KrTrashHandler::startWatcher(); isStarting = false; //HACK - used by [ListerTextArea|KrSearchDialog|LocateDlg]:keyPressEvent() KrGlobal::copyShortcut = _listPanelActions->actCopy->shortcut(); //HACK: make sure the active view becomes focused // for some reason sometimes the active view cannot be focused immediately at this point, // so queue it for the main loop QTimer::singleShot(0, ACTIVE_PANEL->view->widget(), SLOT(setFocus())); _openUrlTimer.setSingleShot(true); connect(&_openUrlTimer, SIGNAL(timeout()), SLOT(doOpenUrl())); KStartupInfo *startupInfo = new KStartupInfo(0, this); connect(startupInfo, &KStartupInfo::gotNewStartup, this, &Krusader::slotGotNewStartup); connect(startupInfo, &KStartupInfo::gotRemoveStartup, this, &Krusader::slotGotRemoveStartup); } Krusader::~Krusader() { KrTrashHandler::stopWatcher(); if (!isExiting) // save the settings if it was not saved (SIGTERM received) saveSettings(); delete MAIN_VIEW; MAIN_VIEW = 0; App = 0; } void Krusader::setTray(bool forceCreation) { const bool trayIsNeeded = forceCreation || KConfigGroup(krConfig, "Look&Feel") .readEntry("Minimize To Tray", _ShowTrayIcon); if (!sysTray && trayIsNeeded) { sysTray = new KStatusNotifierItem(this); sysTray->setIconByName(privIcon()); // we have our own "quit" method, re-connect QAction *quitAction = sysTray->action(QStringLiteral("quit")); if (quitAction) { disconnect(quitAction, &QAction::triggered, nullptr, nullptr); connect(quitAction, &QAction::triggered, this, &Krusader::quit); } } else if (sysTray && !trayIsNeeded) { // user does not want tray anymore :( sysTray->deleteLater(); } } bool Krusader::versionControl() { // create config file krConfig = KSharedConfig::openConfig().data(); KConfigGroup nogroup(krConfig, QString()); const bool firstRun = nogroup.readEntry("First Time", true); KrGlobal::sCurrentConfigVersion = nogroup.readEntry("Config Version", -1); // first installation of krusader if (firstRun) { KMessageBox::information( krApp, i18n("Welcome to Krusader.

As this is your first run, your machine " "will now be checked for external applications. Then the Konfigurator will " "be launched where you can customize Krusader to your needs.

")); } nogroup.writeEntry("Version", VERSION); nogroup.writeEntry("First Time", false); krConfig->sync(); QDir().mkpath(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/krusader/")); return firstRun; } void Krusader::statusBarUpdate(const QString& mess) { // change the message on the statusbar for 5 seconds if (statusBar()->isVisible()) statusBar()->showMessage(mess, 5000); } bool Krusader::event(QEvent *e) { if(e->type() == QEvent::ApplicationPaletteChange) { KrColorCache::getColorCache().refreshColors(); } return KParts::MainWindow::event(e); } // Moving from Pixmap actions to generic filenames - thanks to Carsten Pfeiffer void Krusader::setupActions() { QAction *bringToTopAct = new QAction(i18n("Bring Main Window to Top"), this); actionCollection()->addAction("bring_main_window_to_top", bringToTopAct); connect(bringToTopAct, SIGNAL(triggered()), SLOT(moveToTop())); KrActions::setupActions(this); _krActions = new KrActions(this); _viewActions = new ViewActions(this, this); _listPanelActions = new ListPanelActions(this, this); _tabActions = new TabActions(this, this); } /////////////////////////////////////////////////////////////////////////// //////////////////// implementation of slots ////////////////////////////// /////////////////////////////////////////////////////////////////////////// void Krusader::savePosition() { KConfigGroup cfg(krConfig, "Private"); cfg.writeEntry("Start Position", pos()); cfg.writeEntry("Start Size", size()); cfg = krConfig->group("Startup"); MAIN_VIEW->saveSettings(cfg); // NOTE: this would save current window state/size, statusbar and settings for each toolbar. // We are not using this and saving everything manually because // - it does not save window position // - window size save/restore does sometimes not work (multi-monitor setup) // - saving the statusbar visibility should be independent from window position and restoring it // does not work properly. //KConfigGroup cfg = KConfigGroup(&cfg, "MainWindowSettings"); //saveMainWindowSettings(cfg); //statusBar()->setVisible(cfg.readEntry("StatusBar", "Enabled") != "Disabled"); krConfig->sync(); } void Krusader::saveSettings() { // workaround: revert terminal fullscreen mode before saving widget and toolbar visibility if (MAIN_VIEW->isTerminalEmulatorFullscreen()) { MAIN_VIEW->setTerminalEmulator(false, true); } KConfigGroup noGroup(krConfig, QString()); noGroup.writeEntry("Config Version", KrGlobal::sConfigVersion); // save toolbar settings KConfigGroup cfg(krConfig, "Main Toolbar"); toolBar()->saveSettings(cfg); cfg = krConfig->group("Job Toolbar"); toolBar("jobToolBar")->saveSettings(cfg); cfg = krConfig->group("Actions Toolbar"); toolBar("actionsToolBar")->saveSettings(cfg); cfg = krConfig->group("Startup"); // save toolbar visibility and position cfg.writeEntry("State", saveState()); cfg.writeEntry("Show status bar", statusBar()->isVisible()); // save panel and window settings if (cfg.readEntry("Remember Position", _RememberPos)) savePosition(); // save the gui components visibility if (cfg.readEntry("UI Save Settings", _UiSave)) { cfg.writeEntry("Show FN Keys", KrActions::actToggleFnkeys->isChecked()); cfg.writeEntry("Show Cmd Line", KrActions::actToggleCmdline->isChecked()); cfg.writeEntry("Show Terminal Emulator", KrActions::actToggleTerminal->isChecked()); } // save popular links _popularUrls->save(); krConfig->sync(); } void Krusader::closeEvent(QCloseEvent *event) { if (!sysTray || _quit) { _quit = false; // in case quit will be aborted KParts::MainWindow::closeEvent(event); // (may) quit, continues with queryClose()... } else { // close window to tray event->ignore(); hide(); } } void Krusader::showEvent(QShowEvent *event) { const KConfigGroup lookFeelGroup(krConfig, "Look&Feel"); if (sysTray && !lookFeelGroup.readEntry("Minimize To Tray", _ShowTrayIcon)) { // restoring from "start to tray", tray icon is not needed anymore sysTray->deleteLater(); } KParts::MainWindow::showEvent(event); } bool Krusader::queryClose() { if (isStarting || isExiting) return false; if (qApp->isSavingSession()) { // KDE is logging out, accept the close acceptClose(); return true; } const KConfigGroup cfg = krConfig->group("Look&Feel"); const bool confirmExit = cfg.readEntry("Warn On Exit", _WarnOnExit); // ask user and wait until all KIO::job operations are terminated. Krusader won't exit before // that anyway if (!krJobMan->waitForJobs(confirmExit)) return false; /* First try to close the child windows, because it's the safer way to avoid crashes, then close the main window. If closing a child is not successful, then we cannot let the main window close. */ for (;;) { QWidgetList list = QApplication::topLevelWidgets(); QWidget *activeModal = QApplication::activeModalWidget(); QWidget *w = list.at(0); if (activeModal && activeModal != this && activeModal != menuBar() && list.contains(activeModal) && !activeModal->isHidden()) { w = activeModal; } else { int i = 1; for (; i < list.count(); ++i) { w = list.at(i); if (!(w && (w == this || w->isHidden() || w == menuBar()))) break; } if (i == list.count()) w = 0; } if (!w) break; if (!w->close()) { if (w->inherits("QDialog")) { fprintf(stderr, "Failed to close: %s\n", w->metaObject()->className()); } return false; } } acceptClose(); return true; } void Krusader::acceptClose() { saveSettings(); emit shutdown(); // Removes the DBUS registration of the application. Single instance mode requires unique appid. // As Krusader is exiting, we release that unique appid, so new Krusader instances // can be started. QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.unregisterObject("/Instances/" + Krusader::AppName); isExiting = true; } // the please wait dialog functions void Krusader::startWaiting(QString msg, int count , bool cancel) { plzWait->startWaiting(msg , count, cancel); } bool Krusader::wasWaitingCancelled() const { return plzWait->wasCancelled(); } void Krusader::stopWait() { plzWait->stopWait(); } void Krusader::updateUserActions() { KActionMenu *userActionMenu = (KActionMenu *) KrActions::actUserMenu; if (userActionMenu) { userActionMenu->menu()->clear(); userActionMenu->addAction(KrActions::actManageUseractions); userActionMenu->addSeparator(); krUserAction->populateMenu(userActionMenu, NULL); } } const char* Krusader::privIcon() { if (geteuid()) return "krusader_user"; else return "krusader_root"; } void Krusader::quit() { _quit = true; // remember that we want to quit and not close to tray close(); // continues with closeEvent()... } void Krusader::moveToTop() { if (isHidden()) show(); KWindowSystem::forceActiveWindow(winId()); } bool Krusader::isRunning() { moveToTop(); //FIXME - doesn't belong here return true; } bool Krusader::isLeftActive() { return MAIN_VIEW->isLeftActive(); } bool Krusader::openUrl(QString url) { _urlToOpen = url; _openUrlTimer.start(0); return true; } void Krusader::doOpenUrl() { QUrl url = QUrl::fromUserInput(_urlToOpen, QDir::currentPath(), QUrl::AssumeLocalFile); _urlToOpen.clear(); int tab = ACTIVE_MNG->findTab(url); if(tab >= 0) ACTIVE_MNG->setActiveTab(tab); else if((tab = OTHER_MNG->findTab(url)) >= 0) { OTHER_MNG->setActiveTab(tab); OTHER_MNG->currentPanel()->view->widget()->setFocus(); } else ACTIVE_MNG->slotNewTab(url); } void Krusader::slotGotNewStartup(const KStartupInfoId &id, const KStartupInfoData &data) { Q_UNUSED(id) Q_UNUSED(data) // This is here to show busy mouse cursor when _other_ applications are launched, not for krusader itself. qApp->setOverrideCursor(Qt::BusyCursor); } void Krusader::slotGotRemoveStartup(const KStartupInfoId &id, const KStartupInfoData &data) { Q_UNUSED(id) Q_UNUSED(data) qApp->restoreOverrideCursor(); } KrView *Krusader::activeView() { return ACTIVE_PANEL->view; } AbstractPanelManager *Krusader::activeManager() { return MAIN_VIEW->activeManager(); } AbstractPanelManager *Krusader::leftManager() { return MAIN_VIEW->leftManager(); } AbstractPanelManager *Krusader::rightManager() { return MAIN_VIEW->rightManager(); }