diff --git a/krusader/Dialogs/krdialogs.cpp b/krusader/Dialogs/krdialogs.cpp index b7b58b3e..176cb88e 100644 --- a/krusader/Dialogs/krdialogs.cpp +++ b/krusader/Dialogs/krdialogs.cpp @@ -1,200 +1,201 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * Copyright (C) 2000 Rafi Yanai * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This package is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this package; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ #include "krdialogs.h" // QtCore +#include #include // QtGui #include #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include #include #include "../krglobal.h" #include "../FileSystem/filesystem.h" #include "../defaults.h" #include "../JobMan/jobman.h" QUrl KChooseDir::getFile(const QString &text, const QUrl& url, const QUrl& cwd) { return get(text, url, cwd, KFile::File); } QUrl KChooseDir::getDir(const QString &text, const QUrl& url, const QUrl& cwd) { return get(text, url, cwd, KFile::Directory); } QUrl KChooseDir::get(const QString &text, const QUrl &url, const QUrl &cwd, KFile::Modes mode) { QScopedPointer dlg(new KUrlRequesterDialog(FileSystem::ensureTrailingSlash(url), text, krMainWindow)); dlg->urlRequester()->setStartDir(cwd); dlg->urlRequester()->setMode(mode); dlg->exec(); QUrl u = dlg->selectedUrl(); // empty if cancelled if (u.scheme() == "zip" || u.scheme() == "krarc" || u.scheme() == "tar" || u.scheme() == "iso") { if (QDir(u.path()).exists()) { u.setScheme("file"); } } return u; } KChooseDir::ChooseResult KChooseDir::getCopyDir(const QString &text, const QUrl &url, const QUrl &cwd) { QScopedPointer dlg(new KUrlRequesterDlgForCopy(url, text, krMainWindow, true)); dlg->urlRequester()->setStartDir(cwd); dlg->urlRequester()->setMode(KFile::Directory); dlg->exec(); QUrl u = dlg->selectedURL(); if (u.scheme() == "zip" || u.scheme() == "krarc" || u.scheme() == "tar" || u.scheme() == "iso") { if (QDir(u.path()).exists()) { u.setScheme("file"); } } ChooseResult result; result.url = u; result.enqueue = dlg->isQueued(); return result; } KUrlRequesterDlgForCopy::KUrlRequesterDlgForCopy(const QUrl &urlName, const QString &_text, QWidget *parent, bool modal) : QDialog(parent) { setWindowModality(modal ? Qt::WindowModal : Qt::NonModal); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); mainLayout->addWidget(new QLabel(_text)); urlRequester_ = new KUrlRequester(urlName, this); urlRequester_->setMinimumWidth(urlRequester_->sizeHint().width() * 3); mainLayout->addWidget(urlRequester_); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); mainLayout->addWidget(buttonBox); okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); QPushButton *queueButton = new QPushButton( krJobMan->isQueueModeEnabled() ? i18n("F2 Delay Job Start") : i18n("F2 Queue"), this); queueButton->setToolTip(krJobMan->isQueueModeEnabled() ? i18n("Do not start the job now.") : i18n("Enqueue the job if another job is running. Otherwise start immediately.")); buttonBox->addButton(queueButton, QDialogButtonBox::ActionRole); connect(buttonBox, SIGNAL(accepted()), SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), SLOT(reject())); connect(queueButton, SIGNAL(clicked()), SLOT(slotQueueButtonClicked())); connect(urlRequester_, SIGNAL(textChanged(QString)), SLOT(slotTextChanged(QString))); urlRequester_->setFocus(); bool state = !urlName.isEmpty(); okButton->setEnabled(state); } void KUrlRequesterDlgForCopy::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_F2: slotQueueButtonClicked(); return; default: QDialog::keyPressEvent(e); } } void KUrlRequesterDlgForCopy::slotQueueButtonClicked() { queueStart = true; accept(); } void KUrlRequesterDlgForCopy::slotTextChanged(const QString & text) { bool state = !text.trimmed().isEmpty(); okButton->setEnabled(state); } QUrl KUrlRequesterDlgForCopy::selectedURL() const { if (result() == QDialog::Accepted) { QUrl url = urlRequester_->url(); qDebug() << "requester returned URL=" << url.toDisplayString(); if (url.isValid()) KRecentDocument::add(url); return url; } else return QUrl(); } KUrlRequester * KUrlRequesterDlgForCopy::urlRequester() { return urlRequester_; } KRGetDate::KRGetDate(QDate date, QWidget *parent) : QDialog(parent, Qt::MSWindowsFixedSizeDialogHint) { setWindowModality(Qt::WindowModal); dateWidget = new KDatePicker(this); dateWidget->setDate(date); dateWidget->resize(dateWidget->sizeHint()); setMinimumSize(dateWidget->sizeHint()); setMaximumSize(dateWidget->sizeHint()); resize(minimumSize()); connect(dateWidget, SIGNAL(dateSelected(QDate)), this, SLOT(setDate(QDate))); connect(dateWidget, SIGNAL(dateEntered(QDate)), this, SLOT(setDate(QDate))); // keep the original date - incase ESC is pressed originalDate = date; } QDate KRGetDate::getDate() { if (exec() == QDialog::Rejected) chosenDate = QDate(); hide(); return chosenDate; } void KRGetDate::setDate(QDate date) { chosenDate = date; accept(); } diff --git a/krusader/DiskUsage/diskusage.cpp b/krusader/DiskUsage/diskusage.cpp index 00416630..39a4bb25 100644 --- a/krusader/DiskUsage/diskusage.cpp +++ b/krusader/DiskUsage/diskusage.cpp @@ -1,1137 +1,1138 @@ /*************************************************************************** diskusage.cpp - description ------------------- copyright : (C) 2004 + by Csaba Karai e-mail : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD S o u r c e F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #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" // 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; } case Qt::Key_D: if (e->modifiers() == Qt::ControlModifier) { executeAction(DETAILED_VIEW_ID); return; } case Qt::Key_F: if (e->modifiers() == Qt::ControlModifier) { executeAction(FILELIGHT_VIEW_ID); return; } 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; } 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; } 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"); else { QMimeDatabase db; QMimeType mt = db.mimeTypeForName(mime); if (mt.isValid()) icon = FL_LOADICON(mt.iconName()); else icon = FL_LOADICON("file-broken"); } // 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/FileSystem/defaultfilesystem.cpp b/krusader/FileSystem/defaultfilesystem.cpp index e3471e05..84bf7dcb 100644 --- a/krusader/FileSystem/defaultfilesystem.cpp +++ b/krusader/FileSystem/defaultfilesystem.cpp @@ -1,410 +1,411 @@ /*************************************************************************** defaultfilesystem.cpp ------------------- copyright : (C) 2000 by Rafi Yanai e-mail : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD S o u r c e F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "defaultfilesystem.h" // QtCore +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fileitem.h" #include "../defaults.h" #include "../krglobal.h" #include "../krservices.h" #include "../JobMan/krjob.h" DefaultFileSystem::DefaultFileSystem(): FileSystem(), _watcher() { _type = FS_DEFAULT; } void DefaultFileSystem::copyFiles(const QList &urls, const QUrl &destination, KIO::CopyJob::CopyMode mode, bool showProgressInfo, JobMan::StartMode startMode) { // resolve relative path before resolving symlinks const QUrl dest = resolveRelativePath(destination); KIO::JobFlags flags = showProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo; KrJob *krJob = KrJob::createCopyJob(mode, urls, dest, flags); // destination can be a full path with filename when copying/moving a single file const QUrl destDir = dest.adjusted(QUrl::RemoveFilename); connect(krJob, &KrJob::started, this, [=](KIO::Job *job) { connectJobToDestination(job, destDir); }); if (mode == KIO::CopyJob::Move) { // notify source about removed files connect(krJob, &KrJob::started, this, [=](KIO::Job *job) { connectJobToSources(job, urls); }); } krJobMan->manageJob(krJob, startMode); } void DefaultFileSystem::dropFiles(const QUrl &destination, QDropEvent *event) { qDebug() << "destination=" << destination; // resolve relative path before resolving symlinks const QUrl dest = resolveRelativePath(destination); KIO::DropJob *job = KIO::drop(event, dest); #if KIO_VERSION >= QT_VERSION_CHECK(5, 30, 0) // NOTE: a DropJob "starts" with showing a menu. If the operation is choosen (copy/move/link) // the actual CopyJob starts automatically - we cannot manage the start of the CopyJob (see // documentation for KrJob) connect(job, &KIO::DropJob::copyJobStarted, this, [=](KIO::CopyJob *kJob) { connectJobToDestination(job, dest); // now we have to refresh the destination KrJob *krJob = KrJob::createDropJob(job, kJob); krJobMan->manageStartedJob(krJob, kJob); if (kJob->operationMode() == KIO::CopyJob::Move) { // notify source about removed files connectJobToSources(kJob, kJob->srcUrls()); } }); #else // NOTE: DropJob does not provide information about the actual user choice // (move/copy/link/abort). We have to assume the worst (move) connectJob(job, dest); connectSourceFileSystem(job, KUrlMimeData::urlsFromMimeData(event->mimeData())); #endif } void DefaultFileSystem::addFiles(const QList &fileUrls, KIO::CopyJob::CopyMode mode, const QString &dir) { QUrl destination(_currentDirectory); if (!dir.isEmpty()) { destination.setPath(QDir::cleanPath(destination.path() + '/' + dir)); const QString scheme = destination.scheme(); if (scheme == "tar" || scheme == "zip" || scheme == "krarc") { if (QDir(destination.path()).exists()) // if we get out from the archive change the protocol destination.setScheme("file"); } } destination = ensureTrailingSlash(destination); // destination is always a directory copyFiles(fileUrls, destination, mode); } void DefaultFileSystem::mkDir(const QString &name) { KIO::SimpleJob* job = KIO::mkdir(getUrl(name)); connectJobToDestination(job, currentDirectory()); } void DefaultFileSystem::rename(const QString &oldName, const QString &newName) { const QUrl oldUrl = getUrl(oldName); const QUrl newUrl = getUrl(newName); KIO::Job *job = KIO::moveAs(oldUrl, newUrl, KIO::HideProgressInfo); connectJobToDestination(job, currentDirectory()); KIO::FileUndoManager::self()->recordJob(KIO::FileUndoManager::Rename, {oldUrl}, newUrl, job); } QUrl DefaultFileSystem::getUrl(const QString& name) const { // NOTE: on non-local fs file URL does not have to be path + name! FileItem *fileItem = getFileItem(name); if (fileItem) return fileItem->getUrl(); QUrl absoluteUrl(_currentDirectory); absoluteUrl.setPath(absoluteUrl.path() + '/' + name); return absoluteUrl; } void DefaultFileSystem::updateFilesystemInfo() { if (!KConfigGroup(krConfig, "Look&Feel").readEntry("ShowSpaceInformation", true)) { _mountPoint = ""; emit fileSystemInfoChanged(i18n("Space information disabled"), "", 0, 0); return; } // TODO get space info for trash:/ with KIO spaceInfo job if (!_currentDirectory.isLocalFile()) { _mountPoint = ""; emit fileSystemInfoChanged(i18n("No space information on non-local filesystems"), "", 0, 0); return; } const QString path = _currentDirectory.path(); const KDiskFreeSpaceInfo info = KDiskFreeSpaceInfo::freeSpaceInfo(path); if (!info.isValid()) { _mountPoint = ""; emit fileSystemInfoChanged(i18n("Space information unavailable"), "", 0, 0); return; } _mountPoint = info.mountPoint(); const KMountPoint::Ptr mountPoint = KMountPoint::currentMountPoints().findByPath(path); const QString fsType = mountPoint ? mountPoint->mountType() : ""; emit fileSystemInfoChanged("", fsType, info.size(), info.available()); } // ==== protected ==== bool DefaultFileSystem::refreshInternal(const QUrl &directory, bool onlyScan) { qDebug() << "refresh internal to URL=" << directory.toDisplayString(); if (!KProtocolManager::supportsListing(directory)) { emit error(i18n("Protocol not supported by Krusader:\n%1", directory.url())); return false; } delete _watcher; // stop watching the old dir if (directory.isLocalFile()) { qDebug() << "start local refresh to URL=" << directory.toDisplayString(); // we could read local directories with KIO but using Qt is a lot faster! return refreshLocal(directory, onlyScan); } _currentDirectory = cleanUrl(directory); // start the listing job KIO::ListJob *job = KIO::listDir(_currentDirectory, KIO::HideProgressInfo, showHiddenFiles()); connect(job, &KIO::ListJob::entries, this, &DefaultFileSystem::slotAddFiles); connect(job, &KIO::ListJob::redirection, this, &DefaultFileSystem::slotRedirection); connect(job, &KIO::ListJob::permanentRedirection, this, &DefaultFileSystem::slotRedirection); connect(job, &KIO::Job::result, this, &DefaultFileSystem::slotListResult); // ensure connection credentials are asked only once if(!parentWindow.isNull()) { KIO::JobUiDelegate *ui = static_cast(job->uiDelegate()); ui->setWindow(parentWindow); } emit refreshJobStarted(job); _listError = false; // ugly: we have to wait here until the list job is finished QEventLoop eventLoop; connect(job, &KJob::finished, &eventLoop, &QEventLoop::quit); eventLoop.exec(); // blocking until quit() return !_listError; } // ==== protected slots ==== void DefaultFileSystem::slotListResult(KJob *job) { qDebug() << "got list result"; if (job && job->error()) { // we failed to refresh _listError = true; qDebug() << "error=" << job->errorString() << "; text=" << job->errorText(); emit error(job->errorString()); // display error message (in panel) } } void DefaultFileSystem::slotAddFiles(KIO::Job *, const KIO::UDSEntryList& entries) { for (const KIO::UDSEntry entry : entries) { FileItem *fileItem = FileSystem::createFileItemFromKIO(entry, _currentDirectory); if (fileItem) { addFileItem(fileItem); } } } void DefaultFileSystem::slotRedirection(KIO::Job *job, const QUrl &url) { qDebug() << "redirection to URL=" << url.toDisplayString(); // some protocols (zip, tar) send redirect to local URL without scheme const QUrl newUrl = preferLocalUrl(url); if (newUrl.scheme() != _currentDirectory.scheme()) { // abort and start over again, // some protocols (iso, zip, tar) do this on transition to local fs job->kill(); _isRefreshing = false; refresh(newUrl); return; } _currentDirectory = cleanUrl(newUrl); } void DefaultFileSystem::slotWatcherCreated(const QString& path) { qDebug() << "path created (doing nothing): " << path; } void DefaultFileSystem::slotWatcherDirty(const QString& path) { qDebug() << "path dirty: " << path; if (path == realPath()) { // this happens // 1. if a directory was created/deleted/renamed inside this directory. // 2. during and after a file operation (create/delete/rename/touch) inside this directory // KDirWatcher doesn't reveal the name of changed directories and we have to refresh. // (QFileSystemWatcher in Qt5.7 can't help here either) refresh(); return; } const QString name = QUrl::fromLocalFile(path).fileName(); FileItem *fileItem = getFileItem(name); if (!fileItem) { qWarning() << "file not found (unexpected), path=" << path; // this happens at least for cifs mounted filesystems: when a new file is created, a dirty // signal with its file path but no other signals are sent (buggy behaviour of KDirWatch) refresh(); return; } // we have an updated file.. FileItem *newFileItem = createLocalFileItem(name); addFileItem(newFileItem); emit updatedFileItem(newFileItem); delete fileItem; } void DefaultFileSystem::slotWatcherDeleted(const QString& path) { qDebug() << "path deleted: " << path; if (path != realPath()) { // ignore deletion of files here, a 'dirty' signal will be send anyway return; } // the current directory was deleted. Try a refresh, which will fail. An error message will // be emitted and the empty (non-existing) directory remains. refresh(); } bool DefaultFileSystem::refreshLocal(const QUrl &directory, bool onlyScan) { const QString path = KrServices::urlToLocalPath(directory); #ifdef Q_WS_WIN if (!path.contains("/")) { // change C: to C:/ path = path + QString("/"); } #endif // check if the new directory exists if (!QDir(path).exists()) { emit error(i18n("The folder %1 does not exist.", path)); return false; } // mount if needed emit aboutToOpenDir(path); // set the current directory... _currentDirectory = directory; _currentDirectory.setPath(QDir::cleanPath(_currentDirectory.path())); // Note: we are using low-level Qt functions here. // It's around twice as fast as using the QDir class. QT_DIR* dir = QT_OPENDIR(path.toLocal8Bit()); if (!dir) { emit error(i18n("Cannot open the folder %1.", path)); return false; } // change directory to the new directory const QString savedDir = QDir::currentPath(); if (!QDir::setCurrent(path)) { emit error(i18nc("%1=folder path", "Access to %1 denied", path)); QT_CLOSEDIR(dir); return false; } QT_DIRENT* dirEnt; QString name; const bool showHidden = showHiddenFiles(); while ((dirEnt = QT_READDIR(dir)) != NULL) { name = QString::fromLocal8Bit(dirEnt->d_name); // show hidden files? if (!showHidden && name.left(1) == ".") continue; // we don't need the "." and ".." entries if (name == "." || name == "..") continue; FileItem* temp = createLocalFileItem(name); addFileItem(temp); } // clean up QT_CLOSEDIR(dir); QDir::setCurrent(savedDir); if (!onlyScan) { // start watching the new dir for file changes _watcher = new KDirWatch(this); // if the current dir is a link path the watcher needs to watch the real path - and signal // parameters will be the real path _watcher->addDir(realPath(), KDirWatch::WatchFiles); connect(_watcher.data(), &KDirWatch::dirty, this, &DefaultFileSystem::slotWatcherDirty); // NOTE: not connecting 'created' signal. A 'dirty' is send after that anyway //connect(_watcher, SIGNAL(created(QString)), this, SLOT(slotWatcherCreated(QString))); connect(_watcher.data(), &KDirWatch::deleted, this, &DefaultFileSystem::slotWatcherDeleted); _watcher->startScan(false); } return true; } FileItem *DefaultFileSystem::createLocalFileItem(const QString &name) { return FileSystem::createLocalFileItem(name, _currentDirectory.path()); } QString DefaultFileSystem::DefaultFileSystem::realPath() { return QDir(_currentDirectory.toLocalFile()).canonicalPath(); } QUrl DefaultFileSystem::resolveRelativePath(const QUrl &url) { // if e.g. "/tmp/bin" is a link to "/bin", // resolve "/tmp/bin/.." to "/tmp" and not "/" return url.adjusted(QUrl::NormalizePathSegments); } diff --git a/krusader/FileSystem/filesystem.cpp b/krusader/FileSystem/filesystem.cpp index 3d8a29b3..5c395de0 100644 --- a/krusader/FileSystem/filesystem.cpp +++ b/krusader/FileSystem/filesystem.cpp @@ -1,314 +1,315 @@ /*************************************************************************** filesystem.cpp ------------------- copyright : (C) 2000 by Shie Erlich & Rafi Yanai e-mail : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net ------------------------------------------------------------------------ the filesystem class is an extendable class which by itself does (almost) nothing. other filesystems like the normal_filesystem inherits from this class and make it possible to use a consistent API for all types of filesystems. *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD S o u r c e F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "filesystem.h" // QtCore +#include #include #include // QtWidgets #include #include #include #include #include "fileitem.h" #include "krpermhandler.h" #include "../defaults.h" #include "../krglobal.h" #include "../JobMan/jobman.h" #include "../JobMan/krjob.h" FileSystem::FileSystem() : DirListerInterface(0), _isRefreshing(false) {} FileSystem::~FileSystem() { clear(_fileItems); // please don't remove this line. This informs the view about deleting the file items. emit cleared(); } QList FileSystem::getUrls(const QStringList &names) const { QList urls; for (const QString name : names) { urls.append(getUrl(name)); } return urls; } FileItem *FileSystem::getFileItem(const QString &name) const { return _fileItems.contains(name) ? _fileItems.value(name) : 0; } KIO::filesize_t FileSystem::totalSize() const { KIO::filesize_t temp = 0; for (FileItem *item : _fileItems.values()) { if (!item->isDir() && item->getName() != "." && item->getName() != "..") { temp += item->getSize(); } } return temp; } QUrl FileSystem::ensureTrailingSlash(const QUrl &url) { if (url.path().endsWith('/')) { return url; } QUrl adjustedUrl(url); adjustedUrl.setPath(adjustedUrl.path() + '/'); return adjustedUrl; } QUrl FileSystem::preferLocalUrl(const QUrl &url){ if (url.isEmpty() || !url.scheme().isEmpty()) return url; QUrl adjustedUrl = url; adjustedUrl.setScheme("file"); return adjustedUrl; } bool FileSystem::scanOrRefresh(const QUrl &directory, bool onlyScan) { qDebug() << "from current dir=" << _currentDirectory.toDisplayString() << "; to=" << directory.toDisplayString(); if (_isRefreshing) { // NOTE: this does not happen (unless async)"; return false; } // workaround for krarc: find out if transition to local fs is wanted and adjust URL manually QUrl url = directory; if (_currentDirectory.scheme() == "krarc" && url.scheme() == "krarc" && QDir(url.path()).exists()) { url.setScheme("file"); } const bool dirChange = !url.isEmpty() && cleanUrl(url) != _currentDirectory; const QUrl toRefresh = dirChange ? url.adjusted(QUrl::NormalizePathSegments) : _currentDirectory; if (!toRefresh.isValid()) { emit error(i18n("Malformed URL:\n%1", toRefresh.toDisplayString())); return false; } _isRefreshing = true; FileItemDict tempFileItems(_fileItems); // old file items are still used during refresh _fileItems.clear(); if (dirChange) // show an empty directory while loading the new one and clear selection emit cleared(); const bool refreshed = refreshInternal(toRefresh, onlyScan); _isRefreshing = false; if (!refreshed) { // cleanup and abort if (!dirChange) emit cleared(); clear(tempFileItems); return false; } emit scanDone(dirChange); clear(tempFileItems); updateFilesystemInfo(); return true; } void FileSystem::deleteFiles(const QStringList &fileNames, bool moveToTrash) { // get absolute URLs for file names deleteAnyFiles(getUrls(fileNames), moveToTrash); } void FileSystem::deleteAnyFiles(const QList &urls, bool moveToTrash) { KrJob *krJob = KrJob::createDeleteJob(urls, moveToTrash); connect(krJob, &KrJob::started, this, [=](KIO::Job *job) { connectJobToSources(job, urls); }); if (moveToTrash) { // update destination: the trash bin (in case a panel/tab is showing it) connect(krJob, &KrJob::started, this, [=](KIO::Job *job) { // Note: the "trash" protocal should always have only one "/" after the "scheme:" part connect(job, &KIO::Job::result, this, [=]() { emit fileSystemChanged(QUrl("trash:/")); }); }); } krJobMan->manageJob(krJob); } void FileSystem::connectJobToSources(KJob *job, const QList urls) { if (!urls.isEmpty()) { // NOTE: we assume that all files were in the same directory and only emit one signal for // the directory of the first file URL // TODO for deletion we need to actually refresh // * all dirs containing deleted files - once // * all deleted dirs + all subdirs const QUrl url = urls.first().adjusted(QUrl::RemoveFilename); connect(job, &KIO::Job::result, this, [=]() { emit fileSystemChanged(url); }); } } void FileSystem::connectJobToDestination(KJob *job, const QUrl &destination) { connect(job, &KIO::Job::result, this, [=]() { emit fileSystemChanged(destination); }); // (additional) direct refresh if on local fs because watcher is too slow const bool refresh = cleanUrl(destination) == _currentDirectory && isLocal(); connect(job, &KIO::Job::result, this, [=](KJob* job) { slotJobResult(job, refresh); }); } bool FileSystem::showHiddenFiles() { const KConfigGroup gl(krConfig, "Look&Feel"); return gl.readEntry("Show Hidden", _ShowHidden); } void FileSystem::addFileItem(FileItem *item) { _fileItems.insert(item->getName(), item); } FileItem *FileSystem::createLocalFileItem(const QString &name, const QString &directory, bool virt) { const QDir dir = QDir(directory); const QString path = dir.filePath(name); const QByteArray filePath = path.toLocal8Bit(); QT_STATBUF stat_p; stat_p.st_size = 0; stat_p.st_mode = 0; stat_p.st_mtime = 0; stat_p.st_uid = 0; stat_p.st_gid = 0; QT_LSTAT(filePath.data(), &stat_p); const KIO::filesize_t size = stat_p.st_size; bool isDir = S_ISDIR(stat_p.st_mode); const bool isLink = S_ISLNK(stat_p.st_mode); QString linkDestination; bool brokenLink = false; if (isLink) { // find where the link is pointing to qDebug() << "link name=" << path; // the path of the symlink target cannot be longer than the file size of the symlink char buffer[stat_p.st_size]; memset(buffer, 0, sizeof(buffer)); int bytesRead = readlink(filePath.data(), buffer, sizeof(buffer)); if (bytesRead != -1) { linkDestination = QString::fromLocal8Bit(buffer, bytesRead); // absolute or relative const QFileInfo linkFile(dir, linkDestination); if (!linkFile.exists()) brokenLink = true; else if (linkFile.isDir()) isDir = true; } else { qWarning() << "failed to read link, path=" << path; } } return new FileItem(virt ? path : name, QUrl::fromLocalFile(path), isDir, size, stat_p.st_mode, stat_p.st_mtime, stat_p.st_ctime, stat_p.st_atime, stat_p.st_uid, stat_p.st_gid, QString(), QString(), isLink, linkDestination, brokenLink); } FileItem *FileSystem::createFileItemFromKIO(const KIO::UDSEntry &entry, const QUrl &directory, bool virt) { const KFileItem kfi(entry, directory, true, true); const QString name = kfi.text(); // ignore un-needed entries if (name.isEmpty() || name == "." || name == "..") { return 0; } const QString localPath = kfi.localPath(); const QUrl url = !localPath.isEmpty() ? QUrl::fromLocalFile(localPath) : kfi.url(); const QString fname = virt ? url.toDisplayString() : name; // get file statistics... const time_t mtime = kfi.time(KFileItem::ModificationTime).toTime_t(); const time_t ctime = kfi.time(KFileItem::CreationTime).toTime_t(); // "Creation"? its "Changed" const time_t atime = kfi.time(KFileItem::AccessTime).toTime_t(); const mode_t mode = kfi.mode() | kfi.permissions(); // NOTE: we could get the mimetype (and file icon) from the kfileitem here but this is very // slow. Instead, the file item class has it's own (faster) way to determine the file type. // NOTE: "broken link" flag is always false, checking link destination existence is // considered to be too expensive return new FileItem(fname, url, kfi.isDir(), kfi.size(), mode, mtime, ctime, atime, (uid_t) -1, (gid_t) -1, kfi.user(), kfi.group(), kfi.isLink(), kfi.linkDest(), false, kfi.ACL().asString(), kfi.defaultACL().asString()); } void FileSystem::slotJobResult(KJob *job, bool refresh) { if (job->error() && job->uiDelegate()) { // show errors for modifying operations as popup (works always) job->uiDelegate()->showErrorMessage(); } if (refresh) { FileSystem::refresh(); } } void FileSystem::clear(FileItemDict &fileItems) { QHashIterator lit(fileItems); while (lit.hasNext()) { delete lit.next().value(); } fileItems.clear(); } diff --git a/krusader/FileSystem/sizecalculator.cpp b/krusader/FileSystem/sizecalculator.cpp index d8774cfa..b3ae5728 100644 --- a/krusader/FileSystem/sizecalculator.cpp +++ b/krusader/FileSystem/sizecalculator.cpp @@ -1,183 +1,183 @@ /***************************************************************************** * Copyright (C) 2017 Krusader Krew * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This package is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this package; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ #include "sizecalculator.h" // QtCore +#include #include #include #include "fileitem.h" #include "virtualfilesystem.h" -#include "../krglobal.h" SizeCalculator::SizeCalculator(const QList &urls) : QObject(nullptr), m_urls(urls), m_nextUrls(urls), m_totalSize(0), m_totalFiles(0), m_totalDirs(0), m_canceled(false), m_directorySizeJob(nullptr) { QTimer::singleShot(0, this, SLOT(start())); } SizeCalculator::~SizeCalculator() { if (m_directorySizeJob) m_directorySizeJob->kill(); } void SizeCalculator::start() { emit started(); nextUrl(); } void SizeCalculator::add(const QUrl &url) { m_urls.append(url); m_nextUrls.append(url); emitProgress(); } KIO::filesize_t SizeCalculator::totalSize() const { return m_totalSize + (m_directorySizeJob ? m_directorySizeJob->totalSize() : 0); } unsigned long SizeCalculator::totalFiles() const { return m_totalFiles + (m_directorySizeJob ? m_directorySizeJob->totalFiles() : 0); } unsigned long SizeCalculator::totalDirs() const { return m_totalDirs + (m_directorySizeJob ? m_directorySizeJob->totalSubdirs() : 0); } void SizeCalculator::cancel() { m_canceled = true; if (m_directorySizeJob) m_directorySizeJob->kill(); done(); } void SizeCalculator::nextUrl() { if (m_canceled) return; emitProgress(); if (!m_currentUrl.isEmpty()) emit calculated(m_currentUrl, m_currentUrlSize); m_currentUrlSize = 0; if (m_nextUrls.isEmpty()) { done(); return; } m_currentUrl = m_nextUrls.takeFirst(); if (m_currentUrl.scheme() == "virt") { // calculate size of all files/directories in this virtual directory VirtualFileSystem *fs = new VirtualFileSystem(); if (!fs->scanDir(m_currentUrl)) { qWarning() << "cannot scan virtual FS, URL=" << m_currentUrl.toDisplayString(); nextUrl(); return; } for (FileItem *file : fs->fileItems()) m_nextSubUrls << file->getUrl(); delete fs; } else { m_nextSubUrls << m_currentUrl; } nextSubUrl(); } void SizeCalculator::nextSubUrl() { if (m_canceled) return; if (m_nextSubUrls.isEmpty()) { nextUrl(); return; } const QUrl url = m_nextSubUrls.takeFirst(); KIO::StatJob *statJob = KIO::stat(url, KIO::HideProgressInfo); connect(statJob, &KIO::Job::result, this, &SizeCalculator::slotStatResult); } void SizeCalculator::slotStatResult(KJob *job) { if (m_canceled) return; if (job->error()) { qWarning() << "stat job failed, error=" << job->error() << "; error string=" << job->errorString(); nextSubUrl(); return; } const KIO::StatJob *statJob = static_cast(job); const QUrl url = statJob->url(); const KFileItem kfi(statJob->statResult(), url, true); if (kfi.isFile() || kfi.isLink()) { m_totalFiles++; m_totalSize += kfi.size(); m_currentUrlSize += kfi.size(); nextSubUrl(); return; } // URL should be a directory, we are always counting the directory itself m_totalDirs++; m_directorySizeJob = KIO::directorySize(url); connect(m_directorySizeJob.data(), &KIO::Job::result, this, &SizeCalculator::slotDirectorySizeResult); } void SizeCalculator::slotDirectorySizeResult(KJob *) { if (!m_directorySizeJob->error()) { m_totalSize += m_directorySizeJob->totalSize(); // do not count filesystem size of empty directories for this current directory m_currentUrlSize += m_directorySizeJob->totalFiles() == 0 ? 0 : m_directorySizeJob->totalSize(); m_totalFiles += m_directorySizeJob->totalFiles(); m_totalDirs += m_directorySizeJob->totalSubdirs(); } m_directorySizeJob = 0; nextSubUrl(); } void SizeCalculator::done() { emit finished(m_canceled); deleteLater(); } void SizeCalculator::emitProgress() { emit progressChanged((m_urls.length() - (float)m_nextUrls.length()) / m_urls.length() * 100); } diff --git a/krusader/Filter/advancedfilter.cpp b/krusader/Filter/advancedfilter.cpp index 3c4ea84f..539b1426 100644 --- a/krusader/Filter/advancedfilter.cpp +++ b/krusader/Filter/advancedfilter.cpp @@ -1,619 +1,620 @@ /*************************************************************************** advancedfilter.cpp - description ------------------- copyright : (C) 2003 + by Shie Erlich & Rafi Yanai & Csaba Karai e-mail : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD S o u r c e F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "advancedfilter.h" // QtCore +#include #include #include // QtGui #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include "../krglobal.h" #include "../Dialogs/krdialogs.h" #define USERSFILE QString("/etc/passwd") #define GROUPSFILE QString("/etc/group") AdvancedFilter::AdvancedFilter(FilterTabs *tabs, QWidget *parent) : QWidget(parent), fltTabs(tabs) { QGridLayout *filterLayout = new QGridLayout(this); filterLayout->setSpacing(6); filterLayout->setContentsMargins(11, 11, 11, 11); // Options for size QGroupBox *sizeGroup = new QGroupBox(this); QSizePolicy sizeGroupPolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); sizeGroupPolicy.setHeightForWidth(sizeGroup->sizePolicy().hasHeightForWidth()); sizeGroup->setSizePolicy(sizeGroupPolicy); sizeGroup->setTitle(i18n("Size")); QGridLayout *sizeLayout = new QGridLayout(sizeGroup); sizeLayout->setAlignment(Qt::AlignTop); sizeLayout->setSpacing(6); sizeLayout->setContentsMargins(11, 11, 11, 11); minSizeEnabled = new QCheckBox(sizeGroup); minSizeEnabled->setText(i18n("At Least")); minSizeEnabled->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); sizeLayout->addWidget(minSizeEnabled, 0, 0); minSizeAmount = new QSpinBox(sizeGroup); minSizeAmount->setRange(0, 999999999); minSizeAmount->setEnabled(false); sizeLayout->addWidget(minSizeAmount, 0, 1); minSizeType = new KComboBox(false, sizeGroup); // i18n: @item:inlistbox next to a text field containing the amount minSizeType->addItem(i18n("Byte")); // i18n: @item:inlistbox next to a text field containing the amount minSizeType->addItem(i18n("KiB")); // i18n: @item:inlistbox next to a text field containing the amount minSizeType->addItem(i18n("MiB")); // i18n: @item:inlistbox next to a text field containing the amount minSizeType->addItem(i18n("GiB")); minSizeType->setEnabled(false); sizeLayout->addWidget(minSizeType, 0, 2); maxSizeEnabled = new QCheckBox(sizeGroup); maxSizeEnabled->setText(i18n("At Most")); maxSizeEnabled->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); sizeLayout->addWidget(maxSizeEnabled, 0, 3); maxSizeAmount = new QSpinBox(sizeGroup); maxSizeAmount->setRange(0, 999999999); maxSizeAmount->setEnabled(false); sizeLayout->addWidget(maxSizeAmount, 0, 4); maxSizeType = new KComboBox(false, sizeGroup); // i18n: @item:inlistbox next to a text field containing the amount maxSizeType->addItem(i18n("Byte")); // i18n: @item:inlistbox next to a text field containing the amount maxSizeType->addItem(i18n("KiB")); // i18n: @item:inlistbox next to a text field containing the amount maxSizeType->addItem(i18n("MiB")); // i18n: @item:inlistbox next to a text field containing the amount maxSizeType->addItem(i18n("GiB")); maxSizeType->setEnabled(false); sizeLayout->addWidget(maxSizeType, 0, 5); filterLayout->addWidget(sizeGroup, 0, 0); // Options for date QPixmap iconDate = krLoader->loadIcon("view-calendar", KIconLoader::Toolbar, 16); QGroupBox *dateGroup = new QGroupBox(this); QButtonGroup *btnGroup = new QButtonGroup(dateGroup); dateGroup->setTitle(i18n("Date")); btnGroup->setExclusive(true); QGridLayout *dateLayout = new QGridLayout(dateGroup); dateLayout->setAlignment(Qt::AlignTop); dateLayout->setSpacing(6); dateLayout->setContentsMargins(11, 11, 11, 11); anyDateEnabled = new QRadioButton(dateGroup); anyDateEnabled->setText(i18n("Any date")); btnGroup->addButton(anyDateEnabled); anyDateEnabled->setChecked(true); modifiedBetweenEnabled = new QRadioButton(dateGroup); modifiedBetweenEnabled->setText(i18n("&Modified between")); btnGroup->addButton(modifiedBetweenEnabled); modifiedBetweenData1 = new KLineEdit(dateGroup); modifiedBetweenData1->setEnabled(false); modifiedBetweenData1->setText(""); modifiedBetweenBtn1 = new QToolButton(dateGroup); modifiedBetweenBtn1->setEnabled(false); modifiedBetweenBtn1->setText(""); modifiedBetweenBtn1->setIcon(QIcon(iconDate)); QLabel *andLabel = new QLabel(dateGroup); andLabel->setText(i18n("an&d")); modifiedBetweenData2 = new KLineEdit(dateGroup); modifiedBetweenData2->setEnabled(false); modifiedBetweenData2->setText(""); andLabel->setBuddy(modifiedBetweenData2); modifiedBetweenBtn2 = new QToolButton(dateGroup); modifiedBetweenBtn2->setEnabled(false); modifiedBetweenBtn2->setText(""); modifiedBetweenBtn2->setIcon(QIcon(iconDate)); notModifiedAfterEnabled = new QRadioButton(dateGroup); notModifiedAfterEnabled->setText(i18n("&Not modified after")); btnGroup->addButton(notModifiedAfterEnabled); notModifiedAfterData = new KLineEdit(dateGroup); notModifiedAfterData->setEnabled(false); notModifiedAfterData->setText(""); notModifiedAfterBtn = new QToolButton(dateGroup); notModifiedAfterBtn->setEnabled(false); notModifiedAfterBtn->setText(""); notModifiedAfterBtn->setIcon(QIcon(iconDate)); modifiedInTheLastEnabled = new QRadioButton(dateGroup); modifiedInTheLastEnabled->setText(i18n("Mod&ified in the last")); btnGroup->addButton(modifiedInTheLastEnabled); modifiedInTheLastData = new QSpinBox(dateGroup); modifiedInTheLastData->setRange(0, 99999); modifiedInTheLastData->setEnabled(false); modifiedInTheLastType = new KComboBox(dateGroup); modifiedInTheLastType->addItem(i18n("days")); modifiedInTheLastType->addItem(i18n("weeks")); modifiedInTheLastType->addItem(i18n("months")); modifiedInTheLastType->addItem(i18n("years")); modifiedInTheLastType->setEnabled(false); notModifiedInTheLastData = new QSpinBox(dateGroup); notModifiedInTheLastData->setRange(0, 99999); notModifiedInTheLastData->setEnabled(false); QLabel *notModifiedInTheLastLbl = new QLabel(dateGroup); notModifiedInTheLastLbl->setText(i18n("No&t modified in the last")); notModifiedInTheLastLbl->setBuddy(notModifiedInTheLastData); notModifiedInTheLastType = new KComboBox(dateGroup); notModifiedInTheLastType->addItem(i18n("days")); notModifiedInTheLastType->addItem(i18n("weeks")); notModifiedInTheLastType->addItem(i18n("months")); notModifiedInTheLastType->addItem(i18n("years")); notModifiedInTheLastType->setEnabled(false); // Date options layout dateLayout->addWidget(anyDateEnabled, 0, 0); dateLayout->addWidget(modifiedBetweenEnabled, 1, 0); dateLayout->addWidget(modifiedBetweenData1, 1, 1); dateLayout->addWidget(modifiedBetweenBtn1, 1, 2); dateLayout->addWidget(andLabel, 1, 3); dateLayout->addWidget(modifiedBetweenData2, 1, 4); dateLayout->addWidget(modifiedBetweenBtn2, 1, 5); dateLayout->addWidget(notModifiedAfterEnabled, 2, 0); dateLayout->addWidget(notModifiedAfterData, 2, 1); dateLayout->addWidget(notModifiedAfterBtn, 2, 2); dateLayout->addWidget(modifiedInTheLastEnabled, 3, 0); QHBoxLayout *modifiedInTheLastLayout = new QHBoxLayout(); modifiedInTheLastLayout->addWidget(modifiedInTheLastData); modifiedInTheLastLayout->addWidget(modifiedInTheLastType); dateLayout->addLayout(modifiedInTheLastLayout, 3, 1); dateLayout->addWidget(notModifiedInTheLastLbl, 4, 0); modifiedInTheLastLayout = new QHBoxLayout(); modifiedInTheLastLayout->addWidget(notModifiedInTheLastData); modifiedInTheLastLayout->addWidget(notModifiedInTheLastType); dateLayout->addLayout(modifiedInTheLastLayout, 4, 1); filterLayout->addWidget(dateGroup, 1, 0); // Options for ownership QGroupBox *ownershipGroup = new QGroupBox(this); ownershipGroup->setTitle(i18n("Ownership")); QGridLayout *ownershipLayout = new QGridLayout(ownershipGroup); ownershipLayout->setAlignment(Qt::AlignTop); ownershipLayout->setSpacing(6); ownershipLayout->setContentsMargins(11, 11, 11, 11); QHBoxLayout *hboxLayout = new QHBoxLayout(); hboxLayout->setSpacing(6); hboxLayout->setContentsMargins(0, 0, 0, 0); belongsToUserEnabled = new QCheckBox(ownershipGroup); belongsToUserEnabled->setText(i18n("Belongs to &user")); hboxLayout->addWidget(belongsToUserEnabled); belongsToUserData = new KComboBox(ownershipGroup); belongsToUserData->setEnabled(false); belongsToUserData->setEditable(false); hboxLayout->addWidget(belongsToUserData); belongsToGroupEnabled = new QCheckBox(ownershipGroup); belongsToGroupEnabled->setText(i18n("Belongs to gr&oup")); hboxLayout->addWidget(belongsToGroupEnabled); belongsToGroupData = new KComboBox(ownershipGroup); belongsToGroupData->setEnabled(false); belongsToGroupData->setEditable(false); hboxLayout->addWidget(belongsToGroupData); ownershipLayout->addLayout(hboxLayout, 0, 0, 1, 4); permissionsEnabled = new QCheckBox(ownershipGroup); permissionsEnabled->setText(i18n("P&ermissions")); ownershipLayout->addWidget(permissionsEnabled, 1, 0); QGroupBox *ownerGroup = new QGroupBox(ownershipGroup); QHBoxLayout *ownerHBox = new QHBoxLayout(ownerGroup); ownerGroup->setTitle(i18n("O&wner")); ownerR = new KComboBox(ownerGroup); ownerR->addItem(i18n("?")); ownerR->addItem(i18n("r")); ownerR->addItem(i18n("-")); ownerR->setEnabled(false); ownerHBox->addWidget(ownerR); ownerW = new KComboBox(ownerGroup); ownerW->addItem(i18n("?")); ownerW->addItem(i18n("w")); ownerW->addItem(i18n("-")); ownerW->setEnabled(false); ownerHBox->addWidget(ownerW); ownerX = new KComboBox(ownerGroup); ownerX->addItem(i18n("?")); ownerX->addItem(i18n("x")); ownerX->addItem(i18n("-")); ownerX->setEnabled(false); ownerHBox->addWidget(ownerX); ownershipLayout->addWidget(ownerGroup, 1, 1); QGroupBox *groupGroup = new QGroupBox(ownershipGroup); QHBoxLayout *groupHBox = new QHBoxLayout(groupGroup); groupGroup->setTitle(i18n("Grou&p")); groupR = new KComboBox(groupGroup); groupR->addItem(i18n("?")); groupR->addItem(i18n("r")); groupR->addItem(i18n("-")); groupR->setEnabled(false); groupHBox->addWidget(groupR); groupW = new KComboBox(groupGroup); groupW->addItem(i18n("?")); groupW->addItem(i18n("w")); groupW->addItem(i18n("-")); groupW->setEnabled(false); groupHBox->addWidget(groupW); groupX = new KComboBox(groupGroup); groupX->addItem(i18n("?")); groupX->addItem(i18n("x")); groupX->addItem(i18n("-")); groupX->setEnabled(false); groupHBox->addWidget(groupX); ownershipLayout->addWidget(groupGroup, 1, 2); QGroupBox *allGroup = new QGroupBox(ownershipGroup); QHBoxLayout *allHBox = new QHBoxLayout(allGroup); allGroup->setTitle(i18n("A&ll")); allR = new KComboBox(allGroup); allR->addItem(i18n("?")); allR->addItem(i18n("r")); allR->addItem(i18n("-")); allR->setEnabled(false); allHBox->addWidget(allR); allW = new KComboBox(allGroup); allW->addItem(i18n("?")); allW->addItem(i18n("w")); allW->addItem(i18n("-")); allW->setEnabled(false); allHBox->addWidget(allW); allX = new KComboBox(allGroup); allX->addItem(i18n("?")); allX->addItem(i18n("x")); allX->addItem(i18n("-")); allX->setEnabled(false); allHBox->addWidget(allX); ownershipLayout->addWidget(allGroup, 1, 3); QLabel *infoLabel = new QLabel(ownershipGroup); QFont infoLabel_font(infoLabel->font()); infoLabel_font.setFamily("adobe-helvetica"); infoLabel_font.setItalic(true); infoLabel->setFont(infoLabel_font); infoLabel->setText(i18n("Note: a '?' is a wildcard")); ownershipLayout->addWidget(infoLabel, 2, 0, 1, 4, Qt::AlignRight); filterLayout->addWidget(ownershipGroup, 2, 0); // Connection table connect(minSizeEnabled, SIGNAL(toggled(bool)), minSizeAmount, SLOT(setEnabled(bool))); connect(minSizeEnabled, SIGNAL(toggled(bool)), minSizeType, SLOT(setEnabled(bool))); connect(maxSizeEnabled, SIGNAL(toggled(bool)), maxSizeAmount, SLOT(setEnabled(bool))); connect(maxSizeEnabled, SIGNAL(toggled(bool)), maxSizeType, SLOT(setEnabled(bool))); connect(modifiedBetweenEnabled, SIGNAL(toggled(bool)), modifiedBetweenData1, SLOT(setEnabled(bool))); connect(modifiedBetweenEnabled, SIGNAL(toggled(bool)), modifiedBetweenBtn1, SLOT(setEnabled(bool))); connect(modifiedBetweenEnabled, SIGNAL(toggled(bool)), modifiedBetweenData2, SLOT(setEnabled(bool))); connect(modifiedBetweenEnabled, SIGNAL(toggled(bool)), modifiedBetweenBtn2, SLOT(setEnabled(bool))); connect(notModifiedAfterEnabled, SIGNAL(toggled(bool)), notModifiedAfterData, SLOT(setEnabled(bool))); connect(notModifiedAfterEnabled, SIGNAL(toggled(bool)), notModifiedAfterBtn, SLOT(setEnabled(bool))); connect(modifiedInTheLastEnabled, SIGNAL(toggled(bool)), modifiedInTheLastData, SLOT(setEnabled(bool))); connect(modifiedInTheLastEnabled, SIGNAL(toggled(bool)), modifiedInTheLastType, SLOT(setEnabled(bool))); connect(modifiedInTheLastEnabled, SIGNAL(toggled(bool)), notModifiedInTheLastData, SLOT(setEnabled(bool))); connect(modifiedInTheLastEnabled, SIGNAL(toggled(bool)), notModifiedInTheLastType, SLOT(setEnabled(bool))); connect(belongsToUserEnabled, SIGNAL(toggled(bool)), belongsToUserData, SLOT(setEnabled(bool))); connect(belongsToGroupEnabled, SIGNAL(toggled(bool)), belongsToGroupData, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), ownerR, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), ownerW, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), ownerX, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), groupR, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), groupW, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), groupX, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), allR, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), allW, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), allX, SLOT(setEnabled(bool))); connect(modifiedBetweenBtn1, SIGNAL(clicked()), this, SLOT(modifiedBetweenSetDate1())); connect(modifiedBetweenBtn2, SIGNAL(clicked()), this, SLOT(modifiedBetweenSetDate2())); connect(notModifiedAfterBtn, SIGNAL(clicked()), this, SLOT(notModifiedAfterSetDate())); // fill the users and groups list fillList(belongsToUserData, USERSFILE); fillList(belongsToGroupData, GROUPSFILE); // tab order setTabOrder(minSizeEnabled, minSizeAmount); setTabOrder(minSizeAmount, maxSizeEnabled); setTabOrder(maxSizeEnabled, maxSizeAmount); setTabOrder(maxSizeAmount, modifiedBetweenEnabled); setTabOrder(modifiedBetweenEnabled, modifiedBetweenData1); setTabOrder(modifiedBetweenData1, modifiedBetweenData2); setTabOrder(modifiedBetweenData2, notModifiedAfterEnabled); setTabOrder(notModifiedAfterEnabled, notModifiedAfterData); setTabOrder(notModifiedAfterData, modifiedInTheLastEnabled); setTabOrder(modifiedInTheLastEnabled, modifiedInTheLastData); setTabOrder(modifiedInTheLastData, notModifiedInTheLastData); setTabOrder(notModifiedInTheLastData, belongsToUserEnabled); setTabOrder(belongsToUserEnabled, belongsToUserData); setTabOrder(belongsToUserData, belongsToGroupEnabled); setTabOrder(belongsToGroupEnabled, belongsToGroupData); setTabOrder(belongsToGroupData, permissionsEnabled); setTabOrder(permissionsEnabled, ownerR); setTabOrder(ownerR, ownerW); setTabOrder(ownerW, ownerX); setTabOrder(ownerX, groupR); setTabOrder(groupR, groupW); setTabOrder(groupW, groupX); setTabOrder(groupX, allR); setTabOrder(allR, allW); setTabOrder(allW, allX); setTabOrder(allX, minSizeType); setTabOrder(minSizeType, maxSizeType); setTabOrder(maxSizeType, modifiedInTheLastType); setTabOrder(modifiedInTheLastType, notModifiedInTheLastType); } void AdvancedFilter::modifiedBetweenSetDate1() { changeDate(modifiedBetweenData1); } void AdvancedFilter::modifiedBetweenSetDate2() { changeDate(modifiedBetweenData2); } void AdvancedFilter::notModifiedAfterSetDate() { changeDate(notModifiedAfterData); } void AdvancedFilter::changeDate(KLineEdit *p) { // check if the current date is valid QDate d = stringToDate(p->text()); if (!d.isValid()) d = QDate::currentDate(); KRGetDate *gd = new KRGetDate(d, this); d = gd->getDate(); // if a user pressed ESC or closed the dialog, we'll return an invalid date if (d.isValid()) p->setText(dateToString(d)); delete gd; } void AdvancedFilter::fillList(KComboBox *list, QString filename) { QFile data(filename); if (!data.open(QIODevice::ReadOnly)) { qWarning() << "Search: Unable to read " << filename << " !!!"; return; } // and read it into the temporary array QTextStream t(&data); while (!t.atEnd()) { QString s = t.readLine(); QString name = s.left(s.indexOf(':')); if (!name.startsWith('#')) list->addItem(name); } } void AdvancedFilter::invalidDateMessage(KLineEdit *p) { // FIXME p->text() is empty sometimes (to reproduce, set date to "13.09.005") KMessageBox::detailedError(this, i18n("Invalid date entered."), i18n("The date %1 is not valid according to your locale. Please re-enter a valid date (use the date button for easy access).", p->text())); p->setFocus(); } bool AdvancedFilter::getSettings(FilterSettings &s) { s.minSizeEnabled = minSizeEnabled->isChecked(); s.minSize.amount = minSizeAmount->value(); s.minSize.unit = static_cast(minSizeType->currentIndex()); s.maxSizeEnabled = maxSizeEnabled->isChecked(); s.maxSize.amount = maxSizeAmount->value(); s.maxSize.unit = static_cast(maxSizeType->currentIndex()); if (s.minSizeEnabled && s.maxSizeEnabled && (s.maxSize.size() < s.minSize.size())) { KMessageBox::detailedError(this, i18n("Specified sizes are inconsistent."), i18n("Please re-enter the values, so that the left side size " "will be smaller than (or equal to) the right side size.")); minSizeAmount->setFocus(); return false; } s.modifiedBetweenEnabled = modifiedBetweenEnabled->isChecked(); s.modifiedBetween1 = stringToDate(modifiedBetweenData1->text()); s.modifiedBetween2 = stringToDate(modifiedBetweenData2->text()); if (s.modifiedBetweenEnabled) { // check if date is valid if (!s.modifiedBetween1.isValid()) { invalidDateMessage(modifiedBetweenData1); return false; } else if (!s.modifiedBetween2.isValid()) { invalidDateMessage(modifiedBetweenData2); return false; } else if (s.modifiedBetween1 > s.modifiedBetween2) { KMessageBox::detailedError(this, i18n("Dates are inconsistent."), i18n("The date on the left is later than the date on the right. " "Please re-enter the dates, so that the left side date " "will be earlier than the right side date.")); modifiedBetweenData1->setFocus(); return false; } } s.notModifiedAfterEnabled = notModifiedAfterEnabled->isChecked(); s.notModifiedAfter = stringToDate(notModifiedAfterData->text()); if(s.notModifiedAfterEnabled && !s.notModifiedAfter.isValid()) { invalidDateMessage(notModifiedAfterData); return false; } s.modifiedInTheLastEnabled = modifiedInTheLastEnabled->isChecked(); s.modifiedInTheLast.amount = modifiedInTheLastData->value(); s.modifiedInTheLast.unit = static_cast(modifiedInTheLastType->currentIndex()); s.notModifiedInTheLast.amount = notModifiedInTheLastData->value(); s.notModifiedInTheLast.unit = static_cast(notModifiedInTheLastType->currentIndex()); if (s.modifiedInTheLastEnabled && s.modifiedInTheLast.amount && s.notModifiedInTheLast.amount) { if (s.modifiedInTheLast.days() < s.notModifiedInTheLast.days()) { KMessageBox::detailedError(this, i18n("Dates are inconsistent."), i18n("The date on top is later than the date on the bottom. " "Please re-enter the dates, so that the top date " "will be earlier than the bottom date.")); modifiedInTheLastData->setFocus(); return false; } } s.ownerEnabled = belongsToUserEnabled->isChecked(); s.owner = belongsToUserData->currentText(); s.groupEnabled = belongsToGroupEnabled->isChecked(); s.group = belongsToGroupData->currentText(); s.permissionsEnabled = permissionsEnabled->isChecked(); s.permissions = ownerR->currentText() + ownerW->currentText() + ownerX->currentText() + groupR->currentText() + groupW->currentText() + groupX->currentText() + allR->currentText() + allW->currentText() + allX->currentText(); return true; } void AdvancedFilter::applySettings(const FilterSettings &s) { minSizeEnabled->setChecked(s.minSizeEnabled); minSizeAmount->setValue(s.minSize.amount); minSizeType->setCurrentIndex(s.minSize.unit); maxSizeEnabled->setChecked(s.maxSizeEnabled); maxSizeAmount->setValue(s.maxSize.amount); maxSizeType->setCurrentIndex(s.maxSize.unit); if (s.modifiedBetweenEnabled) modifiedBetweenEnabled->setChecked(true); else if (s.notModifiedAfterEnabled) notModifiedAfterEnabled->setChecked(true); else if (s.modifiedInTheLastEnabled) modifiedInTheLastEnabled->setChecked(true); else anyDateEnabled->setChecked(true); modifiedBetweenData1->setText(dateToString(s.modifiedBetween1)); modifiedBetweenData2->setText(dateToString(s.modifiedBetween2)); notModifiedAfterData->setText(dateToString(s.notModifiedAfter)); modifiedInTheLastData->setValue(s.modifiedInTheLast.amount); modifiedInTheLastType->setCurrentIndex(s.modifiedInTheLast.unit); notModifiedInTheLastData->setValue(s.notModifiedInTheLast.amount); notModifiedInTheLastType->setCurrentIndex(s.notModifiedInTheLast.unit); belongsToUserEnabled->setChecked(s.ownerEnabled); setComboBoxValue(belongsToUserData, s.owner); belongsToGroupEnabled->setChecked(s.groupEnabled); setComboBoxValue(belongsToGroupData, s.group); permissionsEnabled->setChecked(s.permissionsEnabled); QString perm = s.permissions; if (perm.length() != 9) perm = "?????????"; setComboBoxValue(ownerR, QString(perm[0])); setComboBoxValue(ownerW, QString(perm[1])); setComboBoxValue(ownerX, QString(perm[2])); setComboBoxValue(groupR, QString(perm[3])); setComboBoxValue(groupW, QString(perm[4])); setComboBoxValue(groupX, QString(perm[5])); setComboBoxValue(allR, QString(perm[6])); setComboBoxValue(allW, QString(perm[7])); setComboBoxValue(allX, QString(perm[8])); } diff --git a/krusader/Filter/filtersettings.cpp b/krusader/Filter/filtersettings.cpp index 8bb6bfa4..2761c98c 100644 --- a/krusader/Filter/filtersettings.cpp +++ b/krusader/Filter/filtersettings.cpp @@ -1,332 +1,333 @@ /*************************************************************************** filtersettings.cpp - description ------------------- copyright : (C) 2003 + by Shie Erlich & Rafi Yanai & Csaba Karai (C) 2011 + by Jan Lepper e-mail : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD S o u r c e F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "filtersettings.h" -#include "../krglobal.h" #include "../krservices.h" +#include + #include FilterSettings::FileSize& FilterSettings::FileSize::operator=(const FileSize &other) { amount = other.amount; unit = other.unit; return *this; } KIO::filesize_t FilterSettings::FileSize::size() const { switch (unit) { case Byte: return amount; case KiloByte: return amount * 1024; case MegaByte: return amount * 1024 * 1024; case GigaByte: return amount * 1024 * 1024 * 1024; default: qWarning() << "invalid size unit: " << unit; return amount; } } FilterSettings::TimeSpan& FilterSettings::TimeSpan::operator=(const TimeSpan &other) { amount = other.amount; unit = other.unit; return *this; } int FilterSettings::TimeSpan::days() const { switch (unit) { case Day: return amount; case Week: return amount * 7; case Month: return amount * 30; case Year: return amount * 365; default: qWarning() << "invalid time unit: " << unit; return amount; } } FilterSettings::FilterSettings() : valid(false), searchFor("*"), searchForCase(false), searchInArchives(false), recursive(false), followLinks(false), containsTextCase(false), containsWholeWord(false), containsRegExp(false), minSizeEnabled(false), maxSizeEnabled(false), modifiedBetweenEnabled(false), notModifiedAfterEnabled(false), modifiedInTheLastEnabled(false), ownerEnabled(false), groupEnabled(false), permissionsEnabled(false) { } FilterSettings& FilterSettings::operator=(const FilterSettings& other) { #define COPY(var) { var = other.var; } COPY(valid); COPY(searchFor); COPY(searchForCase); COPY(mimeType); COPY(searchInArchives); COPY(recursive); COPY(followLinks); COPY(searchIn); COPY(dontSearchIn); COPY(contentEncoding); COPY(containsText); COPY(containsTextCase); COPY(containsWholeWord); COPY(containsRegExp); COPY(minSizeEnabled); COPY(minSize); COPY(maxSizeEnabled); COPY(maxSize); COPY(modifiedBetweenEnabled); COPY(modifiedBetween1); COPY(modifiedBetween2); COPY(notModifiedAfterEnabled); COPY(notModifiedAfter); COPY(modifiedInTheLastEnabled); COPY(modifiedInTheLast); COPY(notModifiedInTheLast); COPY(ownerEnabled); COPY(owner); COPY(groupEnabled); COPY(group); COPY(permissionsEnabled); COPY(permissions); #undef COPY return *this; } void FilterSettings::load(KConfigGroup cfg) { *this = FilterSettings(); #define LOAD(key, var) { var = cfg.readEntry(key, var); } LOAD("IsValid", valid); if(!isValid()) return; LOAD("SearchFor", searchFor); LOAD("MimeType", mimeType); LOAD("SearchInArchives", searchInArchives); LOAD("Recursive", recursive); LOAD("FollowLinks", followLinks); searchIn = KrServices::toUrlList(cfg.readEntry("SearchIn", QStringList())); dontSearchIn = KrServices::toUrlList(cfg.readEntry("DontSearchIn", QStringList())); LOAD("ContentEncoding", contentEncoding); LOAD("ContainsText", containsText); LOAD("ContainsTextCase", containsTextCase); LOAD("ContainsWholeWord", containsWholeWord); LOAD("ContainsRegExp", containsRegExp); LOAD("MinSizeEnabled", minSizeEnabled); LOAD("MinSizeAmount", minSize.amount); minSize.unit = static_cast(cfg.readEntry("MinSizeUnit", 0)); LOAD("MaxSizeEnabled", maxSizeEnabled); LOAD("MaxSizeAmount", maxSize.amount); maxSize.unit = static_cast(cfg.readEntry("MaxSizeUnit", 0)); LOAD("ModifiedBetweenEnabled", modifiedBetweenEnabled); LOAD("ModifiedBetween1", modifiedBetween1); LOAD("ModifiedBetween2", modifiedBetween2); LOAD("NotModifiedAfterEnabled", notModifiedAfterEnabled); LOAD("NotModifiedAfter", notModifiedAfter); LOAD("ModifiedInTheLastEnabled", modifiedInTheLastEnabled); LOAD("ModifiedInTheLastAmount", modifiedInTheLast.amount); modifiedInTheLast.unit = static_cast(cfg.readEntry("ModifiedInTheLastUnit", 0)); LOAD("NotModifiedInTheLastAmount", notModifiedInTheLast.amount); notModifiedInTheLast.unit = static_cast(cfg.readEntry("NotModifiedInTheLastUnit", 0)); LOAD("OwnerEnabled", ownerEnabled); LOAD("Owner", owner); LOAD("GroupEnabled", groupEnabled); LOAD("Group", group); LOAD("PermissionsEnabled", permissionsEnabled); LOAD("Permissions", permissions); #undef LOAD } void FilterSettings::saveDate(QString key, const QDate &date, KConfigGroup &cfg) { if(date.isValid()) cfg.writeEntry(key, date); else cfg.deleteEntry(key); } void FilterSettings::save(KConfigGroup cfg) const { cfg.writeEntry("IsValid", valid); if(!isValid()) return; cfg.writeEntry("SearchFor", searchFor); cfg.writeEntry("MimeType", mimeType); cfg.writeEntry("SearchInArchives", searchInArchives); cfg.writeEntry("Recursive", recursive); cfg.writeEntry("FollowLinks", followLinks); cfg.writeEntry("SearchIn", KrServices::toStringList(searchIn)); cfg.writeEntry("DontSearchIn", KrServices::toStringList(dontSearchIn)); cfg.writeEntry("ContentEncoding", contentEncoding); cfg.writeEntry("ContainsText", containsText); cfg.writeEntry("ContainsTextCase", containsTextCase); cfg.writeEntry("ContainsWholeWord", containsWholeWord); cfg.writeEntry("ContainsRegExp", containsRegExp); cfg.writeEntry("MinSizeEnabled", minSizeEnabled); cfg.writeEntry("MinSizeAmount", minSize.amount); cfg.writeEntry("MinSizeUnit", static_cast(minSize.unit)); cfg.writeEntry("MaxSizeEnabled", maxSizeEnabled); cfg.writeEntry("MaxSizeAmount", maxSize.amount); cfg.writeEntry("MaxSizeUnit", static_cast(maxSize.unit)); cfg.writeEntry("ModifiedBetweenEnabled", modifiedBetweenEnabled); saveDate("ModifiedBetween1", modifiedBetween1, cfg); saveDate("ModifiedBetween2", modifiedBetween2, cfg); cfg.writeEntry("NotModifiedAfterEnabled", notModifiedAfterEnabled); saveDate("NotModifiedAfter", notModifiedAfter, cfg); cfg.writeEntry("ModifiedInTheLastEnabled", modifiedInTheLastEnabled); cfg.writeEntry("ModifiedInTheLastAmount", modifiedInTheLast.amount); cfg.writeEntry("ModifiedInTheLastUnit", static_cast(modifiedInTheLast.unit)); cfg.writeEntry("NotModifiedInTheLastAmount", notModifiedInTheLast.amount); cfg.writeEntry("NotModifiedInTheLastUnit", static_cast(notModifiedInTheLast.unit)); cfg.writeEntry("OwnerEnabled", ownerEnabled); cfg.writeEntry("Owner", owner); cfg.writeEntry("GroupEnabled", groupEnabled); cfg.writeEntry("Group", group); cfg.writeEntry("PermissionsEnabled", permissionsEnabled); cfg.writeEntry("Permissions", permissions); } // bool start: set it to true if this date is the beginning of the search, // if it's the end, set it to false time_t FilterSettings::qdate2time_t (QDate d, bool start) { struct tm t; t.tm_sec = (start ? 0 : 59); t.tm_min = (start ? 0 : 59); t.tm_hour = (start ? 0 : 23); t.tm_mday = d.day(); t.tm_mon = d.month() - 1; t.tm_year = d.year() - 1900; t.tm_wday = d.dayOfWeek() - 1; // actually ignored by mktime t.tm_yday = d.dayOfYear() - 1; // actually ignored by mktime t.tm_isdst = -1; // daylight saving time information isn't available return mktime(&t); } KRQuery FilterSettings::toQuery() const { if(!isValid()) return KRQuery(); KRQuery query; ////////////// General Options ////////////// query.setNameFilter(searchFor, searchForCase); query.setMimeType(mimeType); QString charset; if (!contentEncoding.isEmpty()) charset = KCharsets::charsets()->encodingForName(contentEncoding); if (!containsText.isEmpty()) { query.setContent(containsText, containsTextCase, containsWholeWord, charset, containsRegExp); } query.setRecursive(recursive); query.setSearchInArchives(searchInArchives); query.setFollowLinks(followLinks); if (!searchIn.isEmpty()) query.setSearchInDirs(searchIn); if (!dontSearchIn.isEmpty()) query.setDontSearchInDirs(dontSearchIn); ////////////// Advanced Options ////////////// if (minSizeEnabled) query.setMinimumFileSize(minSize.size()); if (maxSizeEnabled) query.setMaximumFileSize(maxSize.size()); if (modifiedBetweenEnabled) { if(modifiedBetween1.isValid()) query.setNewerThan(qdate2time_t(modifiedBetween1, true)); if(modifiedBetween2.isValid()) query.setOlderThan(qdate2time_t(modifiedBetween2, false)); } else if (notModifiedAfterEnabled && notModifiedAfter.isValid()) { query.setOlderThan(qdate2time_t(notModifiedAfter, false)); } else if (modifiedInTheLastEnabled) { if (modifiedInTheLast.amount) { QDate d = QDate::currentDate().addDays((-1) * modifiedInTheLast.days()); query.setNewerThan(qdate2time_t(d, true)); } if (notModifiedInTheLast.amount) { QDate d = QDate::currentDate().addDays((-1) * notModifiedInTheLast.days()); query.setOlderThan(qdate2time_t(d, true)); } } if (ownerEnabled && !owner.isEmpty()) query.setOwner(owner); if (groupEnabled && !group.isEmpty()) query.setGroup(group); if (permissionsEnabled && !permissions.isEmpty()) query.setPermissions(permissions); return query; } diff --git a/krusader/JobMan/jobman.cpp b/krusader/JobMan/jobman.cpp index 0322c865..28d66655 100644 --- a/krusader/JobMan/jobman.cpp +++ b/krusader/JobMan/jobman.cpp @@ -1,456 +1,457 @@ /***************************************************************************** * Copyright (C) 2016 Krusader Krew * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This package is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this package; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ #include "jobman.h" // QtCore +#include #include // QtWidgets #include #include #include #include #include #include #include #include #include #include "krjob.h" #include "../krglobal.h" const int MAX_OLD_MENU_ACTIONS = 10; /** The menu action entry for a job in the popup menu.*/ class JobMenuAction : public QWidgetAction { Q_OBJECT public: JobMenuAction(KrJob *krJob, QObject *parent, KJob *kJob = nullptr) : QWidgetAction(parent), m_krJob(krJob) { QWidget *container = new QWidget(); QGridLayout *layout = new QGridLayout(container); m_description = new QLabel(krJob->description()); m_progressBar = new QProgressBar(); layout->addWidget(m_description, 0, 0, 1, 3); layout->addWidget(m_progressBar, 1, 0); m_pauseResumeButton = new QPushButton(); updatePauseResumeButton(); connect(m_pauseResumeButton, &QPushButton::clicked, this, &JobMenuAction::slotPauseResumeButtonClicked); layout->addWidget(m_pauseResumeButton, 1, 1); m_cancelButton = new QPushButton(); m_cancelButton->setIcon(QIcon::fromTheme("remove")); m_cancelButton->setToolTip(i18n("Cancel Job")); connect(m_cancelButton, &QPushButton::clicked, this, &JobMenuAction::slotCancelButtonClicked); layout->addWidget(m_cancelButton, 1, 2); setDefaultWidget(container); if (kJob) { slotStarted(kJob); } else { connect(krJob, &KrJob::started, this, &JobMenuAction::slotStarted); } connect(krJob, &KrJob::terminated, this, &JobMenuAction::slotTerminated); } bool isDone() { return !m_krJob; } protected slots: void slotDescription(KJob *, const QString &description, const QPair &field1, const QPair &field2) { const QPair textField = !field2.first.isEmpty() ? field2 : field1; QString text = description; if (!textField.first.isEmpty()) { text += QString(" - %1: %2").arg(textField.first, textField.second); } m_description->setText(text); if (!field2.first.isEmpty() && !field1.first.isEmpty()) { // NOTE: tooltips for QAction items in menu are not shown m_progressBar->setToolTip(QString("%1: %2").arg(field1.first, field1.second)); } } void slotPercent(KJob *, unsigned long percent) { m_progressBar->setValue(percent); } void updatePauseResumeButton() { m_pauseResumeButton->setIcon(QIcon::fromTheme( m_krJob->isRunning() ? "media-playback-pause" : m_krJob->isPaused() ? "media-playback-start" : "chronometer-start")); m_pauseResumeButton->setToolTip(m_krJob->isRunning() ? i18n("Pause Job") : m_krJob->isPaused() ? i18n("Resume Job") : i18n("Start Job")); } void slotResult(KJob *job) { // NOTE: m_job may already set to NULL now if(!job->error()) { // percent signal is not reliable, set manually m_progressBar->setValue(100); } } void slotTerminated() { qDebug() << "job description=" << m_krJob->description(); m_pauseResumeButton->setEnabled(false); m_cancelButton->setIcon(QIcon::fromTheme("edit-clear")); m_cancelButton->setToolTip(i18n("Clear")); m_krJob = nullptr; } void slotPauseResumeButtonClicked() { if (!m_krJob) return; if (m_krJob->isRunning()) m_krJob->pause(); else m_krJob->start(); } void slotCancelButtonClicked() { if (m_krJob) { m_krJob->cancel(); } else { deleteLater(); } } private slots: void slotStarted(KJob *job) { connect(job, &KJob::description, this, &JobMenuAction::slotDescription); connect(job, SIGNAL(percent(KJob *, ulong)), this, SLOT(slotPercent(KJob *, ulong))); connect(job, &KJob::suspended, this, &JobMenuAction::updatePauseResumeButton); connect(job, &KJob::resumed, this, &JobMenuAction::updatePauseResumeButton); connect(job, &KJob::result, this, &JobMenuAction::slotResult); connect(job, &KJob::warning, this, [](KJob *, const QString &plain, const QString &) { qWarning() << "unexpected job warning: " << plain; }); updatePauseResumeButton(); } private: KrJob *m_krJob; QLabel *m_description; QProgressBar *m_progressBar; QPushButton *m_pauseResumeButton; QPushButton *m_cancelButton; }; #include "jobman.moc" // required for class definitions with Q_OBJECT macro in implementation files const QString JobMan::sDefaultToolTip = i18n("No jobs"); JobMan::JobMan(QObject *parent) : QObject(parent), m_messageBox(0) { // job control action m_controlAction = new KToolBarPopupAction(QIcon::fromTheme("media-playback-pause"), i18n("Play/Pause &Job"), this); m_controlAction->setEnabled(false); connect(m_controlAction, &QAction::triggered, this, &JobMan::slotControlActionTriggered); QMenu *menu = new QMenu(krMainWindow); menu->setMinimumWidth(300); // make scrollable if menu is too long menu->setStyleSheet("QMenu { menu-scrollable: 1; }"); m_controlAction->setMenu(menu); // progress bar action m_progressBar = new QProgressBar(); m_progressBar->setToolTip(sDefaultToolTip); m_progressBar->setEnabled(false); // listen to clicks on progress bar m_progressBar->installEventFilter(this); QWidgetAction *progressAction = new QWidgetAction(krMainWindow); progressAction->setText(i18n("Job Progress Bar")); progressAction->setDefaultWidget(m_progressBar); m_progressAction = progressAction; // job queue mode action KConfigGroup cfg(krConfig, "JobManager"); m_queueMode = cfg.readEntry("Queue Mode", false); m_modeAction = new QAction(QIcon::fromTheme("media-playlist-repeat"), i18n("Job Queue Mode"), krMainWindow); m_modeAction->setToolTip(i18n("Run only one job in parallel")); m_modeAction->setCheckable(true); m_modeAction->setChecked(m_queueMode); connect(m_modeAction, &QAction::toggled, this, [=](bool checked) mutable { m_queueMode = checked; cfg.writeEntry("Queue Mode", m_queueMode); }); // undo action KIO::FileUndoManager *undoManager = KIO::FileUndoManager::self(); undoManager->uiInterface()->setParentWidget(krMainWindow); m_undoAction = new QAction(QIcon::fromTheme("edit-undo"), i18n("Undo Last Job"), krMainWindow); m_undoAction->setEnabled(false); connect(m_undoAction, &QAction::triggered, undoManager, &KIO::FileUndoManager::undo); connect(undoManager, static_cast(&KIO::FileUndoManager::undoAvailable), m_undoAction, &QAction::setEnabled); connect(undoManager, &KIO::FileUndoManager::undoTextChanged, this, &JobMan::slotUndoTextChange); } bool JobMan::waitForJobs(bool waitForUserInput) { if (m_jobs.isEmpty() && !waitForUserInput) return true; // attempt to get all job threads does not work //QList threads = krMainWindow->findChildren(); m_autoCloseMessageBox = !waitForUserInput; m_messageBox = new QMessageBox(krMainWindow); m_messageBox->setWindowTitle(i18n("Warning")); m_messageBox->setIconPixmap(QIcon::fromTheme("dialog-warning") .pixmap(QMessageBox::standardIcon(QMessageBox::Information).size())); m_messageBox->setText(i18n("Are you sure you want to quit?")); m_messageBox->addButton(QMessageBox::Abort); m_messageBox->addButton(QMessageBox::Cancel); m_messageBox->setDefaultButton(QMessageBox::Cancel); for (KrJob *job: m_jobs) connect(job, &KrJob::terminated, this, &JobMan::slotUpdateMessageBox); slotUpdateMessageBox(); int result = m_messageBox->exec(); // blocking m_messageBox->deleteLater(); m_messageBox = 0; // accepted -> cancel all jobs if (result == QMessageBox::Abort) { for (KrJob *job: m_jobs) { job->cancel(); } return true; } // else: return false; } void JobMan::manageJob(KrJob *job, StartMode startMode) { qDebug() << "new job, startMode=" << startMode; managePrivate(job); connect(job, &KrJob::started, this, &JobMan::slotKJobStarted); const bool enqueue = startMode == Enqueue || (startMode == Default && m_queueMode); if (startMode == Start || (startMode == Default && !m_queueMode) || (enqueue && !jobsAreRunning())) { job->start(); } updateUI(); } void JobMan::manageStartedJob(KrJob *krJob, KJob *kJob) { managePrivate(krJob, kJob); slotKJobStarted(kJob); updateUI(); } // #### protected slots void JobMan::slotKJobStarted(KJob *job) { // KJob has two percent() functions connect(job, SIGNAL(percent(KJob*,ulong)), this, SLOT(slotPercent(KJob*,ulong))); connect(job, &KJob::description, this, &JobMan::slotDescription); connect(job, &KJob::suspended, this, &JobMan::updateUI); connect(job, &KJob::resumed, this, &JobMan::updateUI); } void JobMan::slotControlActionTriggered() { if (m_jobs.isEmpty()) { m_controlAction->menu()->clear(); m_controlAction->setEnabled(false); return; } const bool anyRunning = jobsAreRunning(); if (!anyRunning && m_queueMode) { m_jobs.first()->start(); } else { for (KrJob *job : m_jobs) { if (anyRunning) job->pause(); else job->start(); } } } void JobMan::slotPercent(KJob *, unsigned long) { updateUI(); } void JobMan::slotDescription(KJob*,const QString &description, const QPair &field1, const QPair &field2) { // TODO cache all descriptions if (m_jobs.length() > 1) return; m_progressBar->setToolTip( QString("%1\n%2: %3\n%4: %5") .arg(description, field1.first, field1.second, field2.first, field2.second)); } void JobMan::slotTerminated(KrJob *krJob) { qDebug() << "terminated, job description: " << krJob->description(); m_jobs.removeAll(krJob); // NOTE: ignoring queue mode here. We assume that if queue mode is turned off, the user created // jobs which were not already started with a "queue" option and still wants queue behaviour. if (!m_jobs.isEmpty() && !jobsAreRunning()) { foreach (KrJob *job, m_jobs) { if (!job->isPaused()) { // start next job job->start(); break; } } } updateUI(); cleanupMenu(); } void JobMan::slotUpdateControlAction() { m_controlAction->setEnabled(!m_controlAction->menu()->isEmpty()); } void JobMan::slotUndoTextChange(const QString &text) { m_undoAction->setToolTip(KIO::FileUndoManager::self()->undoAvailable() ? text : i18n("Undo Last Job")); } void JobMan::slotUpdateMessageBox() { if (!m_messageBox) return; if (m_jobs.isEmpty() && m_autoCloseMessageBox) { m_messageBox->done(QMessageBox::Abort); return; } if (m_jobs.isEmpty()) { m_messageBox->setInformativeText(""); m_messageBox->setButtonText(QMessageBox::Abort, "Quit"); return; } m_messageBox->setInformativeText(i18np("There is one job operation left.", "There are %1 job operations left.", m_jobs.length())); m_messageBox->setButtonText(QMessageBox::Abort, "Abort Jobs and Quit"); } // #### private void JobMan::managePrivate(KrJob *job, KJob *kJob) { JobMenuAction *menuAction = new JobMenuAction(job, m_controlAction, kJob); connect(menuAction, &QObject::destroyed, this, &JobMan::slotUpdateControlAction); m_controlAction->menu()->addAction(menuAction); cleanupMenu(); slotUpdateControlAction(); connect(job, &KrJob::terminated, this, &JobMan::slotTerminated); m_jobs.append(job); } void JobMan::cleanupMenu() { const QList actions = m_controlAction->menu()->actions(); for (QAction *action : actions) { if (m_controlAction->menu()->actions().count() <= MAX_OLD_MENU_ACTIONS) break; JobMenuAction *jobAction = static_cast(action); if (jobAction->isDone()) { m_controlAction->menu()->removeAction(action); action->deleteLater(); } } } void JobMan::updateUI() { int totalPercent = 0; for (KrJob *job: m_jobs) { totalPercent += job->percent(); } const bool hasJobs = !m_jobs.isEmpty(); m_progressBar->setEnabled(hasJobs); if (hasJobs) { m_progressBar->setValue(totalPercent / m_jobs.length()); } else { m_progressBar->reset(); } if (!hasJobs) m_progressBar->setToolTip(i18n("No Jobs")); if (m_jobs.length() > 1) m_progressBar->setToolTip(i18np("%1 Job", "%1 Jobs", m_jobs.length())); const bool running = jobsAreRunning(); m_controlAction->setIcon(QIcon::fromTheme( !hasJobs ? "edit-clear" : running ? "media-playback-pause" : "media-playback-start")); m_controlAction->setToolTip(!hasJobs ? i18n("Clear Job List") : running ? i18n("Pause All Jobs") : i18n("Resume Job List")); } bool JobMan::jobsAreRunning() { for (KrJob *job: m_jobs) if (job->isRunning()) return true; return false; } diff --git a/krusader/Panel/PanelView/krview.cpp b/krusader/Panel/PanelView/krview.cpp index cc6b52f4..0fba10c3 100644 --- a/krusader/Panel/PanelView/krview.cpp +++ b/krusader/Panel/PanelView/krview.cpp @@ -1,1212 +1,1213 @@ /*************************************************************************** krview.cpp ------------------- copyright : (C) 2000-2002 by Shie Erlich & Rafi Yanai e-mail : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD S o u r c e F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #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 "../kicons.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 else 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; } QRegExp rx(text, caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard); if (!direction) { if (rx.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 (item == startItem) { return false; } if (rx.indexIn(item->name()) == 0) { _view->setCurrentKrViewItem(item); _view->makeItemVisible(item); return true; } } } 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(krLoader->loadIcon(icon_name, KIconLoader::Desktop, 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() { if (getCurrentKrViewItem() == 0) return QString(); KrViewItem * iterator = getNext(getCurrentKrViewItem()); 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::delItem(const QString &name) { KrViewItem *it = findItemByName(name); if(!it) return; if(_previews) _previews->deletePreview(it); preDelItem(it); if (it->FILEITEM->isDir()) { --_numDirs; } --_count; delete it; op()->emitSelectionChanged(); } void KrView::addItem(FileItem *fileitem) { if (isFiltered(fileitem)) return; KrViewItem *item = preAddItem(fileitem); if (!item) return; // don't add it after all if(_previews) _previews->updatePreview(item); if (fileitem->isDir()) ++_numDirs; ++_count; if (item->name() == nameToMakeCurrent()) { setCurrentKrViewItem(item); // dictionary based - quick makeItemVisible(item); } 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 delItem(name); if (!isFiltered(newFileItem)) { addItem(newFileItem); if(_previews) _previews->updatePreview(findItemByFileItem(newFileItem)); } if (isCurrent) setCurrentItem(name); 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 op()->emitGoHome(); // ask krusader to move to the home directory } return true; case Qt::Key_Delete : // delete/trash the file (delete with alternative mode is a panel action) if (e->modifiers() == 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 op()->emitDirUp(); // ask krusader to move up a directory } 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) { /* Shift+Home */ 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; } // default continues here !!!!!!!!!!! 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() { QString currentItem = getCurrentItem(); QList selection = selectedUrls(); QModelIndex currentIndex = getCurrentIndex(); 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 (!nameToMakeCurrent().isEmpty()) { setCurrentItem(nameToMakeCurrent()); setNameToMakeCurrent(""); } else 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, 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/krcolorcache.cpp b/krusader/Panel/krcolorcache.cpp index e1921f21..4c32114f 100644 --- a/krusader/Panel/krcolorcache.cpp +++ b/krusader/Panel/krcolorcache.cpp @@ -1,758 +1,759 @@ /***************************************************************************** * Copyright (C) 2000-2002 Shie Erlich * * Copyright (C) 2000-2002 Rafi Yanai * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This package is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this package; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ #include "krcolorcache.h" #include "../krglobal.h" #include "../defaults.h" // QtCore +#include #include #include // QtGui #include // QtWidgets #include #include // Macro: set target = col, if col is valid #define SETCOLOR(target, col) { if (col.isValid()) target = col; } // Static class, which lists all allowed keywords for a quick access. // Just call a method to initialize it. class KrColorSettingNames { static QMap s_colorNames; static QMap s_numNames; static QMap s_boolNames; static void initialize(); public: static QStringList getColorNames(); static bool isColorNameValid(const QString & settingName); static QStringList getNumNames(); static bool isNumNameValid(const QString & settingName); static QStringList getBoolNames(); static bool isBoolNameValid(const QString & settingName); } krColorSettingNames; QMap KrColorSettingNames::s_colorNames; QMap KrColorSettingNames::s_numNames; QMap KrColorSettingNames::s_boolNames; void KrColorSettingNames::initialize() { if (!s_colorNames.empty()) return; s_colorNames["Foreground"] = true; s_colorNames["Inactive Foreground"] = true; s_colorNames["Directory Foreground"] = true; s_colorNames["Inactive Directory Foreground"] = true; s_colorNames["Executable Foreground"] = true; s_colorNames["Inactive Executable Foreground"] = true; s_colorNames["Symlink Foreground"] = true; s_colorNames["Inactive Symlink Foreground"] = true; s_colorNames["Invalid Symlink Foreground"] = true; s_colorNames["Inactive Invalid Symlink Foreground"] = true; s_colorNames["Marked Foreground"] = true; s_colorNames["Inactive Marked Foreground"] = true; s_colorNames["Marked Background"] = true; s_colorNames["Inactive Marked Background"] = true; s_colorNames["Current Foreground"] = true; s_colorNames["Inactive Current Foreground"] = true; s_colorNames["Current Background"] = true; s_colorNames["Inactive Current Background"] = true; s_colorNames["Marked Current Foreground"] = true; s_colorNames["Inactive Marked Current Foreground"] = true; s_colorNames["Alternate Background"] = true; s_colorNames["Inactive Alternate Background"] = true; s_colorNames["Background"] = true; s_colorNames["Inactive Background"] = true; s_colorNames["Alternate Marked Background"] = true; s_colorNames["Inactive Alternate Marked Background"] = true; s_colorNames["Dim Target Color"] = true; s_numNames["Dim Factor"] = true; s_boolNames["KDE Default"] = true; s_boolNames["Enable Alternate Background"] = true; s_boolNames["Show Current Item Always"] = true; s_boolNames["Dim Inactive Colors"] = true; } QStringList KrColorSettingNames::getColorNames() { initialize(); return s_colorNames.keys(); } bool KrColorSettingNames::isColorNameValid(const QString & settingName) { initialize(); return s_colorNames.contains(settingName); } QStringList KrColorSettingNames::getNumNames() { initialize(); return s_numNames.keys(); } bool KrColorSettingNames::isNumNameValid(const QString & settingName) { initialize(); return s_numNames.contains(settingName); } QStringList KrColorSettingNames::getBoolNames() { initialize(); return s_boolNames.keys(); } bool KrColorSettingNames::isBoolNameValid(const QString & settingName) { initialize(); return s_boolNames.contains(settingName); } /* KrColorSettings implementation. Contains all properties in QMaps. loadFromConfig initializes them from krConfig. */ class KrColorSettingsImpl { friend class KrColorSettings; QMap m_colorTextValues; QMap m_colorValues; QMap m_numValues; QMap m_boolValues; void loadFromConfig(); }; void KrColorSettingsImpl::loadFromConfig() { KConfigGroup group(krConfig, "Colors"); QStringList names = KrColorSettingNames::getColorNames(); for (QStringList::Iterator it = names.begin(); it != names.end(); ++it) { m_colorTextValues[*it] = group.readEntry(*it, QString()); if (m_colorTextValues[*it].count(',') == 2) m_colorValues[*it] = group.readEntry(*it, QColor()); else m_colorValues[*it] = QColor(); } names = KrColorSettingNames::getNumNames(); for (QStringList::Iterator it = names.begin(); it != names.end(); ++it) { if (!group.readEntry(*it, QString()).isEmpty()) { m_numValues[*it] = group.readEntry(*it, (long long)0); } } names = KrColorSettingNames::getBoolNames(); for (QStringList::Iterator it = names.begin(); it != names.end(); ++it) { if (!group.readEntry(*it, QString()).isEmpty()) { m_boolValues[*it] = group.readEntry(*it, false); } } } KrColorSettings::KrColorSettings() { m_impl = new KrColorSettingsImpl(); m_impl->loadFromConfig(); } KrColorSettings::KrColorSettings(const KrColorSettings & src) { m_impl = new KrColorSettingsImpl(); operator =(src); } KrColorSettings::~KrColorSettings() { delete m_impl; } const KrColorSettings & KrColorSettings::operator= (const KrColorSettings & src) { if (this == & src) return * this; QStringList names = KrColorSettingNames::getColorNames(); for (QStringList::Iterator it = names.begin(); it != names.end(); ++it) { m_impl->m_colorTextValues[*it] = src.m_impl->m_colorTextValues[*it]; m_impl->m_colorValues[*it] = src.m_impl->m_colorValues[*it]; } for (QMap::Iterator it = src.m_impl->m_numValues.begin(); it != src.m_impl->m_numValues.end(); ++it) { m_impl->m_numValues[it.key()] = it.value(); } for (QMap::Iterator it = src.m_impl->m_boolValues.begin(); it != src.m_impl->m_boolValues.end(); ++it) { m_impl->m_boolValues[it.key()] = it.value(); } return * this; } QList KrColorSettings::getColorNames() { return KrColorSettingNames::getColorNames(); } bool KrColorSettings::isColorNameValid(const QString & settingName) { return KrColorSettingNames::isColorNameValid(settingName); } bool KrColorSettings::setColorValue(const QString & settingName, const QColor & color) { if (!isColorNameValid(settingName)) { qWarning() << "Invalid color setting name: " << settingName; return false; } m_impl->m_colorValues[settingName] = color; return true; } QColor KrColorSettings::getColorValue(const QString & settingName) const { if (!isColorNameValid(settingName)) { qWarning() << "Invalid color setting name: " << settingName; return QColor(); } return m_impl->m_colorValues[settingName]; } bool KrColorSettings::setColorTextValue(const QString & settingName, const QString & colorText) { if (!isColorNameValid(settingName)) { qWarning() << "Invalid color setting name: " << settingName; return false; } m_impl->m_colorTextValues[settingName] = colorText; return true; } QString KrColorSettings::getColorTextValue(const QString & settingName) const { if (!isColorNameValid(settingName)) { qWarning() << "Invalid color setting name: " << settingName; return QString(); } return m_impl->m_colorTextValues[settingName]; } QList KrColorSettings::getNumNames() { return KrColorSettingNames::getNumNames(); } bool KrColorSettings::isNumNameValid(const QString & settingName) { return KrColorSettingNames::isNumNameValid(settingName); } bool KrColorSettings::setNumValue(const QString & settingName, int value) { if (!isNumNameValid(settingName)) { qWarning() << "Invalid number setting name: " << settingName; return false; } m_impl->m_numValues[settingName] = value; return true; } int KrColorSettings::getNumValue(const QString & settingName, int defaultValue) const { if (!isNumNameValid(settingName)) { qWarning() << "Invalid number setting name: " << settingName; return 0; } if (!m_impl->m_numValues.contains(settingName)) return defaultValue; return m_impl->m_numValues[settingName]; } QList KrColorSettings::getBoolNames() { return KrColorSettingNames::getBoolNames(); } bool KrColorSettings::isBoolNameValid(const QString & settingName) { return KrColorSettingNames::isBoolNameValid(settingName); } bool KrColorSettings::setBoolValue(const QString & settingName, bool value) { if (!isBoolNameValid(settingName)) { qWarning() << "Invalid bool setting name: " << settingName; return false; } m_impl->m_boolValues[settingName] = value; return true; } int KrColorSettings::getBoolValue(const QString & settingName, bool defaultValue) const { if (!isBoolNameValid(settingName)) { qWarning() << "Invalid bool setting name: " << settingName; return false; } if (!m_impl->m_boolValues.contains(settingName)) return defaultValue; return m_impl->m_boolValues[settingName]; } KrColorItemType::KrColorItemType() { m_fileType = File; m_alternateBackgroundColor = false; m_activePanel = false; m_currentItem = false; m_selectedItem = false; } KrColorItemType::KrColorItemType(FileType type, bool alternateBackgroundColor, bool activePanel, bool currentItem, bool selectedItem) { m_fileType = type; m_alternateBackgroundColor = alternateBackgroundColor; m_activePanel = activePanel; m_currentItem = currentItem; m_selectedItem = selectedItem; } KrColorItemType::KrColorItemType(const KrColorItemType & src) { operator= (src); } const KrColorItemType & KrColorItemType::operator= (const KrColorItemType & src) { if (this == & src) return * this; m_fileType = src.m_fileType; m_alternateBackgroundColor = src.m_alternateBackgroundColor; m_activePanel = src.m_activePanel; m_currentItem = src.m_currentItem; m_selectedItem = src.m_selectedItem; return * this; } /* KrColorCache implementation. Contains the KrColorSettings used for teh calculation and the cache for the results. getColors is the only method to call. All other are taken from the previous versions. */ class KrColorCacheImpl { friend class KrColorCache; QMap m_cachedColors; KrColorSettings m_colorSettings; KrColorGroup getColors(const KrColorItemType & type) const; static const QColor & setColorIfContrastIsSufficient(const QColor & background, const QColor & color1, const QColor & color2); QColor getForegroundColor(bool isActive) const; QColor getSpecialForegroundColor(const QString & type, bool isActive) const; QColor getBackgroundColor(bool isActive) const; QColor getAlternateBackgroundColor(bool isActive) const; QColor getMarkedForegroundColor(bool isActive) const; QColor getMarkedBackgroundColor(bool isActive) const; QColor getAlternateMarkedBackgroundColor(bool isActive) const; QColor getCurrentForegroundColor(bool isActive) const; QColor getCurrentBackgroundColor(bool isActive) const; QColor getCurrentMarkedForegroundColor(bool isActive) const; QColor dimColor(QColor color, bool isBackgroundColor) const; }; KrColorGroup KrColorCacheImpl::getColors(const KrColorItemType & type) const { KrColorGroup result; if (m_colorSettings.getBoolValue("KDE Default", _KDEDefaultColors)) { bool enableAlternateBackground = m_colorSettings.getBoolValue("Enable Alternate Background", _AlternateBackground); QPalette p = QGuiApplication::palette(); QColor background = enableAlternateBackground && type.m_alternateBackgroundColor ? p.color(QPalette::Active, QPalette::Base) : p.color(QPalette::Active, QPalette::AlternateBase); result.setBackground(background); result.setText(p.color(QPalette::Active, QPalette::Text)); result.setHighlight(p.color(QPalette::Active, QPalette::Highlight)); result.setHighlightedText(p.color(QPalette::Active, QPalette::HighlightedText)); /* if (type.m_currentItem && type.m_activePanel) { QColor currentBackground = KColorScheme(QPalette::Active).background(KColorScheme::ActiveBackground).color(); // set the background result.setColor(QColorGroup::Highlight, currentBackground); result.setColor(QColorGroup::Base, currentBackground); result.setColor(QColorGroup::Background, currentBackground); }*/ return result; } bool markCurrentAlways = m_colorSettings.getBoolValue("Show Current Item Always", _ShowCurrentItemAlways); bool dimBackground = m_colorSettings.getBoolValue("Dim Inactive Colors", false); // cache m_activePanel flag. If color dimming is turned on, it is set to true, as the inactive colors // are calculated from the active ones at the end. bool isActive = type.m_activePanel; if (dimBackground) isActive = true; // First calculate fore- and background. QColor background = type.m_alternateBackgroundColor ? getAlternateBackgroundColor(isActive) : getBackgroundColor(isActive); QColor foreground; switch (type.m_fileType) { case KrColorItemType::Directory : foreground = getSpecialForegroundColor("Directory", isActive); break; case KrColorItemType::Executable : foreground = getSpecialForegroundColor("Executable", isActive); break; case KrColorItemType::InvalidSymlink : foreground = getSpecialForegroundColor("Invalid Symlink", isActive); break; case KrColorItemType::Symlink : foreground = getSpecialForegroundColor("Symlink", isActive); break; default: foreground = getForegroundColor(isActive); } // set the background color result.setBackground(background); // set the foreground color result.setText(foreground); // now the color of a marked item QColor markedBackground = type.m_alternateBackgroundColor ? getAlternateMarkedBackgroundColor(isActive) : getMarkedBackgroundColor(isActive); QColor markedForeground = getMarkedForegroundColor(isActive); if (!markedForeground.isValid()) // transparent // choose fore- or background, depending on its contrast compared to markedBackground markedForeground = setColorIfContrastIsSufficient(markedBackground, foreground, background); // set it in the color group (different group color than normal foreground!) result.setHighlightedText(markedForeground); result.setHighlight(markedBackground); // In case the current item is a selected one, set the fore- and background colors for the contrast calculation below if (type.m_selectedItem) { background = markedBackground; foreground = markedForeground; } // finally the current item if (type.m_currentItem && (markCurrentAlways || isActive)) { // if this is the current item AND the panels has the focus OR the current should be marked always QColor currentBackground = getCurrentBackgroundColor(isActive); if (!currentBackground.isValid()) // transparent currentBackground = background; // set the background result.setHighlight(currentBackground); result.setBackground(currentBackground); QColor color; if (type.m_selectedItem) color = getCurrentMarkedForegroundColor(isActive); if (!color.isValid()) { // not used color = getCurrentForegroundColor(isActive); if (!color.isValid()) // transparent // choose fore- or background, depending on its contrast compared to markedBackground color = setColorIfContrastIsSufficient(currentBackground, foreground, background); } // set the foreground result.setText(color); result.setHighlightedText(color); } if (dimBackground && !type.m_activePanel) { // if color dimming is chosen, dim the colors for the inactive panel result.setBackground(dimColor(result.background(), true)); result.setText(dimColor(result.text(), false)); result.setHighlightedText(dimColor(result.highlightedText(), false)); result.setHighlight(dimColor(result.highlight(), true)); } return result; } const QColor & KrColorCacheImpl::setColorIfContrastIsSufficient(const QColor & background, const QColor & color1, const QColor & color2) { #define sqr(x) ((x)*(x)) int contrast = sqr(color1.red() - background.red()) + sqr(color1.green() - background.green()) + sqr(color1.blue() - background.blue()); // if the contrast between background and color1 is too small, take color2 instead. if (contrast < 1000) return color2; return color1; } QColor KrColorCacheImpl::getForegroundColor(bool isActive) const { QPalette p = QGuiApplication::palette(); QColor color = p.color(QPalette::Active, QPalette::Text); SETCOLOR(color, m_colorSettings.getColorValue("Foreground")); if (!isActive) SETCOLOR(color, m_colorSettings.getColorValue("Inactive Foreground")); return color; } QColor KrColorCacheImpl::getSpecialForegroundColor(const QString & type, bool isActive) const { QString colorName = "Inactive " + type + " Foreground"; if (!isActive && m_colorSettings.getColorTextValue(colorName) == "Inactive Foreground") return getForegroundColor(false); QColor color = m_colorSettings.getColorValue(type + " Foreground"); if (!isActive) SETCOLOR(color, m_colorSettings.getColorValue(colorName)); if (!color.isValid()) return getForegroundColor(isActive); return color; } QColor KrColorCacheImpl::getBackgroundColor(bool isActive) const { QColor color = QGuiApplication::palette().color(QPalette::Active, QPalette::Base); SETCOLOR(color, m_colorSettings.getColorValue("Background")); if (!isActive) SETCOLOR(color, m_colorSettings.getColorValue("Inactive Background")); return color; } QColor KrColorCacheImpl::getAlternateBackgroundColor(bool isActive) const { QPalette p = QGuiApplication::palette(); if (isActive && m_colorSettings.getColorTextValue("Alternate Background") == "Background") return getBackgroundColor(true); if (!isActive && m_colorSettings.getColorTextValue("Inactive Alternate Background").isEmpty()) return getAlternateBackgroundColor(true); if (!isActive && m_colorSettings.getColorTextValue("Inactive Alternate Background") == "Inactive Background") return getBackgroundColor(false); QColor color = isActive ? m_colorSettings.getColorValue("Alternate Background") : m_colorSettings.getColorValue("Inactive Alternate Background"); if (!color.isValid()) color = p.color(QPalette::Active, QPalette::AlternateBase); if (!color.isValid()) color = p.color(QPalette::Active, QPalette::Base); return color; } QColor KrColorCacheImpl::getMarkedForegroundColor(bool isActive) const { QString colorName = isActive ? "Marked Foreground" : "Inactive Marked Foreground"; if (m_colorSettings.getColorTextValue(colorName) == "transparent") return QColor(); if (isActive && m_colorSettings.getColorTextValue(colorName).isEmpty()) return QGuiApplication::palette().color(QPalette::Active, QPalette::HighlightedText); if (!isActive && m_colorSettings.getColorTextValue(colorName).isEmpty()) return getMarkedForegroundColor(true); return m_colorSettings.getColorValue(colorName); } QColor KrColorCacheImpl::getMarkedBackgroundColor(bool isActive) const { if (isActive && m_colorSettings.getColorTextValue("Marked Background").isEmpty()) return QGuiApplication::palette().color(QPalette::Active, QPalette::Highlight); if (isActive && m_colorSettings.getColorTextValue("Marked Background") == "Background") return getBackgroundColor(true); if (!isActive && m_colorSettings.getColorTextValue("Inactive Marked Background").isEmpty()) return getMarkedBackgroundColor(true); if (!isActive && m_colorSettings.getColorTextValue("Inactive Marked Background") == "Inactive Background") return getBackgroundColor(false); return isActive ? m_colorSettings.getColorValue("Marked Background") : m_colorSettings.getColorValue("Inactive Marked Background"); } QColor KrColorCacheImpl::getAlternateMarkedBackgroundColor(bool isActive) const { if (isActive && m_colorSettings.getColorTextValue("Alternate Marked Background") == "Alternate Background") return getAlternateBackgroundColor(true); if (isActive && m_colorSettings.getColorTextValue("Alternate Marked Background").isEmpty()) return getMarkedBackgroundColor(true); if (!isActive && m_colorSettings.getColorTextValue("Inactive Alternate Marked Background").isEmpty()) return getAlternateMarkedBackgroundColor(true); if (!isActive && m_colorSettings.getColorTextValue("Inactive Alternate Marked Background") == "Inactive Alternate Background") return getAlternateBackgroundColor(false); if (!isActive && m_colorSettings.getColorTextValue("Inactive Alternate Marked Background") == "Inactive Marked Background") return getMarkedBackgroundColor(false); return isActive ? m_colorSettings.getColorValue("Alternate Marked Background") : m_colorSettings.getColorValue("Inactive Alternate Marked Background"); } QColor KrColorCacheImpl::getCurrentForegroundColor(bool isActive) const { QColor color = m_colorSettings.getColorValue("Current Foreground"); if (!isActive) SETCOLOR(color, m_colorSettings.getColorValue("Inactive Current Foreground")); return color; } QColor KrColorCacheImpl::getCurrentBackgroundColor(bool isActive) const { if (isActive && m_colorSettings.getColorTextValue("Current Background").isEmpty()) return QColor(); if (isActive && m_colorSettings.getColorTextValue("Current Background") == "Background") return getBackgroundColor(true); if (!isActive && m_colorSettings.getColorTextValue("Inactive Current Background").isEmpty()) return getCurrentBackgroundColor(true); if (!isActive && m_colorSettings.getColorTextValue("Inactive Current Background") == "Inactive Background") return getBackgroundColor(false); return isActive ? m_colorSettings.getColorValue("Current Background") : m_colorSettings.getColorValue("Inactive Current Background"); } QColor KrColorCacheImpl::getCurrentMarkedForegroundColor(bool isActive) const { QString colorName = isActive ? "Marked Current Foreground" : "Inactive Marked Current Foreground"; if (isActive && m_colorSettings.getColorTextValue(colorName).isEmpty()) return QColor(); if (isActive && m_colorSettings.getColorTextValue(colorName) == "Marked Foreground") return getMarkedForegroundColor(true); if (!isActive && m_colorSettings.getColorTextValue(colorName).isEmpty()) return getCurrentMarkedForegroundColor(true); if (!isActive && m_colorSettings.getColorTextValue(colorName) == "Inactive Marked Foreground") return getMarkedForegroundColor(false); return m_colorSettings.getColorValue(colorName); } QColor KrColorCacheImpl::dimColor(QColor color, bool /* isBackgroundColor */) const { int dimFactor = m_colorSettings.getNumValue("Dim Factor", 100); QColor targetColor = m_colorSettings.getColorValue("Dim Target Color"); if (!targetColor.isValid()) targetColor = QColor(255, 255, 255); bool dimBackground = m_colorSettings.getBoolValue("Dim Inactive Colors", false); bool dim = dimFactor >= 0 && dimFactor < 100 && dimBackground; if (dim) color = KrColorCache::dimColor(color, dimFactor, targetColor); return color; } KrColorCache * KrColorCache::m_instance = 0; KrColorCache::KrColorCache() { m_impl = new KrColorCacheImpl; } KrColorCache::~KrColorCache() { delete m_impl; } KrColorCache & KrColorCache::getColorCache() { if (!m_instance) { m_instance = new KrColorCache; m_instance->refreshColors(); } return * m_instance; } void KrColorCache::getColors(KrColorGroup & result, const KrColorItemType & type) const { // for the cache lookup: calculate a unique key from the type char hashKey[128]; switch (type.m_fileType) { case KrColorItemType::Directory : strcpy(hashKey, "Directory"); break; case KrColorItemType::Executable : strcpy(hashKey, "Executable"); break; case KrColorItemType::InvalidSymlink : strcpy(hashKey, "InvalidSymlink"); break; case KrColorItemType::Symlink : strcpy(hashKey, "Symlink"); break; default: strcpy(hashKey, "File"); } if (type.m_activePanel) strcat(hashKey, "-Active"); if (type.m_alternateBackgroundColor) strcat(hashKey, "-Alternate"); if (type.m_currentItem) strcat(hashKey, "-Current"); if (type.m_selectedItem) strcat(hashKey, "-Selected"); // lookup in cache if (!m_impl->m_cachedColors.contains(hashKey)) // not found: calculate color group and store it in cache m_impl->m_cachedColors[hashKey] = m_impl->getColors(type); // get color group from cache const KrColorGroup & col = m_impl->m_cachedColors[hashKey]; // copy colors in question to result color group result.setBackground(col.background()); result.setText(col.text()); result.setHighlightedText(col.highlightedText()); result.setHighlight(col.highlight()); } bool KrColorCache::getDimSettings(QColor & dimColor, int & dimFactor) { if (m_impl->m_colorSettings.getBoolValue("Dim Inactive Colors", false)) { dimFactor = m_impl->m_colorSettings.getNumValue("Dim Factor", 100); dimColor = m_impl->m_colorSettings.getColorValue("Dim Target Color"); if (!dimColor.isValid()) dimColor.setRgb(255, 255, 255); return dimFactor >= 0 && dimFactor < 100; } return false; } QColor KrColorCache::dimColor(const QColor & color, int dim, const QColor & targetColor) { return QColor((targetColor.red() * (100 - dim) + color.red() * dim) / 100, (targetColor.green() * (100 - dim) + color.green() * dim) / 100, (targetColor.blue() * (100 - dim) + color.blue() * dim) / 100); } void KrColorCache::refreshColors() { m_impl->m_cachedColors.clear(); m_impl->m_colorSettings = KrColorSettings(); QPixmapCache::clear(); // dimmed icons are cached colorsRefreshed(); } void KrColorCache::setColors(const KrColorSettings & colorSettings) { m_impl->m_cachedColors.clear(); m_impl->m_colorSettings = colorSettings; QPixmapCache::clear(); // dimmed icons are cached colorsRefreshed(); } diff --git a/krusader/Panel/krlayoutfactory.cpp b/krusader/Panel/krlayoutfactory.cpp index 1b433f45..fb64c55d 100644 --- a/krusader/Panel/krlayoutfactory.cpp +++ b/krusader/Panel/krlayoutfactory.cpp @@ -1,324 +1,325 @@ /*************************************************************************** krlayoutfactory.cpp ------------------- copyright : (C) 2010 by Jan Lepper e-mail : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD S o u r c e F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "krlayoutfactory.h" #include "listpanelframe.h" #include "../krglobal.h" // QtCore +#include #include #include #include #include // QtWidgets #include #include #include #include // QtXml #include #include #include #define XMLFILE_VERSION "1.0" #define MAIN_FILE "layout.xml" #define MAIN_FILE_RC_PATH ":/" MAIN_FILE #define EXTRA_FILE_MASK "layouts/*.xml" #define DEFAULT_LAYOUT "krusader:default" bool KrLayoutFactory::_parsed = false; QDomDocument KrLayoutFactory::_mainDoc; QList KrLayoutFactory::_extraDocs; QString KrLayoutFactory::layoutDescription(QString layoutName) { if(layoutName == DEFAULT_LAYOUT) return i18nc("Default layout", "Default"); else if(layoutName == "krusader:compact") return i18n("Compact"); else if(layoutName == "krusader:classic") return i18n("Classic"); else return i18n("Custom layout: \"%1\"", layoutName); } bool KrLayoutFactory::parseFiles() { if (_parsed) return true; QString mainFilePath = QStandardPaths::locate(QStandardPaths::DataLocation, MAIN_FILE); if (!mainFilePath.isEmpty()) _parsed = parseFile(mainFilePath, _mainDoc); else qWarning() << "can't locate" << MAIN_FILE; if (!_parsed) _parsed = parseRessource(MAIN_FILE_RC_PATH, _mainDoc); if (!_parsed) return false; QStringList extraFilePaths = QStandardPaths::locateAll(QStandardPaths::DataLocation, EXTRA_FILE_MASK); foreach(const QString &path, extraFilePaths) { qWarning() << "extra file: " << path; QDomDocument doc; if (parseFile(path, doc)) _extraDocs << doc; } return true; } bool KrLayoutFactory::parseFile(QString path, QDomDocument &doc) { bool success = false; QFile file(path); if (file.open(QIODevice::ReadOnly)) return parseContent(file.readAll(), path, doc); else qWarning() << "can't open" << path; return success; } bool KrLayoutFactory::parseRessource(QString path, QDomDocument &doc) { QResource res(path); if (res.isValid()) { QByteArray data; if (res.isCompressed()) data = qUncompress(res.data(), res.size()); else data = QByteArray(reinterpret_cast(res.data()), res.size()); return parseContent(data, path, doc); } else { qWarning() << "resource does not exist:" << path; return false; } } bool KrLayoutFactory::parseContent(QByteArray content, QString fileName, QDomDocument &doc) { bool success = false; QString errorMsg; if (doc.setContent(content, &errorMsg)) { QDomElement root = doc.documentElement(); if (root.tagName() == "KrusaderLayout") { QString version = root.attribute("version"); if(version == XMLFILE_VERSION) success = true; else qWarning() << fileName << "has wrong version" << version << "- required is" << XMLFILE_VERSION; } else qWarning() << "root.tagName() != \"KrusaderLayout\""; } else qWarning() << "error parsing" << fileName << ":" << errorMsg; return success; } void KrLayoutFactory::getLayoutNames(QDomDocument doc, QStringList &names) { QDomElement root = doc.documentElement(); for(QDomElement e = root.firstChildElement(); ! e.isNull(); e = e.nextSiblingElement()) { if (e.tagName() == "layout") { QString name(e.attribute("name")); if (!name.isEmpty() && (name != DEFAULT_LAYOUT)) names << name; } } } QStringList KrLayoutFactory::layoutNames() { QStringList names; names << DEFAULT_LAYOUT; if (parseFiles()) { getLayoutNames(_mainDoc, names); foreach(const QDomDocument &doc, _extraDocs) getLayoutNames(doc, names); } return names; } QDomElement KrLayoutFactory::findLayout(QDomDocument doc, QString layoutName) { QDomElement root = doc.documentElement(); for(QDomElement e = root.firstChildElement(); ! e.isNull(); e = e.nextSiblingElement()) { if (e.tagName() == "layout" && e.attribute("name") == layoutName) return e; } return QDomElement(); } QLayout *KrLayoutFactory::createLayout(QString layoutName) { if(layoutName.isEmpty()) { KConfigGroup cg(krConfig, "PanelLayout"); layoutName = cg.readEntry("Layout", DEFAULT_LAYOUT); } QLayout *layout = 0; if (parseFiles()) { QDomElement layoutRoot; layoutRoot = findLayout(_mainDoc, layoutName); if (layoutRoot.isNull()) { foreach(const QDomDocument &doc, _extraDocs) { layoutRoot = findLayout(doc, layoutName); if(!layoutRoot.isNull()) break; } } if (layoutRoot.isNull()) { qWarning() << "no layout with name" << layoutName << "found"; if(layoutName != DEFAULT_LAYOUT) return createLayout(DEFAULT_LAYOUT); } else { layout = createLayout(layoutRoot, panel); } } if(layout) { foreach(const QString &name, widgets.keys()) { qWarning() << "widget" << name << "was not added to the layout"; widgets[name]->hide(); } } else qWarning() << "couldn't load layout" << layoutName; return layout; } QBoxLayout *KrLayoutFactory::createLayout(QDomElement e, QWidget *parent) { QBoxLayout *l = 0; bool horizontal = false; if(e.attribute("type") == "horizontal") { horizontal = true; l = new QHBoxLayout(); } else if(e.attribute("type") == "vertical") l = new QVBoxLayout(); else { qWarning() << "unknown layout type:" << e.attribute("type"); return 0; } l->setSpacing(0); l->setContentsMargins(0, 0, 0, 0); for(QDomElement child = e.firstChildElement(); ! child.isNull(); child = child.nextSiblingElement()) { if (child.tagName() == "layout") { if(QLayout *childLayout = createLayout(child, parent)) l->addLayout(childLayout); } else if(child.tagName() == "frame") { QWidget *frame = createFrame(child, parent); l->addWidget(frame); } else if(child.tagName() == "widget") { if(QWidget *w = widgets.take(child.attribute("name"))) l->addWidget(w); else qWarning() << "layout: so such widget:" << child.attribute("name"); } else if(child.tagName() == "hide_widget") { if(QWidget *w = widgets.take(child.attribute("name"))) w->hide(); else qWarning() << "layout: so such widget:" << child.attribute("name"); } else if(child.tagName() == "spacer") { if(horizontal) l->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Fixed)); else l->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding)); } } return l; } QWidget *KrLayoutFactory::createFrame(QDomElement e, QWidget *parent) { KConfigGroup cg(krConfig, "PanelLayout"); QString color = cg.readEntry("FrameColor", "default"); if(color == "default") color = e.attribute("color"); else if(color == "none") color.clear(); int shadow = -1, shape = -1; QMetaEnum shadowEnum = QFrame::staticMetaObject.enumerator(QFrame::staticMetaObject.indexOfEnumerator("Shadow")); QString cfgShadow = cg.readEntry("FrameShadow", "default"); if(cfgShadow != "default") shadow = shadowEnum.keyToValue(cfgShadow.toLatin1().data()); if(shadow < 0) shadow = shadowEnum.keyToValue(e.attribute("shadow").toLatin1().data()); QMetaEnum shapeEnum = QFrame::staticMetaObject.enumerator(QFrame::staticMetaObject.indexOfEnumerator("Shape")); QString cfgShape = cg.readEntry("FrameShape", "default"); if(cfgShape!= "default") shape = shapeEnum.keyToValue(cfgShape.toLatin1().data()); if(shape < 0) shape = shapeEnum.keyToValue(e.attribute("shape").toLatin1().data()); QFrame *frame = new ListPanelFrame(parent, color); frame->setFrameStyle(shape | shadow); frame->setAcceptDrops(true); if(QLayout *l = createLayout(e, frame)) { l->setContentsMargins(frame->frameWidth(), frame->frameWidth(), frame->frameWidth(), frame->frameWidth()); frame->setLayout(l); } QObject::connect(frame, SIGNAL(dropped(QDropEvent*,QWidget*)), panel, SLOT(handleDrop(QDropEvent*))); if(!color.isEmpty()) QObject::connect(panel, SIGNAL(refreshColors(bool)), frame, SLOT(refreshColors(bool))); return frame; } diff --git a/krusader/Panel/krsearchbar.cpp b/krusader/Panel/krsearchbar.cpp index 29be3a36..c5b41135 100644 --- a/krusader/Panel/krsearchbar.cpp +++ b/krusader/Panel/krsearchbar.cpp @@ -1,396 +1,397 @@ /***************************************************************************** * Copyright (C) 2010 Jan Lepper * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This package is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this package; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ #include "krsearchbar.h" #include "PanelView/krview.h" #include "PanelView/krviewitem.h" #include "../FileSystem/dirlisterinterface.h" #include "../defaults.h" #include "../krglobal.h" +#include #include #include #include #include #include #include #include #include #include KrSearchBar::KrSearchBar(KrView *view, QWidget *parent) : QWidget(parent), _view(0) { // close button QToolButton *closeButton = new QToolButton(this); closeButton->setAutoRaise(true); closeButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-close"))); closeButton->setToolTip(i18n("Close the search bar")); connect(closeButton, SIGNAL(clicked()), SLOT(hideBar())); // combo box for changing search mode _modeBox = new QComboBox(this); _modeBox->addItems(QStringList() << i18n("Search") << i18n("Select") << i18n("Filter")); int defaultIndex = KConfigGroup (krConfig, "Look&Feel") .readEntry("Default Search Mode", QString::number(KrSearchBar::MODE_SEARCH)).toInt(); _modeBox->setCurrentIndex(defaultIndex); _modeBox->setToolTip(i18n("Change the search mode")); connect(_modeBox, SIGNAL(currentIndexChanged(int)), SLOT(onModeChange())); _currentMode = static_cast(_modeBox->currentIndex()); // combo box for entering search string _textBox = new KComboBox(this); _textBox->setEditable(true); _modeBox->setToolTip(i18n("Enter or select search string")); QStringList savedSearches = KConfigGroup(krConfig, "Private") .readEntry("Predefined Selections", QStringList()); if (savedSearches.count() > 0) _textBox->addItems(savedSearches); _textBox->setCurrentText(""); _textBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred)); connect(_textBox, SIGNAL(currentTextChanged(QString)), SLOT(onSearchChange())); QToolButton *saveSearchBtn = new QToolButton(this); saveSearchBtn->setIcon(krLoader->loadIcon("document-save", KIconLoader::Toolbar, 16)); saveSearchBtn->setFixedSize(20, 20); saveSearchBtn->setToolTip(i18n("Save the current search string")); connect(saveSearchBtn, SIGNAL(clicked()), this, SLOT(saveSearchString())); _openSelectDialogBtn = new QToolButton(this); _openSelectDialogBtn->setIcon(krLoader->loadIcon("configure", KIconLoader::Toolbar, 16)); _openSelectDialogBtn->setFixedSize(20, 20); _openSelectDialogBtn->setToolTip(i18n("Open selection dialog")); QHBoxLayout *layout = new QHBoxLayout(this); layout->setMargin(0); layout->addWidget(closeButton); layout->addWidget(_modeBox); layout->addWidget(_textBox); layout->addWidget(saveSearchBtn); layout->addWidget(_openSelectDialogBtn); _textBox->installEventFilter(this); setView(view); } void KrSearchBar::setView(KrView *view) { if (_view) { _view->widget()->removeEventFilter(this); disconnect(_openSelectDialogBtn, 0, 0, 0); } _view = view; connect(_openSelectDialogBtn, &QToolButton::clicked, [this](){ _view->customSelection(true); }); _view->widget()->installEventFilter(this); } // #### public slots void KrSearchBar::showBar(SearchMode mode) { if (mode != MODE_LAST) { _modeBox->setCurrentIndex(mode); } show(); _textBox->setFocus(); } void KrSearchBar::hideBar() { resetSearch(); if (_textBox->hasFocus()) _view->widget()->setFocus(); hide(); } void KrSearchBar::resetSearch() { _textBox->clearEditText(); indicateMatch(true); } // #### protected slots void KrSearchBar::onModeChange() { if (_currentMode == MODE_FILTER) { _view->op()->filterSearch(QString(), true); // reset filter } _currentMode = static_cast(_modeBox->currentIndex()); onSearchChange(); } void KrSearchBar::onSearchChange() { const QString text = _textBox->currentText(); switch(_currentMode) { case MODE_SEARCH: { const bool anyMatch = _view->op()->searchItem(text, caseSensitive()); indicateMatch(anyMatch); break; } case MODE_SELECT: { _view->unselectAll(); if (!text.isEmpty()) { const bool anyMatch = _view->changeSelection(KRQuery(text, caseSensitive()), true); indicateMatch(anyMatch); } break; } case MODE_FILTER: { const bool anyMatch =_view->op()->filterSearch(text, caseSensitive()); indicateMatch(anyMatch); break; } default: qWarning() << "unexpected search mode: " << _currentMode; } _textBox->setFocus(); } void KrSearchBar::saveSearchString() { KConfigGroup group(krConfig, "Private"); QStringList lst = group.readEntry("Predefined Selections", QStringList()); QString searchString = _textBox->currentText(); if (lst.indexOf(searchString) != -1) { // already saved return; } lst.append(searchString); group.writeEntry("Predefined Selections", lst); _textBox->addItem(searchString); QToolTip::showText(QCursor::pos(), i18n("Saved search text to history")); } // #### protected void KrSearchBar::keyPressEvent(QKeyEvent *event) { const bool handled = handleKeyPressEvent(static_cast(event)); if (handled) { return; } QWidget::keyPressEvent(event); } bool KrSearchBar::eventFilter(QObject *watched, QEvent *event) { if (event->type() != QEvent::ShortcutOverride && watched == _view->widget()) { QKeyEvent *ke = static_cast(event); // overwrite "escape" shortcut if bar is shown if ((ke->key() == Qt::Key_Escape) && (ke->modifiers() == Qt::NoModifier) && !isHidden()) { ke->accept(); handleKeyPressEvent(ke); return true; } } if (event->type() != QEvent::KeyPress) { return false; } qDebug() << "key press event=" << event; QKeyEvent *ke = static_cast(event); if (watched == _view->widget()) { KConfigGroup grpSv(krConfig, "Look&Feel"); const bool autoShow = grpSv.readEntry("New Style Quicksearch", _NewStyleQuicksearch); if (isHidden() && !autoShow) { return false; } if (!isHidden()) { const bool handled = handleKeyPressEvent(ke); if (handled) { return true; } } if (isHidden() || // view can handle its own event if user does not want to remove text or... !((ke->key() == Qt::Key_Backspace && !_textBox->currentText().isEmpty()) || // ...insert space in search bar (even if not focused) (ke->key() == Qt::Key_Space && _currentMode == KrSearchBar::MODE_SEARCH))) { const bool handled = _view->handleKeyEvent(ke); if (handled) { return true; } } if (ke->text().isEmpty() || (ke->modifiers() != Qt::NoModifier && ke->modifiers() != Qt::ShiftModifier && ke->modifiers() != Qt::KeypadModifier)) { return false; } // start searching if bar is hidden? if (isHidden()) { if (autoShow) { showBar(); } else { return false; } } // bar is visible and gets the key input _textBox->setFocus(); if (ke->key() == Qt::Key_Backspace) { _textBox->lineEdit()->backspace(); } else { _textBox->setEditText(_textBox->currentText().append(ke->text())); } return true; } else if (watched == _textBox) { // allow the view to handle (most) key events from the text box if (ke->modifiers() == Qt::NoModifier && ke->key() != Qt::Key_Space && ke->key() != Qt::Key_Backspace && ke->key() != Qt::Key_Left && ke->key() != Qt::Key_Right) { bool handled = _view->handleKeyEvent(ke); if (handled) { _view->widget()->setFocus(); return true; } } } return false; } // #### private bool KrSearchBar::handleKeyPressEvent(QKeyEvent *ke) { if (ke->modifiers() != Qt::NoModifier) { return false; } switch (ke->key()) { case Qt::Key_Escape: { hideBar(); return true; } case Qt::Key_Up: return handleUpDownKeyPress(true); case Qt::Key_Down: return handleUpDownKeyPress(false); case Qt::Key_Insert: { // select current item and jump to next search result KrViewItem * item = _view->getCurrentKrViewItem(); if (item) { item->setSelected(!item->isSelected()); _view->op()->searchItem(_textBox->currentText(), caseSensitive(), 1); } return true; } case Qt::Key_Home: { // jump to first search result KrViewItem * item = _view->getLast(); if (item) { _view->setCurrentKrViewItem(_view->getLast()); _view->op()->searchItem(_textBox->currentText(), caseSensitive(), 1); } return true; } case Qt::Key_End: { // jump to last search result KrViewItem * item = _view->getFirst(); if (item) { _view->setCurrentKrViewItem(_view->getFirst()); _view->op()->searchItem(_textBox->currentText(), caseSensitive(), -1); } return true; } } return false; } bool KrSearchBar::handleUpDownKeyPress(bool up) { if (_currentMode != MODE_SEARCH) { return false; } const bool updownCancel = KConfigGroup(krConfig, "Look&Feel") .readEntry("Up/Down Cancels Quicksearch", false); if (updownCancel) { hideBar(); return false; } const bool anyMatch = _view->op()->searchItem(_textBox->currentText(), caseSensitive(), up ? -1 : 1); indicateMatch(anyMatch); return true; } void KrSearchBar::indicateMatch(bool anyMatch) { KConfigGroup gc(krConfig, "Colors"); QPalette p = QGuiApplication::palette(); QString foreground, background; if (anyMatch) { foreground = "Quicksearch Match Foreground"; background = "Quicksearch Match Background"; } else { foreground = "Quicksearch Non-match Foreground"; background = "Quicksearch Non-match Background"; } QColor fore = Qt::black; QString foreSetting = gc.readEntry(foreground, QString()); if (foreSetting == "KDE default") { fore = p.color(QPalette::Active, QPalette::Text); } else if (!foreSetting.isEmpty()) { fore = gc.readEntry(foreground, fore); } QColor back = anyMatch ? QColor(192, 255, 192) : QColor(255, 192, 192); QString backSetting = gc.readEntry(background, QString()); if (backSetting == "KDE default") { back = p.color(QPalette::Active, QPalette::Base); } else if (!backSetting.isEmpty()) { back = gc.readEntry(background, back); } QPalette pal = palette(); pal.setColor(QPalette::Base, back); pal.setColor(QPalette::Text, fore); _textBox->lineEdit()->setPalette(pal); } bool KrSearchBar::caseSensitive() { KConfigGroup grpSvr(krConfig, "Look&Feel"); return grpSvr.readEntry("Case Sensitive Quicksearch", _CaseSensitiveQuicksearch); } diff --git a/krusader/krglobal.h b/krusader/krglobal.h index b15cf0cc..1081fff6 100644 --- a/krusader/krglobal.h +++ b/krusader/krglobal.h @@ -1,110 +1,106 @@ /*************************************************************************** krglobal.h ------------------- begin : Thu May 4 2000 copyright : (C) 2000 by Shie Erlich & Rafi Yanai e-mail : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD H e a d e r F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KRGLOBAL_H #define KRGLOBAL_H -// QtCore -#include // QtGui #include #include -#define krOut qDebug() - class KConfig; class KMountMan; class KrBookmarkHandler; class KRslots; class KIconLoader; class KrusaderView; class UserAction; class JobMan; class QWidget; class KrPanel; // global references to frequently used objects class KrGlobal { public: static KConfig *config; // allow everyone to access the config static KMountMan *mountMan; // krusader's Mount Manager static KrBookmarkHandler *bookman; static KRslots *slot; static KIconLoader *iconLoader; // the app's icon loader static KrusaderView *mainView; // The GUI static QWidget *mainWindow; static UserAction *userAction; static JobMan *jobMan; // static ListPanel *activePanel; static KrPanel *activePanel(); //HACK - used by [ListerTextArea|KrSearchDialog|LocateDlg]:keyPressEvent() static QKeySequence copyShortcut; // static void enableAction(const char *name, bool enable); // static QAction *getAction(const char *name); /** Version of saved configuration. Use this to detect configuration updates. */ static const int sConfigVersion = 1; static int sCurrentConfigVersion; }; #define krConfig KrGlobal::config #define krMtMan (*(KrGlobal::mountMan)) #define krBookMan KrGlobal::bookman #define SLOTS KrGlobal::slot #define krLoader KrGlobal::iconLoader #define MAIN_VIEW KrGlobal::mainView #define krMainWindow KrGlobal::mainWindow #define krUserAction KrGlobal::userAction #define krJobMan KrGlobal::jobMan #define ACTIVE_PANEL (KrGlobal::activePanel()) #define ACTIVE_MNG (MAIN_VIEW->activeManager()) #define ACTIVE_FUNC (ACTIVE_PANEL->func) #define OTHER_MNG (MAIN_VIEW->inactiveManager()) #define OTHER_PANEL (ACTIVE_PANEL->otherPanel()) #define OTHER_FUNC (OTHER_PANEL->func) #define LEFT_PANEL (MAIN_VIEW->leftPanel()) #define LEFT_FUNC (LEFT_PANEL->func) #define LEFT_MNG (MAIN_VIEW->leftManager()) #define RIGHT_PANEL (MAIN_VIEW->rightPanel()) #define RIGHT_FUNC (RIGHT_PANEL->func) #define RIGHT_MNG (MAIN_VIEW->rightManager()) // #define krEnableAction(name, enable) (KrGlobal::enableAction(#name, (enable))) // #define krGetAction(name) (KrGlobal::getAction(#name)) #endif diff --git a/krusader/krservices.cpp b/krusader/krservices.cpp index d398deae..8e70383e 100644 --- a/krusader/krservices.cpp +++ b/krusader/krservices.cpp @@ -1,316 +1,317 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 Rafi Yanai * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This package is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this package; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ #include "krservices.h" // QtCore #include +#include #include #include #include #include #include "krglobal.h" #include "defaults.h" QMap* KrServices::slaveMap = 0; QSet KrServices::krarcArchiveMimetypes = KrServices::generateKrarcArchiveMimetypes(); #ifdef KRARC_QUERY_ENABLED QSet KrServices::isoArchiveMimetypes = QSet::fromList(KProtocolInfo::archiveMimetypes("iso")); #else QSet KrServices::isoArchiveMimetypes; #endif QString KrServices::GLOBAL_MESSAGE_PATTERN = "%{time hh:mm:ss.zzz}-%{type} %{category} %{function}@%{line} # %{message}"; QSet KrServices::generateKrarcArchiveMimetypes() { // Hard-code these proven mimetypes openable by krarc protocol. // They cannot be listed in krarc.protocol itself // because it would baffle other file managers (like Dolphin). QSet mimes; mimes += QString("application/x-deb"); mimes += QString("application/x-debian-package"); mimes += QString("application/vnd.debian.binary-package"); mimes += QString("application/x-java-archive"); mimes += QString("application/x-rpm"); mimes += QString("application/x-source-rpm"); mimes += QString("application/vnd.oasis.opendocument.chart"); mimes += QString("application/vnd.oasis.opendocument.database"); mimes += QString("application/vnd.oasis.opendocument.formula"); mimes += QString("application/vnd.oasis.opendocument.graphics"); mimes += QString("application/vnd.oasis.opendocument.presentation"); mimes += QString("application/vnd.oasis.opendocument.spreadsheet"); mimes += QString("application/vnd.oasis.opendocument.text"); mimes += QString("application/vnd.openxmlformats-officedocument.presentationml.presentation"); mimes += QString("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); mimes += QString("application/vnd.openxmlformats-officedocument.wordprocessingml.document"); mimes += QString("application/x-cbz"); mimes += QString("application/x-cbr"); mimes += QString("application/epub+zip"); mimes += QString("application/x-webarchive"); mimes += QString("application/x-plasma"); mimes += QString("application/vnd.rar"); #ifdef KRARC_QUERY_ENABLED mimes += QSet::fromList(KProtocolInfo::archiveMimetypes("krarc")); #endif return mimes; } bool KrServices::cmdExist(QString cmdName) { KConfigGroup group(krConfig, "Dependencies"); if (QFile(group.readEntry(cmdName, QString())).exists()) return true; return !QStandardPaths::findExecutable(cmdName).isEmpty(); } QString KrServices::fullPathName(QString name, QString confName) { QString supposedName; if (confName.isNull()) confName = name; KConfigGroup config(krConfig, "Dependencies"); if (QFile(supposedName = config.readEntry(confName, QString())).exists()) return supposedName; if ((supposedName = QStandardPaths::findExecutable(name)).isEmpty()) return ""; config.writeEntry(confName, supposedName); return supposedName; } QString KrServices::chooseFullPathName(QStringList names, QString confName) { foreach(const QString &name, names) { QString foundTool = KrServices::fullPathName(name, confName); if (! foundTool.isEmpty()) { return foundTool; } } return ""; } bool KrServices::isExecutable(const QString &path) { QFileInfo info(path); return info.isFile() && info.isExecutable(); } QString KrServices::registeredProtocol(QString mimetype) { if (slaveMap == 0) { slaveMap = new QMap(); KConfigGroup group(krConfig, "Protocols"); QStringList protList = group.readEntry("Handled Protocols", QStringList()); for (QStringList::Iterator it = protList.begin(); it != protList.end(); ++it) { QStringList mimes = group.readEntry(QString("Mimes For %1").arg(*it), QStringList()); for (QStringList::Iterator it2 = mimes.begin(); it2 != mimes.end(); ++it2) (*slaveMap)[*it2] = *it; } } QString protocol = (*slaveMap)[mimetype]; if (protocol.isEmpty()) { if (krarcArchiveMimetypes.contains(mimetype)) { return "krarc"; } protocol = KProtocolManager::protocolForArchiveMimetype(mimetype); } return protocol; } bool KrServices::isoSupported(QString mimetype) { return isoArchiveMimetypes.contains(mimetype); } void KrServices::clearProtocolCache() { if (slaveMap) delete slaveMap; slaveMap = 0; } bool KrServices::fileToStringList(QTextStream *stream, QStringList& target, bool keepEmptyLines) { if (!stream) return false; QString line; while (!stream->atEnd()) { line = stream->readLine().trimmed(); if (keepEmptyLines || !line.isEmpty()) target.append(line); } return true; } bool KrServices::fileToStringList(QFile *file, QStringList& target, bool keepEmptyLines) { QTextStream stream(file); return fileToStringList(&stream, target, keepEmptyLines); } QString KrServices::quote(QString name) { if (!name.contains('\'')) return '\'' + name + '\''; if (!name.contains('"') && !name.contains('$')) return '\"' + name + '\"'; return escape(name); } QStringList KrServices::quote(const QStringList& names) { QStringList result; for (int i = 0; i < names.size(); ++i) result.append(quote(names[i])); return result; } QList KrServices::toUrlList(const QStringList &list) { QList result; for (QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) { result.append(QUrl::fromUserInput(*it, QDir::currentPath(), QUrl::AssumeLocalFile)); } return result; } QStringList KrServices::toStringList(const QList &list) { QStringList result; for(QList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) { result.append(it->toString()); } return result; } // Adds one tool to the list in the supportedTools method void supportedTool(QStringList &tools, QString toolType, QStringList names, QString confName) { QString foundTool = KrServices::chooseFullPathName(names, confName); if (! foundTool.isEmpty()) { tools.append(toolType); tools.append(foundTool); } } // return a list in the format of TOOLS,PATH. for example // DIFF,kdiff,TERMINAL,konsole,... // // currently supported tools: DIFF, MAIL, RENAME // // to use it: QStringList lst = supportedTools(); // int i = lst.indexOf("DIFF"); // if (i!=-1) pathToDiff=lst[i+1]; QStringList KrServices::supportedTools() { QStringList tools; // first, a diff program: kdiff supportedTool(tools, "DIFF", QStringList() << "kdiff3" << "kompare" << "xxdiff", "diff utility"); // a mailer: kmail or thunderbird supportedTool(tools, "MAIL", QStringList() << "thunderbird" << "kmail", "mailer"); // rename tool: krename supportedTool(tools, "RENAME", QStringList() << "krename", "krename"); // checksum utility supportedTool(tools, "MD5", QStringList() << "md5sum", "checksum utility"); return tools; } QString KrServices::escape(QString name) { const QString evilstuff = "\\\"'`()[]{}!?;$&<>| \t\r\n"; // stuff that should get escaped for (int i = 0; i < evilstuff.length(); ++i) name.replace(evilstuff[ i ], ('\\' + evilstuff[ i ])); return name; } QString KrServices::escapeFileUrl(QString urlString) { // Avoid that if a path contains a '#' then what follows the '#' be interpreted as the fragment identifier of // the URL and not a part of the file path; for more information https://bugs.kde.org/show_bug.cgi?id=270150 can be seen return urlString.replace('#', "%23").replace('?', "%3F"); } QUrl KrServices::escapeFileUrl(const QUrl &url) { return QUrl(KrServices::escapeFileUrl(url.toString())); } QString KrServices::urlToLocalPath(const QUrl &url) { QUrl fileUrl = QUrl(url); // QUrl::toLocalFile() does not work if the protocol is "file" e.g. when opening an archive fileUrl.setScheme("file"); QString path = fileUrl.toLocalFile(); REPLACE_DIR_SEP2(path); #ifdef Q_WS_WIN if (path.startsWith(DIR_SEPARATOR)) { int p = 1; while (p < path.length() && path[ p ] == DIR_SEPARATOR_CHAR) p++; /* /C:/Folder */ if (p + 2 <= path.length() && path[ p ].isLetter() && path[ p + 1 ] == ':') { path = path.mid(p); } } #endif return path; } static bool s_withDebugMessages; static QtMessageHandler s_defaultMessageHandler; void KrServices::setGlobalKrMessageHandler(bool withDebugMessages) { s_withDebugMessages = withDebugMessages; s_defaultMessageHandler = qInstallMessageHandler(0); qInstallMessageHandler(&krMessageHandler); } void KrServices::krMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { // filter debug if not enabled if (type != QtDebugMsg || s_withDebugMessages) { s_defaultMessageHandler(type, context, msg); } } diff --git a/krusader/krusaderview.cpp b/krusader/krusaderview.cpp index 4b041428..b66f966e 100644 --- a/krusader/krusaderview.cpp +++ b/krusader/krusaderview.cpp @@ -1,531 +1,532 @@ /*************************************************************************** krusaderview.cpp ------------------- copyright : (C) 2000 by Shie Erlich & Rafi Yanai e-mail : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD S o u r c e F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "krusaderview.h" // QtCore +#include #include #include // QtGui #include #include // QtWidgets #include #include #include #include #include #include #include #include "krusader.h" #include "kractions.h" #include "krslots.h" #include "defaults.h" #include "Panel/listpanel.h" #include "Panel/panelfunc.h" #include "GUI/kcmdline.h" #include "GUI/kfnkeys.h" #include "GUI/terminaldock.h" #include "panelmanager.h" #include "GUI/profilemanager.h" #include "Dialogs/percentalsplitter.h" #include "krservices.h" KrusaderView::KrusaderView(QWidget *parent) : QWidget(parent), activeMng(0) { } void KrusaderView::start(const KConfigGroup &cfg, bool restoreSettings, const QList &leftTabs, const QList &rightTabs) { //////////////////////////////// // make a 1x1 mainLayout, it will auto-expand: mainLayout = new QGridLayout(this); mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setSpacing(0); // vertical splitter vert_splitter = new QSplitter(this); // splits between panels and terminal/cmdline vert_splitter->setOrientation(Qt::Vertical); // horizontal splitter horiz_splitter = new PercentalSplitter(vert_splitter); (_terminalDock = new TerminalDock(vert_splitter, krApp))->hide(); // create it hidden // create a command line thing _cmdLine = new KCMDLine(this); // add a panel manager for each side of the splitter leftMng = createManager(true); rightMng = createManager(false); leftMng->setOtherManager(rightMng); rightMng->setOtherManager(leftMng); // make the left panel focused at program start activeMng = leftMng; // create the function keys widget _fnKeys = new KFnKeys(this, krApp); _fnKeys->hide(); _fnKeys->setWhatsThis(i18n("Function keys allow performing fast " "operations on files.")); // and insert the whole thing into the main layout... at last mainLayout->addWidget(vert_splitter, 0, 0); //<> mainLayout->addWidget(_cmdLine, 1, 0); mainLayout->addWidget(_fnKeys, 2, 0); mainLayout->activate(); // get the last saved sizes of the splitter QList lst = cfg.readEntry("Splitter Sizes", QList()); if (lst.count() != 2) { lst.clear(); lst.push_back(100); lst.push_back(100); } else if (lst[0] < 1 && lst[1] < 1) { lst[ 0 ] = 100; lst[ 1 ] = 100; } horiz_splitter->setSizes(lst); verticalSplitterSizes = cfg.readEntry("Terminal Emulator Splitter Sizes", QList ()); if (verticalSplitterSizes.count() != 2 || (verticalSplitterSizes[0] < 1 && verticalSplitterSizes[1] < 1)) { verticalSplitterSizes.clear(); verticalSplitterSizes << 100 << 100; } leftPanel()->start(leftTabs.isEmpty() ? QUrl::fromLocalFile(QDir::homePath()) : leftTabs.at(0)); rightPanel()->start(rightTabs.isEmpty() ? QUrl::fromLocalFile(QDir::homePath()) : rightTabs.at(0)); ACTIVE_PANEL->gui->slotFocusOnMe(); // left starts out active for (int i = 1; i < leftTabs.count(); i++) leftMng->slotNewTab(leftTabs.at(i), false); for (int j = 1; j < rightTabs.count(); j++) rightMng->slotNewTab(rightTabs.at(j), false); // this is needed so that all tab labels get updated leftMng->layoutTabs(); rightMng->layoutTabs(); if(restoreSettings) { if(leftTabs.isEmpty()) leftMng->loadSettings(KConfigGroup(&cfg, "Left Tab Bar")); if(rightTabs.isEmpty()) rightMng->loadSettings(KConfigGroup(&cfg, "Right Tab Bar")); if (cfg.readEntry("Left Side Is Active", false)) leftPanel()->slotFocusOnMe(); else rightPanel()->slotFocusOnMe(); } } void KrusaderView::updateGUI(const KConfigGroup &cfg) { if (!cfg.readEntry("Show Cmd Line", _ShowCmdline)) { cmdLine()->hide(); KrActions::actToggleCmdline->setChecked(false); } else { cmdLine()->show(); KrActions::actToggleCmdline->setChecked(true); } // update the Fn bar to the shortcuts selected by the user fnKeys()->updateShortcuts(); if (!cfg.readEntry("Show FN Keys", _ShowFNkeys)) { fnKeys()->hide(); KrActions::actToggleFnkeys->setChecked(false); } else { fnKeys()->show(); KrActions::actToggleFnkeys->setChecked(true); } // set vertical mode if (cfg.readEntry("Vertical Mode", false)) { toggleVerticalMode(); } if (cfg.readEntry("Show Terminal Emulator", _ShowTerminalEmulator)) { setTerminalEmulator(true); // create konsole_part }; } void KrusaderView::setPanelSize(bool leftPanel, int percent) { QList panelSizes = horiz_splitter->sizes(); int totalSize = panelSizes[0] + panelSizes[1]; if (leftPanel) { panelSizes[0] = totalSize * percent / 100; panelSizes[1] = totalSize * (100 - percent) / 100; } else { // == RIGHT_PANEL panelSizes[0] = totalSize * (100 - percent) / 100; panelSizes[1] = totalSize * percent / 100; } horiz_splitter->setSizes(panelSizes); } PanelManager *KrusaderView::createManager(bool left) { PanelManager *p = new PanelManager(horiz_splitter, krApp, left); connect(p, SIGNAL(draggingTab(PanelManager*,QMouseEvent*)), SLOT(draggingTab(PanelManager*,QMouseEvent*))); connect(p, SIGNAL(draggingTabFinished(PanelManager*,QMouseEvent*)), SLOT(draggingTabFinished(PanelManager*,QMouseEvent*))); connect(p, SIGNAL(pathChanged(ListPanel*)), SLOT(slotPathChanged(ListPanel*))); connect(p, SIGNAL(setActiveManager(PanelManager*)), SLOT(slotSetActiveManager(PanelManager*))); return p; } ListPanel* KrusaderView::leftPanel() { return leftMng->currentPanel()->gui; } ListPanel* KrusaderView::rightPanel() { return rightMng->currentPanel()->gui; } // updates the command line whenever current panel or its path changes ////////////////////////////////////////////////////////// void KrusaderView::slotPathChanged(ListPanel *p) { if(p == ACTIVE_PANEL) { _cmdLine->setCurrent(p->lastLocalPath()); KConfigGroup cfg = krConfig->group("General"); if (cfg.readEntry("Send CDs", _SendCDs)) { // hopefully, this is cached in kconfig _terminalDock->sendCd(p->lastLocalPath()); } } } int KrusaderView::getFocusCandidates(QVector &widgets) { ACTIVE_PANEL->gui->getFocusCandidates(widgets); if(_terminalDock->isTerminalVisible()) widgets << _terminalDock; if(_cmdLine->isVisible()) widgets << _cmdLine; for(int i = 0; i < widgets.count(); i++) { if(widgets[i] == focusWidget() || widgets[i]->focusWidget() == focusWidget()) return i; } return -1; } void KrusaderView::focusUp() { qDebug() << "focus UP"; QVector widgets; int currentFocus = getFocusCandidates(widgets); if(currentFocus < 0) return; currentFocus--; if(currentFocus >= 0 && currentFocus < widgets.count()) widgets[currentFocus]->setFocus(); } void KrusaderView::focusDown() { qDebug() << "focus DOWN"; QVector widgets; int currentFocus = getFocusCandidates(widgets); if(currentFocus < 0) return; currentFocus++; if(currentFocus < widgets.count()) widgets[currentFocus]->setFocus(); } void KrusaderView::cmdLineFocus() // command line receive's keyboard focus { _cmdLine->setFocus(); } void KrusaderView::cmdLineUnFocus() // return focus to the active panel { ACTIVE_PANEL->gui->slotFocusOnMe(); } // Tab - switch focus void KrusaderView::panelSwitch() { ACTIVE_PANEL->otherPanel()->gui->slotFocusOnMe(); } void KrusaderView::slotSetActiveManager(PanelManager *manager) { activeMng = manager; slotPathChanged(manager->currentPanel()->gui); } void KrusaderView::swapSides() { QList lst = horiz_splitter->sizes(); horiz_splitter->addWidget(leftMng); int old = lst[ 0 ]; lst[ 0 ] = lst [ 1 ]; lst[ 1 ] = old; horiz_splitter->setSizes(lst); PanelManager *tmpMng = leftMng; leftMng = rightMng; rightMng = tmpMng; leftMng->setLeft(true); rightMng->setLeft(false); leftPanel()->updateGeometry(); rightPanel()->updateGeometry(); } void KrusaderView::setTerminalEmulator(bool show, bool fullscreen) { static bool fnKeysShown = true; // first time init. should be overridden static bool cmdLineShown = true; static bool statusBarShown = true; static bool mainToolBarShown = true; static bool jobToolBarShown = true; static bool actionToolBarShown = true; static bool menuBarShown = true; static bool terminalEmulatorShown = true; if (show) { if (fullscreen) { // save what is shown fnKeysShown = !_fnKeys->isHidden(); cmdLineShown = !_cmdLine->isHidden(); statusBarShown = !krApp->statusBar()->isHidden(); mainToolBarShown = !krApp->toolBar()->isHidden(); jobToolBarShown = !krApp->toolBar("jobToolBar")->isHidden(); actionToolBarShown = !krApp->toolBar("actionToolBar")->isHidden(); menuBarShown = !krApp->menuBar()->isHidden(); terminalEmulatorShown = _terminalDock->isTerminalVisible(); } if(!_terminalDock->isTerminalVisible()) { // show terminal const bool isInitialized = _terminalDock->initialise(); if (!isInitialized) { _terminalDock->hide(); KrActions::actToggleTerminal->setChecked(false); return; } _terminalDock->show(); _terminalDock->setFocus(); slotPathChanged(ACTIVE_PANEL->gui); KrActions::actToggleTerminal->setChecked(true); } else if (fullscreen) { // save current terminal size before going to fullscreen verticalSplitterSizes = vert_splitter->sizes(); } if (fullscreen) { // hide everything else leftMng->hide(); rightMng->hide(); _fnKeys->hide(); _cmdLine->hide(); krApp->statusBar()->hide(); krApp->toolBar()->hide(); krApp->toolBar("jobToolBar")->hide(); krApp->toolBar("actionToolBar")->hide(); krApp->menuBar()->hide(); // fix showing nothing if terminal is open but splitter widget size is zero vert_splitter->setSizes(QList() << 0 << vert_splitter->height()); } else { vert_splitter->setSizes(verticalSplitterSizes); } } else { // hide const bool isFullscreen = isTerminalEmulatorFullscreen(); if (!(fullscreen && terminalEmulatorShown)) { // hide terminal emulator ACTIVE_PANEL->gui->slotFocusOnMe(); if (_terminalDock->isTerminalVisible() && !isFullscreen) verticalSplitterSizes = vert_splitter->sizes(); _terminalDock->hide(); KrActions::actToggleTerminal->setChecked(false); } else { // not fullscreen anymore but terminal is still visible vert_splitter->setSizes(verticalSplitterSizes); } if (isFullscreen) { // restore: unhide everything that was hidden before leftMng->show(); rightMng->show(); if (fnKeysShown) _fnKeys->show(); if (cmdLineShown) _cmdLine->show(); if (statusBarShown) krApp->statusBar()->show(); if (mainToolBarShown) krApp->toolBar()->show(); if (jobToolBarShown) krApp->toolBar("jobToolBar")->show(); if (actionToolBarShown) krApp->toolBar("actionToolBar")->show(); if (menuBarShown) krApp->menuBar()->show(); } } } void KrusaderView::focusTerminalEmulator() { if (_terminalDock->isTerminalVisible()) _terminalDock->setFocus(); } void KrusaderView::toggleFullScreenTerminalEmulator() { setTerminalEmulator(!isTerminalEmulatorFullscreen(), true); } bool KrusaderView::isTerminalEmulatorFullscreen() { return leftMng->isHidden() && rightMng->isHidden(); } void KrusaderView::profiles(QString profileName) { ProfileManager profileManager("Panel", this); profileManager.hide(); connect(&profileManager, SIGNAL(saveToProfile(QString)), this, SLOT(savePanelProfiles(QString))); connect(&profileManager, SIGNAL(loadFromProfile(QString)), this, SLOT(loadPanelProfiles(QString))); if (profileName.isEmpty()) profileManager.profilePopup(); else profileManager.loadProfile(profileName); } void KrusaderView::loadPanelProfiles(QString group) { KConfigGroup ldg(krConfig, group); leftMng->loadSettings(KConfigGroup(&ldg, "Left Tabs")); rightMng->loadSettings(KConfigGroup(&ldg, "Right Tabs")); if (ldg.readEntry("Left Side Is Active", true)) leftPanel()->slotFocusOnMe(); else rightPanel()->slotFocusOnMe(); } void KrusaderView::savePanelProfiles(QString group) { KConfigGroup svr(krConfig, group); svr.writeEntry("Vertical Mode", isVertical()); svr.writeEntry("Left Side Is Active", ACTIVE_PANEL->gui->isLeft()); leftMng->saveSettings(KConfigGroup(&svr, "Left Tabs"), false); rightMng->saveSettings(KConfigGroup(&svr, "Right Tabs"), false); } void KrusaderView::toggleVerticalMode() { if (horiz_splitter->orientation() == Qt::Vertical) { horiz_splitter->setOrientation(Qt::Horizontal); KrActions::actVerticalMode->setText(i18n("Vertical Mode")); KrActions::actVerticalMode->setIcon(QIcon::fromTheme("view-split-top-bottom")); } else { horiz_splitter->setOrientation(Qt::Vertical); KrActions::actVerticalMode->setText(i18n("Horizontal Mode")); KrActions::actVerticalMode->setIcon(QIcon::fromTheme("view-split-left-right")); } } void KrusaderView::saveSettings(KConfigGroup &cfg) { QList lst = horiz_splitter->sizes(); cfg.writeEntry("Splitter Sizes", lst); QList vertSplitterSizes = _terminalDock->isVisible() && !isTerminalEmulatorFullscreen() // fix sizes() not returning correct values on fullscreen+shutdown && vert_splitter->sizes().first() != 0 ? vert_splitter->sizes() : verticalSplitterSizes; cfg.writeEntry("Terminal Emulator Splitter Sizes", vertSplitterSizes); cfg.writeEntry("Vertical Mode", isVertical()); cfg.writeEntry("Left Side Is Active", ACTIVE_PANEL->gui->isLeft()); leftMng->saveSettings(KConfigGroup(&cfg, "Left Tab Bar"), true); rightMng->saveSettings(KConfigGroup(&cfg, "Right Tab Bar"), true); } bool KrusaderView::cursorIsOnOtherSide(PanelManager *of, const QPoint &globalPos) { int border = -1; int pos = -1; if (horiz_splitter->orientation() == Qt::Horizontal) { pos = globalPos.x(); if(of == leftMng) border = leftMng->mapToGlobal(QPoint(leftMng->width(), 0)).x(); else border = rightMng->mapToGlobal(QPoint(0, 0)).x(); } else { pos = globalPos.y(); if(of == leftMng) border = leftMng->mapToGlobal(QPoint(0, leftMng->height())).y(); else border = rightMng->mapToGlobal(QPoint(0, 0)).y(); } return (of == leftMng) ? pos > border : pos < border; } void KrusaderView::draggingTab(PanelManager *from, QMouseEvent *e) { QString icon; if (horiz_splitter->orientation() == Qt::Horizontal) icon = (from == leftMng) ? "arrow-right" : "arrow-left"; else icon = (from == leftMng) ? "arrow-down" : "arrow-up"; QCursor cursor(QIcon::fromTheme(icon).pixmap(22)); if (cursorIsOnOtherSide(from, e->globalPos())) { if(!qApp->overrideCursor()) qApp->setOverrideCursor(cursor); } else qApp->restoreOverrideCursor(); } void KrusaderView::draggingTabFinished(PanelManager *from, QMouseEvent *e) { qApp->restoreOverrideCursor(); if (cursorIsOnOtherSide(from, e->globalPos())) from->moveTabToOtherSide(); }